81#ifndef LIBLTS_BISIM_DNJ_H
82#define LIBLTS_BISIM_DNJ_H
86#include "mcrl2/lts/detail/liblts_scc.h"
87#include "mcrl2/lts/detail/liblts_merge.h"
88#include "mcrl2/lts/detail/coroutine.h"
89#include "mcrl2/lts/detail/check_complexity.h"
90#include "mcrl2/lts/detail/fixed_vector.h"
91#include "mcrl2/lts/detail/simple_list.h"
111 #define ONLY_IF_DEBUG(...) __VA_ARGS__
113 #define ONLY_IF_DEBUG(...)
120template <
class LTS_TYPE>
class bisim_partitioner_dnj;
136template <
class Iterator>
137union iterator_or_counter
146 iterator_or_counter() { count = 0; }
150 void convert_to_iterator(
const Iterator other)
152 new (&begin) Iterator(other);
157 ~iterator_or_counter() { begin.~Iterator(); }
161class block_bunch_entry;
162class action_block_entry;
186class state_info_entry;
187class permutation_entry;
197using permutation_t = fixed_vector<permutation_entry>;
205class block_bunch_slice_t;
206using block_bunch_slice_iter_t = simple_list<block_bunch_slice_t>::iterator;
207using block_bunch_slice_const_iter_t = simple_list<block_bunch_slice_t>::const_iterator;
208using block_bunch_slice_iter_or_null_t = iterator_or_null_t<block_bunch_slice_t>;
210enum new_block_mode_t { new_block_is_U, new_block_is_R };
218class state_info_entry
228 iterator_or_counter<pred_entry*> pred_inert;
237 iterator_or_counter<succ_entry*> succ_inert;
246 pred_entry* ed_noninert_end;
251 permutation_entry* pos =
nullptr;
267 iterator_or_counter<succ_entry*> untested_to_U_eqv;
270 template<
class LTS_TYPE>
271 std::string debug_id_short(
const bisim_partitioner_dnj<LTS_TYPE>&
273 { assert(partitioner.part_st.state_info.data() <=
this);
274 assert(
this < partitioner.part_st.state_info.data_end());
275 return std::to_string(
this - partitioner.part_st.state_info.data());
279 template<
class LTS_TYPE>
280 std::string debug_id(
const bisim_partitioner_dnj<LTS_TYPE>&
283 return "state " + debug_id_short(partitioner);
286 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
287 mutable check_complexity::state_dnj_counter_t work_counter;
293class permutation_entry {
296 state_info_entry* st;
300 permutation_entry() =
default;
306 permutation_entry(
const permutation_entry&& other)
noexcept
317 permutation_entry& operator=(
const permutation_entry& other)
noexcept
356 permutation_entry* begin;
359 permutation_entry* marked_bottom_begin;
362 permutation_entry* nonbottom_begin;
365 permutation_entry* marked_nonbottom_begin;
368 permutation_entry* end;
372 simple_list<block_bunch_slice_t> stable_block_bunch;
377 const state_type seqnr;
386 block_t(permutation_entry*
const new_begin,
387 permutation_entry*
const new_end, state_type
const new_seqnr)
389 marked_bottom_begin(new_end),
390 nonbottom_begin(new_end),
391 marked_nonbottom_begin(new_end),
393 stable_block_bunch(),
395 { assert(new_begin < new_end);
400 state_type size()
const
401 { assert(begin <= marked_bottom_begin); assert(marked_nonbottom_begin <= end);
402 assert(marked_bottom_begin <= nonbottom_begin);
403 assert(nonbottom_begin <= marked_nonbottom_begin);
409 state_type bottom_size()
const
410 { assert(begin <= marked_bottom_begin); assert(marked_nonbottom_begin <= end);
411 assert(marked_bottom_begin <= nonbottom_begin);
412 assert(nonbottom_begin <= marked_nonbottom_begin);
413 return nonbottom_begin - begin;
418 state_type marked_bottom_size()
const
419 { assert(begin <= marked_bottom_begin); assert(marked_nonbottom_begin <= end);
420 assert(marked_bottom_begin <= nonbottom_begin);
421 assert(nonbottom_begin <= marked_nonbottom_begin);
422 return nonbottom_begin - marked_bottom_begin;
427 state_type marked_size()
const
429 return end - marked_nonbottom_begin + marked_bottom_size();
434 state_type unmarked_bottom_size()
const
435 { assert(begin <= marked_bottom_begin); assert(marked_nonbottom_begin <= end);
436 assert(marked_bottom_begin <= nonbottom_begin);
437 assert(nonbottom_begin <= marked_nonbottom_begin);
438 return marked_bottom_begin - begin;
443 state_type unmarked_nonbottom_size()
const
444 { assert(begin <= marked_bottom_begin); assert(marked_nonbottom_begin <= end);
445 assert(marked_bottom_begin <= nonbottom_begin);
446 assert(nonbottom_begin <= marked_nonbottom_begin);
447 return marked_nonbottom_begin - nonbottom_begin;
456 bool mark_nonbottom(permutation_entry*
const s)
457 { assert(nonbottom_begin <= s); assert(s < end);
459 assert(begin <= marked_bottom_begin);
460 assert(marked_bottom_begin <= nonbottom_begin);
461 assert(nonbottom_begin <= marked_nonbottom_begin);
462 if (marked_nonbottom_begin <= s) {
return false; } assert(marked_nonbottom_begin <= end);
463 std::swap(*s, *--marked_nonbottom_begin); assert(nonbottom_begin <= marked_nonbottom_begin);
473 bool mark(permutation_entry*
const s)
474 { assert(begin <= s);
475 if (s < nonbottom_begin)
476 { assert(begin <= marked_bottom_begin); assert(marked_nonbottom_begin <= end);
477 assert(nonbottom_begin <= marked_nonbottom_begin);
478 if (marked_bottom_begin <= s) {
return false; } assert(marked_bottom_begin <= nonbottom_begin);
479 std::swap(*s, *--marked_bottom_begin); assert(begin <= marked_bottom_begin);
482 return mark_nonbottom(s);
498 block_t* split_off_block(
enum new_block_mode_t new_block_mode,
ONLY_IF_DEBUG(
const bisim_partitioner_dnj<LTS_TYPE>& partitioner, )
499 state_type new_seqnr);
502 template<
class LTS_TYPE>
503 inline std::string debug_id(
const bisim_partitioner_dnj<LTS_TYPE>&
505 { assert(partitioner.part_st.permutation.data() <= begin);
506 assert(begin < end); assert(begin <= marked_bottom_begin);
507 assert(marked_bottom_begin <= nonbottom_begin);
508 assert(nonbottom_begin <= marked_nonbottom_begin);
509 assert(marked_nonbottom_begin <= end);
510 assert(end <= partitioner.part_st.permutation.data_end());
512 std::to_string(begin - partitioner.part_st.permutation.data()) +
513 "," + std::to_string(end - partitioner.part_st.permutation.data()) +
514 ") (#" + std::to_string(seqnr) +
")";
517 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
518 mutable check_complexity::block_dnj_counter_t work_counter;
534 permutation_t permutation;
537 fixed_vector<state_info_entry> state_info;
542 state_type nr_of_blocks = 0;
550 part_state_t(state_type
const num_states)
551 : permutation(num_states),
552 state_info(num_states)
553 { assert(0 < num_states);
554 permutation_entry* perm_iter(permutation.data());
556 static_assert(std::is_trivially_destructible_v<block_t>);
558 state_info_entry* state_iter(state_info.data()); assert(perm_iter < permutation.data_end());
561 state_iter->pos = perm_iter;
562 perm_iter->st = state_iter;
564 while (++state_iter, ++perm_iter < permutation.data_end()); assert(state_iter == state_info.data_end());
575 { ONLY_IF_DEBUG( state_type deleted_blocks(0); )
576 permutation_entry* perm_iter(permutation.data_end()); assert(permutation.data() < perm_iter);
579 block_t*
const B(perm_iter[-1].st->bl.ock); assert(B->end == perm_iter);
580 perm_iter = B->begin; ONLY_IF_DEBUG( ++deleted_blocks; )
583 while (permutation.data() < perm_iter); assert(deleted_blocks == nr_of_blocks);
590 state_type state_size()
const {
return permutation.size(); }
596 const block_t* block(state_type
const s)
const
598 return state_info[s].bl.ock;
609 template<
class LTS_TYPE>
610 void print_block(
const block_t*
const B,
611 const char*
const message,
612 const permutation_entry* begin_print,
613 const permutation_entry*
const end_print,
614 const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
const
615 { assert(B->begin <= begin_print); assert(end_print <= B->end);
616 if (end_print == begin_print)
621 mCRL2log(log::debug) <<
'\t' << message
622 << (1 < end_print - begin_print ?
"s:\n" :
":\n");
623 assert(begin_print < end_print);
627 << begin_print->st->debug_id(partitioner);
628 if (B != begin_print->st->bl.ock)
630 mCRL2log(log::debug) <<
", inconsistent: points "
631 "to " << begin_print->st->bl.ock->debug_id(partitioner);
633 if (begin_print != begin_print->st->pos)
636 <<
", inconsistent pointer to state_info_entry";
640 while (++begin_print < end_print);
647 template<
class LTS_TYPE>
648 void print_part(
const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
const
650 if (!mCRL2logEnabled(log::debug))
654 const block_t* B(permutation.front().st->bl.ock);
657 mCRL2log(log::debug)<<B->debug_id(partitioner)<<
":\n";
658 print_block(B,
"Bottom state",
659 B->begin, B->marked_bottom_begin, partitioner);
660 print_block(B,
"Marked bottom state",
661 B->marked_bottom_begin, B->nonbottom_begin, partitioner);
662 print_block(B,
"Non-bottom state",
663 B->nonbottom_begin, B->marked_nonbottom_begin, partitioner);
664 print_block(B,
"Marked non-bottom state",
665 B->marked_nonbottom_begin, B->end, partitioner);
668 while(B->end<permutation.data_end() && (B = B->end->st->bl.ock,
true));
674 template<
class LTS_TYPE>
675 void assert_consistency(
676 const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
const
678 const permutation_entry* perm_iter(permutation.data());
679 state_type true_nr_of_blocks(0);
680 assert(perm_iter < permutation.data_end());
683 const block_t*
const block(perm_iter->st->bl.ock);
685 assert(block->begin == perm_iter);
686 assert(block->begin < block->marked_bottom_begin);
687 assert(block->marked_bottom_begin == block->nonbottom_begin);
688 assert(block->nonbottom_begin <= block->marked_nonbottom_begin);
689 assert(block->marked_nonbottom_begin == block->end);
690 assert(partitioner.branching||block->nonbottom_begin==block->end);
691 assert(0 <= block->seqnr);
692 assert(block->seqnr < nr_of_blocks);
693 unsigned const max_block(check_complexity::log_n -
694 check_complexity::ilog2(block->size()));
700 const state_info_entry*
const state(perm_iter->st);
702 assert(&state_info.back() == state ||
703 state->pred_inert.begin <= state[1].pred_inert.begin);
706 if (perm_iter < block->nonbottom_begin)
708 assert(&state_info.back() == state || state->
709 succ_inert.begin <= state[1].succ_inert.begin);
719 assert(&state_info.back() == state || state->
720 succ_inert.begin < state[1].succ_inert.begin);
726 assert(block == state->bl.ock);
727 assert(perm_iter == state->pos);
729 while (++perm_iter < block->end);
730 assert(perm_iter == block->end);
733 while (perm_iter < permutation.data_end());
734 assert(nr_of_blocks == true_nr_of_blocks);
744 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
746 bool operator()(
const iterator_or_counter<action_block_entry*> p1,
747 const action_block_entry*
const action_block)
const
749 return p1.begin > action_block;
751 }
const action_label_greater;
796 block_bunch_entry* block_bunch;
806 succ_entry* begin_or_before_end;
810 succ_entry* out_slice_begin(
ONLY_IF_DEBUG(
const fixed_vector<succ_entry>& succ )
815 bunch_t* bunch()
const;
816 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
828 template <
class LTS_TYPE>
829 static inline void add_work_to_out_slice(
830 const bisim_partitioner_dnj<LTS_TYPE>& partitioner,
831 const succ_entry* out_slice_begin,
832 enum check_complexity::counter_type ctr,
unsigned max_value);
839class block_bunch_entry
843 pred_entry* pred =
nullptr;
847 block_bunch_slice_iter_or_null_t slice;
860 action_block_entry* action_block =
nullptr;
863 state_info_entry* source =
nullptr;
866 state_info_entry* target =
nullptr;
869 template <
class LTS_TYPE>
870 std::string debug_id_short(
const bisim_partitioner_dnj<LTS_TYPE>&
873 return "from " + source->debug_id_short(partitioner) +
874 " to " + target->debug_id_short(partitioner);
878 template <
class LTS_TYPE>
879 std::string debug_id(
const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
883 label_type
const label(std::lower_bound(
884 partitioner.action_label.cbegin(), partitioner.action_label.cend(),
885 action_block, action_label_greater) -
886 partitioner.action_label.cbegin());
887 assert(label < partitioner.action_label.size());
888 assert(partitioner.action_label[label].begin <= action_block);
889 assert(0==label||action_block<partitioner.action_label[label-1].begin);
892 return pp(partitioner.aut.action_label(label)) +
"-transition " +
893 debug_id_short(partitioner);
896 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
897 mutable check_complexity::trans_dnj_counter_t work_counter;
904class action_block_entry
923 action_block_entry* begin_or_before_end;
927 action_block_entry* action_block_slice_begin(
ONLY_IF_DEBUG(
const action_block_entry*
const action_block_begin,
928 const action_block_entry*
const action_block_orig_inert_begin )
931 action_block_entry* result(begin_or_before_end); assert(
nullptr != result);
933 { assert(
this == result->begin_or_before_end);
939 assert(
nullptr != succ); assert(
nullptr != result->succ);
940 assert(succ->bunch() == result->succ->bunch());
941 assert(result == action_block_begin ||
nullptr == result[-1].succ ||
942 action_block_orig_inert_begin <= result ||
943 result[-1].succ->block_bunch->pred->target->bl.ock !=
944 result->succ->block_bunch->pred->target->bl.ock);
961 action_block_entry* begin;
964 action_block_entry* end;
970 union next_nontrivial_and_label_t
977 bunch_t* next_nontrivial;
984 next_nontrivial_and_label_t()
986 next_nontrivial =
nullptr;
988 } next_nontrivial_and_label;
992 bunch_t(action_block_entry*
const new_begin,
993 action_block_entry*
const new_end)
996 next_nontrivial_and_label()
1004 bool is_trivial()
const
1006 return nullptr == next_nontrivial_and_label.next_nontrivial;
1016 bunch_t* split_off_small_action_block_slice(part_trans_t& part_tr);
1019 template <
class LTS_TYPE>
1020 std::string debug_id_short(
const bisim_partitioner_dnj<LTS_TYPE>&
1023 assert(partitioner.part_tr.action_block.data() <= begin);
1024 assert(end <= partitioner.part_tr.action_block_inert_begin);
1025 return "bunch [" + std::to_string(begin -
1026 partitioner.part_tr.action_block.data()) +
"," +
1027 std::to_string(end - partitioner.part_tr.action_block.data()) +
")";
1031 template <
class LTS_TYPE>
1032 std::string debug_id(
const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
1034 { assert(
nullptr != end[-1].succ);
1035 const action_block_entry* iter(begin); assert(iter < end);
1036 assert(
nullptr != iter->succ);
1037 assert(iter == iter->succ->block_bunch->pred->action_block);
1038 std::string result(debug_id_short(partitioner));
1039 result +=
" containing transition";
1040 result += iter < end - 1 ?
"s " :
" ";
1041 result += iter->succ->block_bunch->pred->debug_id_short(partitioner);
1047 while (
nullptr == iter->succ)
1052 assert(iter == iter->succ->block_bunch->pred->action_block);
1054 result += iter->succ->block_bunch->pred->debug_id_short(partitioner);
1060 while (++iter < end)
1062 if (
nullptr != iter->succ)
1063 { assert(iter == iter->succ->block_bunch->pred->action_block);
1065 result += iter->succ->block_bunch->pred->debug_id_short(
1072 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1078 template <
class LTS_TYPE>
1079 int max_work_counter(
const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
1084 label_type
const label(std::lower_bound(
1085 partitioner.action_label.cbegin(), partitioner.action_label.cend(),
1086 begin, action_label_greater) -
1087 partitioner.action_label.cbegin());
1088 assert(label < partitioner.action_label.size());
1089 assert(partitioner.action_label[label].begin <= begin);
1090 assert(0 == label || begin < partitioner.action_label[label-1].begin);
1091 if (0 == label || end < partitioner.action_label[label - 1].begin)
1093 assert(check_complexity::ilog2(end - begin) <=
1094 check_complexity::log_n);
1095 return check_complexity::log_n-check_complexity::ilog2(end-begin);
1100 mutable check_complexity::bunch_dnj_counter_t work_counter;
1121class block_bunch_slice_t
1127 block_bunch_entry* end;
1135 block_bunch_entry* marked_begin =
nullptr;
1138 bool is_stable()
const {
return nullptr == marked_begin; }
1143 { assert(!is_stable()); assert(!empty());
1144 marked_begin =
nullptr;
1149 void make_unstable()
1150 { assert(is_stable());
1151 marked_begin = end; assert(!is_stable());
1156 block_bunch_slice_t(block_bunch_entry*
const new_end,
1157 bunch_t*
const new_bunch,
bool const new_is_stable)
1175 return end[-1].slice !=
this;
1180 block_t* source_block()
const
1182 return end[-1].pred->source->bl.ock;
1186 template <
class LTS_TYPE>
1187 std::string debug_id(
const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
1191 bool operator()(
const block_bunch_entry& p1,
1192 const block_bunch_slice_t*
const p2)
const
1194 return p1.slice != p2;
1196 }
const block_bunch_not_equal;
1198 assert(partitioner.part_tr.block_bunch.data() < end);
1199 assert(end <= partitioner.part_tr.block_bunch_inert_begin);
1200 std::string
const index_string(std::to_string(end -
1201 &partitioner.part_tr.block_bunch.cbegin()[1]));
1204 return "empty block_bunch_slice [" + index_string +
"," +
1207 const block_bunch_entry* begin(
1208 &partitioner.part_tr.block_bunch.cbegin()[1]);
1209 if (trans_type bunch_size(
1216 begin = end - bunch_size;
1218 begin = std::lower_bound(begin,
const_cast<
const block_bunch_entry*>
1219 (is_stable() || marked_begin==end ? end-1 : marked_begin),
1220 this, block_bunch_not_equal);
1221 assert(begin->slice ==
this);
1222 assert(begin[-1].slice !=
this);
1223 return (is_stable() ?
"stable block_bunch-slice ["
1224 :
"unstable block_bunch_slice [") +
1225 std::to_string(begin-&partitioner.part_tr.block_bunch.cbegin()[1]) +
1226 "," + index_string +
") containing transitions from " +
1227 source_block()->debug_id(partitioner) +
1228 " in " + bunch->debug_id_short(partitioner);
1231 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1239 template <
class LTS_TYPE>
1240 bool add_work_to_bottom_transns(
enum check_complexity::
1241 counter_type
const ctr,
unsigned const max_value,
1242 const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
const
1244 assert(1U == max_value);
1245 const block_t*
const block(source_block());
1247 const block_bunch_entry* block_bunch(end);
1248 assert(partitioner.part_tr.block_bunch.front().slice !=
this);
1249 assert(block_bunch[-1].slice ==
this);
1253 const state_info_entry*
const source(block_bunch->pred->source);
1254 assert(source->bl.ock == block);
1255 if (source->pos < block->nonbottom_begin
1256
1257
1258)
1266 while (block_bunch[-1].slice ==
this);
1270 mutable check_complexity::block_bunch_dnj_counter_t work_counter;
1276inline succ_entry* succ_entry::out_slice_begin(
ONLY_IF_DEBUG(
const fixed_vector<succ_entry>& succ )
1278{ assert(
nullptr != begin_or_before_end);
1279 succ_entry* result(begin_or_before_end); assert(result->block_bunch->pred->action_block->succ == result);
1281 { assert(
nullptr != result->begin_or_before_end);
1282 assert(
this == result->begin_or_before_end);
1283 result =
this; assert(result->block_bunch->pred->action_block->succ == result);
1284 } assert(block_bunch->pred->source == result->block_bunch->pred->source);
1286 assert(
nullptr != result->begin_or_before_end);
1287 assert(
this <= result->begin_or_before_end);
1288 assert(block_bunch->slice == result->block_bunch->slice);
1289 assert(&succ.cbegin()[1] == result ||
1290 result[-1].block_bunch->pred->source < block_bunch->pred->source ||
1291 result[-1].bunch() != block_bunch->slice->bunch);
1297inline bunch_t* succ_entry::bunch()
const
1299 return block_bunch->slice->bunch;
1301 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1310 template <
class LTS_TYPE>
1311 inline void succ_entry::add_work_to_out_slice(
1312 const bisim_partitioner_dnj<LTS_TYPE>& partitioner,
1313 const succ_entry* out_slice_begin,
1314 enum check_complexity::counter_type
const ctr,
unsigned const max_value)
1316 const succ_entry*
const out_slice_before_end(
1317 out_slice_begin->begin_or_before_end);
1318 assert(
nullptr != out_slice_before_end);
1319 assert(out_slice_begin <= out_slice_before_end);
1321 add_work(ctr, max_value), partitioner);
1323 while (++out_slice_begin <= out_slice_before_end)
1327 add_work_notemporary(ctr, max_value), partitioner);
1330 (
void) partitioner; (
void) out_slice_before_end;
1342 fixed_vector<succ_entry> succ;
1348 fixed_vector<block_bunch_entry> block_bunch;
1354 fixed_vector<pred_entry> pred;
1363 fixed_vector<action_block_entry> action_block;
1366 block_bunch_entry* block_bunch_inert_begin;
1369 action_block_entry* action_block_inert_begin;
1372 const action_block_entry* action_block_orig_inert_begin =
nullptr;
1375 simple_list<block_bunch_slice_t> splitter_list;
1378 bunch_t* first_nontrivial =
nullptr;
1382 static_assert(std::is_trivially_destructible_v<bunch_t>);
1386 state_type nr_of_new_bottom_states = 0;
1389 trans_type nr_of_bunches = 0;
1390 trans_type nr_of_nontrivial_bunches = 0;
1391 trans_type nr_of_action_block_slices = 0;
1392 trans_type nr_of_block_bunch_slices = 0;
1402 part_trans_t(trans_type num_transitions,
1403 trans_type num_actions)
1404 : succ(num_transitions + 2),
1405 block_bunch(num_transitions + 1),
1406 pred(num_transitions + 2),
1407 action_block(num_transitions + num_actions < 1
1408 ? 0 : num_transitions + num_actions - 1),
1409 block_bunch_inert_begin(block_bunch.data_end()),
1410 action_block_inert_begin(action_block.data_end()),
1413 succ.front().block_bunch = block_bunch.data();
1414 succ.back() .block_bunch = block_bunch.data();
1415 block_bunch.front().pred = pred.data();
1416 block_bunch.front().slice =
nullptr;
1417 pred.front().source =
nullptr;
1418 pred.front().target =
nullptr;
1419 pred.back() .source =
nullptr;
1420 pred.back() .target =
nullptr;
1432 action_block_entry* action_block_iter(action_block.data());
1437 if (action_block_inert_begin <= action_block_iter)
1438 { assert(0 == nr_of_bunches);
1442 while (
nullptr == action_block_iter->succ && ( assert(
nullptr == action_block_iter->begin_or_before_end),
1443 ++action_block_iter,
true)); assert(
nullptr != action_block_iter->begin_or_before_end);
1444 bunch_t*
const bunch(action_block_iter->succ->bunch()); assert(bunch->begin == action_block_iter);
1445 action_block_iter = bunch->end;
1446 delete bunch; ONLY_IF_DEBUG( --nr_of_bunches; )
1455 bunch_t* get_some_nontrivial()
1457 return first_nontrivial;
1463 void make_nontrivial(bunch_t*
const bunch)
1464 { assert(1 < bunch->end - bunch->begin); assert(bunch->is_trivial());
1467 bunch->next_nontrivial_and_label.next_nontrivial =
1468 nullptr == first_nontrivial ? bunch : first_nontrivial;
1473 first_nontrivial = bunch; assert(nr_of_nontrivial_bunches < nr_of_bunches);
1474 ++nr_of_nontrivial_bunches;
1480 void make_trivial(bunch_t*
const bunch)
1481 { assert(!bunch->is_trivial()); assert(first_nontrivial == bunch);
1483 bunch == bunch->next_nontrivial_and_label.next_nontrivial
1484 ?
nullptr : bunch->next_nontrivial_and_label.next_nontrivial; assert(bunch->end - 1 == bunch->begin->begin_or_before_end);
1485 bunch->next_nontrivial_and_label.next_nontrivial =
nullptr; assert(0 < nr_of_nontrivial_bunches);
1486 --nr_of_nontrivial_bunches; assert(bunch->begin == bunch->end[-1].begin_or_before_end);
1512 void first_move_transition_to_new_bunch(
1513 action_block_entry*
const action_block_iter,
1514 bunch_t*
const bunch_T_a_Bprime,
1515 bool const first_transition_of_state)
1520 succ_entry*
const old_succ_pos(action_block_iter->succ); assert(
nullptr != old_succ_pos);
1521 assert(old_succ_pos->block_bunch->pred->action_block == action_block_iter);
1522 succ_entry*
const out_slice_begin(old_succ_pos->out_slice_begin(
ONLY_IF_DEBUG( succ )
1523 )); assert(out_slice_begin->block_bunch->pred->action_block->succ ==
1525 succ_entry*
const new_succ_pos(out_slice_begin->begin_or_before_end); assert(
nullptr != new_succ_pos);
1526 assert(out_slice_begin == new_succ_pos->begin_or_before_end);
1527 assert(new_succ_pos<old_succ_pos->block_bunch->pred->source->succ_inert.begin);
1528 assert(new_succ_pos->block_bunch->pred->action_block->succ == new_succ_pos);
1529 if (old_succ_pos < new_succ_pos)
1531 std::swap(old_succ_pos->block_bunch, new_succ_pos->block_bunch);
1532 old_succ_pos->block_bunch->pred->action_block->succ = old_succ_pos; assert(action_block_iter == new_succ_pos->block_bunch->pred->action_block);
1533 action_block_iter->succ = new_succ_pos;
1537 assert(old_succ_pos == new_succ_pos);
1544 out_slice_begin->begin_or_before_end = new_succ_pos - 1;
1551 if (first_transition_of_state)
1553 new_succ_pos->begin_or_before_end = new_succ_pos;
1557 succ_entry*
const out_slice_before_end(
1558 new_succ_pos[1].begin_or_before_end); assert(
nullptr != out_slice_before_end);
1559 assert(new_succ_pos < out_slice_before_end);
1560 assert(out_slice_before_end->block_bunch->pred->action_block->succ ==
1561 out_slice_before_end);
1562 assert(new_succ_pos + 1 == out_slice_before_end->begin_or_before_end);
1563 out_slice_before_end->begin_or_before_end = new_succ_pos; assert(out_slice_before_end <
1564 new_succ_pos->block_bunch->pred->source->succ_inert.begin);
1565 new_succ_pos->begin_or_before_end = out_slice_before_end; assert(bunch_T_a_Bprime == out_slice_before_end->bunch());
1568 assert(new_succ_pos == action_block_iter->succ);
1570 block_bunch_entry*
const old_block_bunch_pos(
1571 new_succ_pos->block_bunch); assert(old_block_bunch_pos->pred->action_block == action_block_iter);
1572 block_t*
const source_block = old_block_bunch_pos->pred->source->bl.ock; assert(!old_block_bunch_pos->slice.is_null());
1573 block_bunch_slice_iter_t
const old_block_bunch_slice(
1574 old_block_bunch_pos->slice);
1575 block_bunch_entry*
const new_block_bunch_pos(
1576 old_block_bunch_slice->end - 1); assert(
nullptr != new_block_bunch_pos->pred->action_block->succ);
1577 assert(new_block_bunch_pos->pred->action_block->succ->block_bunch ==
1578 new_block_bunch_pos);
1580 block_bunch_slice_iter_t new_block_bunch_slice;
1581 if (new_block_bunch_pos + 1 >= block_bunch_inert_begin ||
1582 (new_block_bunch_slice = (block_bunch_slice_iter_t)
1583 new_block_bunch_pos[1].slice, assert(!new_block_bunch_pos[1].slice.is_null()),
1584 bunch_T_a_Bprime != new_block_bunch_slice->bunch ||
1585 source_block != new_block_bunch_slice->source_block()))
1586 { assert(first_transition_of_state);
1594 new_block_bunch_slice = splitter_list.emplace_back(
1595 new_block_bunch_pos + 1, bunch_T_a_Bprime,
false);
1597 splitter_list.emplace_back(new_block_bunch_pos + 1,
1598 bunch_T_a_Bprime,
false);
1599 new_block_bunch_slice = std::prev(splitter_list.end());
1601 ++nr_of_block_bunch_slices;
1602 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1603 new_block_bunch_slice->work_counter = old_block_bunch_slice->work_counter;
1605 splitter_list.splice(splitter_list.end(),
1606 source_block->stable_block_bunch, old_block_bunch_slice);
1607 old_block_bunch_slice->make_unstable();
1608 } assert(!new_block_bunch_slice->is_stable());
1611 if (old_block_bunch_pos < new_block_bunch_pos)
1613 std::swap(old_block_bunch_pos->pred, new_block_bunch_pos->pred); assert(
nullptr != old_block_bunch_pos->pred->action_block->succ);
1614 old_block_bunch_pos->pred->action_block->succ->block_bunch =
1615 old_block_bunch_pos; assert(new_succ_pos == new_block_bunch_pos->pred->action_block->succ);
1616 new_succ_pos->block_bunch = new_block_bunch_pos;
1620 assert(new_block_bunch_pos == old_block_bunch_pos);
1622 assert(new_block_bunch_pos->slice == old_block_bunch_slice);
1623 new_block_bunch_pos->slice = new_block_bunch_slice;
1625 assert(new_block_bunch_pos + 1 == old_block_bunch_slice->marked_begin);
1626 old_block_bunch_slice->end = new_block_bunch_pos;
1627 old_block_bunch_slice->marked_begin = new_block_bunch_pos; assert(
nullptr != new_block_bunch_pos);
1628 if (old_block_bunch_slice->empty())
1629 { assert(!old_block_bunch_slice->is_stable());
1630 splitter_list.erase(old_block_bunch_slice); assert(!new_block_bunch_slice->is_stable());
1631 --nr_of_block_bunch_slices;
1637 source_block->stable_block_bunch.splice(
1638 source_block->stable_block_bunch.end(),
1639 splitter_list, new_block_bunch_slice);
1640 new_block_bunch_slice->make_stable();
1646 source_block->marked_nonbottom_begin = source_block->end; assert(source_block->marked_bottom_begin == source_block->begin);
1647 source_block->marked_bottom_begin = source_block->nonbottom_begin;
1673 void second_move_transition_to_new_bunch(
1674 action_block_entry*
const action_block_iter,
ONLY_IF_DEBUG(
const bisim_partitioner_dnj<LTS_TYPE>& partitioner,
1675 bunch_t*
const bunch_T_a_Bprime, )
1676 bunch_t*
const large_splitter_bunch)
1677 { assert(
nullptr != bunch_T_a_Bprime);
1684 succ_entry*
const new_succ_pos(action_block_iter->succ); assert(
nullptr != new_succ_pos);
1685 assert(new_succ_pos->block_bunch->pred->action_block == action_block_iter);
1686 state_info_entry*
const source(
1687 new_succ_pos->block_bunch->pred->source); assert(source->pos->st == source);
1688 assert(new_succ_pos < source->succ_inert.begin);
1689 assert(source == partitioner.part_st.state_info.data() ||
1690 source[-1].succ_inert.begin <= new_succ_pos);
1691 assert(
nullptr != new_succ_pos->begin_or_before_end);
1692 succ_entry*
const new_begin_or_before_end(
1693 new_succ_pos->begin_or_before_end->begin_or_before_end); assert(
nullptr != new_begin_or_before_end);
1694 assert(new_begin_or_before_end->block_bunch->pred->action_block->succ ==
1695 new_begin_or_before_end);
1696 if (new_begin_or_before_end < new_succ_pos)
1697 { assert(source == partitioner.part_st.state_info.data() ||
1698 source[-1].succ_inert.begin <= new_begin_or_before_end);
1699 new_succ_pos->begin_or_before_end = new_begin_or_before_end;
1702 { assert(new_begin_or_before_end == new_succ_pos);
1704 const succ_entry*
const new_before_end(
1705 new_begin_or_before_end->begin_or_before_end); assert(
nullptr != new_before_end);
1706 if (new_begin_or_before_end <= new_before_end)
1707 { assert(&partitioner.part_tr.succ.cbegin()[1] == new_begin_or_before_end ||
1708 new_begin_or_before_end[-1].block_bunch->pred->source < source ||
1709 new_begin_or_before_end[-1].bunch() != bunch_T_a_Bprime);
1710 assert(new_before_end + 1 == source->succ_inert.begin ||
1711 bunch_T_a_Bprime != new_before_end[1].bunch());
1712 if (source == new_succ_pos[-1].block_bunch->pred->source &&
1713 new_succ_pos[-1].bunch() == large_splitter_bunch)
1716 block_bunch_entry*
const old_block_bunch_pos(
1717 new_succ_pos[-1].block_bunch); assert(!old_block_bunch_pos->slice.is_null());
1718 assert(old_block_bunch_pos->pred->action_block->succ == new_succ_pos - 1);
1719 block_bunch_slice_iter_t
const large_splitter_slice(
1720 old_block_bunch_pos->slice);
1721 if (!large_splitter_slice->is_stable())
1723 block_bunch_entry*
const new_block_bunch_pos(
1724 large_splitter_slice->marked_begin - 1); assert(
nullptr != new_block_bunch_pos->pred->action_block->succ);
1725 assert(new_block_bunch_pos->pred->action_block->succ->block_bunch ==
1726 new_block_bunch_pos);
1727 if (old_block_bunch_pos < new_block_bunch_pos)
1729 std::swap(old_block_bunch_pos->pred,
1730 new_block_bunch_pos->pred);
1731 old_block_bunch_pos->pred->action_block->
1732 succ->block_bunch = old_block_bunch_pos; assert(new_block_bunch_pos->pred->action_block->succ == new_succ_pos - 1);
1733 new_succ_pos[-1].block_bunch = new_block_bunch_pos;
1735 large_splitter_slice->marked_begin=new_block_bunch_pos; assert(
nullptr != new_block_bunch_pos);
1739 assert(1 >= source->bl.ock->size());
1745 assert(source == partitioner.part_st.state_info.data() || source[-1].succ_inert.begin <= new_before_end);
1749 const block_bunch_entry* new_block_bunch_pos(new_succ_pos->block_bunch);
1750 assert(new_block_bunch_pos->pred->action_block->succ == new_succ_pos);
1751 assert(!new_block_bunch_pos->slice.is_null());
1752 block_bunch_slice_const_iter_t
const new_block_bunch_slice(
1753 new_block_bunch_pos->slice);
1754 assert(new_block_bunch_pos < new_block_bunch_slice->end);
1755 assert(bunch_T_a_Bprime == new_block_bunch_slice->bunch);
1756 if (new_block_bunch_pos + 1
1757 < new_block_bunch_slice->end)
1768 == new_block_bunch_pos->pred
1772 (--new_block_bunch_pos)->slice
1773 == new_block_bunch_slice);
1774 assert(new_block_bunch_pos <= partitioner.part_tr.block_bunch.data() ||
1775 source->bl.ock != new_block_bunch_pos->pred->source->bl.ock ||
1776 bunch_T_a_Bprime != new_block_bunch_pos->slice->bunch);
1810 succ_entry* move_out_slice_to_new_block(
1811 succ_entry* out_slice_end,
ONLY_IF_DEBUG(
const bisim_partitioner_dnj<LTS_TYPE>& partitioner, )
1812 block_t*
const old_block,
1813 block_bunch_slice_const_iter_t
const splitter_T)
1814 { assert(&succ.cbegin()[1] < out_slice_end);
1815 succ_entry*
const out_slice_begin(
1816 out_slice_end[-1].begin_or_before_end); assert(
nullptr != out_slice_begin);
1817 assert(out_slice_begin < out_slice_end);
1818 assert(out_slice_begin->block_bunch->pred->action_block->succ ==
1820 block_bunch_entry* old_block_bunch_pos(out_slice_end[-1].block_bunch); assert(
nullptr != old_block_bunch_pos->pred->action_block->succ);
1821 assert(!old_block_bunch_pos->slice.is_null());
1822 block_bunch_slice_iter_t
const old_block_bunch_slice(
1823 old_block_bunch_pos->slice); assert(old_block_bunch_pos->pred->action_block->succ->block_bunch ==
1824 old_block_bunch_pos);
1825 if (&*splitter_T == &*old_block_bunch_slice)
1827 return out_slice_begin;
1830 block_bunch_entry* old_block_bunch_slice_end(
1831 old_block_bunch_slice->end);
1832 state_info_entry*
const source(old_block_bunch_pos->pred->source); assert(out_slice_end <= source->succ_inert.begin);
1833 assert(partitioner.part_st.state_info.data() == source ||
1834 source[-1].succ_inert.begin < out_slice_end);
1835 block_t*
const new_block(source->bl.ock); assert(source == out_slice_begin->block_bunch->pred->source);
1836 block_bunch_slice_iter_t new_block_bunch_slice; assert(source->pos->st == source);
1837 if (old_block_bunch_slice_end >= block_bunch_inert_begin ||
1838 new_block != old_block_bunch_slice_end->pred->source->bl.ock ||
1839 (new_block_bunch_slice = (block_bunch_slice_iter_t)
1840 old_block_bunch_slice_end->slice, assert(!old_block_bunch_slice_end->slice.is_null()),
1841 old_block_bunch_slice->bunch != new_block_bunch_slice->bunch))
1845 if (old_block_bunch_slice->is_stable())
1849 new_block_bunch_slice =
1850 new_block->stable_block_bunch.emplace_front(
1851 old_block_bunch_slice->end,
1852 old_block_bunch_slice->bunch,
true);
1854 new_block->stable_block_bunch.emplace_front(
1855 old_block_bunch_slice->end,
1856 old_block_bunch_slice->bunch,
true);
1857 new_block_bunch_slice =
1858 new_block->stable_block_bunch.begin();
1864 new_block_bunch_slice = splitter_list.emplace_after(
1865 old_block_bunch_slice,
1866 old_block_bunch_slice->end,
1867 old_block_bunch_slice->bunch,
false);
1869 new_block_bunch_slice = splitter_list.emplace(
1870 std::next(old_block_bunch_slice),
1871 old_block_bunch_slice->end,
1872 old_block_bunch_slice->bunch,
false);
1875 ++nr_of_block_bunch_slices;
1876 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1877 new_block_bunch_slice->work_counter = old_block_bunch_slice->work_counter;
1880 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1881 unsigned max_counter = check_complexity::log_n -
1882 check_complexity::ilog2(new_block->size());
1884 assert(out_slice_begin < out_slice_end);
1886 { assert(old_block_bunch_pos == out_slice_end[-1].block_bunch);
1887 --out_slice_end; assert(old_block_bunch_pos->slice == old_block_bunch_slice);
1888 assert(source == out_slice_end->block_bunch->pred->source);
1889 --old_block_bunch_slice_end;
1891 old_block_bunch_slice_end->slice = new_block_bunch_slice;
mCRL2complexity(old_block_bunch_pos->pred, add_work(
1892 check_complexity::move_out_slice_to_new_block, max_counter), partitioner);
1893 if (old_block_bunch_slice->is_stable() || ( assert(!new_block_bunch_slice->is_stable()),
1894 old_block_bunch_slice->marked_begin >
1895 old_block_bunch_slice_end &&
1896 ( assert(
nullptr != old_block_bunch_slice_end),
1899 old_block_bunch_slice->marked_begin =
1900 old_block_bunch_slice_end,
true)))
1904 std::swap(old_block_bunch_pos->pred,
1905 old_block_bunch_slice_end->pred);
1911 pred_entry*
const old_pred = old_block_bunch_pos->pred;
1912 if (old_block_bunch_pos < old_block_bunch_slice->marked_begin)
1918 block_bunch_entry*
const old_marked_begin =
1919 old_block_bunch_slice->marked_begin - 1; assert(old_block_bunch_pos < old_block_bunch_slice_end);
1920 old_block_bunch_slice->marked_begin = old_marked_begin;
1922 old_block_bunch_pos->pred = old_marked_begin->pred;
1923 old_marked_begin->pred = old_block_bunch_slice_end->pred;
1924 old_block_bunch_slice_end->pred = old_pred; assert(
nullptr != old_marked_begin->pred->action_block->succ);
1926 old_marked_begin->pred->action_block->succ->
1927 block_bunch = old_marked_begin;
1933 block_bunch_entry*
const new_marked_begin =
1934 new_block_bunch_slice->marked_begin - 1;
1935 new_block_bunch_slice->marked_begin = new_marked_begin; assert(old_block_bunch_pos < new_marked_begin ||
1936 old_block_bunch_pos == old_block_bunch_slice_end);
1937 old_block_bunch_pos->pred=old_block_bunch_slice_end->pred; assert(old_block_bunch_slice_end <= new_marked_begin);
1938 old_block_bunch_slice_end->pred = new_marked_begin->pred;
1939 new_marked_begin->pred = old_pred; assert(out_slice_end == new_marked_begin->pred->action_block->succ);
1941 out_slice_end->block_bunch = new_marked_begin;
1943 } assert(
nullptr != old_block_bunch_slice_end->pred->action_block->succ);
1944 old_block_bunch_slice_end->pred->action_block->succ->block_bunch =
1945 old_block_bunch_slice_end; assert(
nullptr != old_block_bunch_pos->pred->action_block->succ);
1946 old_block_bunch_pos->pred->action_block->succ->block_bunch =
1947 old_block_bunch_pos;
1949 while (out_slice_begin < out_slice_end &&
1950 (old_block_bunch_pos = out_slice_end[-1].block_bunch,
true));
1951 old_block_bunch_slice->end = old_block_bunch_slice_end;
1953 if (old_block_bunch_slice->empty())
1955 if (old_block_bunch_slice->is_stable())
1971 old_block->stable_block_bunch.erase(old_block_bunch_slice);
1975 splitter_list.erase(old_block_bunch_slice);
1977 --nr_of_block_bunch_slices;
1979 return out_slice_begin;
1992 void first_move_transition_to_new_action_block(pred_entry*
const pred_iter)
1994 action_block_entry*
const old_action_block_pos(
1995 pred_iter->action_block); assert(
nullptr != old_action_block_pos->succ);
1996 assert(old_action_block_pos->succ->block_bunch->pred == pred_iter);
1997 action_block_entry*
const action_block_slice_begin(
1998 old_action_block_pos->action_block_slice_begin(
ONLY_IF_DEBUG( action_block.data(), action_block_orig_inert_begin )
1999 )); assert(
nullptr != action_block_slice_begin->succ);
2000 assert(action_block_slice_begin->succ->block_bunch->pred->action_block ==
2001 action_block_slice_begin);
2002 action_block_entry*
const new_action_block_pos(
2003 action_block_slice_begin->begin_or_before_end); assert(
nullptr != new_action_block_pos);
2004 assert(action_block_slice_begin == new_action_block_pos->begin_or_before_end);
2005 assert(
nullptr != new_action_block_pos->succ);
2006 assert(new_action_block_pos->succ->block_bunch->pred->action_block ==
2007 new_action_block_pos);
2008 if (old_action_block_pos < new_action_block_pos)
2010 succ_entry*
const temp(new_action_block_pos->succ); assert(
nullptr != temp); assert(
nullptr != old_action_block_pos->succ);
2011 new_action_block_pos->succ = old_action_block_pos->succ;
2012 old_action_block_pos->succ = temp;
2013 temp->block_bunch->pred->action_block = old_action_block_pos; assert(pred_iter == new_action_block_pos->succ->block_bunch->pred);
2014 pred_iter->action_block = new_action_block_pos;
2017 action_block_slice_begin->begin_or_before_end =
2018 new_action_block_pos - 1;
2021 { assert(old_action_block_pos == new_action_block_pos);
2022 if (action_block_slice_begin < new_action_block_pos)
2027 action_block_slice_begin->begin_or_before_end =
2028 new_action_block_pos - 1;
2032 --nr_of_action_block_slices;
2034 } assert(
nullptr != new_action_block_pos->succ);
2035 assert(pred_iter == new_action_block_pos->succ->block_bunch->pred);
2041 if (new_action_block_pos + 1 >= action_block_inert_begin ||
2042 nullptr == new_action_block_pos[1].succ ||
2043 new_action_block_pos[1].succ->bunch() !=
2044 new_action_block_pos->succ->bunch() ||
2045 new_action_block_pos[1].succ->block_bunch->pred->target->bl.ock !=
2046 pred_iter->target->bl.ock)
2050 new_action_block_pos->begin_or_before_end = new_action_block_pos;
2051 ++nr_of_action_block_slices;
2055 action_block_entry*
const action_block_slice_before_end(
2056 new_action_block_pos[1].begin_or_before_end); assert(
nullptr != action_block_slice_before_end);
2057 assert(new_action_block_pos < action_block_slice_before_end);
2058 assert(
nullptr != action_block_slice_before_end->succ);
2059 assert(action_block_slice_before_end->succ->block_bunch->pred->action_block ==
2060 action_block_slice_before_end);
2061 assert(new_action_block_pos + 1 ==
2062 action_block_slice_before_end->begin_or_before_end);
2063 action_block_slice_before_end->begin_or_before_end =
2064 new_action_block_pos; assert(action_block_slice_before_end->succ->block_bunch->
2065 pred->target->bl.ock == pred_iter->target->bl.ock);
2066 new_action_block_pos->begin_or_before_end =
2067 action_block_slice_before_end; assert(action_block_slice_before_end < action_block_inert_begin);
2078 void second_move_transition_to_new_action_block(
2079 pred_entry*
const pred_iter)
2081 action_block_entry*
const new_action_block_pos(
2082 pred_iter->action_block); assert(
nullptr != new_action_block_pos->succ);
2083 assert(new_action_block_pos->succ->block_bunch->pred == pred_iter);
2084 action_block_entry*
const old_begin_or_before_end(
2085 new_action_block_pos->begin_or_before_end); assert(
nullptr != old_begin_or_before_end);
2086 assert(
nullptr != old_begin_or_before_end->succ);
2087 assert(old_begin_or_before_end->succ->block_bunch->pred->action_block ==
2088 old_begin_or_before_end);
2089 if (action_block_entry*
const new_begin_or_before_end(
2090 old_begin_or_before_end->begin_or_before_end); assert(
nullptr != new_begin_or_before_end),
2091 assert(
nullptr != new_begin_or_before_end->succ),
2092 assert(new_begin_or_before_end->succ->block_bunch->pred->action_block ==
2093 new_begin_or_before_end),
2094 new_begin_or_before_end < new_action_block_pos)
2095 { assert(old_begin_or_before_end==new_begin_or_before_end->begin_or_before_end);
2096 new_action_block_pos->begin_or_before_end =
2097 new_begin_or_before_end; assert(new_action_block_pos <= old_begin_or_before_end);
2102 assert(new_begin_or_before_end == new_action_block_pos);
2104 if (old_begin_or_before_end < new_action_block_pos)
2111 bunch_t*
const bunch(new_action_block_pos->succ->bunch());
2112 if (!bunch->is_trivial()) {
return; } assert(old_begin_or_before_end + 1 == bunch->end);
2113 if (bunch->begin < new_action_block_pos)
2115 make_nontrivial(bunch);
2144 bool make_noninert(pred_entry*
const old_pred_pos,
2145 block_bunch_slice_iter_or_null_t*
const new_noninert_block_bunch_ptr)
2147 state_info_entry*
const source(old_pred_pos->source); assert(source->pos->st == source);
2148 state_info_entry*
const target(old_pred_pos->target); assert(target->pos->st == target);
2150 action_block_entry*
const new_action_block_pos(
2151 action_block_inert_begin++); assert(
nullptr != new_action_block_pos->succ);
2152 assert(new_action_block_pos->succ->block_bunch->pred->action_block ==
2153 new_action_block_pos);
2154 succ_entry*
const new_succ_pos(source->succ_inert.begin++); assert(new_succ_pos->block_bunch->pred->action_block->succ == new_succ_pos);
2155 block_bunch_entry*
const new_block_bunch_pos(
2156 block_bunch_inert_begin++); assert(
nullptr != new_block_bunch_pos->pred->action_block->succ);
2157 assert(new_block_bunch_pos->pred->action_block->succ->block_bunch ==
2158 new_block_bunch_pos);
2159 action_block_entry*
const old_action_block_pos(
2160 old_pred_pos->action_block); assert(new_action_block_pos <= old_action_block_pos);
2162 succ_entry*
const old_succ_pos(old_action_block_pos->succ); assert(
nullptr != old_succ_pos);
2163 block_bunch_entry*
const old_block_bunch_pos(
2164 old_succ_pos->block_bunch); assert(old_pred_pos == old_block_bunch_pos->pred);
2165 pred_entry*
const new_pred_pos(target->pred_inert.begin++); assert(
nullptr != new_pred_pos->action_block->succ);
2166 assert(new_pred_pos->action_block->succ->block_bunch->pred == new_pred_pos);
2168 assert(
nullptr == new_action_block_pos->begin_or_before_end);
2169 if (new_action_block_pos < old_action_block_pos)
2170 { assert(
nullptr == old_action_block_pos->begin_or_before_end);
2171 old_action_block_pos->succ = new_action_block_pos->succ; assert(
nullptr != old_action_block_pos->succ);
2172 assert(old_action_block_pos->succ->block_bunch->pred->action_block ==
2173 new_action_block_pos);
2174 old_action_block_pos->succ->block_bunch->pred->action_block =
2175 old_action_block_pos;
2179 assert(new_action_block_pos == old_action_block_pos);
2181 new_action_block_pos->succ = new_succ_pos; assert(
nullptr != new_succ_pos);
2184 assert(
nullptr == new_succ_pos->begin_or_before_end);
2185 if (new_succ_pos < old_succ_pos)
2186 { assert(
nullptr == old_succ_pos->begin_or_before_end);
2187 old_succ_pos->block_bunch = new_succ_pos->block_bunch; assert(old_succ_pos->block_bunch->pred->action_block->succ == new_succ_pos);
2188 old_succ_pos->block_bunch->pred->action_block->succ = old_succ_pos; assert(
nullptr != old_succ_pos);
2192 assert(new_succ_pos == old_succ_pos);
2194 new_succ_pos->block_bunch = new_block_bunch_pos;
2197 assert(new_block_bunch_pos->slice.is_null());
2198 if (new_block_bunch_pos < old_block_bunch_pos)
2199 { assert(old_block_bunch_pos->slice.is_null());
2200 assert(
nullptr != old_block_bunch_pos->pred->action_block->succ);
2201 old_block_bunch_pos->pred = new_block_bunch_pos->pred; assert(old_block_bunch_pos->pred->action_block->succ->block_bunch ==
2202 new_block_bunch_pos);
2203 assert(
nullptr != old_block_bunch_pos->pred->action_block->succ);
2204 old_block_bunch_pos->pred->action_block->succ->block_bunch =
2205 old_block_bunch_pos;
2209 assert(new_block_bunch_pos == old_block_bunch_pos);
2211 new_block_bunch_pos->pred = new_pred_pos;
2215 if (new_pred_pos < old_pred_pos)
2219 std::swap(*old_pred_pos, *new_pred_pos); assert(
nullptr != old_pred_pos->action_block->succ);
2220 assert(old_pred_pos->action_block->succ->block_bunch->pred == new_pred_pos);
2221 old_pred_pos->action_block->succ->block_bunch->pred = old_pred_pos;
2225 assert(new_pred_pos == old_pred_pos);
2227 new_pred_pos->action_block = new_action_block_pos;
2229 assert(source->bl.ock->nonbottom_begin <= source->pos);
2230 bool became_bottom(
false); assert(succ.back().block_bunch->pred->source != source);
2231 if (source != source->succ_inert.begin->block_bunch->pred->source)
2233 block_t*
const source_block(source->bl.ock);
2235 if (source->pos >= source_block->marked_nonbottom_begin)
2237 std::swap(*source->pos,
2238 *source_block->marked_nonbottom_begin++);
2239 } assert(source->pos < source_block->marked_nonbottom_begin);
2240 std::swap(*source->pos, *source_block->nonbottom_begin++);
2241 ++nr_of_new_bottom_states;
2242 became_bottom =
true;
2245 bunch_t* new_noninert_bunch; assert(
nullptr != new_action_block_pos);
2246 if (!new_noninert_block_bunch_ptr->is_null())
2255 new_noninert_bunch = (*new_noninert_block_bunch_ptr)->bunch; assert(new_action_block_pos >= new_noninert_bunch->end);
2257 for (
const action_block_entry*temp_action_block_pos=new_action_block_pos ;
2258 temp_action_block_pos > new_noninert_bunch->end ; )
2260 assert(
nullptr == (--temp_action_block_pos)->succ);
2263 new_noninert_bunch->end = action_block_inert_begin;
2264 assert((*new_noninert_block_bunch_ptr)->end == new_block_bunch_pos);
2265 (*new_noninert_block_bunch_ptr)->end = block_bunch_inert_begin;
2266 if (!(*new_noninert_block_bunch_ptr)->is_stable())
2267 { assert((*new_noninert_block_bunch_ptr)->marked_begin == new_block_bunch_pos);
2268 (*new_noninert_block_bunch_ptr)->marked_begin =
2269 block_bunch_inert_begin;
2271 new_block_bunch_pos->slice = *new_noninert_block_bunch_ptr;
2273 assert(new_noninert_bunch->begin < new_action_block_pos);
2274 if (
nullptr != new_action_block_pos[-1].succ &&
2275 target->bl.ock == new_action_block_pos[-1].
2276 succ->block_bunch->pred->target->bl.ock)
2279 action_block_entry*
const action_block_slice_begin(
2280 new_action_block_pos[-1].begin_or_before_end); assert(
nullptr != action_block_slice_begin);
2281 assert(new_action_block_pos-1==action_block_slice_begin->begin_or_before_end);
2282 assert(
nullptr != action_block_slice_begin->succ);
2283 assert(action_block_slice_begin->succ->block_bunch->pred->action_block ==
2284 action_block_slice_begin);
2285 action_block_slice_begin->begin_or_before_end =
2286 new_action_block_pos;
2287 new_action_block_pos->begin_or_before_end =
2288 action_block_slice_begin;
2293 new_action_block_pos->begin_or_before_end=new_action_block_pos;
2294 if (new_noninert_bunch->is_trivial())
2296 make_nontrivial(new_noninert_bunch);
2304 for (
const action_block_entry* iter = action_block.data();
2305 iter < new_noninert_bunch->begin; ++iter)
2307 assert(
nullptr == iter->succ);
2308 assert(
nullptr == iter->begin_or_before_end);
2312 ++nr_of_action_block_slices;
2315 assert(source != succ.front().block_bunch->pred->source);
2316 if (source == new_succ_pos[-1].block_bunch->pred->source &&
2317 new_succ_pos[-1].bunch() == new_noninert_bunch)
2320 succ_entry*
const out_slice_begin(
2321 new_succ_pos[-1].begin_or_before_end); assert(
nullptr != out_slice_begin);
2322 assert(new_succ_pos - 1 == out_slice_begin->begin_or_before_end);
2323 out_slice_begin->begin_or_before_end = new_succ_pos; assert(out_slice_begin->block_bunch->pred->action_block->succ ==
2325 new_succ_pos->begin_or_before_end = out_slice_begin;
2326 return became_bottom;
2332 new_noninert_bunch =
2334 simple_list<block_bunch_slice_t>::get_pool().
2335 template construct<bunch_t>
2339 (new_action_block_pos, action_block_inert_begin);
2344 block_bunch_slice_iter_t new_noninert_block_bunch(
2345 splitter_list.emplace_back(
2346 block_bunch_inert_begin, new_noninert_bunch,
false));
2348 splitter_list.emplace_back(block_bunch_inert_begin,
2349 new_noninert_bunch,
false);
2350 block_bunch_slice_iter_t new_noninert_block_bunch(
2351 std::prev(splitter_list.end()));
2353 ++nr_of_block_bunch_slices;
2354 new_block_bunch_pos->slice = new_noninert_block_bunch;
2355 *new_noninert_block_bunch_ptr = new_noninert_block_bunch;
2358 new_action_block_pos->begin_or_before_end = new_action_block_pos;
2359 ++nr_of_action_block_slices;
2360 } assert(&succ.cbegin()[1] == new_succ_pos ||
2361 new_succ_pos[-1].block_bunch->pred->source < source ||
2362 new_succ_pos[-1].bunch() != new_noninert_bunch);
2363 new_succ_pos->begin_or_before_end = new_succ_pos;
2364 return became_bottom;
2391 void adapt_transitions_for_new_block(
2392 block_t*
const new_block,
2393 block_t*
const old_block,
ONLY_IF_DEBUG(
const bisim_partitioner_dnj<LTS_TYPE>& partitioner, )
2394 bool const add_new_noninert_to_splitter,
2395 const block_bunch_slice_iter_t splitter_T,
2396 enum new_block_mode_t
const new_block_mode)
2397 { assert(splitter_T->is_stable());
2400 permutation_entry* s_iter(new_block->begin); assert(s_iter < new_block->end);
2403 state_info_entry*
const s(s_iter->st); assert(new_block == s->bl.ock);
2404 assert(s->pos == s_iter);
2406 assert(s != succ.front().block_bunch->pred->source);
2407 for (succ_entry* succ_iter(s->succ_inert.begin);
2408 s == succ_iter[-1].block_bunch->pred->source; )
2410 succ_iter = move_out_slice_to_new_block(succ_iter,
ONLY_IF_DEBUG( partitioner, )
2411 old_block, splitter_T); assert(succ_iter->block_bunch->pred->action_block->succ == succ_iter);
2412 assert(s == succ_iter->block_bunch->pred->source);
2417 assert(s != pred.front().target);
2418 for (pred_entry* pred_iter(s->pred_inert.begin);
2419 s == (--pred_iter)->target; )
2420 { assert(pred.data() < pred_iter);
2421 assert(
nullptr != pred_iter->action_block->succ);
2422 assert(pred_iter->action_block->succ->block_bunch->pred == pred_iter);
2423 first_move_transition_to_new_action_block(pred_iter);
2426 while (++s_iter < new_block->end);
2428 if (new_block_is_R == new_block_mode)
2429 { assert(splitter_T->source_block() == new_block);
2432 new_block->stable_block_bunch.splice(
2433 new_block->stable_block_bunch.begin(),
2434 old_block->stable_block_bunch, splitter_T);
2438 assert(splitter_T->source_block() == old_block);
2444 s_iter = new_block->begin; assert(s_iter < new_block->end);
2447 state_info_entry*
const s(s_iter->st); assert(s->pos == s_iter); assert(s != pred.front().target);
2448 for (pred_entry* pred_iter(s->pred_inert.begin);
2449 s == (--pred_iter)->target; )
2450 { assert(pred.data() < pred_iter);
2451 assert(
nullptr != pred_iter->action_block->succ);
2452 assert(pred_iter->action_block->succ->block_bunch->pred == pred_iter);
2453 second_move_transition_to_new_action_block(pred_iter);
2456 while (++s_iter < new_block->end);
2457 assert(0 == new_block->marked_size()); assert(0 == old_block->marked_size());
2458 assert(block_bunch.data_end() - block_bunch_inert_begin ==
2459 action_block.data_end() - action_block_inert_begin);
2460 if (block_bunch_inert_begin < block_bunch.data_end())
2462 block_bunch_slice_iter_or_null_t new_noninert_block_bunch;
2463 if (add_new_noninert_to_splitter)
2465 new_noninert_block_bunch = splitter_T;
2469 new_noninert_block_bunch =
nullptr;
2471 if (new_block_is_U == new_block_mode)
2472 { assert(old_block == new_block->end->st->bl.ock);
2473 assert(new_block->end < partitioner.part_st.permutation.data_end());
2474 permutation_entry* target_iter(new_block->begin); assert(target_iter < new_block->end);
2477 state_info_entry*
const s(target_iter->st); assert(s->pos == target_iter);
2479 assert(s != pred.back().target);
2480 for (pred_entry* pred_iter(s->pred_inert.begin);
2481 s == pred_iter->target; ++pred_iter)
2482 { assert(pred_iter < &pred.back());
2483 assert(
nullptr != pred_iter->action_block->succ);
2484 state_info_entry*
const t(pred_iter->source); assert(pred_iter->action_block->succ->block_bunch->pred == pred_iter);
2485 assert(t->pos->st == t);
2486 if (new_block != t->bl.ock)
2487 { assert(old_block == t->bl.ock);
2488 if (!make_noninert(pred_iter,
2489 &new_noninert_block_bunch))
2492 old_block->mark_nonbottom(t->pos);
2498 while (++target_iter < new_block->end); assert(0 < old_block->bottom_size());
2501 { assert(new_block_is_R == new_block_mode);
2502 assert(partitioner.part_st.permutation.data() < new_block->begin);
2503 assert(old_block == new_block->begin[-1].st->bl.ock);
2504 assert(0 < old_block->bottom_size());
2505 for(permutation_entry* source_iter(new_block->nonbottom_begin);
2506 source_iter < new_block->marked_nonbottom_begin; )
2508 state_info_entry*
const s(source_iter->st); assert(s->pos == source_iter);
2510 assert(succ.back().block_bunch->pred->source != s);
2511 succ_entry* succ_iter(s->succ_inert.begin); assert(succ_iter < &succ.back());
2512 bool dont_mark(
true); assert(s == succ_iter->block_bunch->pred->source);
2514 { assert(succ_iter->block_bunch->pred->action_block->succ == succ_iter);
2516 succ_iter->block_bunch->pred->target->bl.ock)
2517 { assert(old_block == succ_iter->block_bunch->pred->target->bl.ock);
2518 dont_mark = make_noninert(
2519 succ_iter->block_bunch->pred,
2520 &new_noninert_block_bunch);
2524 while (s == (++succ_iter)->block_bunch->pred->source);
2530 { assert(s->pos == source_iter);
2531 new_block->mark_nonbottom(source_iter);
2532 } assert(new_block->nonbottom_begin <= source_iter);
2539 assert(block_bunch_inert_begin == block_bunch.data_end());
2542 adapt_transitions_for_new_block, check_complexity::log_n -
2543 check_complexity::ilog2(new_block->size())), partitioner);
2548 template <
class LTS_TYPE>
2549 void print_trans(
const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
const
2551 if (!mCRL2logEnabled(log::debug))
2556 const succ_entry* succ_iter(&succ.cbegin()[1]);
2557 if (succ_iter >= &succ.back())
2559 mCRL2log(log::debug) <<
"No transitions.\n";
2562 const state_info_entry* source(succ_iter->block_bunch->pred->source);
2563 mCRL2log(log::debug) << source->debug_id(partitioner) <<
":\n";
2564 if (succ_iter->block_bunch->slice.is_null())
2566 mCRL2log(log::debug) <<
"\tInert successors:\n";
2568 block_bunch_slice_iter_or_null_t current_out_bunch(
nullptr);
2571 bool always_print=
false;
2572 if (source != succ_iter->block_bunch->pred->source)
2573 { assert(source < succ_iter->block_bunch->pred->source);
2574 source = succ_iter->block_bunch->pred->source;
2576 << source->debug_id(partitioner) <<
":\n";
2580 succ_iter->block_bunch->slice != current_out_bunch)
2582 if (succ_iter->block_bunch->slice.is_null())
2583 { assert(succ_iter == source->succ_inert.begin);
2584 mCRL2log(log::debug)<<
"\tInert successors:\n";
2585 current_out_bunch =
nullptr;
2588 { assert(succ_iter < source->succ_inert.begin);
2592 mCRL2log(log::debug) <<
"\tSuccessors in "
2593 <<succ_iter->bunch()->debug_id_short(partitioner)<<
":\n";
2594 current_out_bunch = succ_iter->block_bunch->slice;
2598 << succ_iter->block_bunch->pred->debug_id(partitioner) <<
'\n';
2600 while (++succ_iter < &succ.back());
2603 const action_block_entry* action_block_iter(action_block.data());
2605 assert(action_block_iter
2611 == action_block_iter
2615 == action_block_iter
2616 ->begin_or_before_end),
2617 ++action_block_iter,
2621 const action_block_entry* bunch_end;
2622 const action_block_entry* action_block_slice_end;
2623 assert(
nullptr != action_block_iter->succ);
2624 if (action_block_iter->succ->block_bunch->slice.is_null())
2625 { assert(action_block_iter == action_block_inert_begin);
2626 mCRL2log(log::debug) <<
"Inert transition slice [";
2627 action_block_slice_end = bunch_end = action_block.data_end();
2631 const bunch_t*
const bunch(action_block_iter->succ->bunch());
2632 assert(
nullptr != bunch);
2633 mCRL2log(log::debug) << bunch->debug_id_short(
2634 partitioner) <<
":\n\taction_block-slice [";
2635 assert(bunch->begin == action_block_iter);
2636 bunch_end = bunch->end;
2637 assert(bunch_end <= action_block_inert_begin);
2638 assert(
nullptr != action_block_iter->begin_or_before_end);
2639 action_block_slice_end =
2640 action_block_iter->begin_or_before_end + 1;
2642 assert(action_block_slice_end <= bunch_end);
2646 mCRL2log(log::debug) << (action_block_iter -
2647 action_block.data()) <<
","
2648 << (action_block_slice_end - action_block.data()) <<
"):\n";
2650 assert(action_block_iter < action_block_slice_end);
2653 assert(
nullptr != action_block_iter->succ);
2655 << action_block_iter->succ->block_bunch->
2656 pred->debug_id(partitioner) <<
'\n';
2658 while (++action_block_iter < action_block_slice_end);
2660 while (action_block_iter < bunch_end &&
2661 nullptr == action_block_iter->succ)
2663 assert(
nullptr == action_block_iter->begin_or_before_end);
2664 ++action_block_iter;
2665 assert(action_block_iter < bunch_end);
2667 if (action_block_iter
2672 assert(
nullptr != action_block_iter->begin_or_before_end);
2673 action_block_slice_end =
2674 action_block_iter->begin_or_before_end + 1;
2675 mCRL2log(log::debug) <<
"\taction_block-slice [";
2678 assert(action_block_iter == bunch_end);
2679 while (action_block_iter < action_block.data_end() &&
2680 nullptr == action_block_iter->succ)
2682 assert(
nullptr == action_block_iter->begin_or_before_end);
2683 ++action_block_iter;
2686 while (action_block_iter < action_block.data_end());
2702inline block_t* block_t::split_off_block(
2703 enum new_block_mode_t
const new_block_mode,
ONLY_IF_DEBUG(
const bisim_partitioner_dnj<LTS_TYPE>& partitioner, )
2704 state_type
const new_seqnr)
2705{ assert(0 < marked_size()); assert(0 < unmarked_bottom_size());
2708 state_type swapcount(std::min(marked_bottom_size(),
2709 unmarked_nonbottom_size()));
2710 if (permutation_entry*
const splitpoint(marked_bottom_begin +
2711 unmarked_nonbottom_size()); assert(begin < splitpoint), assert(splitpoint < end),
2712 assert(splitpoint->st->pos == splitpoint),
2713 new_block_is_U == new_block_mode)
2714 { assert((state_type) (splitpoint - begin) <= size()/2);
2717 simple_list<block_bunch_slice_t>::get_pool().
2718 template construct<block_t>
2722 (begin, splitpoint, new_seqnr);
2723 new_block->nonbottom_begin = marked_bottom_begin;
2727 nonbottom_begin = marked_nonbottom_begin;
2730 { assert(new_block_is_R == new_block_mode);
2733 simple_list<block_bunch_slice_t>::get_pool().
2734 template construct<block_t>
2738 (splitpoint, end, new_seqnr);
2739 new_block->nonbottom_begin = marked_nonbottom_begin; assert((state_type) (end - splitpoint) <= size()/2);
2743 nonbottom_begin = marked_bottom_begin;
2745 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
2746 new_block->work_counter = work_counter;
2761 permutation_entry* pos1(marked_bottom_begin);
2762 permutation_entry* pos2(marked_nonbottom_begin); assert(pos1 < pos2);
2763 permutation_entry
const temp(std::move(*pos1));
2766 --pos2; assert(pos1 < pos2);
2767 *pos1 = std::move(*pos2);
2769 if (0 >= --swapcount) {
break; } assert(pos1 < pos2);
2770 *pos2 = std::move(*pos1);
2772 *pos2 = std::move(temp);
2775 {
const permutation_entry* s_iter(begin); assert(s_iter < end);
2778 s_iter->st->pos == s_iter);
2780 while (++s_iter < end);
2784 marked_nonbottom_begin = end;
2785 marked_bottom_begin = nonbottom_begin;
2786 new_block->marked_bottom_begin = new_block->nonbottom_begin; assert(new_block->size() <= size());
2788 assert(new_block->marked_nonbottom_begin == new_block->end);
2789 permutation_entry* s_iter(new_block->begin); assert(s_iter < new_block->end);
2791 { assert(s_iter->st->pos == s_iter);
2792 s_iter->st->bl.ock = new_block;
2794 while (++s_iter < new_block->end);
mCRL2complexity(new_block, add_work(check_complexity::split_off_block,
2795 check_complexity::log_n - check_complexity::ilog2(new_block->size())),
2811inline bunch_t* bunch_t::split_off_small_action_block_slice(
2812 part_trans_t& part_tr)
2813{ assert(begin < end); assert(
nullptr != begin->succ);
2814 assert(
nullptr != begin->begin_or_before_end);
2815 action_block_entry*
const first_slice_end(begin->begin_or_before_end + 1); assert(
nullptr != end[-1].succ); assert(
nullptr!=end[-1].begin_or_before_end);
2816 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);
2817 bunch_t* bunch_T_a_Bprime;
2818 assert(last_slice_begin < end); assert(
nullptr != first_slice_end[-1].succ);
2819 assert(
nullptr != last_slice_begin->succ);
2820 if (first_slice_end - begin > end - last_slice_begin)
2825 simple_list<block_bunch_slice_t>::get_pool().
2826 template construct<bunch_t>
2830 (last_slice_begin, end); assert(
nullptr != bunch_T_a_Bprime);
2831 end = last_slice_begin;
2832 while (
nullptr == end[-1].succ)
2834 --end; assert(first_slice_end <= end); assert(
nullptr == end->begin_or_before_end);
2835 } assert(
nullptr != end[-1].begin_or_before_end);
2836 if (first_slice_end == end)
2838 part_tr.make_trivial(
this);
2846 simple_list<block_bunch_slice_t>::get_pool().
2847 template construct<bunch_t>
2851 (begin, first_slice_end); assert(
nullptr != bunch_T_a_Bprime);
2852 begin = first_slice_end;
2853 while (
nullptr == begin->succ)
2854 { assert(
nullptr == begin->begin_or_before_end);
2855 ++begin; assert(begin <= last_slice_begin);
2856 } assert(
nullptr != begin->begin_or_before_end);
2857 if (begin == last_slice_begin)
2859 part_tr.make_trivial(
this);
2862 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
2863 bunch_T_a_Bprime->work_counter = work_counter;
2865 ++part_tr.nr_of_bunches;
2866 return bunch_T_a_Bprime;
2893
2894
2903template <
class LTS_TYPE>
2904class bisim_partitioner_dnj
2908 enum refine_mode_t{extend_from_marked_states,
2909 extend_from_marked_states_add_new_noninert_to_splitter,
2910 extend_from_splitter };
2916 bisim_dnj::part_state_t part_st;
2920 bisim_dnj::part_trans_t part_tr;
2931 fixed_vector<bisim_dnj::iterator_or_counter<
2932 bisim_dnj::action_block_entry*> > action_label;
2935 bool const branching;
2942 bool const preserve_divergence;
2943 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
2944 friend class bisim_dnj::pred_entry;
2945 friend class bisim_dnj::bunch_t;
2949 std::clock_t end_initial_part;
2962 bisim_partitioner_dnj(LTS_TYPE& new_aut,
bool const new_branching =
false,
2963 bool const new_preserve_divergence =
false)
2965 part_st(new_aut.num_states()),
2966 part_tr(new_aut.num_transitions(), new_aut.num_action_labels()),
2967 action_label(new_aut.num_action_labels()),
2968 branching(new_branching),
2969 preserve_divergence(new_preserve_divergence)
2970 { assert(branching || !preserve_divergence);
2972 create_initial_partition();
ONLY_IF_DEBUG( part_tr.action_block_orig_inert_begin =
2973 part_tr.action_block_inert_begin; )
2974 end_initial_part = std::clock();
2975 refine_partition_until_it_becomes_stable();
2983 state_type num_eq_classes()
const
2985 return part_st.nr_of_blocks;
2996 state_type get_eq_class(state_type
const s)
const
2998 return part_st.block(s)->seqnr;
3014 void finalize_minimized_LTS()
3021 const bisim_dnj::permutation_entry* s_iter(part_st.permutation.data()); assert(s_iter < part_st.permutation.data_end());
3024 const bisim_dnj::block_t*
const B(s_iter->st->bl.ock);
3026 for (
const bisim_dnj::block_bunch_slice_t& block_bunch :
3027 B->stable_block_bunch)
3028 { assert(block_bunch.is_stable()); assert(!block_bunch.empty());
3029 const bisim_dnj::pred_entry*
const
3030 pred(block_bunch.end[-1].pred); assert(pred->source->bl.ock == B);
3031 assert(
nullptr != pred->action_block->succ);
3032 assert(pred->action_block->succ->block_bunch->pred == pred);
3033 assert(pred->action_block->succ->block_bunch->slice == &block_bunch);
3035 label(block_bunch.bunch->next_nontrivial_and_label.label); assert(0 <= label); assert(label < action_label.size());
3036 aut.add_transition(transition(B->seqnr, label,
3037 pred->target->bl.ock->seqnr));
3041 while (s_iter < part_st.permutation.data_end());
3046 if (aut.has_state_info())
3047
3050 std::remove_reference_t<
decltype(aut.state_labels())> new_labels(num_eq_classes());
3052 state_type i(0); assert(i < aut.num_states());
3055 const state_type new_index(get_eq_class(i));
3056 new_labels[new_index]=new_labels[new_index]+aut.state_label(i);
3058 while (++i < aut.num_states());
3060 aut.set_num_states(num_eq_classes(),
false); assert(0 == aut.num_state_labels());
3061 new_labels.swap(aut.state_labels());
3065 aut.set_num_states(num_eq_classes(),
false);
3068 aut.set_initial_state(get_eq_class(aut.initial_state()));
3076 bool in_same_class(state_type
const s, state_type
const t)
const
3078 return part_st.block(s) == part_st.block(t);
3106 void create_initial_partition()
3108 mCRL2log(log::verbose) <<
"An O(m log n) "
3109 << (branching ? (preserve_divergence
3110 ?
"divergence-preserving branching "
3113 <<
"bisimulation partitioner created for " << part_st.state_size()
3114 <<
" states and " << aut.num_transitions() <<
" transitions.\n";
3116 if (part_st.state_size() > 2 * aut.num_transitions() + 1)
3118 mCRL2log(log::warning) <<
"There are several isolated states "
3119 "without incoming or outgoing transition. It is not "
3120 "guaranteed that branching bisimulation minimisation runs in "
3121 "time O(m log n).\n";
3124 sort_transitions(aut.get_transitions(), tgt_lbl_src);
3125 mCRL2log(log::verbose) <<
"Carried out sorting\n";
3127 bisim_dnj::block_t* B(
3129 simple_list<bisim_dnj::block_bunch_slice_t>::get_pool().
3130 template construct<bisim_dnj::block_t>
3132 new bisim_dnj::block_t
3134 (part_st.permutation.data(),
3135 part_st.permutation.data_end(), part_st.nr_of_blocks++));
3145 assert(action_label.size() == aut.num_action_labels());
3147 trans_type inert_transitions(0);
3148 for (
const transition& t: aut.get_transitions())
3150 if (branching&&aut.is_tau(aut.apply_hidden_label_map(t.label()))&& ((
3151 t.from() != t.to()) || (assert(preserve_divergence),
false)))
3154 ++part_st.state_info[t.from()].succ_inert.count;
3155 ++inert_transitions;
3158 if (part_st.state_info[t.from()].pos < B->nonbottom_begin)
3160 std::swap(*part_st.state_info[t.from()].pos,
3161 *--B->nonbottom_begin);
3168 ++part_st.state_info[t.from()].untested_to_U_eqv.count;
3169 ++action_label[aut.apply_hidden_label_map(t.label())].count;
3171 ++part_st.state_info[t.to()].pred_inert.count;
3174 B->marked_bottom_begin = B->nonbottom_begin;
3182 bisim_dnj::pred_entry* next_pred_begin(&part_tr.pred.begin()[1]);
3183 bisim_dnj::succ_entry* next_succ_begin(&part_tr.succ.begin()[1]);
3184 bisim_dnj::state_info_entry* state_iter(part_st.state_info.data()); assert(state_iter < part_st.state_info.data_end());
3187 state_iter->bl.ed_noninert_end = next_pred_begin;
3188 next_pred_begin += state_iter->pred_inert.count;
3189 state_iter->pred_inert.convert_to_iterator(next_pred_begin);
3192 assert(
nullptr != next_succ_begin);
3193 state_iter->untested_to_U_eqv.convert_to_iterator(
3194 next_succ_begin + state_iter->untested_to_U_eqv.count);
3195 if (next_succ_begin < state_iter->untested_to_U_eqv.begin)
3196 { assert(
nullptr != state_iter->untested_to_U_eqv.begin);
3197 next_succ_begin->begin_or_before_end =
3198 state_iter->untested_to_U_eqv.begin - 1;
3199 for (bisim_dnj::succ_entry*
const
3200 out_slice_begin(next_succ_begin);
3201 ++next_succ_begin < state_iter->untested_to_U_eqv.begin; )
3203 next_succ_begin->begin_or_before_end = out_slice_begin;
3206 B->mark(state_iter->pos);
3208 state_iter->succ_inert.convert_to_iterator(next_succ_begin +
3209 state_iter->succ_inert.count);
3211 while (next_succ_begin < state_iter->succ_inert.begin)
3212 { assert(
nullptr == next_succ_begin->begin_or_before_end);
3216 next_succ_begin = state_iter->succ_inert.begin;
3218 while (++state_iter < part_st.state_info.data_end());
3221 part_tr.action_block_inert_begin =
3222 part_tr.action_block.data_end() - inert_transitions; assert(part_tr.action_block.data() <= part_tr.action_block_inert_begin);
3223 part_tr.block_bunch_inert_begin =
3224 part_tr.block_bunch.data_end() - inert_transitions; assert(part_tr.block_bunch.data() < part_tr.block_bunch_inert_begin);
3225 bisim_dnj::bunch_t* bunch(
nullptr);
3227 if (1 + part_tr.block_bunch.data() < part_tr.block_bunch_inert_begin)
3228 { assert(part_tr.action_block.data() < part_tr.action_block_inert_begin);
3232 simple_list<bisim_dnj::block_bunch_slice_t>::get_pool().
3233 template construct<bisim_dnj::bunch_t>
3235 new bisim_dnj::bunch_t
3237 (part_tr.action_block.data(),
3238 part_tr.action_block_inert_begin); assert(
nullptr != bunch); assert(part_tr.splitter_list.empty());
3239 ++part_tr.nr_of_bunches; assert(1 == part_tr.nr_of_bunches);
3242 part_tr.splitter_list.emplace_front(
3243 part_tr.block_bunch_inert_begin, bunch,
false); assert(!part_tr.splitter_list.empty());
3244 ++part_tr.nr_of_block_bunch_slices; assert(1 == part_tr.nr_of_block_bunch_slices);
3255 assert(part_tr.action_block.size() ==
3256 aut.num_transitions() + action_label.size() - 1);
3257 bisim_dnj::action_block_entry*
3258 next_action_label_begin(part_tr.action_block.data());
3259 trans_type
const n_square(part_st.state_size() * part_st.state_size());
3260 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3261 trans_type max_transitions = n_square;
3263 label_type label(action_label.size()); assert(0 < label);
3267 if (0 < action_label[label].count)
3268 { assert(
nullptr != bunch);
3269 if (++part_tr.nr_of_action_block_slices == 2)
3273 part_tr.make_nontrivial(bunch);
3275 if (n_square < action_label[label].count)
3277 mCRL2log(log::warning) <<
"There are "
3278 << action_label[label].count <<
' '
3279 << pp(aut.action_label(label)) <<
"-transitions. "
3280 "This is more than n^2 (= " << n_square <<
"). It is "
3281 "not guaranteed that branching bisimulation "
3282 "minimisation runs in time O(m log n).\n";
3283 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3284 if (max_transitions < action_label[label].count)
3285 { max_transitions = action_label[label].count; }
3290 action_label[label].convert_to_iterator(
3291 next_action_label_begin + action_label[label].count);
3292 next_action_label_begin->begin_or_before_end =
3293 action_label[label].begin - 1; assert(
nullptr != next_action_label_begin->begin_or_before_end);
3294 bisim_dnj::action_block_entry*
const
3295 action_block_slice_begin(next_action_label_begin); assert(
nullptr != action_block_slice_begin);
3296 while (++next_action_label_begin < action_label[label].begin)
3298 next_action_label_begin->begin_or_before_end =
3299 action_block_slice_begin;
3304 action_label[label].convert_to_iterator(
3305 next_action_label_begin);
3306 if (0 != label && aut.num_transitions() < action_label.size())
3308 mCRL2log(log::warning) <<
"Action label "
3309 << pp(aut.action_label(label)) <<
" has no "
3310 "transitions, and the number of action labels exceeds "
3311 "the number of transitions. It is not guaranteed that "
3312 "branching bisimulation minimisation runs in time "
3317 while (0 < label && ( assert(next_action_label_begin < part_tr.action_block_inert_begin),
3318 next_action_label_begin->succ =
nullptr,
3319 next_action_label_begin->begin_or_before_end =
nullptr,
3320 ++next_action_label_begin,
true)); assert(next_action_label_begin == part_tr.action_block_inert_begin);
3321 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3322 check_complexity::init(2 * max_transitions);
3324 bisim_dnj::block_bunch_entry*
3325 next_block_bunch(1 + part_tr.block_bunch.data());
3326 for (
const transition& t: aut.get_transitions())
3328 bisim_dnj::state_info_entry*
const
3329 source(part_st.state_info.data() + t.from());
3330 bisim_dnj::state_info_entry*
const
3331 target(part_st.state_info.data() + t.to());
3332 bisim_dnj::succ_entry* succ_pos;
3333 bisim_dnj::block_bunch_entry* block_bunch_pos;
3334 bisim_dnj::pred_entry* pred_pos;
3335 bisim_dnj::action_block_entry* action_block_pos;
3337 if (branching&&aut.is_tau(aut.apply_hidden_label_map(t.label()))&& ((
3338 t.from() != t.to()) || (assert(preserve_divergence),
false)))
3343 succ_pos = --source->succ_inert.begin; assert(
nullptr == succ_pos->begin_or_before_end);
3344 block_bunch_pos = part_tr.block_bunch.data_end() -
3345 inert_transitions; assert(block_bunch_pos >= part_tr.block_bunch_inert_begin);
3346 pred_pos = --target->pred_inert.begin; assert(block_bunch_pos->slice.is_null());
3347 action_block_pos = part_tr.action_block.data_end() -
3348 inert_transitions; assert(action_block_pos >= part_tr.action_block_inert_begin);
3349 action_block_pos->begin_or_before_end =
nullptr;
3350 --inert_transitions;
3358 --part_st.state_info[t.from()].untested_to_U_eqv.begin; assert(
nullptr != succ_pos->begin_or_before_end);
3359 assert(
nullptr != succ_pos->begin_or_before_end->begin_or_before_end);
3360 assert(succ_pos->begin_or_before_end <= succ_pos ||
3361 succ_pos->begin_or_before_end->begin_or_before_end == succ_pos);
3362 block_bunch_pos = next_block_bunch++; assert(block_bunch_pos < part_tr.block_bunch_inert_begin);
3363 pred_pos = target->bl.ed_noninert_end++;
3365 --action_label[aut.apply_hidden_label_map(t.label())].begin; assert(
nullptr != action_block_pos->begin_or_before_end);
3366 assert(
nullptr != action_block_pos->begin_or_before_end->begin_or_before_end);
3367 assert(action_block_pos->begin_or_before_end <= action_block_pos ||
3368 action_block_pos->begin_or_before_end->
3369 begin_or_before_end == action_block_pos);
3370 assert(!part_tr.splitter_list.empty());
3371 block_bunch_pos->slice = part_tr.splitter_list.begin(); assert(action_block_pos < part_tr.action_block_inert_begin);
3372 } assert(target->bl.ed_noninert_end <= target->pred_inert.begin);
3373 succ_pos->block_bunch = block_bunch_pos;
3374 block_bunch_pos->pred = pred_pos;
3375 pred_pos->action_block = action_block_pos;
3376 pred_pos->source = source;
3377 pred_pos->target = target; assert(
nullptr != succ_pos);
3378 action_block_pos->succ = succ_pos;
3379 } assert(0 == inert_transitions);
3380 assert(next_block_bunch == part_tr.block_bunch_inert_begin);
3382 aut.clear_transitions();
3384 state_iter = part_st.state_info.data(); assert(state_iter < part_st.state_info.data_end());
3387 state_iter->bl.ock = B;
3389 while (++state_iter < part_st.state_info.data_end());
3391 if (
nullptr != bunch)
3393 while (
nullptr == bunch->begin->succ)
3394 { assert(
nullptr == bunch->begin->begin_or_before_end);
3395 ++bunch->begin; assert(bunch->begin < bunch->end);
3396 } assert(
nullptr != bunch->begin->begin_or_before_end);
3397 while (
nullptr == bunch->end[-1].succ)
3398 { assert(
nullptr == bunch->end[-1].begin_or_before_end);
3399 --bunch->end; assert(bunch->begin < bunch->end);
3400 } assert(
nullptr != bunch->end[-1].begin_or_before_end);
3403 create_initial_partition, 1U), *
this);
3409 if (0 < B->marked_size())
3411 part_tr.print_trans(*
this); )
3412 bisim_dnj::block_bunch_slice_iter_t slice =
3413 part_tr.splitter_list.begin();
3418 extend_from_marked_states_add_new_noninert_to_splitter);
3421 B->marked_nonbottom_begin = B->end;
3424 { assert(B->nonbottom_begin == B->end);
3425 assert(B->marked_nonbottom_begin == B->end);
3427 B->stable_block_bunch.splice(B->stable_block_bunch.end(),
3428 part_tr.splitter_list, slice);
3429 slice->make_stable();
3430 } assert(!B->stable_block_bunch.empty()); assert(part_tr.splitter_list.empty());
3431 assert(B->stable_block_bunch.front().end <= part_tr.block_bunch_inert_begin);
3432 assert(1 + part_tr.block_bunch.data() < B->stable_block_bunch.front().end);
3433 B->marked_bottom_begin = B->nonbottom_begin; assert(!B->stable_block_bunch.front().empty());
3438 assert(0 == B->marked_size());
3452 void assert_stability()
const
3454 part_st.assert_consistency(*
this);
3456 assert(part_tr.succ.size() == part_tr.block_bunch.size() + 1);
3457 assert(part_tr.pred.size() == part_tr.block_bunch.size() + 1);
3458 assert(part_tr.action_block.size() ==
3459 part_tr.block_bunch.size() + action_label.size() - 2);
3460 if (part_tr.block_bunch.empty())
3465 assert(part_tr.splitter_list.empty());
3467
3468
3469
3471 trans_type true_nr_of_block_bunch_slices(0);
3473 const bisim_dnj::permutation_entry*
3474 perm_iter(part_st.permutation.data());
3475 assert(perm_iter < part_st.permutation.data_end());
3478 const bisim_dnj::block_t*
const block(perm_iter->st->bl.ock);
3479 unsigned const max_block(check_complexity::log_n -
3480 check_complexity::ilog2(block->size()));
3482 std::unordered_set<
const bisim_dnj::block_bunch_slice_t*>
3483 block_bunch_check_set;
3485 block_bunch_check_set.reserve(
3486 block->stable_block_bunch.size());
3490 for (
const bisim_dnj::block_bunch_slice_t& block_bunch :
3491 block->stable_block_bunch)
3493 assert(block_bunch.source_block() == block);
3494 assert(block_bunch.is_stable());
3495 block_bunch_check_set.insert(&block_bunch);
3497 block_bunch.bunch->max_work_counter(*
this)), *
this);
3498 ++true_nr_of_block_bunch_slices;
3504 trans_type block_bunch_count(0);
3505 const bisim_dnj::state_info_entry*
const state(perm_iter->st);
3506 assert(state!=part_tr.succ.front().block_bunch->pred->source);
3508 for (
const bisim_dnj::succ_entry*
3509 out_slice_end(state->succ_inert.begin);
3510 state == out_slice_end[-1].block_bunch->pred->source; )
3511 { assert(!out_slice_end[-1].block_bunch->slice.is_null());
3512 bisim_dnj::block_bunch_slice_const_iter_t
const
3513 block_bunch_slice(out_slice_end[-1].block_bunch->slice);
3514 const bisim_dnj::bunch_t*
const bunch(
3515 block_bunch_slice->bunch);
3516 assert(block == block_bunch_slice->source_block());
3517 if (block_bunch_slice->is_stable())
3519 assert(1 == block_bunch_check_set.count(
3520 &*block_bunch_slice));
3521 ++block_bunch_count;
3532 const bisim_dnj::succ_entry*
const out_slice_begin(
3533 out_slice_end[-1].begin_or_before_end);
3534 assert(
nullptr != out_slice_begin);
3535 assert(out_slice_begin < out_slice_end);
3536 assert(
nullptr != out_slice_begin->begin_or_before_end);
3537 assert(out_slice_begin->begin_or_before_end + 1 ==
3544 assert(bunch->begin <=
3545 out_slice_end->block_bunch->pred->action_block);
3546 assert(out_slice_end->block_bunch->pred->
3547 action_block < bunch->end);
3548 assert(out_slice_end->block_bunch->slice ==
3550 assert(
nullptr != out_slice_end->begin_or_before_end);
3551 if (out_slice_end->block_bunch + 1 !=
3552 block_bunch_slice->end)
3554 assert(out_slice_end->block_bunch + 1 <
3555 block_bunch_slice->end);
3556 assert(out_slice_end->block_bunch[1].slice ==
3560 no_temporary_work(max_block,
3561 check_complexity::log_n -
3562 check_complexity::ilog2(out_slice_end->
3563 block_bunch->pred->target->bl.ock->size()),
3564 perm_iter < block->nonbottom_begin),*
this);
3566 while (out_slice_begin < out_slice_end &&
3567 (assert(out_slice_begin ==
3568 out_slice_end->begin_or_before_end),
true));
3570 if (perm_iter < block->nonbottom_begin)
3572 assert(block_bunch_check_set.size() == block_bunch_count);
3575 while (++perm_iter < block->end);
3577 while (perm_iter < part_st.permutation.data_end());
3578 assert(part_tr.nr_of_block_bunch_slices ==
3579 true_nr_of_block_bunch_slices);
3580 assert(part_tr.action_block.data()<=part_tr.action_block_inert_begin);
3581 assert(part_tr.block_bunch.data() < part_tr.block_bunch_inert_begin);
3583 { assert(part_tr.action_block_inert_begin <=
3584 part_tr.action_block.data_end());
3585 assert(part_tr.block_bunch_inert_begin <=
3586 part_tr.block_bunch.data_end());
3587 assert(part_tr.block_bunch.data_end() -
3588 part_tr.block_bunch_inert_begin ==
3589 part_tr.action_block.data_end()-part_tr.action_block_inert_begin);
3592 for (
const bisim_dnj::action_block_entry* action_block(
3593 part_tr.action_block_inert_begin);
3594 action_block < part_tr.action_block.data_end();
3596 { assert(
nullptr == action_block->begin_or_before_end);
3597 const bisim_dnj::succ_entry*
const
3598 succ_iter(action_block->succ);
3599 assert(
nullptr != succ_iter);
3600 assert(succ_iter->block_bunch->slice.is_null());
3601 const bisim_dnj::pred_entry*
const
3602 pred_iter(succ_iter->block_bunch->pred);
3603 assert(action_block == pred_iter->action_block);
3604 assert(part_tr.block_bunch_inert_begin <=
3605 succ_iter->block_bunch);
3606 assert(pred_iter->source != pred_iter->target);
3607 assert(pred_iter->source->bl.ock == pred_iter->target->bl.ock);
3608 assert(pred_iter->source->succ_inert.begin <= succ_iter);
3609 assert(pred_iter->source->succ_inert.begin == succ_iter ||
3610 succ_iter[-1].block_bunch->pred->source==pred_iter->source);
3611 assert(pred_iter->target->pred_inert.begin <= pred_iter);
3612 assert(pred_iter->target->pred_inert.begin == pred_iter ||
3613 pred_iter[-1].target == pred_iter->target);
3614 unsigned const max_block(check_complexity::log_n -
3615 check_complexity::ilog2(pred_iter->target->bl.ock->size()));
3617 max_block,
false), *
this);
3622 assert(!preserve_divergence);
3623 assert(part_tr.action_block_inert_begin ==
3624 part_tr.action_block.data_end());
3625 assert(part_tr.block_bunch_inert_begin ==
3626 part_tr.block_bunch.data_end());
3628 const bisim_dnj::action_block_entry*
3629 action_slice_end(part_tr.action_block_inert_begin);
3630 trans_type true_nr_of_bunches(0);
3631 trans_type true_nr_of_nontrivial_bunches(0);
3632 trans_type true_nr_of_action_block_slices(0);
3634 label_type label(0);
3635 assert(label < action_label.size());
3636 const bisim_dnj::bunch_t* previous_bunch(
nullptr);
3639 assert(part_tr.action_block.data() <= action_label[label].begin);
3640 assert(action_label[label].begin <= action_slice_end);
3641 assert(action_slice_end <= part_tr.action_block_inert_begin);
3643 for (
const bisim_dnj::action_block_entry*
3644 action_block_slice_end(action_slice_end);
3645 action_label[label].begin < action_block_slice_end; )
3647 const bisim_dnj::action_block_entry*
const
3648 action_block_slice_begin(
3649 action_block_slice_end[-1].begin_or_before_end);
3650 assert(
nullptr != action_block_slice_begin);
3651 assert(action_block_slice_begin < action_block_slice_end);
3652 assert(action_block_slice_end <= action_slice_end);
3653 assert(
nullptr != action_block_slice_begin->succ);
3654 const bisim_dnj::block_t*
const
3655 target_block(action_block_slice_begin->
3656 succ->block_bunch->pred->target->bl.ock);
3657 const bisim_dnj::bunch_t*
const
3658 bunch(action_block_slice_begin->succ->bunch());
3659 if (previous_bunch != bunch)
3661 assert(
nullptr == previous_bunch);
3662 previous_bunch = bunch;
3663 assert(bunch->end == action_block_slice_end);
3664 if (bunch->begin == action_block_slice_begin)
3669 assert(bunch->is_trivial());
3673 assert(!bunch->is_trivial());
3674 ++true_nr_of_nontrivial_bunches;
3677 bunch->max_work_counter(*
this)), *
this);
3678 ++true_nr_of_bunches;
3680 if(bunch->begin == action_block_slice_begin)
3682 previous_bunch =
nullptr;
3688 < action_block_slice_begin);
3691 assert(action_block_slice_begin->begin_or_before_end + 1 ==
3692 action_block_slice_end);
3694 const bisim_dnj::action_block_entry*
3695 action_block(action_block_slice_end);
3699 const bisim_dnj::succ_entry*
const
3700 succ_iter(action_block->succ);
3701 assert(
nullptr != succ_iter);
3702 const bisim_dnj::pred_entry*
const
3703 pred_iter(succ_iter->block_bunch->pred);
3704 assert(action_block == pred_iter->action_block);
3705 assert(succ_iter->block_bunch <
3706 part_tr.block_bunch_inert_begin);
3707 assert(!branching || !aut.is_tau(label) ||
3708 pred_iter->source->bl.ock!=pred_iter->target->bl.ock ||
3709 (preserve_divergence &&
3710 pred_iter->source == pred_iter->target));
3711 assert(succ_iter < pred_iter->source->succ_inert.begin);
3712 assert(succ_iter+1==pred_iter->source->succ_inert.begin ||
3713 succ_iter[1].block_bunch->pred->source ==
3715 assert(pred_iter < pred_iter->target->pred_inert.begin);
3716 assert(pred_iter+1==pred_iter->target->pred_inert.begin ||
3717 pred_iter[1].target == pred_iter->target);
3718 assert(target_block == pred_iter->target->bl.ock);
3719 assert(bunch == succ_iter->bunch());
3721 while (action_block_slice_begin < action_block &&
3724 assert(action_block->begin_or_before_end ==
3725 action_block_slice_begin),
true));
3726 action_block_slice_end = action_block_slice_begin;
3727 ++true_nr_of_action_block_slices;
3729 if (action_slice_end < part_tr.action_block_inert_begin)
3732 assert(
nullptr == action_slice_end->succ);
3733 assert(
nullptr == action_slice_end->begin_or_before_end);
3736 while (++label < action_label.size() &&
3737 (action_slice_end = action_label[label - 1].begin - 1,
true));
3738 assert(
nullptr == previous_bunch);
3739 assert(part_tr.nr_of_bunches == true_nr_of_bunches);
3740 assert(part_tr.nr_of_nontrivial_bunches ==
3741 true_nr_of_nontrivial_bunches);
3742 assert(part_tr.nr_of_action_block_slices ==
3743 true_nr_of_action_block_slices);
3763 void refine_partition_until_it_becomes_stable()
3766 std::clock_t next_print_time = std::clock();
3767 const std::clock_t rounded_start_time=next_print_time-CLOCKS_PER_SEC/2;
3773 ONLY_IF_DEBUG( part_st.print_part(*
this); part_tr.print_trans(*
this);
3774 assert_stability(); )
3775 assert(part_tr.nr_of_bunches + part_tr.nr_of_nontrivial_bunches <=
3776 part_tr.nr_of_action_block_slices);
3777 bisim_dnj::bunch_t*
const bunch_T(part_tr.get_some_nontrivial());
3778 if (mCRL2logEnabled(log::verbose))
3780 if (std::clock_t now = std::clock(); next_print_time <= now ||
3791 next_print_time+=((now-next_print_time)/(60*CLOCKS_PER_SEC)
3792 + 1) * (60*CLOCKS_PER_SEC);
3793 now = (now - rounded_start_time) / CLOCKS_PER_SEC;
3801 << now / 3600 <<
" h ";
3805 << now / 60 <<
" min ";
3809 <<
" sec passed since starting the main loop.\n";
3811 #define PRINT_SG_PL(counter, sg_string, pl_string)
3813 << (1
== (counter) ? (sg_string) : (pl_string))
3815 << (
nullptr == bunch_T ?
"The reduced LTS contains "
3816 :
"The reduced LTS contains at least ")
3818 " state and ",
" states and ")
3820 " transition.",
" transitions.");
3821 if (1 < part_tr.nr_of_action_block_slices)
3823 #define PRINT_INT_PERCENTAGE(num,denom)
3824 (((num) * 200
+ (denom)) / (denom) / 2
)
3825 mCRL2log(log::verbose) <<
" Estimated "
3827 part_tr.nr_of_action_block_slices - 1)
3829 #undef PRINT_INT_PERCENTAGE
3837 <<
"\nThe current partition contains ";
3842 " new bottom state, ",
" new bottom states, ");
3846 assert(0 == part_tr.nr_of_new_bottom_states);
3850 " bunch (of which ",
" bunches (of which ")
3852 " is nontrivial), and ",
" are nontrivial), and ")
3854 " action-block-slice.\n",
" action-block-slices.\n");
3859 << bunch_T->debug_id(*
this) <<
'\n'; )
3860 assert(part_tr.nr_of_bunches < part_tr.nr_of_action_block_slices);
3861 bisim_dnj::bunch_t*
const bunch_T_a_Bprime(
3862 bunch_T->split_off_small_action_block_slice(part_tr));
3864 << bunch_T_a_Bprime->debug_id(*
this) <<
'\n'; )
3865 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3866 unsigned const max_splitter_counter(
3867 bunch_T_a_Bprime->max_work_counter(*
this));
3869 bisim_dnj::action_block_entry* splitter_iter(
3870 bunch_T_a_Bprime->begin); assert(splitter_iter < bunch_T_a_Bprime->end);
3872 { assert(
nullptr != splitter_iter->succ);
3873 bisim_dnj::state_info_entry*
const
3874 source(splitter_iter->succ->block_bunch->pred->source); assert(splitter_iter->succ->block_bunch->pred->action_block == splitter_iter);
3878 bool const first_transition_of_state(
3879 source->bl.ock->mark(source->pos));
3884 part_tr.first_move_transition_to_new_bunch(splitter_iter,
3885 bunch_T_a_Bprime, first_transition_of_state);
3888 while (++splitter_iter < bunch_T_a_Bprime->end);
3893 splitter_iter = bunch_T_a_Bprime->begin; assert(splitter_iter < bunch_T_a_Bprime->end);
3900 part_tr.second_move_transition_to_new_bunch(splitter_iter,
ONLY_IF_DEBUG( *
this, bunch_T_a_Bprime, )
3904 while (++splitter_iter < bunch_T_a_Bprime->end);
mCRL2complexity(bunch_T_a_Bprime,
3905 add_work(check_complexity::refine_partition_until_stable_find_pred,
3906 max_splitter_counter), *
this);
3907 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3908 bisim_dnj::block_bunch_slice_iter_or_null_t bbslice_T_a_Bprime_B(
nullptr);
3910 while (!part_tr.splitter_list.empty())
3912 bisim_dnj::block_bunch_slice_iter_t splitter_Tprime_B(
3913 part_tr.splitter_list.begin());
3914 bisim_dnj::block_t* block_B(splitter_Tprime_B->source_block()); assert(!splitter_Tprime_B->is_stable());
3915 bool const is_primary_splitter = 0 < block_B->marked_size(); assert(!splitter_Tprime_B->empty());
3916 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3917 bool add_stabilize_to_bottom_transns_succeeded =
true;
3918 if (is_primary_splitter)
3920 assert(bbslice_T_a_Bprime_B.is_null());
3923 check_complexity::refine_partition_until_stable_stabilize,
3924 max_splitter_counter), *
this);
3926 else if (!bbslice_T_a_Bprime_B.is_null())
3931 add_work(check_complexity::
3932 refine_partition_until_stable_stabilize_for_large_splitter,
3933 max_splitter_counter), *
this);
3939 add_stabilize_to_bottom_transns_succeeded = splitter_Tprime_B->
3940 add_work_to_bottom_transns(check_complexity::
3941 refine_partition_until_stable_stabilize_new_noninert_a_priori,
3945 if (1 < block_B->size())
3947 bisim_dnj::permutation_entry*
const
3948 block_B_begin(block_B->begin); assert(block_B_begin->st->pos == block_B_begin);
3952 bisim_dnj::block_t*block_R=split(block_B,splitter_Tprime_B,
3953 is_primary_splitter ? extend_from_marked_states
3954 : extend_from_splitter);
3955 if (block_B_begin < block_R->begin)
3960 if (is_primary_splitter)
3961 { assert(splitter_Tprime_B->bunch == bunch_T_a_Bprime);
3964 bisim_dnj::block_t*
const
3965 block_U(block_B_begin->st->bl.ock); assert(block_U->end == block_R->begin);
3966 bisim_dnj::block_bunch_slice_iter_t U_splitter(
3967 part_tr.splitter_list.begin()); assert(0 == block_U->marked_size());
3968 if (part_tr.splitter_list.end() != U_splitter &&
3969 (U_splitter->source_block() == block_U ||
3970 (++U_splitter != part_tr.splitter_list.end() &&
3971 U_splitter->source_block() == block_U)))
3972 { assert(!U_splitter->is_stable());
3973 assert(U_splitter->bunch == bunch_T);
3974 block_U->stable_block_bunch.splice(
3975 block_U->stable_block_bunch.end(),
3976 part_tr.splitter_list, U_splitter);
3977 U_splitter->make_stable();
3982 for (bisim_dnj::block_bunch_slice_const_iter_t
3983 iter(part_tr.splitter_list.cbegin());
3984 part_tr.splitter_list.cend() != iter; ++iter)
3985 { assert(!iter->is_stable());
3986 assert(iter->source_block() != block_U);
3990 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
3995 if (!add_stabilize_to_bottom_transns_succeeded)
3996 { assert(splitter_Tprime_B->add_work_to_bottom_transns(
3998 refine_partition_until_stable_stabilize_new_noninert_a_posteriori,
4001 if (splitter_Tprime_B->work_counter.has_temporary_work())
4002 { assert(splitter_Tprime_B->add_work_to_bottom_transns(
4004 handle_new_noninert_transns_make_unstable_a_posteriori,
4006 splitter_Tprime_B->work_counter.reset_temporary_work();
4010 if (0 < block_R->marked_size())
4011 {
ONLY_IF_DEBUG(
const bisim_dnj::block_bunch_entry*
const splitter_end =
4012 splitter_Tprime_B->end; )
4020 block_R = handle_new_noninert_transns(
4021 block_R, splitter_Tprime_B);
4023 if (splitter_end[-1].pred->source->bl.ock == block_R)
4024 { assert(!splitter_end[-1].slice.is_null());
4026 (bisim_dnj::block_bunch_slice_iter_t) splitter_end[-1].slice;
4028 assert(
nullptr == block_R || splitter_Tprime_B->source_block() == block_R);
4032 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4034 { assert(0 == block_R->marked_size());
4035 assert(add_stabilize_to_bottom_transns_succeeded);
4037 if (splitter_Tprime_B->work_counter.has_temporary_work())
4038 { assert(!is_primary_splitter);
4039 if (!splitter_Tprime_B->add_work_to_bottom_transns(check_complexity
4040 ::handle_new_noninert_transns_make_unstable_a_posteriori,
4043 splitter_Tprime_B->work_counter.reset_temporary_work();
4050 { assert(block_B->nonbottom_begin == block_B->end);
4051 assert(block_B->marked_nonbottom_begin == block_B->end);
4053 block_B->marked_bottom_begin = block_B->end;
4054 block_B->stable_block_bunch.splice(
4055 block_B->stable_block_bunch.end(),
4056 part_tr.splitter_list, splitter_Tprime_B);
4057 splitter_Tprime_B->make_stable(); assert(add_stabilize_to_bottom_transns_succeeded);
4058 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4060 if (splitter_Tprime_B->work_counter.has_temporary_work())
4061 { assert(!is_primary_splitter);
4062 if (!splitter_Tprime_B->add_work_to_bottom_transns(check_complexity::
4063 handle_new_noninert_transns_make_unstable_a_posteriori,
4066 splitter_Tprime_B->work_counter.reset_temporary_work();
4071 if (is_primary_splitter && !part_tr.splitter_list.empty() &&
4072 part_tr.splitter_list.front().bunch == bunch_T &&
4073 part_tr.splitter_list.front().source_block() == block_B)
4077 assert(
nullptr != block_B);
4078 assert(splitter_Tprime_B->source_block() == block_B);
4079 assert(splitter_Tprime_B->bunch == bunch_T_a_Bprime);
4080 bbslice_T_a_Bprime_B = splitter_Tprime_B;
4084 bbslice_T_a_Bprime_B =
nullptr;
4089 } assert(part_tr.nr_of_bunches == part_tr.nr_of_action_block_slices);
4090 assert(0 == part_tr.nr_of_nontrivial_bunches);
4096 const bisim_dnj::action_block_entry*
4097 action_block_iter_end(part_tr.action_block_inert_begin);
4098 label_type label(0); assert(label < action_label.size());
4101 for (bisim_dnj::action_block_entry*
4102 action_block_iter(action_label[label].begin);
4103 action_block_iter < action_block_iter_end;
4104 action_block_iter = action_block_iter->begin_or_before_end + 1)
4105 { assert(
nullptr != action_block_iter->succ);
4106 assert(action_block_iter->succ->block_bunch->pred->action_block ==
4108 assert(action_block_iter->succ->bunch()->is_trivial());
4109 action_block_iter->succ->bunch()->
4110 next_nontrivial_and_label.label = label; assert(
nullptr != action_block_iter->begin_or_before_end);
4111 assert(action_block_iter <= action_block_iter->begin_or_before_end);
4114 while (++label < action_label.size() &&
4115 (action_block_iter_end = action_label[label - 1].begin - 1,
true));
4154 bisim_dnj::block_t* split(bisim_dnj::block_t*
const block_B,
4155 const bisim_dnj::block_bunch_slice_iter_t splitter_T,
4156 enum refine_mode_t mode)
4157 { assert(block_B == splitter_T->source_block());
4160 << block_B->debug_id(*
this)
4161 <<
',' << splitter_T->debug_id(*
this)
4162 << (extend_from_marked_states_add_new_noninert_to_splitter == mode
4163 ?
",extend_from_marked_states_add_new_noninert_to_splitter)\n"
4164 : (extend_from_marked_states == mode
4165 ?
",extend_from_marked_states)\n"
4166 : (extend_from_splitter == mode
4167 ?
",extend_from_splitter)\n"
4168 :
",UNKNOWN MODE)\n")));
4170 bisim_dnj::block_t* block_R=
nullptr; assert(!splitter_T->is_stable()); assert(1 < block_B->size());
4173 bisim_dnj::block_bunch_entry* splitter_iter;
4174 bisim_dnj::permutation_entry* block;
4177 if (extend_from_splitter == mode)
4178 { assert(0 == block_B->marked_size());
4180 R_s_iter.splitter_iter = splitter_T->end; assert(splitter_T->marked_begin <= R_s_iter.splitter_iter);
4181 while (splitter_T->marked_begin < R_s_iter.splitter_iter)
4182 { assert(&part_tr.block_bunch.cbegin()[1] < R_s_iter.splitter_iter);
4183 --R_s_iter.splitter_iter;
4184 bisim_dnj::state_info_entry*
const
4185 s(R_s_iter.splitter_iter->pred->source); assert(s->bl.ock == block_B); assert(s->pos->st == s);
4186 block_B->mark(s->pos);
4190 }
else { assert(0 < block_B->marked_size());
4191 assert(splitter_T->marked_begin == splitter_T->end); }
4192 block_B->stable_block_bunch.splice(block_B->stable_block_bunch.end(),
4193 part_tr.splitter_list, splitter_T);
4194 splitter_T->make_stable();
4198 bisim_dnj::permutation_entry*
4199 untested_to_U_defined_end(block_B->nonbottom_begin);
4200 bisim_dnj::permutation_entry*
4201 U_nonbottom_end(untested_to_U_defined_end);
4204 bisim_dnj::permutation_entry* U_s_iter;
4205 bisim_dnj::pred_entry* U_t_iter;
4206 bisim_dnj::state_info_entry* U_t;
4207 const bisim_dnj::succ_entry* U_u_iter;
4210 bisim_dnj::pred_entry* R_t_iter;
4213 (SPLIT_U_PREDECESSOR_HANDLED)
4214 (SPLIT_R_STATE_HANDLED)
4215 (SPLIT_U_STATE_HANDLED)
4217 (SPLIT_R_COLLECT_SPLITTER))
4223 if(block_B->size() / 2 < block_B->unmarked_bottom_size())
4229 if (0 == block_B->unmarked_bottom_size())
4234 block_B->marked_nonbottom_begin = block_B->end;
4235 block_B->marked_bottom_begin = block_B->nonbottom_begin;
4237 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4238 finalise_U_is_smaller(
nullptr, block_R, *
this);
4245 if (U_nonbottom_end < block_B->marked_nonbottom_begin)
4248 U_s_iter = block_B->begin;
4250 U_s_iter < U_nonbottom_end)
4252 assert(part_tr.pred.front().target != U_s_iter->st);
4254 U_t_iter = U_s_iter->st->pred_inert.begin,
4255 U_t_iter->target == U_s_iter->st, ++U_t_iter)
4257 U_t = U_t_iter->source; assert(block_B->nonbottom_begin <= U_t->pos);
4258 assert(U_t->pos < block_B->end);
4259 if (block_B->marked_nonbottom_begin <= U_t->pos)
4264 if (untested_to_U_defined_end <= U_t->pos)
4268 U_t->untested_to_U_eqv.begin =
4269 U_t->succ_inert.begin;
4270 std::swap(*U_t->pos,
4271 *untested_to_U_defined_end++);
4273 } assert(U_t != part_tr.succ.back().block_bunch->pred->source);
4275 ++U_t->untested_to_U_eqv.begin;
4277 if (U_t == U_t->untested_to_U_eqv.
4278 begin->block_bunch->pred->source)
4283 if (extend_from_splitter == mode)
4284 { assert(U_t != part_tr.succ.front().block_bunch->pred->source);
4287 U_u_iter = U_t->succ_inert.begin; assert(part_tr.succ.data() < U_u_iter);
4289 U_u_iter[-1].block_bunch->pred->source)
4291 U_u_iter=U_u_iter[-1].begin_or_before_end; assert(
nullptr != U_u_iter);
4292 assert(U_u_iter->block_bunch->pred->source == U_t);
4293 assert(!U_u_iter->block_bunch->slice.is_null());
4294 bisim_dnj::block_bunch_slice_const_iter_t
4296 U_u_iter->block_bunch->slice);
4297 if (&*block_bunch == &*splitter_T)
4302 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4303 bisim_dnj::succ_entry::add_work_to_out_slice(*
this, U_u_iter,
4304 check_complexity::split_U_test_noninert_transitions, 1U);
4309 } assert(U_nonbottom_end <= U_t->pos);
4310 assert(U_t->pos < untested_to_U_defined_end);
4311 std::swap(*U_t->pos, *U_nonbottom_end++);
4313 if (block_B->size() / 2 <
4314 U_nonbottom_end-block_B->nonbottom_begin +
4315 block_B->unmarked_bottom_size())
4323 untested_to_U_defined_end = U_nonbottom_end;
4329 check_complexity::split_U_handle_transition_to_U_state, 1U), *
this);
4332 check_complexity::split_U_find_predecessors_of_U_state, 1U), *
this);
4334 if(block_B->marked_bottom_begin == U_s_iter)
4336 U_s_iter = block_B->nonbottom_begin;
4348 block_B->marked_nonbottom_begin = U_nonbottom_end;
4350 bisim_dnj::block_t*
const block_U(
4351 block_R->split_off_block(bisim_dnj::new_block_is_U,
ONLY_IF_DEBUG( *
this, )
4352 part_st.nr_of_blocks++));
4355 assert(0 == block_U->marked_size()); assert(0 == block_R->marked_size());
4356 part_tr.adapt_transitions_for_new_block(block_U,
4358 ONLY_IF_DEBUG(*
this, ) extend_from_marked_states_add_new_noninert_to_splitter == mode,
4360 bisim_dnj::new_block_is_U);
4361#if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4362 finalise_U_is_smaller(block_U, block_R, *
this);
4370 if (block_B->size() / 2 < block_B->marked_size())
4379 if (extend_from_splitter == mode)
4382 if (U_nonbottom_end < block_B->marked_nonbottom_begin)
4383 { assert(part_tr.block_bunch.front().slice != splitter_T);
4385 R_s_iter.splitter_iter[-1].slice == splitter_T)
4386 { assert(&part_tr.block_bunch.cbegin()[1] < R_s_iter.splitter_iter);
4387 --R_s_iter.splitter_iter;
4388 bisim_dnj::state_info_entry*
const s(
4389 R_s_iter.splitter_iter->pred->source); assert(s->bl.ock == block_B); assert(s->pos->st == s);
4390 if (block_B->nonbottom_begin <= s->pos)
4391 { assert(U_nonbottom_end <= s->pos);
4392 if (s->pos < untested_to_U_defined_end)
4399 *--untested_to_U_defined_end);
4401 if (block_B->mark_nonbottom(s->pos) &&
4403 block_B->size()/2 < block_B->marked_size())
4412 assert(block_B->marked_bottom_begin <= s->pos);
4415 check_complexity::split_R_handle_transition_from_R_state, 1U), *
this);
4423 mode = extend_from_marked_states;
4430 assert(part_tr.block_bunch.front().slice != splitter_T);
4431 while (R_s_iter.splitter_iter[-1].slice == splitter_T)
4433 assert(&part_tr.block_bunch.cbegin()[1] < R_s_iter.splitter_iter);
4434 --R_s_iter.splitter_iter;
4435 bisim_dnj::state_info_entry*
const
4436 s(R_s_iter.splitter_iter->pred->source);
4437 assert(s->bl.ock == block_B); assert(s->pos->st == s);
4438 assert(s->pos < block_B->nonbottom_begin ||
4439 block_B->marked_nonbottom_begin <= s->pos);
4440 assert(block_B->marked_bottom_begin <= s->pos);
4446 assert(0 != block_B->marked_size());
4448 if (U_nonbottom_end < block_B->marked_nonbottom_begin)
4451 R_s_iter.block = block_B->nonbottom_begin;
4452 if (block_B->marked_bottom_begin == R_s_iter.block)
4457 R_s_iter.block = block_B->end;
4458 } assert(block_B->marked_nonbottom_begin != R_s_iter.block);
4460 block_B->marked_nonbottom_begin != R_s_iter.block)
4462 --R_s_iter.block; assert(part_tr.pred.back().target != R_s_iter.block->st);
4465 R_t_iter = R_s_iter.block->st->pred_inert.begin,
4466 R_t_iter->target == R_s_iter.block->st, ++R_t_iter)
4468 bisim_dnj::state_info_entry*
const
4469 t(R_t_iter->source); assert(U_nonbottom_end <= t->pos);
4470 assert(t->pos->st == t); assert(t->pos < block_B->end);
4471 if (t->pos < untested_to_U_defined_end)
4477 *--untested_to_U_defined_end);
4479 if (block_B->mark_nonbottom(t->pos) &&
4481 block_B->size() / 2 < block_B->marked_size())
4487 check_complexity::split_R_handle_transition_to_R_state, 1U), *
this);
4490 check_complexity::split_R_find_predecessors_of_R_state,
4492 if (block_B->marked_bottom_begin == R_s_iter.block &&
4493 R_s_iter.block < block_B->nonbottom_begin)
4495 R_s_iter.block = block_B->end;
4507 block_R = block_B->split_off_block(bisim_dnj::new_block_is_R,
ONLY_IF_DEBUG( *
this, )
4508 part_st.nr_of_blocks++);
4511 assert(0 == block_B->marked_size()); assert(0 == block_R->marked_size());
4512 part_tr.adapt_transitions_for_new_block(block_R,
4514 ONLY_IF_DEBUG(*
this, ) extend_from_marked_states_add_new_noninert_to_splitter == mode,
4516 bisim_dnj::new_block_is_R);
4517#if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4518 finalise_R_is_smaller(block_B, block_R, *
this);
4549 bisim_dnj::block_t* handle_new_noninert_transns(
4550 bisim_dnj::block_t*
const block_R,
4551 bisim_dnj::block_bunch_slice_const_iter_t bbslice_Tprime_R)
4552 { assert(block_R == bbslice_Tprime_R->source_block());
4553 bisim_dnj::block_t* block_Rprime; assert(&part_tr.block_bunch.cbegin()[1] < part_tr.block_bunch_inert_begin);
4554 bisim_dnj::block_t* block_N; assert(!part_tr.block_bunch_inert_begin[-1].slice.is_null());
4555 bisim_dnj::block_bunch_slice_iter_t
const bbslice_R_tau_U(
4556 part_tr.block_bunch_inert_begin[-1].slice); assert(bbslice_Tprime_R->is_stable());
4557 assert(!bbslice_R_tau_U->is_stable());
4558 assert(block_R == bbslice_R_tau_U->source_block());
4559 assert(0 < block_R->marked_size());
4561 if (0 < block_R->unmarked_bottom_size())
4562 { assert(part_tr.splitter_list.begin() != part_tr.splitter_list.end());
4564 bool const next_splitter_is_of_same_block =
4565 part_tr.splitter_list.begin() != bbslice_R_tau_U &&
4566 part_tr.splitter_list.front().source_block() == block_R;
4568 block_N = split(block_R,
4570 extend_from_marked_states_add_new_noninert_to_splitter);
4571 assert(part_st.permutation.data()
4574 = block_N->begin[-1].st->bl.ock;
4580 if (next_splitter_is_of_same_block &&
4581 (assert(part_tr.splitter_list.begin() != part_tr.splitter_list.end()),
4582 part_tr.splitter_list.front().source_block()==block_N))
4584 bisim_dnj::block_bunch_slice_iter_t
const bbslice_T_Rprime(
4585 std::next(part_tr.splitter_list.begin()));
4586 if (part_tr.splitter_list.end() != bbslice_T_Rprime &&
4587 bbslice_T_Rprime->source_block() == block_Rprime)
4592 part_tr.splitter_list.splice(part_tr.splitter_list.begin(),
4593 part_tr.splitter_list, bbslice_T_Rprime);
4597 if (0 < block_N->marked_bottom_size())
4605 bbslice_Tprime_R = bbslice_R_tau_U;
4606 block_N->marked_bottom_begin = block_N->nonbottom_begin;
4608 else if (bbslice_Tprime_R->source_block() != block_N)
4609 { assert(bbslice_Tprime_R->source_block() == block_Rprime);
4613 assert(!bbslice_Tprime_R->end->slice.is_null());
4614 assert(bbslice_Tprime_R->end < part_tr.block_bunch_inert_begin);
4615 bbslice_Tprime_R = (bisim_dnj::block_bunch_slice_const_iter_t)
4616 bbslice_Tprime_R->end->slice; assert(bbslice_Tprime_R->source_block() == block_N);
4623 block_N->stable_block_bunch.splice(
4624 block_N->stable_block_bunch.end(),
4625 part_tr.splitter_list, bbslice_R_tau_U);
4626 bbslice_R_tau_U->make_stable();
4627 block_N->marked_bottom_begin = block_N->nonbottom_begin;
4628 block_Rprime =
nullptr;
4630 block_N->marked_nonbottom_begin = block_N->end;
4632 if (1 >= block_N->size())
4634 return block_Rprime;
4643 for (bisim_dnj::block_bunch_slice_iter_t bbslice_T_N(
4644 block_N->stable_block_bunch.begin());
4645 block_N->stable_block_bunch.end() != bbslice_T_N; )
4646 { assert(bbslice_T_N->is_stable());
4647 bisim_dnj::block_bunch_slice_iter_t
const
4648 next_bbslice_T_N(std::next(bbslice_T_N));
4649 if (&*bbslice_T_N != &*bbslice_Tprime_R &&
4650 &*bbslice_T_N != &*bbslice_R_tau_U)
4657 part_tr.splitter_list.splice(part_tr.splitter_list.end(),
4658 block_N->stable_block_bunch, bbslice_T_N);
4659 bbslice_T_N->make_unstable();
4661 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4667 assert(!bbslice_T_N->work_counter.has_temporary_work());
4668 if (!bbslice_T_N->add_work_to_bottom_transns(check_complexity::
4669 handle_new_noninert_transns_make_unstable_a_priori, 1U, *
this))
4671 handle_new_noninert_transns_make_unstable_temp, 1U), *
this);
4672 assert(bbslice_T_N->work_counter.has_temporary_work());
4673 assert(!bbslice_T_N->is_stable());
4676 bbslice_T_N = next_bbslice_T_N;
4681 bisim_dnj::permutation_entry* s_iter(block_N->begin); assert(s_iter < block_N->nonbottom_begin);
4684 bisim_dnj::state_info_entry*
const s(s_iter->st); assert(s->pos == s_iter);
4686 for (bisim_dnj::succ_entry* succ_iter(s->succ_inert.begin);
4687 s == succ_iter[-1].block_bunch->pred->source; )
4688 { assert(succ_iter[-1].begin_or_before_end < succ_iter);
4689 succ_iter = succ_iter[-1].begin_or_before_end; assert(
nullptr != succ_iter);
4690 assert(succ_iter->block_bunch->pred->action_block->succ == succ_iter);
4691 assert(s == succ_iter->block_bunch->pred->source);
4692 bisim_dnj::block_bunch_entry*
const
4693 old_block_bunch_pos(succ_iter->block_bunch); assert(!old_block_bunch_pos->slice.is_null());
4694 bisim_dnj::block_bunch_slice_iter_t
const
4695 bbslice_T_N((bisim_dnj::block_bunch_slice_iter_t)
4696 old_block_bunch_pos->slice);
4697 if (!bbslice_T_N->is_stable())
4698 { assert(&*bbslice_T_N != &*bbslice_Tprime_R && bbslice_T_N != bbslice_R_tau_U);
4699 bisim_dnj::block_bunch_entry*
const
4700 new_block_bunch_pos(bbslice_T_N->marked_begin - 1);
4703 if (old_block_bunch_pos <= new_block_bunch_pos)
4705 bbslice_T_N->marked_begin = new_block_bunch_pos; assert(new_block_bunch_pos->slice == bbslice_T_N);
4706 std::swap(old_block_bunch_pos->pred,
4707 new_block_bunch_pos->pred); assert(
nullptr != old_block_bunch_pos->pred->action_block->succ);
4708 old_block_bunch_pos->pred->action_block->succ->
4709 block_bunch = old_block_bunch_pos; assert(new_block_bunch_pos->pred->action_block->succ == succ_iter);
4710 succ_iter->block_bunch = new_block_bunch_pos;
4715 assert(&*bbslice_T_N == &*bbslice_Tprime_R || bbslice_T_N == bbslice_R_tau_U);
4718 check_complexity::handle_new_noninert_transns, 1U), *
this);
4720 while (++s_iter < block_N->nonbottom_begin);
4722 return block_Rprime;
4727 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
4728 namespace bisim_dnj {
4737 template <
class LTS_TYPE>
4738 static void finalise_U_is_smaller(
const block_t*
const block_U,
4739 const block_t*
const block_R,
4740 const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
4742 if (
nullptr != block_U)
4744 unsigned const max_U_block(check_complexity::log_n -
4745 check_complexity::ilog2(block_U->size()));
4747 const permutation_entry* s_iter(block_U->begin);
4748 assert(s_iter < block_U->end);
4751 const state_info_entry*
const s(s_iter->st);
4753 check_complexity::split_U_find_predecessors_of_U_state,
4754 check_complexity::split_find_predecessors_of_R_or_U_state,
4755 max_U_block), partitioner);
4756 assert(s != partitioner.part_tr.pred.back().target);
4757 for (
const pred_entry* pred_iter(s->pred_inert.begin);
4758 s == pred_iter->target; ++pred_iter)
4761 split_U_handle_transition_to_U_state,
4763 split_handle_transition_to_R_or_U_state,
4764 max_U_block), partitioner);
4769 assert(s != partitioner.part_tr.pred.front().target);
4770 for (
const pred_entry* pred_iter(s->pred_inert.begin);
4771 s == (--pred_iter)->target; )
4774 split_U_handle_transition_to_U_state,
4776 split_handle_transition_to_R_or_U_state,
4777 max_U_block), partitioner);
4779 assert(s != partitioner.part_tr.succ.front().
4780 block_bunch->pred->source);
4781 for (
const succ_entry* succ_iter(s->succ_inert.begin);
4782 s == (--succ_iter)->block_bunch->pred->source; )
4786 split_U_test_noninert_transitions,
4788 split_handle_transition_from_R_or_U_state,
4789 max_U_block), partitioner);
4792 while (++s_iter < block_U->end);
4796 const permutation_entry* s_iter(block_R->begin);
4797 assert(s_iter < block_R->end);
4800 const state_info_entry*
const s(s_iter->st);
4802 split_R_find_predecessors_of_R_state), partitioner);
4803 assert(s != partitioner.part_tr.pred.back().target);
4804 for (
const pred_entry* pred_iter(s->pred_inert.begin);
4805 s == pred_iter->target; ++pred_iter)
4808 split_R_handle_transition_to_R_state), partitioner);
4811 partitioner.part_tr.succ.front().block_bunch->pred->source);
4812 for (
const succ_entry* succ_iter(s->succ_inert.begin);
4813 s == (--succ_iter)->block_bunch->pred->source; )
4817 split_R_handle_transition_from_R_state), partitioner);
4822 split_U_test_noninert_transitions,
4824 split_test_noninert_transitions_found_new_bottom_state,
4828 while (++s_iter < block_R->end);
4830 check_complexity::check_temporary_work();
4841 template <
class LTS_TYPE>
4842 static void finalise_R_is_smaller(
const block_t*
const block_U,
4843 const block_t*
const block_R,
4844 const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
4846 unsigned const max_R_block(check_complexity::log_n -
4847 check_complexity::ilog2(block_R->size()));
4849 const permutation_entry* s_iter(block_U->begin);
4850 assert(s_iter < block_U->end);
4853 const state_info_entry*
const s(s_iter->st);
4855 split_U_find_predecessors_of_U_state), partitioner);
4856 assert(s != partitioner.part_tr.pred.back().target);
4857 for (
const pred_entry* pred_iter(s->pred_inert.begin);
4858 s == pred_iter->target; ++pred_iter)
4861 split_U_handle_transition_to_U_state), partitioner);
4866 assert(s != partitioner.part_tr.pred.front().target);
4867 for (
const pred_entry* pred_iter(s->pred_inert.begin);
4868 s == (--pred_iter)->target; )
4871 split_U_handle_transition_to_U_state), partitioner);
4874 partitioner.part_tr.succ.front().block_bunch->pred->source);
4875 for (
const succ_entry* succ_iter(s->succ_inert.begin);
4876 s == (--succ_iter)->block_bunch->pred->source; )
4880 split_U_test_noninert_transitions), partitioner);
4883 while (++s_iter < block_U->end);
4885 s_iter = block_R->begin;
4886 assert(s_iter < block_R->end);
4889 const state_info_entry*
const s(s_iter->st);
4891 check_complexity::split_R_find_predecessors_of_R_state,
4892 check_complexity::split_find_predecessors_of_R_or_U_state,
4893 max_R_block), partitioner);
4894 assert(s != partitioner.part_tr.pred.back().target);
4895 for (
const pred_entry* pred_iter(s->pred_inert.begin);
4896 s == pred_iter->target; ++pred_iter)
4899 check_complexity::split_R_handle_transition_to_R_state,
4900 check_complexity::split_handle_transition_to_R_or_U_state,
4901 max_R_block), partitioner);
4904 partitioner.part_tr.succ.front().block_bunch->pred->source);
4905 for (
const succ_entry* succ_iter(s->succ_inert.begin);
4906 s == (--succ_iter)->block_bunch->pred->source; )
4910 split_R_handle_transition_from_R_state,
4912 split_handle_transition_from_R_or_U_state,
4913 max_R_block), partitioner);
4918 split_U_test_noninert_transitions), partitioner);
4921 while (++s_iter < block_R->end);
4922 check_complexity::check_temporary_work();
4958template <
class LTS_TYPE>
4959void bisimulation_reduce_dnj(LTS_TYPE& l,
bool const branching =
false,
4960 bool const preserve_divergence =
false)
4962 if (1 >= l.num_states())
4966 mCRL2log(log::warning) <<
"There is only 1 state in the LTS. It is "
4967 "not guaranteed that branching bisimulation minimisation runs "
4968 "in time O(m log n).\n";
4971 const std::clock_t start_SCC=std::clock();
4974 scc_reduce(l, preserve_divergence);
4977 if (1 >= l.num_states())
4984 const std::clock_t start_part=std::clock();
4985 bisim_partitioner_dnj<LTS_TYPE> bisim_part(l, branching,
4986 preserve_divergence);
4989 const std::clock_t end_part=std::clock();
4990 bisim_part.finalize_minimized_LTS();
4992 if (mCRL2logEnabled(log::verbose))
4994 const std::clock_t end_finalizing=std::clock();
4995 const int prec=
static_cast<
int>(std::lrint(std::log10(CLOCKS_PER_SEC)+0.19897000433602));
5001 runtime[0]=(
double) (end_finalizing - start_SCC)/CLOCKS_PER_SEC;
5002 runtime[1]=(
double) ( start_part-start_SCC)/CLOCKS_PER_SEC;
5003 runtime[2]=(
double) ( bisim_part.end_initial_part-start_part )/CLOCKS_PER_SEC;
5004 runtime[3]=(
double) ( end_part-bisim_part.end_initial_part )/CLOCKS_PER_SEC;
5005 runtime[4]=(
double) (end_finalizing-end_part )/CLOCKS_PER_SEC;
5006 if (runtime[0]>=60.0)
5008 int min[
sizeof(runtime)/
sizeof(runtime[0])];
5009 for (
unsigned i = 0; i <
sizeof(runtime)/
sizeof(runtime[0]); ++i)
5011 min[i] =
static_cast<
int>(trunc(runtime[i] / 60.0));
5012 runtime[i] -= 60 * min[i];
5016 int h[
sizeof(runtime)/
sizeof(runtime[0])];
5017 for (
unsigned i=0; i <
sizeof(runtime)/
sizeof(runtime[0]); ++i)
5022 int width =
static_cast<
int>(trunc(log10(h[0])) + 1);
5024 mCRL2log(log::verbose) << std::fixed << std::setprecision(prec)
5025 <<
"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"
5026 "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"
5027 "Time spent on refining: " << std::setw(width) << h[3] <<
"h " << std::setw(2) << min[3] <<
"min " << std::setw(prec+3) << runtime[3] <<
"s\n"
5028 "Time spent on finalizing: " << std::setw(width) << h[4] <<
"h " << std::setw(2) << min[4] <<
"min " << std::setw(prec+3) << runtime[4] <<
"s\n"
5029 "Total CPU time: " << std::setw(width) << h[0] <<
"h " << std::setw(2) << min[0] <<
"min " << std::setw(prec+3) << runtime[0] <<
"s\n"
5030 "BENCHMARK TIMEdnj: " <<
static_cast<
double>(end_part-start_part)/CLOCKS_PER_SEC <<
"\n"
5031 << std::defaultfloat;
5035 mCRL2log(log::verbose) << std::fixed << std::setprecision(prec)
5036 <<
"Time spent on contracting SCCs: " << std::setw(2) << min[1] <<
"min " << std::setw(prec+3) << runtime[1] <<
"s\n"
5037 "Time spent on initial partition:" << std::setw(2) << min[2] <<
"min " << std::setw(prec+3) << runtime[2] <<
"s\n"
5038 "Time spent on refining: " << std::setw(2) << min[3] <<
"min " << std::setw(prec+3) << runtime[3] <<
"s\n"
5039 "Time spent on finalizing: " << std::setw(2) << min[4] <<
"min " << std::setw(prec+3) << runtime[4] <<
"s\n"
5040 "Total CPU time: " << std::setw(2) << min[0] <<
"min " << std::setw(prec+3) << runtime[0] <<
"s\n"
5041 "BENCHMARK TIMEdnj: " <<
static_cast<
double>(end_part-start_part)/CLOCKS_PER_SEC <<
"\n"
5042 << std::defaultfloat;
5047 mCRL2log(log::verbose) << std::fixed << std::setprecision(prec)
5048 <<
"Time spent on contracting SCCs: " << std::setw(prec+3) << runtime[1] <<
"s\n"
5049 "Time spent on initial partition:" << std::setw(prec+3) << runtime[2] <<
"s\n"
5050 "Time spent on refining: " << std::setw(prec+3) << runtime[3] <<
"s\n"
5051 "Time spent on finalizing: " << std::setw(prec+3) << runtime[4] <<
"s\n"
5052 "Total CPU time: " << std::setw(prec+3) << runtime[0] <<
"s\n"
5053 "BENCHMARK TIMEdnj: " <<
static_cast<
double>(end_part-start_part)/CLOCKS_PER_SEC <<
"\n"
5054 << std::defaultfloat;
5079template <
class LTS_TYPE>
5080bool destructive_bisimulation_compare_dnj(LTS_TYPE& l1, LTS_TYPE& l2,
5081 bool const branching =
false,
bool const preserve_divergence =
false,
5082 bool const generate_counter_examples =
false,
5083 const std::string& =
"",
5086 if (generate_counter_examples)
5088 mCRL2log(log::warning) <<
"The JGKW20 branching bisimulation "
5089 "algorithm does not generate counterexamples.\n";
5091 std::size_t init_l2(l2.initial_state() + l1.num_states());
5092 detail::merge(l1, std::move(l2));
5098 scc_partitioner<LTS_TYPE> scc_part(l1);
5099 scc_part.replace_transition_system(preserve_divergence);
5100 init_l2 = scc_part.get_eq_class(init_l2);
5104 assert(!preserve_divergence);
5106 assert(1 < l1.num_states());
5107 bisim_partitioner_dnj<LTS_TYPE> bisim_part(l1, branching,
5108 preserve_divergence);
5110 return bisim_part.in_same_class(l1.initial_state(), init_l2);
5130template <
class LTS_TYPE>
5131inline bool bisimulation_compare_dnj(
const LTS_TYPE& l1,
const LTS_TYPE& l2,
5132 bool const branching =
false,
bool const preserve_divergence =
false)
5134 LTS_TYPE l1_copy(l1);
5135 LTS_TYPE l2_copy(l2);
5136 return destructive_bisimulation_compare_dnj(l1_copy, l2_copy, branching,
5137 preserve_divergence);
#define mCRL2complexity(unit, call, info_for_debug)
Assigns work to a counter and checks for errors.
aterm & operator=(const aterm &other) noexcept=default
aterm(const aterm &other) noexcept=default
This class has user-declared copy constructor so declare default copy and move operators.
std::size_t m_top_of_stack
static constexpr std::size_t maximal_size_of_stack
std::array< unprotected_aterm_core, maximal_size_of_stack > m_stack
void initialise(const term_balanced_tree< Term > &tree)
const Term & dereference() const
Dereference operator.
iterator(const iterator &other)
bool equal(const iterator &other) const
Equality operator.
iterator(const term_balanced_tree< Term > &tree)
void increment()
Increments the iterator.
bool is_node() const
Returns true iff the tree is a node with a left and right subtree.
static void make_tree_helper(aterm &result, ForwardTraversalIterator &p, const std::size_t size, Transformer transformer)
term_balanced_tree & operator=(const term_balanced_tree &) noexcept=default
Assignment operator.
size_type size() const
Returns the size of the term_balanced_tree.
term_balanced_tree(term_balanced_tree &&) noexcept=default
Move constructor.
bool empty() const
Returns true if tree is empty.
static const aterm & empty_tree()
static void make_tree(aterm &result, ForwardTraversalIterator &p, const std::size_t size, Transformer transformer)
term_balanced_tree(ForwardTraversalIterator first, const std::size_t size)
Creates an term_balanced_tree with a copy of a range.
static const function_symbol & tree_single_node_function()
const aterm & left_branch() const
Get the left branch of the tree.
term_balanced_tree(const term_balanced_tree &) noexcept=default
Copy constructor.
term_balanced_tree(ForwardTraversalIterator first, const std::size_t size, Transformer transformer)
Creates an term_balanced_tree with a copy of a range, where a transformer is applied to each term bef...
static const function_symbol & tree_node_function()
const Term & operator[](std::size_t position) const
Element indexing operator.
iterator begin() const
Returns an iterator pointing to the beginning of the term_balanced_tree.
iterator end() const
Returns an iterator pointing to the end of the term_balanced_tree.
term_balanced_tree()
Default constructor. Creates an empty tree.
const aterm & right_branch() const
Get the left branch of the tree.
term_balanced_tree & operator=(term_balanced_tree &&) noexcept=default
Move assign operator.
term_balanced_tree(const aterm &tree)
Construction from aterm.
const Term & element_at(std::size_t position, std::size_t size) const
Get an element at the indicated position.
static const function_symbol & tree_empty_function()
friend void make_term_balanced_tree(term_balanced_tree< Term1 > &result, ForwardTraversalIterator p, std::size_t size, Transformer transformer)
term_balanced_tree(detail::_term_appl *t)
A unordered_map class in which aterms can be stored.
data_expression & operator=(data_expression &&) noexcept=default
sort_expression sort() const
Returns the sort of the data expression.
data_expression(const data_expression &) noexcept=default
Move semantics.
data_expression(data_expression &&) noexcept=default
Rewriter that operates on data expressions.
data_expression operator()(const data_expression &d) const
Rewrites a data expression.
void add_sort(const basic_sort &s)
Adds a sort to this specification.
\brief An untyped parameter
Action rename specification.
\brief A timed multi-action
multi_action(const multi_action &) noexcept=default
Move semantics.
const process::action_list & actions() const
multi_action(const process::action_list &actions=process::action_list(), data::data_expression time=data::undefined_real())
Constructor. Actions are sorted to establish the sorted-storage invariant.
This class contains labels for probabilistic transistions, consisting of a numerator and a denumerato...
static const data::rewriter & m_rewriter()
static probabilistic_data_expression one()
Constant one.
probabilistic_data_expression operator+(const probabilistic_data_expression &other) const
Standard addition operator. Note that the expression is not evaluated. For this the rewriter has to b...
probabilistic_data_expression(const data::data_expression &d)
Construct a probabilistic_data_expression from a data_expression, which must be of sort real.
bool operator==(const probabilistic_data_expression &other) const
probabilistic_data_expression(std::size_t enumerator, std::size_t denominator)
bool operator!=(const probabilistic_data_expression &other) const
bool operator>=(const probabilistic_data_expression &other) const
bool operator<(const probabilistic_data_expression &other) const
bool operator<=(const probabilistic_data_expression &other) const
bool operator>(const probabilistic_data_expression &other) const
probabilistic_data_expression(const std::string &enumerator, const std::string &denominator)
probabilistic_data_expression operator-(const probabilistic_data_expression &other) const
Standard subtraction operator.
static data::data_specification data_specification_with_real()
probabilistic_data_expression()
static probabilistic_data_expression zero()
Constant zero.
Linear process specification.
STATE & state()
Get the state in a state probability pair.
PROBABILITY m_probability
state_probability_pair(state_probability_pair &&p)=default
state_probability_pair & operator=(state_probability_pair &&p)=default
state_probability_pair(const state_probability_pair &p)=default
Copy constructor;.
state_probability_pair & operator=(const state_probability_pair &p)=default
Standard assignment.
const PROBABILITY & probability() const
get the probability from a state proability pair.
const STATE & state() const
Get the state from a state probability pair.
PROBABILITY & probability()
Set the probability in a state probability pair.
state_probability_pair(const STATE &state, const PROBABILITY &probability)
constructor.
bool operator==(const state_probability_pair &other) const
Standard equality operator.
Linear process specification.
A class containing the values for action labels for the .lts format.
action_label_lts & operator=(const action_label_lts &)=default
Copy assignment.
void hide_actions(const std::vector< std::string > &tau_actions)
Hide the actions with labels in tau_actions.
action_label_lts(const action_label_lts &)=default
Copy constructor.
static const action_label_lts & tau_action()
action_label_lts(const mcrl2::lps::multi_action &a)
Constructor.
action_label_lts()=default
Default constructor.
void set_truths(formula &f)
Compute and set the truth values of a formula f.
block_index_type target(observation_t obs)
state_type max_state_index
level_type gca_level(const block_index_type B1, const block_index_type B2)
Auxiliarry function that computes the level of the greatest common ancestor. In other words a lvl i s...
std::vector< block > blocks
std::vector< state_type > block_index_of_a_state
label_type label(observation_t obs)
bisim_partitioner_minimal_depth(LTS_TYPE &l, const std::size_t init_l2)
Creates a bisimulation partitioner for an LTS.
std::set< block_index_type > partition
mcrl2::state_formulas::state_formula dist_formula_mindepth(const std::size_t s, const std::size_t t)
Creates a state formula that distinguishes state s from state t.
formula distinguish(const block_index_type b1, const block_index_type b2)
Creates a formula that distinguishes a block b1 from the block b2.
std::vector< block_index_type > BL
~bisim_partitioner_minimal_depth()=default
Destroys this partitioner.
std::vector< bool > block_flags
std::vector< block_index_type > to_be_processed
regular_formulas::regular_formula create_regular_formula(const mcrl2::lps::multi_action &a) const
create_regular_formula Creates a regular formula that represents action a
bool in_same_class(const std::size_t s, const std::size_t t)
block_index_type lift_block(const block_index_type B1, level_type goal)
mcrl2::state_formulas::state_formula conjunction(std::vector< formula > &conjunctions)
conjunction Creates a conjunction of state formulas
std::vector< bool > state_flags
mcrl2::state_formulas::state_formula convert_formula(formula &f)
void split_BL(level_type lvl)
Performs the splits based on the blocks in Bsplit and the flags set in state_flags.
bool refine_partition(level_type lvl)
std::vector< bool > block_flags
state_type max_state_index
mcrl2::state_formulas::state_formula conjunction(std::set< mcrl2::state_formulas::state_formula > terms) const
conjunction Creates a conjunction of state formulas
regular_formulas::regular_formula create_regular_formula(const mcrl2::lts::action_label_string &a) const
create_regular_formula Creates a regular formula that represents action a
regular_formulas::regular_formula create_regular_formula(const mcrl2::lps::multi_action &a) const
create_regular_formula Creates a regular formula that represents action a
std::vector< bool > block_is_in_to_be_processed
std::vector< bool > state_flags
std::map< block_index_type, block_index_type > right_child
std::vector< block_index_type > BL
bool in_same_class(const std::size_t s, const std::size_t t) const
Returns whether two states are in the same bisimulation equivalence class.
mcrl2::state_formulas::state_formula until_formula(const mcrl2::state_formulas::state_formula &phi1, const label_type &a, const mcrl2::state_formulas::state_formula &phi2)
until_formula Creates a state formula that corresponds to the until operator phi1phi2 from HMLU
std::size_t get_eq_class(const std::size_t s) const
Gives the bisimulation equivalence class number of a state.
bisim_partitioner(LTS_TYPE &l, const bool branching=false, const bool preserve_divergence=false, const bool generate_counter_examples=false)
Creates a bisimulation partitioner for an LTS.
~bisim_partitioner()=default
Destroys this partitioner.
std::map< block_index_type, label_type > split_by_action
std::size_t num_eq_classes() const
Gives the number of bisimulation equivalence classes of the LTS.
mcrl2::state_formulas::state_formula counter_formula(std::size_t s, std::size_t t)
Creates a state formula that distinguishes state s from state t.
void order_recursively_on_tau_reachability(const state_type s, std::map< state_type, std::vector< state_type > > &inert_transition_map, std::vector< non_bottom_state > &new_non_bottom_states, std::set< state_type > &visited)
std::vector< block_index_type > to_be_processed
std::map< block_index_type, block_index_type > split_by_block
void refine_partion_with_respect_to_divergences()
void replace_transition_system(const bool branching, const bool preserve_divergences)
Replaces the transition relation of the current lts by the transitions of the bisimulation reduced tr...
std::vector< block > blocks
void order_on_tau_reachability(std::vector< non_bottom_state > &non_bottom_states)
void split_the_blocks_in_BL(bool &partition_is_unstable, const label_type splitter_label, const block_index_type splitter_block)
void refine_partition_until_it_becomes_stable(const bool branching, const bool preserve_divergence)
void create_initial_partition(const bool branching, const bool preserve_divergences)
std::vector< state_type > block_index_of_a_state
mcrl2::state_formulas::state_formula counter_formula_aux(const block_index_type B1, const block_index_type B2)
void check_internal_consistency_of_the_partitioning_data_structure(const bool branching, const bool preserve_divergence) const
outgoing_transitions_per_state_action_t outgoing_transitions
std::map< state_type, std::size_t > state2num_touched
mcrl2::state_formulas::state_formula conjunction(std::vector< mcrl2::state_formulas::state_formula > &conjunctions)
conjunction Creates a conjunction of state formulas
regular_formulas::regular_formula make_tau_hat(regular_formulas::regular_formula &f)
void split_and_intersect(std::set< block_index_type > &truths, std::pair< block_index_type, block_index_type > liftedB1B2)
state_type max_state_index
branching_bisim_partitioner_minimal_depth(LTS_TYPE &l, const std::size_t init_l2)
Creates a branching bisimulation partitioner for an LTS.
mcrl2::state_formulas::state_formula dist_formula(block_index_type block_index1, block_index_type block_index2)
std::map< state_type, block_index_type > state2block
bool in_same_class(const std::size_t s, const std::size_t t)
std::vector< state_type > bottom_states
std::vector< block > blocks
std::size_t refine_partition()
std::map< state_type, signature_type > state2sig
regular_formulas::regular_formula create_regular_formula(const mcrl2::lps::multi_action &a) const
create_regular_formula Creates a regular formula that represents action a
bool is_dist(std::set< blockpair_type > &dist_blockpairs, std::set< block_index_type > &to_dist)
is_dist Checks if a given conjunction correctly exludes a set of blocks.
std::vector< mcrl2::state_formulas::state_formula > filtered_dist_conjunction(std::map< blockpair_type, mcrl2::state_formulas::state_formula > &Phi, std::set< block_index_type > &Tdist, std::set< block_index_type > &Truths)
mcrl2::state_formulas::state_formula dist_formula_mindepth(size_t s, size_t t)
Creates a state formula that distinguishes state s from state t.
bool is_tau(label_type l)
bool is_dist(const std::set< blockpair_type > &dist_blockpairs, const std::set< block_index_type > &to_dist, std::set< block_index_type > &truths)
is_dist overloaded to also maintain the truth values computed at the end.
signature_type get_signature(state_type s)
std::pair< block_index_type, block_index_type > min_split_blockpair(block_index_type b1, block_index_type b2)
function object to compare two constln_t pointers based on their contents
A class that can be used to store counterexample trees and.
lts_type type()
Provides the type of this lts, in casu lts_aut.
bool operator==(const lts_aut_base &) const
Standard equality function.
void swap(lts_aut_base &) noexcept
Standard swap function.
void swap(lts_dot_base &) noexcept
The standard swap function.
lts_type type() const
The lts_type of state_label_dot. In this case lts_dot.
void clear()
Clear the transitions system.
const std::vector< std::string > & state_element_values(std::size_t idx) const
Provides the vector of strings that correspond to the values of the number at position idx in a vecto...
std::size_t add_state_element_value(std::size_t idx, const std::string &s)
Adds a string to the state element values for the idx-th position in a state vector....
void swap(lts_fsm_base &other) noexcept
Standard swap function.
bool operator==(const lts_fsm_base &other) const
lts_type type() const
The lts_type of this labelled transition system. In this case lts_fsm.
std::string state_element_value(std::size_t parameter_index, std::size_t element_index) const
Returns the element_index'th element for the parameter with index parameter_index.
std::string state_label_to_string(const state_label_fsm &l) const
Pretty print a state value of this FSM.
a base class for lts_lts_t and probabilistic_lts_t.
static lts_type type()
Yields the type of this lts, in this case lts_lts.
void set_process_parameters(const data::variable_list ¶ms)
Set the state parameters for this LTS.
lts_lts_base()=default
Default constructor.
bool operator==(const lts_lts_base &other) const
Standard equality function;.
process::action_label_list m_action_decls
void set_action_label_declarations(const process::action_label_list &decls)
Set the action label information for this LTS.
const data::variable & process_parameter(std::size_t i) const
Returns the i-th parameter of the state vectors stored in this LTS.
data::data_specification m_data_spec
const data::variable_list & process_parameters() const
Return the process parameters stored in this LTS.
void set_data(const data::data_specification &spec)
Set the mCRL2 data specification of this LTS.
void swap(lts_lts_base &l) noexcept
const process::action_label_list & action_label_declarations() const
Return action label declarations stored in this LTS.
data::variable_list m_parameters
A simple labelled transition format with only strings as action labels.
void load(const std::string &filename)
Load the labelled transition system from a file.
void load(std::istream &is)
Load the labelled transition system from an input stream.
void save(const std::string &filename) const
Save the labelled transition system to file.
A class to contain labelled transition systems in graphviz format.
void save(const std::string &filename) const
Save the labelled transition system to a file.
void save(std::ostream &os) const
Save the labelled transition system to a stream.
The class lts_fsm_t contains labelled transition systems in .fsm format.
void load(const std::string &filename)
Save the labelled transition system to file.
void save(const std::string &filename) const
Save the labelled transition system to file.
This class contains labelled transition systems in .lts format.
lts_lts_t()=default
Creates an object containing no information.
void save(const std::string &filename) const
Save the labelled transition system to file.
void load(const std::string &filename)
Load the labelled transition system from file.
A simple labelled transition format with only strings as action labels.
void load(const std::string &filename)
Load the labelled transition system from a file.
void load(std::istream &is)
Load the labelled transition system from an input stream.
void save(const std::string &filename) const
Save the labelled transition system to file.
A class to contain labelled transition systems in graphviz format.
void save(std::ostream &os) const
Save the labelled transition system to a stream.
void save(const std::string &filename) const
Save the labelled transition system to a file.
The class lts_fsm_t contains labelled transition systems in .fsm format.
This class contains probabilistic labelled transition systems in .lts format.
probabilistic_lts_lts_t()=default
Creates an object containing no information.
void load(const std::string &filename)
Load the labelled transition system from file.
void save(const std::string &filename) const
Save the labelled transition system to file.
A class that contains a labelled transition system.
probabilistic_lts(probabilistic_lts &&other)=default
Standard move constructor.
void set_initial_probabilistic_state(const PROBABILISTIC_STATE_T &state)
Sets the probabilistic initial state number of this LTS.
probabilistic_lts()=default
Creates an empty LTS.
const PROBABILISTIC_STATE_T & initial_probabilistic_state() const
Gets the initial state number of this LTS.
bool operator==(const probabilistic_lts &other) const
Standard equality operator.
labels_size_type num_probabilistic_states() const
Gets the number of probabilistic states of this LTS.
static constexpr bool is_probabilistic_lts
An indicator that this is a probabilistic lts.
void clear_probabilistic_states()
Clear the probabilistic states in this probabilistic transitions system.
states_size_type add_and_reset_probabilistic_state(PROBABILISTIC_STATE_T &s)
Adds a probabilistic state to this LTS and resets the state to empty.
void clear()
Clear the transitions system.
probabilistic_lts & operator=(probabilistic_lts &&other)=default
Standard assignment move operator.
void swap(probabilistic_lts &other) noexcept
Swap this lts with the supplied supplied LTS.
probabilistic_lts & operator=(const probabilistic_lts &other)=default
Standard assignment operator.
std::vector< PROBABILISTIC_STATE_T > m_probabilistic_states
probabilistic_lts(const probabilistic_lts &other)=default
Standard copy constructor.
states_size_type add_probabilistic_state(const PROBABILISTIC_STATE_T &s)
Adds a probabilistic state to this LTS.
states_size_type initial_state() const
PROBABILISTIC_STATE_T m_init_probabilistic_state
A class that contains a probabilistic state.
void set(const STATE &s)
Set this probabilistic state to a single state with probability one.
const_iterator begin() const
Gets an iterator over pairs of state and probability. This can only be used when the state is stored ...
void construct_internal_vector_representation()
Guarantee that this probabilistic state is internally stored as a vector, such that begin/end,...
probabilistic_state & operator=(const probabilistic_state &other)
Copy assignment constructor.
const_reverse_iterator rbegin() const
Gets a reverse iterator over pairs of state and probability. This can only be used when the state is ...
std::size_t size() const
Gets the number of probabilistic states in the vector representation of this state....
bool operator!=(const probabilistic_state &other) const
Standard equality operator.
iterator begin()
Gets an iterator over pairs of state and probability. This can only be used if the state is internall...
probabilistic_state & operator=(probabilistic_state &&other)=default
Move assignment operator.
STATE get() const
Get a probabilistic state if is is simple, i.e., consists of a single state.
void swap(probabilistic_state &other) noexcept
Swap this probabilistic state.
iterator end()
Gets the end iterator over pairs of state and probability.
reverse_iterator rbegin()
Gets a reverse iterator over pairs of state and probability. This can only be used if the state is in...
std::vector< state_probability_pair > m_probabilistic_state
const_iterator end() const
Gets the end iterator over pairs of state and probability.
reverse_iterator rend()
Gets the reverse end iterator over pairs of state and probability.
bool operator==(const probabilistic_state &other) const
Standard equality operator.
void clear()
Makes the probabilistic state empty.
probabilistic_state(probabilistic_state &&other)=default
Move constructor.
probabilistic_state(const STATE_PROBABILITY_PAIR_ITERATOR begin, const STATE_PROBABILITY_PAIR_ITERATOR end)
Creates a probabilistic state on the basis of state_probability_pairs.
STATE maximal_state() const
Provides the maximal state index in a probabilistic state.
probabilistic_state(const probabilistic_state &other)
Copy constructor.
void shrink_to_fit()
If a probabilistic state is ready, shrinking it to minimal size might be useful to reduce its memory ...
probabilistic_state()
Default constructor.
probabilistic_state(const STATE &s)
Constructor of a probabilistic state from a non probabilistic state.
void add(const STATE &s, const PROBABILITY &p)
Add a state with a probability to the probabilistic state.
const_reverse_iterator rend() const
Gets the reverse end iterator over pairs of state and probability.
Class for computing the signature for strong bisimulation.
Class for computing the signature for branching bisimulation.
Class for computing the signature for divergence preserving branching bisimulation.
Signature based reductions for labelled transition systems.
This class contains labels for states in dot format.
void set_name(const std::string &s)
This method sets the name of the state label to the string s.
std::string name() const
This method returns the string in the name field of a state label.
std::string label() const
This method returns the label in the name field of a state label.
void set_label(const std::string &s)
This method sets the label field of the state label to the string s.
state_label_dot(const std::string &state_name, const std::string &state_label)
A constructor setting the name and label of this state label to the indicated values.
std::string m_state_label
bool operator==(const state_label_dot &l) const
Standard comparison operator, comparing both the string in the name field, as well as the one in the ...
bool operator!=(const state_label_dot &l) const
Standard inequality operator. Just the negation of equality.
state_label_dot()=default
The default constructor.
This class contains state labels for the fsm format.
state_label_fsm()=default
Default constructor. The label becomes an empty vector.
state_label_fsm(const state_label_fsm &)=default
Copy constructor.
state_label_fsm & operator=(const state_label_fsm &)=default
Copy assignment.
static state_label_fsm number_to_label(const std::size_t n)
Create a state label consisting of a number as the only list element.
state_label_fsm(const std::vector< std::size_t > &v)
Default constructor. The label is set to the vector v.
state_label_fsm operator+(const state_label_fsm &l) const
An operator to concatenate two state labels. Fsm labels cannot be concatenated. Therefore,...
This class contains state labels for an labelled transition system in .lts format.
state_label_lts(const state_label_lts &)=default
Copy constructor.
state_label_lts operator+(const state_label_lts &l) const
An operator to concatenate two state labels.
state_label_lts(const super &l)
Construct a state label out of list of balanced trees of data expressions, representing a state label...
state_label_lts()=default
Default constructor.
state_label_lts(const lps::state &l)
Construct a state label out of a balanced tree of data expressions, representing a state label.
state_label_lts & operator=(const state_label_lts &)=default
Copy assignment.
static state_label_lts number_to_label(const std::size_t n)
Create a state label consisting of a number as the only list element.
state_label_lts(const CONTAINER &l)
Construct a single state label out of the elements in a container.
Process specification consisting of a data specification, action labels, a sequence of process equati...
\brief An untyped multi action or data application
#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
#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 INIT_WITHOUT_BLC_SETS
#define abort_if_non_bottom_size_too_large_NewBotSt(i)
#define bottom_size(coroutine)
#define new_start_bottom_states(idx)
#define new_end_bottom_states(idx)
#define abort_if_size_too_large(coroutine, i)
#define non_bottom_states_NewBotSt
#define new_end_bottom_states_NewBotSt
#define abort_if_bottom_size_too_large(coroutine)
#define bottom_and_non_bottom_size(coroutine)
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
global_function_symbol g_tree_node("@node@", 2)
global_function_symbol g_empty("@empty@", 0)
aterm g_empty_tree(g_empty)
global_function_symbol g_single_tree_node("@single_node@", 1)
std::string pp(const term_balanced_tree< Term > t)
bool is_aterm_balanced_tree(const aterm &t)
void make_term_balanced_tree(term_balanced_tree< Term > &result, ForwardTraversalIterator p, std::size_t size, Transformer transformer)
static data_specification const & default_specification()
Namespace for system defined sort bool_.
const function_symbol & false_()
Constructor for function symbol false.
const function_symbol & true_()
Constructor for function symbol true.
Namespace for system defined sort int_.
application cint(const data_expression &arg0)
Application of function symbol @cInt.
const basic_sort & int_()
Constructor for sort expression Int.
Namespace for system defined sort nat.
const basic_sort & nat()
Constructor for sort expression Nat.
application cnat(const data_expression &arg0)
Application of function symbol @cNat.
Namespace for system defined sort pos.
const basic_sort & pos()
Constructor for sort expression Pos.
Namespace for system defined sort real_.
data_expression & real_one()
application creal(const data_expression &arg0, const data_expression &arg1)
Application of function symbol @cReal.
data_expression & real_zero()
const basic_sort & real_()
Constructor for sort expression Real.
application plus(const data_expression &arg0, const data_expression &arg1)
Application of function symbol +.
application minus(const data_expression &arg0, const data_expression &arg1)
Application of function symbol -.
bool is_data_expression(const atermpp::aterm &x)
Test for a data_expression expression.
application less(const data_expression &arg0, const data_expression &arg1)
Application of function symbol <.
bool is_untyped_data_parameter(const atermpp::aterm &x)
application equal_to(const data_expression &arg0, const data_expression &arg1)
Application of function symbol ==.
std::pair< std::set< data::variable >, std::set< data::variable > > read_write_parameters(const lps::action_summand &summand, const std::set< data::variable > &process_parameters)
Computes the read and written process parameters for the given summand.
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
multi_action complete_multi_action(process::untyped_multi_action &x, const process::action_label_list &action_decls, const data::data_specification &data_spec=data::detail::default_specification())
void remove_common_divisor(std::size_t &enumerator, std::size_t &denominator)
void complete_action_rename_specification(action_rename_specification &x, const lps::stochastic_specification &spec)
process::untyped_multi_action parse_multi_action_new(const std::string &text)
multi_action complete_multi_action(process::untyped_multi_action &x, multi_action_type_checker &typechecker, const data::data_specification &data_spec=data::detail::default_specification())
std::size_t greatest_common_divisor(std::size_t x, std::size_t y)
action_rename_specification parse_action_rename_specification_new(const std::string &text)
The main namespace for the LPS library.
specification parse_linear_process_specification(const std::string &text)
Parses a linear process specification from a string.
void complete_data_specification(stochastic_specification &spec)
Adds all sorts that appear in the process of l to the data specification of l.
multi_action parse_multi_action(const std::string &text, const process::action_label_list &action_decls, const data::data_specification &data_spec=data::detail::default_specification())
Parses a multi_action from a string.
void parse_lps(std::istream &, Specification &)
process::action parse_action(const std::string &text, const process::action_label_list &action_decls, const data::data_specification &data_spec=data::detail::default_specification())
Parses an action from a string.
void complete_data_specification(specification &spec)
Adds all sorts that appear in the process of l to the data specification of l.
std::string pp(const probabilistic_data_expression &l)
multi_action parse_multi_action(std::stringstream &in, multi_action_type_checker &typechecker, const data::data_specification &data_spec=data::detail::default_specification())
Parses a multi_action from an input stream.
action_rename_specification parse_action_rename_specification(std::istream &in, const lps::stochastic_specification &spec)
Parses a process specification from an input stream.
std::ostream & operator<<(std::ostream &out, const probabilistic_data_expression &x)
Pretty print to an outstream.
multi_action parse_multi_action(std::stringstream &in, const process::action_label_list &action_decls, const data::data_specification &data_spec=data::detail::default_specification())
Parses a multi_action from an input stream.
action_rename_specification parse_action_rename_specification(const std::string &spec_string, const lps::stochastic_specification &spec)
Parses an action rename specification. Parses an action rename specification. If the action rename sp...
void parse_lps< specification >(std::istream &from, specification &result)
void make_state(state &result, ForwardTraversalIterator p, const std::size_t size)
void parse_lps< stochastic_specification >(std::istream &from, stochastic_specification &result)
Parses a stochastic linear process specification from an input stream.
std::string pp(const lps::state &x)
multi_action parse_multi_action(const std::string &text, multi_action_type_checker &typechecker, const data::data_specification &data_spec=data::detail::default_specification())
Parses a multi_action from a string.
void parse_lps(const std::string &text, Specification &result)
specification parse_linear_process_specification(std::istream &spec_stream)
Parses a linear process specification from an input stream.
void make_state(state &result, ForwardTraversalIterator p, const std::size_t size, Transformer transformer)
bool bisimulation_compare(const LTS_TYPE &l1, const LTS_TYPE &l2, bool branching=false, bool preserve_divergences=false, bool generate_counter_examples=false, const std::string &counter_example_file="", bool structured_output=false)
Checks whether the two initial states of two lts's are strong or branching bisimilar.
lts_type guess_format(std::string const &s, const bool be_verbose)
Determines the LTS format from a filename by its extension.
static const std::array< std::string, 5 > extension_strings
std::string supported_lts_formats_text(lts_type default_format, const std::set< lts_type > &supported)
Gives a textual list describing supported LTS formats.
bool destructive_branching_bisimulation_compare_minimal_depth(LTS_TYPE &l1, LTS_TYPE &l2, const std::string &counter_example_file)
std::string supported_lts_formats_text(const std::set< lts_type > &supported)
Gives a textual list describing supported LTS formats.
bool destructive_bisimulation_compare_minimal_depth(LTS_TYPE &l1, LTS_TYPE &l2, const std::string &counter_example_file)
std::string string_for_type(const lts_type type)
Gives a string representation of an LTS format.
void unmark_explicit_divergence_transitions(LTS_TYPE &l, const std::size_t divergent_transition_label)
std::string mime_type_for_type(const lts_type type)
Gives the MIME type associated with an LTS format.
void get_trans(const outgoing_transitions_per_state_t &begin, tree_set_store &tss, std::ptrdiff_t d, std::vector< transition > &d_trans, LTS_TYPE &aut)
lts_type parse_format(std::string const &s)
Determines the LTS format from a format specification string.
static const std::array< std::string, 5 > type_strings
std::string extension_for_type(const lts_type type)
Gives the filename extension associated with an LTS format.
LABEL_TYPE make_divergence_label(const std::string &s)
const std::set< lts_type > & supported_lts_formats()
Gives the set of all supported LTS formats.
std::string lts_extensions_as_string(const std::set< lts_type > &supported)
Gives a list of extensions for supported LTS formats.
std::string lts_extensions_as_string(const std::string &sep, const std::set< lts_type > &supported)
Gives a list of extensions for supported LTS formats.
std::size_t mark_explicit_divergence_transitions(LTS_TYPE &l)
bool destructive_bisimulation_compare(LTS_TYPE &l1, LTS_TYPE &l2, bool branching=false, bool preserve_divergences=false, bool generate_counter_examples=false, const std::string &counter_example_file="", bool structured_output=false)
Checks whether the two initial states of two lts's are strong or branching bisimilar.
void bisimulation_reduce(LTS_TYPE &l, bool branching=false, bool preserve_divergences=false)
Reduce transition system l with respect to strong or (divergence preserving) branching bisimulation.
bool lts_named_cmp(const std::array< std::string, Size > &N, T a, T b)
static const std::array< std::string, 5 > type_desc_strings
static const std::array< std::string, 5 > mime_type_strings
static const std::set< lts_type > & initialise_supported_lts_formats()
std::string pp(const state_label_dot &l)
Pretty print function for a state_label_dot. Only prints the label field.
std::string pp(const state_label_lts &label)
Pretty print a state value of this LTS.
bool is_deterministic(const LTS_TYPE &l)
Checks whether this LTS is deterministic.
outgoing_transitions_per_state_action_t transitions_per_outgoing_state_action_pair_reversed(const std::vector< transition > &trans)
Provide the transitions as a multimap accessible per from state and label, ordered backwardly.
action_label_lts parse_lts_action(const std::string &multi_action_string, const data::data_specification &data_spec, lps::multi_action_type_checker &typechecker)
Parse a string into an action label.
void group_transitions_on_label(std::vector< transition > &transitions, std::function< std::size_t(const transition &)> get_label, const std::size_t number_of_labels, const std::size_t tau_label_index)
std::size_t to(const outgoing_pair_t &p)
Target state of a label state pair.
std::string pp(const state_label_fsm &label)
Pretty print an fsm state label.
outgoing_transitions_per_state_action_t transitions_per_outgoing_state_action_pair(const std::vector< transition > &trans)
Provide the transitions as a multimap accessible per from state and label.
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.
void determinise(LTS_TYPE &l)
Determinises this LTS.
std::string pp(const probabilistic_state< STATE, PROBABILITY > &l)
std::ostream & operator<<(std::ostream &out, const probabilistic_state< STATE, PROBABILITY > &l)
Pretty print to an outstream.
void reduce(LTS_TYPE &l, lts_equivalence eq)
Applies a reduction algorithm to this LTS.
bool compare(const LTS_TYPE &l1, const LTS_TYPE &l2, lts_equivalence eq, bool generate_counter_examples=false, const std::string &counter_example_file="", bool structured_output=false)
Checks whether this LTS is equivalent to another LTS.
outgoing_transitions_per_state_action_t transitions_per_outgoing_state_action_pair_reversed(const std::vector< transition > &trans, const std::set< transition::size_type > &hide_label_set)
Provide the transitions as a multimap accessible per from state and label, ordered backwardly.
bool destructive_compare(LTS_TYPE &l1, LTS_TYPE &l2, const lts_equivalence eq, const bool generate_counter_examples=false, const std::string &counter_example_file=std::string(), const bool structured_output=false)
Checks whether this LTS is equivalent to another LTS.
std::string pp(const action_label_lts &l)
Print the action label to string.
bool destructive_compare(LTS_TYPE &l1, LTS_TYPE &l2, lts_preorder pre, bool generate_counter_example, const std::string &counter_example_file="", bool structured_output=false, lps::exploration_strategy strategy=lps::es_breadth, bool preprocess=true)
Checks whether this LTS is smaller than another LTS according to a preorder.
outgoing_transitions_per_state_action_t transitions_per_outgoing_state_action_pair(const std::vector< transition > &trans, const std::set< transition::size_type > &hide_label_set)
Provide the transitions as a multimap accessible per from state and label.
void merge(LTS_TYPE &l1, const LTS_TYPE &l2)
Merge the second lts into the first lts.
bool reachability_check(lts< SL, AL, BASE > &l, bool remove_unreachable=false)
Checks whether all states in this LTS are reachable from the initial state and remove unreachable sta...
std::size_t label(const outgoing_pair_t &p)
Label of a pair of a label and target state.
std::size_t from(const outgoing_transitions_per_state_action_t::const_iterator &i)
From state of an iterator exploring transitions per outgoing state and action.
void group_transitions_on_label(const std::vector< transition >::iterator begin, const std::vector< transition >::iterator end, std::function< std::size_t(const transition &)> get_label, std::vector< std::pair< std::size_t, std::size_t > > &count_sum_transitions_per_action, const std::size_t tau_label_index=0, std::vector< std::size_t > &todo_stack=bogus_todo_stack)
bool reachability_check(probabilistic_lts< SL, AL, PROBABILISTIC_STATE, BASE > &l, bool remove_unreachable=false)
Checks whether all states in a probabilistic LTS are reachable from the initial state and remove unre...
bool compare(const LTS_TYPE &l1, const LTS_TYPE &l2, lts_preorder pre, bool generate_counter_example, const std::string &counter_example_file="", bool structured_output=false, lps::exploration_strategy strategy=lps::es_breadth, bool preprocess=true)
Checks whether this LTS is smaller than another LTS according to a preorder.
The main namespace for the Process library.
bool is_linear(const process_specification &p, bool verbose=false)
Returns true if the process specification is linear.
bool is_untyped_multi_action(const atermpp::aterm &x)
void swap(atermpp::term_balanced_tree< T > &t1, atermpp::term_balanced_tree< T > &t2) noexcept
Swaps two balanced trees.
#define USE_POOL_ALLOCATOR
static const atermpp::aterm StateMay
static const atermpp::aterm StateOr
static const atermpp::aterm UntypedRegFrm
static const atermpp::aterm StateFrm
static const atermpp::aterm StateYaled
static const atermpp::aterm RegAlt
static const atermpp::aterm ActNot
static const atermpp::aterm ActImp
static const atermpp::aterm ActTrue
static const atermpp::aterm StateInfimum
static const atermpp::aterm StateAnd
static const atermpp::aterm StateExists
static const atermpp::aterm RegTrans
static const atermpp::aterm ActOr
static const atermpp::aterm StateConstantMultiplyAlt
static const atermpp::aterm ActFrm
static const atermpp::aterm ActForall
static const atermpp::aterm StateYaledTimed
static const atermpp::aterm ActFalse
static const atermpp::aterm StateFalse
static const atermpp::aterm RegFrm
static const atermpp::aterm StateDelay
static const atermpp::aterm StatePlus
static const atermpp::aterm StateMinus
static const atermpp::aterm StateNu
static const atermpp::aterm ActAnd
static const atermpp::aterm StateDelayTimed
static const atermpp::aterm StateSupremum
static const atermpp::aterm StateSum
static const atermpp::aterm ActAt
static const atermpp::aterm ActExists
static const atermpp::aterm StateMu
static const atermpp::aterm RegTransOrNil
static const atermpp::aterm StateVar
static const atermpp::aterm StateImp
static const atermpp::aterm RegSeq
static const atermpp::aterm StateTrue
static const atermpp::aterm StateForall
static const atermpp::aterm StateMust
static const atermpp::aterm StateNot
static const atermpp::aterm ActMultAct
static const atermpp::aterm StateConstantMultiply
std::vector< state_type > bottom_states
block_index_type parent_block_index
block_index_type block_index
void swap(block &b) noexcept
std::vector< transition > non_inert_transitions
std::vector< non_bottom_state > non_bottom_states
std::vector< state_type > inert_transitions
non_bottom_state(const state_type s, const std::vector< state_type > &it)
non_bottom_state(const state_type s)
std::vector< state_type > states
void swap(block &b) noexcept
block_index_type block_index
std::vector< transition > transitions
block_index_type parent_block_index
bool operator==(const block &other)
void swap(block &b) noexcept
block_index_type parent_block_index
block_index_type block_index
bool operator!=(const block &other)
Converts a process expression into linear process format. Use the convert member functions for this.
lps::specification convert(const process_specification &p)
Converts a process_specification into a specification. Throws non_linear_process if a non-linear sub-...
Converts a process expression into linear process format. Use the convert member functions for this.
lps::stochastic_specification convert(const process_specification &p)
Converts a process_specification into a stochastic_specification. Throws non_linear_process if a non-...
std::size_t operator()(const atermpp::term_balanced_tree< T > &t) const
std::size_t operator()(const mcrl2::lps::probabilistic_data_expression &p) const
std::size_t operator()(const mcrl2::lps::state_probability_pair< STATE, PROBABILITY > &p) const
std::size_t operator()(const mcrl2::lts::action_label_lts &as) const
std::size_t operator()(const mcrl2::lts::probabilistic_state< STATE, PROBABILITY > &p) const