mCRL2
Loading...
Searching...
No Matches
lts_utilities.h
Go to the documentation of this file.
1// Author(s): 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
18#ifndef MCRL2_LTS_LTS_UTILITIES_H
19#define MCRL2_LTS_LTS_UTILITIES_H
20
21#include "mcrl2/lts/lts_lts.h"
22
23namespace mcrl2
24{
25
26namespace lts
27{
28
36inline void sort_transitions(std::vector<transition>& transitions,
37 const std::set<transition::size_type>& hidden_label_set,
39{
40 switch (ts)
41 {
42 case lbl_tgt_src:
43 {
44 const detail::compare_transitions_lts compare(hidden_label_set);
45 sort(transitions.begin(),transitions.end(),compare);
46 break;
47 }
48 case tgt_src_lbl:
49 {
50 const detail::compare_transitions_tsl compare(hidden_label_set);
51 sort(transitions.begin(),transitions.end(),compare);
52 break;
53 }
54 case tgt_lbl_src:
55 {
56 const detail::compare_transitions_tls compare(hidden_label_set);
57 sort(transitions.begin(),transitions.end(),compare);
58 break;
59 }
60 case tgt_lbl:
61 {
62 const detail::compare_transitions_tl compare(hidden_label_set);
63 sort(transitions.begin(),transitions.end(),compare);
64 break;
65 }
66 case target:
67 {
69 sort(transitions.begin(),transitions.end(),compare);
70 break;
71 }
72 case src_lbl_tgt:
73 default:
74 {
75 const detail::compare_transitions_slt compare(hidden_label_set);
76 sort(transitions.begin(),transitions.end(),compare);
77 break;
78 }
79 }
80}
81
88inline std::string ptr(const transition t)
89 {
90 return std::to_string(t.from()) + " -" + std::to_string(t.label()) + "-> " + std::to_string(t.to());
91 }
92
93static std::vector<std::size_t> bogus_todo_stack;
94
95template <bool USE_STACK>
96inline void group_transitions_on_label(const std::vector<transition>::iterator begin,
97 const std::vector<transition>::iterator end,
98 std::function<std::size_t(const transition&)> get_label,
99 std::vector<std::pair<std::size_t, std::size_t>>& count_sum_transitions_per_action,
100 const std::size_t tau_label_index=0,
101 std::vector<std::size_t>& todo_stack=bogus_todo_stack)
102{
103// std::cerr << "START SORTING TRANSITIONS\n";
104// std::cerr << "==============\n"; for(auto t=begin; t!=end; ++t){ std::cerr << ptr(*t) << "\n";} std::cerr << "---------\n";
105#ifndef NDEBUG
106 for(std::pair<std::size_t, std::size_t> p: count_sum_transitions_per_action){ assert(p.first==0); }
107 assert(todo_stack.empty());
108#endif
109
110 if (USE_STACK) todo_stack.push_back(tau_label_index);
111 for(std::vector<transition>::iterator ti=begin; ti!=end; ++ti)
112 {
113 const transition& t=*ti;
114 std::size_t label=get_label(t);
115 if (USE_STACK && label!=tau_label_index && count_sum_transitions_per_action[label].first==0)
116 {
117 todo_stack.push_back(label);
118 }
119// std::cerr << "COUNT LABEL " << label << "\n";
120 count_sum_transitions_per_action[label].first++;
121 }
122// std::cerr << "+++++++++++++++++++++\n"; for(auto p: count_sum_transitions_per_action) { std::cerr << "AAAA1 " << p.first << " " << p.second << "\n"; }
123
124 // Sum the number of transitions per label. By summing these numbers up, count_sum_transitions_per_action[a].second indicates the starting
125 // position where a transition with label a must be placed.
126
127 std::size_t sum=0;
128 if (USE_STACK)
129 {
130 for(std::size_t a: todo_stack)
131 {
132 sum=sum+count_sum_transitions_per_action[a].first;
133 count_sum_transitions_per_action[a].second=sum;
134 }
135 }
136 else
137 {
138 for(std::pair<std::size_t, std::size_t>& p: count_sum_transitions_per_action)
139 {
140 sum=sum+p.first;
141 p.second=sum;
142 }
143 }
144// std::cerr << "+++++++++++++++++++++\n"; for(auto p: count_sum_transitions_per_action) { std::cerr << "AAAA2 " << p.first << " " << p.second << "\n"; }
145
146 // Move from left to right through the transitions and move them to the required place.
147 std::vector<transition>::iterator current_leftmost_position=begin;
148 std::vector<std::size_t>::iterator current_leftmost_label=todo_stack.begin();
149 std::size_t current_label=USE_STACK?*current_leftmost_label:0;
150 while (current_leftmost_position!=end)
151 {
152// std::cerr << "POINTERS " << &*current_leftmost_position << " " << &*end << "\n";
153// std::cerr << "POINTERS1 " << &*current_leftmost_label << " " << &*todo_stack.end() << "\n";
154// std::cerr << "AAAAA==============\n"; for(auto t=begin; t!=end; ++t){ std::cerr << ptr(*t) << "\n";} std::cerr << "---------\n";
155 if (USE_STACK)
156 {
157 assert(current_leftmost_label!=todo_stack.end());
158 while (count_sum_transitions_per_action[current_label].first==0)
159 {
160// std::cerr << "HIER\n";
161 current_leftmost_label++;
162 if (current_leftmost_label==todo_stack.end())
163 {
164 break;
165 }
166 current_label=*current_leftmost_label;
167 }
168 // Move to the first position with the current label that is potentially not correct.
169 if (current_leftmost_label==todo_stack.end())
170 {
171 break;
172 }
173 }
174 else
175 {
176 while (current_label<count_sum_transitions_per_action.size() &&
177 count_sum_transitions_per_action[current_label].first==0)
178 {
179// std::cerr << "HIER\n";
180 current_label++;
181 }
182 // Move to the first position with the current label that is potentially not correct.
183 if (current_label==count_sum_transitions_per_action.size())
184 {
185 break;
186 }
187 }
188 current_leftmost_position=begin+
189 count_sum_transitions_per_action[current_label].second-
190 count_sum_transitions_per_action[current_label].first;
191
192// std::cerr << "current_leftmost_position: " << &*current_leftmost_position << "\n";
193// std::cerr << "BBBBB==============\n"; for(auto t=begin; t!=end; ++t){ std::cerr << ptr(*t) << "\n";} std::cerr << "---------\n";
194 // Shift the current leftmost position until a transition is found that must be moved.
195 while (current_leftmost_position!=end && get_label(*current_leftmost_position)==current_label)
196 {
197 current_leftmost_position++;
198 count_sum_transitions_per_action[current_label].first--;
199 // count_sum_transitions_per_action[current_label].second;
200 }
201
202 // Check whether a transition with the current label is expected at the current_leftmost_position.
203 if (count_sum_transitions_per_action[current_label].first>0)
204 {
205 // At the current position there is a transition that needs to be moved. Move transitions out of the way, until
206 // the transitions that belongs here is found and is moved in place.
207 transition transition_on_the_move= *current_leftmost_position;
208// std::cerr << "Transition on the move " << ptr(transition_on_the_move) << "\n";
209 do
210 {
211// std::cerr << "CCCCC==============\n"; for(auto t=begin; t!=end; ++t){ std::cerr << ptr(*t) << "\n";} std::cerr << "---------\n";
212 std::size_t label=get_label(transition_on_the_move);
213 std::size_t new_position=count_sum_transitions_per_action[label].second-count_sum_transitions_per_action[label].first;
214// std::cerr << "FIrst NEW POSITION " << new_position << "\n";
215 assert(0<std::distance(begin,end)-new_position);
216 count_sum_transitions_per_action[label].first--;
217 // Search for a target position with a non-matching label.
218 while (get_label(*(begin+new_position))==label)
219 {
220 new_position++;
221 // count_sum_transitions_per_action[label].second++;
222 count_sum_transitions_per_action[label].first--;
223 }
224 assert(get_label(transition_on_the_move)!=get_label(*(begin+new_position)));
225// std::cerr << "DEFINITIVE NEW POSITION " << new_position << "\n";
226 std::swap(transition_on_the_move,*(begin+new_position));
227 }
228 while (get_label(transition_on_the_move)!=current_label);
229 // We found the transition that we must put at the current place.
230 *current_leftmost_position=transition_on_the_move;
231 current_leftmost_position++;
232 count_sum_transitions_per_action[current_label].first--;
233 // count_sum_transitions_per_action[current_label].second++;
234 }
235 }
236// std::cerr << "==============\n"; for(auto t=begin; t!=end; ++t){ std::cerr << ptr(*t) << "\n";} std::cerr << "---------\n";
237// std::cerr << "END SORTING TRANSITIONS\n";
238}
239
240inline void group_transitions_on_label(std::vector<transition>& transitions,
241 std::function<std::size_t(const transition&)> get_label,
242 const std::size_t number_of_labels,
243 const std::size_t tau_label_index)
244{
245 std::vector<std::pair<std::size_t, std::size_t>> count_sum_transitions_per_action(number_of_labels, {0,0});
246 std::vector<std::size_t> todo_stack;
247 group_transitions_on_label<true>(transitions.begin(), transitions.end(), get_label,
248 count_sum_transitions_per_action, tau_label_index, todo_stack);
249}
250
251
252// Group the elements from begin up to end, using a range from [0,domain_size> where
253// each element pinpointed by the iterator has a value indicated by get_value.
254// first_element is the first element in the grouping, unless first_element is undefined, i.e. -1.
255
256/* template <class ITERATOR>
257void group_in_situ(const ITERATOR& begin,
258 const ITERATOR& end,
259 std::function<std::size_t(const typename ITERATOR::value_type&)> get_value,
260 std::vector<std::size_t>& todo_stack,
261 std::vector<std::pair<std::size_t, std::size_t> >& value_sum_counter)
262{
263 // Initialise the action counter.
264 todo_stack.clear();
265
266//std::cerr << "GROUP IN SITU " << &*begin << " " << &*end << " " << std::distance(begin,end) << "\n";
267//std::cerr << "VALUE COUNTER IN "; for(auto s: value_counter){ std::cerr << s.label_counter << " "; } std::cerr << "\n";
268//std::cerr << "RANGE IN "; for(auto s=begin; s!=end; s++){ std::cerr << *s << " "; } std::cerr << "\n";
269 for(ITERATOR i=begin; i!=end; ++i)
270 {
271 std::size_t n=get_value(*i);
272//std::cerr << "CONSIDER IN SITU " << &*i << " with value " << n << "\n";
273 if (value_sum_counter[n].first==0)
274 {
275 todo_stack.push_back(n);
276 }
277 value_sum_counter[n].first++;
278 }
279
280 // Accumulate the entries in value_counter in sum_counter;
281 std::size_t sum=0;
282 for(std::size_t n: todo_stack)
283 {
284 sum=sum+value_sum_counter[n].first;
285 value_sum_counter[n].second=sum;
286 }
287//std::cerr << "VALUE COUNTER1 count "; for(auto s: value_counter){ std::cerr << s.label_counter << " "; } std::cerr << "\n";
288//std::cerr << "VALUE COUNTER1 not_in "; for(auto s: value_counter){ std::cerr << s.not_investigated << " "; } std::cerr << "\n";
289
290 // std::vector<std::size_t>::iterator current_value=todo_stack.begin();
291
292 // Move from left to right through the transitions and move them to the required place.
293 std::vector<transition>::iterator current_leftmost_position=begin;
294 std::vector<std::size_t>::iterator current_leftmost_value=todo_stack.begin();
295 while (current_leftmost_position!=end)
296 {
297// std::cerr << "POINTERS " << &*current_leftmost_position << " " << &*transitions.end() << "\n";
298// std::cerr << "AAAAA==============\n"; for(auto t: transitions){ std::cerr << ptr(t) << "\n";} std::cerr << "---------\n";
299 while (current_leftmost_value!=todo_stack.end() && value_sum_counter[*current_leftmost_value].first==0)
300 {
301// std::cerr << "HIER\n";
302 current_leftmost_value++;
303 }
304 // Move to the first position with the current label that is potentially not correct.
305// std::cerr << "Current leftmost label " << *current_leftmost_value << " " << value_counter[*current_leftmost_value] << " " << sum_counter[*current_leftmost_value] << "\n";
306 if (current_leftmost_value==todo_stack.end())
307 {
308 break;
309 }
310 current_leftmost_position=begin+value_sum_counter[*current_leftmost_value].second-value_sum_counter[*current_leftmost_value].first;
311
312 // Shift the current leftmost position until a transition is found that must be moved.
313 // while (current_leftmost_position!=end && get_value(*current_leftmost_position)==*current_leftmost_value)
314 while (current_leftmost_position!=end && current_leftmost_position->to()==*current_leftmost_value)
315 {
316 current_leftmost_position++;
317 value_sum_counter[*current_leftmost_value].first--;
318 // sum_counter[*current_leftmost_value]++;
319 }
320
321 // Check whether a transition with the current valuel is expected at the current_leftmost_position.
322 if (value_sum_counter[*current_leftmost_value].first>0)
323 {
324 // At the current position there is a transition that needs to be moved. Move transitions out of the way, until
325 // the transitions that belongs here is found and is moved in place.
326 transition transition_on_the_move= *current_leftmost_position;
327//std::cerr << "Transition on the move " << ptr(transition_on_the_move) << "\n";
328 do
329 {
330 // std::size_t value=get_value(transition_on_the_move);
331 std::size_t value=transition_on_the_move.to();
332 assert(value<value_sum_counter.size());
333 std::size_t new_position=value_sum_counter[value].second-value_sum_counter[value].first;
334// std::cerr << "FIrst NEW POSITION " << new_position << " " << std::distance(begin,end) << "\n";
335 assert(std::distance(begin,end)-new_position>0);
336 value_sum_counter[value].first--;
337 // Search for a target position with a non-matching label.
338 // while (get_value(*(begin+new_position))==value)
339 while ((begin+new_position)->to()==value)
340 {
341 new_position++;
342 // value_sum_counter[value]++;
343 value_sum_counter[value].first--;
344 }
345 assert(get_value(transition_on_the_move)!=get_value(*(begin+new_position)));
346//std::cerr << "DEFINITIVE NEW POSITION " << new_position << "\n";
347 std::swap(transition_on_the_move,*(begin+new_position));
348 }
349 // while (get_value(transition_on_the_move)!=*current_leftmost_value);
350 while (transition_on_the_move.to()!=*current_leftmost_value);
351 // We found the transition that we must put at the current place.
352 *current_leftmost_position=transition_on_the_move;
353 current_leftmost_position++;
354 value_sum_counter[*current_leftmost_value].first--;
355 // sum_counter[*current_leftmost_value]++;
356 }
357 }
358//std::cerr << "END SORTING TRANSITIONS\n";
359
360
361
362//std::cerr << "TODO STACK "; for(auto s: todo_stack){ std::cerr << s << " "; } std::cerr << "\n";
363//std::cerr << "VALUE COUNTER2 "; for(auto s: value_counter){ std::cerr << s << " "; } std::cerr << "\n";
364//std::cerr << "RANGE OUT "; for(auto s=begin; s!=end; s++){ std::cerr << *s << " "; } std::cerr << "\n";
365} */
366
367
368
369inline void group_transitions_on_label_tgt(std::vector<transition>& transitions, const std::size_t number_of_labels, const std::size_t tau_label_index,
370 const std::size_t number_of_states)
371{
372 std::vector<std::pair<std::size_t, std::size_t>> count_sum_transitions_per_action(number_of_labels, {0,0});
373 std::vector<std::size_t> todo_stack;
374
375 group_transitions_on_label<true>(transitions.begin(),
376 transitions.end(),
377 [](const transition& t){ return t.label(); },
378 count_sum_transitions_per_action,
379 tau_label_index,
380 todo_stack);
381//std::cerr << "HIER\n";
382 std::vector<std::size_t> todo_stack_target;
383 // std::vector<std::size_t> value_counter(number_of_states,0);
384 std::vector<std::pair<std::size_t, std::size_t>> value_sum_counter(number_of_states, {0,0});
385 std::vector<transition>::iterator begin=transitions.begin();
386 for(std::size_t label: todo_stack)
387 {
388//std::cerr << "SORT " << &*begin << " tot " << &*end << " " << current_label << " " << std::distance(begin,end) << "\n";
389 todo_stack_target.clear();
390 std::vector<transition>::iterator end=transitions.begin()+count_sum_transitions_per_action[label].second;
391 group_transitions_on_label<true>(begin, end, [](const std::vector<transition>::value_type& t){ return t.to(); }, value_sum_counter, 0, todo_stack_target);
392 begin=end;
393 }
394}
395
396
397inline void group_transitions_on_tgt_label(std::vector<transition>& transitions,
398 const std::size_t number_of_labels,
399 const std::size_t tau_label_index,
400 const std::size_t number_of_states)
401{
402 constexpr std::size_t log2cache_size = 16; // This is an approximation of the 2log of the cache size in pointers.
403 constexpr std::size_t one=1;
404 assert(number_of_states>0);
405 assert(number_of_states< (one << 2*log2cache_size));
406 size_t relevant_bits=(number_of_states<2?1:std::log2(number_of_states-1)+1);
407 assert((one<<relevant_bits)>=number_of_states);
408 size_t mask=0, shift=0;
409 if (relevant_bits>log2cache_size)
410 {
411 // Sort in two phases, with the relevant bits evenly divided.
412 mask=(one<<(relevant_bits/2))-1;
413 shift=relevant_bits-(relevant_bits/2);
414 }
415 else
416 {
417 mask=(one<<relevant_bits)-1;
418 shift=0;
419 }
420 relevant_bits=shift;
421
422// std::cerr << "SHIFT MASK1 " << shift << " " << mask << "\n";
423
424 std::vector<std::pair<std::size_t, std::size_t>> count_sum_transitions_per_tgt1(mask+1, {0,0});
425 std::vector<std::size_t> todo_stack;
426
427 group_transitions_on_label<false>(transitions.begin(),
428 transitions.end(),
429 [shift](const transition& t){ return (t.to()>>shift); },
430 count_sum_transitions_per_tgt1);
431// std::cerr << "==============\n"; for(transition& t: transitions){ std::cerr << ptr(t) << "\n";} std::cerr << "---------\n";
432//std::cerr << "END SORTING TRANSITIONS\n";
433
434 if (relevant_bits>0)
435 {
436 mask=(one<<shift)-1;
437 std::vector<std::pair<std::size_t, std::size_t>> count_sum_transitions_per_tgt2(mask+1, {0,0});
438 std::vector<std::size_t> todo_stack_target;
439 std::vector<std::pair<std::size_t, std::size_t>> value_sum_counter(number_of_labels, {0,0});
440
441 std::vector<transition>::iterator begin=transitions.begin();
442 for(std::pair<std::size_t, std::size_t>& p1: count_sum_transitions_per_tgt1)
443 {
444// std::cerr << "P1: " << p1.first << " " << p1.second << "\n";
445 std::vector<transition>::iterator end=transitions.begin()+p1.second;
446// std::cerr << "SHIFT MASK2 " << shift << " " << mask << "\n";
447 group_transitions_on_label<false>(begin,
448 end,
449 [mask](const transition& t){ return (t.to() & mask); },
450 count_sum_transitions_per_tgt2);
451// std::cerr << "QQQQQ==============\n"; for(auto t=begin; t!=end; t++){ std::cerr << ptr(*t) << "\n";} std::cerr << "---------\n";
452 std::vector<transition>::iterator begina=begin;
453 for(std::pair<std::size_t, std::size_t>& p2: count_sum_transitions_per_tgt2)
454 {
455
456 std::vector<transition>::iterator enda=begin+p2.second;
457// std::cerr << "LABEL1 \n";
458 group_transitions_on_label<true>(begina,
459 enda,
460 [](const std::vector<transition>::value_type& t){ return t.label(); },
461 value_sum_counter,
462 tau_label_index,
463 todo_stack_target);
464 for(std::size_t i:todo_stack)
465 {
466 if (value_sum_counter[i].first!=0) throw mcrl2::runtime_error("BLAH " + std::to_string(value_sum_counter[i].first));;
467 value_sum_counter[i].second=0;
468 }
469 todo_stack_target.clear();
470 begina=enda;
471
472 }
473 begin=end;
474 }
475 }
476 else
477 {
478 std::vector<std::size_t> todo_stack_target;
479 // std::vector<std::size_t> value_counter(number_of_labels,0);
480 std::vector<std::pair<std::size_t, std::size_t>> value_sum_counter(number_of_labels, {0,0});
481 std::vector<transition>::iterator begin=transitions.begin();
482 for(std::pair<std::size_t, std::size_t>& p: count_sum_transitions_per_tgt1)
483 {
484//std::cerr << "SORT " << &*begin << " tot " << &*end << " " << current_label << " " << std::distance(begin,end) << "\n";
485 std::vector<transition>::iterator end=transitions.begin()+p.second;
486//std::cerr << "LABEL2 \n";
487 group_transitions_on_label<true>(begin,
488 end,
489 [](const transition& t){ return t.label(); },
490 value_sum_counter,
491 0,
492 todo_stack_target);
493 for(std::size_t i:todo_stack)
494 {
495 value_sum_counter[i]={0,0};
496 }
497 todo_stack_target.clear();
498 // std::sort(begin, end, [](const transition& t1, const transition& t2){ return t1.label()<t2.label(); });
499 begin=end;
500 }
501 }
502#ifndef NDEBUG
503 std::size_t last_state=0;
504 std::size_t last_label=tau_label_index;
505 std::unordered_set<std::size_t> seen_labels;
506// std::cerr << "==============\n"; for(transition& t: transitions){ std::cerr << ptr(t) << "\n";} std::cerr << "---------\n";
507 for(const transition& t: transitions)
508 {
509// std::cerr << "CHECK " << ptr(t) << "\n";
510 if (last_state<t.to())
511 {
512 last_label=tau_label_index;
513 last_state=t.to();
514 seen_labels.clear();
515 }
516 else
517 {
518 assert(last_state==t.to());
519 if (last_label!=t.label())
520 {
521 seen_labels.insert(last_label);
522 assert(seen_labels.count(t.label())==0);
523 last_label=t.label();
524 }
525 }
526 }
527#endif
528}
529
530template <class LTS_TYPE>
531inline void group_transitions_on_tgt_label(LTS_TYPE& aut)
532{
533 group_transitions_on_tgt_label(aut.get_transitions(), aut.num_action_labels(), aut.tau_label_index(), aut.num_states());
534}
535
536/* YYYYY
537inline void group_transitions_on_tgt_lbl_recursive(std::vector<transition>& transitions,
538 const std::size_t number_of_labels,
539 const std::size_t tau_label_index,
540 const std::size_t number_of_states,
541 const std::size_t bit_position,
542 std::vector<std::size_t>& todo_stack,
543 std::vector<std::pair<std::size_t, std::size_t>> count_sum_transitions_per_value
544 )
545{
546 constexpr size_t shift=11;
547 constexpr size_t mask= (1<<shift)-1;
548 std::vector<std::pair<std::size_t, std::size_t>> count_sum_transitions_per_action(mask+1, {0,0});
549 std::vector<std::size_t> todo_stack;
550
551 std::vector<std::pair<std::size_t, std::size_t>> value_sum_counter(mask+1, {0,0});
552 std::vector<transition>::iterator begin=transitions.begin();
553 for(std::size_t label: todo_stack)
554 {
555
556 group_transitions_on_label(transitions.begin(),
557 transitions.end(),
558 [](const transition& t){ return t.to() & mask; },
559 count_sum_transitions_per_action,
560 tau_label_index,
561 todo_stack);
562
563
564//std::cerr << "HIER\n";
565 std::vector<std::size_t> todo_stack_target;
566 // std::vector<std::size_t> value_counter(number_of_states,0);
567 std::vector<std::pair<std::size_t, std::size_t>> value_sum_counter(mask+1, {0,0});
568
569*/
570
571
577inline void sort_transitions(std::vector<transition>& transitions, transition_sort_style ts = src_lbl_tgt)
578{
579 sort_transitions(transitions, std::set<transition::size_type>(), ts);
580}
581
582
583namespace detail
584{
585
586// An indexed sorted vector below contains the outgoing or incoming transitions per state,
587// grouped per state. The input consists of a vector of transitions. The incoming/outcoming
588// tau transitions are grouped by state in the m_states_with_outgoing_or_incoming_transition.
589// It is as long as the lts aut has transitions. The vector m_indices is as long as the number
590// of states plus 1. For each state it contains the place in the other vector where its tau transitions
591// start. So, the tau transitions reside at position indices[s] to indices[s+1]. These indices
592// can be acquired using the functions lowerbound and upperbound.
593// This data structure is chosen due to its minimal memory and time footprint.
594template <class CONTENT>
596{
597 protected:
598 typedef std::size_t state_type;
599 typedef std::size_t label_type;
600 typedef std::pair<label_type,state_type> label_state_pair;
601
603 std::vector <size_t> m_indices;
604
605 public:
606
607 indexed_sorted_vector_for_transitions(const std::vector < transition >& transitions , state_type num_states, bool outgoing)
608 : m_indices(num_states+1,0)
609 {
610 // First count the number of outgoing transitions per state and put it in indices.
611 for(const transition& t: transitions)
612 {
613 m_indices[outgoing?t.from():t.to()]++;
614 }
615
616 // Calculate the m_indices where the states with outgoing/incoming tau transition must be placed.
617 // Put the starting index for state i at position i-1. When placing the transitions these indices
618 // are decremented properly.
619
620 size_t sum=0;
621 for(state_type& i: m_indices) // The vector is changed. This must be a reference.
622 {
623 sum=sum+i;
624 i=sum;
625 }
626
627 // Now declare enough space for all transitions and store them in reverse order, while
628 // at the same time decrementing the indices in m_indices.
630 for(const transition& t: transitions)
631 {
632 if (outgoing)
633 {
634 assert(t.from()<m_indices.size());
635 assert(m_indices[t.from()]>0);
636 m_indices[t.from()]--;
639 }
640 else
641 {
642 assert(t.to()<m_indices.size());
643 assert(m_indices[t.to()]>0);
644 m_indices[t.to()]--;
647 }
648 }
649 assert(m_indices.at(num_states)==m_states_with_outgoing_or_incoming_transition.size());
650 }
651
652 // Get the indexed transitions.
653 const std::vector<CONTENT>& get_transitions() const
654 {
656 }
657
658 // Get the lowest index of incoming/outging transitions stored in m_states_with_outgoing_or_incoming_transition.
659 size_t lowerbound(const state_type s) const
660 {
661 assert(s+1<m_indices.size());
662 return m_indices[s];
663 }
664
665 // Get 1 beyond the higest index of incoming/outging transitions stored in m_states_with_outgoing_or_incoming_transition.
666 size_t upperbound(const state_type s) const
667 {
668 assert(s+1<m_indices.size());
669 return m_indices[s+1];
670 }
671
672 // Drastically clear the vectors by resetting its memory usage to minimal.
673 void clear()
674 {
675 std::vector <state_type>().swap(m_states_with_outgoing_or_incoming_transition);
676 std::vector <size_t>().swap(m_indices);
677
678 }
679};
680
681} // end namespace detail
682
683//
685typedef std::pair<transition::size_type, transition::size_type> outgoing_pair_t;
686
687typedef detail::indexed_sorted_vector_for_transitions < outgoing_pair_t > outgoing_transitions_per_state_t;
688
690inline std::size_t label(const outgoing_pair_t& p)
691{
692 return p.first;
693}
694
696inline std::size_t to(const outgoing_pair_t& p)
697{
698 return p.second;
699}
700
702// It can be considered to replace this function with an unordered_multimap.
703// This may increase memory requirements, but would allow for constant versus logarithmic access times
704// of elements.
705typedef std::multimap<std::pair<transition::size_type, transition::size_type>, transition::size_type>
707
709inline std::size_t from(const outgoing_transitions_per_state_action_t::const_iterator& i)
710{
711 return i->first.first;
712}
713
715inline std::size_t label(const outgoing_transitions_per_state_action_t::const_iterator& i)
716{
717 return i->first.second;
718}
719
721inline std::size_t to(const outgoing_transitions_per_state_action_t::const_iterator& i)
722{
723 return i->second;
724}
725
728{
730 for (const transition& t: trans)
731 {
732 result.insert(std::pair<std::pair<transition::size_type, transition::size_type>, transition::size_type>(
733 std::pair<transition::size_type, transition::size_type>(t.from(), t.label()), t.to()));
734 }
735 return result;
736}
737
740 const std::vector<transition>& trans,
741 const std::set<transition::size_type>& hide_label_set)
742{
744 for (const transition& t: trans)
745 {
746 result.insert(std::pair<std::pair<transition::size_type, transition::size_type>, transition::size_type>(
747 std::pair<transition::size_type, transition::size_type>(t.from(), detail::apply_hidden_labels(t.label(),hide_label_set)), t.to()));
748 }
749 return result;
750}
751
754{
756 for (const transition& t: trans)
757 {
758 result.insert(std::pair<std::pair<transition::size_type, transition::size_type>, transition::size_type>(
759 std::pair<transition::size_type, transition::size_type>(t.to(), t.label()), t.from()));
760 }
761 return result;
762}
763
766 const std::vector<transition>& trans,
767 const std::set<transition::size_type>& hide_label_set)
768{
770 for (const transition& t: trans)
771 {
772 result.insert(std::pair<std::pair<transition::size_type, transition::size_type>, transition::size_type>(
773 std::pair<transition::size_type, transition::size_type>(t.to(), detail::apply_hidden_labels(t.label(),hide_label_set)), t.from()));
774 }
775 return result;
776}
777
778namespace detail
779{
780// Yields a label with an obscure name referring to divergence.
781
782template < class LABEL_TYPE >
783// LABEL_TYPE make_divergence_label(const std::string& s, const LABEL_TYPE& l)
784LABEL_TYPE make_divergence_label(const std::string& s)
785{
786 return LABEL_TYPE(s);
787}
788
789template <>
790inline mcrl2::lts::action_label_lts make_divergence_label<mcrl2::lts::action_label_lts>(const std::string& s)
791{
795}
796
797// Make a new divergent_transition_label and replace each self loop with it.
798// Return the number of the divergent transition label.
799template < class LTS_TYPE >
801{
802 // Below we create an odd action label, representing divergence.
803 const typename LTS_TYPE::action_label_t lab=make_divergence_label<typename LTS_TYPE::action_label_t>("!@*&divergence&*@!");
804 std::size_t divergent_transition_label=l.add_action(lab);
805 assert(divergent_transition_label+1==l.num_action_labels());
806 for(transition& t: l.get_transitions())
807 {
808 if (l.is_tau(l.apply_hidden_label_map(t.label())) && t.to()==t.from())
809 {
810 t = transition(t.to(),divergent_transition_label,t.to());
811 }
812 }
813 return divergent_transition_label;
814}
815
816// Replace each transition in a state that is an outgoing divergent_transition with a tau_loop in that state.
817template < class LTS_TYPE >
818void unmark_explicit_divergence_transitions(LTS_TYPE& l, const std::size_t divergent_transition_label)
819{
820 for(transition& t: l.get_transitions())
821 {
822 if (t.label()==divergent_transition_label)
823 {
824 t = transition(t.from(),l.tau_label_index(),t.from());
825 }
826 }
827}
828
829} // namespace detail
830
831}
832}
833
834#endif // MCRL2_LTS_LTS_UTILITIES_H
Term containing a string.
A list of aterm objects.
Definition aterm_list.h:24
\brief A timed multi-action
A class containing the values for action labels for the .lts format.
Definition lts_lts.h:144
std::pair< label_type, state_type > label_state_pair
indexed_sorted_vector_for_transitions(const std::vector< transition > &transitions, state_type num_states, bool outgoing)
const std::vector< CONTENT > & get_transitions() const
A class containing triples, source label and target representing transitions.
Definition transition.h:48
size_type from() const
The source of the transition.
Definition transition.h:89
size_type label() const
The label of the transition.
Definition transition.h:95
size_type to() const
The target of the transition.
Definition transition.h:102
std::size_t size_type
The type of the elements in a transition.
Definition transition.h:51
\brief An action label
Standard exception class for reporting runtime errors.
Definition exception.h:27
This file contains a class that contains labelled transition systems in lts (mcrl2) format.
void unmark_explicit_divergence_transitions(LTS_TYPE &l, const std::size_t divergent_transition_label)
LABEL_TYPE make_divergence_label(const std::string &s)
std::size_t mark_explicit_divergence_transitions(LTS_TYPE &l)
std::size_t apply_hidden_labels(const std::size_t n, const std::set< std::size_t > &hidden_action_set)
Definition transition.h:25
transition_sort_style
Transition sort styles.
Definition transition.h:35
std::multimap< std::pair< transition::size_type, transition::size_type >, transition::size_type > outgoing_transitions_per_state_action_t
Type for exploring transitions per state and action.
outgoing_transitions_per_state_action_t transitions_per_outgoing_state_action_pair_reversed(const std::vector< transition > &trans)
Provide the transitions as a multimap accessible per from state and label, ordered backwardly.
void group_transitions_on_label_tgt(std::vector< transition > &transitions, const std::size_t number_of_labels, const std::size_t tau_label_index, const std::size_t number_of_states)
static std::vector< std::size_t > bogus_todo_stack
std::size_t to(const outgoing_pair_t &p)
Target state of a label state pair.
outgoing_transitions_per_state_action_t transitions_per_outgoing_state_action_pair(const std::vector< transition > &trans)
Provide the transitions as a multimap accessible per from state and label.
void sort_transitions(std::vector< transition > &transitions, const std::set< transition::size_type > &hidden_label_set, transition_sort_style ts=src_lbl_tgt)
Sorts the transitions using a sort style.
void group_transitions_on_tgt_label(std::vector< transition > &transitions, const std::size_t number_of_labels, const std::size_t tau_label_index, const std::size_t number_of_states)
detail::indexed_sorted_vector_for_transitions< outgoing_pair_t > outgoing_transitions_per_state_t
std::string ptr(const transition t)
Sorts the transitions on labels. Action with the tau label are put first.
std::size_t label(const outgoing_pair_t &p)
Label of a pair of a label and target state.
std::size_t from(const outgoing_transitions_per_state_action_t::const_iterator &i)
From state of an iterator exploring transitions per outgoing state and action.
void group_transitions_on_label(const std::vector< transition >::iterator begin, const std::vector< transition >::iterator end, std::function< std::size_t(const transition &)> get_label, std::vector< std::pair< std::size_t, std::size_t > > &count_sum_transitions_per_action, const std::size_t tau_label_index=0, std::vector< std::size_t > &todo_stack=bogus_todo_stack)
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
void swap(atermpp::unprotected_aterm_core &t1, atermpp::unprotected_aterm_core &t2) noexcept
Swaps two aterms.
Definition aterm.h:462