81#ifndef LIBLTS_BISIM_DNJ_H
82#define LIBLTS_BISIM_DNJ_H
106 #define ONLY_IF_DEBUG(...) __VA_ARGS__
108 #define ONLY_IF_DEBUG(...)
131template <
class Iterator>
147 new (&
begin) Iterator(other);
156class block_bunch_entry;
157class action_block_entry;
181class state_info_entry;
182class permutation_entry;
267 template<
class LTS_TYPE>
276 template<
class LTS_TYPE>
387 { assert(new_begin < new_end);
466 { assert(
begin <= s);
496 template<
class LTS_TYPE>
508 ") (#" + std::to_string(
seqnr) +
")";
547 { assert(0 < num_states);
549 static_assert(std::is_trivially_destructible<block_t>::value); )
553 state_iter->pos = perm_iter;
554 perm_iter->
st = state_iter;
556 while (++state_iter, ++perm_iter <= &
permutation.back()); assert(state_iter == 1 + &
state_info.back());
560 #ifndef USE_POOL_ALLOCATOR
571 block_t*
const B(perm_iter[-1].st->bl.ock); assert(B->
end == perm_iter);
601 template<
class LTS_TYPE>
603 const char*
const message,
607 { assert(B->
begin <= begin_print); assert(end_print <= B->end);
608 if (end_print == begin_print)
return;
611 << (1 < end_print - begin_print ?
"s:\n" :
":\n");
612 assert(begin_print < end_print);
617 if (B != begin_print->
st->
bl.
ock)
622 if (begin_print != begin_print->
st->
pos)
625 <<
", inconsistent pointer to state_info_entry";
629 while (++begin_print < end_print);
636 template<
class LTS_TYPE>
660 template<
class LTS_TYPE>
692 if (perm_iter < block->nonbottom_begin)
713 assert(perm_iter ==
state->pos);
715 while (++perm_iter < block->end);
732 bool operator()(
const iterator_or_counter<action_block_entry*> p1,
733 const action_block_entry*
const action_block)
const
735 return p1.begin > action_block;
814 template <
class LTS_TYPE>
855 template <
class LTS_TYPE>
864 template <
class LTS_TYPE>
878 return pp(partitioner.
aut.action_label(
label)) +
"-transition " +
924 assert(
nullptr !=
succ); assert(
nullptr != result->
succ);
926 assert(result == action_block_begin ||
nullptr == result[-1].
succ ||
927 action_block_orig_inert_begin <= result ||
1004 template <
class LTS_TYPE>
1010 return "bunch [" + std::to_string(
begin -
1016 template <
class LTS_TYPE>
1019 { assert(
nullptr !=
end[-1].succ);
1021 assert(
nullptr != iter->
succ);
1024 result +=
" containing transition";
1025 result += iter <
end - 1 ?
"s " :
" ";
1028 if (
end <= iter)
return result;
1029 while (
nullptr == iter->
succ) ++iter;
1039 while (++iter <
end)
1041 if (
nullptr != iter->
succ)
1056 template <
class LTS_TYPE>
1136 bunch_t*
const new_bunch,
bool const new_is_stable)
1163 template <
class LTS_TYPE>
1171 return p1.
slice != p2;
1173 }
const block_bunch_not_equal;
1177 std::string
const index_string(std::to_string(
end -
1181 return "empty block_bunch_slice [" + index_string +
"," +
1189 begin =
end - bunch_size;
1193 this, block_bunch_not_equal);
1194 assert(begin->
slice ==
this);
1195 assert(begin[-1].slice !=
this);
1196 return (
is_stable() ?
"stable block_bunch-slice ["
1197 :
"unstable block_bunch_slice [") +
1199 "," + index_string +
") containing transitions from " +
1211 template <
class LTS_TYPE>
1213 counter_type const ctr, unsigned const max_value,
1216 assert(1U == max_value);
1220 assert(partitioner.part_tr.block_bunch.front().slice !=
this);
1221 assert(block_bunch[-1].slice ==
this);
1226 assert(source->
bl.
ock == block);
1227 if (source->
pos < block->nonbottom_begin
1237 while (block_bunch[-1].slice ==
this);
1260 assert(&succ.cbegin()[1] == result ||
1281 template <
class LTS_TYPE>
1287 const succ_entry*
const out_slice_before_end(
1289 assert(
nullptr != out_slice_before_end);
1292 add_work(ctr, max_value), partitioner);
1297 add_work_notemporary(ctr, max_value), partitioner);
1352 #ifdef USE_POOL_ALLOCATOR
1353 static_assert(std::is_trivially_destructible<bunch_t>::value);
1354 static_assert(std::is_trivially_destructible<
1379 :
succ(num_transitions + 2),
1381 pred(num_transitions + 2),
1399 pred.front().source =
nullptr;
1400 pred.front().target =
nullptr;
1401 pred.back() .source =
nullptr;
1402 pred.back() .target =
nullptr;
1409 #ifndef USE_POOL_ALLOCATOR
1428 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
1577 new_block_bunch_pos + 1, bunch_T_a_Bprime,
false);
1580 bunch_T_a_Bprime,
false);
1584 old_block_bunch_slice->work_counter; )
1587 old_block_bunch_slice->make_unstable();
1588 } assert(!new_block_bunch_slice->is_stable());
1591 if (old_block_bunch_pos < new_block_bunch_pos)
1597 }
else assert(new_block_bunch_pos == old_block_bunch_pos);
1598 assert(new_block_bunch_pos->
slice == old_block_bunch_slice);
1599 new_block_bunch_pos->
slice = new_block_bunch_slice;
1601 assert(new_block_bunch_pos + 1 == old_block_bunch_slice->marked_begin);
1602 old_block_bunch_slice->end = new_block_bunch_pos;
1603 old_block_bunch_slice->marked_begin = new_block_bunch_pos; assert(
nullptr != new_block_bunch_pos);
1604 if (old_block_bunch_slice->empty())
1605 { assert(!old_block_bunch_slice->is_stable());
1607 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.front() ||
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.front() ||
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.front() ||
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.front() ||
1735 bunch_T_a_Bprime != new_block_bunch_pos->
slice->bunch);
1771 #ifndef USE_SIMPLE_LIST
1775 { assert(&
succ.cbegin()[1] < out_slice_end);
1777 out_slice_end[-1].begin_or_before_end); assert(
nullptr != out_slice_begin);
1778 assert(out_slice_begin < out_slice_end);
1782 assert(!old_block_bunch_pos->
slice.is_null());
1785 old_block_bunch_pos);
1786 if (&*splitter_T == &*old_block_bunch_slice)
return out_slice_begin;
1789 old_block_bunch_slice->end);
1791 assert(&partitioner.part_st.state_info.front() == source ||
1792 source[-1].
succ_inert.begin < out_slice_end);
1798 old_block_bunch_slice_end->
slice, assert(!old_block_bunch_slice_end->
slice.is_null()),
1799 old_block_bunch_slice->bunch != new_block_bunch_slice->bunch))
1803 if (old_block_bunch_slice->is_stable())
1806 #ifdef USE_SIMPLE_LIST
1807 new_block_bunch_slice =
1810 old_block_bunch_slice->end,
1811 old_block_bunch_slice->bunch,
true);
1814 old_block_bunch_slice->end,
1815 old_block_bunch_slice->bunch,
true);
1816 new_block_bunch_slice =
1822 #ifdef USE_SIMPLE_LIST
1825 old_block_bunch_slice,
1826 old_block_bunch_slice->end,
1827 old_block_bunch_slice->bunch,
false);
1830 std::next(old_block_bunch_slice),
1831 old_block_bunch_slice->end,
1832 old_block_bunch_slice->bunch,
false);
1836 old_block_bunch_slice->work_counter; )
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 #ifdef USE_SIMPLE_LIST
1914 old_block_bunch_slice);
1916 if (old_block_bunch_slice->is_stable())
1941 return out_slice_begin;
1961 )); assert(
nullptr != action_block_slice_begin->
succ);
1963 action_block_slice_begin);
1967 assert(
nullptr != new_action_block_pos->
succ);
1969 new_action_block_pos);
1970 if (old_action_block_pos < new_action_block_pos)
1972 succ_entry*
const temp(new_action_block_pos->
succ); assert(
nullptr != temp); assert(
nullptr != old_action_block_pos->
succ);
1973 new_action_block_pos->
succ = old_action_block_pos->
succ;
1974 old_action_block_pos->
succ = temp;
1980 new_action_block_pos - 1;
1983 { assert(old_action_block_pos == new_action_block_pos);
1984 if (action_block_slice_begin < new_action_block_pos)
1990 new_action_block_pos - 1;
1993 } assert(
nullptr != new_action_block_pos->
succ);
2001 nullptr == new_action_block_pos[1].
succ ||
2002 new_action_block_pos[1].
succ->bunch() !=
2015 new_action_block_pos[1].begin_or_before_end); assert(
nullptr != action_block_slice_before_end);
2016 assert(new_action_block_pos < action_block_slice_before_end);
2017 assert(
nullptr != action_block_slice_before_end->
succ);
2019 action_block_slice_before_end);
2020 assert(new_action_block_pos + 1 ==
2023 new_action_block_pos; assert(action_block_slice_before_end->
succ->
block_bunch->
2045 assert(
nullptr != old_begin_or_before_end->
succ);
2047 old_begin_or_before_end);
2049 old_begin_or_before_end->
begin_or_before_end); assert(
nullptr != new_begin_or_before_end),
2050 assert(
nullptr != new_begin_or_before_end->succ),
2051 assert(new_begin_or_before_end->succ->block_bunch->pred->action_block ==
2052 new_begin_or_before_end),
2053 new_begin_or_before_end < new_action_block_pos)
2056 new_begin_or_before_end; assert(new_action_block_pos <= old_begin_or_before_end);
2058 }
else assert(new_begin_or_before_end == new_action_block_pos);
2059 if (old_begin_or_before_end < new_action_block_pos)
return;
2064 if (!bunch->
is_trivial()) {
return; } assert(old_begin_or_before_end + 1 == bunch->
end);
2065 if (bunch->
begin < new_action_block_pos)
2105 new_action_block_pos);
2110 new_block_bunch_pos);
2112 old_pred_pos->
action_block); assert(new_action_block_pos <= old_action_block_pos);
2114 succ_entry*
const old_succ_pos(old_action_block_pos->
succ); assert(
nullptr != old_succ_pos);
2116 old_succ_pos->
block_bunch); assert(old_pred_pos == old_block_bunch_pos->
pred);
2121 if (new_action_block_pos < old_action_block_pos)
2123 old_action_block_pos->
succ = new_action_block_pos->
succ; assert(
nullptr != old_action_block_pos->
succ);
2125 new_action_block_pos);
2127 old_action_block_pos;
2128 }
else assert(new_action_block_pos == old_action_block_pos);
2129 new_action_block_pos->
succ = new_succ_pos; assert(
nullptr != new_succ_pos);
2133 if (new_succ_pos < old_succ_pos)
2137 }
else assert(new_succ_pos == old_succ_pos);
2141 assert(new_block_bunch_pos->
slice.is_null());
2142 if (new_block_bunch_pos < old_block_bunch_pos)
2143 { assert(old_block_bunch_pos->
slice.is_null());
2146 new_block_bunch_pos);
2149 old_block_bunch_pos;
2150 }
else assert(new_block_bunch_pos == old_block_bunch_pos);
2151 new_block_bunch_pos->
pred = new_pred_pos;
2155 if (new_pred_pos < old_pred_pos)
2162 }
else assert(new_pred_pos == old_pred_pos);
2166 bool became_bottom(
false); assert(
succ.back().block_bunch->pred->source != source);
2167 if (source != source->
succ_inert.begin->block_bunch->pred->source)
2178 became_bottom =
true;
2181 bunch_t* new_noninert_bunch; assert(
nullptr != new_action_block_pos);
2182 if (!new_noninert_block_bunch_ptr->is_null())
2191 new_noninert_bunch = (*new_noninert_block_bunch_ptr)->bunch; assert(new_action_block_pos >= new_noninert_bunch->
end);
2194 temp_action_block_pos > new_noninert_bunch->
end ; )
2196 assert(
nullptr == (--temp_action_block_pos)->
succ);
2200 assert((*new_noninert_block_bunch_ptr)->end == new_block_bunch_pos);
2202 if (!(*new_noninert_block_bunch_ptr)->is_stable())
2203 { assert((*new_noninert_block_bunch_ptr)->marked_begin == new_block_bunch_pos);
2204 (*new_noninert_block_bunch_ptr)->marked_begin =
2207 new_block_bunch_pos->
slice = *new_noninert_block_bunch_ptr;
2209 assert(new_noninert_bunch->
begin < new_action_block_pos);
2210 if (
nullptr != new_action_block_pos[-1].
succ &&
2211 target->bl.ock == new_action_block_pos[-1].
2212 succ->block_bunch->pred->target->bl.ock)
2216 new_action_block_pos[-1].begin_or_before_end); assert(
nullptr != action_block_slice_begin);
2218 assert(
nullptr != action_block_slice_begin->
succ);
2220 action_block_slice_begin);
2222 new_action_block_pos;
2224 action_block_slice_begin;
2241 iter < new_noninert_bunch->
begin; ++iter)
2243 assert(
nullptr == iter->succ);
2244 assert(
nullptr == iter->begin_or_before_end);
2251 assert(source !=
succ.front().block_bunch->pred->source);
2252 if (source == new_succ_pos[-1].
block_bunch->pred->source &&
2253 new_succ_pos[-1].
bunch() == new_noninert_bunch)
2257 new_succ_pos[-1].begin_or_before_end); assert(
nullptr != out_slice_begin);
2262 return became_bottom;
2268 new_noninert_bunch =
2269 #ifdef USE_POOL_ALLOCATOR
2270 storage.template construct<bunch_t>
2278 #ifdef USE_SIMPLE_LIST
2285 new_noninert_bunch,
false);
2290 new_block_bunch_pos->
slice = new_noninert_block_bunch;
2291 *new_noninert_block_bunch_ptr = new_noninert_block_bunch;
2294 new_action_block_pos->begin_or_before_end = new_action_block_pos;
2296 } assert(&
succ.cbegin()[1] == new_succ_pos ||
2298 new_succ_pos[-1].
bunch() != new_noninert_bunch);
2300 return became_bottom;
2330 bool const add_new_noninert_to_splitter,
2333 { assert(splitter_T->is_stable());
2340 assert(s->
pos == s_iter);
2342 assert(s !=
succ.front().block_bunch->pred->source);
2344 s == succ_iter[-1].block_bunch->pred->source; )
2350 splitter_T); assert(succ_iter->block_bunch->pred->action_block->succ == succ_iter);
2351 assert(s == succ_iter->block_bunch->pred->source);
2356 assert(s !=
pred.front().target);
2358 s == (--pred_iter)->
target; )
2359 { assert(&
pred.front() < pred_iter);
2360 assert(
nullptr != pred_iter->action_block->succ);
2361 assert(pred_iter->action_block->succ->block_bunch->pred == pred_iter);
2365 while (++s_iter < new_block->end);
2368 { assert(splitter_T->source_block() == new_block);
2371 new_block->stable_block_bunch.splice(
2372 new_block->stable_block_bunch.begin(),
2373 old_block->stable_block_bunch, splitter_T);
2374 }
else assert(splitter_T->source_block() == old_block);
2379 s_iter = new_block->begin; assert(s_iter < new_block->end);
2384 s == (--pred_iter)->
target; )
2385 { assert(&
pred.front() < pred_iter);
2386 assert(
nullptr != pred_iter->action_block->succ);
2387 assert(pred_iter->action_block->succ->block_bunch->pred == pred_iter);
2391 while (++s_iter < new_block->end);
2392 assert(0 == new_block->marked_size()); assert(0 == old_block->marked_size());
2398 if (add_new_noninert_to_splitter)
2400 new_noninert_block_bunch = splitter_T;
2404 new_noninert_block_bunch =
nullptr;
2407 { assert(old_block == new_block->end->st->bl.ock);
2408 assert(new_block->end <= &partitioner.part_st.permutation.back());
2409 permutation_entry* target_iter(new_block->begin); assert(target_iter < new_block->end);
2414 assert(s !=
pred.back().target);
2416 s == pred_iter->target; ++pred_iter)
2417 { assert(pred_iter < &
pred.back());
2418 assert(
nullptr != pred_iter->action_block->succ);
2419 state_info_entry*
const t(pred_iter->source); assert(pred_iter->action_block->succ->block_bunch->pred == pred_iter);
2420 assert(t->
pos->
st == t);
2421 if (new_block != t->
bl.
ock)
2422 { assert(old_block == t->
bl.
ock);
2424 &new_noninert_block_bunch))
2427 old_block->mark_nonbottom(t->
pos);
2433 while (++target_iter < new_block->end); assert(0 < old_block->bottom_size());
2437 assert(&partitioner.part_st.permutation.front() < new_block->begin);
2438 assert(old_block == new_block->begin[-1].st->bl.ock);
2439 assert(0 < old_block->bottom_size());
2441 source_iter < new_block->marked_nonbottom_begin; )
2445 assert(
succ.back().block_bunch->pred->source != s);
2455 &new_noninert_block_bunch);
2459 while (s == (++succ_iter)->
block_bunch->pred->source);
2460 if (dont_mark) ++source_iter;
2462 { assert(s->
pos == source_iter);
2463 new_block->mark_nonbottom(source_iter);
2464 } assert(new_block->nonbottom_begin <= source_iter);
2476 template <
class LTS_TYPE>
2482 if (succ_iter >= &
succ.back())
2494 { assert(source < succ_iter->
block_bunch->pred->source);
2497 << source->
debug_id(partitioner) <<
":\n";
2502 { assert(!current_out_bunch.is_null());
2504 { assert(succ_iter == source->
succ_inert.begin);
2506 current_out_bunch =
nullptr;
2509 { assert(succ_iter < source->succ_inert.begin);
2510 assert(!current_out_bunch.is_null());
2512 current_out_bunch->bunch != succ_iter->
bunch());
2521 while (++succ_iter < &
succ.back());
2526 while (
nullptr == action_block_iter->
succ &&
2528 ++action_block_iter,
true));
2533 assert(
nullptr != action_block_iter->
succ);
2542 assert(
nullptr != bunch);
2544 partitioner) <<
":\n\taction_block-slice [";
2545 assert(bunch->
begin == action_block_iter);
2546 bunch_end = bunch->
end;
2549 action_block_slice_end =
2552 assert(action_block_slice_end <= bunch_end);
2560 assert(action_block_iter < action_block_slice_end);
2563 assert(
nullptr != action_block_iter->
succ);
2566 pred->debug_id(partitioner) <<
'\n';
2568 while (++action_block_iter < action_block_slice_end);
2570 while (action_block_iter < bunch_end &&
2571 nullptr == action_block_iter->
succ)
2574 ++action_block_iter;
2575 assert(action_block_iter < bunch_end);
2577 if (action_block_iter >= bunch_end)
break;
2579 action_block_slice_end =
2584 assert(action_block_iter == bunch_end);
2586 nullptr == action_block_iter->
succ)
2589 ++action_block_iter;
2615{ assert(0 < marked_size()); assert(0 < unmarked_bottom_size());
2618 state_type swapcount(std::min(marked_bottom_size(),
2619 unmarked_nonbottom_size()));
2621 unmarked_nonbottom_size()); assert(begin < splitpoint), assert(splitpoint < end),
2622 assert(splitpoint->st->pos == splitpoint),
2624 { assert((
state_type) (splitpoint - begin) <= size()/2);
2626 #ifdef USE_POOL_ALLOCATOR
2627 storage.template construct<block_t>
2631 (begin, splitpoint, new_seqnr);
2636 nonbottom_begin = marked_nonbottom_begin;
2641 #ifdef USE_POOL_ALLOCATOR
2642 storage.template construct<block_t>
2646 (splitpoint, end, new_seqnr);
2651 nonbottom_begin = marked_bottom_begin;
2674 --pos2; assert(pos1 < pos2);
2675 *pos1 = std::move(*pos2);
2677 if (0 >= --swapcount) {
break; } assert(pos1 < pos2);
2678 *pos2 = std::move(*pos1);
2680 *pos2 = std::move(temp);
2684 do assert(s_iter->
st->
pos == s_iter);
2685 while (++s_iter < end); }
2688 marked_nonbottom_begin = end;
2689 marked_bottom_begin = nonbottom_begin;
2695 { assert(s_iter->
st->
pos == s_iter);
2696 s_iter->
st->
bl.
ock = new_block;
2720 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);
2722 assert(last_slice_begin <
end); assert(
nullptr != first_slice_end[-1].succ);
2723 assert(
nullptr != last_slice_begin->
succ);
2724 if (first_slice_end -
begin >
end - last_slice_begin)
2728 #ifdef USE_POOL_ALLOCATOR
2729 part_tr.storage.template construct<bunch_t>
2733 (last_slice_begin,
end); assert(
nullptr != bunch_T_a_Bprime);
2734 end = last_slice_begin;
2735 while (
nullptr ==
end[-1].succ)
2738 } assert(
nullptr !=
end[-1].begin_or_before_end);
2745 #ifdef USE_POOL_ALLOCATOR
2746 part_tr.storage.template construct<bunch_t>
2750 (
begin, first_slice_end); assert(
nullptr != bunch_T_a_Bprime);
2751 begin = first_slice_end;
2759 return bunch_T_a_Bprime;
2796template <
class LTS_TYPE>
2853 bool const new_preserve_divergence =
false)
2855 part_st(new_aut.num_states()),
2856 part_tr(new_aut.num_transitions(), new_aut.num_action_labels()),
2920 { assert(block_bunch.is_stable()); assert(!block_bunch.empty());
2922 pred(block_bunch.end[-1].
pred); assert(pred->source->bl.ock == B);
2923 assert(
nullptr != pred->action_block->succ);
2924 assert(pred->action_block->succ->block_bunch->pred == pred);
2925 assert(pred->action_block->succ->block_bunch->slice == &block_bunch);
2929 pred->target->bl.ock->seqnr));
2938 if (
aut.has_state_info())
2942 typename std::remove_reference<
decltype(
aut.state_labels())>::type
2949 new_labels[new_index]=new_labels[new_index]+
aut.state_label(i);
2951 while (++i <
aut.num_states());
2955 new_labels.swap(
aut.state_labels());
3004 ?
"divergence-preserving branching "
3008 <<
" states and " <<
aut.num_transitions() <<
" transitions.\n";
3013 "without incoming or outgoing transition. It is not "
3014 "guaranteed that branching bisimulation minimisation runs in "
3015 "time O(m log n).\n";
3023 part_tr.storage.template construct<bisim_dnj::block_t>
3048 ++inert_transitions;
3081 next_pred_begin += state_iter->
pred_inert.count;
3082 state_iter->
pred_inert.convert_to_iterator(next_pred_begin);
3085 assert(
nullptr != next_succ_begin);
3088 if (next_succ_begin < state_iter->untested_to_U_eqv.begin)
3093 out_slice_begin(next_succ_begin);
3101 state_iter->
succ_inert.convert_to_iterator(next_succ_begin +
3104 while (next_succ_begin < state_iter->succ_inert.begin)
3109 next_succ_begin = state_iter->
succ_inert.begin;
3124 #ifdef USE_POOL_ALLOCATOR
3125 part_tr.storage.template construct<bisim_dnj::bunch_t>
3158 { assert(
nullptr != bunch);
3169 <<
pp(
aut.action_label(
label)) <<
"-transitions. "
3170 "This is more than n^2 (= " << n_square <<
"). It is "
3171 "not guaranteed that branching bisimulation "
3182 action_block_slice_begin(next_action_label_begin); assert(
nullptr != action_block_slice_begin);
3186 action_block_slice_begin;
3192 next_action_label_begin);
3197 "transitions, and the number of action labels exceeds "
3198 "the number of transitions. It is not guaranteed that "
3199 "branching bisimulation minimisation runs in time "
3205 next_action_label_begin->
succ =
nullptr,
3233 pred_pos = --
target->pred_inert.begin; assert(block_bunch_pos->
slice.is_null());
3236 --inert_transitions;
3249 pred_pos =
target->bl.ed_noninert_end++;
3255 begin_or_before_end == action_block_pos);
3258 } assert(
target->bl.ed_noninert_end <=
target->pred_inert.begin);
3260 block_bunch_pos->
pred = pred_pos;
3262 pred_pos->
source = source;
3263 pred_pos->
target =
target; assert(
nullptr != succ_pos);
3264 action_block_pos->
succ = succ_pos;
3265 } assert(0 == inert_transitions);
3268 aut.clear_transitions();
3273 state_iter->
bl.
ock = B;
3277 if (
nullptr != bunch)
3283 while (
nullptr == bunch->
end[-1].
succ)
3314 slice->make_stable();
3360 std::unordered_set<const bisim_dnj::block_bunch_slice_t*>
3361 block_bunch_check_set;
3362 #ifndef USE_SIMPLE_LIST
3363 block_bunch_check_set.reserve(
3364 block->stable_block_bunch.size());
3369 block->stable_block_bunch)
3371 assert(block_bunch.source_block() == block);
3372 assert(block_bunch.is_stable());
3373 block_bunch_check_set.insert(&block_bunch);
3375 block_bunch.bunch->max_work_counter(*
this)), *
this);
3376 ++true_nr_of_block_bunch_slices;
3388 state == out_slice_end[-1].block_bunch->pred->source; )
3389 { assert(!out_slice_end[-1].block_bunch->
slice.is_null());
3391 block_bunch_slice(out_slice_end[-1].block_bunch->
slice);
3393 block_bunch_slice->bunch);
3394 assert(block == block_bunch_slice->source_block());
3395 if (block_bunch_slice->is_stable())
3397 assert(1 == block_bunch_check_set.count(
3398 &*block_bunch_slice));
3399 ++block_bunch_count;
3404 out_slice_end[-1].begin_or_before_end);
3405 assert(
nullptr != out_slice_begin);
3406 assert(out_slice_begin < out_slice_end);
3415 assert(bunch->
begin <=
3416 out_slice_end->block_bunch->pred->action_block);
3417 assert(out_slice_end->block_bunch->pred->
3418 action_block < bunch->end);
3419 assert(out_slice_end->block_bunch->slice ==
3421 assert(
nullptr != out_slice_end->begin_or_before_end);
3422 if (out_slice_end->block_bunch + 1 !=
3423 block_bunch_slice->end)
3425 assert(out_slice_end->block_bunch + 1 <
3426 block_bunch_slice->end);
3427 assert(out_slice_end->block_bunch[1].slice ==
3431 no_temporary_work(max_block,
3435 perm_iter < block->nonbottom_begin),*
this);
3437 while (out_slice_begin < out_slice_end &&
3438 (assert(out_slice_begin ==
3441 if (perm_iter < block->nonbottom_begin)
3443 assert(block_bunch_check_set.size() == block_bunch_count);
3446 while (++perm_iter < block->end);
3450 true_nr_of_block_bunch_slices);
3466 { assert(
nullptr == action_block->begin_or_before_end);
3468 succ_iter(action_block->succ);
3469 assert(
nullptr != succ_iter);
3487 max_block,
false), *
this);
3501 trans_type true_nr_of_action_block_slices(0);
3513 action_block_slice_end(action_slice_end);
3517 action_block_slice_begin(
3518 action_block_slice_end[-1].begin_or_before_end);
3519 assert(
nullptr != action_block_slice_begin);
3520 assert(action_block_slice_begin < action_block_slice_end);
3521 assert(action_block_slice_end <= action_slice_end);
3522 assert(
nullptr != action_block_slice_begin->
succ);
3524 target_block(action_block_slice_begin->
3525 succ->block_bunch->pred->target->bl.ock);
3527 bunch(action_block_slice_begin->
succ->
bunch());
3528 if (previous_bunch != bunch)
3530 assert(
nullptr == previous_bunch);
3531 previous_bunch = bunch;
3532 assert(bunch->
end == action_block_slice_end);
3533 if (bunch->
begin == action_block_slice_begin)
3543 ++true_nr_of_nontrivial_bunches;
3547 ++true_nr_of_bunches;
3549 if(bunch->
begin == action_block_slice_begin)
3551 previous_bunch =
nullptr;
3553 else assert(bunch->
begin < action_block_slice_begin);
3556 action_block_slice_end);
3559 action_block(action_block_slice_end);
3564 succ_iter(action_block->
succ);
3565 assert(
nullptr != succ_iter);
3575 assert(succ_iter < pred_iter->source->succ_inert.begin);
3579 assert(pred_iter < pred_iter->
target->pred_inert.begin);
3582 assert(target_block == pred_iter->
target->
bl.
ock);
3583 assert(bunch == succ_iter->
bunch());
3585 while (action_block_slice_begin < action_block &&
3589 action_block_slice_begin),
true));
3590 action_block_slice_end = action_block_slice_begin;
3591 ++true_nr_of_action_block_slices;
3596 assert(
nullptr == action_slice_end->
succ);
3602 assert(
nullptr == previous_bunch);
3605 true_nr_of_nontrivial_bunches);
3607 true_nr_of_action_block_slices);
3630 clock_t next_print_time = clock();
3631 const clock_t rounded_start_time = next_print_time - CLOCKS_PER_SEC/2;
3644 if (clock_t now = clock(); next_print_time <= now ||
3655 next_print_time+=((now-next_print_time)/(60*CLOCKS_PER_SEC)
3656 + 1) * (60*CLOCKS_PER_SEC);
3657 now = (now - rounded_start_time) / CLOCKS_PER_SEC;
3665 << now / 3600 <<
" h ";
3669 << now / 60 <<
" min ";
3673 <<
" sec passed since starting the main loop.\n";
3675 #define PRINT_SG_PL(counter, sg_string, pl_string) \
3677 << (1 == (counter) ? (sg_string) : (pl_string))
3679 << (
nullptr == bunch_T ?
"The reduced LTS contains "
3680 :
"The reduced LTS contains at least ")
3682 " state and ",
" states and ")
3684 " transition.",
" transitions.");
3687 #define PRINT_INT_PERCENTAGE(num,denom) \
3688 (((num) * 200 + (denom)) / (denom) / 2)
3693 #undef PRINT_INT_PERCENTAGE
3701 <<
"\nThe current partition contains ";
3706 " new bottom state, ",
" new bottom states, ");
3710 " bunch (of which ",
" bunches (of which ")
3712 " is nontrivial), and ",
" are nontrivial), and ")
3714 " action-block-slice.\n",
" action-block-slices.\n");
3719 << bunch_T->
debug_id(*
this) <<
'\n'; )
3725 << bunch_T_a_Bprime->
debug_id(*
this) <<
'\n';
3726 unsigned const max_splitter_counter(
3730 bunch_T_a_Bprime->
begin); assert(splitter_iter < bunch_T_a_Bprime->end);
3732 { assert(
nullptr != splitter_iter->
succ);
3738 bool const first_transition_of_state(
3745 bunch_T_a_Bprime, first_transition_of_state);
3748 while (++splitter_iter < bunch_T_a_Bprime->end);
3753 splitter_iter = bunch_T_a_Bprime->
begin; assert(splitter_iter < bunch_T_a_Bprime->end);
3764 while (++splitter_iter < bunch_T_a_Bprime->end);
mCRL2complexity(bunch_T_a_Bprime,
3766 max_splitter_counter), *
this);
3768 bbslice_T_a_Bprime_B(
nullptr); )
3773 bisim_dnj::block_t* block_B(splitter_Tprime_B->source_block()); assert(!splitter_Tprime_B->is_stable());
3774 bool const is_primary_splitter = 0 < block_B->
marked_size(); assert(!splitter_Tprime_B->empty());
3776 bool add_stabilize_to_bottom_transns_succeeded =
true;
3777 if (is_primary_splitter)
3779 assert(bbslice_T_a_Bprime_B.is_null());
3783 max_splitter_counter), *
this);
3785 else if (!bbslice_T_a_Bprime_B.is_null())
3791 refine_partition_until_stable__stabilize_for_large_splitter,
3792 max_splitter_counter), *
this);
3798 add_stabilize_to_bottom_transns_succeeded = splitter_Tprime_B->
3800 refine_partition_until_stable__stabilize_new_noninert_a_priori,
3804 if (1 < block_B->
size())
3807 block_B_begin(block_B->
begin); assert(block_B_begin->
st->
pos == block_B_begin);
3814 if (block_B_begin < block_R->begin)
3819 if (is_primary_splitter)
3820 { assert(splitter_Tprime_B->bunch == bunch_T_a_Bprime);
3824 block_U(block_B_begin->
st->
bl.
ock); assert(block_U->
end == block_R->
begin);
3828 (U_splitter->source_block() == block_U ||
3830 U_splitter->source_block() == block_U)))
3831 { assert(!U_splitter->is_stable());
3832 assert(U_splitter->bunch == bunch_T);
3836 U_splitter->make_stable();
3844 { assert(!iter->is_stable());
3845 assert(iter->source_block() != block_U);
3854 if (!add_stabilize_to_bottom_transns_succeeded)
3855 { assert(splitter_Tprime_B->add_work_to_bottom_transns(
3857 refine_partition_until_stable__stabilize_new_noninert_a_posteriori,
3860 if (splitter_Tprime_B->work_counter.has_temporary_work())
3861 { assert(splitter_Tprime_B->add_work_to_bottom_transns(
3863 handle_new_noninert_transns__make_unstable_a_posteriori,
3865 splitter_Tprime_B->work_counter.reset_temporary_work();
3871 splitter_Tprime_B->end; )
3880 block_R, splitter_Tprime_B);
3882 if (splitter_end[-1].pred->source->bl.ock == block_R)
3883 { assert(!splitter_end[-1].slice.is_null());
3887 assert(
nullptr == block_R || splitter_Tprime_B->source_block() == block_R);
3894 assert(add_stabilize_to_bottom_transns_succeeded);
3896 if (splitter_Tprime_B->work_counter.has_temporary_work())
3897 { assert(!is_primary_splitter);
3898 assert(splitter_Tprime_B->add_work_to_bottom_transns(
3900 handle_new_noninert_transns__make_unstable_a_posteriori,
3902 splitter_Tprime_B->work_counter.reset_temporary_work();
3916 splitter_Tprime_B->make_stable(); assert(add_stabilize_to_bottom_transns_succeeded);
3919 if (splitter_Tprime_B->work_counter.has_temporary_work())
3920 { assert(!is_primary_splitter);
3921 assert(splitter_Tprime_B->add_work_to_bottom_transns(
3923 handle_new_noninert_transns__make_unstable_a_posteriori,
3925 splitter_Tprime_B->work_counter.reset_temporary_work();
3936 assert(
nullptr != block_B);
3937 assert(splitter_Tprime_B->source_block() == block_B);
3938 assert(splitter_Tprime_B->bunch == bunch_T_a_Bprime);
3939 bbslice_T_a_Bprime_B = splitter_Tprime_B;
3941 else bbslice_T_a_Bprime_B =
nullptr;
3959 action_block_iter < action_block_iter_end;
3961 { assert(
nullptr != action_block_iter->succ);
3962 assert(action_block_iter->succ->block_bunch->pred->action_block ==
3964 assert(action_block_iter->succ->bunch()->is_trivial());
3965 action_block_iter->succ->bunch()->
3966 next_nontrivial_and_label.label =
label; assert(
nullptr != action_block_iter->begin_or_before_end);
3967 assert(action_block_iter <= action_block_iter->begin_or_before_end);
4013 { assert(block_B == splitter_T->source_block());
4017 <<
',' << splitter_T->debug_id(*
this)
4019 ?
",extend_from_marked_states__add_new_noninert_to_splitter)\n"
4021 ?
",extend_from_marked_states)\n"
4023 ?
",extend_from_splitter)\n"
4024 :
",UNKNOWN MODE)\n")));
4036 R_s_iter.splitter_iter = splitter_T->end; assert(splitter_T->marked_begin <= R_s_iter.splitter_iter);
4037 while (splitter_T->marked_begin < R_s_iter.splitter_iter)
4039 --R_s_iter.splitter_iter;
4041 s(R_s_iter.splitter_iter->pred->source); assert(s->
bl.
ock == block_B); assert(s->
pos->
st == s);
4047 assert(splitter_T->marked_begin == splitter_T->end); }
4050 splitter_T->make_stable();
4057 U_nonbottom_end(untested_to_U_defined_end);
4069 (SPLIT_U_PREDECESSOR_HANDLED)
4070 (SPLIT_R_STATE_HANDLED)
4071 (SPLIT_U_STATE_HANDLED)
4073 (SPLIT_R_COLLECT_SPLITTER))
4092 block_R = block_B;
ONLY_IF_DEBUG( finalise_U_is_smaller(
nullptr, block_R, *
this); )
4098 if (U_nonbottom_end < block_B->marked_nonbottom_begin)
4101 U_s_iter = block_B->
begin;
4103 U_s_iter < U_nonbottom_end)
4108 U_t_iter->
target == U_s_iter->
st, ++U_t_iter)
4111 assert(U_t->
pos < block_B->
end);
4117 if (untested_to_U_defined_end <= U_t->pos)
4124 *untested_to_U_defined_end++);
4126 } assert(U_t !=
part_tr.
succ.back().block_bunch->pred->source);
4131 begin->block_bunch->pred->source)
4137 { assert(U_t !=
part_tr.
succ.front().block_bunch->pred->source);
4150 if (&*block_bunch == &*splitter_T)
4159 } assert(U_nonbottom_end <= U_t->pos);
4160 assert(U_t->
pos < untested_to_U_defined_end);
4163 if (block_B->
size() / 2 <
4173 untested_to_U_defined_end = U_nonbottom_end;
4228 if (U_nonbottom_end < block_B->marked_nonbottom_begin)
4231 R_s_iter.splitter_iter[-1].slice == splitter_T)
4233 --R_s_iter.splitter_iter;
4235 R_s_iter.splitter_iter->pred->source); assert(s->
bl.
ock == block_B); assert(s->
pos->
st == s);
4237 { assert(U_nonbottom_end <= s->pos);
4238 if (s->
pos < untested_to_U_defined_end)
4245 *--untested_to_U_defined_end);
4273 while (R_s_iter.splitter_iter[-1].slice == splitter_T)
4276 --R_s_iter.splitter_iter;
4278 s(R_s_iter.splitter_iter->pred->source);
4279 assert(s->
bl.
ock == block_B); assert(s->
pos->
st == s);
4290 if (U_nonbottom_end < block_B->marked_nonbottom_begin)
4299 R_s_iter.block = block_B->
end;
4304 --R_s_iter.block; assert(
part_tr.
pred.back().target != R_s_iter.block->st);