mCRL2
Loading...
Searching...
No Matches
check_complexity.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
72
73#ifndef _CHECK_COMPLEXITY_H
74#define _CHECK_COMPLEXITY_H
75
76// If the preprocessor constant `COUNT_WORK_BALANCE` is defined, the temporary
77// work is even counted in non-debug modes. No checks are executed; we only
78// keep enough information to print a grand total at the end.
79// In this mode, we at least need to call `init()`, `finalise_work()`,
80// `cancel_work()`, and `wait()`. It is not necessary to preserve
81// `add_work_notemporary()`. The function `print_grand_totals()` prints a
82// verbose message about the number of coroutine steps executed.
83//#define COUNT_WORK_BALANCE
84
85// If the preprocessor constant `TEST_WORK_COUNTER_NAMES` is defined,
86// initialising will print an overview of the defined work counter names (to
87// check whether the constants defined in this file correspond properly with
88// the strings in `check_complexity.cpp`) and terminate.
89//#define TEST_WORK_COUNTER_NAMES
90
91#include <cstring> // for std::size_t and std::memset()
92#include <cassert>
93#include <cmath> // for std::log2()
94#include <climits> // for CHAR_BIT
95
97
98
99namespace mcrl2
100{
101namespace lts
102{
103namespace detail
104{
105
112typedef std::size_t state_type;
113#define STATE_TYPE_MIN (std::numeric_limits<state_type>::min())
114#define STATE_TYPE_MAX (std::numeric_limits<state_type>::max())
115
122typedef std::size_t trans_type;
123#define TRANS_TYPE_MIN (std::numeric_limits<trans_type>::min())
124#define TRANS_TYPE_MAX (std::numeric_limits<trans_type>::max())
125
126#if !defined(NDEBUG) || defined(COUNT_WORK_BALANCE)
127
129typedef std::make_signed<trans_type>::type signed_trans_type;
130
138{
139 public:
150 {
151 // block counters: every state in the block is regarded as visited. In
152 // this way, every state is ``visited'' O(log n) times.
153 // Invariant of the following block counters:
154 // 0 <= (counter value) <= ilog2(n) - ilog2(constellation size)
157
158 // If a loop runs over every state of a block exactly once, we simplify
159 // the task of updating the counters by making the corresponding loop
160 // counter a block counter:
162 // Invariant of the following block counters:
163 // 0 <= (counter value) <= ilog2(n) - ilog2(block size)
168
169 // state counters: every state is visited O(log n) times
170 // Invariant: 0 <= (counter value) <= ilog2(n) - ilog2(block size)
173
174 // The following counters are used when one refines a block: the first
175 // group is used to store the amount of work that (a posteriori) turns
176 // out to be useful. After that, there are two groups of counters to
177 // store temporary work.
180
181 // temporary state counters (blue):
185
186 // temporary state counters (red):
189
190 // new bottom state counters: every state is visited once
191 // Invariant: if s is a non-bottom state, the counter is 0;
192 // otherwise, the counter is 0 or 1.
194 // the next counter is used to count the work done on a virtual
195 // self-loop in line 4.15 (the new bottom state is regarded as red
196 // because it is in the splitter, but there is no transition to the
197 // splitter).
200
201 // B_to_C_descriptor counters: every transition in the B_to_C-slice is
202 // regarded as visited. In this way, every transition is ``visited''
203 // O(log n) times.
204 // Invariant:
205 // 0 <= (counter value) <= ilog2(n) - ilog2(target constellation size)
208
209 // If a loop runs over every transition in a B_to_C slice exactly once,
210 // we simplify the task of updating the counters by making the
211 // corresponding loop counter a B_to_C counter:
213 // the following counter is also meant for temporary work.
214 // Sometimes, after separating the new bottom states from the old ones,
215 // a constellation is reachable from the block of the new bottom
216 // states, but only from non-bottom states in this block. In that
217 // case, it cannot yet be determined which state will be a new bottom
218 // state. Then, the work is assigned temporarily to the B_to_C slice,
219 // until some new bottom state is found to which to assign it.
224
225 // transition counters: every transition is visited O(log n) times
226 // counters for transitions into the splitter NewC
227 // Invariant:
228 // 0 <= (counter value) <= ilog2(n) - ilog2(target constln size)
234
235 // counters for outgoing transitions
236 // Invariant:
237 // 0 <= (counter value) <= ilog2(n) - ilog2(source block size)
241
242 // counters for incoming transitions
243 // Invariant:
244 // 0 <= (counter value) <= ilog2(n) - ilog2(target block size)
247
248 // temporary transition counters for refine: similar to the temporary
249 // counters for states, we have a first group to store the work done
250 // for the smaller half, and temporary counters to store the work until
251 // it becomes clear which half wins.
252 // Because we have to sort the transitions into those to NewC, the
253 // outgoing and the incoming transitions, these counters are
254 // distributed above. The counters used to store the work done for
255 // the smaller half are: refine_outgoing_transition_3_6_or_23l,
256 // refine_outgoing_transition_to_marked_state_3_6l and
257 // refine_incoming_transition_3_18.
258
259 // temporary transition counters (blue):
264 // The work in the following counter is assigned to red (new
265 // bottom) states if the blue block is smaller!
267
268 // temporary transition counters (red):
272
273 // new bottom transition counters: every transition is visited once
274 // Invariant: If source is a non-bottom state, the counter is 0;
275 // otherwise, the counter is 0 or 1.
278 // For the following counters, we have an ``a priori'' and an ``a
279 // posteriori'' variant. The reason is, as explained with the
280 // B_to_C slice counters, that sometimes a constellation is
281 // reachable from the block of new bottom states but it is not yet
282 // clear which of the source states will become a new bottom state.
283 // In that case, the ``a posteriori'' counters are used. Later,
284 // the same block and the same constellation may be refined another
285 // time, but now with known new bottom states; then, the ``a
286 // priori'' counters are used.
293
294 /*-------------- counters for the bisim_jgkw algorithm --------------*/
295
296 // block counters
297 // Block counters are used to assign some work to each state in the
298 // block (and possibly, by transitivity, each incoming or outgoing
299 // transition of the block).
305
306 // state counters
307 // If every state of a block is handled by some loop, we
308 // abbreviate the counter to a block counter.
311
312 // temporary state counters (U-coroutine):
315
316 // temporary state counters (R-coroutine):
321
322 // bunch counters (only for small bunches, i. e. bunches that have been
323 // split off from a large bunch)
327
328 // block_bunch-slice counters (only for block_bunch-slices that are
329 // part of a small bunch)
340
341 // transition counters
342 // If every transition of a state is handled by some loop, we
343 // abbreviate the counter to a state counter (and possibly, by
344 // transitivity, to a block counter).
345 move_out_slice_to_new_block, // source block size
349
350 // temporary transition counters (U-coroutine):
354 // U: source block size
355
356 // temporary transition counters (R-coroutine):
360
361 // transition counters for new bottom states:
369
370 /*--------------- counters for the bisim_gj algorithm ---------------*/
371
372 // block counters
373 // Invariant:
374 // 0 <= (counter value) <= ilog2 n - ilog2(constellation size)
378 // Invariant: 0 <= (counter value) <= ilog2 n - ilog2(block size)
381
382 // state counters
383 // Invariant: 0 <= (counter value) <= ilog2 n - ilog2(block size)
391 // temporary state counters
392 // Invariant: 0 <= (counter value) <= 1
397 // bottom state counters
400 // other state counter
401 // Invariant: 0 <= (counter value) <= 1
404
405 // BLC slice counters
406 // Invariant:
407 // 0 <= (counter value) <= ilog2 n - ilog2(source constln size)
408 // Note that it should be the source constellation size,
409 // even though the BLC slice only contains transitions
410 // from a single source block.
413 // Invariant:
414 // 0 <= (counter value) <= ilog2 n - ilog2(target constln size)
419
420 // transition counters
421 // Invariant:
422 // 0 <= (counter value) <= ilog2 n - ilog2(source block size)
425 // Invariant:
426 // 0 <= (counter value) <= ilog2 n - ilog2(target block size)
428 // Invariant:
429 // 0 <= (counter value) <= ilog2 n - ilog2(target constln size)
431 // Invariant:
432 // 0 == (counter value) during the first half of initialisation
433 // 0 <= (counter value) <= ilog2 n after the quicksort part of the
434 // initialisation
436 // temporary transition counters
442 // source is in R: new bottom state
444 // counters for transitions starting in (new) bottom states
445 // Invariant: 0 <= (counter value) <= (source is a bottom state)
453 // other transition counters
454 // Invariant: 0 <= (counter value) <= 1
457 };
458
459#ifndef NDEBUG
461 #define DONT_COUNT_TEMPORARY (std::numeric_limits<unsigned char>::max()-1)
462#endif
463
465 // three magic values to ensure that the result is actually correct...
468 complexity_error = 81956
469 };
470
474 static unsigned char log_n;
475
479 static int ilog2(state_type size)
480 { assert(0<size);
481 #ifdef __GNUC__
482 if constexpr (sizeof(unsigned) == sizeof(size))
483 {
484 return sizeof(size) * CHAR_BIT - 1 - __builtin_clz(size);
485 }
486 else if constexpr (sizeof(unsigned long) == sizeof(size))
487 {
488 return sizeof(size) * CHAR_BIT - 1 - __builtin_clzl(size);
489 }
490 else if constexpr(sizeof(unsigned long long) == sizeof(size))
491 {
492 return sizeof(size) * CHAR_BIT - 1 - __builtin_clzll(size);
493 }
494 //#elif defined(_MSC_VER)
495 // if constexpr (sizeof(long) == sizeof(size))
496 // {
497 // long result;
498 // _BitScanReverse(result, size);
499 // return result - 1;
500 // }
501 // else if constexpr(sizeof(__int64) == sizeof(size))
502 // {
503 // long result;
504 // _BitScanReverse64(result, size);
505 // return result - 1;
506 // }
507 #endif
508 return (int) std::log2(size);
509 }
510
511 private:
512#ifndef NDEBUG
519#endif
523
524 public:
525#ifndef NDEBUG
527 static const char *work_names[TRANS_gj_MAX - BLOCK_MIN + 1];
528#endif
529
534 static void wait(trans_type units = 1)
535 {
536 #ifndef NDEBUG
538 no_of_waiting_cycles += units;
539 #endif
541 }
542
544 {
545 #ifndef NDEBUG
546 assert(0 <= sensible_work &&
550 #endif
551 }
552
553 private:
554 static void finalise_work_units(trans_type units=1)
555 {
556 #ifndef NDEBUG
557 sensible_work += units;
558 #endif
560 }
561
562 static void cancel_work_units(trans_type units=1)
563 {
564 #ifndef NDEBUG
565 sensible_work -= units;
566 #endif
568 }
569
570 public:
576 {
577 #ifndef NDEBUG
578 assert(-1 <= sensible_work);
579 //assert(0 == no_of_waiting_cycles);
580 sensible_work = 0;
582 #endif
583 }
584
586 template <enum counter_type FirstCounter, enum counter_type LastCounter,
587 enum counter_type FirstTempCounter =
588 (enum counter_type) (LastCounter + 1),
589 enum counter_type FirstPostprocessCounter = FirstTempCounter>
591 {
592 static_assert(FirstCounter < FirstTempCounter);
593 static_assert(FirstTempCounter <= FirstPostprocessCounter);
594 static_assert(FirstPostprocessCounter <=
595 (enum counter_type) (LastCounter + 1));
596 public:
598 unsigned char counters[LastCounter - FirstCounter + 1];
599
610 [[nodiscard]]
612 {
613 assert(FirstTempCounter <= ctr);
614 assert(ctr < FirstPostprocessCounter);
615 assert(0 == no_of_waiting_cycles);
616#ifndef NDEBUG
617 if ((FirstTempCounter != TRANS_MIN_TEMP &&
618 FirstTempCounter != TRANS_dnj_MIN_TEMP &&
619 FirstTempCounter != TRANS_gj_MIN_TEMP) ||
620 DONT_COUNT_TEMPORARY != counters[ctr - FirstCounter])
621#endif
622 {
623 assert(counters[ctr - FirstCounter] <= 1);
624 cancel_work_units(counters[ctr - FirstCounter]);
625 //if (0 != counters[ctr-FirstCounter])
626 //{
627 // mCRL2log(log::debug) << "Cancelling work ("
628 // << counters[ctr - FirstCounter] << ") for counter \""
629 // << work_names[ctr - BLOCK_MIN] << "\" done on ";
630 // counters[ctr - FirstCounter] = 0;
631 // return complexity_print;
632 //}
633 }
634 //else if (DONT_COUNT_TEMPORARY == counters[ctr - FirstCounter])
635 //{
636 // mCRL2log(log::debug) << "Work was artificially assigned "
637 // "(without changing the balance) to counter \""
638 // << work_names[ctr - BLOCK_MIN] << "\" of ";
639 // counters[ctr - FirstCounter] = 0;
640 // return complexity_print;
641 //}
642 counters[ctr - FirstCounter] = 0;
643 return complexity_ok;
644 }
645
646
661 [[nodiscard]]
663 enum counter_type const to, unsigned const max_value)
664 {
665#ifndef NDEBUG
666 // assert(...) -- see move_work().
667 if ((FirstTempCounter != TRANS_MIN_TEMP &&
668 FirstTempCounter != TRANS_dnj_MIN_TEMP &&
669 FirstTempCounter != TRANS_gj_MIN_TEMP) ||
670 DONT_COUNT_TEMPORARY != counters[from - FirstCounter])
671 {
672 finalise_work_units(counters[from - FirstCounter]);
673 }
674 else
675 {
676 counters[from - FirstCounter] = 1;
677 }
678#else
679 // The counter value is always != DONT_COUNT_TEMPORARY.
680 finalise_work_units(counters[from - FirstCounter]);
681#endif
682 return move_work(from, to, max_value);
683 }
684
685
688 {
689 std::memset(counters, '\0', sizeof(counters));
690 }
691
692
706 [[nodiscard]]
708 unsigned const max_value)
709 {
710#ifdef NDEBUG
711 if (ctr < FirstTempCounter || ctr >= FirstPostprocessCounter)
712 {
713 return complexity_ok;
714 }
715#else
716 if (FirstCounter > ctr || ctr > LastCounter)
717 {
718 mCRL2log(log::error) << "Error 20: counter \""
719 << work_names[ctr - BLOCK_MIN] << "\" is not available in ";
720 return complexity_error;
721 }
722 assert(max_value <= (ctr < FirstTempCounter ? log_n : 1U));
723 if (counters[ctr - FirstCounter] >= max_value)
724 {
725 mCRL2log(log::error) << "Error 1: counter \""
726 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
727 "maximum value (" << max_value << ") for ";
728 return complexity_error;
729 }
730#endif
731 counters[ctr - FirstCounter] = max_value;
732 return complexity_ok;
733 }
734
735 protected:
753 [[nodiscard]]
755 enum counter_type const to, unsigned const max_value)
756 {
757#ifndef NDEBUG
758 assert(FirstTempCounter <= from);
759 assert(from < FirstPostprocessCounter);
760 assert(FirstCounter <= to);
761 assert(to < FirstTempCounter || FirstPostprocessCounter <= to);
762 assert(to <= LastCounter);
763 assert(max_value <= (to < FirstTempCounter ? log_n : 1U));
764 if (0 == counters[from - FirstCounter]) return complexity_ok;
765 if (counters[to - FirstCounter] >= max_value)
766 {
767 mCRL2log(log::error) << "Error 2: counter \""
768 << work_names[to - BLOCK_MIN] << "\" exceeded "
769 "maximum value (" << max_value << ") for ";
770 return complexity_error;
771 }
772 /*
773 if ((FirstTempCounter == TRANS_MIN_TEMP ||
774 FirstTempCounter == TRANS_dnj_MIN_TEMP) &&
775 FirstTempCounter <= to && to < FirstPostprocessCounter &&
776 DONT_COUNT_TEMPORARY == counters[from - FirstCounter])
777 {
778 assert(1 == max_value);
779 // the next assertion is always satisfied if 1 == max_value.
780 // assert(0 == counters[to - FirstCounter]);
781 counters[to - FirstCounter] = DONT_COUNT_TEMPORARY;
782 }
783 else
784 */
785 {
786 counters[to - FirstCounter] = max_value;
787 assert(1 == counters[from - FirstCounter]);
788 }
789#else
790 (void) to; (void) max_value; // avoid unused variable warning
791#endif
792 counters[from - FirstCounter] = 0;
793 //mCRL2log(log::debug) << "moving work from counter \""
794 // << work_names[from - BLOCK_MIN] << "\" to \""
795 // << work_names[to - BLOCK_MIN] << "\" for ";
796 //return complexity_print;
797 return complexity_ok;
798 }
799 };
800
801
802 // usage of the functions below: as soon as the block is refined, one
803 // has to call state_counter_t::blue_is_smaller() or state_counter_t::
804 // red_is_smaller() for every state in the old and new block. Also, one
805 // needs to call trans_counter_t::blue_is_smaller() or trans_counter_t::
806 // red_is_smaller() for every incoming and outgoing transition in the old
807 // and new block. (Inert transitions need to be handled only once.) After
808 // that, one calls check_temporary_work() to verify that not too much
809 // work was done on the larger block.
810
815 class block_counter_t : public counter_t<BLOCK_MIN, BLOCK_MAX>
816 {
817 public:
834 [[nodiscard]]
835 result_type no_temporary_work(unsigned const max_C,
836 unsigned const max_B)
837 {
838#ifndef NDEBUG
839 assert(max_C <= max_B);
840 for (enum counter_type ctr = BLOCK_MIN;
842 ctr = (enum counter_type) (ctr + 1))
843 {
844 assert(counters[ctr - BLOCK_MIN] <= max_C);
845 counters[ctr - BLOCK_MIN] = max_C;
846 }
847 assert(max_B <= log_n);
848 for (enum counter_type ctr =
850 ctr <= BLOCK_MAX; ctr = (enum counter_type) (ctr + 1))
851 {
852 assert(counters[ctr - BLOCK_MIN] <= max_B);
853 counters[ctr - BLOCK_MIN] = max_B;
854 }
855#else
856 (void) max_C; (void) max_B; // avoid unused variable warning
857#endif
858 return complexity_ok;
859 }
860 };
861
866 class B_to_C_counter_t : public counter_t<B_TO_C_MIN, B_TO_C_MAX,
867 B_TO_C_MIN_TEMP, (enum counter_type) (B_TO_C_MAX_TEMP + 1)>
868 {
869 public:
883 [[nodiscard]]
884 result_type no_temporary_work(unsigned const max_targetC)
885 {
886#ifndef NDEBUG
887 assert(max_targetC <= log_n);
888 for (enum counter_type ctr = B_TO_C_MIN;
889 ctr < B_TO_C_MIN_TEMP; ctr = (enum counter_type) (ctr + 1))
890 {
891 assert(counters[ctr - B_TO_C_MIN] <= max_targetC);
892 counters[ctr - B_TO_C_MIN] = max_targetC;
893 }
894 for (enum counter_type ctr = B_TO_C_MIN_TEMP;
895 ctr <= B_TO_C_MAX_TEMP; ctr = (enum counter_type) (ctr + 1))
896 {
897 if (counters[ctr - B_TO_C_MIN] > 0)
898 {
899 mCRL2log(log::error) << "Error 3: counter \""
900 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
901 "maximum value (" << 0 << ") for ";
902 return complexity_error;
903 }
904 }
905 static_assert(B_TO_C_MAX_TEMP == B_TO_C_MAX);
906#else
907 (void) max_targetC; // avoid unused variable warning
908#endif
909 return complexity_ok;
910 }
911
928 unsigned char get_work_counter_4_4() const
929 {
931 B_TO_C_MIN];
932 }
933
934
950 {
952 B_TO_C_MIN] = 0;
953 }
954 };
955
956 class state_counter_t : public counter_t<STATE_MIN, STATE_MAX,
957 STATE_MIN_TEMP, (enum counter_type) (STATE_MAX_TEMP + 1)>
958 {
959 public:
981 [[nodiscard]]
982 result_type no_temporary_work(unsigned const max_B, bool const bottom)
983 {
984#ifndef NDEBUG
985 assert(max_B <= log_n);
986 for (enum counter_type ctr = STATE_MIN;
987 ctr < STATE_MIN_TEMP; ctr = (enum counter_type) (ctr + 1))
988 {
989 assert(counters[ctr - STATE_MIN] <= max_B);
990 counters[ctr - STATE_MIN] = max_B;
991 }
992
993 // temporary state counters must be zero:
994 for (enum counter_type ctr = STATE_MIN_TEMP;
995 ctr <= STATE_MAX_TEMP; ctr = (enum counter_type) (ctr + 1))
996 {
997 if (counters[ctr - STATE_MIN] > 0)
998 {
999 mCRL2log(log::error) << "Error 4: counter \""
1000 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1001 "maximum value (" << 0 << ") for ";
1002 return complexity_error;
1003 }
1004 }
1005 // bottom state counters must be 0 for non-bottom states and 1 for
1006 // bottom states:
1007 // assert((unsigned) bottom <= 1);
1008 for(enum counter_type ctr = (enum counter_type) (STATE_MAX_TEMP+1);
1009 ctr <= STATE_MAX ; ctr = (enum counter_type) (ctr + 1))
1010 {
1011 if (counters[ctr - STATE_MIN] > (unsigned) bottom)
1012 {
1013 mCRL2log(log::error) << "Error 5: counter \""
1014 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1015 "maximum value (" << (unsigned) bottom << ") for ";
1016 return complexity_error;
1017 }
1018 counters[ctr - STATE_MIN] = (unsigned) bottom;
1019 }
1020#else
1021 (void) max_B; (void) bottom; // avoid unused variable warning
1022#endif
1023 return complexity_ok;
1024 }
1025 };
1026
1027 class trans_counter_t : public counter_t<TRANS_MIN, TRANS_MAX,
1028 TRANS_MIN_TEMP, (enum counter_type) (TRANS_MAX_TEMP + 1)>
1029 {
1030 public:
1063 [[nodiscard]]
1064 result_type no_temporary_work(unsigned const max_sourceB,
1065 unsigned const max_targetC,
1066 unsigned const max_targetB, bool const source_bottom)
1067 {
1068#ifndef NDEBUG
1069 assert(max_targetC <= max_targetB);
1070 for (enum counter_type ctr = TRANS_MIN;
1072 ctr = (enum counter_type) (ctr + 1))
1073 {
1074 assert(counters[ctr - TRANS_MIN] <= max_targetC);
1075 counters[ctr - TRANS_MIN] = max_targetC;
1076 }
1077 assert(max_sourceB <= log_n);
1080 ctr = (enum counter_type) (ctr + 1))
1081 {
1082 assert(counters[ctr - TRANS_MIN] <= max_sourceB);
1083 counters[ctr - TRANS_MIN] = max_sourceB;
1084 }
1085 assert(max_targetB <= log_n);
1087 ctr < TRANS_MIN_TEMP; ctr = (enum counter_type) (ctr + 1))
1088 {
1089 assert(counters[ctr - TRANS_MIN] <= max_targetB);
1090 counters[ctr - TRANS_MIN] = max_targetB;
1091 }
1092 // temporary transition counters must be zero
1093 for (enum counter_type ctr = TRANS_MIN_TEMP;
1094 ctr <= TRANS_MAX_TEMP; ctr = (enum counter_type)(ctr + 1))
1095 {
1096 if (counters[ctr - TRANS_MIN] > 0)
1097 {
1098 mCRL2log(log::error) << "Error 6: counter \""
1099 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1100 "maximum value (" << 0 << ") for ";
1101 return complexity_error;
1102 }
1103 }
1104 // bottom state counters must be 0 for transitions from non-bottom
1105 // states and 1 for other transitions
1106 assert((unsigned) source_bottom <= 1);
1107 for(enum counter_type ctr = (enum counter_type) (TRANS_MAX_TEMP+1);
1108 ctr <= TRANS_MAX ; ctr = (enum counter_type) (ctr + 1))
1109 {
1110 if (counters[ctr - TRANS_MIN] > (unsigned) source_bottom)
1111 {
1112 mCRL2log(log::error) << "Error 7: counter \""
1113 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1114 "maximum value (" << (unsigned) source_bottom << ") for ";
1115 return complexity_error;
1116 }
1117 counters[ctr - TRANS_MIN] = (unsigned) source_bottom;
1118 }
1119#else
1120 (void) max_sourceB; (void) max_targetC; (void) max_targetB;
1121 (void) source_bottom; // avoid unused variable warning
1122#endif
1123 return complexity_ok;
1124 }
1125
1126
1145 [[nodiscard]]
1147 unsigned const max_value)
1148 {
1149#ifndef NDEBUG
1150 if (TRANS_MIN_TEMP > ctr || ctr > TRANS_MAX_TEMP)
1151 {
1152 return add_work(ctr, max_value);
1153 }
1154
1155 assert(1 == max_value);
1156 if (0 == counters[ctr - TRANS_MIN])
1157 {
1159 return complexity_ok;
1160 }
1161
1162 mCRL2log(log::error) << "Error 8: counter \""
1163 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1164 "maximum value (" << max_value << ") for ";
1165 return complexity_error;
1166#else
1167 (void) ctr; (void) max_value;
1168 return complexity_ok;
1169#endif
1170 }
1171 };
1172
1173 /*----------------- class specialisations for bisim_dnj -----------------*/
1174
1175 class block_dnj_counter_t : public counter_t<BLOCK_dnj_MIN, BLOCK_dnj_MAX,
1176 create_initial_partition>
1177 {
1178 public:
1194 [[nodiscard]]
1195 result_type no_temporary_work(unsigned const max_block)
1196 {
1197#ifndef NDEBUG
1198 assert((log_n + 1U) / 2U <= max_block);
1199 if (max_block > log_n)
1200 {
1201 mCRL2log(log::error) << "Error 14: max_block == "
1202 << max_block << " exceeded log_n == "
1203 << (unsigned) log_n << " for ";
1204 return complexity_error;
1205 }
1206 assert(max_block <= log_n);
1207 for (enum counter_type ctr = BLOCK_dnj_MIN;
1209 ctr = (enum counter_type) (ctr + 1))
1210 {
1211 assert(counters[ctr - BLOCK_dnj_MIN] <= max_block);
1212 counters[ctr - BLOCK_dnj_MIN] = max_block;
1213 }
1214 for (enum counter_type ctr = create_initial_partition;
1215 ctr <= BLOCK_dnj_MAX; ctr = (enum counter_type) (ctr + 1))
1216 {
1217 assert(counters[ctr - BLOCK_dnj_MIN] <= 1);
1218 counters[ctr - BLOCK_dnj_MIN] = 1;
1219 }
1220#else
1221 (void) max_block; // avoid unused variable warning
1222#endif
1223 return complexity_ok;
1224 }
1225 };
1226
1227 class state_dnj_counter_t : public counter_t<STATE_dnj_MIN, STATE_dnj_MAX,
1228 STATE_dnj_MIN_TEMP, (enum counter_type) (STATE_dnj_MAX_TEMP + 1)>
1229 {
1230 public:
1246 [[nodiscard]]
1247 result_type no_temporary_work(unsigned const max_block,
1248 bool const bottom)
1249 {
1250#ifndef NDEBUG
1251 assert((log_n + 1U) / 2U <= max_block);
1252 assert(max_block <= log_n);
1253 for (enum counter_type ctr = STATE_dnj_MIN;
1254 ctr < STATE_dnj_MIN_TEMP; ctr = (enum counter_type) (ctr + 1))
1255 {
1256 assert(counters[ctr - STATE_dnj_MIN] <= max_block);
1257 counters[ctr - STATE_dnj_MIN] = max_block;
1258 }
1259 for (enum counter_type ctr = STATE_dnj_MIN_TEMP;
1260 ctr <= STATE_dnj_MAX_TEMP; ctr = (enum counter_type) (ctr + 1))
1261 {
1262 assert(counters[ctr - STATE_dnj_MIN] <= 0);
1263 }
1264 // assert((unsigned) bottom <= 1);
1265 for (enum counter_type ctr =
1266 (enum counter_type) (STATE_dnj_MAX_TEMP + 1);
1267 ctr <= STATE_dnj_MAX; ctr = (enum counter_type) (ctr + 1))
1268 {
1269 assert(counters[ctr - STATE_dnj_MIN] <= (unsigned) bottom);
1270 counters[ctr - STATE_dnj_MIN] = (unsigned) bottom;
1271 }
1272#else
1273 (void) max_block; (void) bottom; // avoid unused variable warning
1274#endif
1275 return complexity_ok;
1276 }
1277 };
1278
1279 class bunch_dnj_counter_t : public counter_t<BUNCH_dnj_MIN, BUNCH_dnj_MAX>
1280 {
1281 public:
1297 [[nodiscard]]
1298 result_type no_temporary_work(unsigned const max_bunch)
1299 {
1300#ifndef NDEBUG
1301 assert(max_bunch <= log_n);
1302 for (enum counter_type ctr = BUNCH_dnj_MIN;
1303 ctr <= BUNCH_dnj_MAX; ctr = (enum counter_type) (ctr + 1))
1304 {
1305 assert(counters[ctr - BUNCH_dnj_MIN] <= max_bunch);
1306 counters[ctr - BUNCH_dnj_MIN] = max_bunch;
1307 }
1308#else
1309 (void) max_bunch; // avoid unused variable warning
1310#endif
1311 return complexity_ok;
1312 }
1313 };
1314
1315 class block_bunch_dnj_counter_t : public counter_t<BLOCK_BUNCH_dnj_MIN,
1316 BLOCK_BUNCH_dnj_MAX, BLOCK_BUNCH_dnj_MIN_TEMP,
1317 (enum counter_type) (BLOCK_BUNCH_dnj_MAX_TEMP + 1)>
1318 {
1319 public:
1335 [[nodiscard]]
1336 result_type no_temporary_work(unsigned const max_bunch)
1337 {
1338#ifndef NDEBUG
1339 assert(max_bunch <= log_n);
1340 for (enum counter_type ctr = BLOCK_BUNCH_dnj_MIN;
1342 ctr = (enum counter_type) (ctr + 1))
1343 {
1344 if (counters[ctr - BLOCK_BUNCH_dnj_MIN] > max_bunch)
1345 {
1346 mCRL2log(log::error) << "Error 12: counter \""
1347 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1348 "maximum value (" << (unsigned) max_bunch << ") for ";
1349 return complexity_error;
1350 }
1351 assert(counters[ctr - BLOCK_BUNCH_dnj_MIN] <= max_bunch);
1352 counters[ctr - BLOCK_BUNCH_dnj_MIN] = max_bunch;
1353 }
1354 for (enum counter_type ctr = BLOCK_BUNCH_dnj_MIN_TEMP;
1355 ctr <= BLOCK_BUNCH_dnj_MAX; ctr = (enum counter_type) (ctr + 1))
1356 {
1357 if (counters[ctr - BLOCK_BUNCH_dnj_MIN] > 0)
1358 {
1359 mCRL2log(log::error) << "Error 13: counter \""
1360 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1361 "maximum value (" << (unsigned) 0 << ") for ";
1362 return complexity_error;
1363 }
1364 assert(counters[ctr - BLOCK_BUNCH_dnj_MIN] <= 0);
1365 }
1367#else
1368 (void) max_bunch; // avoid unused variable warning
1369#endif
1370 return complexity_ok;
1371 }
1372
1374 {
1377 }
1379 {
1382 }
1383 };
1384
1385 class trans_dnj_counter_t : public counter_t<TRANS_dnj_MIN, TRANS_dnj_MAX,
1386 TRANS_dnj_MIN_TEMP, (enum counter_type) (TRANS_dnj_MAX_TEMP + 1)>
1387 {
1388 public:
1406 [[nodiscard]]
1407 result_type no_temporary_work(unsigned const max_source_block,
1408 unsigned const max_target_block, bool const bottom)
1409 {
1410#ifndef NDEBUG
1411 assert((log_n + 1U) / 2U <= max_source_block);
1412 assert(max_source_block <= log_n);
1413 for (enum counter_type ctr = TRANS_dnj_MIN;
1415 ctr = (enum counter_type) (ctr + 1))
1416 {
1417 assert(counters[ctr - TRANS_dnj_MIN] <= max_source_block);
1418 counters[ctr - TRANS_dnj_MIN] = max_source_block;
1419 }
1420 assert((log_n + 1U) / 2U <= max_target_block);
1421 assert(max_target_block <= log_n);
1423 ctr < TRANS_dnj_MIN_TEMP;
1424 ctr = (enum counter_type) (ctr + 1))
1425 {
1426 assert(counters[ctr - TRANS_dnj_MIN] <= max_target_block);
1427 counters[ctr - TRANS_dnj_MIN] = max_target_block;
1428 }
1429 for (enum counter_type ctr = TRANS_dnj_MIN_TEMP;
1430 ctr <= TRANS_dnj_MAX_TEMP; ctr = (enum counter_type) (ctr + 1))
1431 {
1432 assert(counters[ctr - TRANS_dnj_MIN] <= 0);
1433 }
1434 // assert((unsigned) bottom <= 1);
1435 for (enum counter_type ctr =
1436 (enum counter_type) (TRANS_dnj_MAX_TEMP + 1);
1437 ctr <= TRANS_dnj_MAX; ctr = (enum counter_type) (ctr + 1))
1438 {
1439 if (counters[ctr - TRANS_dnj_MIN] > (unsigned) bottom)
1440 {
1441 mCRL2log(log::error) << "Error 11: counter \""
1442 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1443 "maximum value (" << (unsigned) bottom << ") for ";
1444 return complexity_error;
1445 }
1446 counters[ctr - TRANS_dnj_MIN] = (unsigned) bottom;
1447 }
1448#else
1449 (void) max_source_block; (void) max_target_block; (void) bottom;
1450 // avoid unused variable warning
1451#endif
1452 return complexity_ok;
1453 }
1454
1473 [[nodiscard]]
1475 unsigned const max_value)
1476 {
1477#ifndef NDEBUG
1478 if (TRANS_dnj_MIN_TEMP > ctr || ctr > TRANS_dnj_MAX_TEMP)
1479 {
1480 return add_work(ctr, max_value);
1481 }
1482
1483 assert(1 == max_value);
1484 if (0 == counters[ctr - TRANS_dnj_MIN])
1485 {
1487 return complexity_ok;
1488 }
1489
1490 mCRL2log(log::error) << "Error 9: counter \""
1491 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1492 "maximum value (" << max_value << ") for ";
1493 return complexity_error;
1494#else
1495 (void) ctr; (void) max_value; // avoid unused variable warning
1496 return complexity_ok;
1497#endif
1498 }
1499 };
1500
1501 /*----------------- class specialisations for bisim_gj ------------------*/
1502
1503 class block_gj_counter_t : public counter_t<BLOCK_gj_MIN, BLOCK_gj_MAX>
1504 {
1505 public:
1521 [[nodiscard]]
1522 result_type no_temporary_work(unsigned const max_C,
1523 unsigned const max_B)
1524 {
1525#ifndef NDEBUG
1526 assert(max_C <= max_B);
1527 assert(max_B <= log_n);
1528 enum counter_type ctr;
1529 for (ctr = BLOCK_gj_MIN ;
1531 ctr = (enum counter_type) (ctr + 1))
1532 {
1533 assert(counters[ctr - BLOCK_gj_MIN] <= max_C);
1534 counters[ctr - BLOCK_gj_MIN] = max_C;
1535 }
1536 for (; ctr <= BLOCK_gj_MAX ; ctr = (enum counter_type) (ctr + 1))
1537 {
1538 assert(counters[ctr - BLOCK_gj_MIN] <= max_B);
1539 counters[ctr - BLOCK_gj_MIN] = max_B;
1540 }
1541#else
1542 (void) max_C; (void) max_B; // avoid unused variable warning
1543#endif
1544 return complexity_ok;
1545 }
1546 };
1547
1548 class BLC_gj_counter_t : public counter_t<BLC_gj_MIN, BLC_gj_MAX>
1549 {
1550 public:
1568 [[nodiscard]]
1569 result_type no_temporary_work(unsigned max_sourceC,
1570 unsigned max_targetC)
1571 {
1572#ifndef NDEBUG
1573 assert(max_sourceC <= log_n);
1574 assert(max_targetC <= log_n);
1575 enum counter_type ctr;
1576 for (ctr = BLC_gj_MIN ; ctr <
1578 ctr = (enum counter_type) (ctr + 1))
1579 {
1580 assert(counters[ctr - BLC_gj_MIN] <= max_sourceC);
1581 counters[ctr - BLC_gj_MIN] = max_sourceC;
1582 }
1583 for (; ctr <= BLC_gj_MAX ; ctr = (enum counter_type) (ctr + 1))
1584 {
1585 assert(counters[ctr - BLC_gj_MIN] <= max_targetC);
1586 counters[ctr - BLC_gj_MIN] = max_targetC;
1587 }
1588#else
1589 (void) max_sourceC; (void) max_targetC;
1590 // avoid unused variable warning
1591#endif
1592 return complexity_ok;
1593 }
1594 };
1595
1596 class state_gj_counter_t : public counter_t<STATE_gj_MIN, STATE_gj_MAX,
1597 STATE_gj_MIN_TEMP, (enum counter_type) (STATE_gj_MAX_TEMP + 1)>
1598 {
1599 public:
1621 [[nodiscard]]
1622 result_type no_temporary_work(unsigned const max_B, bool const bottom)
1623 {
1624#ifndef NDEBUG
1625 assert(max_B <= log_n);
1626 enum counter_type ctr;
1627 for (ctr = STATE_gj_MIN ;
1628 ctr < STATE_gj_MIN_TEMP ; ctr = (enum counter_type) (ctr + 1))
1629 {
1630 if (counters[ctr - STATE_gj_MIN] > max_B)
1631 {
1632 mCRL2log(log::error) << "Error 21: counter \""
1633 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1634 "maximum value (" << max_B << ") for ";
1635 return complexity_error;
1636 }
1637 assert(counters[ctr - STATE_gj_MIN] <= max_B);
1638 counters[ctr - STATE_gj_MIN] = max_B;
1639 }
1640
1641 // temporary state counters must be zero:
1642 for ( ; ctr <= STATE_gj_MAX_TEMP ; ctr=(enum counter_type) (ctr+1))
1643 {
1644 if (counters[ctr - STATE_gj_MIN] > 0)
1645 {
1646 mCRL2log(log::error) << "Error 15: counter \""
1647 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1648 "maximum value (" << 0 << ") for ";
1649 return complexity_error;
1650 }
1651 }
1652
1653 // bottom state counters must be 0 for non-bottom states and 1 for
1654 // bottom states:
1655 assert((unsigned) bottom <= 1);
1657 ctr = (enum counter_type) (ctr + 1))
1658 {
1659 if (counters[ctr - STATE_gj_MIN] > (unsigned) bottom)
1660 {
1661 mCRL2log(log::error) << "Error 16: counter \""
1662 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1663 "maximum value (" << (unsigned) bottom << ") for ";
1664 return complexity_error;
1665 }
1666 counters[ctr - STATE_gj_MIN] = (unsigned) bottom;
1667 }
1668
1669 // other counters must be at most 1 (after initialisation)
1670 for ( ; ctr <= STATE_gj_MAX ; ctr = (enum counter_type) (ctr + 1))
1671 {
1672 assert(counters[ctr - STATE_gj_MIN] <= 1);
1673 }
1674#else
1675 (void) max_B; (void) bottom; //avoid unused variable warning
1676#endif
1677 return complexity_ok;
1678 }
1679 };
1680
1681 class trans_gj_counter_t : public counter_t<TRANS_gj_MIN, TRANS_gj_MAX,
1682 TRANS_gj_MIN_TEMP, (enum counter_type) (TRANS_gj_MAX_TEMP + 1)>
1683 {
1684 public:
1717 [[nodiscard]]
1718 result_type no_temporary_work(unsigned const max_sourceB,
1719 unsigned const max_targetC,
1720 unsigned const max_targetB, bool const source_bottom)
1721 {
1722#ifndef NDEBUG
1723 assert(max_sourceB <= log_n);
1724 assert(max_targetB <= log_n);
1725 assert(max_targetC <= max_targetB);
1726 enum counter_type ctr;
1727 for (ctr = TRANS_gj_MIN;
1729 ctr = (enum counter_type) (ctr + 1))
1730 {
1731 assert(counters[ctr - TRANS_gj_MIN] <= max_sourceB);
1732 counters[ctr - TRANS_gj_MIN] = max_sourceB;
1733 }
1734 for ( ; ctr <
1736 ctr = (enum counter_type) (ctr + 1))
1737 {
1738 assert(counters[ctr - TRANS_gj_MIN] <= max_targetB);
1739 counters[ctr - TRANS_gj_MIN] = max_targetB;
1740 }
1742 ctr = (enum counter_type) (ctr+1))
1743 {
1744 assert(counters[ctr - TRANS_gj_MIN] <= max_targetC);
1745 counters[ctr - TRANS_gj_MIN] = max_targetC;
1746 }
1747 // counter for the initialisation
1748 for ( ; ctr < TRANS_gj_MIN_TEMP; ctr = (enum counter_type) (ctr+1))
1749 {
1750 assert(counters[ctr - TRANS_gj_MIN] <= log_n);
1751 // counters[ctr - TRANS_gj_MIN] = ...;
1752 }
1753 // temporary transition counters must be zero
1754 for (; ctr <= TRANS_gj_MAX_TEMP ; ctr = (enum counter_type)(ctr+1))
1755 {
1756 if (counters[ctr - TRANS_gj_MIN] > 0)
1757 {
1758 mCRL2log(log::error) << "Error 17: counter \""
1759 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1760 "maximum value (" << 0 << ") for ";
1761 return complexity_error;
1762 }
1763 }
1764 // bottom state counters must be 0 for transitions from non-bottom
1765 // states and 1 for other transitions
1767 ctr = (enum counter_type) (ctr + 1))
1768 {
1769 if (counters[ctr - TRANS_gj_MIN] > (unsigned) source_bottom)
1770 {
1771 mCRL2log(log::error) << "Error 18: counter \""
1772 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1773 "maximum value (" << (unsigned) source_bottom << ") for ";
1774 return complexity_error;
1775 }
1776 counters[ctr - TRANS_gj_MIN] = (unsigned) source_bottom;
1777 }
1778 // other counters must be at most 1 (after initialisation)
1779 assert((unsigned) source_bottom <= 1);
1780 for ( ; ctr <= TRANS_gj_MAX ; ctr = (enum counter_type) (ctr+1))
1781 {
1782 if (counters[ctr - TRANS_gj_MIN] > 1)
1783 {
1784 mCRL2log(log::error) << "Error 19: counter \""
1785 << work_names[ctr - BLOCK_MIN]
1786 << "\" exceeded maximum value (" << 1 << ") for ";
1787 return complexity_error;
1788 }
1789 }
1790#else
1791 (void) max_sourceB; (void) max_targetC; (void) max_targetB;
1792 (void) source_bottom; // avoid unused variable warning
1793#endif
1794 return complexity_ok;
1795 }
1796
1797
1816 [[nodiscard]]
1818 unsigned const max_value)
1819 {
1820#ifndef NDEBUG
1821 if (TRANS_gj_MIN_TEMP > ctr || ctr > TRANS_gj_MAX_TEMP)
1822 {
1823 return add_work(ctr, max_value);
1824 }
1825
1826 assert(1 == max_value);
1827 if (0 == counters[ctr - TRANS_gj_MIN])
1828 {
1830 return complexity_ok;
1831 }
1832
1833 mCRL2log(log::error) << "Error 8: counter \""
1834 << work_names[ctr - BLOCK_MIN] << "\" exceeded "
1835 "maximum value (" << max_value << ") for ";
1836 return complexity_error;
1837#else
1838 (void) ctr; (void) max_value; // avoid unused variable warning
1839 return complexity_ok;
1840#endif
1841 }
1842 };
1843
1844
1845 #ifdef TEST_WORK_COUNTER_NAMES
1850 static void test_work_names();
1851 #endif
1852
1853
1858 static void init(state_type n)
1859 {
1860 #ifdef TEST_WORK_COUNTER_NAMES
1861 // as debugging measure:
1862 test_work_names();
1863 #endif
1864
1865 log_n = ilog2(n);
1866 #ifndef NDEBUG
1867 assert(0 == sensible_work); sensible_work = 0;
1870 #endif
1874 }
1875
1876
1879 {
1880 trans_type overall_total = sensible_work_grand_total +
1882 #define percentage(steps,total) \
1883 (assert((steps)<= \
1884 (std::numeric_limits<trans_type>::max()-(total))/200), \
1885 ((steps)*(trans_type)200+(total))/(total)/2)
1886 if (0 != overall_total)
1887 {
1888 //auto old_log_level=log::logger::get_reporting_level();
1889 //log::logger::set_reporting_level(log::verbose);
1890 mCRL2log(log::verbose) << "In the coroutines, "
1892 << " states and transitions were inspected. ";
1894 {
1895 mCRL2log(log::verbose) << "Additionally, there were "
1896 << no_of_waiting_cycles_grand_total << " waiting cycles ("
1898 << "% of all steps and cycles).\n";
1899 }
1900 mCRL2log(log::verbose) << "Of these, "
1901 << cancelled_work_grand_total << " steps were cancelled ("
1902 << percentage(cancelled_work_grand_total, overall_total)
1903 << "% of all steps";
1905 {
1906 mCRL2log(log::verbose) << " and cycles).\n";
1908 {
1909 mCRL2log(log::verbose) << "If we exclude the waiting "
1910 "cycles, then " << percentage(cancelled_work_grand_total,
1912 << "% of the steps have been cancelled.\n";
1913 }
1914 }
1915 else
1916 {
1917 mCRL2log(log::verbose) << ").\n";
1918 }
1919 //log::logger::set_reporting_level(old_log_level);
1923 }
1924 #undef percentage
1925 }
1926
1927
1940#ifndef NDEBUG
1941 #define mCRL2complexity(unit, call, info_for_debug) \
1942 do \
1943 { \
1944 const enum check_complexity::result_type \
1945 GG00OCOC0GQQ0COG00GQQQQOCOGQCO=((unit)->work_counter. call ); \
1946 switch (GG00OCOC0GQQ0COG00GQQQQOCOGQCO) \
1947 { \
1948 case check_complexity::complexity_ok: break; \
1949 default: \
1950 mCRL2log(log::error) << "Unexpected return value " \
1951 << (int)GG00OCOC0GQQ0COG00GQQQQOCOGQCO << " for ";\
1952 [[fallthrough]]; \
1953 case check_complexity::complexity_error: \
1954 case check_complexity::complexity_print: \
1955 mCRL2log(log::error) \
1956 << (unit)->debug_id(info_for_debug) << '\n'; \
1957 if (check_complexity::complexity_print != \
1958 GG00OCOC0GQQ0COG00GQQQQOCOGQCO) \
1959 exit(EXIT_FAILURE); \
1960 break; \
1961 } \
1962 } \
1963 while (0)
1964#else
1965 #define mCRL2complexity(unit, call, info_for_debug) \
1966 do \
1967 { \
1968 if (check_complexity::complexity_ok != \
1969 ((unit)->work_counter. call )) \
1970 { \
1971 mCRL2log(log::error) << __FILE__ << ':' << __LINE__ \
1972 << " Error in mCRL2complexity()\n"; \
1973 exit(EXIT_FAILURE); \
1974 } \
1975 } \
1976 while (0)
1977#endif
1978
1979};
1980
1981#else // ifndef NDEBUG
1982
1983 #define mCRL2complexity(unit, call, info_for_debug) do {} while (0)
1984
1985#endif // ifndef NDEBUG
1986
1987} // end namespace detail
1988} // end namespace lts
1989} // end namespace mcrl2
1990
1991#endif // ifndef _COUNT_ITERATIONS_H
#define DONT_COUNT_TEMPORARY
special value for temporary work without changing the balance
#define percentage(steps, total)
result_type no_temporary_work(unsigned max_sourceC, unsigned max_targetC)
ensures there is no orphaned temporary work counter
void reset_work_counter_4_4()
sets the temporary counter associated with line 4.4 to zero
result_type no_temporary_work(unsigned const max_targetC)
ensures there is no orphaned temporary work counter
unsigned char get_work_counter_4_4() const
returns the temporary counter associated with line 4.4
result_type no_temporary_work(unsigned const max_bunch)
ensures there is no orphaned temporary work counter
result_type no_temporary_work(unsigned const max_C, unsigned const max_B)
ensures there is no orphaned temporary work counter
result_type no_temporary_work(unsigned const max_block)
ensures there is no orphaned temporary work counter
result_type no_temporary_work(unsigned const max_C, unsigned const max_B)
ensures there is no orphaned temporary work counter
result_type no_temporary_work(unsigned const max_bunch)
ensures there is no orphaned temporary work counter
subset of counters (to be associated with a state or transition)
result_type add_work(enum counter_type const ctr, unsigned const max_value)
register work with some counter
counter_t()
constructor, initializes all counters to 0
result_type finalise_work(enum counter_type const from, enum counter_type const to, unsigned const max_value)
move temporary work to its final counter
unsigned char counters[LastCounter - FirstCounter+1]
actual space to store the counters
result_type move_work(enum counter_type const from, enum counter_type const to, unsigned const max_value)
move temporary work to another counter
result_type cancel_work(enum counter_type const ctr)
cancel temporary work
result_type no_temporary_work(unsigned const max_B, bool const bottom)
ensures there is no orphaned temporary work counter
result_type no_temporary_work(unsigned const max_block, bool const bottom)
ensures there is no orphaned temporary work counter
result_type no_temporary_work(unsigned const max_B, bool const bottom)
ensures there is no orphaned temporary work counter
result_type add_work_notemporary(enum counter_type const ctr, unsigned const max_value)
register work with some temporary counter without changing the balance between sensible and superfluo...
result_type no_temporary_work(unsigned const max_sourceB, unsigned const max_targetC, unsigned const max_targetB, bool const source_bottom)
ensures there is no orphaned temporary work counter
result_type no_temporary_work(unsigned const max_source_block, unsigned const max_target_block, bool const bottom)
ensures there is no orphaned temporary work counter
result_type add_work_notemporary(enum counter_type const ctr, unsigned const max_value)
register work with some temporary counter without changing the balance between sensible and superfluo...
result_type no_temporary_work(unsigned const max_sourceB, unsigned const max_targetC, unsigned const max_targetB, bool const source_bottom)
ensures there is no orphaned temporary work counter
result_type add_work_notemporary(enum counter_type const ctr, unsigned const max_value)
register work with some temporary counter without changing the balance between sensible and superfluo...
class for time complexity checks
static int ilog2(state_type size)
calculate the base-2 logarithm, rounded down
static void cancel_work_units(trans_type units=1)
static signed_trans_type sensible_work
counter to register the work balance for coroutines
static void wait(trans_type units=1)
do some work that cannot be assigned directly
static unsigned char log_n
value of floor(log2(n)) for easy access
counter_type
Type for complexity budget counters.
static trans_type sensible_work_grand_total
the number of useful steps in the course of the whole algorithm
static trans_type no_of_waiting_cycles_grand_total
the number of waiting cycles in the course of the whole algorithm
static trans_type cancelled_work_grand_total
the number of cancelled steps (in aborted coroutines) in the course of the whole algorithm
static const char * work_names[TRANS_gj_MAX - BLOCK_MIN+1]
printable names of the counter types (for error messages)
static void check_temporary_work()
check that not too much superfluous work has been done
static void finalise_work_units(trans_type units=1)
static void print_grand_totals()
print grand total of work in the coroutines (to measure overhead)
static void init(state_type n)
starts counting for a new refinement run
static bool cannot_wait_before_reset
indicates whether waiting cycles are allowed
static trans_type no_of_waiting_cycles
the number of waiting cycles that have been done in the current accounting period
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:391
@ verbose
Definition logger.h:37
std::size_t state_type
type used to store state (numbers and) counts
std::size_t trans_type
type used to store transition (numbers and) counts
std::make_signed< trans_type >::type signed_trans_type
type used to store differences between transition counters
std::size_t to(const outgoing_pair_t &p)
Target state of a label state pair.
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.
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
Definition indexed_set.h:72