11#ifndef MCRL2_LTS_DETAIL_LIBLTS_BISIM_H
12#define MCRL2_LTS_DETAIL_LIBLTS_BISIM_H
15#include "mcrl2/modal_formula/state_formula.h"
16#include "mcrl2/lts/lts_utilities.h"
17#include "mcrl2/lts/detail/liblts_scc.h"
18#include "mcrl2/lts/detail/liblts_merge.h"
19#include "mcrl2/lts/lts_aut.h"
20#include "mcrl2/lts/lts_fsm.h"
21#include "mcrl2/lts/lts_dot.h"
26template <
class LTS_TYPE>
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
51 const bool branching =
false,
52 const bool preserve_divergence =
false,
53 const bool generate_counter_examples =
false)
58 assert(branching || !preserve_divergence);
59 mCRL2log(log::log_level_t::verbose) << (preserve_divergence?
"Divergence preserving b":
"B") <<
60 (branching?
"ranching b":
"") <<
"isimulation partitioner created for "
61 << l.num_states() <<
" states and " <<
62 l.num_transitions() <<
" transitions\n";
64 if (generate_counter_examples)
66 outgoing_transitions = transitions_per_outgoing_state_action_pair(aut.get_transitions(), aut.hidden_label_set());
78
79
80
81
82
83
84
85
86
87
88
94 std::set < transition > resulting_transitions;
96 for (
const transition& i:
aut.get_transitions())
98 const bool is_transition_i_hidden=
aut.is_tau(
aut.apply_hidden_label_map(i.label()));
100 !is_transition_i_hidden ||
101 get_eq_class(i.from())!=get_eq_class(i.to()) ||
102 (preserve_divergences && i.from()==i.to()))
104 resulting_transitions.insert(
106 get_eq_class(i.from()),
112 (is_transition_i_hidden?aut.tau_label_index():i.label()),
113 get_eq_class(i.to())));
117 aut.clear_transitions();
120 for (
const transition& t: resulting_transitions)
122 aut.add_transition(t);
127 if (
aut.has_state_info())
130 std::vector<
typename LTS_TYPE::state_label_t> new_labels(num_eq_classes());
132 for(std::size_t i=aut.num_states(); i>0; )
135 const std::size_t new_index=get_eq_class(i);
136 new_labels[new_index] = new_labels[new_index] + aut.state_label(i);
139 aut.set_num_states(num_eq_classes());
140 for(std::size_t i=0; i<num_eq_classes(); ++i)
142 aut.set_state_label(i,new_labels[i]);
147 aut.set_num_states(num_eq_classes());
150 aut.set_initial_state(get_eq_class(aut.initial_state()));
154
155
158 return max_state_index;
163
164
167 assert(s<block_index_of_a_state.size());
168 return blocks[block_index_of_a_state[s]].state_index;
173
174
175
176
179 return get_eq_class(s)==get_eq_class(t);
184
185
186
187
188
189
190
234 state_type state_index1=b.state_index;
235 b.state_index=state_index;
236 state_index=state_index1;
238 block_index_type block_index1=b.block_index;
239 b.block_index=block_index;
240 block_index=block_index1;
242 block_index_type parent_block_index1=b.parent_block_index;
243 b.parent_block_index=parent_block_index;
244 parent_block_index=parent_block_index1;
246 bottom_states.swap(b.bottom_states);
247 non_bottom_states.swap(b.non_bottom_states);
248 non_inert_transitions.swap(b.non_inert_transitions);
284 const bool preserve_divergences)
287 to_be_processed.clear();
289 block initial_partition;
292 sort_transitions(aut.get_transitions(), aut.hidden_label_set(), mcrl2::lts::transition_sort_style::src_lbl_tgt);
294 state_type last_non_stored_state_number=0;
295 bool bottom_state=
true;
296 std::vector < state_type > current_inert_transitions;
303 std::size_t initial_partition_non_inert_counter=0;
304 std::size_t current_inert_transition_counter=0;
305 const std::vector<transition> & trans=aut.get_transitions();
308 if (branching && aut.is_tau(aut.apply_hidden_label_map(t.label())))
310 if (preserve_divergences && t.from()==t.to())
312 initial_partition_non_inert_counter++;
316 current_inert_transition_counter++;
320 current_inert_transitions.reserve(initial_partition_non_inert_counter);
321 initial_partition.non_inert_transitions.reserve(current_inert_transition_counter);
324 const std::vector<transition>& trans=aut.get_transitions();
325 for (std::vector<transition>::const_iterator r=trans.begin(); r!=trans.end(); ++r)
327 const transition t=* r;
329 if (branching && aut.is_tau(aut.apply_hidden_label_map(t.label())))
331 if (preserve_divergences && t.from()==t.to())
333 initial_partition.non_inert_transitions.push_back(transition(t.from(),aut.tau_label_index(),t.to()));
337 current_inert_transitions.push_back(t.to());
341 std::vector<transition>::const_iterator next_i=r;
343 if (next_i==trans.end() || t.from()!=next_i->from())
346 for (; last_non_stored_state_number<t.from(); ++last_non_stored_state_number)
348 initial_partition.bottom_states.push_back(last_non_stored_state_number);
353 initial_partition.bottom_states.push_back(t.from());
357 initial_partition.non_bottom_states.push_back(non_bottom_state(t.from()));
358 current_inert_transitions.swap(initial_partition.non_bottom_states.back().inert_transitions);
361 assert(last_non_stored_state_number==t.from());
362 last_non_stored_state_number++;
366 for (; last_non_stored_state_number<aut.num_states(); ++last_non_stored_state_number)
368 initial_partition.bottom_states.push_back(last_non_stored_state_number);
374 order_on_tau_reachability(initial_partition.non_bottom_states);
377 sort_transitions(aut.get_transitions(), aut.hidden_label_set(), mcrl2::lts::transition_sort_style::lbl_tgt_src);
378 const std::vector<transition> & trans1=aut.get_transitions();
381 if (!branching || !aut.is_tau(aut.apply_hidden_label_map(t.label())))
384 initial_partition.non_inert_transitions.push_back(t);
388 initial_partition.block_index=0;
389 initial_partition.state_index=0;
391 initial_partition.parent_block_index=0;
392 blocks.push_back(block());
393 blocks.back().swap(initial_partition);
394 block_index_of_a_state=std::vector < block_index_type >(aut.num_states(),0);
395 block_flags.push_back(
false);
396 state_flags=std::vector <
bool >(aut.num_states(),
false);
397 block_is_in_to_be_processed.push_back(
false);
398 to_be_processed.clear();
410 std::size_t consistency_check_counter=1;
411 std::size_t consistency_check_barrier=1;
413 bool partition_is_unstable=
true;
415 while (!to_be_processed.empty() || partition_is_unstable)
419 consistency_check_counter++;
420 if (consistency_check_counter>=consistency_check_barrier)
422 consistency_check_counter=0;
423 consistency_check_barrier=consistency_check_barrier*2;
424 check_internal_consistency_of_the_partitioning_data_structure(branching, preserve_divergence);
427 if (to_be_processed.empty() && partition_is_unstable)
430 for (block_index_type i=0; i< blocks.size(); ++i)
432 to_be_processed.push_back(i);
434 block_is_in_to_be_processed=std::vector <
bool >(blocks.size(),
true);
435 partition_is_unstable=
false;
438 const block_index_type splitter_index=to_be_processed.back();
439 to_be_processed.pop_back();
440 block_is_in_to_be_processed[splitter_index]=
false;
449 for (std::size_t i=0; i<blocks[splitter_index].non_inert_transitions.size(); ++i)
453 assert(blocks[splitter_index].non_inert_transitions[i].from()<aut.num_states());
454 state_flags[blocks[splitter_index].non_inert_transitions[i].from()]=
true;
455 const block_index_type marked_block_index=block_index_of_a_state[blocks[splitter_index].non_inert_transitions[i].from()];
456 if (block_flags[marked_block_index]==
false)
458 block_flags[marked_block_index]=
true;
459 BL.push_back(marked_block_index);
463 if ((i+1)==blocks[splitter_index].non_inert_transitions.size() ||
464 aut.apply_hidden_label_map(blocks[splitter_index].non_inert_transitions[i].label())!=
465 aut.apply_hidden_label_map(blocks[splitter_index].non_inert_transitions[i+1].label()))
471 split_the_blocks_in_BL(partition_is_unstable,aut.apply_hidden_label_map(blocks[splitter_index].non_inert_transitions[i].label()),splitter_index);
481 block_is_in_to_be_processed.clear();
483 to_be_processed.clear();
490 bool& partition_is_unstable,
491 const label_type splitter_label,
492 const block_index_type splitter_block)
494 for (block_index_type i1: BL)
496 block_flags[i1] =
false;
497 std::vector < state_type > flagged_states;
498 std::vector < state_type > non_flagged_states;
499 std::vector < state_type > i1_bottom_states;
500 i1_bottom_states.swap(blocks[i1].bottom_states);
502 for (state_type bottom_state: i1_bottom_states)
504 if (state_flags[bottom_state])
507 flagged_states.push_back(bottom_state);
512 non_flagged_states.push_back(bottom_state);
513 block_index_of_a_state[bottom_state] = blocks.size();
516 assert(!flagged_states.empty()||!blocks[i1].non_bottom_states.empty()||i1_bottom_states.empty());
517 block_index_type reset_state_flags_block = i1;
519 if (!non_flagged_states.empty())
524 if (mCRL2logEnabled(log::log_level_t::debug))
526 const std::size_t new_block_count = (blocks.size()+1)/2;
527 const std::size_t m =
static_cast<std::size_t>(std::pow(10.0, std::floor(std::log10(
static_cast<
double>(new_block_count)))));
528 if (new_block_count % m==0)
530 mCRL2log(log::log_level_t::debug) <<
"Bisimulation partitioner: create block " << new_block_count << std::endl;
535 blocks.push_back(block());
536 block_index_type new_block1=blocks.size()-1;
537 blocks.back().state_index=max_state_index;
539 blocks.back().block_index=new_block1;
540 blocks.back().parent_block_index = i1;
542 non_flagged_states.swap(blocks.back().bottom_states);
544 to_be_processed.push_back(blocks.back().block_index);
545 block_is_in_to_be_processed.push_back(
true);
548 blocks.push_back(block());
549 block_index_type new_block2=blocks.size()-1;
550 blocks.back().state_index = blocks[i1].state_index;
551 blocks.back().block_index=new_block2;
552 reset_state_flags_block=new_block2;
553 blocks.back().parent_block_index = i1;
556 flagged_states.swap(blocks.back().bottom_states);
557 std::vector < state_type > &reference_to_flagged_states_of_block2=blocks.back().bottom_states;
558 for (state_type j: reference_to_flagged_states_of_block2)
560 block_index_of_a_state[j] = new_block2;
565 if (store_counter_info)
567 right_child[i1] = new_block1;
568 split_by_action[i1] = splitter_label;
569 split_by_block[i1] = splitter_block;
572 std::set<block_index_type> reachable_blocks = {};
573 for (state_type source_state : blocks[new_block1].bottom_states)
575 for (outgoing_transitions_per_state_action_t::const_iterator i = outgoing_transitions.lower_bound(std::pair<state_type, label_type>(source_state, splitter_label));
576 i != outgoing_transitions.upper_bound(std::pair<state_type, label_type>(source_state, splitter_label)); ++i)
578 state_type target_state = to(i);
579 block_index_type target_block = block_index_of_a_state[target_state];
580 reachable_blocks.insert(target_block == new_block1 || target_block == new_block2 ? i1 : target_block);
583 r_alpha[new_block1] = reachable_blocks;
587 std::set<block_index_type> tau_reachable_blocks = {};
588 for (state_type source_state : blocks[new_block1].bottom_states)
590 for (label_type lab = 0; lab < aut.num_action_labels(); ++lab)
592 if (aut.is_tau(aut.apply_hidden_label_map(lab)))
594 for (outgoing_transitions_per_state_action_t::const_iterator i = outgoing_transitions.lower_bound(std::pair<state_type, label_type>(source_state, lab));
595 i != outgoing_transitions.upper_bound(std::pair<state_type, label_type>(source_state, lab)); ++i)
597 state_type target_state = to(i);
598 block_index_type target_block = block_index_of_a_state[target_state];
599 if (!(target_block == i1 || target_block == new_block1 || target_block == new_block2))
601 tau_reachable_blocks.insert(target_block);
607 r_tauP[new_block1] = tau_reachable_blocks;
612 to_be_processed.push_back(blocks.back().block_index);
613 block_is_in_to_be_processed.push_back(
true);
616 block_is_in_to_be_processed[i1] =
false;
619 block_flags.push_back(
false);
620 block_flags.push_back(
false);
627 std::vector < transition > flagged_non_inert_transitions;
628 std::vector < transition > non_flagged_non_inert_transitions;
631 flagged_non_inert_transitions.reserve(blocks[i1].non_inert_transitions.size());
632 non_flagged_non_inert_transitions.reserve(blocks[i1].non_inert_transitions.size());
638 std::vector < non_bottom_state > flagged_non_bottom_states;
639 std::vector < non_bottom_state > non_flagged_non_bottom_states;
640 std::vector < non_bottom_state > i1_non_bottom_states;
641 i1_non_bottom_states.swap(blocks[i1].non_bottom_states);
642 for (
typename std::vector < non_bottom_state >::iterator k=i1_non_bottom_states.begin();
643 k!=i1_non_bottom_states.end(); ++k)
645 const std::vector < state_type > &inert_transitions=k->inert_transitions;
646 if (!state_flags[k->state])
648 bool all_transitions_end_in_unflagged_block=
true;
649 for (std::vector < state_type > :: const_iterator l=inert_transitions.begin();
650 all_transitions_end_in_unflagged_block && l!=inert_transitions.end(); ++l)
652 if (block_index_of_a_state[*l]!= new_block1)
654 block_index_of_a_state[*l]=new_block2;
655 all_transitions_end_in_unflagged_block=
false;
658 if (all_transitions_end_in_unflagged_block)
661 non_bottom_state s(k->state);
662 s.inert_transitions.swap(k->inert_transitions);
663 non_flagged_non_bottom_states.push_back(s);
664 block_index_of_a_state[k->state]=new_block1;
670 std::vector < state_type > remaining_inert_transitions;
671 for (state_type inert_transition: inert_transitions)
673 if (block_index_of_a_state[inert_transition] == new_block1)
677 non_flagged_non_inert_transitions.push_back(
678 transition(k->state, aut.tau_label_index(), inert_transition));
683 block_index_of_a_state[inert_transition] = new_block2;
684 remaining_inert_transitions.push_back(inert_transition);
687 if (remaining_inert_transitions.empty())
691 blocks[new_block2].bottom_states.push_back(k->state);
692 block_index_of_a_state[k->state]=new_block2;
693 partition_is_unstable=
true;
697 flagged_non_bottom_states.push_back(non_bottom_state(k->state,remaining_inert_transitions));
698 block_index_of_a_state[k->state]=new_block2;
701 non_flagged_non_bottom_states.swap(blocks[new_block1].non_bottom_states);
702 flagged_non_bottom_states.swap(blocks[new_block2].non_bottom_states);
707 assert(i1 < blocks.size());
708 std::vector < transition > i1_non_inert_transitions;
709 i1_non_inert_transitions.swap(blocks[i1].non_inert_transitions);
710 for (
auto& i1_non_inert_transition: i1_non_inert_transitions)
712 if (block_index_of_a_state[i1_non_inert_transition.to()] == new_block1)
714 non_flagged_non_inert_transitions.push_back(i1_non_inert_transition);
718 block_index_of_a_state[i1_non_inert_transition.to()] = new_block2;
719 flagged_non_inert_transitions.push_back(i1_non_inert_transition);
731 blocks[new_block1].non_inert_transitions.reserve(non_flagged_non_inert_transitions.size());
732 for (
const auto& non_flagged_non_inert_transition: non_flagged_non_inert_transitions)
734 blocks[new_block1].non_inert_transitions.push_back(non_flagged_non_inert_transition);
737 blocks[new_block2].non_inert_transitions.reserve(flagged_non_inert_transitions.size());
738 for (
const auto& flagged_non_inert_transition: flagged_non_inert_transitions)
740 blocks[new_block2].non_inert_transitions.push_back(flagged_non_inert_transition);
746 i1_bottom_states.swap(blocks[i1].bottom_states);
749 std::vector < state_type > &flagged_states_to_be_unflagged=blocks[reset_state_flags_block].bottom_states;
750 for (state_type j: flagged_states_to_be_unflagged)
752 state_flags[j] =
false;
755 std::vector < non_bottom_state > &flagged_states_to_be_unflagged1=blocks[reset_state_flags_block].non_bottom_states;
756 for (
typename std::vector < non_bottom_state >::const_iterator j=flagged_states_to_be_unflagged1.begin();
757 j!=flagged_states_to_be_unflagged1.end(); ++j)
759 state_flags[j->state]=
false;
771 if (inert_transition_map.count(s)>0)
773 if (visited.count(s)==0)
776 std::vector < state_type> &inert_transitions=inert_transition_map[s];
777 for (state_type inert_transition: inert_transitions)
779 order_recursively_on_tau_reachability(inert_transition,
780 inert_transition_map,
781 new_non_bottom_states,
784 new_non_bottom_states.push_back(non_bottom_state(s));
785 inert_transitions.swap(new_non_bottom_states.back().inert_transitions);
792 std::set < state_type > visited;
793 std::map < state_type, std::vector < state_type > > inert_transition_map;
794 for (
typename std::vector < non_bottom_state >::iterator i=non_bottom_states.begin();
795 i!=non_bottom_states.end(); ++i)
797 i->inert_transitions.swap(inert_transition_map[i->state]);
799 std::vector < non_bottom_state > new_non_bottom_states;
801 for (
typename std::vector < non_bottom_state >::const_iterator i=non_bottom_states.begin();
802 i!=non_bottom_states.end(); ++i)
804 order_recursively_on_tau_reachability(i->state, inert_transition_map, new_non_bottom_states, visited);
806 new_non_bottom_states.swap(non_bottom_states);
810
811
812
813
816 return utilities::detail::join<mcrl2::state_formulas::state_formula>(terms.begin(), terms.end(),
817 [](mcrl2::state_formulas::state_formula a, mcrl2::state_formulas::state_formula b)
818 {
return mcrl2::state_formulas::and_(a, b); }, mcrl2::state_formulas::true_());
822
823
824
825
826
833
834
835
836
837
841 process::action_list({ process::action(process::action_label(a, {}), {}) })));
845
846
847
848
849
850
851
852
853
854
858 std::string var =
"X" + std::to_string(fresh_var_counter++);
860 mcrl2::state_formulas::may(regular_formulas::regular_formula(action_formulas::multi_action()), mcrl2::state_formulas::variable(var, {}));
864 mcrl2::state_formulas::mu(var, {}, mcrl2::state_formulas::and_(phi1, mcrl2::state_formulas::or_(tauStep, lastStep)));
866 if (aut.is_tau(aut.apply_hidden_label_map(a)))
874
875
876
877
878
879
884 std::set < block_index_type > blocks_containing_B1;
885 block_index_type B1p = B1;
886 blocks_containing_B1.insert(B1p);
887 while (blocks[B1p].parent_block_index != B1p)
889 B1p = blocks[B1p].parent_block_index;
890 blocks_containing_B1.insert(B1p);
894 block_index_type DB = B2;
895 while (blocks_containing_B1.count(DB) == 0)
897 assert(blocks[DB].parent_block_index != DB);
898 DB = blocks[DB].parent_block_index;
903 const block_index_type R = right_child.at(DB);
904 const label_type a = split_by_action.at(DB);
905 const block_index_type Bp = split_by_block.at(DB);
908 std::set<mcrl2::state_formulas::state_formula> Gamma2;
909 for (block_index_type PPB : r_alpha.at(R))
911 Gamma2.insert(counter_formula_aux(Bp, PPB));
919 std::set<mcrl2::state_formulas::state_formula> Gamma1;
920 for (block_index_type PPB : r_tauP.at(R))
922 Gamma1.insert(counter_formula_aux(DB, PPB));
927 if (aut.is_tau(aut.apply_hidden_label_map(a)))
929 Phi2 = mcrl2::state_formulas::and_(Phi2, counter_formula_aux(Bp, R));
932 Phi = until_formula(Phi1, a, Phi2);
936 Phi = mcrl2::state_formulas::may(create_regular_formula(aut.action_label(a)), Phi2);
939 if (blocks_containing_B1.count(R) == 0)
957 const bool branching,
958 const bool preserve_divergence)
const
960 state_type total_number_of_states=0;
961 std::size_t total_number_of_transitions=0;
963 assert(!blocks.empty());
964 std::set < block_index_type > block_indices;
966 assert(block_index_of_a_state.size()==aut.num_states());
967 for (
typename std::vector < block >::const_iterator i=blocks.begin();
968 i!=blocks.end(); ++i)
971 assert(i->block_index<blocks.size());
972 assert(block_indices.count(i->block_index)==0);
973 block_indices.insert(i->block_index);
976 const std::vector < state_type > &i_bottom_states=i->bottom_states;
978 for (state_type bottom_state: i_bottom_states)
980 total_number_of_states++;
981 assert(bottom_state < aut.num_states());
983 assert(block_index_of_a_state[bottom_state] == i->block_index);
988 const std::vector < non_bottom_state > &i_non_bottom_states=i->non_bottom_states;
989 std::set < state_type > visited;
990 std::set < state_type > local_bottom_states;
991 for (
typename std::vector < non_bottom_state >::const_iterator j=i_non_bottom_states.begin();
992 j!=i_non_bottom_states.end(); ++j)
994 local_bottom_states.insert(j->state);
997 for (
typename std::vector < non_bottom_state >::const_iterator j=i_non_bottom_states.begin();
998 j!=i_non_bottom_states.end(); ++j)
1000 total_number_of_states++;
1001 assert(j->state<aut.num_states());
1003 assert(block_index_of_a_state[j->state]==i->block_index);
1004 const std::vector < state_type > &j_inert_transitions=j->inert_transitions;
1005 for (state_type inert_transition: j_inert_transitions)
1007 total_number_of_transitions++;
1008 assert(inert_transition < aut.num_states());
1010 assert(visited.count(inert_transition) > 0 || local_bottom_states.count(inert_transition) == 0);
1012 visited.insert(j->state);
1018 const std::vector < transition > &i_non_inert_transitions=i->non_inert_transitions;
1019 std::set < label_type > observed_action_labels;
1020 for (std::vector < transition >::const_iterator j=i_non_inert_transitions.begin();
1021 j!=i_non_inert_transitions.end(); ++j)
1023 total_number_of_transitions++;
1024 assert(j->to()<aut.num_states());
1025 assert(j->from()<aut.num_states());
1028 std::vector < transition >::const_iterator j_next=j;
1030 if (j_next==i_non_inert_transitions.end() || (aut.apply_hidden_label_map(j->label())!=aut.apply_hidden_label_map(j_next->label())))
1032 assert(observed_action_labels.count(aut.apply_hidden_label_map(j->label()))==0);
1033 observed_action_labels.insert(aut.apply_hidden_label_map(j->label()));
1037 if (!preserve_divergence && branching && aut.is_tau(aut.apply_hidden_label_map(j->label())))
1039 assert(j->to()!=j->from());
1043 assert(block_index_of_a_state[j->to()]==i->block_index);
1048 assert(total_number_of_states==aut.num_states());
1049 assert(total_number_of_transitions==aut.num_transitions());
1052 assert(block_index_of_a_state.size()==aut.num_states());
1053 for (block_index_type i: block_index_of_a_state)
1055 assert(blocks[i].block_index == i);
1059 for (
bool block_flag: block_flags)
1061 assert(!block_flag);
1065 for (
bool state_flag: state_flags)
1067 assert(!state_flag);
1072 std::vector <
bool > temporary_block_is_in_to_be_processed(blocks.size(),
false);
1074 for (block_index_type i: to_be_processed)
1076 temporary_block_is_in_to_be_processed[i] =
true;
1078 for (state_type i=0; i<blocks.size(); ++i)
1080 assert(!block_is_in_to_be_processed[i] || temporary_block_is_in_to_be_processed[i]);
1094
1095
1096
1097
1098template<
class LTS_TYPE>
1099void bisimulation_reduce(LTS_TYPE& l,
bool branching =
false,
bool preserve_divergences =
false);
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113template<
class LTS_TYPE>
1116 bool branching =
false,
1117 bool preserve_divergences =
false,
1118 bool generate_counter_examples =
false,
1119 const std::string& counter_example_file =
"",
1120 bool structured_output =
false);
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136template<
class LTS_TYPE>
1139 bool branching =
false,
1140 bool preserve_divergences =
false,
1141 bool generate_counter_examples =
false,
1142 const std::string& counter_example_file =
"",
1143 bool structured_output =
false);
1145template <
class LTS_TYPE>
1147 const std::size_t s,
const std::size_t t)
1149 if (get_eq_class(s)==get_eq_class(t))
1151 throw mcrl2::runtime_error(
"Requesting a counter state formula for two bisimilar states. Such a state formula is not useful.");
1154 return counter_formula_aux(block_index_of_a_state[s], block_index_of_a_state[t]);
1158template <
class LTS_TYPE>
1159void bisimulation_reduce(LTS_TYPE& l,
1160 const bool branching ,
1161 const bool preserve_divergences )
1166 scc_reduce(l,preserve_divergences);
1174 bisim_part.replace_transition_system(branching,preserve_divergences);
1177template <
class LTS_TYPE>
1178bool bisimulation_compare(
1181 const bool branching ,
1182 const bool preserve_divergences ,
1183 const bool generate_counter_examples ,
1184 const std::string& ,
1185 const bool structured_output )
1187 LTS_TYPE l1_copy(l1);
1188 LTS_TYPE l2_copy(l2);
1189 return destructive_bisimulation_compare(l1_copy,l2_copy,branching,preserve_divergences,
1190 generate_counter_examples, structured_output);
1193template <
class LTS_TYPE>
1194bool destructive_bisimulation_compare(
1197 const bool branching ,
1198 const bool preserve_divergences ,
1199 const bool generate_counter_examples ,
1200 const std::string& counter_example_file ,
1203 std::size_t init_l2 = l2.initial_state() + l1.num_states();
1210 detail::scc_partitioner<LTS_TYPE> scc_part(l1);
1211 scc_part.replace_transition_system(preserve_divergences);
1212 init_l2 = scc_part.get_eq_class(init_l2);
1215 detail::
bisim_partitioner<LTS_TYPE> bisim_part(l1, branching, preserve_divergences, generate_counter_examples);
1216 if (generate_counter_examples && !bisim_part.in_same_class(l1.initial_state(), init_l2))
1220 std::string filename =
"Counterexample.mcf";
1221 if (!counter_example_file.empty())
1223 filename = counter_example_file;
1225 std::ofstream counter_file(filename);
1226 counter_file << mcrl2::state_formulas::pp(counter_example_formula);
1227 counter_file.close();
1228 mCRL2log(mcrl2::log::log_level_t::info) <<
"Saved counterexample to: \"" << filename <<
"\"" << std::endl;
1231 return bisim_part.in_same_class(l1.initial_state(),init_l2);
\brief A timed multi-action
const process::action_list & actions() const
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
function object to compare two constln_t pointers based on their contents
A class that can be used to store counterexample trees and.
A class that contains a labelled transition system.
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.
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
The main namespace for the LPS library.
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(const std::set< lts_type > &supported)
Gives a textual list describing supported LTS formats.
std::string string_for_type(const lts_type type)
Gives a string representation of an LTS format.
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.
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.
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)
std::string supported_lts_formats_text(lts_type default_format, const std::set< lts_type > &supported)
Gives a textual list describing supported LTS formats.
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()
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::exploration_strategy::es_breadth, bool preprocess=true)
Checks whether this LTS is smaller than another LTS according to a preorder.
bool is_deterministic(const LTS_TYPE &l)
Checks whether this LTS is deterministic.
void determinise(LTS_TYPE &l)
Determinises this LTS.
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::exploration_strategy::es_breadth, bool preprocess=true)
Checks whether this LTS is smaller than another LTS according to a preorder.
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.
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.
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...
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...
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)