11#ifndef MCRL2_LTS_DETAIL_LIBLTS_PBISIM_BEM_H
12#define MCRL2_LTS_DETAIL_LIBLTS_PBISIM_BEM_H
14#include "mcrl2/utilities/execution_timer.h"
15#include "mcrl2/lts/detail/liblts_plts_merge.h"
20template <
class LTS_TYPE>
26
27
28
31 mCRL2log(log::verbose) <<
"Probabilistic bisimulation partitioner created for "
32 << l.num_states() <<
" states and " <<
33 l.num_transitions() <<
" transitions\n";
34 timer.start(
"bisimulation_reduce (bem)");
37 timer.finish(
"bisimulation_reduce (bem)");
42
43
46 return state_partition.size();
50
51
54 assert(s<block_index_of_a_state.size());
55 return block_index_of_a_state[s];
59
60
63 assert(d < step_class_index_of_a_distribution.size());
64 assert(step_class_index_of_a_distribution[d] < step_classes.size());
65 assert(step_classes[step_class_index_of_a_distribution[d]].equivalent_step_class < step_classes.size());
66 return step_classes[step_class_index_of_a_distribution[d]].equivalent_step_class;
70
71
74 std::set < transition > resulting_transitions;
76 const std::vector<transition>& trans = aut.get_transitions();
77 for (
const transition& t : trans)
79 resulting_transitions.insert(
81 get_eq_class(t.from()),
83 get_eq_step_class(t.to())));
86 aut.clear_transitions();
89 for (
const transition& t : resulting_transitions)
91 aut.add_transition(t);
96
97
100 std::vector<
typename LTS_TYPE::probabilistic_state_t> new_probabilistic_states;
103 for (step_class_type& sc : equivalent_step_classes)
105 typename LTS_TYPE::probabilistic_state_t equivalent_ps = calculate_equivalent_probabilistic_state(sc);
106 new_probabilistic_states.push_back(equivalent_ps);
110 aut.clear_probabilistic_states();
113 for (
const typename LTS_TYPE::probabilistic_state_t& new_ps : new_probabilistic_states)
115 aut.add_probabilistic_state(new_ps);
118 typename LTS_TYPE::probabilistic_state_t old_initial_prob_state =
aut.initial_probabilistic_state();
120 aut.set_initial_probabilistic_state(new_initial_prob_state);
124
125
126
127
130 return get_eq_step_class(s) == get_eq_step_class(t);
140 using probability_fraction_type =
typename LTS_TYPE::probabilistic_state_t::probability_t;
191
192
195 std::vector< std::vector< std::list<distribution_type*> > > steps;
196 std::vector<transition>& transitions = aut.get_transitions();
197 std::vector< std::vector<
bool> > distribution_per_step_class;
199 distribution_per_step_class.resize(aut.num_action_labels());
200 for (std::vector<
bool>& i : distribution_per_step_class)
202 i.resize(aut.num_probabilistic_states());
208 distributions.resize(aut.num_probabilistic_states());
210 for (distribution_type& distribution : distributions)
212 distribution.key = key;
213 distribution.incoming_transitions_per_label.resize(aut.num_action_labels());
218 steps.resize(aut.num_states());
219 for (std::size_t i = 0; i < steps.size(); i++)
221 steps[i].resize(aut.num_action_labels());
224 for (transition& t : transitions)
226 steps[t.from()][t.label()].push_back(&distributions[t.to()]);
227 distributions[t.to()].incoming_transitions_per_label[t.label()].push_back(&t);
233 step_classes.resize(aut.num_action_labels());
235 for (step_class_type& sc : step_classes)
237 sc.prev_states.resize(aut.num_states());
241 std::size_t max_block_size = 0;
243 std::deque<tree_type> tree_nodes;
244 std::vector<tree_type*> leaves;
247 tree_nodes.push_back(v0);
250 for (state_type s = 0; s < aut.num_states(); s++)
253 tree_type* v = &tree_nodes[0];
256 for (std::size_t i = 0; i < aut.num_action_labels(); i++)
258 step_classes[i].key = i;
259 step_classes[i].action = i;
260 if (steps[s][i].size() > 0)
262 for (distribution_type* d : steps[s][i])
264 if (distribution_per_step_class[i][d->key] ==
false)
266 step_classes[i].distributions.push_back(d);
267 distribution_per_step_class[i][d->key] =
true;
271 step_classes[i].prev_states[s] =
true;
273 if (v->left ==
nullptr)
278 tree_nodes.push_back(w);
279 v->left = &tree_nodes.back();
282 if (i == aut.num_action_labels() - 1)
284 leaves.push_back(v->left);
292 if (v->right ==
nullptr)
297 tree_nodes.push_back(w);
298 v->right = &tree_nodes.back();
301 if (i == aut.num_action_labels() - 1)
303 leaves.push_back(v->right);
311 v->states.push_back(s);
315 if (v->count > max_block_size)
318 max_block_size = v->count;
323 blocks.resize(leaves.size());
326 std::size_t larger_key = 0;
327 for (tree_type* leaf_ptr : leaves)
329 block_type& block = blocks[key];
331 block.states.splice(block.states.end(), leaf_ptr->states);
333 if (leaf_ptr == max_block)
343 for (block_type& b : blocks)
345 if (b.key != larger_key)
348 b.is_in_new_blocks =
true;
349 state_partition.push_front(&b);
354 b.is_in_new_blocks =
false;
355 state_partition.push_back(&b);
361 for (step_class_type& sc : step_classes)
363 if (sc.distributions.size() > 0)
365 step_partition.push_front(&sc);
366 sc.is_in_new_step_classes =
true;
370 block_index_of_a_state.resize(aut.num_states());
371 for (
const block_type& b : blocks)
373 for (
const state_type s : b.states)
375 block_index_of_a_state[s] = b.key;
382
383
384
387 probability_fraction_type prob_to_block;
388 const typename LTS_TYPE::probabilistic_state_t& prob_state =
aut.probabilistic_state(d.key);
391 if (prob_state.size()>1)
393 for (
const typename LTS_TYPE::probabilistic_state_t::state_probability_pair& prob_pair : prob_state)
395 const state_type s = prob_pair.state();
396 if (block_index_of_a_state[s] == b.key)
398 prob_to_block = prob_to_block + prob_pair.probability();
404 const state_type s = prob_state.get();
405 if (block_index_of_a_state[s] == b.key)
407 prob_to_block = prob_to_block + LTS_TYPE::probabilistic_state_t::probability_t::one();
411 return prob_to_block;
416 typename LTS_TYPE::probabilistic_state_t new_prob_state;
421 std::map<state_type, probability_fraction_type> prob_state_map;
422 for (
const typename LTS_TYPE::probabilistic_state_t::state_probability_pair& sp_pair : ps)
425 state_type new_state = get_eq_class(sp_pair.state());
427 if (prob_state_map.count(new_state) == 0)
430 prob_state_map[new_state] = sp_pair.probability();
435 prob_state_map[new_state] = prob_state_map[new_state] + sp_pair.probability();
440 typename std::map<state_type, probability_fraction_type>::const_iterator i = prob_state_map.begin();
441 if (++i==prob_state_map.end())
443 new_prob_state.set(prob_state_map.begin()->first);
448 for (
const std::pair<
const state_type, probability_fraction_type>& i: prob_state_map)
450 new_prob_state.add(i.first, i.second);
458 new_prob_state.set(get_eq_class(ps.get()));
461 return new_prob_state;
466 typename LTS_TYPE::probabilistic_state_t equivalent_prob_state;
471 typename LTS_TYPE::probabilistic_state_t old_prob_state =
aut.probabilistic_state(d->key);
475 return equivalent_prob_state;
479
480
481
484 std::list<step_class_type*> step_partition_old;
485 std::list<block_type*> state_partition_old;
488 while (state_partition.front()->is_in_new_blocks ==
true ||
489 (step_partition.size()>0 && step_partition.front()->is_in_new_step_classes ==
true))
492 if (state_partition.front()->is_in_new_blocks ==
true)
495 block_type* c_block = state_partition.front();
496 state_partition.pop_front();
497 state_partition.push_back(c_block);
498 c_block->is_in_new_blocks =
false;
501 step_partition_old.swap(step_partition);
504 static std::vector<
typename std::list<step_class_type*>::iterator> pending_new_step_classes;
505 pending_new_step_classes.clear();
508 for (
typename std::list<step_class_type*>::iterator sc_iter = step_partition_old.begin();
509 sc_iter != step_partition_old.end(); ++sc_iter)
511 step_class_type* sc_ptr = *sc_iter;
515 static std::map< probability_fraction_type, std::list<distribution_type*> > distributions_ordered_by_prob;
516 distributions_ordered_by_prob.clear();
519 for (distribution_type* d : sc_ptr->distributions)
521 probability_fraction_type probability = probability_to_block(*d, *c_block);
522 distributions_ordered_by_prob[probability].push_back(d);
527 if (distributions_ordered_by_prob.size() >= 2)
529 step_class_type* new_step_class_ptr;
531 step_classes.resize(step_classes.size() + distributions_ordered_by_prob.size() - 1);
533 std::size_t new_class_count = 0;
534 for (std::pair< probability_fraction_type, std::list<distribution_type*> > ordered_dist : distributions_ordered_by_prob)
536 std::list<distribution_type*>& distribution_list = ordered_dist.second;
538 if (new_class_count == 0)
542 sc_ptr->distributions.swap(distribution_list);
545 for (std::size_t i = 0; i < sc_ptr->prev_states.size(); i++)
547 sc_ptr->prev_states[i] =
false;
551 for (distribution_type* d : sc_ptr->distributions)
553 for (transition* t_ptr : d->incoming_transitions_per_label[sc_ptr->action])
555 sc_ptr->prev_states[t_ptr->from()] =
true;
560 if (sc_ptr->is_in_new_step_classes ==
false)
564 pending_new_step_classes.push_back(sc_iter);
565 sc_ptr->is_in_new_step_classes =
true;
570 new_step_class_ptr = &step_classes[step_classes.size() - new_class_count];
573 new_step_class_ptr->key = step_classes.size() - new_class_count;
574 new_step_class_ptr->action = sc_ptr->action;
575 new_step_class_ptr->is_in_new_step_classes =
true;
576 new_step_class_ptr->prev_states.resize(aut.num_states());
577 new_step_class_ptr->distributions.swap(distribution_list);
580 for (distribution_type* d : new_step_class_ptr->distributions)
582 for (transition* t_ptr : d->incoming_transitions_per_label[new_step_class_ptr->action])
584 new_step_class_ptr->prev_states[t_ptr->from()] =
true;
589 step_partition.push_front(new_step_class_ptr);
597 for (
const typename std::list<step_class_type*>::iterator& sc_iter: pending_new_step_classes)
599 step_partition.splice(step_partition.begin(), step_partition_old, sc_iter);
603 step_partition.splice(step_partition.end(), step_partition_old);
607 if (step_partition.front()->is_in_new_step_classes ==
true)
610 step_class_type* step_class = step_partition.front();
611 step_partition.pop_front();
612 step_class->is_in_new_step_classes =
false;
613 step_partition.push_back(step_class);
616 state_partition_old.swap(state_partition);
618 static std::vector<
typename std::list<block_type*>::iterator > blocks_to_move_to_front;
619 static std::vector<block_type*> new_blocks_to_move_to_front;
620 blocks_to_move_to_front.clear();
621 new_blocks_to_move_to_front.clear();
623 for (
typename std::list<block_type*>::iterator block_iter = state_partition_old.begin();
624 block_iter != state_partition_old.end(); ++block_iter)
626 block_type* b_to_split = *block_iter;
627 block_type new_block;
628 new_block.is_in_new_blocks =
false;
629 block_type temp_block;
630 block_type* new_block_ptr;
631 new_block.key = blocks.size();
634 for (state_type s : b_to_split->states)
637 if (step_class->prev_states[s] ==
true)
639 new_block.states.push_back(s);
643 temp_block.states.push_back(s);
648 if (new_block.states.size() > 0 && temp_block.states.size() > 0)
652 for (state_type s : new_block.states)
654 block_index_of_a_state[s] = new_block.key;
657 blocks.push_back(new_block);
658 new_block_ptr = &blocks.back();
661 b_to_split->states.swap(temp_block.states);
666 if (b_to_split->is_in_new_blocks ==
false)
668 if (new_block_ptr->states.size() < b_to_split->states.size())
670 new_blocks_to_move_to_front.push_back(new_block_ptr);
671 new_block_ptr->is_in_new_blocks =
true;
675 b_to_split->is_in_new_blocks =
true;
676 blocks_to_move_to_front.push_back(block_iter);
679 state_partition.push_back(new_block_ptr);
687 new_block_ptr->is_in_new_blocks =
true;
690 new_blocks_to_move_to_front.push_back(new_block_ptr);
696 state_partition.splice(state_partition.begin(), state_partition_old);
699 for (
const typename std::list<block_type*>::iterator& block_iter: blocks_to_move_to_front)
701 state_partition.splice(state_partition.begin(), state_partition, block_iter);
705 for (block_type* block_ptr : new_blocks_to_move_to_front)
707 state_partition.push_front(block_ptr);
718 for (
const block_type& b : blocks)
720 for (
const state_type s : b.states)
722 block_index_of_a_state[s] = b.key;
726 step_class_index_of_a_distribution.resize(aut.num_probabilistic_states());
727 for (step_class_type& sc : step_classes)
729 sc.equivalent_step_class = sc.key;
731 for (
const distribution_type* d : sc.distributions)
733 step_class_index_of_a_distribution[d->key] = sc.key;
740 typename LTS_TYPE::probabilistic_state_t new_prob_state;
741 std::unordered_map<
typename LTS_TYPE::probabilistic_state_t, std::vector<step_class_type*> > reduced_step_partition;
744 for (step_class_type& sc : step_classes)
746 if (sc.distributions.size() > 0)
748 typename LTS_TYPE::probabilistic_state_t new_prob_state = calculate_equivalent_probabilistic_state(sc);
751 reduced_step_partition[new_prob_state].push_back(&sc);
755 step_class_key_type equivalent_class_key = 0;
756 for (
typename std::unordered_map<
typename LTS_TYPE::probabilistic_state_t,
757 std::vector<step_class_type*> >::iterator i = reduced_step_partition.begin();
758 i != reduced_step_partition.end(); ++i)
760 std::vector<step_class_type*>& sc_vector = i->second;
762 equivalent_step_classes.push_back(*sc_vector[0]);
763 for (step_class_type* sc :sc_vector)
765 sc->equivalent_step_class = equivalent_class_key;
767 equivalent_class_key++;
775
776
777
778template <
class LTS_TYPE>
782
783
784
785
786template <
class LTS_TYPE>
791
792
793
794
795
796
797template <
class LTS_TYPE>
801template <
class LTS_TYPE>
809 l.clear_state_labels();
812 l.set_num_states(prob_bisim_part.num_eq_classes());
813 prob_bisim_part.replace_transitions();
814 prob_bisim_part.replace_probabilistic_states();
817template <
class LTS_TYPE>
823 LTS_TYPE l1_copy(l1);
824 LTS_TYPE l2_copy(l2);
825 return destructive_probabilistic_bisimulation_compare_bem(l1_copy, l2_copy, timer);
828template <
class LTS_TYPE>
834 std::size_t initial_probabilistic_state_key_l1;
835 std::size_t initial_probabilistic_state_key_l2;
843 initial_probabilistic_state_key_l2 = l1.num_probabilistic_states() - 1;
844 initial_probabilistic_state_key_l1 = l1.num_probabilistic_states() - 2;
848 return prob_bisim_part.in_same_probabilistic_class(initial_probabilistic_state_key_l2,
849 initial_probabilistic_state_key_l1);
function object to compare two constln_t pointers based on their contents
std::size_t num_eq_classes() const
Gives the number of bisimulation equivalence classes of the LTS.
std::list< block_type * > state_partition
std::size_t get_eq_step_class(const std::size_t d) const
Gives the bisimulation equivalence step class number of a probabilistic state.
LTS_TYPE::probabilistic_state_t calculate_new_probabilistic_state(typename LTS_TYPE::probabilistic_state_t ps)
std::vector< block_key_type > block_index_of_a_state
std::deque< block_type > blocks
std::vector< step_class_key_type > step_class_index_of_a_distribution
std::list< step_class_type * > step_partition
std::deque< step_class_type > step_classes
void refine_partition_until_it_becomes_stable()
Two-phased partitioning algorithm described in page 204. Fig 9. Baier. \detail Refinement of state pa...
probability_fraction_type probability_to_block(distribution_type &d, block_type &b)
Calculates the probability to reach block b from distribution d.
bool in_same_probabilistic_class(const std::size_t s, const std::size_t t) const
Returns whether two states are in the same probabilistic bisimulation equivalence class.
void create_initial_partition()
Creates the initial partition of step classes and blocks. \detail The blocks are initially partitione...
void postprocessing_stage()
std::size_t get_eq_class(const std::size_t s) const
Gives the bisimulation equivalence class number of a state.
prob_bisim_partitioner_bem(LTS_TYPE &l, utilities::execution_timer &timer)
Creates a probabilistic bisimulation partitioner for an PLTS.
std::deque< step_class_type > equivalent_step_classes
void replace_transitions()
Replaces the transition relation of the current lts by the transitions of the bisimulation reduced tr...
LTS_TYPE::probabilistic_state_t calculate_equivalent_probabilistic_state(step_class_type &sc)
std::vector< distribution_type > distributions
void replace_probabilistic_states()
Replaces the probabilistic states of the current lts by the probabilistic states of the bisimulation ...
Simple timer to time the CPU time used by a piece of code.
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
bool probabilistic_bisimulation_compare_bem(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_bem(LTS_TYPE &l1, LTS_TYPE &l2, utilities::execution_timer &timer)
Checks whether the two initial states of two plts's are probabilistic bisimilar.
void probabilistic_bisimulation_reduce_bem(LTS_TYPE &l, utilities::execution_timer &timer)
Reduce transition system l with respect to probabilistic bisimulation.
std::list< state_type > states
distribution_key_type key
std::vector< bool > prev_states
std::size_t equivalent_step_class
std::list< distribution_type * > distributions
bool is_in_new_step_classes
std::list< state_type > states