mCRL2
Loading...
Searching...
No Matches
liblts_bisim_gjkw.h
Go to the documentation of this file.
1// Author(s): David N. Jansen, Radboud Universiteit, Nijmegen, The Netherlands
2//
3// Copyright: see the accompanying file COPYING or copy at
4// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
5//
6// Distributed under the Boost Software License, Version 1.0.
7// (See accompanying file LICENSE_1_0.txt or copy at
8// http://www.boost.org/LICENSE_1_0.txt)
9
10/// \file lts/detail/liblts_bisim_gjkw.h
11///
12/// \brief O(m log n)-time stuttering equivalence algorithm
13///
14/// \details This file implements the efficient partition refinement algorithm
15/// by Groote / Jansen / Keiren / Wijs to calculate the stuttering equivalence
16/// quotient of a Kripke structure. (Labelled transition systems are converted
17/// to Kripke structures before the main algorithm).
18/// The file accompanies the planned publication in the ACM Trans. Comput. Log.
19/// Log. special issue for TACAS 2016, to appear in 2017.
20///
21/// \author David N. Jansen, Radboud Universiteit, Nijmegen, The Netherlands
22
23#ifndef MCRL2_LTS_DETAIL_LIBLTS_BISIM_GJKW_H
24#define MCRL2_LTS_DETAIL_LIBLTS_BISIM_GJKW_H
25
26#include <unordered_map> // used during initialisation
27#include <list> // for the list of B_to_C_descriptors
28#include <utility> // for std::cmp_less_equal
29
30#include "mcrl2/lts/detail/liblts_scc.h"
31#include "mcrl2/lts/detail/liblts_merge.h"
32#include "mcrl2/lts/detail/check_complexity.h"
33#include "mcrl2/lts/detail/fixed_vector.h"
34
35namespace mcrl2::lts::detail
36{
37// The bisimulation algorithm below is hand-tuned and deliberately uses helper
38// macros such as ONLY_IF_DEBUG. This check is therefore suppressed for the
39// whole file.
40// NOLINTBEGIN(cppcoreguidelines-macro-usage)
41 #ifndef NDEBUG
42 /// \cond INTERNAL_DOCS
43 /// \brief include something in Debug mode
44 /// \details In a few places, we have to include an additional parameter to
45 /// a function in Debug mode. While it is in principle possible to use
46 /// #ifndef NDEBUG ... #endif, that would lead to distributing the code
47 /// over many code lines. This macro expands to its arguments in Debug
48 /// mode and to nothing otherwise.
49 #define ONLY_IF_DEBUG(...) __VA_ARGS__
50 /// \endcond
51 #else
52 #define ONLY_IF_DEBUG(...)
53 #endif
54// state_type and trans_type are defined in check_complexity.h.
55
56/// \brief type used to store label numbers and counts
58
59/* ************************************************************************* */
60/* */
61/* R E F I N A B L E P A R T I T I O N */
62/* */
63/* ************************************************************************* */
64
65
66
67
68
69/// \defgroup part_state Data structures for states
70/// \details The following definitions provide a _refinable partition_ data
71/// structure. The basic idea is that we store a permutation of the states (in
72/// a permutation_t array), so that states belonging to the same block are
73/// adjacent, and also that blocks belonging to the same constellation are
74/// adjacent.
75///
76/// The basic structure therefore consists of the classes:
77///
78/// state_info_ptr - an entry in the permutation array; it contains a
79/// pointer to a state_info_entry.
80/// permutation_t - an array of permutation_entries.
81/// constln_t - contains information about a constellation, in
82/// particular which slice of permutation_t contains its
83/// states.
84/// block_t - contains information about a block, in particular which
85/// slice of permutation_t contains its states, and its
86/// constellation.
87/// state_info_entry - contains information about a state, in particular its
88/// position in the permutation_t array and its block.
89/// state_info_t - an array of state_info_entries.
90/// part_state_t - the complete data structure combining state_info_t and
91/// permutation_t.
92///
93/// This basic structure is extended as follows:
94/// - Because we combine this data structure with a partition of the
95/// transitions, a state_info_entry also contains information which slice of
96/// the incoming and outgoing, inert and non-inert transitions belong to the
97/// state. In many cases the slice of this state ends exactly where the
98/// slice of the next state begins, so we can find the end of this state's
99/// slice by looking at the next state's state_info_entry. Therefore,
100/// state_info_ptr actually contains a pointer to a state_info_entry with
101/// the additional guarantee that this is not the last entry in state_info_t.
102/// (To make this a small bit more type safe, we could change the type
103/// state_info_ptr to something like "pointer to an array with two
104/// state_info_entries", typedef state_info_entry (*state_info_ptr)[2];.
105/// Still, that would allow unsafe pointer juggling.)
106/// - A block_t also contains information about its outgoing inert transitions.
107/// - A state_info_entry also contains information used during `refine()` or
108/// `process_new_bottom()`.
109///@{
110
111namespace bisim_gjkw
112{
113
114class state_info_entry;
115
116using state_info_ptr = state_info_entry*;
117using state_info_const_ptr = const state_info_entry*;
118
119/// \class permutation_t
120/// \brief stores a permutation of the states, ordered by block
121/// \details This is the central concept of the _refinable partition_: the
122/// permutation of the states, such that states belonging to the same block are
123/// adjacent, and also that blocks belonging to the same constellation are
124/// adjacent.
125///
126/// Iterating over the states of a block or the blocks of a constellation will
127/// therefore be done using the permutation_t array.
128using permutation_t = fixed_vector<state_info_ptr>;
131
132class block_t;
133class constln_t;
134
135class B_to_C_entry;
136class pred_entry;
137class succ_entry;
141
145class B_to_C_descriptor;
149
150/// \class state_info_entry
151/// \brief stores information about a single state
152/// \details This class stores all other information about a state that the
153/// partition needs. In particular: the block where the state belongs and the
154/// position in the permutation array (i. e. the inverse of the permutation).
155///
156/// A `state_info_entry` only works correctly if it is part of an array where
157/// there is one more `state_info_entry`. The reason is that iterators past
158/// the last transition are not actually stored here, as they are equal to the
159/// iterator to the first transition of the next state. The array will contain
160/// one additional "state" that is only used for these pointers.
161class state_info_entry
162{
163 private:
164 /// \brief iterator to first incoming transition
165 /// \details also serves as iterator past the last incoming transition of
166 /// the previous state.
167 pred_iter_t state_in_begin;
168
169 /// \brief iterator to first outgoing transition
170 /// \details also serves as iterator past the last outgoing transition of
171 /// the previous state.
172 succ_iter_t state_out_begin;
173
174 /// iterator to first _inert_ incoming transition
175 pred_iter_t state_inert_in_begin;
176
177 /// iterator to first _inert_ outgoing transition
178 succ_iter_t state_inert_out_begin;
179
180 /// iterator past the last _inert_ outgoing transition
181 succ_iter_t state_inert_out_end;
182 public:
183 /// block where the state belongs
184 block_t* block = nullptr;
185
186 /// position of the state in the permutation array
187 permutation_iter_t pos;
188
189 /// number of inert transitions to non-blue states
190 state_type notblue = 0UL;
191 private:
192 /// iterator to first outgoing transition to the constellation of interest
193 succ_iter_t int_current_constln;
194 public:
195 /// get constellation where the state belongs
196 const constln_t* constln() const;
197 constln_t* constln();
198
199 succ_const_iter_t current_constln() const { return int_current_constln; }
200 succ_iter_t current_constln() { return int_current_constln; }
201 void set_current_constln(succ_iter_t const new_current_constln)
202 {
203 int_current_constln = new_current_constln; // current_constln points to a successor transition of this state:
204 assert(succ_begin() <= int_current_constln);
205 assert(int_current_constln <= succ_end());
206 // it points to a place where a constellation slice starts or ends:
207 // (This assertion cannot be tested because the types are not yet
208 // complete.)
209 // assert(succ_begin() == int_current_constln ||
210 // succ_end() == int_current_constln ||
211 // int_current_constln[-1].constln_slice !=
212 // int_current_constln->constln_slice);
213 // it points to the relevant constellation:
214 // The following assertions cannot be executed immediately after each
215 // call.
216 // assert(succ_begin() == current_constln() ||
217 // *current_constln()[-1].target->constln() <= *SpC);
218 // assert(succ_end() == current_constln() ||
219 // *SpC <= *current_constln()->target->constln());
220 }
221
222 /// iterator to first incoming transition
223 pred_const_iter_t pred_begin() const { return state_in_begin; }
224 pred_iter_t pred_begin() { return state_in_begin; }
225 void set_pred_begin(pred_iter_t new_in_begin)
226 {
227 state_in_begin = new_in_begin;
228 }
229
230 /// iterator past the last incoming transition
231 pred_const_iter_t pred_end() const
232 { assert(s_i_begin <= this); assert(this < s_i_end);
233 return this[1].state_in_begin;
234 }
235 pred_iter_t pred_end()
236 { assert(s_i_begin <= this); assert(this < s_i_end);
237 return this[1].state_in_begin;
238 }
239 void set_pred_end(pred_iter_t new_in_end)
240 { assert(s_i_begin <= this); assert(this < s_i_end);
241 this[1].set_pred_begin(new_in_end);
242 }
243
244 /// iterator to first non-inert incoming transition
245 pred_const_iter_t noninert_pred_begin() const { return state_in_begin; }
246 pred_iter_t noninert_pred_begin() { return state_in_begin; }
247
248 /// iterator past the last non-inert incoming transition
249 pred_const_iter_t noninert_pred_end() const { return inert_pred_begin(); }
250 pred_iter_t noninert_pred_end() { return inert_pred_begin(); }
251
252 /// iterator to first inert incoming transition
253 pred_const_iter_t inert_pred_begin() const { return state_inert_in_begin; }
254 pred_iter_t inert_pred_begin() { return state_inert_in_begin; }
255 void set_inert_pred_begin(pred_iter_t new_inert_in_begin)
256 {
257 state_inert_in_begin = new_inert_in_begin; assert(pred_begin() <= inert_pred_begin());
258 assert(inert_pred_begin() <= pred_end());
259 }
260
261 /// iterator one past the last inert incoming transition
262 pred_const_iter_t inert_pred_end() const { return pred_end(); }
263 pred_iter_t inert_pred_end() { return pred_end(); }
264
265 /// iterator to first outgoing transition
266 succ_const_iter_t succ_begin() const { return state_out_begin; }
267 succ_iter_t succ_begin() { return state_out_begin; }
268 void set_succ_begin(succ_iter_t new_out_begin)
269 {
270 state_out_begin = new_out_begin;
271 }
272
273 /// iterator past the last outgoing transition
274 succ_const_iter_t succ_end() const
275 { assert(s_i_begin <= this); assert(this < s_i_end);
276 return this[1].state_out_begin;
277 }
278 succ_iter_t succ_end()
279 { assert(s_i_begin <= this); assert(this < s_i_end);
280 return this[1].state_out_begin;
281 }
282 void set_succ_end(succ_iter_t new_out_end)
283 { assert(s_i_begin <= this); assert(this < s_i_end);
284 this[1].set_succ_begin(new_out_end); assert(succ_begin() <= succ_end());
285 }
286
287 /// iterator to first inert outgoing transition
288 succ_const_iter_t inert_succ_begin() const {return state_inert_out_begin;}
289 succ_iter_t inert_succ_begin() { return state_inert_out_begin; }
290 void set_inert_succ_begin(succ_iter_t const new_inert_out_begin)
291 { // The following assertions cannot be tested because the respective
292 // types are not yet complete.
293 // if (new_inert_out_begin > inert_succ_begin())
294 // {
295 // assert(*new_inert_out_begin[-1].target->constln()<=*constln());
296 // assert(new_inert_out_begin[-1].target->block != block);
297 // }
298 // else if (new_inert_out_begin < inert_succ_begin())
299 // {
300 // assert(new_inert_out_begin->target->block == block);
301 // }
302 state_inert_out_begin = new_inert_out_begin; assert(succ_begin() <= inert_succ_begin());
303 assert(inert_succ_begin() <= inert_succ_end());
304 }
305
306 /// iterator past the last inert outgoing transition
307 succ_const_iter_t inert_succ_end() const { return state_inert_out_end; }
308 succ_iter_t inert_succ_end() { return state_inert_out_end; }
309
310 void set_inert_succ_begin_and_end(succ_iter_t new_inert_out_begin,
311 succ_iter_t new_inert_out_end)
312 {
313 state_inert_out_begin = new_inert_out_begin;
314 state_inert_out_end = new_inert_out_end; assert(succ_begin() <= inert_succ_begin());
315 assert(inert_succ_begin() <= inert_succ_end());
316 assert(inert_succ_end() <= succ_end());
317 // The following assertions cannot be tested always, as the function
318 // may be called earlier than the assertions are reestablished.
319 // assert(succ_begin() == inert_succ_begin() ||
320 // *inert_succ_begin()[-1].target->constln() <= *constln());
321 // assert(succ_begin() == inert_succ_begin() ||
322 // inert_succ_begin()[-1].target->block != block);
323 // assert(inert_succ_begin() == inert_succ_end() ||
324 // (inert_succ_begin()->target->block == block &&
325 // inert_succ_end()[-1].target->block == block));
326 // assert(succ_end() == inert_succ_end() ||
327 // *constln() < *inert_succ_end()->target->constln());
328 }
329
330 bool surely_has_transition_to(const constln_t* SpC) const;
331 bool surely_has_no_transition_to(const constln_t* SpC) const;
332 #ifndef NDEBUG
333 /// \brief print a short state identification for debugging
334 /// \details This function is only available if compiled in Debug mode.
335 std::string debug_id_short() const
336 {
337 assert(s_i_begin <= this);
338 assert(this < s_i_end);
339 return std::to_string(this - s_i_begin);
340 }
341
342 /// \brief print a state identification for debugging
343 /// \details This function is only available if compiled in Debug mode.
344 std::string debug_id() const
345 {
346 return "state " + debug_id_short();
347 }
348 private:
349 /// \brief pointer at the first entry in the `state_info` array
350 static state_info_const_ptr s_i_begin;
351
352 /// \brief pointer past the last actual entry in the `state_info` array
353 /// \details `state_info` actually contains an additional entry that is
354 /// only used partially, namely to store pointers to the end of the
355 /// transition slices of the last state. In other words, `s_i_end` points
356 /// at this additional, partially used entry.
357 static state_info_const_ptr s_i_end;
358
359 friend class part_state_t;
360 public:
361 #endif
362 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
363 mutable check_complexity::state_counter_t work_counter;
364 #endif
365};
366
367
368/// swap two permutations
369static inline void swap_permutation(permutation_iter_t s1,
370 permutation_iter_t s2)
371{
372 // swap contents of permutation array
373 std::swap(*s1, *s2);
374 // swap pointers to permutation array
375 (*s1)->pos = s1;
376 (*s2)->pos = s2;
377}
378
379/// \class block_t
380/// \brief stores information about a block
381/// \details A block corresponds to a slice of the permutation array. As the
382/// number of blocks is initially unknown, we will allocate instances of this
383/// class dynamically.
384///
385/// The slice in the permutation array containing the states of the block is
386/// subdivided into the following subslices (in this order):
387/// 1. unmarked non-bottom states
388/// 2. marked non-bottom states (initially empty)
389/// 3. unmarked bottom states
390/// 4. marked bottom states (initially empty)
391///
392/// A state should be marked iff it is a predecessor of the current splitter
393/// (through a strong transition). The marking is later extended to the red
394/// states; that are the states with a weak transition to the splitter.
395///
396/// (During the execution of some functions, more slices are subdivided
397/// further; however, as these subdivisions are local to a single function,
398/// they are not stored here.)
399///
400/// The blocks keep track of the total number of blocks allocated and number
401/// themselves sequentially using the static member `nr_of_blocks`. It is
402/// therefore impossible to have multiple refinements running at the same time.
403class block_t
404{
405 private:
406 /// iterator past the last state of the block
407 permutation_iter_t int_end;
408
409 /// iterator to the first state of the block
410 permutation_iter_t int_begin;
411
412 /// iterator to the first marked non-bottom state of the block
413 permutation_iter_t int_marked_nonbottom_begin;
414
415 /// iterator to the first bottom state of the block
416 permutation_iter_t int_bottom_begin;
417
418 /// iterator to the first marked bottom state of the block
419 permutation_iter_t int_marked_bottom_begin;
420
421 /// \brief iterator to the first inert transition of the block
422 /// \details If there are no inert transitions, then `inert_begin` and
423 /// `inert_end` point to the end of the B_to_C-slice containing transitions
424 /// from the block to its own constellation. If there is no such slice,
425 /// both are equal to `B_to_C`.
426 B_to_C_iter_t int_inert_begin;
427
428 /// iterator past the last inert transition of the block
429 B_to_C_iter_t int_inert_end;
430 public:
431 /// \brief list of B_to_C with transitions from this block
432 /// \details This list serves two purposes: it contains all
433 /// B_to_C_descriptors, so that the constellations reachable from this
434 /// block can be found; and if this block has transitions to the current
435 /// splitter SpC\\SpB, then the first element of the list points to these
436 /// transitions.
437 B_to_C_desc_list to_constln;
438 private:
439 /// constellation to which the block belongs
440 constln_t* int_constln;
441
442 /// \brief next block in the list of refinable blocks
443 /// \details If this is the last block in the list, `refinable_next` points
444 /// to this very block. Consequently, it is possible to check whether some
445 /// block is refinable without an additional variable.
446 block_t* refinable_next = nullptr;
447
448 /// first block in the list of refinable blocks
449 static block_t* refinable_first;
450
451 /// \brief unique sequence number of this block
452 /// \details After the stuttering equivalence algorithm has terminated,
453 /// this number is used as a state number in the quotient Kripke structure.
454 /// (For blocks that contain extra Kripke states, the number is set to
455 /// BLOCK_NO_SEQNR).
456 state_type int_seqnr = BLOCK_NO_SEQNR;
457
458 public:
459 /// \brief value of int_seqnr indicating that no sequence number has been
460 /// assigned yet
461 [[maybe_unused]] static constexpr state_type BLOCK_NO_SEQNR = (state_type) -1;
462
463 /// \brief total number of blocks with unique sequence number allocated
464 /// \details Upon starting the stuttering equivalence algorithm, the number
465 /// of blocks must be zero.
466 static state_type nr_of_blocks;
467
468 /// \brief constructor
469 /// \details The constructor initialises the block to: all states are
470 /// bottom states, no state is marked, the block is not refinable.
471 /// \param constln_ constellation to which the block belongs
472 /// \param begin_ initial iterator to the first state of the block
473 /// \param end_ initial iterator past the last state of the block
474 block_t(constln_t* const constln_, permutation_iter_t const begin_, permutation_iter_t const end_)
475 : int_end(end_),
476 int_begin(begin_),
477 int_marked_nonbottom_begin(begin_), // no non-bottom state is marked
478 int_bottom_begin(begin_), // all states are bottom states
479 int_marked_bottom_begin(end_), // no bottom state is marked
480 // int_inert_begin -- is initialised by part_trans_t::create_new_block
481 // int_inert_end -- is initialised by part_trans_t::create_new_block
482 to_constln(), // empty list
483 int_constln(constln_)
484
485
486 { // The following assertions hold trivially.
487 // assert(int_begin <= int_marked_nonbottom_begin);
488 // assert(int_marked_nonbottom_begin <= int_bottom_begin);
489 // assert(int_bottom_begin <= int_marked_bottom_begin);
490 // assert(int_marked_bottom_begin <= int_end);
491 assert(int_bottom_begin < int_end);
492 // The following assertions cannot be tested because constln_t is not
493 // yet complete.
494 // assert(int_constln->begin() <= int_begin);
495 // assert(int_end <= int_constln->end());
496 }
497
498 ~block_t() = default;
499
500 /// assigns a unique sequence number
501 void assign_seqnr()
502 { assert(BLOCK_NO_SEQNR == int_seqnr);
503 int_seqnr = nr_of_blocks++;
504 }
505
506 state_type seqnr() const { return int_seqnr; }
507
508 /// provides an arbitrary refinable block
509 static block_t* get_some_refinable() { return refinable_first; }
510
511 /// \brief checks whether the block is refinable
512 /// \returns true if the block is refinable
513 bool is_refinable() const { return nullptr != refinable_next; }
514
515 /// \brief makes a block refinable (i. e. inserts it into the respective
516 /// list)
517 /// \returns true if the block was not refinable before
518 bool make_refinable()
519 {
520 if (is_refinable())
521 {
522 return false;
523 }
524 refinable_next = nullptr == refinable_first ? this : refinable_first;
525 refinable_first = this;
526 return true;
527 }
528
529 /// \brief makes a block non-refinable (i. e. removes it from the
530 /// respective list)
531 /// \details This member function only works if the block is the first one
532 /// in the list (which will normally be the case).
533 void make_nonrefinable()
534 { assert(refinable_first == this);
535 refinable_first = refinable_next == this ? nullptr : refinable_next;
536 refinable_next = nullptr;
537 }
538
539 /// provides the number of states in the block
540 state_type size() const { return int_end - int_begin; }
541
542 /// \brief provides the number of marked bottom states in the block
543 /// \details This size includes the old bottom states.
544 state_type marked_bottom_size() const
545 {
546 return marked_bottom_end() - marked_bottom_begin();
547 }
548
549 /// \brief provides the number of marked states in the block
550 /// \details This size includes the old bottom states; in other words, the
551 /// old bottom states are always regarded as marked.
552 state_type marked_size() const
553 {
554 return marked_nonbottom_end() - marked_nonbottom_begin() +
555 marked_bottom_size();
556 }
557
558 /// provides the number of unmarked bottom states in the block
559 state_type unmarked_bottom_size() const
560 {
561 return unmarked_bottom_end() - unmarked_bottom_begin();
562 }
563
564 /// \brief compares two blocks for ordering them
565 /// \details The blocks are ordered according to their positions in the
566 /// permutation array. This is a suitable order, as blocks may be refined,
567 /// but never swap positions as a whole. Refining will make the new
568 /// subblocks compare in the same way to other blocks as the original,
569 /// larger block.
570 bool operator<(const block_t& other) const
571 {
572 return begin() < other.begin();
573 }
574
575 /// constellation where the block belongs to
576 const constln_t* constln() const { return int_constln; }
577 constln_t* constln() { return int_constln; }
578 void set_constln(constln_t* new_constln)
579 { // The following assertion cannot be tested because the type constln_t
580 int_constln = new_constln; // is not yet complete.
581 // assert(nullptr == int_constln ||
582 // (int_constln->begin() <= int_begin &&
583 // int_end <= int_constln->end()));
584 }
585
586 /// read FromRed
587 B_to_C_descriptor* FromRed(const constln_t* SpC);
588
589 /// set FromRed to an existing element in to_constln
590 void SetFromRed(B_to_C_desc_iter_t new_fromred);
591
592 /// iterator to the first state in the block
593 permutation_const_iter_t begin() const { return int_begin; }
594 permutation_iter_t begin() { return int_begin; }
595 void set_begin(permutation_iter_t new_begin)
596 {
597 int_begin = new_begin; assert(int_begin <= int_marked_nonbottom_begin);
598 }
599
600 /// iterator past the last state in the block
601 permutation_const_iter_t end() const { return int_end; }
602 permutation_iter_t end() { return int_end; }
603 void set_end(permutation_iter_t new_end)
604 {
605 int_end = new_end; assert(int_marked_bottom_begin <= int_end); assert(int_bottom_begin < int_end);
606 }
607
608 /// iterator to the first non-bottom state in the block
609 permutation_const_iter_t nonbottom_begin() const { return int_begin; }
610 permutation_iter_t nonbottom_begin() { return int_begin; }
611
612 /// iterator past the last non-bottom state in the block
613 permutation_const_iter_t nonbottom_end() const { return int_bottom_begin; }
614 permutation_iter_t nonbottom_end() { return int_bottom_begin; }
615 void set_nonbottom_end(permutation_iter_t new_nonbottom_end)
616 {
617 int_bottom_begin = new_nonbottom_end; assert(int_marked_nonbottom_begin <= int_bottom_begin);
618 assert(int_bottom_begin <= int_marked_bottom_begin);
619 assert(int_bottom_begin < int_end);
620 }
621
622 /// iterator to the first bottom state in the block
623 permutation_const_iter_t bottom_begin() const { return int_bottom_begin; }
624 permutation_iter_t bottom_begin() { return int_bottom_begin; }
625 void set_bottom_begin(permutation_iter_t new_bottom_begin)
626 {
627 int_bottom_begin = new_bottom_begin; assert(int_marked_nonbottom_begin <= int_bottom_begin);
628 assert(int_bottom_begin <= int_marked_bottom_begin);
629 // assert(int_bottom_begin < int_end);
630 }
631
632 /// iterator past the last bottom state in the block
633 permutation_const_iter_t bottom_end() const { return int_end; }
634 permutation_iter_t bottom_end() { return int_end; }
635
636 /// iterator to the first unmarked non-bottom state in the block
637 permutation_const_iter_t unmarked_nonbottom_begin()const{return int_begin;}
638 permutation_iter_t unmarked_nonbottom_begin() { return int_begin; }
639
640 /// iterator past the last unmarked non-bottom state in the block
641 permutation_const_iter_t unmarked_nonbottom_end() const
642 {
643 return int_marked_nonbottom_begin;
644 }
645 permutation_iter_t unmarked_nonbottom_end()
646 {
647 return int_marked_nonbottom_begin;
648 }
649 void set_unmarked_nonbottom_end(permutation_iter_t
650 new_unmarked_nonbottom_end)
651 {
652 int_marked_nonbottom_begin = new_unmarked_nonbottom_end; assert(int_begin <= int_marked_nonbottom_begin);
653 assert(int_marked_nonbottom_begin <= int_bottom_begin);
654 }
655
656 /// iterator to the first marked non-bottom state in the block
657 permutation_const_iter_t marked_nonbottom_begin() const
658 {
659 return int_marked_nonbottom_begin;
660 }
661 permutation_iter_t marked_nonbottom_begin()
662 {
663 return int_marked_nonbottom_begin;
664 }
665 void set_marked_nonbottom_begin(permutation_iter_t
666 new_marked_nonbottom_begin)
667 {
668 int_marked_nonbottom_begin = new_marked_nonbottom_begin; assert(int_begin <= int_marked_nonbottom_begin);
669 assert(int_marked_nonbottom_begin <= int_bottom_begin);
670 }
671
672 /// iterator one past the last marked non-bottom state in the block
673 permutation_const_iter_t marked_nonbottom_end() const
674 {
675 return int_bottom_begin;
676 }
677 permutation_iter_t marked_nonbottom_end() { return int_bottom_begin; }
678
679 /// iterator to the first unmarked bottom state in the block
680 permutation_const_iter_t unmarked_bottom_begin() const
681 {
682 return int_bottom_begin;
683 }
684 permutation_iter_t unmarked_bottom_begin() { return int_bottom_begin; }
685
686 /// iterator past the last unmarked bottom state in the block
687 permutation_const_iter_t unmarked_bottom_end() const
688 {
689 return int_marked_bottom_begin;
690 }
691 permutation_iter_t unmarked_bottom_end() {return int_marked_bottom_begin;}
692 void set_unmarked_bottom_end(permutation_iter_t new_unmarked_bottom_end)
693 {
694 int_marked_bottom_begin = new_unmarked_bottom_end; assert(int_bottom_begin <= int_marked_bottom_begin);
695 assert(int_marked_bottom_begin <= int_end);
696 }
697
698 /// iterator to the first marked bottom state in the block
699 permutation_const_iter_t marked_bottom_begin() const
700 {
701 return int_marked_bottom_begin;
702 }
703 permutation_iter_t marked_bottom_begin() {return int_marked_bottom_begin;}
704 void set_marked_bottom_begin(permutation_iter_t new_marked_bottom_begin)
705 {
706 int_marked_bottom_begin = new_marked_bottom_begin; assert(int_bottom_begin <= int_marked_bottom_begin);
707 assert(int_marked_bottom_begin <= int_end);
708 }
709
710 /// \brief iterator past the last marked bottom state in the block
711 /// \details This includes the old bottom states.
712 permutation_const_iter_t marked_bottom_end() const { return int_end; }
713 permutation_iter_t marked_bottom_end() { return int_end; }
714
715 /// iterator to the first inert transition of the block
716 B_to_C_const_iter_t inert_begin() const { return int_inert_begin; }
717 B_to_C_iter_t inert_begin() { return int_inert_begin; }
718 void set_inert_begin(B_to_C_iter_t new_inert_begin)
719 {
720 int_inert_begin = new_inert_begin; assert(int_inert_begin <= int_inert_end);
721 }
722
723 /// iterator past the last inert transition of the block
724 B_to_C_const_iter_t inert_end() const { return int_inert_end; }
725 B_to_C_iter_t inert_end() { return int_inert_end; }
726 void set_inert_end(B_to_C_iter_t new_inert_end)
727 {
728 int_inert_end = new_inert_end; assert(int_inert_begin <= int_inert_end);
729 }
730 void set_inert_begin_and_end(B_to_C_iter_t new_inert_begin,
731 B_to_C_iter_t new_inert_end)
732 {
733 int_inert_begin = new_inert_begin;
734 int_inert_end = new_inert_end; assert(int_inert_begin <= int_inert_end);
735 }
736
737 /// \brief mark a non-bottom state
738 /// \details Marking is done by moving the state to the slice of the marked
739 /// non-bottom states of the block.
740 /// \param s the non-bottom state that has to be marked
741 /// \returns true if the state was not marked before
742 bool mark_nonbottom(state_info_ptr s)
743 { assert(s->pos < nonbottom_end()); assert(nonbottom_begin() <= s->pos);
744 if (marked_nonbottom_begin() <= s->pos)
745 {
746 return false;
747 }
748 set_marked_nonbottom_begin(marked_nonbottom_begin() - 1);
749 swap_permutation(s->pos, marked_nonbottom_begin());
750 return true;
751 }
752
753 /// \brief mark a state
754 /// \details Marking is done by moving the state to the slice of the marked
755 /// bottom or non-bottom states of the block. If `s` is an old bottom
756 /// state, it is treated as if it already were marked.
757 /// \param s the state that has to be marked
758 /// \returns true if the state was not marked before
759 bool mark(state_info_ptr s)
760 { assert(s->pos < end());
761 if (bottom_begin() <= s->pos)
762 {
763 if (marked_bottom_begin() <= s->pos)
764 {
765 return false;
766 }
767 set_marked_bottom_begin(marked_bottom_begin() - 1);
768 swap_permutation(s->pos, marked_bottom_begin());
769 return true;
770 }
771 return mark_nonbottom(s);
772 }
773
774 /// \brief refine the block (the blue subblock is smaller)
775 /// \details This function is called after a refinement function has found
776 /// that the blue subblock is the smaller one. It creates a new block for
777 /// the blue states.
778 /// \param blue_nonbottom_end iterator past the last blue non-bottom state
779 /// \returns pointer to the new (blue) block
780 block_t* split_off_blue(permutation_iter_t blue_nonbottom_end);
781
782 /// \brief refine the block (the red subblock is smaller)
783 /// \details This function is called after a refinement function has found
784 /// that the red subblock is the smaller one. It creates a new block for
785 /// the red states.
786 ///
787 /// Both `split_off_blue()` and `split_off_red()` unmark all states in the blue
788 /// subblock and mark all bottom states in the red subblock. (This will help
789 /// the caller to distinguish old bottom states from new bottom states found
790 /// after `split_off_blue()` or `split_off_red()`, respectively.) The two
791 /// functions use the same complexity counters because their operations belong
792 /// together.
793 /// \param red_nonbottom_begin iterator to the first red non-bottom state
794 /// \returns pointer to the new (red) block
795 block_t* split_off_red(permutation_iter_t red_nonbottom_begin);
796 #ifndef NDEBUG
797 /// \brief print a block identification for debugging
798 /// \details This function is only available if compiled in Debug mode.
799 std::string debug_id() const
800 {
801 return "block [" + std::to_string(begin() - perm_begin) + "," +
802 std::to_string(end() - perm_begin) + ")" +
803 (BLOCK_NO_SEQNR != seqnr() ?" (#"+std::to_string(seqnr())+")" :"");
804 }
805
806 /// \brief provide an iterator to the beginning of the permutation array
807 /// \details This iterator is required to be able to print identifications
808 /// for debugging. It is only available if compiled in Debug mode.
809 static permutation_const_iter_t permutation_begin() { return perm_begin; }
810 private:
811 static permutation_const_iter_t perm_begin;
812
813 friend class part_state_t;
814 #endif
815 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
816 public:
817 mutable check_complexity::block_counter_t work_counter;
818 #endif
819};
820
821
822/// \class constln_t
823/// \brief stores information about a constellation
824/// \details A constellation corresponds to a slice in the permutation array;
825/// its boundaries are also block boundaries. As the number of constellations
826/// is initially unknown, we will allocate it dynamically.
827class constln_t
828{
829 private:
830 /// iterator past the last state in the constellation
831 permutation_iter_t int_end;
832
833 /// iterator to the first state in the constellation
834 permutation_iter_t int_begin;
835
836 /// \brief next constellation in the list of non-trivial constellations
837 /// \details If this is the last constellation in the list,
838 /// `nontrivial_next` points to this very constellation. Consequently, it
839 /// is possible to check whether some constellation is trivial without an
840 /// additional variable.
841 constln_t* nontrivial_next = nullptr;
842
843 /// first constellation in the list of non-trivial constellations
844 static constln_t* nontrivial_first;
845 public:
846 /// \brief iterator to the first transition into this constellation that
847 /// needs postprocessing
848 /// \details In `postprocess_new_bottom()`, all transitions from a refined
849 /// block to the present constellation have to be gone through. Because
850 /// during this process the refined block may be refined even further, we
851 /// need `postprocess_begin` and `postprocess_end` to store which
852 /// transitions have to be gone through overall.
853 ///
854 /// If no transitions to this constellation need to be postprocessed, the
855 /// variable is set to the same value as postprocess_end, preferably to
856 /// part_trans_t::B_to_C->end().
857 B_to_C_iter_t postprocess_begin;
858
859 /// \brief iterator past the last transition into this constellation that
860 /// needs postprocessing
861 B_to_C_iter_t postprocess_end;
862
863 /// \brief sort key to order constellation-related information
864 /// \details When a constellation is created anew, it it assigned a sort
865 /// key that is lower than the constellation it came from, but never lower
866 /// than the sort key of any other constellation that was lower than the
867 /// original constellation. This ensures that the order of other
868 /// constellations does not change.
869 const state_type sort_key;
870
871 /// \brief constructor
872 /// \param begin_ iterator to the first state in the constellation
873 /// \param end_ iterator past the last state in the constellation
874 constln_t(state_type sort_key_, permutation_iter_t begin_, permutation_iter_t end_, B_to_C_iter_t postprocess_none)
875 : int_end(end_),
876 int_begin(begin_),
877
878 postprocess_begin(postprocess_none),
879 postprocess_end(postprocess_none),
880 sort_key(sort_key_)
881 { assert(int_begin<int_end); assert(std::cmp_less_equal(int_end-int_begin, sort_key));
882 }
883
884 /// \brief destructor
885 ~constln_t() = default;
886
887 /// \brief provides an arbitrary non-trivial constellation
888 /// \details The static function is implemented in a way to provide the
889 /// first constellation in the list of non-trivial constellations.
890 static constln_t* get_some_nontrivial() { return nontrivial_first; }
891
892 /// \brief provides the next non-trivial constellation
893 /// \details This (non-static!) function just returns the next non-trivial
894 /// constellation in the list. Note: If this constellation is the last in
895 /// the list of non-trivial constellations, the convention is that the next
896 /// pointer points to this constellation self (to distinguish it from
897 /// nullptr).
898 const constln_t* get_nontrivial_next() const { return nontrivial_next; }
899
900 /// \brief makes a constellation trivial (i. e. removes it from the
901 /// respective list)
902 /// \details This member function only works if the constellation is the
903 /// first one in the list (which will normally be the case).
904 void make_trivial()
905 { assert(nontrivial_first == this);
906 nontrivial_first = nontrivial_next == this ? nullptr : nontrivial_next;
907 nontrivial_next = nullptr;
908 }
909
910 /// \brief makes a constellation non-trivial (i. e. inserts it into the
911 /// respective list)
912 void make_nontrivial()
913 {
914 if (nullptr == nontrivial_next)
915 {
916 nontrivial_next = nullptr == nontrivial_first ? this
917 : nontrivial_first;
918 nontrivial_first = this;
919 }
920 }
921
922 /// \brief returns true iff the constellation is trivial
923 /// \details If this constellation is the last in the list of non-trivial
924 /// constellations, the convention is that the next pointer points to this
925 /// constellation itself (to distinguish it from nullptr).
926 bool is_trivial() const
927 {
928 return nullptr == nontrivial_next;
929 }
930
931 /// \brief constant iterator to the first state in the constellation
932 permutation_const_iter_t begin() const { return int_begin; }
933 /// \brief iterator to the first state in the constellation
934 permutation_iter_t begin() { return int_begin; }
935 /// \brief set the iterator to the first state in the constellation
936 void set_begin(permutation_iter_t new_begin)
937 {
938 int_begin = new_begin; assert(int_begin < int_end);
939 }
940
941 /// \brief constant iterator past the last state in the constellation
942 permutation_const_iter_t end() const { return int_end; }
943 /// \brief iterator past the last state in the constellation
944 permutation_iter_t end() { return int_end; }
945 /// \brief set the iterator past the last state in the constellation
946 void set_end(permutation_iter_t new_end)
947 {
948 int_end = new_end; assert(int_begin < int_end);
949 }
950
951 /// \brief returns number of states in the constellation
952 state_type size() const { return int_end - int_begin; }
953
954 /// \brief compares two constellations for ordering them
955 /// \details Constellations are ordered according to their sort keys. The
956 /// keys have to be assigned in a way that when a constellation is split,
957 /// the parts are placed where the split constellation was in the order.
958 /// This can be achieved by assigning sort keys that are related to the
959 /// size of the constellation.
960 bool operator<(const constln_t& other) const
961 {
962 return sort_key < other.sort_key;
963 }
964 bool operator> (const constln_t& other) const { return other < *this; }
965 bool operator<=(const constln_t& other) const { return !(other < *this); }
966 bool operator>=(const constln_t& other) const { return !(*this < other); }
967
968 /// \brief split off a single block from the constellation
969 /// \details The function splits the current constellation after its first
970 /// block or before its last block, whichever is smaller. It creates a new
971 /// constellation for the split-off block and returns a pointer to the
972 /// block.
973 block_t* split_off_small_block()
974 { assert(begin() < end());
975 block_t* const FirstB = (*begin())->block;
976 block_t* const LastB = end()[-1]->block; assert(FirstB != LastB);
977 if (FirstB->end() == LastB->begin()) { make_trivial(); } assert(FirstB->constln() == this); assert(LastB->constln() == this);
978 assert(postprocess_begin == postprocess_end);
979 // 2.5: Choose a small splitter block SpB subset of SpC from P,
980 // i.e. |SpB| <= 1/2*|SpC|
981 /// It doesn't matter very much how ties are resolved here:
982 /// `part_tr.change_to_C()` is faster if the first block is selected to
983 /// be split off. `part_tr.split_s_inert_out()` is faster if the last
984 /// block is selected.
985 if (FirstB->size() > LastB->size())
986 {
987 // 2.6: Create a new constellation NewC
988 // 2.6: ... and move SpB from SpC to NewC
989 constln_t* NewC =
990 new constln_t(sort_key - (LastB->begin() - begin()),
991 LastB->begin(), end(), postprocess_end);
992 set_end(LastB->begin());
993 LastB->set_constln(NewC);
994 return LastB;
995 }
996 else
997 {
998 // 2.6: Create a new constellation NewC
999 // 2.6: ... and move SpB from SpC to NewC
1000 constln_t* NewC =
1001 new constln_t(sort_key - (end() - FirstB->end()), begin(),
1002 FirstB->end(), postprocess_end);
1003 set_begin(FirstB->end());
1004 FirstB->set_constln(NewC);
1005 return FirstB;
1006 }
1007 }
1008 #ifndef NDEBUG
1009 /// \brief print a constellation identification for debugging
1010 std::string debug_id() const
1011 {
1012 return "constellation [" +
1013 std::to_string(begin() - block_t::permutation_begin()) +
1014 "," + std::to_string(end() - block_t::permutation_begin()) +
1015 ") (#" + std::to_string(sort_key) + ")";
1016 }
1017 #endif
1018};
1019
1020
1021template <class LTS_TYPE>
1022class bisim_partitioner_gjkw_initialise_helper;
1023
1024class part_trans_t;
1025
1026/// \class part_state_t
1027/// \brief refinable partition data structure
1028/// \details This class collects all information about a partition of the
1029/// states.
1030class part_state_t
1031{
1032 public:
1033 /// \brief permutation array
1034 /// \details This is the central element of the data structure: In this
1035 /// array, states that belong to the same block are stored in adjacent
1036 /// elements, and blocks that belong to the same constellation are stored
1037 /// in adjacent slices.
1038 permutation_t permutation;
1039
1040 private:
1041 /// \brief array with all other information about states
1042 /// \details We allocate 1 additional "state" to allow for the iterators
1043 /// past the last transition, as described in the documentation of
1044 /// `state_info_entry`.
1045 fixed_vector<state_info_entry> state_info;
1046
1047 template <class LTS_TYPE>
1048 friend class bisim_partitioner_gjkw_initialise_helper;
1049 public:
1050 /// \brief constructor
1051 /// \details The constructor allocates memory, but does not actually
1052 /// initialise the partition. Immediately afterwards, the initialisation
1053 /// helper `bisim_partitioner_gjkw_initialise_helper::init_transitions()`
1054 /// should be called.
1055 /// \param n number of states in the Kripke structure
1056 part_state_t(state_type n)
1057 : permutation(n),
1058 state_info(n+1) //< an additional "state" is needed to store pointers
1059 // to the end of the slices of transitions of the last state
1060 { assert(0 == block_t::nr_of_blocks);
1061 #ifndef NDEBUG
1062 block_t::perm_begin = permutation.begin();
1063 state_info_entry::s_i_begin = state_info.data();
1064 state_info_entry::s_i_end = state_info_entry::s_i_begin + n;
1065 #endif
1066 }
1067
1068 /// \brief destructor
1069 /// \details The destructor assumes that the caller has already executed
1070 /// `clear()` to deallocate the memory for the partition.
1071 ~part_state_t()
1072 { assert(state_info.empty()); assert(permutation.empty());
1073 }
1074
1075 /// \brief deallocates constellations and blocks
1076 /// \details This function can be called shortly before destructing the
1077 /// partition. Afterwards, the data structure is in a unusable state,
1078 /// as all information on states, blocks and constellations is deleted and
1079 /// deallocated.
1080 void clear()
1081 {
1082 // We have to deallocate constellations first because deallocating
1083 // blocks makes the constellations inaccessible.
1084 for (permutation_iter_t permutation_iter = permutation.end();
1085 permutation.begin() != permutation_iter; )
1086 {
1087 constln_t* const C = permutation_iter[-1]->constln(); assert(C->end() == permutation_iter);
1088 // permutation_iter[-1]->block->set_constln(nullptr); // assert that constellation is trivial:
1089 assert(permutation_iter[-1]->block->begin() == C->begin());
1090 permutation_iter = C->begin();
1091 delete C;
1092 }
1093 #ifndef NDEBUG
1094 state_type deleted_blocks = 0;
1095 #endif
1096 for (permutation_iter_t permutation_iter = permutation.end();
1097 permutation.begin() != permutation_iter; )
1098 {
1099 block_t* const B = permutation_iter[-1]->block; assert(B->end() == permutation_iter);
1100 permutation_iter = B->begin();
1101 #ifndef NDEBUG
1102 if (block_t::BLOCK_NO_SEQNR != B->seqnr())
1103 {
1104 ++deleted_blocks;
1105 }
1106 else
1107 {
1108 assert(0 == deleted_blocks);
1109 }
1110#endif
1111 delete B;
1112 } assert(deleted_blocks == block_t::nr_of_blocks);
1113 block_t::nr_of_blocks = 0;
1114 state_info.clear();
1115 permutation.clear();
1116 }
1117
1118 /// \brief provide size of state space
1119 /// \returns the stored size of the state space
1120 state_type state_size() const { return permutation.size(); }
1121
1122 /// \brief find block of a state
1123 /// \param s number of the state
1124 /// \returns a pointer to the block where state s resides in
1125 const block_t* block(state_type s) const
1126 {
1127 return state_info[s].block;
1128 }
1129 #ifndef NDEBUG
1130 private:
1131 /// \brief print a slice of the partition (typically a block)
1132 /// \details If the slice indicated by the parameters is not empty, the
1133 /// states in this slice will be printed.
1134 /// \param message text printed as a title if the slice is not empty
1135 /// \param B block that is being printed (it is checked whether
1136 /// states belong to this block)
1137 /// \param begin iterator to the beginning of the slice
1138 /// \param end iterator past the end of the slice
1139 void print_block(const char* message, const block_t* B,
1140 permutation_const_iter_t begin, permutation_const_iter_t end) const;
1141 public:
1142 /// \brief print the partition as a tree (per constellation and block)
1143 /// \details The function prints all constellations (in order); for each
1144 /// constellation it prints the blocks it consists of; and for each block,
1145 /// it lists its states, separated into nonbottom and bottom states.
1146 /// \param part_tr partition for the transitions
1147 void print_part(const part_trans_t& part_tr) const;
1148
1149 /// \brief print all transitions
1150 /// \details For each state (in order), its outgoing transitions are
1151 /// listed, sorted by goal constellation. The function also indicates
1152 /// where the current constellation pointer of the state points at.
1153 void print_trans() const;
1154 #endif
1155};
1156
1157///@} (end of group part_state)
1158
1159
1160
1161
1162
1163/* ************************************************************************* */
1164/* */
1165/* T R A N S I T I O N S */
1166/* */
1167/* ************************************************************************* */
1168
1169
1170
1171
1172
1173/// \defgroup part_trans Data structures for transitions used during partition refinement
1174/// \details These definitions provide a partition for transition data
1175/// structure that can be used for the partition refinement algorithm.
1176///
1177/// Basically, transitions are stored in three arrays:
1178/// - `pred`: transitions ordered by goal state, to allow finding all
1179/// predecessors of a goal state.
1180/// - `succ`: transitions ordered by source state and goal constellation, to
1181/// allow finding all successors of a source state. Given a transition in
1182/// this array, it is easy to find all transitions from the same source state
1183/// to the same goal constellation. It is possible to find out, in time
1184/// logarithmic in the out-degree, whether a state has a transition to a
1185/// given constellation.
1186/// - `B_to_C`: a permutation of the transitions such that transitions from the
1187/// same source block to the same goal constellation are adjacent. Further,
1188/// this array does not need a specific sort order.
1189///
1190/// Within this sort order, inert transitions are always placed after non-inert
1191/// transitions.
1192///
1193/// state_info_entry and block_t (defined above) contain pointers to the slices
1194/// of these arrays. For the incoming transitions, they contain enough
1195/// information; for the outgoing and the B_to_C-transitions, we additionally
1196/// use so-called _descriptors_ that show which slice belongs together.
1197/// The above was the original design described in our publication
1198/// [Groote/Jansen/Keiren/Wijs 2017]. This code reduces the descriptor for the
1199/// outgoing transitions to a single pointer, which is stored in the `succ`
1200/// array directly.
1201
1202///@{
1203
1204/* pred_entry, succ_entry, and B_to_C_entry contain the data that is stored
1205about a transition. Every transition has one of each data structure; the three
1206structures are linked through the iterators (used here as pointers). */
1207class succ_entry
1208{
1209 public:
1210 B_to_C_iter_t B_to_C;
1211 state_info_ptr target = nullptr;
1212
1213 private:
1214 /// \brief points to the last or the first transition to the same
1215 /// constellation
1216 /// \details We need to know, given a transition, which other transitions
1217 /// with the same source state and the same goal constellation there are.
1218 /// This pointer, in most cases, points to the last transition with the
1219 /// same source state and goal constellation, with the exception: If this
1220 /// `succ_entry` is actually the last transition, then the pointer points
1221 /// to the first such transition. In that way, one can find the first and
1222 /// the last relevant transition with one or two levels of dereferencing.
1223 ///
1224 /// The advantage of this pointer is that one does not need to allocate a
1225 /// separate data structure containing this information.
1226 succ_iter_t int_slice_begin_or_before_end;
1227 public:
1228
1229 succ_iter_t slice_begin_or_before_end()
1230 {
1231 return int_slice_begin_or_before_end;
1232 }
1233
1234 succ_const_iter_t slice_begin_or_before_end() const
1235 {
1236 return int_slice_begin_or_before_end;
1237 }
1238
1239 void set_slice_begin_or_before_end(succ_iter_t new_value)
1240 {
1241 int_slice_begin_or_before_end = new_value;
1242 }
1243
1244
1245 succ_iter_t slice_begin()
1246 {
1247 if (this < &*int_slice_begin_or_before_end)
1248 { assert(&*int_slice_begin_or_before_end->int_slice_begin_or_before_end <= this);
1249 return int_slice_begin_or_before_end->
1250 int_slice_begin_or_before_end;
1251 } assert(&*int_slice_begin_or_before_end->int_slice_begin_or_before_end == this);
1252 return int_slice_begin_or_before_end;
1253 }
1254
1255 succ_const_iter_t slice_begin() const
1256 {
1257 if (this < &*int_slice_begin_or_before_end)
1258 { assert(&*int_slice_begin_or_before_end->int_slice_begin_or_before_end <= this);
1259 return int_slice_begin_or_before_end->
1260 int_slice_begin_or_before_end;
1261 } assert(&*int_slice_begin_or_before_end->int_slice_begin_or_before_end == this);
1262 return int_slice_begin_or_before_end;
1263 }
1264
1265 static succ_iter_t slice_end(succ_iter_t this_)
1266 {
1267 if (this_ < this_->int_slice_begin_or_before_end)
1268 { assert(this_->int_slice_begin_or_before_end->
1269 int_slice_begin_or_before_end <= this_);
1270 return this_->int_slice_begin_or_before_end + 1;
1271 } assert(this_->int_slice_begin_or_before_end->
1272 int_slice_begin_or_before_end == this_);
1273 // The following line requires an iterator but a normal method would
1274 // only have a pointer, not an iterator. That's why we need to jump
1275 // through the `static` hoop.
1276 return this_ + 1;
1277 }
1278
1279 static succ_const_iter_t slice_end(succ_const_iter_t this_)
1280 {
1281 if (this_ < this_->int_slice_begin_or_before_end)
1282 { assert(this_->int_slice_begin_or_before_end->
1283 int_slice_begin_or_before_end <= this_);
1284 return this_->int_slice_begin_or_before_end + 1;
1285 } assert(this_->int_slice_begin_or_before_end->
1286 int_slice_begin_or_before_end == this_);
1287 // The following line requires an iterator but a normal method would
1288 // only have a pointer, not an iterator. That's why we need to jump
1289 // through the `static` hoop.
1290 return this_ + 1;
1291 }
1292 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1293 /// adds work (for time complexity measurement) to every transition in the
1294 /// slice to which `this_` belongs.
1295 static void slice_add_work_to_transns(succ_const_iter_t this_,
1296 enum check_complexity::counter_type ctr, unsigned max_value);
1297 #endif
1298};
1299
1300
1301class pred_entry
1302{
1303 public:
1304 succ_iter_t succ;
1305 state_info_ptr source = nullptr;
1306#ifndef NDEBUG
1307 /// \brief print a short transition identification for debugging
1308 /// \details This function is only available if compiled in Debug mode.
1309 std::string debug_id_short() const
1310 {
1311 return "from " + source->debug_id_short() + " to " +
1312 succ->target->debug_id_short();
1313 }
1314
1315 /// \brief print a transition identification for debugging
1316 /// \details This function is only available if compiled in Debug mode.
1317 std::string debug_id() const
1318 {
1319 return "transition " + debug_id_short();
1320 }
1321 #endif
1322 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1323 mutable check_complexity::trans_counter_t work_counter;
1324 #endif
1325};
1326
1327
1328class B_to_C_entry
1329{
1330 public:
1331 pred_iter_t pred;
1332 B_to_C_desc_iter_t B_to_C_slice;
1333};
1334 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1335 /// adds work (for time complexity measurement) to every transition in the
1336 /// slice.
1337 inline void succ_entry::slice_add_work_to_transns(succ_const_iter_t this_,
1338 enum check_complexity::counter_type ctr, unsigned max_value)
1339 {
1340 succ_const_iter_t iter = this_->slice_begin();
1341 succ_const_iter_t end = slice_end(this_); (void) end;
1342 assert(iter < end);
1343 mCRL2complexity(iter->B_to_C->pred, add_work(ctr, max_value), );
1344 #ifndef NDEBUG
1345 while (++iter != end)
1346 {
1347 // treat temporary counters specially
1348 mCRL2complexity(iter->B_to_C->pred,
1349 add_work_notemporary(ctr, max_value), );
1350 }
1351 #endif
1352 }
1353 #endif
1354/* B_to_C_descriptor is a data type that indicates which slice of states
1355belongs together. */
1356class B_to_C_descriptor
1357{
1358 public:
1359 B_to_C_iter_t end, begin;
1360
1361 B_to_C_descriptor(B_to_C_iter_t begin_, B_to_C_iter_t end_)
1362 : end(end_),
1363 begin(begin_)
1364 { }
1365
1366 /// compute the source block of the transitions in this slice
1367 const block_t* from_block() const
1368 { assert(begin < end); assert(begin->pred->succ->B_to_C == begin);
1369 return begin->pred->source->block;
1370 }
1371 block_t* from_block()
1372 { assert(begin < end); assert(begin->pred->succ->B_to_C == begin);
1373 return begin->pred->source->block;
1374 }
1375
1376 /// compute the goal constellation of the transitions in this slice
1377 const constln_t* to_constln() const
1378 { assert(begin < end); assert(begin->pred->succ->B_to_C == begin);
1379 return begin->pred->succ->target->constln();
1380 }
1381 constln_t* to_constln()
1382 { assert(begin < end); assert(begin->pred->succ->B_to_C == begin);
1383 return begin->pred->succ->target->constln();
1384 }
1385
1386 /// \brief returns true iff the slice is marked for postprocessing
1387 /// \details The function uses the data registered with the goal
1388 /// constellation.
1389 bool needs_postprocessing() const
1390 { assert(to_constln()->postprocess_end <= begin ||
1391 end <= to_constln()->postprocess_end);
1392 assert(to_constln()->postprocess_begin <= begin ||
1393 end <= to_constln()->postprocess_begin);
1394 return to_constln()->postprocess_begin <= begin &&
1395 end <= to_constln()->postprocess_end;
1396 }
1397 #ifndef NDEBUG
1398 /// \brief print a B_to_C slice identification for debugging
1399 /// \details This function is only available if compiled in Debug mode.
1400 std::string debug_id() const
1401 {
1402 assert(begin < end);
1403 std::string result("slice containing transition");
1404 if (end - begin > 1)
1405 {
1406 result += "s ";
1407 }
1408 else
1409 {
1410 result += " ";
1411 }
1412 B_to_C_const_iter_t iter = begin;
1413 assert(iter->pred->succ->B_to_C == iter);
1414 result += iter->pred->debug_id_short();
1415 if (end - iter > 4)
1416 {
1417 assert(iter[1].pred->succ->B_to_C == iter+1);
1418 result += ", ";
1419 result += iter[1].pred->debug_id_short();
1420 result += ", ...";
1421 iter = end - 3;
1422 }
1423 while (++iter != end)
1424 {
1425 assert(iter->pred->succ->B_to_C == iter);
1426 result += ", ";
1427 result += iter->pred->debug_id_short();
1428 }
1429 return result;
1430 }
1431 #endif
1432 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1433 /// The function is meant to transfer work temporarily assigned to the
1434 /// B_to_C slice to the transitions in the slice. It is used during
1435 /// handling of new bottom states, so the work is only assigned to
1436 /// transitions that start in a (new) bottom state.
1437 /// If at this moment no such (new) bottom state has been found, the work
1438 /// is kept with the slice and the function returns false. The work should
1439 /// be transferred later (but if there is no later transfer, it should be
1440 /// tested that the function returns true).
1441 bool add_work_to_bottom_transns(enum check_complexity::counter_type ctr,
1442 unsigned max_value)
1443 {
1444 bool added = false;
1445
1446 for (B_to_C_const_iter_t iter = begin; iter != end; ++iter)
1447 {
1448 if (iter->pred->source->pos >=
1449 iter->pred->source->block->bottom_begin())
1450 {
1451 // source state of the transition is a bottom state
1452 #ifndef NDEBUG
1453 if (added)
1454 {
1455 mCRL2complexity(iter->pred,
1456 add_work_notemporary(ctr, max_value), );
1457 continue;
1458 }
1459 #endif
1460 mCRL2complexity(iter->pred, add_work(ctr, max_value), );
1461 added = true;
1462 #ifdef NDEBUG
1463 break;
1464 #endif
1465 }
1466 }
1467 return added;
1468 }
1469
1470 mutable check_complexity::B_to_C_counter_t work_counter;
1471 #endif
1472};
1473
1474
1475/* part_trans_t collects and organises all data for the transitions. */
1476class part_trans_t
1477{
1478 private:
1479 fixed_vector<pred_entry> pred;
1480 fixed_vector<succ_entry> succ;
1481 fixed_vector<B_to_C_entry> B_to_C;
1482
1483 template <class LTS_TYPE>
1484 friend class bisim_partitioner_gjkw_initialise_helper;
1485
1486 void swap_in(B_to_C_iter_t const pos1, B_to_C_iter_t const pos2)
1487 { assert(B_to_C.end() > pos1); assert(pos1->pred->succ->B_to_C == pos1);
1488 assert(B_to_C.end() > pos2); assert(pos2->pred->succ->B_to_C == pos2);
1489 // swap contents
1490 pred_entry const temp_entry(*pos1->pred);
1491 *pos1->pred = *pos2->pred;
1492 *pos2->pred = temp_entry;
1493 // swap pointers to contents
1494 pred_iter_t const temp_iter(pos1->pred);
1495 pos1->pred = pos2->pred;
1496 pos2->pred = temp_iter; assert(B_to_C.end() > pos1); assert(pos1->pred->succ->B_to_C == pos1);
1497 assert(B_to_C.end() > pos2); assert(pos2->pred->succ->B_to_C == pos2);
1498 }
1499
1500 void swap_out(pred_iter_t const pos1, pred_iter_t const pos2)
1501 { assert(pred.end() > pos1); assert(pos1->succ->B_to_C->pred == pos1);
1502 assert(pred.end() > pos2); assert(pos2->succ->B_to_C->pred == pos2);
1503 assert(pos1->succ->slice_begin() == pos2->succ->slice_begin());
1504 assert(succ_entry::slice_end(pos1->succ) == succ_entry::slice_end(pos2->succ));
1505 // swap contents, but do not swap slice_begin_or_before_end
1506 B_to_C_iter_t const temp_B_to_C(pos1->succ->B_to_C);
1507 state_info_ptr temp_target(pos1->succ->target);
1508 pos1->succ->B_to_C = pos2->succ->B_to_C;
1509 pos1->succ->target = pos2->succ->target;
1510 pos2->succ->B_to_C = temp_B_to_C;
1511 pos2->succ->target = temp_target;
1512 // swap pointers to contents
1513 succ_iter_t const temp_iter(pos1->succ);
1514 pos1->succ = pos2->succ;
1515 pos2->succ = temp_iter; assert(pred.end() > pos1); assert(pos1->succ->B_to_C->pred == pos1);
1516 assert(pred.end() > pos2); assert(pos2->succ->B_to_C->pred == pos2);
1517 assert(pos1->succ->slice_begin() == pos2->succ->slice_begin());
1518 assert(succ_entry::slice_end(pos1->succ) == succ_entry::slice_end(pos2->succ));
1519 }
1520
1521 void swap_B_to_C(succ_iter_t const pos1, succ_iter_t const pos2)
1522 { assert(succ.end() > pos1); assert(pos1->B_to_C->pred->succ == pos1);
1523 assert(succ.end() > pos2); assert(pos2->B_to_C->pred->succ == pos2);
1524 if (pos1 != pos2)
1525 {
1526 // swap contents
1527 std::swap(*pos1->B_to_C,*pos2->B_to_C);
1528 // swap pointers to contents
1529 B_to_C_iter_t const temp_iter(std::move(pos1->B_to_C));
1530 pos1->B_to_C = std::move(pos2->B_to_C);
1531 pos2->B_to_C = std::move(temp_iter);
1532 } assert(succ.end() > pos1); assert(pos1->B_to_C->pred->succ == pos1);
1533 assert(succ.end() > pos2); assert(pos2->B_to_C->pred->succ == pos2);
1534 }
1535
1536 // *pos1 -> *pos2 -> *pos3 -> *pos1, where pos3 is between pos1 and pos2
1537 void swap3_B_to_C(succ_iter_t const pos1, succ_iter_t const pos2,
1538 succ_iter_t const pos3)
1539 { assert((pos1->B_to_C <= pos3->B_to_C && pos3->B_to_C <= pos2->B_to_C) ||
1540 (pos2->B_to_C <= pos3->B_to_C && pos3->B_to_C <= pos1->B_to_C));
1541 if (pos2 == pos3 || pos1 == pos3)
1542 {
1543 swap_B_to_C(pos1, pos2);
1544 }
1545 else
1546 { assert(succ.end() > pos1); assert(pos1->B_to_C->pred->succ == pos1);
1547 assert(succ.end() > pos2); assert(pos2->B_to_C->pred->succ == pos2);
1548 assert(succ.end() > pos3); assert(pos3->B_to_C->pred->succ == pos3);
1549 assert(pos1 != pos2); assert(pos1 != pos3); assert(pos2 != pos3);
1550 // swap contents
1551 B_to_C_entry const temp_entry(std::move(*pos1->B_to_C));
1552 *pos1->B_to_C = std::move(*pos3->B_to_C);
1553 *pos3->B_to_C = std::move(*pos2->B_to_C);
1554 *pos2->B_to_C = std::move(temp_entry);
1555 // swap pointers to contents
1556 B_to_C_iter_t const temp_iter(std::move(pos2->B_to_C));
1557 pos2->B_to_C = std::move(pos3->B_to_C);
1558 pos3->B_to_C = std::move(pos1->B_to_C);
1559 pos1->B_to_C = std::move(temp_iter); assert(succ.end() > pos1); assert(pos1->B_to_C->pred->succ == pos1);
1560 assert(succ.end() > pos2); assert(pos2->B_to_C->pred->succ == pos2);
1561 assert(succ.end() > pos3); assert(pos3->B_to_C->pred->succ == pos3);
1562 }
1563 }
1564 public:
1565 part_trans_t(trans_type m)
1566 : pred(m),
1567 succ(m),
1568 B_to_C(m)
1569 { }
1570 ~part_trans_t()
1571 { assert(B_to_C.empty()); assert(succ.empty()); assert(pred.empty());
1572 }
1573
1574 /// clear allocated memory
1575 void clear()
1576 {
1577 // B_to_C_descriptors are deallocated when their respective lists are
1578 // deallocated by destructing the blocks.
1579 B_to_C.clear();
1580 succ.clear();
1581 pred.clear();
1582 }
1583
1584 trans_type trans_size() const { return pred.size(); }
1585
1586 /* split_inert_to_C splits the B_to_C slice of block b to its own
1587 constellation into two slices: one for the inert and one for the non-inert
1588 transitions. It is called with SpB just after a constellation is split, as
1589 the transitions from SpB to itself (= the inert transitions) now go to a
1590 different constellation than the other transitions from SpB to its old
1591 constellation. It does, however, not adapt the other transition arrays to
1592 reflect that noninert and inert transitions from block b would go to
1593 different constellations.
1594 Its time complexity is O(1+min {|out_noninert(b-->C)|, |out_inert(b)|}). */
1595 void split_inert_to_C(block_t* SpB);
1596
1597 /* part_trans_t::change_to_C has to be called after a transition target has
1598 changed its constellation. The member function will adapt the transition
1599 data structure. It assumes that the transition is non-inert and that the
1600 new constellation does not (yet) have inert incoming transitions. It
1601 returns the boundary between transitions to OldC and transitions to NewC in
1602 the state's outgoing transition array. */
1603 succ_iter_t change_to_C(pred_iter_t pred_iter, ONLY_IF_DEBUG( constln_t* SpC, constln_t* NewC, )
1604 bool first_transition_of_state, bool first_transition_of_block);
1605
1606 /* split_s_inert_out splits the outgoing transitions from s to its own
1607 constellation into two: the inert transitions become transitions to the
1608 new constellation of which s is now part; the non-inert transitions remain
1609 transitions to OldC. It returns the boundary between transitions to
1610 OldC and transitions to NewC in the outgoing transition array of s.
1611 Its time complexity is O(1 + min { |out_\nottau(s)|, |out_\tau(s)| }). */
1612 bool split_s_inert_out(state_info_ptr s ONLY_IF_DEBUG(, constln_t* OldC)
1613 );
1614
1615 /* part_trans_t::make_noninert makes the transition identified by succ_iter
1616 noninert. */
1617 void make_noninert(succ_iter_t const succ_iter)
1618 {
1619 // change B_to_C
1620 B_to_C_iter_t const other_B_to_C =
1621 succ_iter->B_to_C->pred->source->block->inert_begin(); assert(succ_iter->B_to_C->B_to_C_slice->begin <= other_B_to_C);
1622 assert(other_B_to_C <= succ_iter->B_to_C);
1623 assert(succ_iter->B_to_C < succ_iter->B_to_C->B_to_C_slice->end);
1624 swap_B_to_C(succ_iter, other_B_to_C->pred->succ);
1625 succ_iter->B_to_C->pred->source->block->set_inert_begin(other_B_to_C +
1626 1);
1627 // change pred
1628 pred_iter_t const other_pred = succ_iter->target->inert_pred_begin(); assert(succ_iter->target->pred_begin() <= other_pred);
1629 assert(other_pred <= succ_iter->B_to_C->pred);
1630 assert(succ_iter->B_to_C->pred < succ_iter->target->pred_end());
1631 swap_in(succ_iter->B_to_C, other_pred->succ->B_to_C);
1632 succ_iter->target->set_inert_pred_begin(other_pred + 1);
1633 // change succ
1634 succ_iter_t const other_succ =
1635 succ_iter->B_to_C->pred->source->inert_succ_begin(); assert(succ_iter->B_to_C->pred->source->succ_begin() <= other_succ);
1636 assert(other_succ <= succ_iter);
1637 assert(succ_iter < succ_iter->B_to_C->pred->source->succ_end());
1638 swap_out(succ_iter->B_to_C->pred, other_succ->B_to_C->pred);
1639 succ_iter->B_to_C->pred->source->set_inert_succ_begin(other_succ + 1);
1640 }
1641
1642 /* part_trans_t::new_block_created splits the B_to_C-slices to reflect that
1643 some transitions now start in the new block NewB. They can no longer be in
1644 the same slice as the transitions that start in the old block.
1645
1646 We need separate functions for blue and red blocks because the B_to_C-slice
1647 of the red block should come after the B_to_C-slice of the blue block,
1648 at least while postprocessing.
1649
1650 Its time complexity is O(1 + |out(NewB)|). */
1651 void new_blue_block_created(block_t* RfnB, block_t* NewB);
1652 void new_red_block_created(block_t* RfnB, block_t* NewB, bool postprocessing);
1653
1654 B_to_C_const_iter_t B_to_C_begin() const { return B_to_C.begin(); }
1655 B_to_C_iter_t B_to_C_end () { return B_to_C.end (); }
1656 pred_const_iter_t pred_end() const { return pred.end(); }
1657 succ_const_iter_t succ_end() const { return succ.end(); }
1658 #ifndef NDEBUG
1659 /// \brief assert that the data structure is consistent and stable
1660 void assert_stability(const part_state_t& part_st) const;
1661 #endif
1662};
1663
1664///@} (end of group part_trans)
1665
1666
1667
1668
1669
1670
1671/* ************************************************************************* */
1672/* */
1673/* A L G O R I T H M S */
1674/* */
1675/* ************************************************************************* */
1676
1677
1678
1679
1680
1681/// \defgroup part_refine Classes to calculate the stutter equivalence quotient of a LTS
1682///@{
1683
1684
1685
1686/*=============================================================================
1687= create initial partition and data structures =
1688=============================================================================*/
1689
1690
1691
1692/// \class bisim_partitioner_gjkw_initialise_helper
1693/// \brief helps with initialising the refinable partition data structure
1694/// \details Before allocating memory for the refinable partition data
1695/// structure, the number of states and transitions (including extra states
1696/// generated by the translation from labelled transition system to Kripke
1697/// structure) has to be known. This class serves to calculate these numbers.
1698///
1699/// The helper class also initialises the variables used by check_complexity to
1700/// find the number of states and transitions in time complexity checks.
1701template<class LTS_TYPE>
1702class bisim_partitioner_gjkw_initialise_helper
1703{
1704 private:
1705 LTS_TYPE& aut;
1706 state_type nr_of_states;
1707 const state_type orig_nr_of_states;
1708 trans_type nr_of_transitions;
1709
1710 // key and hash function for (action, target state) pair. Required since
1711 // unordered_map does not directly allow to use pair keys
1712 class Key
1713 {
1714 public:
1715 label_type first;
1716 state_type second;
1717
1718 Key(const label_type& f, const state_type& s)
1719 : first(f),
1720 second(s)
1721 {}
1722
1723 bool operator==(const Key &other) const
1724 {
1725 return first == other.first && second == other.second;
1726 }
1727 };
1728
1729 class KeyHasher
1730 {
1731 public:
1732 std::size_t operator()(const Key& k) const
1733 {
1734 return std::hash<label_type>()(k.first) ^
1735 (std::hash<state_type>()(k.second) << 1);
1736 }
1737 };
1738 // Map used to convert LTS to Kripke structure
1739 // (also used when converting Kripke structure back to LTS)
1740 std::unordered_map<Key, state_type, KeyHasher> extra_kripke_states;
1741
1742 // temporary map to keep track of blocks. maps transition labels (different
1743 // from tau) to blocks
1744 std::unordered_map<label_type, state_type> action_block_map;
1745
1746 std::vector<state_type> noninert_out_per_state, inert_out_per_state;
1747 std::vector<state_type> noninert_in_per_state, inert_in_per_state;
1748 std::vector<state_type> noninert_out_per_block, inert_out_per_block;
1749 std::vector<state_type> states_per_block;
1750 state_type nr_of_nonbottom_states = 0;
1751 public:
1752 bisim_partitioner_gjkw_initialise_helper(LTS_TYPE& l, bool branching,
1753 bool preserve_divergence);
1754
1755 /// initialise the state in part_st and the transitions in part_tr
1756 void init_transitions(part_state_t& part_st, part_trans_t& part_tr,
1757 bool branching, bool preserve_divergence);
1758
1759 // replace_transition_system() replaces the transitions of the LTS stored here by
1760 // those of its bisimulation quotient. However, it does not change
1761 // anything else; in particular, it does not change the number of states of
1762 // the LTS.
1763 void replace_transition_system(const part_state_t& part_st, ONLY_IF_DEBUG( bool branching, )
1764 bool preserve_divergence);
1765
1766 /// provides the number of states in the Kripke structure
1767 state_type get_nr_of_states() const { return nr_of_states; }
1768
1769 /// provides the number of transitions in the Kripke structure
1770 trans_type get_nr_of_transitions() const { return nr_of_transitions; }
1771};
1772
1773
1774
1775/*=============================================================================
1776= main class =
1777=============================================================================*/
1778
1779
1780
1781struct refine_shared_t;
1782
1783} // end namespace bisim_gjkw
1784
1785/// \class bisim_partitioner_gjkw
1786/// \brief implements the main algorithm for the stutter equivalence quotient
1787template <class LTS_TYPE>
1788class bisim_partitioner_gjkw
1789{
1790 private:
1791 bisim_gjkw::bisim_partitioner_gjkw_initialise_helper<LTS_TYPE> init_helper;
1792 bisim_gjkw::part_state_t part_st;
1793 bisim_gjkw::part_trans_t part_tr;
1794 public:
1795 // The constructor constructs the data structures and immediately
1796 // calculates the bisimulation quotient. However, it does not change the
1797 // LTS.
1798 bisim_partitioner_gjkw(LTS_TYPE& l, bool branching = false,
1799 bool preserve_divergence = false)
1800 : init_helper(l, branching, preserve_divergence),
1801 part_st(init_helper.get_nr_of_states()),
1802 part_tr(init_helper.get_nr_of_transitions())
1803 { assert(branching || !preserve_divergence);
1804 create_initial_partition_gjkw(branching, preserve_divergence);
1805 refine_partition_until_it_becomes_stable_gjkw();
1806 }
1807 ~bisim_partitioner_gjkw()
1808 {
1809 part_tr.clear();
1810 part_st.clear();
1811 }
1812
1813 // replace_transition_system() replaces the transitions of the LTS stored here by
1814 // those of its bisimulation quotient. However, it does not change
1815 // anything else; in particular, it does not change the number of states of
1816 // the LTS.
1817 void replace_transition_system(bool branching, bool preserve_divergence)
1818 {
1819 (void) branching; // avoid warning about unused parameter.
1820 init_helper.replace_transition_system(part_st, ONLY_IF_DEBUG( branching, )
1821 preserve_divergence);
1822 }
1823
1824 static state_type num_eq_classes()
1825 {
1826 return bisim_gjkw::block_t::nr_of_blocks;
1827 }
1828
1829 state_type get_eq_class(state_type s) const
1830 {
1831 return part_st.block(s)->seqnr();
1832 }
1833
1834 bool in_same_class(state_type s, state_type t) const
1835 {
1836 return part_st.block(s) == part_st.block(t);
1837 }
1838
1839 private:
1840
1841 /*-------- dbStutteringEquivalence -- Algorithm 2 of [GJKW 2017] --------*/
1842
1843 void create_initial_partition_gjkw(bool branching,
1844 bool preserve_divergence);
1845 void refine_partition_until_it_becomes_stable_gjkw();
1846
1847 /*----------------- Refine -- Algorithm 3 of [GJKW 2017] ----------------*/
1848
1849 bisim_gjkw::block_t* refine(bisim_gjkw::block_t* RfnB,
1850 const bisim_gjkw::constln_t* SpC,
1851 const bisim_gjkw::B_to_C_descriptor* FromRed,
1852 bool postprocessing
1853 #if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
1854 , const bisim_gjkw::constln_t* NewC = nullptr
1855 #endif
1856 );
1857
1858 /*--------- PostprocessNewBottom -- Algorithm 4 of [GJKW 2017] ----------*/
1859
1860 bisim_gjkw::block_t* postprocess_new_bottom(bisim_gjkw::block_t* RedB);
1861};
1862
1863///@} (end of group part_refine)
1864
1865
1866
1867
1868
1869/* ************************************************************************* */
1870/* */
1871/* I N T E R F A C E */
1872/* */
1873/* ************************************************************************* */
1874
1875
1876
1877
1878
1879/// \defgroup part_interface Nonmember functions serving as interface with the rest of mCRL2
1880/// \details These functions are copied, almost without changes, from
1881/// liblts_bisim_gw.h, which was written by Anton Wijs.
1882///@{
1883
1884/** \brief Reduce transition system l with respect to strong or (divergence
1885 * preserving) branching bisimulation.
1886 * \param[in,out] l The transition system that is reduced.
1887 * \param branching If true branching bisimulation is
1888 * applied, otherwise strong bisimulation.
1889 * \param preserve_divergence Indicates whether loops of internal
1890 * actions on states must be preserved. If
1891 * false these are removed. If true these
1892 * are preserved. */
1893template <class LTS_TYPE>
1894void bisimulation_reduce_gjkw(LTS_TYPE& l, bool branching = false,
1895 bool preserve_divergence = false);
1896
1897/** \brief Checks whether the two initial states of two LTSs are strong or
1898 * branching bisimilar.
1899 * \details The LTSs l1 and l2 are not usable anymore after this call.
1900 * The space consumption is O(n) and time is O(m log n). It uses the branching
1901 * bisimulation algorithm by Groote/Jansen/Keiren/Wijs.
1902 * \param[in,out] l1 A first transition system.
1903 * \param[in,out] l2 A second transistion system.
1904 * \param branching If true branching bisimulation is used,
1905 * otherwise strong bisimulation is applied.
1906 * \param preserve_divergence If true and branching is true, preserve
1907 * tau loops on states.
1908 * \retval True iff the initial states of the current transition system and l2
1909 * are (divergence preserving) (branching) bisimilar. */
1910template <class LTS_TYPE>
1911bool destructive_bisimulation_compare_gjkw(LTS_TYPE& l1, LTS_TYPE& l2,
1912 bool branching = false, bool preserve_divergence = false,
1913 bool generate_counter_examples = false);
1914
1915/** \brief Checks whether the two initial states of two LTSs are strong or
1916 * branching bisimilar.
1917 * \details The LTSs l1 and l2 are first duplicated and subsequently reduced
1918 * modulo bisimulation. If memory space is a concern, one could consider to use
1919 * destructive_bisimulation_compare. This routine uses the O(m log n) branching
1920 * bisimulation routine. It runs in O(m log n) time and uses O(n) memory, where
1921 * n is the number of states and m is the number of transitions.
1922 * \param[in,out] l1 A first transition system.
1923 * \param[in,out] l2 A second transistion system.
1924 * \param branching If true branching bisimulation is used,
1925 * otherwise strong bisimulation is applied.
1926 * \param preserve_divergence If true and branching is true, preserve
1927 * tau loops on states.
1928 * \retval True iff the initial states of the current transition system and l2
1929 * are (divergence preserving) (branching) bisimilar. */
1930template <class LTS_TYPE>
1931bool bisimulation_compare_gjkw(const LTS_TYPE& l1, const LTS_TYPE& l2,
1932 bool branching = false, bool preserve_divergence = false);
1933
1934/// calculates the bisimulation quotient of a LTS.
1935template <class LTS_TYPE>
1936void bisimulation_reduce_gjkw(LTS_TYPE& l, bool const branching /* = false */,
1937 bool const preserve_divergence /* = false */)
1938{
1939 // First, remove tau loops in case of branching bisimulation.
1940 if (branching)
1941 {
1942 scc_reduce(l, preserve_divergence);
1943 }
1944
1945 // Second, apply the branching bisimulation reduction algorithm. If there are
1946 // no taus, this will automatically yield strong bisimulation.
1947 detail::bisim_partitioner_gjkw<LTS_TYPE> bisim_part(l, branching,
1948 preserve_divergence);
1949
1950 // Assign the reduced LTS
1951 bisim_part.replace_transition_system(branching, preserve_divergence);
1952}
1953
1954template <class LTS_TYPE>
1955inline bool bisimulation_compare_gjkw(const LTS_TYPE& l1, const LTS_TYPE& l2,
1956 bool branching /* = false */, bool preserve_divergence /* = false */)
1957{
1958 LTS_TYPE l1_copy(l1);
1959 LTS_TYPE l2_copy(l2);
1960 return destructive_bisimulation_compare_gjkw(l1_copy, l2_copy, branching,
1961 preserve_divergence);
1962}
1963
1964template <class LTS_TYPE>
1965bool destructive_bisimulation_compare_gjkw(LTS_TYPE& l1, LTS_TYPE& l2,
1966 bool branching /* = false */, bool preserve_divergence /* = false */,
1967 bool generate_counter_examples /* = false */,
1968 const std::string& /*counter_example_file = "" */,
1969 bool /*structured_output = false */)
1970{
1971 if (generate_counter_examples)
1972 {
1973 mCRL2log(log::log_level_t::warning) << "The GJKW branching bisimulation algorithm does "
1974 "not generate counterexamples.\n";
1975 }
1976 state_type init_l2 = l2.initial_state() + l1.num_states();
1977 mcrl2::lts::detail::merge(l1, l2);
1978 l2.clear(); // No use for l2 anymore.
1979
1980 // First remove tau loops in case of branching bisimulation.
1981 if (branching)
1982 {
1983 detail::scc_partitioner<LTS_TYPE> scc_part(l1);
1984 scc_part.replace_transition_system(preserve_divergence);
1985 init_l2 = scc_part.get_eq_class(init_l2);
1986 }
1987
1988 detail::bisim_partitioner_gjkw<LTS_TYPE> bisim_part(l1, branching,
1989 preserve_divergence);
1990 return bisim_part.in_same_class(l1.initial_state(), init_l2);
1991}
1992
1993///@} (end of group part_interface)
1994
1995
1996
1997
1998
1999/* ************************************************************************* */
2000/* */
2001/* I M P L E M E N T A T I O N S */
2002/* */
2003/* ************************************************************************* */
2004
2005
2006
2007
2008
2009// This section contains implementations of functions that refer to details of
2010// classes defined later, so they could not be defined at the point of
2011// declaration.
2012
2013namespace bisim_gjkw
2014{
2015
2016/// get the constellation of the state
2017inline const constln_t* state_info_entry::constln() const
2018{
2019 return block->constln();
2020}
2021
2022inline constln_t* state_info_entry::constln()
2023{
2024 return block->constln();
2025}
2026
2027/// read FromRed
2028inline B_to_C_descriptor* block_t::FromRed(const constln_t* const SpC)
2029{
2030 if (!to_constln.empty() && to_constln.front().to_constln() == SpC)
2031 {
2032 return &*to_constln.begin();
2033 }
2034 else
2035 {
2036 #ifndef NDEBUG
2037 for (B_to_C_desc_const_iter_t iter = to_constln.begin();
2038 to_constln.end() != iter; ++iter)
2039 {
2040 assert(iter->from_block() == this);
2041 assert(iter->to_constln() != SpC);
2042 }
2043 #endif
2044 return nullptr;
2045 }
2046}
2047
2048
2049/// set FromRed to an existing element in to_constln
2050inline void block_t::SetFromRed(B_to_C_desc_iter_t const new_fromred)
2051{ assert(!to_constln.empty());
2052 if (to_constln.begin() != new_fromred)
2053 {
2054 to_constln.splice(to_constln.begin(), to_constln, new_fromred);
2055 } assert(new_fromred->from_block() == this);
2056}
2057
2058
2059/// \brief quick check to find out whether the state has a transition to `SpC`
2060/// \details If the current constellation pointer happens to be set to `SpC`,
2061/// the function can quickly find out whether the state has a transition to
2062/// `SpC`.
2063/// The function should not be called for the constellation in which the state
2064/// resides.
2065/// \param SpC constellation of interest
2066/// \returns true if the state is known to have a transition to `SpC`
2067/// \memberof state_info_entry
2068inline bool state_info_entry::surely_has_transition_to(const constln_t* const
2069 SpC) const
2070{ assert(succ_begin()<=current_constln()); assert(current_constln()<=succ_end());
2071 assert(succ_begin() == current_constln() || succ_end() == current_constln() ||
2072 *current_constln()[-1].target->constln() <
2073 *current_constln()->target->constln());
2074 assert(constln() != SpC);
2075 // either current_constln()->target or current_constln()[-1].target is in
2076 // SpC
2077 if (current_constln() != succ_end() &&
2078 current_constln()->target->constln() == SpC)
2079 {
2080 return true;
2081 }
2082 return false;
2083}
2084
2085
2086/// \brief quick check to find out whether the state has _no_ transition to
2087/// `SpC`
2088/// \details If the current constellation pointer happens to be set to `SpC` or
2089/// its successor, the function can quickly find out whether the state has a
2090/// transition to `SpC`.
2091/// The function should not be called for the constellation in which the state
2092/// resides.
2093/// \param SpC constellation of interest
2094/// \returns true if the state is known to have _no_ transition to `SpC`
2095/// \memberof state_info_entry
2096inline bool state_info_entry::surely_has_no_transition_to(
2097 const constln_t* const SpC) const
2098{ assert(succ_begin()<=current_constln()); assert(current_constln()<=succ_end());
2099 assert(succ_begin() == current_constln() || succ_end() == current_constln() ||
2100 *current_constln()[-1].target->constln() <
2101 *current_constln()->target->constln());
2102 assert(constln() != SpC);
2103 // condition:
2104 // current_constln()->target is in a constellation > SpC and
2105 // current_constln()[-1].target is in a constellation < SpC.
2106 if (current_constln() != succ_end() &&
2107 *current_constln()->target->constln() <= *SpC)
2108 {
2109 return false;
2110 }
2111 if (current_constln() != succ_begin() &&
2112 *SpC <= *current_constln()[-1].target->constln())
2113 {
2114 return false;
2115 }
2116 return true;
2117}
2118
2119
2120// NOLINTEND(cppcoreguidelines-macro-usage)
2121
2122} // end namespace bisim_gjkw
2123} // end namespace detail
2124// end namespace lts
2125// end namespace mcrl2
2126
2127#endif // MCRL2_LTS_DETAIL_LIBLTS_BISIM_GJKW_H
#define mCRL2complexity(unit, call, info_for_debug)
Assigns work to a counter and checks for errors.
aterm & operator=(const aterm &other) noexcept=default
aterm(const aterm &other) noexcept=default
This class has user-declared copy constructor so declare default copy and move operators.
static constexpr std::size_t maximal_size_of_stack
std::array< unprotected_aterm_core, maximal_size_of_stack > m_stack
void initialise(const term_balanced_tree< Term > &tree)
const Term & dereference() const
Dereference operator.
bool equal(const iterator &other) const
Equality operator.
iterator(const term_balanced_tree< Term > &tree)
void increment()
Increments the iterator.
bool is_node() const
Returns true iff the tree is a node with a left and right subtree.
static void make_tree_helper(aterm &result, ForwardTraversalIterator &p, const std::size_t size, Transformer transformer)
term_balanced_tree & operator=(const term_balanced_tree &) noexcept=default
Assignment operator.
size_type size() const
Returns the size of the term_balanced_tree.
term_balanced_tree(term_balanced_tree &&) noexcept=default
Move constructor.
bool empty() const
Returns true if tree is empty.
static const aterm & empty_tree()
static void make_tree(aterm &result, ForwardTraversalIterator &p, const std::size_t size, Transformer transformer)
term_balanced_tree(ForwardTraversalIterator first, const std::size_t size)
Creates an term_balanced_tree with a copy of a range.
static const function_symbol & tree_single_node_function()
const aterm & left_branch() const
Get the left branch of the tree.
term_balanced_tree(const term_balanced_tree &) noexcept=default
Copy constructor.
term_balanced_tree(ForwardTraversalIterator first, const std::size_t size, Transformer transformer)
Creates an term_balanced_tree with a copy of a range, where a transformer is applied to each term bef...
static const function_symbol & tree_node_function()
const Term & operator[](std::size_t position) const
Element indexing operator.
iterator begin() const
Returns an iterator pointing to the beginning of the term_balanced_tree.
iterator end() const
Returns an iterator pointing to the end of the term_balanced_tree.
term_balanced_tree()
Default constructor. Creates an empty tree.
const aterm & right_branch() const
Get the left branch of the tree.
term_balanced_tree & operator=(term_balanced_tree &&) noexcept=default
Move assign operator.
term_balanced_tree(const aterm &tree)
Construction from aterm.
const Term & element_at(std::size_t position, std::size_t size) const
Get an element at the indicated position.
static const function_symbol & tree_empty_function()
friend void make_term_balanced_tree(term_balanced_tree< Term1 > &result, ForwardTraversalIterator p, std::size_t size, Transformer transformer)
term_balanced_tree(detail::_term_appl *t)
A list of aterm objects.
Definition aterm_list.h:26
A unordered_map class in which aterms can be stored.
action_formula(action_formula &&) noexcept=default
action_formula & operator=(const action_formula &) noexcept=default
action_formula(const atermpp::aterm &term)
action_formula(const data::data_expression &x)
\brief Constructor Z6.
action_formula(const action_formula &) noexcept=default
Move semantics.
action_formula & operator=(action_formula &&) noexcept=default
action_formula(const data::untyped_data_parameter &x)
\brief Constructor Z6.
action_formula()
\brief Default constructor X3.
action_formula(const process::untyped_multi_action &x)
\brief Constructor Z6.
\brief The and operator for action formulas
and_ & operator=(const and_ &) noexcept=default
and_ & operator=(and_ &&) noexcept=default
and_(const action_formula &left, const action_formula &right)
\brief Constructor Z14.
and_()
\brief Default constructor X3.
and_(and_ &&) noexcept=default
const action_formula & left() const
and_(const atermpp::aterm &term)
and_(const and_ &) noexcept=default
Move semantics.
const action_formula & right() const
\brief The at operator for action formulas
at(const atermpp::aterm &term)
const data::data_expression & time_stamp() const
at & operator=(at &&) noexcept=default
const action_formula & operand() const
at(const at &) noexcept=default
Move semantics.
at(at &&) noexcept=default
at()
\brief Default constructor X3.
at & operator=(const at &) noexcept=default
at(const action_formula &operand, const data::data_expression &time_stamp)
\brief Constructor Z14.
\brief The existential quantification operator for action formulas
exists(const atermpp::aterm &term)
exists & operator=(exists &&) noexcept=default
exists(exists &&) noexcept=default
exists(const exists &) noexcept=default
Move semantics.
exists()
\brief Default constructor X3.
const data::variable_list & variables() const
exists & operator=(const exists &) noexcept=default
const action_formula & body() const
exists(const data::variable_list &variables, const action_formula &body)
\brief Constructor Z14.
\brief The value false for action formulas
false_(const atermpp::aterm &term)
false_()
\brief Default constructor X3.
false_(false_ &&) noexcept=default
false_(const false_ &) noexcept=default
Move semantics.
false_ & operator=(const false_ &) noexcept=default
false_ & operator=(false_ &&) noexcept=default
\brief The universal quantification operator for action formulas
forall & operator=(const forall &) noexcept=default
const action_formula & body() const
forall & operator=(forall &&) noexcept=default
forall(const atermpp::aterm &term)
const data::variable_list & variables() const
forall()
\brief Default constructor X3.
forall(const data::variable_list &variables, const action_formula &body)
\brief Constructor Z14.
forall(const forall &) noexcept=default
Move semantics.
forall(forall &&) noexcept=default
\brief The implication operator for action formulas
const action_formula & left() const
imp(const imp &) noexcept=default
Move semantics.
imp(imp &&) noexcept=default
imp & operator=(imp &&) noexcept=default
imp(const action_formula &left, const action_formula &right)
\brief Constructor Z14.
imp()
\brief Default constructor X3.
imp & operator=(const imp &) noexcept=default
imp(const atermpp::aterm &term)
const action_formula & right() const
\brief The multi action for action formulas
multi_action(const multi_action &) noexcept=default
Move semantics.
multi_action(multi_action &&) noexcept=default
multi_action(const process::action_list &actions)
\brief Constructor Z14.
multi_action(const atermpp::aterm &term)
multi_action & operator=(const multi_action &) noexcept=default
multi_action()
\brief Default constructor X3.
const process::action_list & actions() const
multi_action & operator=(multi_action &&) noexcept=default
\brief The not operator for action formulas
not_(const action_formula &operand)
\brief Constructor Z14.
not_()
\brief Default constructor X3.
const action_formula & operand() const
not_(const atermpp::aterm &term)
not_(not_ &&) noexcept=default
not_(const not_ &) noexcept=default
Move semantics.
not_ & operator=(const not_ &) noexcept=default
not_ & operator=(not_ &&) noexcept=default
\brief The or operator for action formulas
or_ & operator=(const or_ &) noexcept=default
or_(or_ &&) noexcept=default
or_()
\brief Default constructor X3.
or_ & operator=(or_ &&) noexcept=default
or_(const action_formula &left, const action_formula &right)
\brief Constructor Z14.
or_(const atermpp::aterm &term)
or_(const or_ &) noexcept=default
Move semantics.
const action_formula & right() const
const action_formula & left() const
\brief The value true for action formulas
true_(true_ &&) noexcept=default
true_ & operator=(const true_ &) noexcept=default
true_()
\brief Default constructor X3.
true_(const true_ &) noexcept=default
Move semantics.
true_(const atermpp::aterm &term)
true_ & operator=(true_ &&) noexcept=default
data_expression & operator=(data_expression &&) noexcept=default
sort_expression sort() const
Returns the sort of the data expression.
Definition data.cpp:107
data_expression(const data_expression &) noexcept=default
Move semantics.
data_expression(data_expression &&) noexcept=default
Rewriter that operates on data expressions.
Definition rewriter.h:84
data_expression operator()(const data_expression &d) const
Rewrites a data expression.
Definition rewriter.h:161
void add_sort(const basic_sort &s)
Adds a sort to this specification.
\brief A data variable
Definition variable.h:25
Action rename specification.
\brief A timed multi-action
multi_action(const multi_action &) noexcept=default
Move semantics.
const process::action_list & actions() const
multi_action(const process::action_list &actions=process::action_list(), data::data_expression time=data::undefined_real())
Constructor. Actions are sorted to establish the sorted-storage invariant.
This class contains labels for probabilistic transistions, consisting of a numerator and a denumerato...
static probabilistic_data_expression one()
Constant one.
probabilistic_data_expression operator+(const probabilistic_data_expression &other) const
Standard addition operator. Note that the expression is not evaluated. For this the rewriter has to b...
probabilistic_data_expression(const data::data_expression &d)
Construct a probabilistic_data_expression from a data_expression, which must be of sort real.
bool operator==(const probabilistic_data_expression &other) const
probabilistic_data_expression(std::size_t enumerator, std::size_t denominator)
bool operator!=(const probabilistic_data_expression &other) const
bool operator>=(const probabilistic_data_expression &other) const
bool operator<(const probabilistic_data_expression &other) const
bool operator<=(const probabilistic_data_expression &other) const
bool operator>(const probabilistic_data_expression &other) const
probabilistic_data_expression(const std::string &enumerator, const std::string &denominator)
probabilistic_data_expression operator-(const probabilistic_data_expression &other) const
Standard subtraction operator.
static data::data_specification data_specification_with_real()
static probabilistic_data_expression zero()
Constant zero.
Linear process specification.
STATE & state()
Get the state in a state probability pair.
state_probability_pair(state_probability_pair &&p)=default
state_probability_pair & operator=(state_probability_pair &&p)=default
state_probability_pair(const state_probability_pair &p)=default
Copy constructor;.
state_probability_pair & operator=(const state_probability_pair &p)=default
Standard assignment.
const PROBABILITY & probability() const
get the probability from a state proability pair.
const STATE & state() const
Get the state from a state probability pair.
PROBABILITY & probability()
Set the probability in a state probability pair.
state_probability_pair(const STATE &state, const PROBABILITY &probability)
constructor.
bool operator==(const state_probability_pair &other) const
Standard equality operator.
A class containing the values for action labels for the .lts format.
Definition lts_lts.h:142
action_label_lts & operator=(const action_label_lts &)=default
Copy assignment.
void hide_actions(const std::vector< std::string > &tau_actions)
Hide the actions with labels in tau_actions.
Definition lts_lts.h:162
action_label_lts(const action_label_lts &)=default
Copy constructor.
static const action_label_lts & tau_action()
Definition lts_lts.h:178
action_label_lts(const mcrl2::lps::multi_action &a)
Constructor.
Definition lts_lts.h:155
action_label_lts()=default
Default constructor.
void set_truths(formula &f)
Compute and set the truth values of a formula f.
level_type gca_level(const block_index_type B1, const block_index_type B2)
Auxiliarry function that computes the level of the greatest common ancestor. In other words a lvl i s...
bisim_partitioner_minimal_depth(LTS_TYPE &l, const std::size_t init_l2)
Creates a bisimulation partitioner for an LTS.
mcrl2::state_formulas::state_formula dist_formula_mindepth(const std::size_t s, const std::size_t t)
Creates a state formula that distinguishes state s from state t.
formula distinguish(const block_index_type b1, const block_index_type b2)
Creates a formula that distinguishes a block b1 from the block b2.
~bisim_partitioner_minimal_depth()=default
Destroys this partitioner.
regular_formulas::regular_formula create_regular_formula(const mcrl2::lps::multi_action &a) const
create_regular_formula Creates a regular formula that represents action a
bool in_same_class(const std::size_t s, const std::size_t t)
block_index_type lift_block(const block_index_type B1, level_type goal)
mcrl2::state_formulas::state_formula conjunction(std::vector< formula > &conjunctions)
conjunction Creates a conjunction of state formulas
mcrl2::state_formulas::state_formula convert_formula(formula &f)
void split_BL(level_type lvl)
Performs the splits based on the blocks in Bsplit and the flags set in state_flags.
mcrl2::state_formulas::state_formula conjunction(std::set< mcrl2::state_formulas::state_formula > terms) const
conjunction Creates a conjunction of state formulas
regular_formulas::regular_formula create_regular_formula(const mcrl2::lts::action_label_string &a) const
create_regular_formula Creates a regular formula that represents action a
regular_formulas::regular_formula create_regular_formula(const mcrl2::lps::multi_action &a) const
create_regular_formula Creates a regular formula that represents action a
std::vector< bool > block_is_in_to_be_processed
std::map< block_index_type, block_index_type > right_child
std::vector< block_index_type > BL
bool in_same_class(const std::size_t s, const std::size_t t) const
Returns whether two states are in the same bisimulation equivalence class.
mcrl2::state_formulas::state_formula until_formula(const mcrl2::state_formulas::state_formula &phi1, const label_type &a, const mcrl2::state_formulas::state_formula &phi2)
until_formula Creates a state formula that corresponds to the until operator phi1phi2 from HMLU
std::size_t get_eq_class(const std::size_t s) const
Gives the bisimulation equivalence class number of a state.
bisim_partitioner(LTS_TYPE &l, const bool branching=false, const bool preserve_divergence=false, const bool generate_counter_examples=false)
Creates a bisimulation partitioner for an LTS.
~bisim_partitioner()=default
Destroys this partitioner.
std::map< block_index_type, label_type > split_by_action
std::size_t num_eq_classes() const
Gives the number of bisimulation equivalence classes of the LTS.
mcrl2::state_formulas::state_formula counter_formula(std::size_t s, std::size_t t)
Creates a state formula that distinguishes state s from state t.
void order_recursively_on_tau_reachability(const state_type s, std::map< state_type, std::vector< state_type > > &inert_transition_map, std::vector< non_bottom_state > &new_non_bottom_states, std::set< state_type > &visited)
std::vector< block_index_type > to_be_processed
std::map< block_index_type, block_index_type > split_by_block
void replace_transition_system(const bool branching, const bool preserve_divergences)
Replaces the transition relation of the current lts by the transitions of the bisimulation reduced tr...
void order_on_tau_reachability(std::vector< non_bottom_state > &non_bottom_states)
void split_the_blocks_in_BL(bool &partition_is_unstable, const label_type splitter_label, const block_index_type splitter_block)
void refine_partition_until_it_becomes_stable(const bool branching, const bool preserve_divergence)
void create_initial_partition(const bool branching, const bool preserve_divergences)
std::vector< state_type > block_index_of_a_state
mcrl2::state_formulas::state_formula counter_formula_aux(const block_index_type B1, const block_index_type B2)
void check_internal_consistency_of_the_partitioning_data_structure(const bool branching, const bool preserve_divergence) const
outgoing_transitions_per_state_action_t outgoing_transitions
function object to compare two constln_t pointers based on their contents
A class that can be used to store counterexample trees and.
lts_type type()
Provides the type of this lts, in casu lts_aut.
Definition lts_aut.h:39
bool operator==(const lts_aut_base &) const
Standard equality function.
Definition lts_aut.h:52
void swap(lts_aut_base &) noexcept
Standard swap function.
Definition lts_aut.h:45
void swap(lts_dot_base &) noexcept
The standard swap function.
Definition lts_dot.h:120
lts_type type() const
The lts_type of state_label_dot. In this case lts_dot.
Definition lts_dot.h:113
void clear()
Clear the transitions system.
Definition lts_fsm.h:134
const std::vector< std::string > & state_element_values(std::size_t idx) const
Provides the vector of strings that correspond to the values of the number at position idx in a vecto...
Definition lts_fsm.h:146
std::size_t add_state_element_value(std::size_t idx, const std::string &s)
Adds a string to the state element values for the idx-th position in a state vector....
Definition lts_fsm.h:178
void swap(lts_fsm_base &other) noexcept
Standard swap function.
Definition lts_fsm.h:123
bool operator==(const lts_fsm_base &other) const
Definition lts_fsm.h:108
lts_type type() const
The lts_type of this labelled transition system. In this case lts_fsm.
Definition lts_fsm.h:117
std::string state_element_value(std::size_t parameter_index, std::size_t element_index) const
Returns the element_index'th element for the parameter with index parameter_index.
Definition lts_fsm.h:193
std::string state_label_to_string(const state_label_fsm &l) const
Pretty print a state value of this FSM.
Definition lts_fsm.h:156
a base class for lts_lts_t and probabilistic_lts_t.
Definition lts_lts.h:267
static lts_type type()
Yields the type of this lts, in this case lts_lts.
Definition lts_lts.h:295
void set_process_parameters(const data::variable_list &params)
Set the state parameters for this LTS.
Definition lts_lts.h:353
lts_lts_base()=default
Default constructor.
bool operator==(const lts_lts_base &other) const
Standard equality function;.
Definition lts_lts.h:278
process::action_label_list m_action_decls
Definition lts_lts.h:271
void set_action_label_declarations(const process::action_label_list &decls)
Set the action label information for this LTS.
Definition lts_lts.h:317
const data::variable & process_parameter(std::size_t i) const
Returns the i-th parameter of the state vectors stored in this LTS.
Definition lts_lts.h:340
data::data_specification m_data_spec
Definition lts_lts.h:269
const data::variable_list & process_parameters() const
Return the process parameters stored in this LTS.
Definition lts_lts.h:332
void set_data(const data::data_specification &spec)
Set the mCRL2 data specification of this LTS.
Definition lts_lts.h:325
void swap(lts_lts_base &l) noexcept
Definition lts_lts.h:285
const process::action_label_list & action_label_declarations() const
Return action label declarations stored in this LTS.
Definition lts_lts.h:309
data::variable_list m_parameters
Definition lts_lts.h:270
A simple labelled transition format with only strings as action labels.
Definition lts_aut.h:67
void load(const std::string &filename)
Load the labelled transition system from a file.
void load(std::istream &is)
Load the labelled transition system from an input stream.
void save(const std::string &filename) const
Save the labelled transition system to file.
A class to contain labelled transition systems in graphviz format.
Definition lts_dot.h:132
void save(const std::string &filename) const
Save the labelled transition system to a file.
void save(std::ostream &os) const
Save the labelled transition system to a stream.
The class lts_fsm_t contains labelled transition systems in .fsm format.
Definition lts_fsm.h:254
void load(const std::string &filename)
Save the labelled transition system to file.
void save(const std::string &filename) const
Save the labelled transition system to file.
This class contains labelled transition systems in .lts format.
Definition lts_lts.h:369
lts_lts_t()=default
Creates an object containing no information.
void save(const std::string &filename) const
Save the labelled transition system to file.
void load(const std::string &filename)
Load the labelled transition system from file.
A simple labelled transition format with only strings as action labels.
Definition lts_aut.h:100
void load(const std::string &filename)
Load the labelled transition system from a file.
void load(std::istream &is)
Load the labelled transition system from an input stream.
void save(const std::string &filename) const
Save the labelled transition system to file.
A class to contain labelled transition systems in graphviz format.
Definition lts_dot.h:158
void save(std::ostream &os) const
Save the labelled transition system to a stream.
void save(const std::string &filename) const
Save the labelled transition system to a file.
The class lts_fsm_t contains labelled transition systems in .fsm format.
Definition lts_fsm.h:282
This class contains probabilistic labelled transition systems in .lts format.
Definition lts_lts.h:397
probabilistic_lts_lts_t()=default
Creates an object containing no information.
void load(const std::string &filename)
Load the labelled transition system from file.
void save(const std::string &filename) const
Save the labelled transition system to file.
A class that contains a labelled transition system.
probabilistic_lts(probabilistic_lts &&other)=default
Standard move constructor.
void set_initial_probabilistic_state(const PROBABILISTIC_STATE_T &state)
Sets the probabilistic initial state number of this LTS.
probabilistic_lts()=default
Creates an empty LTS.
const PROBABILISTIC_STATE_T & initial_probabilistic_state() const
Gets the initial state number of this LTS.
bool operator==(const probabilistic_lts &other) const
Standard equality operator.
labels_size_type num_probabilistic_states() const
Gets the number of probabilistic states of this LTS.
static constexpr bool is_probabilistic_lts
An indicator that this is a probabilistic lts.
void clear_probabilistic_states()
Clear the probabilistic states in this probabilistic transitions system.
states_size_type add_and_reset_probabilistic_state(PROBABILISTIC_STATE_T &s)
Adds a probabilistic state to this LTS and resets the state to empty.
void clear()
Clear the transitions system.
probabilistic_lts & operator=(probabilistic_lts &&other)=default
Standard assignment move operator.
void swap(probabilistic_lts &other) noexcept
Swap this lts with the supplied supplied LTS.
probabilistic_lts & operator=(const probabilistic_lts &other)=default
Standard assignment operator.
std::vector< PROBABILISTIC_STATE_T > m_probabilistic_states
probabilistic_lts(const probabilistic_lts &other)=default
Standard copy constructor.
states_size_type add_probabilistic_state(const PROBABILISTIC_STATE_T &s)
Adds a probabilistic state to this LTS.
states_size_type initial_state() const
PROBABILISTIC_STATE_T m_init_probabilistic_state
A class that contains a probabilistic state.
void set(const STATE &s)
Set this probabilistic state to a single state with probability one.
const_iterator begin() const
Gets an iterator over pairs of state and probability. This can only be used when the state is stored ...
void construct_internal_vector_representation()
Guarantee that this probabilistic state is internally stored as a vector, such that begin/end,...
probabilistic_state & operator=(const probabilistic_state &other)
Copy assignment constructor.
const_reverse_iterator rbegin() const
Gets a reverse iterator over pairs of state and probability. This can only be used when the state is ...
std::size_t size() const
Gets the number of probabilistic states in the vector representation of this state....
bool operator!=(const probabilistic_state &other) const
Standard equality operator.
iterator begin()
Gets an iterator over pairs of state and probability. This can only be used if the state is internall...
probabilistic_state & operator=(probabilistic_state &&other)=default
Move assignment operator.
STATE get() const
Get a probabilistic state if is is simple, i.e., consists of a single state.
void swap(probabilistic_state &other) noexcept
Swap this probabilistic state.
iterator end()
Gets the end iterator over pairs of state and probability.
reverse_iterator rbegin()
Gets a reverse iterator over pairs of state and probability. This can only be used if the state is in...
std::vector< state_probability_pair > m_probabilistic_state
const_iterator end() const
Gets the end iterator over pairs of state and probability.
reverse_iterator rend()
Gets the reverse end iterator over pairs of state and probability.
bool operator==(const probabilistic_state &other) const
Standard equality operator.
void clear()
Makes the probabilistic state empty.
probabilistic_state(probabilistic_state &&other)=default
Move constructor.
probabilistic_state(const STATE_PROBABILITY_PAIR_ITERATOR begin, const STATE_PROBABILITY_PAIR_ITERATOR end)
Creates a probabilistic state on the basis of state_probability_pairs.
STATE maximal_state() const
Provides the maximal state index in a probabilistic state.
probabilistic_state(const probabilistic_state &other)
Copy constructor.
void shrink_to_fit()
If a probabilistic state is ready, shrinking it to minimal size might be useful to reduce its memory ...
probabilistic_state()
Default constructor.
probabilistic_state(const STATE &s)
Constructor of a probabilistic state from a non probabilistic state.
void add(const STATE &s, const PROBABILITY &p)
Add a state with a probability to the probabilistic state.
const_reverse_iterator rend() const
Gets the reverse end iterator over pairs of state and probability.
Class for computing the signature for strong bisimulation.
Definition sigref.h:76
Class for computing the signature for branching bisimulation.
Definition sigref.h:106
Class for computing the signature for divergence preserving branching bisimulation.
Definition sigref.h:185
Signature based reductions for labelled transition systems.
Definition sigref.h:351
This class contains labels for states in dot format.
Definition lts_dot.h:34
void set_name(const std::string &s)
This method sets the name of the state label to the string s.
Definition lts_dot.h:53
std::string name() const
This method returns the string in the name field of a state label.
Definition lts_dot.h:60
std::string label() const
This method returns the label in the name field of a state label.
Definition lts_dot.h:74
void set_label(const std::string &s)
This method sets the label field of the state label to the string s.
Definition lts_dot.h:67
state_label_dot(const std::string &state_name, const std::string &state_label)
A constructor setting the name and label of this state label to the indicated values.
Definition lts_dot.h:47
std::string m_state_label
Definition lts_dot.h:37
bool operator==(const state_label_dot &l) const
Standard comparison operator, comparing both the string in the name field, as well as the one in the ...
Definition lts_dot.h:82
bool operator!=(const state_label_dot &l) const
Standard inequality operator. Just the negation of equality.
Definition lts_dot.h:89
state_label_dot()=default
The default constructor.
This class contains state labels for the fsm format.
Definition lts_fsm.h:36
state_label_fsm()=default
Default constructor. The label becomes an empty vector.
state_label_fsm(const state_label_fsm &)=default
Copy constructor.
state_label_fsm & operator=(const state_label_fsm &)=default
Copy assignment.
static state_label_fsm number_to_label(const std::size_t n)
Create a state label consisting of a number as the only list element.
Definition lts_fsm.h:67
state_label_fsm(const std::vector< std::size_t > &v)
Default constructor. The label is set to the vector v.
Definition lts_fsm.h:50
state_label_fsm operator+(const state_label_fsm &l) const
An operator to concatenate two state labels. Fsm labels cannot be concatenated. Therefore,...
Definition lts_fsm.h:56
This class contains state labels for an labelled transition system in .lts format.
Definition lts_lts.h:38
state_label_lts(const state_label_lts &)=default
Copy constructor.
state_label_lts operator+(const state_label_lts &l) const
An operator to concatenate two state labels.
Definition lts_lts.h:79
state_label_lts(const super &l)
Construct a state label out of list of balanced trees of data expressions, representing a state label...
Definition lts_lts.h:71
state_label_lts()=default
Default constructor.
state_label_lts(const lps::state &l)
Construct a state label out of a balanced tree of data expressions, representing a state label.
Definition lts_lts.h:64
state_label_lts & operator=(const state_label_lts &)=default
Copy assignment.
static state_label_lts number_to_label(const std::size_t n)
Create a state label consisting of a number as the only list element.
Definition lts_lts.h:94
state_label_lts(const CONTAINER &l)
Construct a single state label out of the elements in a container.
Definition lts_lts.h:55
Process specification consisting of a data specification, action labels, a sequence of process equati...
\brief An untyped multi action or data application
\brief The alt operator for regular formulas
alt(const atermpp::aterm &term)
alt()
\brief Default constructor X3.
alt & operator=(alt &&) noexcept=default
const regular_formula & right() const
alt(const regular_formula &left, const regular_formula &right)
\brief Constructor Z14.
alt(const alt &) noexcept=default
Move semantics.
alt(alt &&) noexcept=default
alt & operator=(const alt &) noexcept=default
const regular_formula & left() const
regular_formula()
\brief Default constructor X3.
regular_formula(const action_formulas::action_formula &x)
\brief Constructor Z6.
regular_formula(const atermpp::aterm &term)
regular_formula(const regular_formula &) noexcept=default
Move semantics.
regular_formula(const data::data_expression &x)
\brief Constructor Z6.
regular_formula & operator=(const regular_formula &) noexcept=default
regular_formula(regular_formula &&) noexcept=default
regular_formula & operator=(regular_formula &&) noexcept=default
\brief The seq operator for regular formulas
seq(const regular_formula &left, const regular_formula &right)
\brief Constructor Z14.
const regular_formula & right() const
seq & operator=(const seq &) noexcept=default
seq(const seq &) noexcept=default
Move semantics.
const regular_formula & left() const
seq(seq &&) noexcept=default
seq()
\brief Default constructor X3.
seq & operator=(seq &&) noexcept=default
seq(const atermpp::aterm &term)
\brief The 'trans or nil' operator for regular formulas
trans_or_nil & operator=(trans_or_nil &&) noexcept=default
trans_or_nil & operator=(const trans_or_nil &) noexcept=default
trans_or_nil(const trans_or_nil &) noexcept=default
Move semantics.
trans_or_nil(const regular_formula &operand)
\brief Constructor Z14.
trans_or_nil()
\brief Default constructor X3.
trans_or_nil(trans_or_nil &&) noexcept=default
trans_or_nil(const atermpp::aterm &term)
const regular_formula & operand() const
\brief The trans operator for regular formulas
trans(const atermpp::aterm &term)
trans(trans &&) noexcept=default
const regular_formula & operand() const
trans & operator=(const trans &) noexcept=default
trans & operator=(trans &&) noexcept=default
trans()
\brief Default constructor X3.
trans(const trans &) noexcept=default
Move semantics.
trans(const regular_formula &operand)
\brief Constructor Z14.
\brief An untyped regular formula or action formula
untyped_regular_formula()
\brief Default constructor X3.
untyped_regular_formula & operator=(untyped_regular_formula &&) noexcept=default
untyped_regular_formula & operator=(const untyped_regular_formula &) noexcept=default
untyped_regular_formula(const std::string &name, const regular_formula &left, const regular_formula &right)
\brief Constructor Z2.
untyped_regular_formula(const core::identifier_string &name, const regular_formula &left, const regular_formula &right)
\brief Constructor Z14.
const core::identifier_string & name() const
untyped_regular_formula(const untyped_regular_formula &) noexcept=default
Move semantics.
untyped_regular_formula(untyped_regular_formula &&) noexcept=default
\brief The and operator for state formulas
and_(and_ &&) noexcept=default
const state_formula & right() const
and_(const atermpp::aterm &term)
and_(const and_ &) noexcept=default
Move semantics.
and_(const state_formula &left, const state_formula &right)
\brief Constructor Z14.
and_ & operator=(const and_ &) noexcept=default
and_()
\brief Default constructor X3.
and_ & operator=(and_ &&) noexcept=default
const state_formula & left() const
\brief The multiply operator for state formulas with values
const_multiply_alt & operator=(const const_multiply_alt &) noexcept=default
const state_formula & left() const
const_multiply_alt(const state_formula &left, const data::data_expression &right)
\brief Constructor Z14.
const_multiply_alt(const const_multiply_alt &) noexcept=default
Move semantics.
const_multiply_alt(const_multiply_alt &&) noexcept=default
const data::data_expression & right() const
const_multiply_alt(const atermpp::aterm &term)
const_multiply_alt & operator=(const_multiply_alt &&) noexcept=default
const_multiply_alt()
\brief Default constructor X3.
\brief The multiply operator for state formulas with values
const data::data_expression & left() const
const_multiply(const const_multiply &) noexcept=default
Move semantics.
const_multiply(const data::data_expression &left, const state_formula &right)
\brief Constructor Z14.
const_multiply()
\brief Default constructor X3.
const_multiply(const_multiply &&) noexcept=default
const_multiply & operator=(const const_multiply &) noexcept=default
const_multiply & operator=(const_multiply &&) noexcept=default
const_multiply(const atermpp::aterm &term)
const state_formula & right() const
\brief The timed delay operator for state formulas
delay_timed(const atermpp::aterm &term)
delay_timed()
\brief Default constructor X3.
delay_timed & operator=(const delay_timed &) noexcept=default
const data::data_expression & time_stamp() const
delay_timed(const data::data_expression &time_stamp)
\brief Constructor Z14.
delay_timed(const delay_timed &) noexcept=default
Move semantics.
delay_timed(delay_timed &&) noexcept=default
delay_timed & operator=(delay_timed &&) noexcept=default
\brief The delay operator for state formulas
delay & operator=(delay &&) noexcept=default
delay()
\brief Default constructor X3.
delay(const delay &) noexcept=default
Move semantics.
delay(delay &&) noexcept=default
delay(const atermpp::aterm &term)
delay & operator=(const delay &) noexcept=default
\brief The existential quantification operator for state formulas
exists(const data::variable_list &variables, const state_formula &body)
\brief Constructor Z14.
const state_formula & body() const
exists(const exists &) noexcept=default
Move semantics.
exists(exists &&) noexcept=default
exists & operator=(const exists &) noexcept=default
exists & operator=(exists &&) noexcept=default
exists()
\brief Default constructor X3.
exists(const atermpp::aterm &term)
const data::variable_list & variables() const
\brief The value false for state formulas
false_(false_ &&) noexcept=default
false_ & operator=(const false_ &) noexcept=default
false_ & operator=(false_ &&) noexcept=default
false_(const atermpp::aterm &term)
false_(const false_ &) noexcept=default
Move semantics.
false_()
\brief Default constructor X3.
\brief The universal quantification operator for state formulas
const state_formula & body() const
forall(const atermpp::aterm &term)
const data::variable_list & variables() const
forall & operator=(const forall &) noexcept=default
forall & operator=(forall &&) noexcept=default
forall(const forall &) noexcept=default
Move semantics.
forall(const data::variable_list &variables, const state_formula &body)
\brief Constructor Z14.
forall(forall &&) noexcept=default
forall()
\brief Default constructor X3.
\brief The implication operator for state formulas
imp()
\brief Default constructor X3.
imp(imp &&) noexcept=default
imp(const state_formula &left, const state_formula &right)
\brief Constructor Z14.
imp & operator=(const imp &) noexcept=default
const state_formula & left() const
const state_formula & right() const
imp(const atermpp::aterm &term)
imp(const imp &) noexcept=default
Move semantics.
imp & operator=(imp &&) noexcept=default
\brief The infimum over a data type for state formulas
infimum(const infimum &) noexcept=default
Move semantics.
infimum()
\brief Default constructor X3.
infimum(const data::variable_list &variables, const state_formula &body)
\brief Constructor Z14.
infimum & operator=(infimum &&) noexcept=default
const data::variable_list & variables() const
const state_formula & body() const
infimum(const atermpp::aterm &term)
infimum(infimum &&) noexcept=default
infimum & operator=(const infimum &) noexcept=default
\brief The may operator for state formulas
const state_formula & operand() const
may()
\brief Default constructor X3.
const regular_formulas::regular_formula & formula() const
may & operator=(const may &) noexcept=default
may & operator=(may &&) noexcept=default
may(const regular_formulas::regular_formula &formula, const state_formula &operand)
\brief Constructor Z14.
may(may &&) noexcept=default
may(const atermpp::aterm &term)
may(const may &) noexcept=default
Move semantics.
\brief The minus operator for state formulas
minus & operator=(minus &&) noexcept=default
minus(minus &&) noexcept=default
minus(const minus &) noexcept=default
Move semantics.
minus(const atermpp::aterm &term)
minus(const state_formula &operand)
\brief Constructor Z14.
const state_formula & operand() const
minus & operator=(const minus &) noexcept=default
minus()
\brief Default constructor X3.
\brief The mu operator for state formulas
const core::identifier_string & name() const
const data::assignment_list & assignments() const
mu(const mu &) noexcept=default
Move semantics.
mu(const std::string &name, const data::assignment_list &assignments, const state_formula &operand)
\brief Constructor Z2.
mu(const core::identifier_string &name, const data::assignment_list &assignments, const state_formula &operand)
\brief Constructor Z14.
mu & operator=(const mu &) noexcept=default
mu(mu &&) noexcept=default
mu & operator=(mu &&) noexcept=default
mu(const atermpp::aterm &term)
mu()
\brief Default constructor X3.
const state_formula & operand() const
\brief The must operator for state formulas
must(must &&) noexcept=default
must & operator=(must &&) noexcept=default
must(const atermpp::aterm &term)
must(const regular_formulas::regular_formula &formula, const state_formula &operand)
\brief Constructor Z14.
const regular_formulas::regular_formula & formula() const
must(const must &) noexcept=default
Move semantics.
const state_formula & operand() const
must()
\brief Default constructor X3.
must & operator=(const must &) noexcept=default
\brief The not operator for state formulas
not_(not_ &&) noexcept=default
not_(const not_ &) noexcept=default
Move semantics.
not_ & operator=(const not_ &) noexcept=default
not_ & operator=(not_ &&) noexcept=default
not_()
\brief Default constructor X3.
not_(const atermpp::aterm &term)
const state_formula & operand() const
not_(const state_formula &operand)
\brief Constructor Z14.
\brief The nu operator for state formulas
nu(const atermpp::aterm &term)
nu(nu &&) noexcept=default
nu(const core::identifier_string &name, const data::assignment_list &assignments, const state_formula &operand)
\brief Constructor Z14.
nu()
\brief Default constructor X3.
nu & operator=(const nu &) noexcept=default
nu & operator=(nu &&) noexcept=default
const core::identifier_string & name() const
nu(const std::string &name, const data::assignment_list &assignments, const state_formula &operand)
\brief Constructor Z2.
const state_formula & operand() const
nu(const nu &) noexcept=default
Move semantics.
const data::assignment_list & assignments() const
\brief The or operator for state formulas
or_(or_ &&) noexcept=default
or_()
\brief Default constructor X3.
or_(const or_ &) noexcept=default
Move semantics.
or_(const state_formula &left, const state_formula &right)
\brief Constructor Z14.
or_ & operator=(const or_ &) noexcept=default
const state_formula & right() const
or_ & operator=(or_ &&) noexcept=default
or_(const atermpp::aterm &term)
const state_formula & left() const
\brief The plus operator for state formulas with values
plus & operator=(plus &&) noexcept=default
plus & operator=(const plus &) noexcept=default
plus(const plus &) noexcept=default
Move semantics.
const state_formula & left() const
plus(const atermpp::aterm &term)
plus()
\brief Default constructor X3.
const state_formula & right() const
plus(plus &&) noexcept=default
plus(const state_formula &left, const state_formula &right)
\brief Constructor Z14.
state_formula(const state_formula &) noexcept=default
Move semantics.
state_formula()
\brief Default constructor X3.
state_formula(state_formula &&) noexcept=default
bool has_time() const
Returns true if the formula is timed.
state_formula(const data::untyped_data_parameter &x)
\brief Constructor Z6.
state_formula & operator=(state_formula &&) noexcept=default
state_formula(const data::data_expression &x)
\brief Constructor Z6.
state_formula(const atermpp::aterm &term)
state_formula & operator=(const state_formula &) noexcept=default
\brief The sum over a data type for state formulas
sum(const sum &) noexcept=default
Move semantics.
sum(sum &&) noexcept=default
sum(const atermpp::aterm &term)
sum(const data::variable_list &variables, const state_formula &body)
\brief Constructor Z14.
sum & operator=(sum &&) noexcept=default
sum()
\brief Default constructor X3.
const data::variable_list & variables() const
const state_formula & body() const
sum & operator=(const sum &) noexcept=default
\brief The supremum over a data type for state formulas
supremum & operator=(supremum &&) noexcept=default
supremum(supremum &&) noexcept=default
supremum(const atermpp::aterm &term)
supremum()
\brief Default constructor X3.
supremum(const supremum &) noexcept=default
Move semantics.
supremum & operator=(const supremum &) noexcept=default
const state_formula & body() const
const data::variable_list & variables() const
supremum(const data::variable_list &variables, const state_formula &body)
\brief Constructor Z14.
\brief The value true for state formulas
true_()
\brief Default constructor X3.
true_ & operator=(const true_ &) noexcept=default
true_(true_ &&) noexcept=default
true_(const true_ &) noexcept=default
Move semantics.
true_(const atermpp::aterm &term)
true_ & operator=(true_ &&) noexcept=default
\brief The state formula variable
variable & operator=(const variable &) noexcept=default
variable(const core::identifier_string &name, const data::data_expression_list &arguments)
\brief Constructor Z14.
variable(const variable &) noexcept=default
Move semantics.
variable(const std::string &name, const data::data_expression_list &arguments)
\brief Constructor Z2.
variable()
\brief Default constructor X3.
variable & operator=(variable &&) noexcept=default
const core::identifier_string & name() const
const data::data_expression_list & arguments() const
variable(variable &&) noexcept=default
variable(const atermpp::aterm &term)
\brief The timed yaled operator for state formulas
yaled_timed(yaled_timed &&) noexcept=default
yaled_timed & operator=(const yaled_timed &) noexcept=default
yaled_timed()
\brief Default constructor X3.
yaled_timed & operator=(yaled_timed &&) noexcept=default
yaled_timed(const yaled_timed &) noexcept=default
Move semantics.
yaled_timed(const data::data_expression &time_stamp)
\brief Constructor Z14.
yaled_timed(const atermpp::aterm &term)
const data::data_expression & time_stamp() const
\brief The yaled operator for state formulas
yaled()
\brief Default constructor X3.
yaled(const atermpp::aterm &term)
yaled & operator=(const yaled &) noexcept=default
yaled(const yaled &) noexcept=default
Move semantics.
yaled(yaled &&) noexcept=default
yaled & operator=(yaled &&) noexcept=default
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:435
std::string pp(const term_balanced_tree< Term > t)
bool is_aterm_balanced_tree(const aterm &t)
void make_term_balanced_tree(term_balanced_tree< Term > &result, ForwardTraversalIterator p, std::size_t size, Transformer transformer)
void make_exists(atermpp::aterm &t, const ARGUMENTS &... args)
void swap(or_ &t1, or_ &t2) noexcept
\brief swap overload
std::string pp(const action_formulas::exists &x, bool arg0)
bool is_at(const atermpp::aterm &x)
void swap(forall &t1, forall &t2) noexcept
\brief swap overload
std::string pp(const action_formulas::imp &x, bool arg0)
void make_and(atermpp::aterm &t, const ARGUMENTS &... args)
std::ostream & operator<<(std::ostream &out, const or_ &x)
std::string pp(const action_formulas::at &x, bool arg0)
std::ostream & operator<<(std::ostream &out, const action_formula &x)
std::string pp(const action_formulas::forall &x, bool arg0)
std::string pp(const action_formulas::or_ &x, bool arg0)
std::string pp(const action_formulas::action_formula &x, bool arg0)
std::ostream & operator<<(std::ostream &out, const true_ &x)
std::ostream & operator<<(std::ostream &out, const exists &x)
std::ostream & operator<<(std::ostream &out, const at &x)
std::string pp(const action_formulas::true_ &x, bool arg0)
std::set< data::variable > find_all_variables(const action_formulas::action_formula &x)
bool is_or(const atermpp::aterm &x)
void swap(action_formula &t1, action_formula &t2) noexcept
\brief swap overload
bool is_true(const atermpp::aterm &x)
bool is_forall(const atermpp::aterm &x)
void swap(not_ &t1, not_ &t2) noexcept
\brief swap overload
std::string pp(const action_formulas::not_ &x, bool arg0)
std::ostream & operator<<(std::ostream &out, const and_ &x)
void make_or(atermpp::aterm &t, const ARGUMENTS &... args)
void swap(true_ &t1, true_ &t2) noexcept
\brief swap overload
std::ostream & operator<<(std::ostream &out, const false_ &x)
bool is_false(const atermpp::aterm &x)
bool is_not(const atermpp::aterm &x)
void swap(false_ &t1, false_ &t2) noexcept
\brief swap overload
void swap(and_ &t1, and_ &t2) noexcept
\brief swap overload
void make_imp(atermpp::aterm &t, const ARGUMENTS &... args)
bool is_imp(const atermpp::aterm &x)
bool is_and(const atermpp::aterm &x)
void make_forall(atermpp::aterm &t, const ARGUMENTS &... args)
void swap(multi_action &t1, multi_action &t2) noexcept
\brief swap overload
void swap(imp &t1, imp &t2) noexcept
\brief swap overload
std::ostream & operator<<(std::ostream &out, const forall &x)
void swap(exists &t1, exists &t2) noexcept
\brief swap overload
std::ostream & operator<<(std::ostream &out, const imp &x)
std::ostream & operator<<(std::ostream &out, const multi_action &x)
void make_multi_action(atermpp::aterm &t, const ARGUMENTS &... args)
bool is_multi_action(const atermpp::aterm &x)
void make_not(atermpp::aterm &t, const ARGUMENTS &... args)
std::ostream & operator<<(std::ostream &out, const not_ &x)
std::string pp(const action_formulas::multi_action &x, bool arg0)
void swap(at &t1, at &t2) noexcept
\brief swap overload
void make_at(atermpp::aterm &t, const ARGUMENTS &... args)
std::string pp(const action_formulas::false_ &x, bool arg0)
bool is_exists(const atermpp::aterm &x)
std::string pp(const action_formulas::and_ &x, bool arg0)
bool is_action_formula(const atermpp::aterm &x)
static data_specification const & default_specification()
Definition parse.h:28
Namespace for system defined sort bool_.
Definition bool.h:29
const function_symbol & false_()
Constructor for function symbol false.
Definition bool.h:106
const function_symbol & true_()
Constructor for function symbol true.
Definition bool.h:74
Namespace for system defined sort int_.
application cint(const data_expression &arg0)
Application of function symbol @cInt.
Definition int1.h:101
const basic_sort & int_()
Constructor for sort expression Int.
Definition int1.h:44
Namespace for system defined sort nat.
const basic_sort & nat()
Constructor for sort expression Nat.
Definition nat1.h:43
application cnat(const data_expression &arg0)
Application of function symbol @cNat.
Definition nat1.h:161
Namespace for system defined sort pos.
const function_symbol & c1()
Constructor for function symbol @c1.
Definition pos1.h:75
const basic_sort & pos()
Constructor for sort expression Pos.
Definition pos1.h:42
Namespace for system defined sort real_.
data_expression & real_one()
application creal(const data_expression &arg0, const data_expression &arg1)
Application of function symbol @cReal.
Definition real1.h:129
data_expression & real_zero()
const basic_sort & real_()
Constructor for sort expression Real.
Definition real1.h:45
application plus(const data_expression &arg0, const data_expression &arg1)
Application of function symbol +.
Definition real1.h:1112
application minus(const data_expression &arg0, const data_expression &arg1)
Application of function symbol -.
Definition real1.h:1197
bool is_data_expression(const atermpp::aterm &x)
Test for a data_expression expression.
application less(const data_expression &arg0, const data_expression &arg1)
Application of function symbol <.
Definition standard.h:263
bool is_untyped_data_parameter(const atermpp::aterm &x)
application equal_to(const data_expression &arg0, const data_expression &arg1)
Application of function symbol ==.
Definition standard.h:149
std::pair< std::set< data::variable >, std::set< data::variable > > read_write_parameters(const lps::action_summand &summand, const std::set< data::variable > &process_parameters)
Computes the read and written process parameters for the given summand.
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
multi_action complete_multi_action(process::untyped_multi_action &x, const process::action_label_list &action_decls, const data::data_specification &data_spec=data::detail::default_specification())
Definition lps.cpp:148
void remove_common_divisor(std::size_t &enumerator, std::size_t &denominator)
void complete_action_rename_specification(action_rename_specification &x, const lps::stochastic_specification &spec)
Definition lps.cpp:166
process::untyped_multi_action parse_multi_action_new(const std::string &text)
Definition lps.cpp:130
multi_action complete_multi_action(process::untyped_multi_action &x, multi_action_type_checker &typechecker, const data::data_specification &data_spec=data::detail::default_specification())
Definition lps.cpp:140
std::size_t greatest_common_divisor(std::size_t x, std::size_t y)
action_rename_specification parse_action_rename_specification_new(const std::string &text)
Definition lps.cpp:156
The main namespace for the LPS library.
Definition constelm.h:18
specification parse_linear_process_specification(const std::string &text)
Parses a linear process specification from a string.
Definition parse.h:149
void complete_data_specification(stochastic_specification &spec)
Adds all sorts that appear in the process of l to the data specification of l.
multi_action parse_multi_action(const std::string &text, const process::action_label_list &action_decls, const data::data_specification &data_spec=data::detail::default_specification())
Parses a multi_action from a string.
Definition parse.h:67
void parse_lps(std::istream &, Specification &)
Definition parse.h:156
process::action parse_action(const std::string &text, const process::action_label_list &action_decls, const data::data_specification &data_spec=data::detail::default_specification())
Parses an action from a string.
Definition parse.h:208
void complete_data_specification(specification &spec)
Adds all sorts that appear in the process of l to the data specification of l.
std::string pp(const probabilistic_data_expression &l)
multi_action parse_multi_action(std::stringstream &in, multi_action_type_checker &typechecker, const data::data_specification &data_spec=data::detail::default_specification())
Parses a multi_action from an input stream.
Definition parse.h:53
action_rename_specification parse_action_rename_specification(std::istream &in, const lps::stochastic_specification &spec)
Parses a process specification from an input stream.
Definition parse.h:91
std::ostream & operator<<(std::ostream &out, const probabilistic_data_expression &x)
Pretty print to an outstream.
multi_action parse_multi_action(std::stringstream &in, const process::action_label_list &action_decls, const data::data_specification &data_spec=data::detail::default_specification())
Parses a multi_action from an input stream.
Definition parse.h:39
action_rename_specification parse_action_rename_specification(const std::string &spec_string, const lps::stochastic_specification &spec)
Parses an action rename specification. Parses an action rename specification. If the action rename sp...
Definition parse.h:107
void parse_lps< specification >(std::istream &from, specification &result)
Definition parse.h:163
void make_state(state &result, ForwardTraversalIterator p, const std::size_t size)
Definition state.h:33
void parse_lps< stochastic_specification >(std::istream &from, stochastic_specification &result)
Parses a stochastic linear process specification from an input stream.
Definition parse.h:180
std::string pp(const lps::state &x)
Definition state.h:44
multi_action parse_multi_action(const std::string &text, multi_action_type_checker &typechecker, const data::data_specification &data_spec=data::detail::default_specification())
Parses a multi_action from a string.
Definition parse.h:80
void parse_lps(const std::string &text, Specification &result)
Definition parse.h:194
specification parse_linear_process_specification(std::istream &spec_stream)
Parses a linear process specification from an input stream.
Definition parse.h:125
void make_state(state &result, ForwardTraversalIterator p, const std::size_t size, Transformer transformer)
Definition state.h:24
bool bisimulation_compare(const LTS_TYPE &l1, const LTS_TYPE &l2, bool branching=false, bool preserve_divergences=false, bool generate_counter_examples=false, const std::string &counter_example_file="", bool structured_output=false)
Checks whether the two initial states of two lts's are strong or branching bisimilar.
lts_type guess_format(std::string const &s, const bool be_verbose)
Determines the LTS format from a filename by its extension.
Definition liblts.cpp:26
static const std::array< std::string, 5 > extension_strings
Definition liblts.cpp:73
std::string supported_lts_formats_text(const std::set< lts_type > &supported)
Gives a textual list describing supported LTS formats.
Definition liblts.cpp:185
bool destructive_bisimulation_compare_minimal_depth(LTS_TYPE &l1, LTS_TYPE &l2, const std::string &counter_example_file)
std::string string_for_type(const lts_type type)
Gives a string representation of an LTS format.
Definition liblts.cpp:112
void unmark_explicit_divergence_transitions(LTS_TYPE &l, const std::size_t divergent_transition_label)
std::string mime_type_for_type(const lts_type type)
Gives the MIME type associated with an LTS format.
Definition liblts.cpp:122
void get_trans(const outgoing_transitions_per_state_t &begin, tree_set_store &tss, std::ptrdiff_t d, std::vector< transition > &d_trans, LTS_TYPE &aut)
lts_type parse_format(std::string const &s)
Determines the LTS format from a format specification string.
Definition liblts.cpp:91
static const std::array< std::string, 5 > type_strings
Definition liblts.cpp:71
std::string extension_for_type(const lts_type type)
Gives the filename extension associated with an LTS format.
Definition liblts.cpp:117
LABEL_TYPE make_divergence_label(const std::string &s)
const std::set< lts_type > & supported_lts_formats()
Gives the set of all supported LTS formats.
Definition liblts.cpp:139
std::string lts_extensions_as_string(const std::set< lts_type > &supported)
Gives a list of extensions for supported LTS formats.
Definition liblts.cpp:221
std::string lts_extensions_as_string(const std::string &sep, const std::set< lts_type > &supported)
Gives a list of extensions for supported LTS formats.
Definition liblts.cpp:190
std::size_t mark_explicit_divergence_transitions(LTS_TYPE &l)
bool destructive_bisimulation_compare(LTS_TYPE &l1, LTS_TYPE &l2, bool branching=false, bool preserve_divergences=false, bool generate_counter_examples=false, const std::string &counter_example_file="", bool structured_output=false)
Checks whether the two initial states of two lts's are strong or branching bisimilar.
void bisimulation_reduce(LTS_TYPE &l, bool branching=false, bool preserve_divergences=false)
Reduce transition system l with respect to strong or (divergence preserving) branching bisimulation.
bool lts_named_cmp(const std::array< std::string, Size > &N, T a, T b)
Definition liblts.cpp:147
std::string supported_lts_formats_text(lts_type default_format, const std::set< lts_type > &supported)
Gives a textual list describing supported LTS formats.
Definition liblts.cpp:152
static const std::array< std::string, 5 > type_desc_strings
Definition liblts.cpp:75
static const std::array< std::string, 5 > mime_type_strings
Definition liblts.cpp:84
static const std::set< lts_type > & initialise_supported_lts_formats()
Definition liblts.cpp:127
bool destructive_compare(LTS_TYPE &l1, LTS_TYPE &l2, lts_preorder pre, bool generate_counter_example, const std::string &counter_example_file="", bool structured_output=false, lps::exploration_strategy strategy=lps::exploration_strategy::es_breadth, bool preprocess=true)
Checks whether this LTS is smaller than another LTS according to a preorder.
std::string pp(const state_label_dot &l)
Pretty print function for a state_label_dot. Only prints the label field.
Definition lts_dot.h:97
void check_lts(const LTS_TYPE &ltsspec)
Throws a runtime error if the LTS contains a transition with an invalid action label index.
std::set< process::action_label > find_action_labels(const LTS_TYPE &ltsspec)
Returns the action labels that occur in the transitions of the given LTS.
std::string pp(const state_label_lts &label)
Pretty print a state value of this LTS.
Definition lts_lts.h:106
bool is_deterministic(const LTS_TYPE &l)
Checks whether this LTS is deterministic.
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.
action_label_lts parse_lts_action(const std::string &multi_action_string, const data::data_specification &data_spec, lps::multi_action_type_checker &typechecker)
Parse a string into an action label.
Definition lts_lts.h:200
void group_transitions_on_label(std::vector< transition > &transitions, std::function< std::size_t(const transition &)> get_label, const std::size_t number_of_labels, const std::size_t tau_label_index)
std::size_t to(const outgoing_pair_t &p)
Target state of a label state pair.
std::string pp(const state_label_fsm &label)
Pretty print an fsm state label.
Definition lts_fsm.h:75
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 determinise(LTS_TYPE &l)
Determinises this LTS.
bool compare(const LTS_TYPE &l1, const LTS_TYPE &l2, lts_preorder pre, bool generate_counter_example, const std::string &counter_example_file="", bool structured_output=false, lps::exploration_strategy strategy=lps::exploration_strategy::es_breadth, bool preprocess=true)
Checks whether this LTS is smaller than another LTS according to a preorder.
std::string pp(const probabilistic_state< STATE, PROBABILITY > &l)
std::ostream & operator<<(std::ostream &out, const probabilistic_state< STATE, PROBABILITY > &l)
Pretty print to an outstream.
void reduce(LTS_TYPE &l, lts_equivalence eq)
Applies a reduction algorithm to this LTS.
bool compare(const LTS_TYPE &l1, const LTS_TYPE &l2, lts_equivalence eq, bool generate_counter_examples=false, const std::string &counter_example_file="", bool structured_output=false)
Checks whether this LTS is equivalent to another LTS.
outgoing_transitions_per_state_action_t transitions_per_outgoing_state_action_pair_reversed(const std::vector< transition > &trans, const std::set< transition::size_type > &hide_label_set)
Provide the transitions as a multimap accessible per from state and label, ordered backwardly.
bool destructive_compare(LTS_TYPE &l1, LTS_TYPE &l2, const lts_equivalence eq, const bool generate_counter_examples=false, const std::string &counter_example_file=std::string(), const bool structured_output=false)
Checks whether this LTS is equivalent to another LTS.
std::string pp(const action_label_lts &l)
Print the action label to string.
Definition lts_lts.h:187
outgoing_transitions_per_state_action_t transitions_per_outgoing_state_action_pair(const std::vector< transition > &trans, const std::set< transition::size_type > &hide_label_set)
Provide the transitions as a multimap accessible per from state and label.
void merge(LTS_TYPE &l1, const LTS_TYPE &l2)
Merge the second lts into the first lts.
bool reachability_check(lts< SL, AL, BASE > &l, bool remove_unreachable=false)
Checks whether all states in this LTS are reachable from the initial state and remove unreachable sta...
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)
bool reachability_check(probabilistic_lts< SL, AL, PROBABILISTIC_STATE, BASE > &l, bool remove_unreachable=false)
Checks whether all states in a probabilistic LTS are reachable from the initial state and remove unre...
void sort_transitions(std::vector< transition > &transitions, const std::set< transition::size_type > &hidden_label_set, transition_sort_style ts=transition_sort_style::src_lbl_tgt)
Sorts the transitions using a sort style.
The main namespace for the Process library.
bool is_linear(const process_specification &p, bool verbose=false)
Returns true if the process specification is linear.
Definition is_linear.h:344
bool is_untyped_multi_action(const atermpp::aterm &x)
void swap(trans &t1, trans &t2) noexcept
\brief swap overload
bool is_alt(const atermpp::aterm &x)
bool is_untyped_regular_formula(const atermpp::aterm &x)
void make_trans(atermpp::aterm &t, const ARGUMENTS &... args)
std::ostream & operator<<(std::ostream &out, const regular_formula &x)
void make_seq(atermpp::aterm &t, const ARGUMENTS &... args)
void make_trans_or_nil(atermpp::aterm &t, const ARGUMENTS &... args)
bool is_trans(const atermpp::aterm &x)
std::string pp(const regular_formulas::trans &x, bool arg0)
void make_alt(atermpp::aterm &t, const ARGUMENTS &... args)
void make_untyped_regular_formula(atermpp::aterm &t, const ARGUMENTS &... args)
std::string pp(const regular_formulas::alt &x, bool arg0)
std::ostream & operator<<(std::ostream &out, const trans &x)
void swap(untyped_regular_formula &t1, untyped_regular_formula &t2) noexcept
\brief swap overload
bool is_trans_or_nil(const atermpp::aterm &x)
std::ostream & operator<<(std::ostream &out, const untyped_regular_formula &x)
bool is_regular_formula(const atermpp::aterm &x)
void swap(trans_or_nil &t1, trans_or_nil &t2) noexcept
\brief swap overload
std::ostream & operator<<(std::ostream &out, const trans_or_nil &x)
bool is_seq(const atermpp::aterm &x)
std::string pp(const regular_formulas::untyped_regular_formula &x, bool arg0)
std::string pp(const regular_formulas::seq &x, bool arg0)
std::string pp(const regular_formulas::trans_or_nil &x, bool arg0)
void swap(seq &t1, seq &t2) noexcept
\brief swap overload
std::ostream & operator<<(std::ostream &out, const seq &x)
void swap(regular_formula &t1, regular_formula &t2) noexcept
\brief swap overload
std::ostream & operator<<(std::ostream &out, const alt &x)
std::string pp(const regular_formulas::regular_formula &x, bool arg0)
void swap(alt &t1, alt &t2) noexcept
\brief swap overload
bool is_timed(const state_formula &x)
void swap(variable &t1, variable &t2) noexcept
\brief swap overload
bool is_infimum(const atermpp::aterm &x)
std::string pp(const state_formulas::nu &x, bool arg0)
std::string pp(const state_formulas::exists &x, bool arg0)
std::string pp(const state_formulas::not_ &x, bool arg0)
std::ostream & operator<<(std::ostream &out, const not_ &x)
bool is_and(const atermpp::aterm &x)
void swap(minus &t1, minus &t2) noexcept
\brief swap overload
std::ostream & operator<<(std::ostream &out, const sum &x)
std::string pp(const state_formulas::supremum &x, bool arg0)
bool is_delay_timed(const atermpp::aterm &x)
void swap(exists &t1, exists &t2) noexcept
\brief swap overload
bool is_const_multiply(const atermpp::aterm &x)
std::ostream & operator<<(std::ostream &out, const exists &x)
std::string pp(const state_formulas::must &x, bool arg0)
void swap(const_multiply_alt &t1, const_multiply_alt &t2) noexcept
\brief swap overload
void make_or(atermpp::aterm &t, const ARGUMENTS &... args)
bool is_minus(const atermpp::aterm &x)
void make_imp(atermpp::aterm &t, const ARGUMENTS &... args)
bool is_exists(const atermpp::aterm &x)
void swap(may &t1, may &t2) noexcept
\brief swap overload
void swap(mu &t1, mu &t2) noexcept
\brief swap overload
bool is_not(const atermpp::aterm &x)
std::string pp(const state_formulas::minus &x, bool arg0)
bool is_state_formula(const atermpp::aterm &x)
void swap(sum &t1, sum &t2) noexcept
\brief swap overload
std::ostream & operator<<(std::ostream &out, const const_multiply &x)
std::ostream & operator<<(std::ostream &out, const may &x)
void make_const_multiply(atermpp::aterm &t, const ARGUMENTS &... args)
std::ostream & operator<<(std::ostream &out, const nu &x)
void make_exists(atermpp::aterm &t, const ARGUMENTS &... args)
void swap(supremum &t1, supremum &t2) noexcept
\brief swap overload
bool is_supremum(const atermpp::aterm &x)
void swap(true_ &t1, true_ &t2) noexcept
\brief swap overload
std::ostream & operator<<(std::ostream &out, const minus &x)
bool is_must(const atermpp::aterm &x)
void swap(const_multiply &t1, const_multiply &t2) noexcept
\brief swap overload
std::set< data::variable > find_all_variables(const state_formulas::state_formula &x)
std::ostream & operator<<(std::ostream &out, const imp &x)
bool is_yaled(const atermpp::aterm &x)
std::ostream & operator<<(std::ostream &out, const mu &x)
std::ostream & operator<<(std::ostream &out, const must &x)
std::ostream & operator<<(std::ostream &out, const supremum &x)
void swap(not_ &t1, not_ &t2) noexcept
\brief swap overload
std::set< data::variable > find_free_variables(const state_formulas::state_formula &x)
void swap(state_formula &t1, state_formula &t2) noexcept
\brief swap overload
bool is_true(const atermpp::aterm &x)
std::string pp(const state_formulas::true_ &x, bool arg0)
void make_and(atermpp::aterm &t, const ARGUMENTS &... args)
std::ostream & operator<<(std::ostream &out, const true_ &x)
std::string pp(const state_formulas::state_formula &x, bool arg0)
std::ostream & operator<<(std::ostream &out, const variable &x)
std::ostream & operator<<(std::ostream &out, const state_formula &x)
void swap(plus &t1, plus &t2) noexcept
\brief swap overload
std::string pp(const state_formulas::const_multiply &x, bool arg0)
void make_plus(atermpp::aterm &t, const ARGUMENTS &... args)
std::ostream & operator<<(std::ostream &out, const and_ &x)
std::string pp(const state_formulas::delay_timed &x, bool arg0)
void swap(yaled &t1, yaled &t2) noexcept
\brief swap overload
void swap(delay &t1, delay &t2) noexcept
\brief swap overload
bool is_variable(const atermpp::aterm &x)
std::ostream & operator<<(std::ostream &out, const forall &x)
void make_infimum(atermpp::aterm &t, const ARGUMENTS &... args)
bool is_may(const atermpp::aterm &x)
std::ostream & operator<<(std::ostream &out, const yaled_timed &x)
bool is_yaled_timed(const atermpp::aterm &x)
bool is_imp(const atermpp::aterm &x)
void swap(yaled_timed &t1, yaled_timed &t2) noexcept
\brief swap overload
void make_delay_timed(atermpp::aterm &t, const ARGUMENTS &... args)
std::string pp(const state_formulas::imp &x, bool arg0)
std::ostream & operator<<(std::ostream &out, const or_ &x)
std::string pp(const state_formulas::mu &x, bool arg0)
void make_const_multiply_alt(atermpp::aterm &t, const ARGUMENTS &... args)
void make_may(atermpp::aterm &t, const ARGUMENTS &... args)
bool is_sum(const atermpp::aterm &x)
state_formulas::state_formula translate_user_notation(const state_formulas::state_formula &x)
void make_must(atermpp::aterm &t, const ARGUMENTS &... args)
state_formulas::state_formula normalize_sorts(const state_formulas::state_formula &x, const data::sort_specification &sortspec)
void swap(and_ &t1, and_ &t2) noexcept
\brief swap overload
bool is_nu(const atermpp::aterm &x)
void swap(false_ &t1, false_ &t2) noexcept
\brief swap overload
std::string pp(const state_formulas::delay &x, bool arg0)
std::ostream & operator<<(std::ostream &out, const false_ &x)
std::string pp(const state_formulas::forall &x, bool arg0)
void swap(forall &t1, forall &t2) noexcept
\brief swap overload
std::string pp(const state_formulas::sum &x, bool arg0)
void swap(delay_timed &t1, delay_timed &t2) noexcept
\brief swap overload
void swap(infimum &t1, infimum &t2) noexcept
\brief swap overload
std::ostream & operator<<(std::ostream &out, const plus &x)
std::string pp(const state_formulas::yaled &x, bool arg0)
bool is_delay(const atermpp::aterm &x)
std::ostream & operator<<(std::ostream &out, const infimum &x)
std::string pp(const state_formulas::infimum &x, bool arg0)
std::string pp(const state_formulas::or_ &x, bool arg0)
std::ostream & operator<<(std::ostream &out, const delay &x)
std::string pp(const state_formulas::may &x, bool arg0)
bool is_false(const atermpp::aterm &x)
void make_variable(atermpp::aterm &t, const ARGUMENTS &... args)
void make_nu(atermpp::aterm &t, const ARGUMENTS &... args)
void make_supremum(atermpp::aterm &t, const ARGUMENTS &... args)
void make_sum(atermpp::aterm &t, const ARGUMENTS &... args)
void swap(must &t1, must &t2) noexcept
\brief swap overload
bool is_plus(const atermpp::aterm &x)
std::ostream & operator<<(std::ostream &out, const delay_timed &x)
void make_not(atermpp::aterm &t, const ARGUMENTS &... args)
void swap(nu &t1, nu &t2) noexcept
\brief swap overload
std::string pp(const state_formulas::and_ &x, bool arg0)
void make_forall(atermpp::aterm &t, const ARGUMENTS &... args)
std::string pp(const state_formulas::false_ &x, bool arg0)
std::string pp(const state_formulas::const_multiply_alt &x, bool arg0)
bool is_mu(const atermpp::aterm &x)
bool is_forall(const atermpp::aterm &x)
void make_minus(atermpp::aterm &t, const ARGUMENTS &... args)
bool is_const_multiply_alt(const atermpp::aterm &x)
void swap(or_ &t1, or_ &t2) noexcept
\brief swap overload
std::string pp(const state_formulas::yaled_timed &x, bool arg0)
std::string pp(const state_formulas::plus &x, bool arg0)
bool is_or(const atermpp::aterm &x)
void make_yaled_timed(atermpp::aterm &t, const ARGUMENTS &... args)
std::string pp(const state_formulas::variable &x, bool arg0)
void swap(imp &t1, imp &t2) noexcept
\brief swap overload
std::set< data::sort_expression > find_sort_expressions(const state_formulas::state_formula &x)
bool find_nil(const state_formulas::state_formula &x)
std::ostream & operator<<(std::ostream &out, const const_multiply_alt &x)
std::set< process::action_label > find_action_labels(const state_formulas::state_formula &x)
std::ostream & operator<<(std::ostream &out, const yaled &x)
void make_mu(atermpp::aterm &t, const ARGUMENTS &... args)
std::set< core::identifier_string > find_identifiers(const state_formulas::state_formula &x)
void swap(atermpp::term_balanced_tree< T > &t1, atermpp::term_balanced_tree< T > &t2) noexcept
Swaps two balanced trees.
static const atermpp::aterm StateMay
static const atermpp::aterm StateOr
static const atermpp::aterm UntypedRegFrm
static const atermpp::aterm StateFrm
static const atermpp::aterm StateYaled
static const atermpp::aterm RegAlt
static const atermpp::aterm ActNot
static const atermpp::aterm ActImp
static const atermpp::aterm ActTrue
static const atermpp::aterm StateInfimum
static const atermpp::aterm StateAnd
static const atermpp::aterm StateExists
static const atermpp::aterm RegTrans
static const atermpp::aterm ActOr
static const atermpp::aterm StateConstantMultiplyAlt
static const atermpp::aterm ActFrm
static const atermpp::aterm ActForall
static const atermpp::aterm StateYaledTimed
static const atermpp::aterm ActFalse
static const atermpp::aterm StateFalse
static const atermpp::aterm RegFrm
static const atermpp::aterm StateDelay
static const atermpp::aterm StatePlus
static const atermpp::aterm StateMinus
static const atermpp::aterm StateNu
static const atermpp::aterm ActAnd
static const atermpp::aterm StateDelayTimed
static const atermpp::aterm StateSupremum
static const atermpp::aterm StateSum
static const atermpp::aterm ActAt
static const atermpp::aterm ActExists
static const atermpp::aterm StateMu
static const atermpp::aterm RegTransOrNil
static const atermpp::aterm StateVar
static const atermpp::aterm StateImp
static const atermpp::aterm RegSeq
static const atermpp::aterm StateTrue
static const atermpp::aterm StateForall
static const atermpp::aterm StateMust
static const atermpp::aterm StateNot
static const atermpp::aterm ActMultAct
static const atermpp::aterm StateConstantMultiply
std::vector< transition > non_inert_transitions
std::vector< non_bottom_state > non_bottom_states
non_bottom_state(const state_type s, const std::vector< state_type > &it)
Converts a process expression into linear process format. Use the convert member functions for this.
lps::specification convert(const process_specification &p)
Converts a process_specification into a specification. Throws non_linear_process if a non-linear sub-...
Converts a process expression into linear process format. Use the convert member functions for this.
lps::stochastic_specification convert(const process_specification &p)
Converts a process_specification into a stochastic_specification. Throws non_linear_process if a non-...
std::size_t operator()(const atermpp::term_balanced_tree< T > &t) const
std::size_t operator()(const mcrl2::lps::probabilistic_data_expression &p) const
std::size_t operator()(const mcrl2::lps::state_probability_pair< STATE, PROBABILITY > &p) const
std::size_t operator()(const mcrl2::lts::action_label_lts &as) const
Definition lts_lts.h:423
std::size_t operator()(const mcrl2::lts::probabilistic_state< STATE, PROBABILITY > &p) const