mCRL2
Loading...
Searching...
No Matches
lts_algorithm.h
Go to the documentation of this file.
1// Author(s): Muck van Weerdenburg, Jan Friso Groote
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
9
19#define BRANCH_BIS_EXPERIMENT_JFG
20
21#ifndef MCRL2_LTS_LTS_ALGORITHM_H
22#define MCRL2_LTS_LTS_ALGORITHM_H
23
27#ifdef BRANCH_BIS_EXPERIMENT_JFG
29#endif
39#include "mcrl2/lts/sigref.h"
40
41namespace mcrl2
42{
43namespace lts
44{
45
51template <class LTS_TYPE>
52void reduce(LTS_TYPE& l, lts_equivalence eq);
53
68template <class LTS_TYPE>
69bool destructive_compare(LTS_TYPE& l1,
70 LTS_TYPE& l2,
71 const lts_equivalence eq,
72 const bool generate_counter_examples = false,
73 const std::string& counter_example_file = std::string(),
74 const bool structured_output = false)
75{
76 // Merge this LTS and l and store the result in this LTS.
77 // In the resulting LTS, the initial state i of l will have the
78 // state number i + N where N is the number of states in this
79 // LTS (before the merge).
80
81 switch (eq)
82 {
83 case lts_eq_none:
84 return false;
85 case lts_eq_bisim:
86 {
87 if (generate_counter_examples)
88 {
89 mCRL2log(mcrl2::log::warning) << "A slower partition refinement algorithm is used to generate minimal-depth counter examples.\n";
90 return detail::destructive_bisimulation_compare_minimal_depth(l1, l2, counter_example_file);
91 }
92 return detail::destructive_bisimulation_compare_dnj(l1,l2, false,false,generate_counter_examples,counter_example_file,structured_output);
93 }
94 case lts_eq_bisim_gv:
95 {
96 return detail::destructive_bisimulation_compare(l1,l2, false,false,generate_counter_examples,counter_example_file,structured_output);
97 }
99 {
100 return detail::destructive_bisimulation_compare_gjkw(l1,l2, false,false,generate_counter_examples,counter_example_file,structured_output);
101 }
102#ifdef BRANCH_BIS_EXPERIMENT_JFG
103 case lts_eq_bisim_gj:
104 {
105 return detail::destructive_bisimulation_compare_gj(l1,l2, false,false,generate_counter_examples,counter_example_file,structured_output);
106 }
107#endif
109 {
110 if (generate_counter_examples)
111 {
112 mCRL2log(mcrl2::log::warning) << "The default branching bisimulation comparison algorithm cannot generate counter examples. A slower partition refinement algorithm (Martens/Groote 2024) is used instead.\n";
113 return detail::destructive_branching_bisimulation_compare_minimal_depth(l1, l2, counter_example_file);
114 }
115 return detail::destructive_bisimulation_compare_dnj(l1,l2, true,false,generate_counter_examples,counter_example_file,structured_output);
116 }
118 {
119 return detail::destructive_bisimulation_compare(l1,l2, true,false,generate_counter_examples,counter_example_file,structured_output);
120 }
122 {
123 return detail::destructive_bisimulation_compare_gjkw(l1,l2, true,false,generate_counter_examples,counter_example_file,structured_output);
124 }
125#ifdef BRANCH_BIS_EXPERIMENT_JFG
127 {
128 return detail::destructive_bisimulation_compare_gj(l1,l2, true,false,generate_counter_examples,counter_example_file,structured_output);
129 }
130#endif
132 {
133 if (generate_counter_examples)
134 {
135 mCRL2log(mcrl2::log::warning) << "The default divergence-preserving branching bisimulation comparison algorithm cannot generate counter examples. Therefore the slower gv algorithm is used instead.\n";
136 return detail::destructive_bisimulation_compare(l1,l2, true,true,generate_counter_examples,counter_example_file,structured_output);
137 }
138 return detail::destructive_bisimulation_compare_dnj(l1,l2, true,true,generate_counter_examples,counter_example_file,structured_output);
139 }
141 {
142 return detail::destructive_bisimulation_compare(l1,l2, true,true,generate_counter_examples,counter_example_file,structured_output);
143 }
145 {
146 return detail::destructive_bisimulation_compare_gjkw(l1,l2, true,true,generate_counter_examples,counter_example_file,structured_output);
147 }
148#ifdef BRANCH_BIS_EXPERIMENT_JFG
150 {
151 return detail::destructive_bisimulation_compare_gj(l1,l2, true,true,generate_counter_examples,counter_example_file,structured_output);
152 }
153#endif
155 {
156 if (generate_counter_examples)
157 {
158 mCRL2log(log::warning) << "Cannot generate counter examples for weak bisimulation\n";
159 }
161 }
163 {
164 if (generate_counter_examples)
165 {
166 mCRL2log(log::warning) << "Cannot generate counter examples for divergence-preserving weak bisimulation\n";
167 }
169 }
170 case lts_eq_sim:
171 {
172 if (generate_counter_examples)
173 {
174 mCRL2log(log::warning) << "Cannot generate counter examples for simulation equivalence\n";
175 }
176 // Run the partitioning algorithm on this merged LTS
177 std::size_t init_l2 = l2.initial_state() + l1.num_states();
178 detail::merge(l1,l2);
179 l2.clear(); // l2 is not needed anymore.
182
183 return sp.in_same_class(l1.initial_state(),init_l2);
184 }
185 case lts_eq_ready_sim:
186 {
187 if (generate_counter_examples)
188 {
189 mCRL2log(log::warning) << "Cannot generate counter examples for ready-simulation equivalence\n";
190 }
191 // Run the partitioning algorithm on this merged LTS
192 std::size_t init_l2 = l2.initial_state() + l1.num_states();
193 detail::merge(l1,l2);
194 l2.clear(); // l2 is not needed anymore.
197
198 return rsp.in_same_class(l1.initial_state(),init_l2);
199 }
200 case lts_eq_trace:
201 {
202 // Determinise first LTS
204 determinise(l1);
205
206 // Determinise second LTS
208 determinise(l2);
209
210 // Trace equivalence now corresponds to bisimilarity
211 if (generate_counter_examples)
212 {
213 return detail::destructive_bisimulation_compare_minimal_depth(l1, l2, counter_example_file);
214 }
215 return detail::destructive_bisimulation_compare(l1, l2, false, false, generate_counter_examples, counter_example_file, structured_output);
216 }
218 {
219 if (generate_counter_examples)
220 {
221 mCRL2log(log::warning) << "Cannot generate counter examples for weak trace equivalence\n";
222 }
223
224 // Eliminate silent steps and determinise first LTS
225 detail::bisimulation_reduce_dnj(l1,true,false);
228 determinise(l1);
229
230 // Eliminate silent steps and determinise second LTS
231 detail::bisimulation_reduce_dnj(l2,true,false);
234 determinise(l2);
235
236 // Weak trace equivalence now corresponds to bisimilarity
237 return detail::destructive_bisimulation_compare(l1,l2,false,false,false,counter_example_file,structured_output);
238 }
240 {
242 }
243 default:
244 throw mcrl2::runtime_error("Comparison for this equivalence is not available");
245 return false;
246 }
247}
248
262template <class LTS_TYPE>
263bool compare(const LTS_TYPE& l1,
264 const LTS_TYPE& l2,
265 const lts_equivalence eq,
266 const bool generate_counter_examples = false,
267 const std::string& counter_example_file = "",
268 const bool structured_output = false);
269
291template <class LTS_TYPE >
292bool destructive_compare(LTS_TYPE& l1,
293 LTS_TYPE& l2,
294 const lts_preorder pre,
295 const bool generate_counter_example,
296 const std::string& counter_example_file = "",
297 const bool structured_output = false,
299 const bool preprocess = true);
300
315template <class LTS_TYPE >
316bool compare(const LTS_TYPE& l1,
317 const LTS_TYPE& l2,
318 const lts_preorder pre,
319 const bool generate_counter_example,
320 const std::string& counter_example_file = "",
321 const bool structured_output = false,
323 const bool preprocess = true);
324
326template <class LTS_TYPE>
327void determinise(LTS_TYPE& l);
328
329
340template <class SL, class AL, class BASE>
341bool reachability_check(lts < SL, AL, BASE>& l, bool remove_unreachable = false)
342{
343 // First calculate which states can be reached, and store this in the array visited.
344 const outgoing_transitions_per_state_t out_trans(l.get_transitions(),l.num_states(),true);
345
346 std::vector < bool > visited(l.num_states(),false);
347 std::stack<std::size_t> todo;
348
349 visited[l.initial_state()]=true;
350 todo.push(l.initial_state());
351
352 while (!todo.empty())
353 {
354 std::size_t state_to_consider=todo.top();
355 todo.pop();
356 // for (const outgoing_pair_t& p: out_trans[state_to_consider])
357 for (detail::state_type i=out_trans.lowerbound(state_to_consider); i<out_trans.upperbound(state_to_consider); ++i)
358 {
359 const outgoing_pair_t& p=out_trans.get_transitions()[i];
360 assert(visited[state_to_consider] && state_to_consider<l.num_states() && to(p)<l.num_states());
361 if (!visited[to(p)])
362 {
363 visited[to(p)]=true;
364 todo.push(to(p));
365 }
366 }
367 }
368
369 // Property: in_visited(s) == true: state s is reachable from the initial state
370
371 // check to see if all states are reachable from the initial state, i.e.
372 // whether all bits are set.
373 bool all_reachable = find(visited.begin(),visited.end(),false)==visited.end();
374
375 if (!all_reachable && remove_unreachable)
376 {
377 // Remove all unreachable states, transitions from such states and labels
378 // that are only used in these transitions.
379
380 std::vector < detail::state_type > state_map(l.num_states());
381 std::vector < detail::state_type > label_map(l.num_action_labels());
382
383 lts < SL, AL, BASE> new_lts=l; // In this way set data specification and action declarations in the new lts.
384 new_lts.clear();
385
386 std::size_t new_nstates = 0;
387 for (std::size_t i=0; i<l.num_states(); i++)
388 {
389 if (visited[i])
390 {
391 state_map[i] = new_nstates;
392 if (l.has_state_info())
393 {
394 new_lts.add_state(l.state_label(i));
395 }
396 else
397 {
398 new_lts.add_state();
399 }
400 new_nstates++;
401 }
402 }
403
404 for (const transition& t: l.get_transitions())
405 {
406 if (visited[t.from()])
407 {
408 label_map[t.label()] = 1;
409 }
410 }
411
412 label_map[0]=1; // Declare the tau action explicitly present.
413 std::size_t new_nlabels = 0;
414 for (std::size_t i=0; i<l.num_action_labels(); i++)
415 {
416 if (label_map[i]>0) // Label i is used.
417 {
418 label_map[i] = new_nlabels;
419 new_lts.add_action(l.action_label(i));
420 new_nlabels++;
421 }
422 }
423
424 for (const transition& t: l.get_transitions())
425 {
426 if (visited[t.from()])
427 {
428 new_lts.add_transition(transition(state_map[t.from()],label_map[t.label()],state_map[t.to()]));
429 }
430 }
431
432 new_lts.set_initial_state(state_map.at(l.initial_state()));
433 l.swap(new_lts);
434 }
435
436 return all_reachable;
437}
438
449template <class SL, class AL, class PROBABILISTIC_STATE, class BASE>
450bool reachability_check(probabilistic_lts < SL, AL, PROBABILISTIC_STATE, BASE>& l, bool remove_unreachable = false)
451{
452 // First calculate which states can be reached, and store this in the array visited.
453 const outgoing_transitions_per_state_t out_trans(l.get_transitions(),l.num_states(),true);
454
455 std::vector < bool > visited(l.num_states(),false);
456 std::stack<std::size_t> todo;
457
458 if (l.initial_probabilistic_state().size()>1) // Target states are in a probabilistic vector.
459 {
460 for(const typename PROBABILISTIC_STATE::state_probability_pair& s: l.initial_probabilistic_state())
461 {
462 visited[s.state()]=true;
463 todo.push(s.state());
464 }
465 }
466 else // it is a singular state;
467 {
468 const typename PROBABILISTIC_STATE::state_t sn=l.initial_probabilistic_state().get();
469 visited[sn]=true;
470 todo.push(sn);
471 }
472
473 while (!todo.empty())
474 {
475 std::size_t state_to_consider=todo.top();
476 todo.pop();
477 // for (const outgoing_pair_t& p: out_trans[state_to_consider])
478 for (detail::state_type i=out_trans.lowerbound(state_to_consider); i<out_trans.upperbound(state_to_consider); ++i)
479 {
480 const outgoing_pair_t& p=out_trans.get_transitions()[i];
481 assert(visited[state_to_consider] && state_to_consider<l.num_states() && to(p)<l.num_probabilistic_states());
482 // Walk through the the states in this probabilistic state.
483 if (l.probabilistic_state(to(p)).size()>1) // Target states are in a probabilistic vector.
484 {
485 for(const typename PROBABILISTIC_STATE::state_probability_pair& pr: l.probabilistic_state(to(p)))
486 {
487 if (!visited[pr.state()])
488 {
489 visited[pr.state()]=true;
490 todo.push(pr.state());
491 }
492 }
493 }
494 else // it is a singular state;
495 {
496 const typename PROBABILISTIC_STATE::state_t sn=l.probabilistic_state(to(p)).get();
497 if (!visited[sn])
498 {
499 visited[sn]=true;
500 todo.push(sn);
501 }
502 }
503 }
504 }
505
506 // Property: in_visited(s) == true: state s is reachable from the initial state
507
508 // check to see if all states are reachable from the initial state, i.e.
509 // whether all bits are set.
510 bool all_reachable = find(visited.begin(),visited.end(),false)==visited.end();
511
512 if (!all_reachable && remove_unreachable)
513 {
514 // Remove all unreachable states, transitions from such states and labels
515 // that are only used in these transitions.
516
517 std::vector < detail::state_type > state_map(l.num_states());
518 std::vector < detail::state_type > label_map(l.num_action_labels());
519
520 probabilistic_lts < SL, AL, PROBABILISTIC_STATE, BASE> new_lts=l; // In this way set data specification and action declarations in the new lts.
521 new_lts.clear();
522
523 std::size_t new_nstates = 0;
524 for (std::size_t i=0; i<l.num_states(); i++)
525 {
526 if (visited[i])
527 {
528 state_map[i] = new_nstates;
529 if (l.has_state_info())
530 {
531 new_lts.add_state(l.state_label(i));
532 }
533 else
534 {
535 new_lts.add_state();
536 }
537 new_nstates++;
538 }
539 }
540
541 for (const transition& t: l.get_transitions())
542 {
543 if (visited[t.from()])
544 {
545 label_map[t.label()] = 1;
546 }
547 }
548
549 label_map[0]=1; // Declare the tau action explicitly present.
550 std::size_t new_nlabels = 0;
551 for (std::size_t i=0; i<l.num_action_labels(); i++)
552 {
553 if (label_map[i]>0) // Label i is used.
554 {
555 label_map[i] = new_nlabels;
556 new_lts.add_action(l.action_label(i));
557 new_nlabels++;
558 }
559 }
560
561 for (const transition& t: l.get_transitions())
562 {
563 if (visited[t.from()])
564 {
565 new_lts.add_transition(transition(state_map[t.from()],label_map[t.label()],t.to()));
566 }
567 }
568
569 PROBABILISTIC_STATE new_initial_state;
570 for (std::size_t i=0; i<l.num_probabilistic_states(); ++i)
571 {
572 new_initial_state.clear();
573 if (l.probabilistic_state(i).size()==0)
574 {
575 new_initial_state.set(state_map[l.probabilistic_state(i).get()]);
576 }
577 else
578 {
579 for(const typename PROBABILISTIC_STATE::state_probability_pair& s: l.probabilistic_state(i))
580 {
581 new_initial_state.add(state_map[s.state()], s.probability());
582 }
583 }
584 new_lts.add_probabilistic_state(new_initial_state);
585 }
586
587 new_initial_state.clear();
588 if (l.initial_probabilistic_state().size()==0)
589 {
590 new_initial_state.set(state_map[l.initial_probabilistic_state().get()]);
591 }
592 else
593 {
594 for(const typename PROBABILISTIC_STATE::state_probability_pair& s: l.initial_probabilistic_state())
595 {
596 new_initial_state.add(state_map[s.state()], s.probability());
597 }
598 }
599 new_lts.set_initial_probabilistic_state(new_initial_state);
600 l.swap(new_lts);
601 }
602
603 return all_reachable;
604}
605
609template <class LTS_TYPE>
610bool is_deterministic(const LTS_TYPE& l);
611
616template <class LTS_TYPE>
617void merge(LTS_TYPE& l1, const LTS_TYPE& l2)
618{
619 detail::merge(l1,l2);
620}
621
622
623/* Here the implementations of the declared functions above are given.
624 Originally these were in a .cpp file, before lts's were templated */
625
626
627
628template <class LTS_TYPE>
629void reduce(LTS_TYPE& l,lts_equivalence eq)
630{
631
632 switch (eq)
633 {
634 case lts_eq_none:
635 return;
636 case lts_eq_bisim:
637 {
638 detail::bisimulation_reduce_dnj(l,false,false);
639 return;
640 }
641 case lts_eq_bisim_gv:
642 {
643 detail::bisimulation_reduce(l,false,false);
644 return;
645 }
647 {
649 return;
650 }
651#ifdef BRANCH_BIS_EXPERIMENT_JFG
652 case lts_eq_bisim_gj:
653 {
654 detail::bisimulation_reduce_gj(l,false,false);
655 return;
656 }
657#endif
659 {
661 s.run();
662 return;
663 }
665 {
667 return;
668 }
670 {
671 detail::bisimulation_reduce(l,true,false);
672 return;
673 }
675 {
677 return;
678 }
679#ifdef BRANCH_BIS_EXPERIMENT_JFG
681 {
682 detail::bisimulation_reduce_gj(l,true,false);
683 return;
684 }
685#endif
687 {
689 s.run();
690 return;
691 }
693 {
695 return;
696 }
698 {
699 detail::bisimulation_reduce(l,true,true);
700 return;
701 }
703 {
705 return;
706 }
707#ifdef BRANCH_BIS_EXPERIMENT_JFG
709 {
711 return;
712 }
713#endif
715 {
717 s.run();
718 return;
719 }
721 {
723 return;
724 }
725 /*
726 case lts_eq_weak_bisim_sigref:
727 {
728 {
729 sigref<LTS_TYPE, signature_branching_bisim<LTS_TYPE> > s1(l);
730 s1.run();
731 }
732 detail::reflexive_transitive_tau_closure(l);
733 {
734 sigref<LTS_TYPE, signature_bisim<LTS_TYPE> > s2(l);
735 s2.run();
736 }
737 scc_reduce(l); // Remove tau loops
738 return;
739 }
740 */
742 {
744 return;
745 }
746 /*
747 case lts_eq_divergence_preserving_weak_bisim_sigref:
748 {
749 {
750 sigref<LTS_TYPE, signature_divergence_preserving_branching_bisim<LTS_TYPE> > s1(l);
751 s1.run();
752 }
753 std::size_t divergence_label=detail::mark_explicit_divergence_transitions(l);
754 detail::reflexive_transitive_tau_closure(l);
755 {
756 sigref<LTS_TYPE, signature_bisim<LTS_TYPE> > s2(l);
757 s2.run();
758 }
759 scc_reduce(l); // Remove tau loops
760 detail::unmark_explicit_divergence_transitions(l,divergence_label);
761 return;
762 }
763 */
764 case lts_eq_sim:
765 {
766 // Run the partitioning algorithm on this LTS
769
770 // Clear this LTS, but keep the labels
771 // l.clear_type();
772 l.clear_state_labels();
773 l.clear_transitions();
774
775 // Assign the reduced LTS
776 l.set_num_states(sp.num_eq_classes());
777 l.set_initial_state(sp.get_eq_class(l.initial_state()));
778
779 const std::vector <transition> trans=sp.get_transitions();
780 l.clear_transitions();
781 for (std::vector <transition>::const_iterator i=trans.begin(); i!=trans.end(); ++i)
782 {
783 l.add_transition(*i);
784 }
785 // Remove unreachable parts
786
787 reachability_check(l,true);
788
789 return;
790 }
791 case lts_eq_ready_sim:
792 {
793 // Run the partitioning algorithm on this LTS
796
797 // Clear this LTS, but keep the labels
798 // l.clear_type();
799 l.clear_state_labels();
800 l.clear_transitions();
801
802 // Assign the reduced LTS
803 l.set_num_states(rsp.num_eq_classes());
804 l.set_initial_state(rsp.get_eq_class(l.initial_state()));
805
806 const std::vector <transition> trans=rsp.get_transitions();
807 l.clear_transitions();
808 for (std::vector <transition>::const_iterator i=trans.begin(); i!=trans.end(); ++i)
809 {
810 l.add_transition(*i);
811 }
812 // Remove unreachable parts
813
814 reachability_check(l,true);
815
816 return;
817 }
818 case lts_eq_trace:
820 determinise(l);
822 return;
824 {
828 determinise(l);
830 return;
831 }
832 case lts_red_tau_star:
833 {
837 return;
838 }
840 {
841 determinise(l);
842 return;
843 }
844 default:
845 throw mcrl2::runtime_error("Unknown reduction method.");
846 }
847}
848
849template <class LTS_TYPE>
850bool compare(const LTS_TYPE& l1, const LTS_TYPE& l2, const lts_equivalence eq, const bool generate_counter_examples, const std::string& counter_example_file, const bool structured_output)
851{
852 switch (eq)
853 {
854 case lts_eq_none:
855 return false;
856 default:
857 LTS_TYPE l1_copy(l1);
858 LTS_TYPE l2_copy(l2);
859 return destructive_compare(l1_copy, l2_copy, eq ,generate_counter_examples, counter_example_file, structured_output);
860 }
861 return false;
862}
863
864template <class LTS_TYPE>
865bool compare(const LTS_TYPE& l1, const LTS_TYPE& l2, const lts_preorder pre, const bool generate_counter_example, const std::string& counter_example_file, const bool structured_output, const lps::exploration_strategy strategy, const bool preprocess)
866{
867 LTS_TYPE l1_copy(l1);
868 LTS_TYPE l2_copy(l2);
869 return destructive_compare(l1_copy, l2_copy, pre, generate_counter_example, counter_example_file, structured_output, strategy, preprocess);
870}
871
872template <class LTS_TYPE>
873bool destructive_compare(LTS_TYPE& l1, LTS_TYPE& l2, const lts_preorder pre, const bool generate_counter_example, const std::string& counter_example_file, const bool structured_output, const lps::exploration_strategy strategy, const bool preprocess)
874{
875 switch (pre)
876 {
877 case lts_pre_sim:
878 {
879 // Merge this LTS and l and store the result in this LTS.
880 // In the resulting LTS, the initial state i of l will have the
881 // state number i + N where N is the number of states in this
882 // LTS (before the merge).
883 const std::size_t init_l2 = l2.initial_state() + l1.num_states();
884 detail::merge(l1,l2);
885
886 // We no longer need l, so clear it to save memory
887 l2.clear();
888
889 // Run the partitioning algorithm on this merged LTS
892
893 return sp.in_preorder(l1.initial_state(),init_l2);
894 }
896 {
897 // Merge this LTS and l and store the result in this LTS.
898 // In the resulting LTS, the initial state i of l will have the
899 // state number i + N where N is the number of states in this
900 // LTS (before the merge).
901 const std::size_t init_l2 = l2.initial_state() + l1.num_states();
902 detail::merge(l1,l2);
903
904 // We no longer need l, so clear it to save memory
905 l2.clear();
906
907 // Run the partitioning algorithm on this prepropcessed LTS
910
911 return rsp.in_preorder(l1.initial_state(),init_l2);
912 }
913 case lts_pre_trace:
914 {
915 // Preprocessing: reduce modulo strong bisimulation equivalence.
916 // This is not strictly necessary, but may reduce time/memory
917 // needed for determinisation.
920
921 // Determinise both LTSes. As postprocessing, reduce modulo
922 // strong bisimulation equivalence. This is not strictly
923 // necessary, but may reduce time/memory needed for simulation
924 // preorder checking.
925 determinise(l1);
927
928 determinise(l2);
930
931 // Trace preorder now corresponds to simulation preorder
932 return destructive_compare(l1, l2, lts_pre_sim, generate_counter_example, counter_example_file, structured_output, strategy);
933 }
935 {
936 // Eliminate silent steps of first LTS
937 detail::bisimulation_reduce_dnj(l1,true,false);
939
940 // Eliminate silent steps of second LTS
941 detail::bisimulation_reduce_dnj(l2,true,false);
943
944 // Weak trace preorder now corresponds to strong trace preorder
945 return destructive_compare(l1, l2, lts_pre_trace, generate_counter_example, counter_example_file, structured_output, strategy);
946 }
948 {
949 if (generate_counter_example)
950 {
951 detail::counter_example_constructor cec("counter_example_trace_preorder", counter_example_file, structured_output);
952 return destructive_refinement_checker(l1, l2, refinement_type::trace, false, strategy, preprocess, cec);
953 }
954 return destructive_refinement_checker(l1, l2, refinement_type::trace, false, strategy, preprocess);
955 }
957 {
958 if (generate_counter_example)
959 {
960 detail::counter_example_constructor cec("counter_example_weak_trace_preorder", counter_example_file, structured_output);
961 return destructive_refinement_checker(l1, l2, refinement_type::trace, true, strategy, preprocess, cec);
962 }
963 return destructive_refinement_checker(l1, l2, refinement_type::trace, true, strategy, preprocess);
964 }
966 {
967 if (generate_counter_example)
968 {
969 detail::counter_example_constructor cec("counter_example_failures_refinement", counter_example_file, structured_output);
970 return destructive_refinement_checker(l1, l2, refinement_type::failures, false, strategy, preprocess, cec);
971 }
972 return destructive_refinement_checker(l1, l2, refinement_type::failures, false, strategy, preprocess);
973 }
975 {
976 if (generate_counter_example)
977 {
978 detail::counter_example_constructor cec("counter_example_weak_failures_refinement", counter_example_file, structured_output);
979 return destructive_refinement_checker(l1, l2, refinement_type::failures, true, strategy, preprocess, cec);
980 }
981 return destructive_refinement_checker(l1, l2, refinement_type::failures, true, strategy, preprocess);
982 }
984 {
985 if (generate_counter_example)
986 {
987 detail::counter_example_constructor cec("counter_example_failures_divergence_refinement", counter_example_file, structured_output);
988 return destructive_refinement_checker(l1, l2, refinement_type::failures_divergence, true, strategy, preprocess, cec);
989 }
990 return destructive_refinement_checker(l1, l2, refinement_type::failures_divergence, true, strategy, preprocess);
991 }
992 default:
993 mCRL2log(log::error) << "Comparison for this preorder is not available\n";
994 return false;
995 }
996}
997
998
999template <class LTS_TYPE>
1000bool is_deterministic(const LTS_TYPE& l)
1001{
1002 if (l.num_transitions() == 0)
1003 {
1004 return true;
1005 }
1006
1007 std::vector<transition> temporary_copy_of_transitions = l.get_transitions();
1008 sort_transitions(temporary_copy_of_transitions, l.hidden_label_set(), src_lbl_tgt);
1009
1010 // Traverse the ordered transitions, and search for two consecutive pairs <s,l,t> and <s,l,t'> with t!=t'.
1011 // Such a pair exists iff l is not deterministic.
1012 transition& previous_t=temporary_copy_of_transitions[0];
1013 bool previous_t_is_valid=false;
1014 for(const transition& t: temporary_copy_of_transitions)
1015 {
1016 if (previous_t_is_valid)
1017 {
1018 if (previous_t.from()==t.from() &&
1019 previous_t.label()==t.label() &&
1020 previous_t.to()!=t.to())
1021 {
1022 return false;
1023 }
1024 }
1025 previous_t=t;
1026 previous_t_is_valid=true;
1027 }
1028 return true;
1029}
1030
1031
1032namespace detail
1033{
1034
1035template <class LTS_TYPE>
1037 tree_set_store& tss,
1038 std::size_t d,
1039 std::vector<transition>& d_trans,
1040 LTS_TYPE& aut)
1041{
1042 if (!tss.is_set_empty(d))
1043 {
1044 if (tss.is_set_empty(tss.get_set_child_right(d)))
1045 {
1046 // for (outgoing_transitions_per_state_t:: const_iterator
1047 // j=begin.lower_bound(tss.get_set_child_left(d)); j!=begin.upper_bound(tss.get_set_child_left(d)); ++j)
1048 const state_type from=tss.get_set_child_left(d);
1049 // for(const outgoing_pair_t& p: begin[from])
1050 for (detail::state_type i=begin.lowerbound(from); i<begin.upperbound(from); ++i)
1051 {
1052 const outgoing_pair_t& p=begin.get_transitions()[i];
1053 d_trans.push_back(transition(from, aut.apply_hidden_label_map(label(p)), to(p)));
1054 }
1055 }
1056 else
1057 {
1058 get_trans(begin,tss,tss.get_set_child_left(d),d_trans,aut);
1059 get_trans(begin,tss,tss.get_set_child_right(d),d_trans,aut);
1060 }
1061 }
1062}
1063} // namespace detail
1064
1065
1066template <class LTS_TYPE>
1067void determinise(LTS_TYPE& l)
1068{
1069 tree_set_store tss;
1070
1071 std::vector<transition> d_transs;
1072 std::vector<std::ptrdiff_t> d_states;
1073
1074 // create the initial state of the DLTS
1075 d_states.push_back(l.initial_state());
1076 std::ptrdiff_t d_id = tss.set_set_tag(tss.create_set(d_states));
1077 d_states.clear();
1078
1079 const outgoing_transitions_per_state_t begin(l.get_transitions(),l.num_states(),true);
1080
1081 l.clear_transitions();
1082 l.clear_state_labels();
1083 std::size_t d_ntransitions = 0;
1084 std::vector < transition > d_transitions;
1085
1086 std::size_t s;
1087 std::size_t i,to,lbl,n_t;
1088
1089 while (d_id < tss.get_next_tag())
1090 {
1091 // collect the outgoing transitions of every state of DLTS state d_id in
1092 // the vector d_transs
1093 detail::get_trans(begin,tss,tss.get_set(d_id),d_transs,l);
1094
1095 // sort d_transs by label and (if labels are equal) by destination
1096 const detail::compare_transitions_lts compare(l.hidden_label_set());
1097 sort(d_transs.begin(),d_transs.end(),compare);
1098
1099 n_t = d_transs.size();
1100 i = 0;
1101 for (lbl = 0; lbl < l.num_action_labels(); ++lbl)
1102 {
1103 // compute the destination of the transition with label lbl
1104 while (i < n_t && l.apply_hidden_label_map(d_transs[i].label()) < lbl)
1105 {
1106 ++i;
1107 }
1108 while (i < n_t && l.apply_hidden_label_map(d_transs[i].label()) == lbl)
1109 {
1110 to = d_transs[i].to();
1111 d_states.push_back(to);
1112 while (i < n_t && l.apply_hidden_label_map(d_transs[i].label()) == lbl &&
1113 d_transs[i].to() == to)
1114 {
1115 ++i;
1116 }
1117 }
1118 s = tss.create_set(d_states);
1119
1120 // generate the transitions to each of the next states
1121 if (!tss.is_set_empty(s))
1122 {
1123 d_transitions.push_back(transition(d_id,lbl,tss.set_set_tag(s)));
1124
1125 if (d_ntransitions%10000 == 0)
1126 {
1128 "generated " << tss.get_next_tag() << " states and " << d_ntransitions
1129 << " transitions; explored " << d_id << " states" << std::endl;
1130 }
1131 }
1132 d_states.clear();
1133 }
1134 d_transs.clear();
1135 ++d_id;
1136 }
1137
1138
1139 l.set_num_states(d_id,false); // remove the state values, and reset the number of states.
1140 l.set_initial_state(0);
1141
1142 for (const transition& t: d_transitions)
1143 {
1144 l.add_transition(t);
1145 }
1146 assert(is_deterministic(l));
1147}
1148
1149} // namespace lts
1150} // namespace mcrl2
1151
1152#endif // MCRL2_LTS_LTS_ALGORITHM_H
1153
1154
1155
A class that can be used to store counterexample trees and.
const std::vector< CONTENT > & get_transitions() const
std::size_t get_eq_class(std::size_t s) const
Definition liblts_sim.h:824
bool in_same_class(std::size_t s, std::size_t t) const
Definition liblts_sim.h:836
std::size_t num_eq_classes() const
Definition liblts_sim.h:818
std::vector< mcrl2::lts::transition > get_transitions() const
Definition liblts_sim.h:768
bool in_preorder(std::size_t s, std::size_t t) const
Definition liblts_sim.h:830
labels_size_type num_action_labels() const
Gets the number of action labels of this LTS.
Definition lts.h:318
void add_transition(const transition &t)
Add a transition to the lts.
Definition lts.h:544
states_size_type num_states() const
Gets the number of states of this LTS.
Definition lts.h:245
ACTION_LABEL_T action_label(const labels_size_type action) const
Gets the label of an action.
Definition lts.h:470
bool has_state_info() const
Checks whether this LTS has state values associated with its states.
Definition lts.h:636
STATE_LABEL_T state_label(const states_size_type state) const
Gets the label of a state.
Definition lts.h:450
states_size_type add_state(const STATE_LABEL_T &label=STATE_LABEL_T())
Adds a state to this LTS.
Definition lts.h:347
const std::vector< transition > & get_transitions() const
Gets a const reference to the vector of transitions of the current lts.
Definition lts.h:526
labels_size_type add_action(const ACTION_LABEL_T &label)
Adds an action with a label to this LTS.
Definition lts.h:361
void set_initial_probabilistic_state(const PROBABILISTIC_STATE_T &state)
Sets the probabilistic initial state number of this LTS.
const PROBABILISTIC_STATE_T & initial_probabilistic_state() const
Gets the initial state number of this LTS.
void swap(probabilistic_lts &other)
Swap this lts with the supplied supplied LTS.
labels_size_type num_probabilistic_states() const
Gets the number of probabilistic states of this LTS.
void clear()
Clear the transitions system.
states_size_type add_probabilistic_state(const PROBABILISTIC_STATE_T &s)
Adds a probabilistic state to this LTS.
const PROBABILISTIC_STATE_T & probabilistic_state(const states_size_type index) const
Gets the probabilistic label of an index.
Signature based reductions for labelled transition systems.
Definition sigref.h:350
void run()
Perform the reduction, modulo the equivalence for which the signature has been passed in as template ...
Definition sigref.h:458
A class containing triples, source label and target representing transitions.
Definition transition.h:47
size_type from() const
The source of the transition.
Definition transition.h:81
size_type label() const
The label of the transition.
Definition transition.h:87
size_type to() const
The target of the transition.
Definition transition.h:94
bool is_set_empty(ptrdiff_t set)
Definition tree_set.cpp:205
ptrdiff_t get_set_child_left(ptrdiff_t set)
Definition tree_set.cpp:185
ptrdiff_t create_set(std::vector< ptrdiff_t > &elems)
Definition tree_set.cpp:139
ptrdiff_t get_set(ptrdiff_t tag)
Definition tree_set.cpp:180
ptrdiff_t get_set_child_right(ptrdiff_t set)
Definition tree_set.cpp:190
ptrdiff_t set_set_tag(ptrdiff_t set)
Definition tree_set.cpp:210
Standard exception class for reporting runtime errors.
Definition exception.h:27
void bisimulation_reduce_gjkw(LTS_TYPE &l, bool branching=false, bool preserve_divergence=false)
Reduce transition system l with respect to strong or (divergence preserving) branching bisimulation.
bool destructive_bisimulation_compare_dnj(LTS_TYPE &l1, LTS_TYPE &l2, bool const branching=false, bool const preserve_divergence=false, bool const generate_counter_examples=false, const std::string &="", bool=false)
Checks whether the two initial states of two LTSs are strong or (divergence-preserving) branching bis...
bool destructive_bisimulation_compare_gjkw(LTS_TYPE &l1, LTS_TYPE &l2, bool branching=false, bool preserve_divergence=false, bool generate_counter_examples=false)
Checks whether the two initial states of two LTSs are strong or branching bisimilar.
void bisimulation_reduce_dnj(LTS_TYPE &l, bool const branching=false, bool const preserve_divergence=false)
Reduce transition system l with respect to strong or (divergence-preserving) branching bisimulation.
O(m log n)-time branching bisimulation algorithm similar to liblts_bisim_dnj.h which does not use bun...
O(m log n)-time stuttering equivalence algorithm.
Author(s): # Carlos Gregorio-Rodriguez, Luis LLana, Rafael Martinez-Torres.
This file defines an algorithm for weak bisimulation, by calculating the transitive tau closure and a...
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:391
Type recording the equivalence reductions supported by the LTS library.
Supperted preorders for LTSes.
@ warning
Definition logger.h:34
void merge(LTS_TYPE &l1, const LTS_TYPE &l2)
bool destructive_branching_bisimulation_compare_minimal_depth(LTS_TYPE &l1, LTS_TYPE &l2, const std::string &counter_example_file)
bool coupled_simulation_compare(LTS_TYPE &l1, LTS_TYPE &l2)
void weak_bisimulation_reduce(LTS_TYPE &l, const bool preserve_divergences=false)
Reduce LTS l with respect to (divergence-preserving) weak bisimulation.
bool destructive_bisimulation_compare_minimal_depth(LTS_TYPE &l1, LTS_TYPE &l2, const std::string &counter_example_file)
std::size_t state_type
type used to store state (numbers and) counts
void bisimulation_reduce(LTS_TYPE &l, const bool branching=false, const bool preserve_divergences=false)
Reduce transition system l with respect to strong or (divergence preserving) branching bisimulation.
bool destructive_bisimulation_compare(LTS_TYPE &l1, LTS_TYPE &l2, const bool branching=false, const bool preserve_divergences=false, const bool generate_counter_examples=false, const std::string &counter_example_file="", const bool structured_output=false)
Checks whether the two initial states of two lts's are strong or branching bisimilar.
bool destructive_bisimulation_compare_gj(LTS_TYPE &l1, LTS_TYPE &l2, const bool branching=false, const bool preserve_divergence=false, const bool generate_counter_examples=false, const std::string &="", bool=false)
Checks whether the two initial states of two LTSs are strong or (divergence-preserving) branching bis...
bool destructive_weak_bisimulation_compare(LTS_TYPE &l1, LTS_TYPE &l2, const bool preserve_divergences=false)
Checks whether the initial states of two LTSs are weakly bisimilar.
void bisimulation_reduce_gj(LTS_TYPE &l, const bool branching=false, const bool preserve_divergence=false)
nonmember functions serving as interface with the rest of mCRL2
void get_trans(const outgoing_transitions_per_state_t &begin, tree_set_store &tss, std::size_t d, std::vector< transition > &d_trans, LTS_TYPE &aut)
void tau_star_reduce(lts< STATE_LABEL_T, ACTION_LABEL_T, LTS_BASE_CLASS > &l)
lts_equivalence
LTS equivalence relations.
@ lts_eq_branching_bisim_sigref
@ lts_eq_divergence_preserving_weak_bisim
@ lts_eq_branching_bisim_gjkw
@ lts_eq_branching_bisim_gv
@ lts_eq_divergence_preserving_branching_bisim_sigref
@ lts_eq_divergence_preserving_branching_bisim
@ lts_eq_branching_bisim_gj
@ lts_eq_divergence_preserving_branching_bisim_gjkw
@ lts_eq_divergence_preserving_branching_bisim_gv
@ lts_eq_divergence_preserving_branching_bisim_gj
bool is_deterministic(const LTS_TYPE &l)
Checks whether this LTS is deterministic.
lts_preorder
LTS preorder relations.
@ lts_pre_failures_refinement
@ lts_pre_failures_divergence_refinement
@ lts_pre_weak_trace_anti_chain
@ lts_pre_weak_failures_refinement
@ lts_pre_trace_anti_chain
std::size_t to(const outgoing_pair_t &p)
Target state of a label state pair.
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.
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::pair< std::size_t, bool > reduce(LTS_TYPE &lts, const bool weak_reduction, const bool preserve_divergence, std::size_t l2_init)
Preprocess the LTS for destructive refinement checking.
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 destructive_refinement_checker(LTS_TYPE &l1, LTS_TYPE &l2, const refinement_type refinement, const bool weak_reduction, const lps::exploration_strategy strategy, const bool preprocess=true, COUNTER_EXAMPLE_CONSTRUCTOR generate_counter_example=detail::dummy_counter_example_constructor())
This function checks using algorithms in the paper mentioned above whether transition system l1 is in...
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.
std::pair< transition::size_type, transition::size_type > outgoing_pair_t
Type for exploring transitions per state.
bool compare(const LTS_TYPE &l1, const LTS_TYPE &l2, const lts_equivalence eq, const bool generate_counter_examples=false, const std::string &counter_example_file="", const bool structured_output=false)
Checks whether this LTS is equivalent to another LTS.
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
Definition indexed_set.h:72
Implementation of LTS reductions using the signature refinement approach of S. Blom and S....