81#ifndef LIBLTS_BISIM_DNJ_H
82#define LIBLTS_BISIM_DNJ_H
108 #define ONLY_IF_DEBUG(...) __VA_ARGS__
110 #define ONLY_IF_DEBUG(...)
133template <
class Iterator>
149 new (&
begin) Iterator(other);
158class block_bunch_entry;
159class action_block_entry;
183class state_info_entry;
184class permutation_entry;
269 template<
class LTS_TYPE>
278 template<
class LTS_TYPE>
285 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
390 { assert(new_begin < new_end);
469 { assert(
begin <= s);
497 template<
class LTS_TYPE>
509 ") (#" + std::to_string(
seqnr) +
")";
512 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
549 { assert(0 < num_states);
551 #ifdef USE_POOL_ALLOCATOR
552 static_assert(std::is_trivially_destructible<block_t>::value);
557 state_iter->
pos = perm_iter;
558 perm_iter->
st = state_iter;
564 #ifndef USE_POOL_ALLOCATOR
575 block_t*
const B(perm_iter[-1].st->bl.ock); assert(B->
end == perm_iter);
605 template<
class LTS_TYPE>
607 const char*
const message,
611 { assert(B->
begin <= begin_print); assert(end_print <= B->end);
612 if (end_print == begin_print)
return;
615 << (1 < end_print - begin_print ?
"s:\n" :
":\n");
616 assert(begin_print < end_print);
621 if (B != begin_print->
st->
bl.
ock)
626 if (begin_print != begin_print->
st->
pos)
629 <<
", inconsistent pointer to state_info_entry";
633 while (++begin_print < end_print);
640 template<
class LTS_TYPE>
664 template<
class LTS_TYPE>
696 if (perm_iter < block->nonbottom_begin)
717 assert(perm_iter ==
state->pos);
719 while (++perm_iter < block->end);
734 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
736 bool operator()(
const iterator_or_counter<action_block_entry*> p1,
737 const action_block_entry*
const action_block)
const
739 return p1.begin > action_block;
806 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
818 template <
class LTS_TYPE>
859 template <
class LTS_TYPE>
868 template <
class LTS_TYPE>
882 return pp(partitioner.
aut.action_label(
label)) +
"-transition " +
886 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
929 assert(
nullptr !=
succ); assert(
nullptr != result->
succ);
931 assert(result == action_block_begin ||
nullptr == result[-1].
succ ||
932 action_block_orig_inert_begin <= result ||
1009 template <
class LTS_TYPE>
1015 return "bunch [" + std::to_string(
begin -
1021 template <
class LTS_TYPE>
1024 { assert(
nullptr !=
end[-1].succ);
1026 assert(
nullptr != iter->
succ);
1029 result +=
" containing transition";
1030 result += iter <
end - 1 ?
"s " :
" ";
1033 if (
end <= iter)
return result;
1034 while (
nullptr == iter->
succ) ++iter;
1044 while (++iter <
end)
1046 if (
nullptr != iter->
succ)
1056 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1062 template <
class LTS_TYPE>
1142 bunch_t*
const new_bunch,
bool const new_is_stable)
1169 template <
class LTS_TYPE>
1177 return p1.
slice != p2;
1179 }
const block_bunch_not_equal;
1183 std::string
const index_string(std::to_string(
end -
1187 return "empty block_bunch_slice [" + index_string +
"," +
1195 begin =
end - bunch_size;
1199 this, block_bunch_not_equal);
1200 assert(begin->
slice ==
this);
1201 assert(begin[-1].slice !=
this);
1202 return (
is_stable() ?
"stable block_bunch-slice ["
1203 :
"unstable block_bunch_slice [") +
1205 "," + index_string +
") containing transitions from " +
1210 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1218 template <
class LTS_TYPE>
1220 counter_type const ctr, unsigned const max_value,
1223 assert(1U == max_value);
1227 assert(partitioner.part_tr.block_bunch.front().slice !=
this);
1228 assert(block_bunch[-1].slice ==
this);
1233 assert(source->
bl.
ock == block);
1234 if (source->
pos < block->nonbottom_begin
1245 while (block_bunch[-1].slice ==
this);
1268 assert(&succ.cbegin()[1] == result ||
1280 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1289 template <
class LTS_TYPE>
1295 const succ_entry*
const out_slice_before_end(
1297 assert(
nullptr != out_slice_before_end);
1300 add_work(ctr, max_value), partitioner);
1306 add_work_notemporary(ctr, max_value), partitioner);
1309 (void) partitioner; (void) out_slice_before_end;
1360 #ifdef USE_POOL_ALLOCATOR
1361 static_assert(std::is_trivially_destructible<bunch_t>::value);
1383 :
succ(num_transitions + 2),
1385 pred(num_transitions + 2),
1387 ? 0 : num_transitions + num_actions - 1),
1402 pred.front().source =
nullptr;
1403 pred.front().target =
nullptr;
1404 pred.back() .source =
nullptr;
1405 pred.back() .target =
nullptr;
1412 #ifndef USE_POOL_ALLOCATOR
1430 action_block_iter = bunch->
end;
1499 bunch_t*
const bunch_T_a_Bprime,
1500 bool const first_transition_of_state)
1505 succ_entry*
const old_succ_pos(action_block_iter->
succ); assert(
nullptr != old_succ_pos);
1512 assert(new_succ_pos<old_succ_pos->
block_bunch->pred->source->succ_inert.begin);
1514 if (old_succ_pos < new_succ_pos)
1518 action_block_iter->
succ = new_succ_pos;
1519 }
else assert(old_succ_pos == new_succ_pos);
1532 if (first_transition_of_state)
1539 new_succ_pos[1].begin_or_before_end); assert(
nullptr != out_slice_before_end);
1540 assert(new_succ_pos < out_slice_before_end);
1542 out_slice_before_end);
1546 new_succ_pos->
begin_or_before_end = out_slice_before_end; assert(bunch_T_a_Bprime == out_slice_before_end->
bunch());
1549 assert(new_succ_pos == action_block_iter->
succ);
1555 old_block_bunch_pos->
slice);
1557 old_block_bunch_slice->end - 1); assert(
nullptr != new_block_bunch_pos->
pred->
action_block->
succ);
1559 new_block_bunch_pos);
1564 new_block_bunch_pos[1].slice, assert(!new_block_bunch_pos[1].slice.is_null()),
1565 bunch_T_a_Bprime != new_block_bunch_slice->bunch ||
1566 source_block != new_block_bunch_slice->source_block()))
1567 { assert(first_transition_of_state);
1574 #ifdef USE_SIMPLE_LIST
1576 new_block_bunch_pos + 1, bunch_T_a_Bprime,
false);
1579 bunch_T_a_Bprime,
false);
1583 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1584 new_block_bunch_slice->work_counter = old_block_bunch_slice->work_counter;
1588 old_block_bunch_slice->make_unstable();
1589 } assert(!new_block_bunch_slice->is_stable());
1592 if (old_block_bunch_pos < new_block_bunch_pos)
1598 }
else assert(new_block_bunch_pos == old_block_bunch_pos);
1599 assert(new_block_bunch_pos->
slice == old_block_bunch_slice);
1600 new_block_bunch_pos->
slice = new_block_bunch_slice;
1602 assert(new_block_bunch_pos + 1 == old_block_bunch_slice->marked_begin);
1603 old_block_bunch_slice->end = new_block_bunch_pos;
1604 old_block_bunch_slice->marked_begin = new_block_bunch_pos; assert(
nullptr != new_block_bunch_pos);
1605 if (old_block_bunch_slice->empty())
1606 { assert(!old_block_bunch_slice->is_stable());
1607 splitter_list.erase(old_block_bunch_slice); assert(!new_block_bunch_slice->is_stable());
1617 new_block_bunch_slice->make_stable();
1652 bunch_t* const bunch_T_a_Bprime, )
1653 bunch_t* const large_splitter_bunch)
1654 { assert(
nullptr != bunch_T_a_Bprime);
1661 succ_entry*
const new_succ_pos(action_block_iter->succ); assert(
nullptr != new_succ_pos);
1665 assert(new_succ_pos < source->succ_inert.begin);
1666 assert(source == partitioner.part_st.state_info.data() ||
1667 source[-1].
succ_inert.begin <= new_succ_pos);
1672 new_begin_or_before_end);
1673 if (new_begin_or_before_end < new_succ_pos)
1674 { assert(source == partitioner.part_st.state_info.data() ||
1675 source[-1].
succ_inert.begin <= new_begin_or_before_end);
1679 { assert(new_begin_or_before_end == new_succ_pos);
1683 if (new_begin_or_before_end <= new_before_end)
1684 { assert(&partitioner.part_tr.succ.cbegin()[1] == new_begin_or_before_end ||
1686 new_begin_or_before_end[-1].
bunch() != bunch_T_a_Bprime);
1687 assert(new_before_end + 1 == source->
succ_inert.begin ||
1688 bunch_T_a_Bprime != new_before_end[1].
bunch());
1689 if (source == new_succ_pos[-1].
block_bunch->pred->source &&
1690 new_succ_pos[-1].
bunch() == large_splitter_bunch)
1694 new_succ_pos[-1].
block_bunch); assert(!old_block_bunch_pos->
slice.is_null());
1697 old_block_bunch_pos->
slice);
1698 if (!large_splitter_slice->is_stable())
1701 large_splitter_slice->marked_begin - 1); assert(
nullptr != new_block_bunch_pos->
pred->
action_block->
succ);
1703 new_block_bunch_pos);
1704 if (old_block_bunch_pos < new_block_bunch_pos)
1707 new_block_bunch_pos->
pred);
1709 succ->block_bunch = old_block_bunch_pos; assert(new_block_bunch_pos->
pred->
action_block->
succ == new_succ_pos - 1);
1710 new_succ_pos[-1].
block_bunch = new_block_bunch_pos;
1712 large_splitter_slice->marked_begin=new_block_bunch_pos; assert(
nullptr != new_block_bunch_pos);
1713 }
else assert(1 >= source->
bl.
ock->
size());
1715 }
else assert(source == partitioner.part_st.state_info.data() ||
1716 source[-1].
succ_inert.begin <= new_before_end);
1721 assert(!new_block_bunch_pos->
slice.is_null());
1723 new_block_bunch_pos->
slice);
1724 assert(new_block_bunch_pos < new_block_bunch_slice->end);
1725 assert(bunch_T_a_Bprime == new_block_bunch_slice->bunch);
1726 if (new_block_bunch_pos + 1 < new_block_bunch_slice->end)
return;
1732 while ((--new_block_bunch_pos)->slice == new_block_bunch_slice);
1733 assert(new_block_bunch_pos <= partitioner.part_tr.block_bunch.data() ||
1735 bunch_T_a_Bprime != new_block_bunch_pos->
slice->bunch);
1773 { assert(&
succ.cbegin()[1] < out_slice_end);
1775 out_slice_end[-1].begin_or_before_end); assert(
nullptr != out_slice_begin);
1776 assert(out_slice_begin < out_slice_end);
1780 assert(!old_block_bunch_pos->
slice.is_null());
1783 old_block_bunch_pos);
1784 if (&*splitter_T == &*old_block_bunch_slice)
return out_slice_begin;
1787 old_block_bunch_slice->end);
1789 assert(partitioner.part_st.state_info.data() == source ||
1790 source[-1].
succ_inert.begin < out_slice_end);
1796 old_block_bunch_slice_end->
slice, assert(!old_block_bunch_slice_end->
slice.is_null()),
1797 old_block_bunch_slice->bunch != new_block_bunch_slice->bunch))
1801 if (old_block_bunch_slice->is_stable())
1804 #ifdef USE_SIMPLE_LIST
1805 new_block_bunch_slice =
1807 old_block_bunch_slice->end,
1808 old_block_bunch_slice->bunch,
true);
1811 old_block_bunch_slice->end,
1812 old_block_bunch_slice->bunch,
true);
1813 new_block_bunch_slice =
1819 #ifdef USE_SIMPLE_LIST
1821 old_block_bunch_slice,
1822 old_block_bunch_slice->end,
1823 old_block_bunch_slice->bunch,
false);
1826 std::next(old_block_bunch_slice),
1827 old_block_bunch_slice->end,
1828 old_block_bunch_slice->bunch,
false);
1832 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1833 new_block_bunch_slice->work_counter = old_block_bunch_slice->work_counter;
1836 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1840 assert(out_slice_begin < out_slice_end);
1842 { assert(old_block_bunch_pos == out_slice_end[-1].
block_bunch);
1843 --out_slice_end; assert(old_block_bunch_pos->
slice == old_block_bunch_slice);
1844 assert(source == out_slice_end->block_bunch->pred->source);
1845 --old_block_bunch_slice_end;
1849 if (old_block_bunch_slice->is_stable() || ( assert(!new_block_bunch_slice->is_stable()),
1850 old_block_bunch_slice->marked_begin >
1851 old_block_bunch_slice_end &&
1852 ( assert(
nullptr != old_block_bunch_slice_end),
1855 old_block_bunch_slice->marked_begin =
1856 old_block_bunch_slice_end,
true)))
1861 old_block_bunch_slice_end->
pred);
1868 if (old_block_bunch_pos < old_block_bunch_slice->marked_begin)
1875 old_block_bunch_slice->marked_begin - 1; assert(old_block_bunch_pos < old_block_bunch_slice_end);
1876 old_block_bunch_slice->marked_begin = old_marked_begin;
1878 old_block_bunch_pos->
pred = old_marked_begin->
pred;
1879 old_marked_begin->
pred = old_block_bunch_slice_end->
pred;
1890 new_block_bunch_slice->marked_begin - 1;
1891 new_block_bunch_slice->marked_begin = new_marked_begin; assert(old_block_bunch_pos < new_marked_begin ||
1892 old_block_bunch_pos == old_block_bunch_slice_end);
1893 old_block_bunch_pos->
pred=old_block_bunch_slice_end->
pred; assert(old_block_bunch_slice_end <= new_marked_begin);
1894 old_block_bunch_slice_end->
pred = new_marked_begin->
pred;
1897 out_slice_end->block_bunch = new_marked_begin;
1903 old_block_bunch_pos;
1905 while (out_slice_begin < out_slice_end &&
1906 (old_block_bunch_pos = out_slice_end[-1].
block_bunch,
true));
1907 old_block_bunch_slice->end = old_block_bunch_slice_end;
1909 if (old_block_bunch_slice->empty())
1911 if (old_block_bunch_slice->is_stable())
1927 old_block->stable_block_bunch.erase(old_block_bunch_slice);
1935 return out_slice_begin;
1955 )); assert(
nullptr != action_block_slice_begin->
succ);
1957 action_block_slice_begin);
1961 assert(
nullptr != new_action_block_pos->
succ);
1963 new_action_block_pos);
1964 if (old_action_block_pos < new_action_block_pos)
1966 succ_entry*
const temp(new_action_block_pos->
succ); assert(
nullptr != temp); assert(
nullptr != old_action_block_pos->
succ);
1967 new_action_block_pos->
succ = old_action_block_pos->
succ;
1968 old_action_block_pos->
succ = temp;
1974 new_action_block_pos - 1;
1977 { assert(old_action_block_pos == new_action_block_pos);
1978 if (action_block_slice_begin < new_action_block_pos)
1984 new_action_block_pos - 1;
1987 } assert(
nullptr != new_action_block_pos->
succ);
1995 nullptr == new_action_block_pos[1].
succ ||
1996 new_action_block_pos[1].
succ->bunch() !=
2009 new_action_block_pos[1].begin_or_before_end); assert(
nullptr != action_block_slice_before_end);
2010 assert(new_action_block_pos < action_block_slice_before_end);
2011 assert(
nullptr != action_block_slice_before_end->
succ);
2013 action_block_slice_before_end);
2014 assert(new_action_block_pos + 1 ==
2017 new_action_block_pos; assert(action_block_slice_before_end->
succ->
block_bunch->
2039 assert(
nullptr != old_begin_or_before_end->
succ);
2041 old_begin_or_before_end);
2043 old_begin_or_before_end->
begin_or_before_end); assert(
nullptr != new_begin_or_before_end),
2044 assert(
nullptr != new_begin_or_before_end->succ),
2045 assert(new_begin_or_before_end->succ->block_bunch->pred->action_block ==
2046 new_begin_or_before_end),
2047 new_begin_or_before_end < new_action_block_pos)
2050 new_begin_or_before_end; assert(new_action_block_pos <= old_begin_or_before_end);
2052 }
else assert(new_begin_or_before_end == new_action_block_pos);
2053 if (old_begin_or_before_end < new_action_block_pos)
return;
2058 if (!bunch->
is_trivial()) {
return; } assert(old_begin_or_before_end + 1 == bunch->
end);
2059 if (bunch->
begin < new_action_block_pos)
2099 new_action_block_pos);
2104 new_block_bunch_pos);
2106 old_pred_pos->
action_block); assert(new_action_block_pos <= old_action_block_pos);
2108 succ_entry*
const old_succ_pos(old_action_block_pos->
succ); assert(
nullptr != old_succ_pos);
2110 old_succ_pos->
block_bunch); assert(old_pred_pos == old_block_bunch_pos->
pred);
2115 if (new_action_block_pos < old_action_block_pos)
2117 old_action_block_pos->
succ = new_action_block_pos->
succ; assert(
nullptr != old_action_block_pos->
succ);
2119 new_action_block_pos);
2121 old_action_block_pos;
2122 }
else assert(new_action_block_pos == old_action_block_pos);
2123 new_action_block_pos->
succ = new_succ_pos; assert(
nullptr != new_succ_pos);
2127 if (new_succ_pos < old_succ_pos)
2131 }
else assert(new_succ_pos == old_succ_pos);
2135 assert(new_block_bunch_pos->
slice.is_null());
2136 if (new_block_bunch_pos < old_block_bunch_pos)
2137 { assert(old_block_bunch_pos->
slice.is_null());
2140 new_block_bunch_pos);
2143 old_block_bunch_pos;
2144 }
else assert(new_block_bunch_pos == old_block_bunch_pos);
2145 new_block_bunch_pos->
pred = new_pred_pos;
2149 if (new_pred_pos < old_pred_pos)
2156 }
else assert(new_pred_pos == old_pred_pos);
2160 bool became_bottom(
false); assert(
succ.back().block_bunch->pred->source != source);
2161 if (source != source->
succ_inert.begin->block_bunch->pred->source)
2172 became_bottom =
true;
2175 bunch_t* new_noninert_bunch; assert(
nullptr != new_action_block_pos);
2176 if (!new_noninert_block_bunch_ptr->is_null())
2185 new_noninert_bunch = (*new_noninert_block_bunch_ptr)->bunch; assert(new_action_block_pos >= new_noninert_bunch->
end);
2188 temp_action_block_pos > new_noninert_bunch->
end ; )
2190 assert(
nullptr == (--temp_action_block_pos)->
succ);
2194 assert((*new_noninert_block_bunch_ptr)->end == new_block_bunch_pos);
2196 if (!(*new_noninert_block_bunch_ptr)->is_stable())
2197 { assert((*new_noninert_block_bunch_ptr)->marked_begin == new_block_bunch_pos);
2198 (*new_noninert_block_bunch_ptr)->marked_begin =
2201 new_block_bunch_pos->
slice = *new_noninert_block_bunch_ptr;
2203 assert(new_noninert_bunch->
begin < new_action_block_pos);
2204 if (
nullptr != new_action_block_pos[-1].
succ &&
2205 target->bl.ock == new_action_block_pos[-1].
2206 succ->block_bunch->pred->target->bl.ock)
2210 new_action_block_pos[-1].begin_or_before_end); assert(
nullptr != action_block_slice_begin);
2212 assert(
nullptr != action_block_slice_begin->
succ);
2214 action_block_slice_begin);
2216 new_action_block_pos;
2218 action_block_slice_begin;
2235 iter < new_noninert_bunch->
begin; ++iter)
2237 assert(
nullptr == iter->succ);
2238 assert(
nullptr == iter->begin_or_before_end);
2245 assert(source !=
succ.front().block_bunch->pred->source);
2246 if (source == new_succ_pos[-1].
block_bunch->pred->source &&
2247 new_succ_pos[-1].
bunch() == new_noninert_bunch)
2251 new_succ_pos[-1].begin_or_before_end); assert(
nullptr != out_slice_begin);
2256 return became_bottom;
2262 new_noninert_bunch =
2263 #ifdef USE_POOL_ALLOCATOR
2265 template construct<bunch_t>
2273 #ifdef USE_SIMPLE_LIST
2279 new_noninert_bunch,
false);
2284 new_block_bunch_pos->
slice = new_noninert_block_bunch;
2285 *new_noninert_block_bunch_ptr = new_noninert_block_bunch;
2288 new_action_block_pos->begin_or_before_end = new_action_block_pos;
2290 } assert(&
succ.cbegin()[1] == new_succ_pos ||
2292 new_succ_pos[-1].
bunch() != new_noninert_bunch);
2294 return became_bottom;
2324 bool const add_new_noninert_to_splitter,
2327 { assert(splitter_T->is_stable());
2334 assert(s->
pos == s_iter);
2336 assert(s !=
succ.front().block_bunch->pred->source);
2338 s == succ_iter[-1].block_bunch->pred->source; )
2341 old_block, splitter_T); assert(succ_iter->block_bunch->pred->action_block->succ == succ_iter);
2342 assert(s == succ_iter->block_bunch->pred->source);
2347 assert(s !=
pred.front().target);
2349 s == (--pred_iter)->
target; )
2350 { assert(
pred.data() < pred_iter);
2351 assert(
nullptr != pred_iter->action_block->succ);
2352 assert(pred_iter->action_block->succ->block_bunch->pred == pred_iter);
2356 while (++s_iter < new_block->end);
2359 { assert(splitter_T->source_block() == new_block);
2362 new_block->stable_block_bunch.splice(
2363 new_block->stable_block_bunch.begin(),
2364 old_block->stable_block_bunch, splitter_T);
2365 }
else assert(splitter_T->source_block() == old_block);
2370 s_iter = new_block->begin; assert(s_iter < new_block->end);
2375 s == (--pred_iter)->
target; )
2376 { assert(
pred.data() < pred_iter);
2377 assert(
nullptr != pred_iter->action_block->succ);
2378 assert(pred_iter->action_block->succ->block_bunch->pred == pred_iter);
2382 while (++s_iter < new_block->end);
2383 assert(0 == new_block->marked_size()); assert(0 == old_block->marked_size());
2389 if (add_new_noninert_to_splitter)
2391 new_noninert_block_bunch = splitter_T;
2395 new_noninert_block_bunch =
nullptr;
2398 { assert(old_block == new_block->end->st->bl.ock);
2399 assert(new_block->end < partitioner.part_st.permutation.data_end());
2400 permutation_entry* target_iter(new_block->begin); assert(target_iter < new_block->end);
2405 assert(s !=
pred.back().target);
2407 s == pred_iter->target; ++pred_iter)
2408 { assert(pred_iter < &
pred.back());
2409 assert(
nullptr != pred_iter->action_block->succ);
2410 state_info_entry*
const t(pred_iter->source); assert(pred_iter->action_block->succ->block_bunch->pred == pred_iter);
2411 assert(t->
pos->
st == t);
2412 if (new_block != t->
bl.
ock)
2413 { assert(old_block == t->
bl.
ock);
2415 &new_noninert_block_bunch))
2418 old_block->mark_nonbottom(t->
pos);
2424 while (++target_iter < new_block->end); assert(0 < old_block->bottom_size());
2428 assert(partitioner.part_st.permutation.data() < new_block->begin);
2429 assert(old_block == new_block->begin[-1].st->bl.ock);
2430 assert(0 < old_block->bottom_size());
2432 source_iter < new_block->marked_nonbottom_begin; )
2436 assert(
succ.back().block_bunch->pred->source != s);
2446 &new_noninert_block_bunch);
2450 while (s == (++succ_iter)->
block_bunch->pred->source);
2451 if (dont_mark) ++source_iter;
2453 { assert(s->
pos == source_iter);
2454 new_block->mark_nonbottom(source_iter);
2455 } assert(new_block->nonbottom_begin <= source_iter);
2467 template <
class LTS_TYPE>
2473 if (succ_iter >= &
succ.back())
2487 bool always_print=
false;
2489 { assert(source < succ_iter->
block_bunch->pred->source);
2492 << source->
debug_id(partitioner) <<
":\n";
2499 { assert(succ_iter == source->
succ_inert.begin);
2501 current_out_bunch =
nullptr;
2504 { assert(succ_iter < source->succ_inert.begin);
2516 while (++succ_iter < &
succ.back());
2520 do assert(action_block_iter <
action_block.data_end());
2521 while (
nullptr == action_block_iter->
succ &&
2523 ++action_block_iter,
true));
2528 assert(
nullptr != action_block_iter->
succ);
2532 action_block_slice_end = bunch_end =
action_block.data_end();
2537 assert(
nullptr != bunch);
2539 partitioner) <<
":\n\taction_block-slice [";
2540 assert(bunch->
begin == action_block_iter);
2541 bunch_end = bunch->
end;
2544 action_block_slice_end =
2547 assert(action_block_slice_end <= bunch_end);
2553 << (action_block_slice_end -
action_block.data()) <<
"):\n";
2555 assert(action_block_iter < action_block_slice_end);
2558 assert(
nullptr != action_block_iter->
succ);
2561 pred->debug_id(partitioner) <<
'\n';
2563 while (++action_block_iter < action_block_slice_end);
2565 while (action_block_iter < bunch_end &&
2566 nullptr == action_block_iter->
succ)
2569 ++action_block_iter;
2570 assert(action_block_iter < bunch_end);
2572 if (action_block_iter >= bunch_end)
break;
2574 action_block_slice_end =
2579 assert(action_block_iter == bunch_end);
2581 nullptr == action_block_iter->
succ)
2584 ++action_block_iter;
2606{ assert(0 < marked_size()); assert(0 < unmarked_bottom_size());
2609 state_type swapcount(std::min(marked_bottom_size(),
2610 unmarked_nonbottom_size()));
2612 unmarked_nonbottom_size()); assert(begin < splitpoint), assert(splitpoint < end),
2613 assert(splitpoint->st->pos == splitpoint),
2615 { assert((
state_type) (splitpoint - begin) <= size()/2);
2617 #ifdef USE_POOL_ALLOCATOR
2619 template construct<block_t>
2623 (begin, splitpoint, new_seqnr);
2628 nonbottom_begin = marked_nonbottom_begin;
2633 #ifdef USE_POOL_ALLOCATOR
2635 template construct<block_t>
2639 (splitpoint, end, new_seqnr);
2644 nonbottom_begin = marked_bottom_begin;
2646 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
2667 --pos2; assert(pos1 < pos2);
2668 *pos1 = std::move(*pos2);
2670 if (0 >= --swapcount) {
break; } assert(pos1 < pos2);
2671 *pos2 = std::move(*pos1);
2673 *pos2 = std::move(temp);
2677 do assert(s_iter->
st->
pos == s_iter);
2678 while (++s_iter < end); }
2681 marked_nonbottom_begin = end;
2682 marked_bottom_begin = nonbottom_begin;
2688 { assert(s_iter->
st->
pos == s_iter);
2689 s_iter->
st->
bl.
ock = new_block;
2713 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);
2715 assert(last_slice_begin <
end); assert(
nullptr != first_slice_end[-1].succ);
2716 assert(
nullptr != last_slice_begin->
succ);
2717 if (first_slice_end -
begin >
end - last_slice_begin)
2721 #ifdef USE_POOL_ALLOCATOR
2723 template construct<bunch_t>
2727 (last_slice_begin,
end); assert(
nullptr != bunch_T_a_Bprime);
2728 end = last_slice_begin;
2729 while (
nullptr ==
end[-1].succ)
2732 } assert(
nullptr !=
end[-1].begin_or_before_end);
2739 #ifdef USE_POOL_ALLOCATOR
2741 template construct<bunch_t>
2745 (
begin, first_slice_end); assert(
nullptr != bunch_T_a_Bprime);
2746 begin = first_slice_end;
2753 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
2757 return bunch_T_a_Bprime;
2794template <
class LTS_TYPE>
2801 extend_from_splitter };
2807 bisim_dnj::part_state_t part_st;
2826 bool const branching;
2834 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
2854 bool const new_preserve_divergence =
false)
2856 part_st(new_aut.num_states()),
2857 part_tr(new_aut.num_transitions(), new_aut.num_action_labels()),
2858 action_label(new_aut.num_action_labels()),
2859 branching(new_branching),
2860 preserve_divergence(new_preserve_divergence)
2861 { assert(branching || !preserve_divergence);
2866 end_initial_part = std::clock();
2868 refine_partition_until_it_becomes_stable();
2878 return part_st.nr_of_blocks;
2891 return part_st.block(s)->seqnr;
2921 { assert(block_bunch.is_stable()); assert(!block_bunch.empty());
2923 pred(block_bunch.end[-1].
pred); assert(pred->source->bl.ock == B);
2924 assert(
nullptr != pred->action_block->succ);
2925 assert(pred->action_block->succ->block_bunch->pred == pred);
2926 assert(pred->action_block->succ->block_bunch->slice == &block_bunch);
2928 label(block_bunch.bunch->next_nontrivial_and_label.label); assert(0 <=
label); assert(
label < action_label.size());
2930 pred->target->bl.ock->seqnr));
2934 while (s_iter < part_st.permutation.data_end());
2939 if (aut.has_state_info())
2943 typename std::remove_reference<
decltype(aut.state_labels())>::type
2944 new_labels(num_eq_classes());
2946 state_type i(0); assert(i < aut.num_states());
2950 new_labels[new_index]=new_labels[new_index]+aut.state_label(i);
2952 while (++i < aut.num_states());
2954 aut.set_num_states(num_eq_classes(),
false); assert(0 == aut.num_state_labels());
2956 new_labels.swap(aut.state_labels());
2960 aut.set_num_states(num_eq_classes(),
false);
2963 aut.set_initial_state(get_eq_class(aut.initial_state()));
2973 return part_st.block(s) == part_st.block(t);
3004 << (branching ? (preserve_divergence
3005 ?
"divergence-preserving branching "
3008 <<
"bisimulation partitioner created for " << part_st.state_size()
3009 <<
" states and " << aut.num_transitions() <<
" transitions.\n";
3011 if (part_st.state_size() > 2 * aut.num_transitions() + 1)
3014 "without incoming or outgoing transition. It is not "
3015 "guaranteed that branching bisimulation minimisation runs in "
3016 "time O(m log n).\n";
3025 template construct<bisim_dnj::block_t>
3029 (part_st.permutation.data(),
3030 part_st.permutation.data_end(), part_st.nr_of_blocks++));
3040 assert(action_label.size() == aut.num_action_labels());
3043 for (
const transition& t: aut.get_transitions())
3045 if (branching&&aut.is_tau(aut.apply_hidden_label_map(t.label()))&& ((
3046 t.from() != t.to()) || (assert(preserve_divergence),
false)))
3049 ++part_st.state_info[t.from()].succ_inert.count;
3050 ++inert_transitions;
3055 std::swap(*part_st.state_info[t.from()].pos,
3063 ++part_st.state_info[t.from()].untested_to_U_eqv.count;
3064 ++action_label[aut.apply_hidden_label_map(t.label())].count;
3066 ++part_st.state_info[t.to()].pred_inert.count;
3083 next_pred_begin += state_iter->
pred_inert.count;
3084 state_iter->
pred_inert.convert_to_iterator(next_pred_begin);
3087 assert(
nullptr != next_succ_begin);
3090 if (next_succ_begin < state_iter->untested_to_U_eqv.begin)
3095 out_slice_begin(next_succ_begin);
3103 state_iter->
succ_inert.convert_to_iterator(next_succ_begin +
3106 while (next_succ_begin < state_iter->succ_inert.begin)
3111 next_succ_begin = state_iter->
succ_inert.begin;
3113 while (++state_iter < part_st.state_info.data_end());
3126 #ifdef USE_POOL_ALLOCATOR
3128 template construct<bisim_dnj::bunch_t>
3151 aut.num_transitions() + action_label.size() - 1);
3154 trans_type const n_square(part_st.state_size() * part_st.state_size());
3155 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3162 if (0 < action_label[
label].count)
3163 { assert(
nullptr != bunch);
3170 if (n_square < action_label[
label].count)
3173 << action_label[
label].count <<
' '
3174 <<
pp(aut.action_label(
label)) <<
"-transitions. "
3175 "This is more than n^2 (= " << n_square <<
"). It is "
3176 "not guaranteed that branching bisimulation "
3177 "minimisation runs in time O(m log n).\n";
3178 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3179 if (max_transitions < action_label[
label].count)
3180 { max_transitions = action_label[
label].count; }
3185 action_label[
label].convert_to_iterator(
3186 next_action_label_begin + action_label[
label].count);
3190 action_block_slice_begin(next_action_label_begin); assert(
nullptr != action_block_slice_begin);
3191 while (++next_action_label_begin < action_label[
label].begin)
3194 action_block_slice_begin;
3199 action_label[
label].convert_to_iterator(
3200 next_action_label_begin);
3201 if (0 !=
label && aut.num_transitions() < action_label.size())
3204 <<
pp(aut.action_label(
label)) <<
" has no "
3205 "transitions, and the number of action labels exceeds "
3206 "the number of transitions. It is not guaranteed that "
3207 "branching bisimulation minimisation runs in time "
3213 next_action_label_begin->
succ =
nullptr,
3216 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3217 check_complexity::init(2 * max_transitions);
3221 for (
const transition& t: aut.get_transitions())
3224 source(part_st.state_info.data() + t.from());
3226 target(part_st.state_info.data() + t.to());
3232 if (branching&&aut.is_tau(aut.apply_hidden_label_map(t.label()))&& ((
3233 t.from() != t.to()) || (assert(preserve_divergence),
false)))
3239 block_bunch_pos = part_tr.
block_bunch.data_end() -
3241 pred_pos = --
target->pred_inert.begin; assert(block_bunch_pos->
slice.is_null());
3245 --inert_transitions;
3253 --part_st.state_info[t.from()].untested_to_U_eqv.begin; assert(
nullptr != succ_pos->
begin_or_before_end);
3258 pred_pos =
target->bl.ed_noninert_end++;
3260 --action_label[aut.apply_hidden_label_map(t.label())].begin; assert(
nullptr != action_block_pos->
begin_or_before_end);
3264 begin_or_before_end == action_block_pos);
3267 } assert(
target->bl.ed_noninert_end <=
target->pred_inert.begin);
3269 block_bunch_pos->
pred = pred_pos;
3271 pred_pos->
source = source;
3272 pred_pos->
target =
target; assert(
nullptr != succ_pos);
3273 action_block_pos->
succ = succ_pos;
3274 } assert(0 == inert_transitions);
3277 aut.clear_transitions();
3279 state_iter = part_st.state_info.data(); assert(state_iter < part_st.state_info.data_end());
3282 state_iter->
bl.
ock = B;
3284 while (++state_iter < part_st.state_info.data_end());
3286 if (
nullptr != bunch)
3292 while (
nullptr == bunch->
end[-1].
succ)
3298 create_initial_partition, 1U), *
this);
3312 extend_from_marked_states__add_new_noninert_to_splitter);
3323 slice->make_stable();
3344 part_st.assert_consistency(*
this);
3349 part_tr.
block_bunch.size() + action_label.size() - 2);
3361 perm_iter(part_st.permutation.data());
3362 assert(perm_iter < part_st.permutation.data_end());
3366 unsigned const max_block(check_complexity::log_n -
3367 check_complexity::ilog2(block->size()));
3369 std::unordered_set<const bisim_dnj::block_bunch_slice_t*>
3370 block_bunch_check_set;
3371 #ifndef USE_SIMPLE_LIST
3372 block_bunch_check_set.reserve(
3373 block->stable_block_bunch.size());
3378 block->stable_block_bunch)
3380 assert(block_bunch.source_block() == block);
3381 assert(block_bunch.is_stable());
3382 block_bunch_check_set.insert(&block_bunch);
3384 block_bunch.bunch->max_work_counter(*
this)), *
this);
3385 ++true_nr_of_block_bunch_slices;
3393 assert(
state!=part_tr.
succ.front().block_bunch->pred->source);
3397 state == out_slice_end[-1].block_bunch->pred->source; )
3398 { assert(!out_slice_end[-1].block_bunch->
slice.is_null());
3400 block_bunch_slice(out_slice_end[-1].block_bunch->
slice);
3402 block_bunch_slice->bunch);
3403 assert(block == block_bunch_slice->source_block());
3404 if (block_bunch_slice->is_stable())
3406 assert(1 == block_bunch_check_set.count(
3407 &*block_bunch_slice));
3408 ++block_bunch_count;
3413 out_slice_end[-1].begin_or_before_end);
3414 assert(
nullptr != out_slice_begin);
3415 assert(out_slice_begin < out_slice_end);
3424 assert(bunch->
begin <=
3425 out_slice_end->block_bunch->pred->action_block);
3426 assert(out_slice_end->block_bunch->pred->
3427 action_block < bunch->end);
3428 assert(out_slice_end->block_bunch->slice ==
3430 assert(
nullptr != out_slice_end->begin_or_before_end);
3431 if (out_slice_end->block_bunch + 1 !=
3432 block_bunch_slice->end)
3434 assert(out_slice_end->block_bunch + 1 <
3435 block_bunch_slice->end);
3436 assert(out_slice_end->block_bunch[1].slice ==
3440 no_temporary_work(max_block,
3441 check_complexity::log_n -
3442 check_complexity::ilog2(out_slice_end->
3444 perm_iter < block->nonbottom_begin),*
this);
3446 while (out_slice_begin < out_slice_end &&
3447 (assert(out_slice_begin ==
3450 if (perm_iter < block->nonbottom_begin)
3452 assert(block_bunch_check_set.size() == block_bunch_count);
3455 while (++perm_iter < block->end);
3457 while (perm_iter < part_st.permutation.data_end());
3459 true_nr_of_block_bunch_slices);
3476 { assert(
nullptr == action_block->begin_or_before_end);
3478 succ_iter(action_block->succ);
3479 assert(
nullptr != succ_iter);
3494 unsigned const max_block(check_complexity::log_n -
3497 max_block,
false), *
this);
3502 assert(!preserve_divergence);
3512 trans_type true_nr_of_action_block_slices(0);
3515 assert(
label < action_label.size());
3520 assert(action_label[
label].begin <= action_slice_end);
3524 action_block_slice_end(action_slice_end);
3525 action_label[
label].begin < action_block_slice_end; )
3528 action_block_slice_begin(
3529 action_block_slice_end[-1].begin_or_before_end);
3530 assert(
nullptr != action_block_slice_begin);
3531 assert(action_block_slice_begin < action_block_slice_end);
3532 assert(action_block_slice_end <= action_slice_end);
3533 assert(
nullptr != action_block_slice_begin->
succ);
3535 target_block(action_block_slice_begin->
3536 succ->block_bunch->pred->target->bl.ock);
3538 bunch(action_block_slice_begin->
succ->
bunch());
3539 if (previous_bunch != bunch)
3541 assert(
nullptr == previous_bunch);
3542 previous_bunch = bunch;
3543 assert(bunch->
end == action_block_slice_end);
3544 if (bunch->
begin == action_block_slice_begin)
3554 ++true_nr_of_nontrivial_bunches;
3558 ++true_nr_of_bunches;
3560 if(bunch->
begin == action_block_slice_begin)
3562 previous_bunch =
nullptr;
3564 else assert(bunch->
begin < action_block_slice_begin);
3567 action_block_slice_end);
3570 action_block(action_block_slice_end);
3575 succ_iter(action_block->
succ);
3576 assert(
nullptr != succ_iter);
3582 assert(!branching || !aut.is_tau(
label) ||
3584 (preserve_divergence &&
3586 assert(succ_iter < pred_iter->source->succ_inert.begin);
3590 assert(pred_iter < pred_iter->
target->pred_inert.begin);
3593 assert(target_block == pred_iter->
target->
bl.
ock);
3594 assert(bunch == succ_iter->
bunch());
3596 while (action_block_slice_begin < action_block &&
3600 action_block_slice_begin),
true));
3601 action_block_slice_end = action_block_slice_begin;
3602 ++true_nr_of_action_block_slices;
3607 assert(
nullptr == action_slice_end->
succ);
3611 while (++
label < action_label.size() &&
3612 (action_slice_end = action_label[
label - 1].begin - 1,
true));
3613 assert(
nullptr == previous_bunch);
3616 true_nr_of_nontrivial_bunches);
3618 true_nr_of_action_block_slices);
3641 std::clock_t next_print_time = std::clock();
3642 const std::clock_t rounded_start_time=next_print_time-CLOCKS_PER_SEC/2;
3649 assert_stability(); )
3655 if (std::clock_t now = std::clock(); next_print_time <= now ||
3666 next_print_time+=((now-next_print_time)/(60*CLOCKS_PER_SEC)
3667 + 1) * (60*CLOCKS_PER_SEC);
3668 now = (now - rounded_start_time) / CLOCKS_PER_SEC;
3676 << now / 3600 <<
" h ";
3680 << now / 60 <<
" min ";
3684 <<
" sec passed since starting the main loop.\n";
3686 #define PRINT_SG_PL(counter, sg_string, pl_string) \
3688 << (1 == (counter) ? (sg_string) : (pl_string))
3690 << (
nullptr == bunch_T ?
"The reduced LTS contains "
3691 :
"The reduced LTS contains at least ")
3693 " state and ",
" states and ")
3695 " transition.",
" transitions.");
3698 #define PRINT_INT_PERCENTAGE(num,denom) \
3699 (((num) * 200 + (denom)) / (denom) / 2)
3704 #undef PRINT_INT_PERCENTAGE
3712 <<
"\nThe current partition contains ";
3717 " new bottom state, ",
" new bottom states, ");
3721 " bunch (of which ",
" bunches (of which ")
3723 " is nontrivial), and ",
" are nontrivial), and ")
3725 " action-block-slice.\n",
" action-block-slices.\n");
3730 << bunch_T->
debug_id(*
this) <<
'\n'; )
3735 << bunch_T_a_Bprime->
debug_id(*
this) <<
'\n'; )
3736 #
if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3737 unsigned const max_splitter_counter(
3741 bunch_T_a_Bprime->
begin); assert(splitter_iter < bunch_T_a_Bprime->end);
3743 { assert(
nullptr != splitter_iter->
succ);
3749 bool const first_transition_of_state(
3756 bunch_T_a_Bprime, first_transition_of_state);
3759 while (++splitter_iter < bunch_T_a_Bprime->end);
3764 splitter_iter = bunch_T_a_Bprime->
begin; assert(splitter_iter < bunch_T_a_Bprime->end);
3775 while (++splitter_iter < bunch_T_a_Bprime->end);
mCRL2complexity(bunch_T_a_Bprime,
3776 add_work(check_complexity::refine_partition_until_stable__find_pred,
3777 max_splitter_counter), *
this);
3778 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3785 bisim_dnj::block_t* block_B(splitter_Tprime_B->source_block()); assert(!splitter_Tprime_B->is_stable());
3786 bool const is_primary_splitter = 0 < block_B->
marked_size(); assert(!splitter_Tprime_B->empty());
3787 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3788 bool add_stabilize_to_bottom_transns_succeeded =
true;
3789 if (is_primary_splitter)
3791 assert(bbslice_T_a_Bprime_B.is_null());
3794 check_complexity::refine_partition_until_stable__stabilize,
3795 max_splitter_counter), *
this);
3797 else if (!bbslice_T_a_Bprime_B.is_null())
3803 refine_partition_until_stable__stabilize_for_large_splitter,
3804 max_splitter_counter), *
this);
3810 add_stabilize_to_bottom_transns_succeeded = splitter_Tprime_B->
3812 refine_partition_until_stable__stabilize_new_noninert_a_priori,
3816 if (1 < block_B->
size())
3819 block_B_begin(block_B->
begin); assert(block_B_begin->
st->
pos == block_B_begin);
3824 is_primary_splitter ? extend_from_marked_states
3825 : extend_from_splitter);
3826 if (block_B_begin < block_R->begin)
3831 if (is_primary_splitter)
3832 { assert(splitter_Tprime_B->bunch == bunch_T_a_Bprime);
3836 block_U(block_B_begin->
st->
bl.
ock); assert(block_U->
end == block_R->
begin);
3840 (U_splitter->source_block() == block_U ||
3842 U_splitter->source_block() == block_U)))
3843 { assert(!U_splitter->is_stable());
3844 assert(U_splitter->bunch == bunch_T);
3848 U_splitter->make_stable();
3856 { assert(!iter->is_stable());
3857 assert(iter->source_block() != block_U);
3861 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3866 if (!add_stabilize_to_bottom_transns_succeeded)
3867 { assert(splitter_Tprime_B->add_work_to_bottom_transns(
3869 refine_partition_until_stable__stabilize_new_noninert_a_posteriori,
3872 if (splitter_Tprime_B->work_counter.has_temporary_work())
3873 { assert(splitter_Tprime_B->add_work_to_bottom_transns(
3875 handle_new_noninert_transns__make_unstable_a_posteriori,
3877 splitter_Tprime_B->work_counter.reset_temporary_work();
3883 splitter_Tprime_B->end; )
3891 block_R = handle_new_noninert_transns(
3892 block_R, splitter_Tprime_B);
3894 if (splitter_end[-1].pred->source->bl.ock == block_R)
3895 { assert(!splitter_end[-1].slice.is_null());
3899 assert(
nullptr == block_R || splitter_Tprime_B->source_block() == block_R);
3903 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3906 assert(add_stabilize_to_bottom_transns_succeeded);
3908 if (splitter_Tprime_B->work_counter.has_temporary_work())
3909 { assert(!is_primary_splitter);
3911 ::handle_new_noninert_transns__make_unstable_a_posteriori,
3914 splitter_Tprime_B->work_counter.reset_temporary_work();
3928 splitter_Tprime_B->make_stable(); assert(add_stabilize_to_bottom_transns_succeeded);
3929 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3931 if (splitter_Tprime_B->work_counter.has_temporary_work())
3932 { assert(!is_primary_splitter);
3934 handle_new_noninert_transns__make_unstable_a_posteriori,
3937 splitter_Tprime_B->work_counter.reset_temporary_work();
3942 if (is_primary_splitter && !part_tr.
splitter_list.empty() &&
3948 assert(
nullptr != block_B);
3949 assert(splitter_Tprime_B->source_block() == block_B);
3950 assert(splitter_Tprime_B->bunch == bunch_T_a_Bprime);
3951 bbslice_T_a_Bprime_B = splitter_Tprime_B;
3953 else bbslice_T_a_Bprime_B =
nullptr;
3970 action_block_iter(action_label[
label].begin);
3971 action_block_iter < action_block_iter_end;
3973 { assert(
nullptr != action_block_iter->succ);
3974 assert(action_block_iter->succ->block_bunch->pred->action_block ==
3976 assert(action_block_iter->succ->bunch()->is_trivial());
3977 action_block_iter->succ->bunch()->
3978 next_nontrivial_and_label.label =
label; assert(
nullptr != action_block_iter->begin_or_before_end);
3979 assert(action_block_iter <= action_block_iter->begin_or_before_end);
3982 while (++
label < action_label.size() &&
3983 (action_block_iter_end = action_label[
label - 1].begin - 1,
true));
4025 { assert(block_B == splitter_T->source_block());
4029 <<
',' << splitter_T->debug_id(*
this)
4030 << (extend_from_marked_states__add_new_noninert_to_splitter == mode
4031 ?
",extend_from_marked_states__add_new_noninert_to_splitter)\n"
4032 : (extend_from_marked_states == mode
4033 ?
",extend_from_marked_states)\n"
4034 : (extend_from_splitter == mode
4035 ?
",extend_from_splitter)\n"
4036 :
",UNKNOWN MODE)\n")));
4045 if (extend_from_splitter == mode)
4048 R_s_iter.splitter_iter = splitter_T->end; assert(splitter_T->marked_begin <= R_s_iter.splitter_iter);
4049 while (splitter_T->marked_begin < R_s_iter.splitter_iter)
4050 { assert(&part_tr.
block_bunch.cbegin()[1] < R_s_iter.splitter_iter);
4051 --R_s_iter.splitter_iter;
4053 s(R_s_iter.splitter_iter->pred->source); assert(s->
bl.
ock == block_B); assert(s->
pos->
st == s);
4059 assert(splitter_T->marked_begin == splitter_T->end); }
4062 splitter_T->make_stable();
4069 U_nonbottom_end(untested_to_U_defined_end);
4081 (SPLIT_U_PREDECESSOR_HANDLED)
4082 (SPLIT_R_STATE_HANDLED)
4083 (SPLIT_U_STATE_HANDLED)
4085 (SPLIT_R_COLLECT_SPLITTER))
4105 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4106 finalise_U_is_smaller(
nullptr, block_R, *
this);
4113 if (U_nonbottom_end < block_B->marked_nonbottom_begin)
4116 U_s_iter = block_B->
begin;
4118 U_s_iter < U_nonbottom_end)
4120 assert(part_tr.
pred.front().target != U_s_iter->
st);
4123 U_t_iter->
target == U_s_iter->
st, ++U_t_iter)
4126 assert(U_t->
pos < block_B->
end);
4132 if (untested_to_U_defined_end <= U_t->pos)
4139 *untested_to_U_defined_end++);
4141 } assert(U_t != part_tr.
succ.back().block_bunch->pred->source);
4146 begin->block_bunch->pred->source)
4151 if (extend_from_splitter == mode)
4152 { assert(U_t != part_tr.
succ.front().block_bunch->pred->source);
4155 U_u_iter = U_t->
succ_inert.begin; assert(part_tr.
succ.data() < U_u_iter);
4165 if (&*block_bunch == &*splitter_T)
4170 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4171 bisim_dnj::succ_entry::add_work_to_out_slice(*
this, U_u_iter,
4172 check_complexity::split_U__test_noninert_transitions, 1U);
4177 } assert(U_nonbottom_end <= U_t->pos);
4178 assert(U_t->
pos < untested_to_U_defined_end);
4181 if (block_B->
size() / 2 <
4191 untested_to_U_defined_end = U_nonbottom_end;
4197 check_complexity::split_U__handle_transition_to_U_state, 1U), *
this);
4200 check_complexity::split_U__find_predecessors_of_U_state, 1U), *
this);
4220 part_st.nr_of_blocks++));
4225 extend_from_marked_states__add_new_noninert_to_splitter ==
4226 mode, splitter_T, bisim_dnj::new_block_is_U);
4227 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4228 finalise_U_is_smaller(block_U, block_R, *
this);
4245 if (extend_from_splitter == mode)
4248 if (U_nonbottom_end < block_B->marked_nonbottom_begin)
4249 { assert(part_tr.
block_bunch.front().slice != splitter_T);
4251 R_s_iter.splitter_iter[-1].slice == splitter_T)
4252 { assert(&part_tr.
block_bunch.cbegin()[1] < R_s_iter.splitter_iter);
4253 --R_s_iter.splitter_iter;
4255 R_s_iter.splitter_iter->pred->source); assert(s->
bl.
ock == block_B); assert(s->
pos->
st == s);
4257 { assert(U_nonbottom_end <= s->pos);
4258 if (s->
pos < untested_to_U_defined_end)
4265 *--untested_to_U_defined_end);
4277 check_complexity::split_R__handle_transition_from_R_state, 1U), *
this);
4285 mode = extend_from_marked_states;
4292 assert(part_tr.
block_bunch.front().slice != splitter_T);
4293 while (R_s_iter.splitter_iter[-1].slice == splitter_T)
4295 assert(&part_tr.
block_bunch.cbegin()[1] < R_s_iter.splitter_iter);
4296 --R_s_iter.splitter_iter;
4298 s(R_s_iter.splitter_iter->pred->source);
4299 assert(s->
bl.
ock == block_B); assert(s->
pos->
st == s);
4310 if (U_nonbottom_end < block_B->marked_nonbottom_begin)
4319 R_s_iter.block = block_B->
end;
4324 --R_s_iter.block; assert(part_tr.
pred.back().target != R_s_iter.block->st);
4327 R_t_iter = R_s_iter.block->st->pred_inert.begin,
4328 R_t_iter->
target == R_s_iter.block->st, ++R_t_iter)
4331 t(R_t_iter->
source); assert(U_nonbottom_end <= t->pos);
4332 assert(t->
pos->
st == t); assert(t->
pos < block_B->
end);
4333 if (t->
pos < untested_to_U_defined_end)
4339 *--untested_to_U_defined_end);
4349 check_complexity::split_R__handle_transition_to_R_state, 1U), *
this);
4352 check_complexity::split_R__find_predecessors_of_R_state,
4357 R_s_iter.block = block_B->
end;
4370 part_st.nr_of_blocks++);
4375 extend_from_marked_states__add_new_noninert_to_splitter ==
4376 mode, splitter_T, bisim_dnj::new_block_is_R);
4377 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4378 finalise_R_is_smaller(block_B, block_R, *
this);
4412 { assert(block_R == bbslice_Tprime_R->source_block());
4417 assert(!bbslice_R_tau_U->is_stable());
4418 assert(block_R == bbslice_R_tau_U->source_block());
4424 bool const next_splitter_is_of_same_block =
4428 block_N = split(block_R, bbslice_R_tau_U,
4429 extend_from_marked_states__add_new_noninert_to_splitter); assert(part_st.permutation.data() < block_N->
begin);
4436 if (next_splitter_is_of_same_block &&
4443 bbslice_T_Rprime->source_block() == block_Rprime)
4461 bbslice_Tprime_R = bbslice_R_tau_U;
4464 else if (bbslice_Tprime_R->source_block() != block_N)
4465 { assert(bbslice_Tprime_R->source_block() == block_Rprime);
4469 assert(!bbslice_Tprime_R->end->slice.is_null());
4472 bbslice_Tprime_R->end->slice; assert(bbslice_Tprime_R->source_block() == block_N);
4482 bbslice_R_tau_U->make_stable();
4484 block_Rprime =
nullptr;
4488 if (1 >= block_N->
size())
return block_Rprime;
4499 { assert(bbslice_T_N->is_stable());
4501 next_bbslice_T_N(std::next(bbslice_T_N));
4502 if (&*bbslice_T_N != &*bbslice_Tprime_R &&
4503 &*bbslice_T_N != &*bbslice_R_tau_U)
4512 bbslice_T_N->make_unstable();
4514 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4520 assert(!bbslice_T_N->work_counter.has_temporary_work());
4522 handle_new_noninert_transns__make_unstable_a_priori, 1U, *
this))
4524 handle_new_noninert_transns__make_unstable_temp, 1U), *
this);
4525 assert(bbslice_T_N->work_counter.has_temporary_work());
4526 assert(!bbslice_T_N->is_stable());
4529 bbslice_T_N = next_bbslice_T_N;
4540 s == succ_iter[-1].block_bunch->pred->source; )
4541 { assert(succ_iter[-1].begin_or_before_end < succ_iter);
4542 succ_iter = succ_iter[-1].begin_or_before_end; assert(
nullptr != succ_iter);
4543 assert(succ_iter->block_bunch->pred->action_block->succ == succ_iter);
4544 assert(s == succ_iter->block_bunch->pred->source);
4546 old_block_bunch_pos(succ_iter->block_bunch); assert(!old_block_bunch_pos->
slice.is_null());
4549 old_block_bunch_pos->
slice);
4550 if (!bbslice_T_N->is_stable())
4551 { assert(&*bbslice_T_N != &*bbslice_Tprime_R && bbslice_T_N != bbslice_R_tau_U);
4553 new_block_bunch_pos(bbslice_T_N->marked_begin - 1);
4556 if (old_block_bunch_pos <= new_block_bunch_pos)
4558 bbslice_T_N->marked_begin = new_block_bunch_pos; assert(new_block_bunch_pos->
slice == bbslice_T_N);
4562 block_bunch = old_block_bunch_pos; assert(new_block_bunch_pos->
pred->
action_block->
succ == succ_iter);
4563 succ_iter->block_bunch = new_block_bunch_pos;
4565 }
else assert(&*bbslice_T_N==&*bbslice_Tprime_R || bbslice_T_N==bbslice_R_tau_U);
4567 check_complexity::handle_new_noninert_transns, 1U), *
this);
4569 while (++s_iter < block_N->nonbottom_begin);
4571 return block_Rprime;
4576 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4577 namespace bisim_dnj {
4586 template <
class LTS_TYPE>
4591 if (
nullptr != block_U)
4593 unsigned const max_U_block(check_complexity::log_n -
4594 check_complexity::ilog2(block_U->
size()));
4597 assert(s_iter < block_U->end);
4602 check_complexity::split_U__find_predecessors_of_U_state,
4603 check_complexity::split__find_predecessors_of_R_or_U_state,
4604 max_U_block), partitioner);
4605 assert(s != partitioner.
part_tr.
pred.back().target);
4607 s == pred_iter->target; ++pred_iter)
4610 split_U__handle_transition_to_U_state,
4612 split__handle_transition_to_R_or_U_state,
4613 max_U_block), partitioner);
4618 assert(s != partitioner.
part_tr.
pred.front().target);
4620 s == (--pred_iter)->
target; )
4623 split_U__handle_transition_to_U_state,
4625 split__handle_transition_to_R_or_U_state,
4626 max_U_block), partitioner);
4631 s == (--succ_iter)->block_bunch->
pred->
source; )
4635 split_U__test_noninert_transitions,
4637 split__handle_transition_from_R_or_U_state,
4638 max_U_block), partitioner);
4641 while (++s_iter < block_U->end);
4646 assert(s_iter < block_R->end);
4651 split_R__find_predecessors_of_R_state), partitioner);
4652 assert(s != partitioner.
part_tr.
pred.back().target);
4654 s == pred_iter->target; ++pred_iter)
4657 split_R__handle_transition_to_R_state), partitioner);
4660 partitioner.
part_tr.
succ.front().block_bunch->pred->source);
4662 s == (--succ_iter)->block_bunch->
pred->
source; )
4666 split_R__handle_transition_from_R_state), partitioner);
4671 split_U__test_noninert_transitions,
4673 split__test_noninert_transitions_found_new_bottom_state,
4677 while (++s_iter < block_R->end);
4679 check_complexity::check_temporary_work();
4690 template <
class LTS_TYPE>
4695 unsigned const max_R_block(check_complexity::log_n -
4696 check_complexity::ilog2(block_R->
size()));
4699 assert(s_iter < block_U->end);
4704 split_U__find_predecessors_of_U_state), partitioner);
4705 assert(s != partitioner.
part_tr.
pred.back().target);
4707 s == pred_iter->target; ++pred_iter)
4710 split_U__handle_transition_to_U_state), partitioner);
4715 assert(s != partitioner.
part_tr.
pred.front().target);
4717 s == (--pred_iter)->
target; )
4720 split_U__handle_transition_to_U_state), partitioner);
4723 partitioner.
part_tr.
succ.front().block_bunch->pred->source);
4725 s == (--succ_iter)->block_bunch->
pred->
source; )
4729 split_U__test_noninert_transitions), partitioner);
4732 while (++s_iter < block_U->end);
4734 s_iter = block_R->
begin;
4735 assert(s_iter < block_R->end);
4740 check_complexity::split_R__find_predecessors_of_R_state,
4741 check_complexity::split__find_predecessors_of_R_or_U_state,
4742 max_R_block), partitioner);
4743 assert(s != partitioner.
part_tr.
pred.back().target);
4745 s == pred_iter->target; ++pred_iter)
4748 check_complexity::split_R__handle_transition_to_R_state,
4749 check_complexity::split__handle_transition_to_R_or_U_state,
4750 max_R_block), partitioner);
4753 partitioner.
part_tr.
succ.front().block_bunch->pred->source);
4755 s == (--succ_iter)->block_bunch->
pred->
source; )
4759 split_R__handle_transition_from_R_state,
4761 split__handle_transition_from_R_or_U_state,
4762 max_R_block), partitioner);
4767 split_U__test_noninert_transitions), partitioner);
4770 while (++s_iter < block_R->end);
4771 check_complexity::check_temporary_work();
4807template <
class LTS_TYPE>
4809 bool const preserve_divergence =
false)
4811 if (1 >= l.num_states())
4816 "not guaranteed that branching bisimulation minimisation runs "
4817 "in time O(m log n).\n";
4820 const std::clock_t start_SCC=std::clock();
4827 if (1 >= l.num_states())
return;
4831 const std::clock_t start_part=std::clock();
4834 preserve_divergence);
4837 const std::clock_t end_part=std::clock();
4843 const std::clock_t end_finalizing=std::clock();
4844 const int prec=std::lrint(std::log10(CLOCKS_PER_SEC)+0.19897000433602);
4850 runtime[0]=(double) (end_finalizing - start_SCC)/CLOCKS_PER_SEC;
4851 runtime[1]=(double) ( start_part-start_SCC)/CLOCKS_PER_SEC;
4852 runtime[2]=(double) ( bisim_part.
end_initial_part-start_part )/CLOCKS_PER_SEC;
4853 runtime[3]=(double) ( end_part-bisim_part.
end_initial_part )/CLOCKS_PER_SEC;
4854 runtime[4]=(double) (end_finalizing-end_part )/CLOCKS_PER_SEC;
4855 if (runtime[0]>=60.0)
4857 int min[
sizeof(runtime)/
sizeof(runtime[0])];
4858 for (
unsigned i = 0; i <
sizeof(runtime)/
sizeof(runtime[0]); ++i)
4860 min[i] = trunc(runtime[i] / 60.0);
4861 runtime[i] -= 60 *
min[i];
4865 int h[
sizeof(runtime)/
sizeof(runtime[0])];
4866 for (
unsigned i=0; i <
sizeof(runtime)/
sizeof(runtime[0]); ++i)
4871 int width = trunc(log10(h[0])) + 1;
4874 <<
"Time spent on contracting SCCs: " << std::setw(width) << h[1] <<
"h " << std::setw(2) <<
min[1] <<
"min " << std::setw(prec+3) << runtime[1] <<
"s\n"
4875 "Time spent on initial partition:" << std::setw(width) << h[2] <<
"h " << std::setw(2) <<
min[2] <<
"min " << std::setw(prec+3) << runtime[2] <<
"s\n"
4876 "Time spent on refining: " << std::setw(width) << h[3] <<
"h " << std::setw(2) <<
min[3] <<
"min " << std::setw(prec+3) << runtime[3] <<
"s\n"
4877 "Time spent on finalizing: " << std::setw(width) << h[4] <<
"h " << std::setw(2) <<
min[4] <<
"min " << std::setw(prec+3) << runtime[4] <<
"s\n"
4878 "Total CPU time: " << std::setw(width) << h[0] <<
"h " << std::setw(2) <<
min[0] <<
"min " << std::setw(prec+3) << runtime[0] <<
"s\n"
4879 << std::defaultfloat;
4884 <<
"Time spent on contracting SCCs: " << std::setw(2) <<
min[1] <<
"min " << std::setw(prec+3) << runtime[1] <<
"s\n"
4885 "Time spent on initial partition:" << std::setw(2) <<
min[2] <<
"min " << std::setw(prec+3) << runtime[2] <<
"s\n"
4886 "Time spent on refining: " << std::setw(2) <<
min[3] <<
"min " << std::setw(prec+3) << runtime[3] <<
"s\n"
4887 "Time spent on finalizing: " << std::setw(2) <<
min[4] <<
"min " << std::setw(prec+3) << runtime[4] <<
"s\n"
4888 "Total CPU time: " << std::setw(2) <<
min[0] <<
"min " << std::setw(prec+3) << runtime[0] <<
"s\n"
4889 << std::defaultfloat;
4895 <<
"Time spent on contracting SCCs: " << std::setw(prec+3) << runtime[1] <<
"s\n"
4896 "Time spent on initial partition:" << std::setw(prec+3) << runtime[2] <<
"s\n"
4897 "Time spent on refining: " << std::setw(prec+3) << runtime[3] <<
"s\n"
4898 "Time spent on finalizing: " << std::setw(prec+3) << runtime[4] <<
"s\n"
4899 "Total CPU time: " << std::setw(prec+3) << runtime[0] <<
"s\n"
4900 << std::defaultfloat;
4925template <
class LTS_TYPE>
4927 bool const branching =
false,
bool const preserve_divergence =
false,
4928 bool const generate_counter_examples =
false,
4929 const std::string& =
"",
4932 if (generate_counter_examples)
4935 "algorithm does not generate counterexamples.\n";
4937 std::size_t init_l2(l2.initial_state() + l1.num_states());
4938 detail::merge(l1, std::move(l2));
4947 }
else assert(!preserve_divergence);
4948 assert(1 < l1.num_states());
4950 preserve_divergence);
4952 return bisim_part.
in_same_class(l1.initial_state(), init_l2);
4972template <
class LTS_TYPE>
4974 bool const branching =
false,
bool const preserve_divergence =
false)
4976 LTS_TYPE l1_copy(l1);
4977 LTS_TYPE l2_copy(l2);
4979 preserve_divergence);
helper class for time complexity checks during test runs
#define mCRL2complexity(unit, call, info_for_debug)
Assigns work to a counter and checks for errors.
Read-only balanced binary tree of terms.
iterator begin() const
Returns an iterator pointing to the beginning of the term_balanced_tree.
information about a transition sorted per (action, target block) pair
action_block_entry * begin_or_before_end
pointer to delimit the slice of transitions in the same (action, block) pair
succ_entry * succ
circular iterator to link the four transition arrays
action_block_entry * action_block_slice_begin(ONLY_IF_DEBUG(const action_block_entry *const action_block_begin, const action_block_entry *const action_block_orig_inert_begin))
find the beginning of the action_block-slice
information about a transition grouped per (source block, bunch) pair
block_bunch_slice_iter_or_null_t slice
block_bunch-slice of which this transition is part
pred_entry * pred
circular iterator to link the four transition arrays
Information about a set of transitions with the same source block, in the same bunch.
void make_unstable()
register that the block_bunch-slice is not stable
bool is_stable() const
returns true iff the block_bunch-slice is registered as stable
bool empty() const
returns true iff the block_bunch-slice is empty
check_complexity::block_bunch_dnj_counter_t work_counter
bool add_work_to_bottom_transns(enum check_complexity::counter_type const ctr, unsigned const max_value, const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
add work to transitions starting in bottom states
block_bunch_slice_t(block_bunch_entry *const new_end, bunch_t *const new_bunch, bool const new_is_stable)
constructor
bunch_t * bunch
bunch to which this slice belongs
std::string debug_id(const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
print a block_bunch-slice identification for debugging
block_bunch_entry * end
pointer past the end of the transitions in the block_bunch array
void make_stable()
register that the block_bunch-slice is stable
block_bunch_entry * marked_begin
pointer to the first marked transition in the block_bunch array
block_t * source_block() const
compute the source block of the transitions in this slice
stores information about a block
std::string debug_id(const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
print a block identification for debugging
state_type size() const
provides the number of states in the block
permutation_entry * nonbottom_begin
iterator to the first non-bottom state of the block
permutation_entry * begin
iterator to the first state of the block
bool mark_nonbottom(permutation_entry *const s)
mark a non-bottom state
check_complexity::block_dnj_counter_t work_counter
permutation_entry * marked_bottom_begin
iterator to the first marked bottom state of the block
state_type marked_size() const
provides the number of marked states in the block
state_type marked_bottom_size() const
provides the number of marked bottom states in the block
permutation_entry * end
iterator past the last state of the block
simple_list< block_bunch_slice_t > stable_block_bunch
list of stable block_bunch-slices with transitions from this block
state_type unmarked_bottom_size() const
provides the number of unmarked bottom states in the block
state_type bottom_size() const
provides the number of bottom states in the block
bool mark(permutation_entry *const s)
mark a state
const state_type seqnr
unique sequence number of this block
permutation_entry * marked_nonbottom_begin
iterator to the first marked non-bottom state of the block
block_t(permutation_entry *const new_begin, permutation_entry *const new_end, state_type const new_seqnr)
constructor
state_type unmarked_nonbottom_size() const
provides the number of unmarked nonbottom states in the block
action_block_entry * end
pointer past the last transition in the bunch
std::string debug_id(const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
print a long bunch identification for debugging
std::string debug_id_short(const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
print a short bunch identification for debugging
union mcrl2::lts::detail::bisim_dnj::bunch_t::next_nontrivial_and_label_t next_nontrivial_and_label
action_block_entry * begin
first transition in the bunch
int max_work_counter(const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
calculates the maximal allowed value for work counters associated with this bunch
check_complexity::bunch_dnj_counter_t work_counter
bool is_trivial() const
returns true iff the bunch is trivial
bunch_t(action_block_entry *const new_begin, action_block_entry *const new_end)
constructor
refinable partition data structure
void assert_consistency(const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
asserts that the partition of states is consistent
fixed_vector< state_info_entry > state_info
array with all other information about states
~part_state_t()
destructor
state_type nr_of_blocks
total number of blocks with unique sequence number allocated
void print_block(const block_t *const B, const char *const message, const permutation_entry *begin_print, const permutation_entry *const end_print, const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
print a slice of the partition (typically a block)
permutation_t permutation
permutation array
const block_t * block(state_type const s) const
find the block of a state
part_state_t(state_type const num_states)
constructor
state_type state_size() const
calculate the size of the state space
void print_part(const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
print the partition per block
fixed_vector< pred_entry > pred
array containing all predecessor entries
state_type nr_of_new_bottom_states
number of new bottom states found until now.
action_block_entry * action_block_inert_begin
pointer to the first inert transition in action_block
trans_type nr_of_nontrivial_bunches
fixed_vector< block_bunch_entry > block_bunch
array containing all block_bunch entries
block_bunch_entry * block_bunch_inert_begin
pointer to the first inert transition in block_bunch
~part_trans_t()
destructor
const action_block_entry * action_block_orig_inert_begin
pointer to the first inert transition in the initial partition
void second_move_transition_to_new_action_block(pred_entry *const pred_iter)
handle one transition after a block has been split, phase 2
fixed_vector< succ_entry > succ
array containing all successor entries
succ_entry * move_out_slice_to_new_block(succ_entry *out_slice_end, ONLY_IF_DEBUG(const bisim_partitioner_dnj< LTS_TYPE > &partitioner,) block_t *const old_block, block_bunch_slice_const_iter_t const splitter_T)
Adapt the non-inert transitions in an out-slice to a new block.
bool make_noninert(pred_entry *const old_pred_pos, block_bunch_slice_iter_or_null_t *const new_noninert_block_bunch_ptr)
adapt data structures for a transition that has become non-inert
part_trans_t(trans_type num_transitions, trans_type num_actions)
constructor
void print_trans(const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
print all transitions
simple_list< block_bunch_slice_t > splitter_list
list of unstable block_bunch-slices
trans_type nr_of_block_bunch_slices
void first_move_transition_to_new_bunch(action_block_entry *const action_block_iter, bunch_t *const bunch_T_a_Bprime, bool const first_transition_of_state)
transition is moved to a new bunch
trans_type nr_of_action_block_slices
void make_nontrivial(bunch_t *const bunch)
insert a bunch into the list of nontrivial bunches
fixed_vector< action_block_entry > action_block
array containing all action_block entries
void adapt_transitions_for_new_block(block_t *const new_block, block_t *const old_block, ONLY_IF_DEBUG(const bisim_partitioner_dnj< LTS_TYPE > &partitioner,) bool const add_new_noninert_to_splitter, const block_bunch_slice_iter_t splitter_T, enum new_block_mode_t const new_block_mode)
Split all data structures after a new block has been created.
bunch_t * get_some_nontrivial()
provide some bunch from the list of non-trivial bunches
void first_move_transition_to_new_action_block(pred_entry *const pred_iter)
handle one transition after a block has been split
trans_type nr_of_bunches
counters to measure progress
void make_trivial(bunch_t *const bunch)
remove a bunch from the list of nontrivial bunches
void second_move_transition_to_new_bunch(action_block_entry *const action_block_iter, ONLY_IF_DEBUG(const bisim_partitioner_dnj< LTS_TYPE > &partitioner, bunch_t *const bunch_T_a_Bprime,) bunch_t *const large_splitter_bunch)
transition is moved to a new bunch, phase 2
bunch_t * first_nontrivial
pointer to first non-trivial bunch
entry in the permutation array
permutation_entry(const permutation_entry &&other) noexcept
move constructor
permutation_entry()=default
default constructor (should not be deleted)
void operator=(const permutation_entry &&other) noexcept
move assignment operator
state_info_entry * st
pointer to the state information data structure
information about a transition sorted per target state
state_info_entry * target
target state of the transition
action_block_entry * action_block
circular iterator to link the four transition arrays
std::string debug_id_short(const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
print a short transition identification for debugging
state_info_entry * source
source state of the transition
std::string debug_id(const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
print a transition identification for debugging
check_complexity::trans_dnj_counter_t work_counter
stores information about a single state
permutation_entry * pos
position of the state in the permutation array
iterator_or_counter< pred_entry * > pred_inert
iterator to first inert incoming transition
union mcrl2::lts::detail::bisim_dnj::state_info_entry::bl_t bl
check_complexity::state_dnj_counter_t work_counter
std::string debug_id_short(const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
print a short state identification for debugging
iterator_or_counter< succ_entry * > untested_to_U_eqv
number of inert transitions to non-U-states
iterator_or_counter< succ_entry * > succ_inert
iterator to first inert outgoing transition
std::string debug_id(const bisim_partitioner_dnj< LTS_TYPE > &partitioner) const
print a state identification for debugging
information about a transition sorted per source state
succ_entry * begin_or_before_end
pointer to delimit the slice of transitions in the same bunch
block_bunch_entry * block_bunch
circular iterator to link the four transition arrays
implements the main algorithm for the branching bisimulation quotient
void refine_partition_until_it_becomes_stable()
Run (branching) bisimulation minimisation in time O(m log n)
state_type num_eq_classes() const
Calculate the number of equivalence classes.
void create_initial_partition()
Create a partition satisfying the main invariant.
bool in_same_class(state_type const s, state_type const t) const
Check whether two states are in the same equivalence class.
bisim_dnj::block_t * handle_new_noninert_transns(bisim_dnj::block_t *const block_R, bisim_dnj::block_bunch_slice_const_iter_t bbslice_Tprime_R)
Handle a block with new non-inert transitions.
void assert_stability() const
assert that the data structure is consistent and stable
bisim_dnj::part_trans_t part_tr
partitions of the transitions (with bunches and action_block-slices)
LTS_TYPE & aut
automaton that is being reduced
state_type get_eq_class(state_type const s) const
Get the equivalence class of a state.
bisim_dnj::block_t * split(bisim_dnj::block_t *const block_B, const bisim_dnj::block_bunch_slice_iter_t splitter_T, enum refine_mode_t mode)
Split a block according to a splitter.
void finalize_minimized_LTS()
Adapt the LTS after minimisation.
std::clock_t end_initial_part
time measurement after the end of create_initial_partition()
bisim_partitioner_dnj(LTS_TYPE &new_aut, bool const new_branching=false, bool const new_preserve_divergence=false)
constructor
bool const branching
true iff branching (not strong) bisimulation has been requested
refine_mode_t
modes that determine details of how split() should work
@ extend_from_marked_states
@ extend_from_marked_states__add_new_noninert_to_splitter
bisim_dnj::part_state_t part_st
partition of the state space into blocks
bool const preserve_divergence
true iff divergence-preserving branching bisimulation has been requested
fixed_vector< bisim_dnj::iterator_or_counter< bisim_dnj::action_block_entry * > > action_label
action label slices
class for time complexity checks
static int ilog2(state_type size)
calculate the base-2 logarithm, rounded down
static unsigned char log_n
value of floor(log2(n)) for easy access
counter_type
Type for complexity budget counters.
@ move_out_slice_to_new_block
This class contains an scc partitioner removing inert tau loops.
std::size_t get_eq_class(const std::size_t s) const
Gives the equivalence class number of a state. The equivalence class numbers range from 0 upto (and e...
void replace_transition_system(const bool preserve_divergence_loops)
The lts for which this partioner is created is replaced by the lts modulo the calculated partition.
constant iterator class for simple_list
iterator class for simple_list
a simple implementation of lists
static my_pool< entry > & get_pool()
A class containing triples, source label and target representing transitions.
helper macros for coroutines
#define ABORT_THIS_COROUTINE()
indicates that this coroutine gives up control to the other one
#define END_COROUTINE
Ends the definition of code for a coroutine.
#define ABORT_OTHER_COROUTINE()
indicates that the other coroutine should give up control
#define COROUTINE_FOR(location, init, condition, update)
a for loop where every iteration incurs one unit of work
#define COROUTINE_WHILE(location, condition)
a while loop where every iteration incurs one unit of work
#define COROUTINES_SECTION
begin a section with two coroutines
#define COROUTINE_DO_WHILE(location, condition)
a do { } while loop where every iteration incurs one unit of work
#define END_COROUTINES_SECTION
Close a section containing coroutines.
#define COROUTINE
Define the code for a coroutine.
#define END_COROUTINE_WHILE
ends a loop started with COROUTINE_WHILE
#define END_COROUTINE_FOR
ends a loop started with COROUTINE_FOR
#define COROUTINE_LABELS(locations)
Declare the interrupt locations for the coroutines.
#define END_COROUTINE_DO_WHILE
ends a loop started with COROUTINE_DO_WHILE
#define TERMINATE_COROUTINE_SUCCESSFULLY()
terminate the pair of coroutines successfully
a vector class that cannot be moved while it is not empty
bool bisimulation_compare_dnj(const LTS_TYPE &l1, const LTS_TYPE &l2, bool const branching=false, bool const preserve_divergence=false)
Checks whether the two initial states of two LTSs are strong or (divergence-preserving) branching bis...
bool destructive_bisimulation_compare_dnj(LTS_TYPE &l1, LTS_TYPE &l2, bool const branching=false, bool const preserve_divergence=false, bool const generate_counter_examples=false, const std::string &="", bool=false)
Checks whether the two initial states of two LTSs are strong or (divergence-preserving) branching bis...
void bisimulation_reduce_dnj(LTS_TYPE &l, bool const branching=false, bool const preserve_divergence=false)
Reduce transition system l with respect to strong or (divergence-preserving) branching bisimulation.
fixed_vector< permutation_entry > permutation_t
iterator_or_null_t< block_bunch_slice_t > block_bunch_slice_iter_or_null_t
simple_list< block_bunch_slice_t >::iterator block_bunch_slice_iter_t
simple_list< block_bunch_slice_t >::const_iterator block_bunch_slice_const_iter_t
bunch_t * split_off_small_action_block_slice(part_trans_t &part_tr)
split off a single action_block-slice from the bunch
succ_entry * out_slice_begin(ONLY_IF_DEBUG(const fixed_vector< succ_entry > &succ))
find the beginning of the out-slice
block_t * split_off_block(enum new_block_mode_t new_block_mode, ONLY_IF_DEBUG(const bisim_partitioner_dnj< LTS_TYPE > &partitioner,) state_type new_seqnr)
refine a block
static void add_work_to_out_slice(const bisim_partitioner_dnj< LTS_TYPE > &partitioner, const succ_entry *out_slice_begin, enum check_complexity::counter_type ctr, unsigned max_value)
assign work to the transitions in an out-slice (i.e. the transitions from one state in a specific bun...
bunch_t * bunch() const
find the bunch of the transition
#define PRINT_SG_PL(counter, sg_string, pl_string)
#define ONLY_IF_DEBUG(...)
include something in Debug mode
#define PRINT_INT_PERCENTAGE(num, denom)
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
std::string pp(const atermpp::aterm &t)
Transform an aterm to an ascii string.
std::string pp(const detail::lhs_t &lhs)
data_expression min(const data_expression &e1, const data_expression &e2, const rewriter &)
atermpp::term_balanced_tree< data::data_expression > state
static struct mcrl2::lts::detail::bisim_dnj::@1 action_label_greater
static void finalise_U_is_smaller(const block_t *const block_U, const block_t *const block_R, const bisim_partitioner_dnj< LTS_TYPE > &partitioner)
moves temporary work counters to normal ones if the U-block is smaller
static void finalise_R_is_smaller(const block_t *const block_U, const block_t *const block_R, const bisim_partitioner_dnj< LTS_TYPE > &partitioner)
moves temporary work counters to normal ones if the R-block is smaller
std::size_t state_type
type used to store state (numbers and) counts
typename simple_list< El >::iterator_or_null iterator_or_null_t
std::size_t label_type
type used to store label numbers and counts
std::size_t trans_type
type used to store transition (numbers and) counts
void sort_transitions(std::vector< transition > &transitions, const std::set< transition::size_type > &hidden_label_set, transition_sort_style ts=src_lbl_tgt)
Sorts the transitions using a sort style.
std::size_t label(const outgoing_pair_t &p)
Label of a pair of a label and target state.
void scc_reduce(LTS_TYPE &l, const bool preserve_divergence_loops=false)
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
void swap(atermpp::unprotected_aterm_core &t1, atermpp::unprotected_aterm_core &t2) noexcept
Swaps two aterms.
Simple list implementation (with pool allocator)
#define USE_POOL_ALLOCATOR
pointer to next non-trivial bunch (in the single-linked list) or label
label_type label
action label of the transition
next_nontrivial_and_label_t()
constructor
bunch_t * next_nontrivial
pointer to the next non-trivial bunch in the single-linked list
union: either iterator or counter (for initialisation)
iterator_or_counter()
Construct the object as a counter.
trans_type count
counter (used during initialisation)
Iterator begin
iterator (used during main part of the algorithm)
~iterator_or_counter()
Destruct the object as an iterator.
void convert_to_iterator(const Iterator other)
Convert the object from counter to iterator.
block where the state belongs
pred_entry * ed_noninert_end