mCRL2
Loading...
Searching...
No Matches
liblts_pbisim_grv.h
Go to the documentation of this file.
1// Author(s): Hector Joao Rivera Verduzco, 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/// \file lts/detail/liblts_pbisim.h
10
11#ifndef MCRL2_LTS_DETAIL_LIBLTS_PBISIM_GRV_H
12#define MCRL2_LTS_DETAIL_LIBLTS_PBISIM_GRV_H
13
14#include "mcrl2/utilities/execution_timer.h"
15#include "mcrl2/lts/detail/embedded_list.h"
16#include "mcrl2/lts/detail/liblts_plts_merge.h"
17
18namespace mcrl2::lts::detail
19{
20
21template < class LTS_TYPE>
22class prob_bisim_partitioner_grv // Called after Groote, Rivera Verduzco and de Vink
23{
24 public:
25 /** \brief Creates a probabilistic bisimulation partitioner for an PLTS.
26 * \details This bisimulation partitioner applies the algorithm described in "J.F. Groote, H.J. Rivera, E.P. de Vink,
27 * An O(mlogn) algorithm for probabilistic bisimulation".
28 */
30 : aut(l)
31 {
32 mCRL2log(log::verbose) << "Probabilistic bisimulation partitioner created for " <<
33 l.num_states() << " states and " <<
34 l.num_transitions() << " transitions\n";
35 timer.start("bisimulation_reduce (grv)");
38 timer.finish("bisimulation_reduce (grv)");
39 }
40
41 /** \brief Gives the number of bisimulation equivalence classes of the LTS.
42 * \return The number of bisimulation equivalence classes of the LTS.
43 */
45 {
46 return action_constellations.size();
47 }
48
49 /** \brief Gives the bisimulation equivalence class number of a state.
50 * \param[in] A state number.
51 * \return The number of the bisimulation equivalence class to which the state belongs to. */
53 {
54 assert(s < action_states.size());
55 return action_states[s].parent_block;
56 }
57
58 /** \brief Gives the bisimulation equivalence probabilistic class number of a probabilistic state.
59 * \param[in] A probabilistic state number.
60 * \return The number of the probabilistic class to which the state belongs to. */
62 {
63 assert(s<probabilistic_states.size());
64 return probabilistic_states[s].parent_block; // The block index is the state number of the block.
65 }
66
67 /** \brief Replaces the transition relation of the current lts by the transitions
68 * of the bisimulation reduced transition system.
69 * \pre The bisimulation equivalence classes have been computed. */
71 {
72 std::set<transition> resulting_transitions;
73
74 const std::vector<transition>& trans = aut.get_transitions();
75 for (const transition& t : trans)
76 {
77 resulting_transitions.insert(
78 transition(
79 get_eq_class(t.from()),
80 t.label(),
81 get_eq_probabilistic_class(t.to())));
82 }
83 // Remove the old transitions
84 aut.clear_transitions();
85
86 // Copy the transitions from the set into the transition system.
87 for (const transition& t : resulting_transitions)
88 {
89 aut.add_transition(t);
90 }
91 }
92
93 /** \brief Replaces the probabilistic states of the current lts by the probabilistic
94 * states of the bisimulation reduced transition system.
95 * \pre The bisimulation classes have been computed. */
97 {
98 std::vector<typename LTS_TYPE::probabilistic_state_t> new_probabilistic_states;
99
100 // get the equivalent probabilistic state of each probabilistic block and add it to aut
101 for (probabilistic_block_type& prob_block : probabilistic_blocks)
102 {
103 if (prob_block.states.size()>0)
104 {
105 typename LTS_TYPE::probabilistic_state_t equivalent_ps = calculate_equivalent_probabilistic_state(prob_block);
106 new_probabilistic_states.push_back(equivalent_ps);
107 }
108 }
109
110 /* Remove old probabilistic states */
111 aut.clear_probabilistic_states();
112
113 // Add new prob states to aut
114 for (const typename LTS_TYPE::probabilistic_state_t& new_ps : new_probabilistic_states)
115 {
116 aut.add_probabilistic_state(new_ps);
117 }
118
119 typename LTS_TYPE::probabilistic_state_t old_initial_prob_state = aut.initial_probabilistic_state();
120 typename LTS_TYPE::probabilistic_state_t new_initial_prob_state = calculate_new_probabilistic_state(old_initial_prob_state);
121 aut.set_initial_probabilistic_state(new_initial_prob_state);
122 }
123
124 /** \brief Returns whether two states are in the same probabilistic bisimulation equivalence class.
125 * \param[in] s A state number.
126 * \param[in] t A state number.
127 * \retval true if \e s and \e t are in the same bisimulation equivalence class;
128 * \retval false otherwise. */
129 bool in_same_probabilistic_class_grv(const std::size_t s, const std::size_t t)
130 {
131 return get_eq_probabilistic_class(s) == get_eq_probabilistic_class(t);
132 }
133
134
135 protected:
136
137 // --------------- BEGIN DECLARATION OF DATA TYPES ---------------------------------------------------------------
138
144 using probability_label_type = typename LTS_TYPE::probabilistic_state_t::probability_t;
145 using probability_fraction_type = typename LTS_TYPE::probabilistic_state_t::probability_t;
146
147 struct action_transition_type : public embedded_list_node <action_transition_type>
148 {
153 };
154
156 {
158 probability_label_type label;
160 };
161
162 struct action_state_type : public embedded_list_node < action_state_type >
163 {
166
167 // Temporary
168 bool mark_state = false;
171 };
172
173 struct probabilistic_state_type : public embedded_list_node < probabilistic_state_type >
174 {
177
178 // Temporary.
179 bool mark_state = false;
180 probability_label_type cumulative_probability;
181 };
182
183 // Prototype.
184 struct action_mark_type;
185
186 struct action_block_type : public embedded_list_node <action_block_type>
187 {
189 embedded_list<action_state_type> states;
191 action_mark_type* marking; // This value is nullptr if the block is not marked.
192
194 };
195
197 {
199 embedded_list<action_state_type> left;
200 embedded_list<action_state_type> middle;
201 embedded_list<action_state_type> right;
203
205 : action_block(&B),
206 large_block_ptr(nullptr)
207 {}
208 };
209
210 // Prototype
212
213 struct probabilistic_block_type : public embedded_list_node <probabilistic_block_type>
214 {
218
219 // a probabilistic block has incoming action transitions ordered by label
221
223 };
224
226 {
232
234 };
235
237 {
238 embedded_list<action_block_type> blocks;
239 std::size_t number_of_states = 0UL; // number of states in this constellation.
240 };
241
243 {
245 std::size_t number_of_states = 0UL; // number of states in this constellation.
246 };
247
248 // --------------- END DECLARATION OF DATA TYPES ---------------------------------------------------------------
249
250 // The class below is used to group transitions on action labels in linear space and time.
251 // This makes use of the fact that action labels have a limited range, smaller than the number of transitions.
253 {
254 protected:
255 // This is a vector that contains transitions with the same label at each entry.
257 // This stack indicates which positions in the vector above are occupied for efficient retrieval.
259
261 {
262 assert(t.label<m_transitions_per_label.size());
263 if (m_transitions_per_label[t.label].size()==0)
264 {
265 m_occupancy_indicator.push(t.label);
266 }
267 m_transitions_per_label[t.label].push_back(t);
268 }
269
270 public:
271 /* set the size of the vector m_transitions_per_label */
272 void initialize(const std::size_t number_of_labels)
273 {
274 m_transitions_per_label=std::vector< embedded_list<action_transition_type> >(number_of_labels);
275 }
276
278 {
279 return m_transitions_per_label;
280 }
281
282 /* This function adds the transitions per label in order to the initial probabilistic block
283 and resets the occupancy array back to empty */
285 {
286 while (!m_occupancy_indicator.empty())
287 {
288 const label_type action=m_occupancy_indicator.top();
289 m_occupancy_indicator.pop();
290
291 // The next operation resets m_transitions_per_label[action] to empty.
292 assert(action<m_transitions_per_label.size());
293 block.incoming_action_transitions.append(m_transitions_per_label[action]);
294 }
295 }
296
297 void move_incoming_transitions(probabilistic_state_type s, embedded_list<action_transition_type>& transition_list_with_t)
298 {
299 for(action_transition_type* t_ptr: s.incoming_transitions)
300 {
301 transition_list_with_t.erase(*t_ptr);
303 }
304 }
305
306 void add_transitions(std::vector<action_transition_type>& transitions)
307 {
308 for(action_transition_type& t: transitions)
309 {
310 add_single_transition(t);
311 }
312 }
313 };
314
315 // The basic stores for all elementary data structures. The deque's are used intentionally
316 // as there are pointers to their content.
325
326 // The storage to store the state_to_constellation counts for each transition. Transition refer with
327 // a pointer to the elements in this deque.
329
330 // The lists below contains all the non trivial constellations.
333
334 // temporary data structures. declared here to prevent redeclaring these too often.
338
339 // The following is a temporary data structure used to group incoming transitions on labels, which is declared
340 // globally to avoid declaring it repeatedly which is time consuming.
342
343
344 LTS_TYPE& aut;
345
347 {
348 // Check whether the constellation count in action transitions is ok.
349 for(const action_transition_type& t: action_transitions)
350 {
351 std::size_t constellation=probabilistic_blocks[probabilistic_states[t.to].parent_block].parent_constellation;
352 std::size_t count_state_to_constellation=0;
353
354 for(const action_transition_type& t1: action_transitions)
355 {
356 if (t.from==t1.from &&
357 t.label==t1.label &&
358 constellation==probabilistic_blocks[probabilistic_states[t1.to].parent_block].parent_constellation)
359 {
360 count_state_to_constellation++;
361 }
362 }
363 if (count_state_to_constellation!=*t.state_to_constellation_count_ptr)
364 {
365 mCRL2log(log::error) << "Transition " << t.from << "--" << t.label << "->" << t.to << " has inconsistent constellation_count: " <<
366 *t.state_to_constellation_count_ptr << ". Should be " << count_state_to_constellation << ".\n";
367 return false;
368
369 }
370 }
371
372 // Check whether the number of states in an action constellation are correct.
373 for(const action_constellation_type& c: action_constellations)
374 {
375 std::size_t counted_states=0;
376 for(const action_block_type& b: c.blocks)
377 {
378 counted_states=counted_states+b.states.size();
379 }
380 assert(counted_states==c.number_of_states); // Number of states in this action constellation does not match the number of states in its blocks.
381 }
382
383 // Check whether the number of states in a probabilistic constellation are correct.
384 for(const probabilistic_constellation_type& c: probabilistic_constellations)
385 {
386 std::size_t counted_states=0;
387 for(const probabilistic_block_type& b: c.blocks)
388 {
389 counted_states=counted_states+b.states.size();
390 }
391 assert(counted_states==c.number_of_states); // Number of states in this probabilistic constellation does not match the number of states in its blocks.
392 }
393
394 for(const action_block_type& b: action_blocks)
395 {
396 assert(b.states.size()>0); // Action block contains no states.
397
398 assert(b.marking==nullptr); // Action block's marking must be a null ptr.
399 }
400
401 for(const probabilistic_block_type& b: probabilistic_blocks)
402 {
403 assert(b.marking==nullptr); // Probabilistic block's marking must be a null ptr.
404 }
405
406 return true;
407 }
408
409 void print_structure(const std::string& info)
410 {
411 std::cerr << info << " ---------------------------------------------------------------------- \n";
412 std::cerr << "Number of action blocks " << action_blocks.size() << "\n";
413 std::cerr << "Number of probabilistic blocks " << probabilistic_blocks.size() << "\n";
414 std::cerr << "Number of action constellations " << action_constellations.size() << "\n";
415 std::cerr << "Number of probabilistic constellations " << probabilistic_constellations.size() << "\n";
416 for(const action_block_type b: action_blocks)
417 {
418 std::cerr << "ACTION BLOCK INFO ------------------------\n";
419 std::cerr << "PARENT CONSTELLATION " << b.parent_constellation << "\n";
420 std::cerr << "NR STATES " << b.states.size() << "\n";
421 for(const probabilistic_transition_type t: b.incoming_probabilistic_transitions)
422 {
423 std::cerr << "INCOMING TRANS " << t.from << " --" << t.label << "-> " << t.to << "\n";
424 }
425 }
426
427 for(const probabilistic_block_type b: probabilistic_blocks)
428 {
429 std::cerr << "probabilistic BLOCK INFO ------------------------\n";
430 std::cerr << "PARENT CONSTELLATION " << b.parent_constellation << "\n";
431 std::cerr << "NR STATES " << b.states.size() << "\n";
432 for(const action_transition_type t: b.incoming_action_transitions)
433 {
434 std::cerr << "INCOMING TRANS " << t.from << " --" << t.label << "-> " << t.to << "\n";
435 }
436 }
437
438 }
439
440 /** Creates the initial partition.
441 * \details The blocks are initially partitioned based on the actions that can perform.
442 */
444 {
445 transitions_per_label.initialize(aut.num_action_labels());
446
447 // Preprocessing initialization. First we have to initialise the action/probabilistic states and
448 // transitions.
450
451 // Add action transitions to its respective list grouped by label.
452 transitions_per_label.add_transitions(action_transitions);
453
454 // We start with all the action states in one block and then we refine this block
455 // according to the outgoing transitions.
456 action_block_type initial_action_block;
457
458 // Link all the action states together to the initial block
459 for (action_state_type& s: action_states)
460 {
461 s.parent_block = 0; // Initial block has number 0.
462 initial_action_block.states.push_back(s);
463 }
464 assert(aut.num_states()==initial_action_block.states.size());
465
466 // Add the linked states to the list of states in the initial block
467 action_blocks.push_back(initial_action_block);
468
469 // Refine the initial action block based on the outgoing transitions.
470 // This corresponds to line 5 of Algorithm 2 in [GRV].
471 refine_initial_action_block(transitions_per_label.transitions());
472
473 // Initialise the probabilistic block. Initally, there is only one block of probabilistic states.
474 probabilistic_blocks.emplace_back();
475
476 probabilistic_block_type& initial_probabilistic_block=probabilistic_blocks.back();
477 initial_probabilistic_block.parent_constellation = 0;
478
479 // Link all the probabilistic states together to the initial block
480 for (probabilistic_state_type& s : probabilistic_states)
481 {
482 s.parent_block = 0; // The initial block has number zero.
483 initial_probabilistic_block.states.push_back(s);
484 }
485 assert(aut.num_probabilistic_states()==initial_probabilistic_block.states.size());
486
487 // Initialise the probabilistic and action constellations; they will contain
488 // all the blocks.
489 probabilistic_constellation_type initial_probabilistic_const;
490 initial_probabilistic_const.number_of_states = aut.num_probabilistic_states();
491
492 // Initially there is only one block in the probabilistic constellation.
493 // initial_probabilistic_const.blocks.init(&probabilistic_blocks.front(), &probabilistic_blocks.front(), 1);
494 initial_probabilistic_const.blocks.push_back(probabilistic_blocks.front());
495 probabilistic_constellations.push_back(initial_probabilistic_const);
496
497 // Initialise the initial action constellation.
498 action_constellations.emplace_back();
499 action_constellation_type& initial_action_const=action_constellations.back();
500
501 initial_action_const.number_of_states = aut.num_states();
502
503 // Construct the list of action blocks by linking them together.
504 for(action_block_type& b : action_blocks)
505 {
506 b.parent_constellation = 0; // The initial constellation has number 0;
507 initial_action_const.blocks.push_back(b);
508 }
509
510//-----------------------------------------------------------------------------
511 // state_to_const_count_temp is used to keep track of the block to constellation count per label of each state.
512 std::vector<std::size_t*> new_count_ptr(aut.num_states(),nullptr);
513
514 for (const embedded_list<action_transition_type>& at_list_per_label : transitions_per_label.transitions())
515 {
516 // Create a new position in state_to_constellation_count if no such count exists for the parent block of the transition.
517 // Assign this position to t.state_to_constellation_count_ptr and increment its count.
518 for(action_transition_type& t: at_list_per_label)
519 {
520 assert(t.from<new_count_ptr.size());
521 if (new_count_ptr[t.from]==nullptr)
522 {
523 state_to_constellation_count.push_back(0);
524 new_count_ptr[t.from] = &state_to_constellation_count.back();
525 }
526 t.state_to_constellation_count_ptr = new_count_ptr[t.from];
527 (*new_count_ptr[t.from])++;
528 }
529
530 // Reset all the variables used to prepare to next iteration.
531 for(const action_transition_type& t: at_list_per_label)
532 {
533 new_count_ptr[t.from] = nullptr;
534 }
535 }
536
537//-----------------------------------------------------------------------------
538
539 // Since the transitions are already grouped by label, add them to the
540 // initial probabilistic block as incoming transitions.
541 transitions_per_label.add_grouped_transitions_to_block(initial_probabilistic_block);
542
543 // Initialise the incoming probabilistic transitions for all action blocks. To that end,
544 // iterate over all probabilistic transitions and add it to its respective destination block.
545 for(probabilistic_transition_type& t : probabilistic_transitions)
546 {
547 action_state_type& s = action_states[t.to];
548 action_block_type& block = action_blocks[s.parent_block];
549 block.incoming_probabilistic_transitions.push_back(t);
550 }
551
552 if (initial_action_const.blocks.size()>1)
553 {
554 non_trivial_action_constellations.push(&initial_action_const);
555 }
556
558 }
559
560 /* This function performs the preprocessing stage to prepare to apply the algorithm.
561 It also initialises the action and probabilistic states and transitions. */
563 {
564 // Allocate space for states and transitions
565
566 action_states.resize(aut.num_states());
567 probabilistic_states.resize(aut.num_probabilistic_states());
568 action_transitions.resize(aut.num_transitions());
569
570 // Initialise the action transitions
571 transition_key_type t_key = 0;
572 for (const transition& t : aut.get_transitions())
573 {
574 action_transition_type& at = action_transitions[t_key];
575 at.from = t.from();
576 at.label = t.label();
577 at.to = t.to();
578 at.state_to_constellation_count_ptr = nullptr;
579
580 // save incoming transition in state
581 probabilistic_states[at.to].incoming_transitions.push_back(&at);
582
583 t_key++;
584 }
585
586 // Initialise the probabilistic transitions. To this end, we have to iterate over
587 // all probabilistic states.
588 for (std::size_t i = 0; i < aut.num_probabilistic_states(); i++)
589 {
590 const typename LTS_TYPE::probabilistic_state_t& ps = aut.probabilistic_state(i);
591 probabilistic_transition_type pt;
592 if (ps.size()>1) // The probabilistic state is stored as a vector.
593 {
594 for (const typename LTS_TYPE::probabilistic_state_t::state_probability_pair& sp_pair : ps)
595 {
596 pt.from = i;
597 pt.label = sp_pair.probability();
598 pt.to = sp_pair.state();
599 probabilistic_transitions.push_back(pt);
600
601 // save incoming transition in state
602 action_states[pt.to].incoming_transitions.push_back(&probabilistic_transitions.back());
603 }
604 }
605 else // The probabilistic state is stored as a single state number with implicit probability 1.
606 {
607 pt.from = i;
608 pt.label = LTS_TYPE::probabilistic_state_t::probability_t::one();
609 pt.to = ps.get();
610 probabilistic_transitions.push_back(pt);
611 // save incoming transition in state
612 action_states[pt.to].incoming_transitions.push_back(&probabilistic_transitions.back());
613 }
614 }
615
616 // End of preprocessing.
617 }
618
619 /* Refine the initial block according to its outgoing transitions.
620 */
621 void refine_initial_action_block(const std::vector< embedded_list<action_transition_type> >& transitions_per_label)
622 {
623 // Iterate over all transitions ordered by label, and refine the block.
624 for (const embedded_list<action_transition_type>& t_list : transitions_per_label)
625 {
626 marked_action_blocks.clear();
627 // The line below garbage collects marked_action_blocks to avoid covering too much memory continuously;
628 static std::size_t count=0; if (count++ == 1000) { marked_action_blocks.shrink_to_fit(); count=0; }
629
630 for(const action_transition_type& t: t_list)
631 {
632 action_state_type& s = action_states[t.from];
633 assert(s.parent_block<action_blocks.size());
634 action_block_type& parent_block = action_blocks[s.parent_block];
635
636 // Move state s to marked states if not already added.
637 if (false == s.mark_state)
638 {
639 // Add parent block to the list of marked blocks if not yet added
640 if (parent_block.marking==nullptr)
641 {
642 marked_action_blocks.emplace_back(parent_block);
643 parent_block.marking=&marked_action_blocks.back();
644 }
645
646 move_list_element_back<action_state_type>(s, parent_block.states, parent_block.marking->left);
647 s.mark_state = true;
648 }
649 }
650
651 // Split the marked blocks.
652 for (action_mark_type& block_marking: marked_action_blocks)
653 {
654 if (0 == block_marking.action_block->states.size())
655 {
656 // If all states in the block are marked, then return all marked states to the block.
657 block_marking.action_block->states = block_marking.left;
658 }
659 else
660 {
661 // Split the block if not all states are marked.
662 action_blocks.emplace_back();
663 action_block_type& new_block=action_blocks.back();
664 new_block.states = block_marking.left;
665
666 // Init parent block of each state in new block.
667 for(action_state_type& s: new_block.states)
668 {
669 s.parent_block = action_blocks.size()-1;
670 }
671
672 }
673
674 // clean mark list
675 block_marking.left.clear();
676 block_marking.action_block->marking=nullptr;
677
678 }
679
680 // Clean the marked states.
681 for(const action_transition_type& t: t_list)
682 {
683 action_states[t.from].mark_state = false;
684 }
685 }
686
687 }
688
689 /* Move an element of a list to the back of another list.
690 */
691 template <typename LIST_ELEMENT>
692 void move_list_element_back(LIST_ELEMENT& s, embedded_list<LIST_ELEMENT>& source_list, embedded_list<LIST_ELEMENT>& dest_list)
693 {
694 source_list.erase(s);
695 dest_list.push_back(s);
696 }
697
698 /** \brief Move an element of a list to the front of another the list.
699 * \details
700 */
701 template<typename LIST_ELEMENT>
702 void move_list_element_front(LIST_ELEMENT& s, embedded_list<LIST_ELEMENT>& source_list, embedded_list<LIST_ELEMENT>& dest_list)
703 {
704 source_list.erase(s);
705 dest_list.push_front(s);
706 }
707
708 /** \brief Refine partition until it becomes stable.
709 * \details
710 */
712 {
713
714 // Refine until all the constellations are trivial.
715 while (!non_trivial_probabilistic_constellations.empty() || !non_trivial_action_constellations.empty())
716 {
717 assert(check_data_structure());
718
719 // Refine probabilistic blocks if a non-trivial action constellation exists.
720 if (!non_trivial_action_constellations.empty())
721 {
722 action_constellation_type* non_trivial_action_const = non_trivial_action_constellations.top();
723 non_trivial_action_constellations.pop();
724 assert(non_trivial_action_const->blocks.size()>=2);
725
726// print_structure("REFINE I");
727 // Choose splitter block Bc of a non-trivial constellation C, such that |Bc| <= 1/2|C|.
728 // And also split constellation C into BC and C\BC in the set of constellations.
729 action_block_type* Bc_ptr = choose_action_splitter(non_trivial_action_const);
730
731 // Derive the left, right and middle sets from mark function.
732 marked_probabilistic_blocks.clear();
733 // The line below garbage collects marked_action_blocks to avoid covering too much memory continuously;
734 static std::size_t count=0; if (count++ == 1000) { marked_probabilistic_blocks.shrink_to_fit(); count=0; }
735
736 mark_probabilistic(*Bc_ptr, marked_probabilistic_blocks);
737
738 // Split every marked probabilistic block based on left, middle and right.
739 for (probabilistic_mark_type& B : marked_probabilistic_blocks)
740 {
741 // We must know whether the current constellation is already on the stack.
742 bool already_on_non_trivial_constellations_stack = probabilistic_constellations[B.probabilistic_block->parent_constellation].blocks.size()>1;
743
744 // First return the largest of left, middle or right to the states of current processed block.
745 B.probabilistic_block->states = *B.large_block_ptr;
746 B.large_block_ptr->clear();
747
748 // Split left set of the block to another block if left has states and it is not
749 // the largest block.
750 if (B.left.size() > 0)
751 {
752 split_probabilistic_block(*B.probabilistic_block, B.left);
753 }
754
755 // Split right set of the block to another block if right has states and it is not
756 // the largest block.
757 if (B.right.size() > 0)
758 {
759 split_probabilistic_block(*B.probabilistic_block, B.right);
760 }
761
762 // Iterate over all middle sets. Split middle sets of the current block to another block if
763 // the middle set has states and it is not the largest block.
764 for (embedded_list<probabilistic_state_type>& middle : B.middle)
765 {
766 if (middle.size() > 0)
767 {
768 split_probabilistic_block(*B.probabilistic_block, middle);
769 }
770 }
771
772 // Move the parent constellation of the current block to the front of the
773 // constellation list if it became unstable.
774 if (!already_on_non_trivial_constellations_stack && probabilistic_constellations[B.probabilistic_block->parent_constellation].blocks.size()>1)
775 {
776 probabilistic_constellation_type& parent_const = probabilistic_constellations[B.probabilistic_block->parent_constellation];
777 assert(parent_const.blocks.size()>1);
778 non_trivial_probabilistic_constellations.push(&parent_const);
779 }
780
781 // Reset middle vector to prepare for the next mark process
782 B.middle.clear();
783 }
784 }
785
786 // Refine action blocks if a non-trivial probabilistic constellation exists.
787 if (!non_trivial_probabilistic_constellations.empty())
788 {
789
790 probabilistic_constellation_type* non_trivial_probabilistic_const = non_trivial_probabilistic_constellations.top();
791 non_trivial_probabilistic_constellations.pop();
792 assert(non_trivial_probabilistic_const->blocks.size()>=2);
793 // Choose splitter block Bc of a non-trivial constellation C, such that |Bc| <= 1/2|C|.
794 // And also split constellation C into BC and C\BC in the set of constellations.
795 probabilistic_block_type* Bc_ptr = choose_probabilistic_splitter(non_trivial_probabilistic_const);
796
797 // For all incoming labeled "a" transitions of each state in BC call the mark function and split the blocks.
798 for (typename embedded_list<action_transition_type>::iterator i=Bc_ptr->incoming_action_transitions.begin();
799 i!=Bc_ptr->incoming_action_transitions.end() ; )
800 {
801 // Derive the left, right and middle sets from mark function based on the incoming labeled "a" transitions.
802 const label_type a = i->label;
803 marked_action_blocks.clear();
804 mark_action(marked_action_blocks, a, i, Bc_ptr->incoming_action_transitions.end()); // The iterator i is implicitly increased
805 // to the position in the list with the next action.
806
807 // Split every marked probabilistic block based on left, middle and right.
808 for (action_mark_type& B : marked_action_blocks)
809 {
810 // We must know whether the current constellation is already on the stack.
811 bool already_on_non_trivial_constellations_stack = action_constellations[B.action_block->parent_constellation].blocks.size()>1;
812
813 // First return the largest of left, middle or right to the states of current processed block.
814 B.action_block->states = *B.large_block_ptr;
815 B.large_block_ptr->clear();
816
817 // Split left set of the block to another block if left has states and it is not the largest block.
818 if (B.left.size() > 0)
819 {
820 split_action_block(*B.action_block, B.left);
821 }
822
823 // Split right set of the block to another block if right has states and it is not the largest block.
824 if (B.right.size() > 0)
825 {
826 split_action_block(*B.action_block, B.right);
827 }
828
829 // Split middle set of the block to another block if middle has states and it is not
830 // the largest block.
831 if (B.middle.size() > 0)
832 {
833 split_action_block(*B.action_block, B.middle);
834 }
835
836 // Move the parent constellation of the current block to the front of the
837 // constellation list if it became unstable.
838 if (!already_on_non_trivial_constellations_stack && action_constellations[B.action_block->parent_constellation].blocks.size()>1)
839 {
840 action_constellation_type& parent_const = action_constellations[B.action_block->parent_constellation];
841 assert(parent_const.blocks.size()>1);
842 non_trivial_action_constellations.push(&parent_const);
843 }
844
845 }
846 }
847 }
848 }
850 }
851
852 /** \brief Split a probabilistic block.
853 * \details Creates another block containing the states specified in states_of_new_block. It adds the new block
854 * to the same constellation as the current block to split.
855 */
856 void split_probabilistic_block(probabilistic_block_type& block_to_split, embedded_list<probabilistic_state_type>& states_of_new_block)
857 {
858 // First create the new block to be allocated, and initialise its parameters
859 probabilistic_blocks.emplace_back();
860 probabilistic_block_type& new_block=probabilistic_blocks.back();
861
862 new_block.parent_constellation = block_to_split.parent_constellation; // The new block is in the same constellation as B
863 new_block.states = states_of_new_block;
864 states_of_new_block.clear();
865
866 // Add the incoming action transition of the new block. To this end, iterate over all
867 // states in the new block and add the incoming transitions of each state to the
868 // incoming transitions of the new block. Also keep track of the labels of the incoming
869 // transitions.
870 for(probabilistic_state_type& s: new_block.states)
871 {
872 // Update the parent block of the state
873 s.parent_block = probabilistic_blocks.size()-1;
874 transitions_per_label.move_incoming_transitions(s,block_to_split.incoming_action_transitions);
875 }
876
877 // Since the transitions are already grouped by label, add them to the
878 // initial probabilistic block as incoming transitions.
879 transitions_per_label.add_grouped_transitions_to_block(new_block);
880
881 // Add the new block to the back of the list of blocks in the parent constellation.
882 probabilistic_constellation_type& parent_const = probabilistic_constellations[new_block.parent_constellation];
883
884 parent_const.blocks.push_back(probabilistic_blocks.back());
885 }
886
887 /** \brief Split an action block.
888 * \details Creates another block containing the states specified in states_of_new_block. It adds the new block
889 * to the same constellation as the current block to split.
890 */
891 void split_action_block(action_block_type& block_to_split, embedded_list<action_state_type>& states_of_new_block)
892 {
893 // First create the new block to be allocated, and initialise its parameters
894 action_blocks.emplace_back();
895 action_block_type& new_block=action_blocks.back();
896
897 new_block.parent_constellation = block_to_split.parent_constellation; // The new block is in the same constellation as block to split
898 new_block.states = states_of_new_block;
899 states_of_new_block.clear();
900
901 // Add the incoming action transition of the new block. To this end, iterate over all
902 // states in the new block and add the incoming transitions of each state to the
903 // incoming transitions of the new block.
904 for(action_state_type& s: new_block.states)
905 {
906 // Update the parent block of the state
907 s.parent_block = action_blocks.size()-1;
908
909 // Iterate over all incoming transitions of the state, to add them to the new block
910 for (probabilistic_transition_type* t : s.incoming_transitions)
911 {
912 // Move transition from list of transitions of previous block to new block
913 move_list_element_back((*t), block_to_split.incoming_probabilistic_transitions,
914 new_block.incoming_probabilistic_transitions);
915 }
916 }
917
918 // Add the new block to the back of the list of blocks in the parent constellation.
919 action_constellation_type& parent_const = action_constellations[new_block.parent_constellation];
920
921 parent_const.blocks.push_back(action_blocks.back());
922 }
923
924 /** \brief Gives the probabilistic blocks that are marked by block Bc.
925 * \details Derives the left, middle and rigth sets of the marked probabilistic blocks, based on the
926 * incoming probabilistic transitions in block Bc.
927 */
928 void mark_probabilistic(const action_block_type& Bc, std::deque<probabilistic_mark_type>& marked_probabilistic_blocks)
929 {
930 // First, iterate over all incoming transitions of block Bc. Mark the blocks that are reached
931 // and calculate the cumulative probability of the reached state. This is the probability of
932 // a state to reach block Bc.
933 for( probabilistic_transition_type& pt: Bc.incoming_probabilistic_transitions)
934 {
935 probabilistic_state_type& s = probabilistic_states[pt.from];
936 const probability_label_type& p = pt.label;
937 probabilistic_block_type& B = probabilistic_blocks[s.parent_block];
938
939 // If the block was not previously marked, then mark the block and move all states to right
940 if (nullptr == B.marking)
941 {
942 marked_probabilistic_blocks.emplace_back(B);
943 B.marking = &marked_probabilistic_blocks.back();
944 B.marking->right = B.states;
945 B.states.clear();
946
947 // Also initialise the larger block pointer to the right set and the maximum cumulative
948 // probability of the block to p.
949 B.marking->large_block_ptr = &B.marking->right;
950 }
951
952 // Since state s can reach block Bc, move state s to the left set if not yet added, and mark the state
953 if (false == s.mark_state)
954 {
955 // State s is not yet marked. Mark the state and move it to left set. In addition, initialise
956 // its cumulative probability.
957 s.mark_state = true;
958 s.cumulative_probability = p;
959 move_list_element_back<probabilistic_state_type>(s, B.marking->right, B.marking->left);
960 }
961 else
962 {
963 // State s was already added to left. Just update its cumulative probability.
964 s.cumulative_probability = s.cumulative_probability + p;
965 }
966 }
967
968 // Group all states with the same cumulative probability to construct the middle sets.
969 // To this end, iterate over all marked blocks. For each block, first add all the states
970 // with probability lower than the max_cumulative_probability of the block to the middle set.
971 for (probabilistic_mark_type& B : marked_probabilistic_blocks)
972 {
973 // Clear this locally used data structure and reset it so now and then to avoid that it requires
974 // too much data.
975 grouped_states_per_probability_in_block.clear();
976 static std::size_t count=0; if (count++ == 1000) { marked_action_blocks.shrink_to_fit(); count=0; }
977
978 embedded_list<probabilistic_state_type> middle_temp=B.left;
979 B.left.clear();
980
981 // First, add all states lower than max_cumulative_probability to the middle set.
982 for(typename embedded_list<probabilistic_state_type>::iterator i=middle_temp.begin(); i!=middle_temp.end(); )
983 {
984 probabilistic_state_type& s= *i;
985 i++; // Increment the iterator here, such that we can change the list.
986
987 if (s.cumulative_probability == probability_label_type().one())
988 {
989 // State s has probability lower than max_cumulative_probability. Add to the middle set.
990 move_list_element_back<probabilistic_state_type>((s), middle_temp, B.left);
991 }
992
993 // Also reset the marked_state variable in the state here, taiking advantage that we
994 // are iterating over all marked states
995 s.mark_state = false;
996 }
997
998 // Add all the states corresponding to the bigger and smaller probability to middle.
999 // Save the remaining states in a vector to sort them later.
1000 for(probabilistic_state_type& s: middle_temp)
1001 {
1002 grouped_states_per_probability_in_block.emplace_back(s.cumulative_probability, &s);
1003 }
1004
1005 // Sort the probabilities of middle, not including the biggest and smallest probability
1006 std::sort(grouped_states_per_probability_in_block.begin(), grouped_states_per_probability_in_block.end());
1007
1008 // Construct the rest of the middle set based on the grouped probabilities. To this end,
1009 // traverse all the vector with the grouped states by probability. Store the states with
1010 // the same probability to a new sub-set in middle set. current_probability is used to
1011 // keep track of the probability that is currently being processed.
1012 probability_label_type current_probability = probability_label_type().zero();
1013
1014 if (grouped_states_per_probability_in_block.size()>0)
1015 {
1016 B.middle.emplace_back();
1017 for (const std::pair<probability_label_type, probabilistic_state_type*>& cumulative_prob_state_pair : grouped_states_per_probability_in_block)
1018 {
1019 probabilistic_state_type* s = cumulative_prob_state_pair.second;
1020 if (current_probability != cumulative_prob_state_pair.first)
1021 {
1022 // The current state has a different probability as the current probability. Allocate
1023 // another space in the middle to store this state and change the current probability.
1024 current_probability = cumulative_prob_state_pair.first;
1025 B.middle.emplace_back(); //put empty list at end of B.middle.
1026 }
1027
1028 move_list_element_back<probabilistic_state_type>((*s), middle_temp, B.middle.back());
1029 }
1030 }
1031
1032 // Now that we have all the states in left, middle and right; we have to find the largest
1033 // set. The large block is initialised to be the right set; hence, we only compare if
1034 // left and middle are larger.
1035 if (B.left.size() > B.large_block_ptr->size())
1036 {
1037 B.large_block_ptr = &B.left;
1038 }
1039
1040 // Iterate over all subsets of middle set to see if there is a one that is the largest.
1041 for (embedded_list<probabilistic_state_type>& middle_set : B.middle)
1042 {
1043 if (middle_set.size() > B.large_block_ptr->size())
1044 {
1045 B.large_block_ptr = &middle_set;
1046 }
1047 }
1048
1049 // Finally, reset the block_is_marked variable of the current block.
1050 B.probabilistic_block->marking = nullptr;
1051 }
1052 }
1053
1054 /** \brief Gives the action blocks that are marked by probabilistic block Bc.
1055 * \details Derives the left, middle and rigth sets of the marked action blocks, based on the
1056 * incoming action transitions labeled with "a" in block Bc.
1057 */
1058 void mark_action(std::deque<action_mark_type>& marked_action_blocks,
1059 const label_type& a,
1060 typename embedded_list<action_transition_type>::iterator& action_walker_begin,
1061 const typename embedded_list<action_transition_type>::iterator action_walker_end)
1062 {
1063 assert(action_walker_begin!=action_walker_end && action_walker_begin->label==a);
1064
1065 // For all incoming transitions with label "a" of block Bc calculate left, middle and right.
1066 // To this end, first move all the states of the block that was reached by traversing the
1067 // transition backwards to its right set, then move all the states that can reach block Bc with
1068 // an "a" action to left and decrement the residual transition count of the state.
1069 for(typename embedded_list<action_transition_type>::iterator action_walker=action_walker_begin;
1070 action_walker!=action_walker_end && action_walker->label==a;
1071 action_walker++)
1072 {
1073 action_transition_type& t= *action_walker;
1074 action_state_type& s = action_states[t.from];
1075 action_block_type& B = action_blocks[s.parent_block];
1076
1077 // If the block was not previously marked, then mark the block and add all states to right.
1078 if (nullptr == B.marking)
1079 {
1080 marked_action_blocks.emplace_back(B);
1081 B.marking = &marked_action_blocks.back();
1082 B.marking->right=B.states;
1083 B.states.clear();
1084 // Also initialise the larger block pointer to the right set.
1085 B.marking->large_block_ptr = &B.marking->right;
1086 }
1087
1088 // Since state s can reach block Bc, move state s to the left set if not yet added, and mark the state
1089 if (false == s.mark_state)
1090 {
1091 // State s is not yet marked. Mark the state and move it to left set. In addition, initialise
1092 // its residual transition count.
1093 s.mark_state = true;
1094 s.residual_transition_cnt = *t.state_to_constellation_count_ptr;
1095 move_list_element_back<action_state_type>(s, B.marking->right, B.marking->left);
1096 }
1097
1098 s.residual_transition_cnt--;
1099 }
1100
1101 // Now, for all marked blocks, check the residual transition count of all the states in left. If the transition
1102 // count is zero, it means that the state only can reach block BC. If the transition count is greater than
1103 // zero, the state has transitions to the other part of the constellation; hence, those states have to be
1104 // moved to middle.
1105 for (action_mark_type& B : marked_action_blocks)
1106 {
1107 // Iterate over all left states in B and check whether the state has to be moved to middle.
1108 for(typename embedded_list<action_state_type>::iterator i=B.left.begin(); i!=B.left.end(); )
1109 {
1110 action_state_type& s= *i;
1111 i++; // This iterator is incremented here as s will be removed from the list over which iteration takes place.
1112 if (s.residual_transition_cnt > 0)
1113 {
1114 // The transition count is greater than zero. Move state to middle set.
1115 move_list_element_back<action_state_type>(s, B.left, B.middle);
1116 }
1117
1118 // Also reset the marked_state variable in the state here, taking advantage that we
1119 // are iterating over all marked states
1120 s.mark_state = false;
1121 }
1122
1123 // Find the largest set.
1124 if (B.left.size() > B.large_block_ptr->size())
1125 {
1126 B.large_block_ptr = &B.left;
1127 }
1128 if (B.middle.size() > B.large_block_ptr->size())
1129 {
1130 B.large_block_ptr = &B.middle;
1131 }
1132
1133 // Finally, reset the block_is_marked variable of the current block.
1134 B.action_block->marking = nullptr;
1135 }
1136
1137 // Update the state_to_constellation_count of each transition. Increment action_walker_begin
1138 // such that it points to the next action after this loop.
1139 for( ;
1140 action_walker_begin!=action_walker_end && action_walker_begin->label==a;
1141 action_walker_begin++)
1142 {
1143 action_transition_type& t= *action_walker_begin;
1144 action_state_type& s = action_states[t.from];
1145
1146 // If the residual_transition_cnt is greater than zero, it means that the state
1147 // is in the middle set; hence, the state_to_constellation_count has to be updated.
1148 if (s.residual_transition_cnt > 0)
1149 {
1150 std::size_t state_to_constellation_count_old = *t.state_to_constellation_count_ptr;
1151
1152 if (state_to_constellation_count_old != s.residual_transition_cnt)
1153 {
1154 // This is the first transition from this state to a new block.
1155 // First update the state_to_constellation_count with the residual_transition_cnt
1156 // which is used by the transitions that we do not visit. Also the not yet
1157 // visited transitions are set to this value.
1158 *t.state_to_constellation_count_ptr = s.residual_transition_cnt;
1159
1160 // Now allocate another state_to_constellation_count for the Bc block
1161 state_to_constellation_count.emplace_back(state_to_constellation_count_old - s.residual_transition_cnt);
1162 s.transition_count_ptr = &state_to_constellation_count.back();
1163 }
1164 t.state_to_constellation_count_ptr = s.transition_count_ptr;
1165 }
1166 }
1167 }
1168
1169 /** \brief Choose an splitter block from a non trivial constellation.
1170 * \details The number of states in the chosen splitter is always less than the half of the non
1171 * trivial constellation. Furtheremore, the selected splitter is moved to a new constellation.
1172 */
1174 {
1175 assert(non_trivial_action_const->blocks.size()>=2);
1176
1177 // First, determine the block to split from constellation. It is the block |Bc| < 1/2|C|
1178 // First try with the first block in the list.
1179 action_block_type* Bc = &non_trivial_action_const->blocks.front();
1180
1181 if (Bc->states.size() > (non_trivial_action_const->number_of_states / 2))
1182 {
1183 // The block is bigger than 1/2|C|. Choose another one.
1184 Bc = &non_trivial_action_const->blocks.back();
1185 }
1186
1187 // Now split the block of the constellation.
1188 // First unlink Bc from the list of blocks of the non trivial constellation.
1189 non_trivial_action_const->blocks.erase(*Bc);
1190
1191 // Update the number of states and blocks of the non trivial block
1192 non_trivial_action_const->number_of_states -= Bc->states.size();
1193
1194 // Check if the constellation is still non-trivial; if not, move it to the non trivial constellation stack.
1195 if (non_trivial_action_const->blocks.size() > 1)
1196 {
1197 //The constellation is non trivial, put it in the stack of non_trivial_constellations.
1198 non_trivial_action_constellations.push(non_trivial_action_const);
1199 }
1200
1201 // Add Bc to a new constellation
1202 action_constellations.emplace_back();
1203 action_constellation_type& new_action_const=action_constellations.back();
1204
1205 Bc->parent_constellation = action_constellations.size()-1;
1206 new_action_const.blocks.push_back(*Bc);
1207 new_action_const.number_of_states = Bc->states.size();
1208
1209 return Bc;
1210 }
1211
1212 /** \brief Choose an splitter block from a non trivial constellation.
1213 * \details The number of states in the chosen splitter is always less than the half of the non
1214 * trivial constellation. Furtheremore, the selected splitter is moved to a new constellation.
1215 */
1217 {
1218 // First, determine the block to split from constellation. It is the block |Bc| < 1/2|C|
1219 // First try with the first block in the list.
1220 probabilistic_block_type* Bc = &non_trivial_probabilistic_const->blocks.front();
1221 if (Bc->states.size() > (non_trivial_probabilistic_const->number_of_states / 2))
1222 {
1223 // The block is bigger than 1/2|C|. Choose another one.
1224 Bc = &non_trivial_probabilistic_const->blocks.back();
1225 }
1226
1227 // Now split the block of the constellation.
1228 // First unlink Bc from the list of blocks of the non trivial constellation.
1229 non_trivial_probabilistic_const->blocks.erase(*Bc);
1230
1231 // Update the number of states and blocks of the non trivial block
1232 non_trivial_probabilistic_const->number_of_states -= Bc->states.size();
1233
1234 // Check if the constellation is still non-trivial; if not, move it to the trivial constellation stack.
1235 if (non_trivial_probabilistic_const->blocks.size() > 1)
1236 {
1237 //The constellation is non trivial, put it in the stack of non_trivial_constellations.
1238 non_trivial_probabilistic_constellations.push(non_trivial_probabilistic_const);
1239 }
1240
1241 // Add Bc to a new constellation
1242 probabilistic_constellations.emplace_back();
1243 probabilistic_constellation_type& new_probabilistic_const=probabilistic_constellations.back();
1244 Bc->parent_constellation = probabilistic_constellations.size()-1;
1245 new_probabilistic_const.blocks.push_back(*Bc);
1246 new_probabilistic_const.number_of_states = Bc->states.size();
1247
1248 return Bc;
1249 }
1250
1251 typename LTS_TYPE::probabilistic_state_t calculate_new_probabilistic_state(typename LTS_TYPE::probabilistic_state_t ps)
1252 {
1253 typename LTS_TYPE::probabilistic_state_t new_prob_state;
1254
1255 /* Iterate over all state probability pairs in the selected probabilistic state*/
1256 if (ps.size()>1) // The state is stored as a vector of states and probabilities.
1257 {
1258 std::map <state_key_type, probability_fraction_type> prob_state_map;
1259 for (const typename LTS_TYPE::probabilistic_state_t::state_probability_pair& sp_pair : ps)
1260 {
1261 /* Check the resulting action state in the final State partition */
1262 state_key_type new_state = get_eq_class(sp_pair.state());
1263
1264 if (prob_state_map.count(new_state) == 0)
1265 {
1266 /* The state is not yet in the mapping. Add the state with its probability*/
1267 prob_state_map[new_state] = sp_pair.probability();
1268 }
1269 else
1270 {
1271 /* The state is already in the mapping. Sum up probabilities */
1272 prob_state_map[new_state] = prob_state_map[new_state] + sp_pair.probability();
1273 }
1274 }
1275 /* Add all the state probabilities pairs in the mapping to its actual data type*/
1276 typename std::map<state_key_type, probability_fraction_type>::iterator i = prob_state_map.begin();
1277 if (++i==prob_state_map.end()) // There is only one state with probability one.
1278 {
1279 new_prob_state.set(prob_state_map.begin()->first);
1280 }
1281 else
1282 {
1283 // This probabilistic state has more components.
1284 for (const auto& i: prob_state_map)
1285 {
1286 new_prob_state.add(i.first, i.second);
1287 }
1288 }
1289 }
1290 else // The state is stored as a number with implicit probability 1.
1291 {
1292 /* Check the resulting action state in the final State partition */
1293 new_prob_state.set(get_eq_class(ps.get()));
1294 }
1295 return new_prob_state;
1296 }
1297
1299 {
1300 // Select the first probabilistic state of the probabilistic block.
1301 assert(pb.states.size()>0);
1302 const probabilistic_state_type& s = pb.states.front();
1303
1304 if (s.incoming_transitions.size()>0)
1305 {
1306 // Take an incoming transition to know the key of the state
1307 state_key_type s_key = s.incoming_transitions.back()->to;
1308
1309 const typename LTS_TYPE::probabilistic_state_t& old_prob_state = aut.probabilistic_state(s_key);
1310
1311 return calculate_new_probabilistic_state(old_prob_state);
1312 }
1313 // else it is the initial proabilistic state.
1314 return calculate_new_probabilistic_state(aut.initial_probabilistic_state());
1315
1316 }
1317};
1318
1319
1320/** \brief Reduce transition system l with respect to probabilistic bisimulation.
1321* \param[in/out] l The transition system that is reduced.
1322*/
1323template < class LTS_TYPE>
1325
1326/** \brief Checks whether the two initial states of two plts's are probabilistic bisimilar.
1327* \details This lts and the lts l2 are not usable anymore after this call.
1328* \param[in/out] l1 A first probabilistic transition system.
1329* \param[in/out] l2 A second probabilistic transition system.
1330* \retval True iff the initial states of the current transition system and l2 are probabilistic bisimilar */
1331template < class LTS_TYPE>
1332bool destructive_probabilistic_bisimulation_compare_grv(LTS_TYPE& l1, LTS_TYPE& l2, utilities::execution_timer& timer);
1333
1334/** \brief Checks whether the two initial states of two plts's are probabilistic bisimilar.
1335* \details The current transitions system and the lts l2 are first duplicated and subsequently
1336* reduced modulo bisimulation. If memory space is a concern, one could consider to
1337* use destructive_bisimulation_compare.
1338* \param[in/out] l1 A first transition system.
1339* \param[in/out] l2 A second transistion system.
1340* \retval True iff the initial states of the current transition system and l2 are probabilistic bisimilar */
1341template < class LTS_TYPE>
1342bool probabilistic_bisimulation_compare_grv(const LTS_TYPE& l1, const LTS_TYPE& l2, utilities::execution_timer& timer);
1343
1344template < class LTS_TYPE>
1346{
1347 // Apply the probabilistic bisimulation reduction algorithm.
1348 detail::prob_bisim_partitioner_grv<LTS_TYPE> prob_bisim_part(l, timer);
1349
1350 // Clear the state labels of the LTS l
1351 l.clear_state_labels();
1352
1353 // Assign the reduced LTS
1354 l.set_num_states(prob_bisim_part.num_eq_classes());
1355 prob_bisim_part.replace_transitions();
1356 prob_bisim_part.replace_probabilistic_states();
1357}
1358
1359template < class LTS_TYPE>
1361 const LTS_TYPE& l1,
1362 const LTS_TYPE& l2,
1363 utilities::execution_timer& timer)
1364{
1365 LTS_TYPE l1_copy(l1);
1366 LTS_TYPE l2_copy(l2);
1367 return destructive_probabilistic_bisimulation_compare_grv(l1_copy, l2_copy, timer);
1368}
1369
1370template < class LTS_TYPE>
1372 LTS_TYPE& l1,
1373 LTS_TYPE& l2,
1374 utilities::execution_timer& timer)
1375{
1376 std::size_t initial_probabilistic_state_key_l1;
1377 std::size_t initial_probabilistic_state_key_l2;
1378
1379 // Merge states
1380 mcrl2::lts::detail::plts_merge(l1, l2);
1381 l2.clear(); // No use for l2 anymore.
1382
1383 // The last two probabilistic states are the initial states of l2 and l1
1384 // in the merged plts.
1385 initial_probabilistic_state_key_l2 = l1.num_probabilistic_states() - 1;
1386 initial_probabilistic_state_key_l1 = l1.num_probabilistic_states() - 2;
1387
1388 detail::prob_bisim_partitioner_grv<LTS_TYPE> prob_bisim_part(l1,timer);
1389
1390 return prob_bisim_part.in_same_probabilistic_class_grv(initial_probabilistic_state_key_l2,
1391 initial_probabilistic_state_key_l1);
1392}
1393
1394} // end namespace detail
1395// end namespace lts
1396// end namespace mcrl2
1397#endif // MCRL2_LTS_DETAIL_LIBLTS_PBISIM_GRV_H
function object to compare two constln_t pointers based on their contents
std::vector< embedded_list< action_transition_type > > m_transitions_per_label
void add_transitions(std::vector< action_transition_type > &transitions)
void move_incoming_transitions(probabilistic_state_type s, embedded_list< action_transition_type > &transition_list_with_t)
const std::vector< embedded_list< action_transition_type > > & transitions() const
std::deque< action_mark_type > marked_action_blocks
std::deque< probabilistic_block_type > probabilistic_blocks
void split_action_block(action_block_type &block_to_split, embedded_list< action_state_type > &states_of_new_block)
Split an action block.
std::stack< action_constellation_type * > non_trivial_action_constellations
LTS_TYPE::probabilistic_state_t calculate_new_probabilistic_state(typename LTS_TYPE::probabilistic_state_t ps)
LTS_TYPE::probabilistic_state_t calculate_equivalent_probabilistic_state(probabilistic_block_type &pb)
std::size_t get_eq_probabilistic_class(const std::size_t s)
Gives the bisimulation equivalence probabilistic class number of a probabilistic state.
void move_list_element_back(LIST_ELEMENT &s, embedded_list< LIST_ELEMENT > &source_list, embedded_list< LIST_ELEMENT > &dest_list)
std::vector< probabilistic_state_type > probabilistic_states
bool in_same_probabilistic_class_grv(const std::size_t s, const std::size_t t)
Returns whether two states are in the same probabilistic bisimulation equivalence class.
std::stack< probabilistic_constellation_type * > non_trivial_probabilistic_constellations
std::vector< action_transition_type > action_transitions
void mark_probabilistic(const action_block_type &Bc, std::deque< probabilistic_mark_type > &marked_probabilistic_blocks)
Gives the probabilistic blocks that are marked by block Bc.
probabilistic_block_type * choose_probabilistic_splitter(probabilistic_constellation_type *non_trivial_probabilistic_const)
Choose an splitter block from a non trivial constellation.
void refine_partition_until_it_becomes_stable()
Refine partition until it becomes stable.
action_block_type * choose_action_splitter(action_constellation_type *non_trivial_action_const)
Choose an splitter block from a non trivial constellation.
prob_bisim_partitioner_grv(LTS_TYPE &l, utilities::execution_timer &timer)
Creates a probabilistic bisimulation partitioner for an PLTS.
std::size_t get_eq_class(const std::size_t s)
Gives the bisimulation equivalence class number of a state.
void mark_action(std::deque< action_mark_type > &marked_action_blocks, const label_type &a, typename embedded_list< action_transition_type >::iterator &action_walker_begin, const typename embedded_list< action_transition_type >::iterator action_walker_end)
Gives the action blocks that are marked by probabilistic block Bc.
std::deque< probabilistic_transition_type > probabilistic_transitions
std::deque< action_constellation_type > action_constellations
std::vector< action_state_type > action_states
void replace_transitions()
Replaces the transition relation of the current lts by the transitions of the bisimulation reduced tr...
std::deque< action_block_type > action_blocks
void refine_initial_action_block(const std::vector< embedded_list< action_transition_type > > &transitions_per_label)
void replace_probabilistic_states()
Replaces the probabilistic states of the current lts by the probabilistic states of the bisimulation ...
std::deque< probabilistic_constellation_type > probabilistic_constellations
void split_probabilistic_block(probabilistic_block_type &block_to_split, embedded_list< probabilistic_state_type > &states_of_new_block)
Split a probabilistic block.
std::size_t num_eq_classes() const
Gives the number of bisimulation equivalence classes of the LTS.
std::deque< probabilistic_mark_type > marked_probabilistic_blocks
void move_list_element_front(LIST_ELEMENT &s, embedded_list< LIST_ELEMENT > &source_list, embedded_list< LIST_ELEMENT > &dest_list)
Move an element of a list to the front of another the list.
Simple timer to time the CPU time used by a piece of code.
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:393
void probabilistic_bisimulation_reduce_grv(LTS_TYPE &l, utilities::execution_timer &timer)
Reduce transition system l with respect to probabilistic bisimulation.
bool probabilistic_bisimulation_compare_grv(const LTS_TYPE &l1, const LTS_TYPE &l2, utilities::execution_timer &timer)
Checks whether the two initial states of two plts's are probabilistic bisimilar.
bool destructive_probabilistic_bisimulation_compare_grv(LTS_TYPE &l1, LTS_TYPE &l2, utilities::execution_timer &timer)
Checks whether the two initial states of two plts's are probabilistic bisimilar.
embedded_list< probabilistic_transition_type > incoming_probabilistic_transitions
std::vector< probabilistic_transition_type * > incoming_transitions
std::vector< embedded_list< probabilistic_state_type > > middle