Sequoia
Loading...
Searching...
No Matches
DynamicDirectedGraphTestingUtilities.hpp
Go to the documentation of this file.
1
2// Copyright Oliver J. Rosten 2023. //
3// Distributed under the GNU GENERAL PUBLIC LICENSE, Version 3.0. //
4// (See accompanying file LICENSE.md or copy at //
5// https://www.gnu.org/licenses/gpl-3.0.en.html) //
7
8#pragma once
9
13
16
17namespace sequoia::testing
18{
19 namespace directed_graph{
21 enum graph_description : std::size_t {
22 empty = 0,
23
24 // x
25 node,
26
27 // /\
28 // \/
29 // x
30 node_0,
31
32 // /\ /\
33 // \/ \/
34 // x
35 node_0_0,
36
37 // x x
38 node_node,
39
40 // x ---> x
41 node_1_node,
42
43 // x <--- x
44 node_node_0,
45
46 // /\
47 // \/
48 // x ---> x
49 node_0_1_node,
50
51 // /\
52 // \/
53 // x x
54 node_0_node,
55
56 // /\
57 // \/
58 // x x
59 node_node_1,
60
61 // x ===> x
62 node_1_1_node,
63
64 // x ---> x
65 // <---
66 node_1_node_0,
67
68 // x x x
69 node_node_node,
70
71 // x ---> x x
72 node_1_node_node,
73
74 // x x <--- x
75 node_node_node_1,
76
77 // x ---> x ---> x
78 node_1_node_2_node,
79
80 // x ---> x <--- x
81 node_1_node_node_1,
82
83 // -> x ---> x ---> x --
84 node_1_node_2_node_0,
85
86 // /\
87 // \/
88 // x x x
89 node_node_1_node,
90
91 // /\
92 // \/
93 // x ---> x x
94 node_1_node_1_node,
95
96
97 // /\
98 // \/
99 // x ---> x x
100 // <---
101 node_1_node_1_0_node,
102
103 // /\
104 // \/
105 // x ---> x ---> x
106 // <---
107 node_1_node_1_0_2_node,
108
109 // /\
110 // \/
111 // x ---> x ---> x
112 node_1_node_1_2_node,
113
114 // /\
115 // \/
116 // -- x x x <-
117 node_2_node_node_2,
118
119 // [2]
120 // x
121 // ^^ ^
122 // // \
123 // // \
124 // x ===> x
125 // [0] [1]
126 node_1_1_2_2_node_2_node,
127
128 // [2]
129 // x
130 // ^^ \^
131 // // \\
132 // // `'\
133 // x ===> x
134 // [0] [1]
135 node_1_1_2_2_node_2_node_1,
136
137 // [2]
138 // x
139 // ^^ \^
140 // // \\
141 // // `'\
142 // x ===> x
143 // [0] [1]
144 node_2_2_1_1_node_2_node_1,
145
146 // x [3]
147 // ^
148 // |
149 // |
150 // x ---> x ---> x
151 // [0] [1] [2]
152 node_3_1_node_2_node_node,
153
154 // x ---> x x <--- x
155 node_1_node_node_node_2,
156
157 // x -- x <- -> x -- x
158 node_2_node_node_node_1,
159
160 end
161 };
162 }
163
164 template
165 <
166 class EdgeWeight,
167 class NodeWeight,
168 class EdgeStorageConfig,
169 class NodeWeightStorage
170 >
172 {
173 public:
175 using edge_t = typename graph_t::edge_init_type;
176 using edges_equivalent_t = std::initializer_list<std::initializer_list<edge_t>>;
177 using transition_graph = typename transition_checker<graph_t>::transition_graph;
178
179 static void check_initialization_exceptions(regular_test& t)
180 {
181 t.check_exception_thrown<std::out_of_range>("Zeroth partial index of edge out of range", [](){ return graph_t{{edge_t{1}}}; });
182 t.check_exception_thrown<std::out_of_range>("First partial index of edge out of range", [](){ return graph_t{{edge_t{0}, edge_t{1}}}; });
183 t.check_exception_thrown<std::out_of_range>("First partial index of edge out of range", [](){ return graph_t{{edge_t{0}, edge_t{2}}, {}}; });
184 t.check_exception_thrown<std::out_of_range>("Zeroth partial index of node 1's edge out of range", [](){ return graph_t{{edge_t{0}, edge_t{1}}, {edge_t{2}}}; });
185 }
186
187 static void execute_operations(regular_test& t)
188 {
189 auto trg{make_transition_graph(t)};
190
191 auto checker{
192 [&t](std::string_view description, const graph_t& obtained, const graph_t& prediction, const graph_t& parent, std::size_t host, std::size_t target) {
193 t.check(equality, {description, no_source_location}, obtained, prediction);
194 if(host != target) t.check_semantics({description, no_source_location}, prediction, parent);
195 }
196 };
197
199 }
200
201 [[nodiscard]]
202 static graph_t make_and_check(regular_test& t, std::string_view description, edges_equivalent_t init)
203 {
205 }
206
207 [[nodiscard]]
208 static transition_graph make_transition_graph(regular_test& t)
209 {
210 using namespace directed_graph;
211
212 check_initialization_exceptions(t);
213
214 return transition_graph{
215 {
216 { // begin, 'empty'
217 {
218 graph_description::empty,
219 t.report(""),
220 [&t](const graph_t& g) -> const graph_t& {
221 t.check_exception_thrown<std::out_of_range>("cbegin_edges throws for empty graph", [&g]() { return g.cbegin_edges(0); });
222 return g;
223 }
224 },
225 {
226 graph_description::empty,
227 t.report(""),
228 [&t](const graph_t& g) -> const graph_t& {
229 t.check_exception_thrown<std::out_of_range>("cend_edges throws for empty graph", [&g]() { return g.cend_edges(0); });
230 return g;
231 }
232 },
233 {
234 graph_description::empty,
235 t.report(""),
236 [&t](const graph_t& g) -> const graph_t& {
237 t.check_exception_thrown<std::out_of_range>("crbegin_edges throws for empty graph", [&g]() { return g.crbegin_edges(0); });
238 return g;
239 }
240 },
241 {
242 graph_description::empty,
243 t.report(""),
244 [&t](const graph_t& g) -> const graph_t& {
245 t.check_exception_thrown<std::out_of_range>("crend_edges throws for empty graph", [&g]() { return g.crend_edges(0); });
246 return g;
247 }
248 },
249 {
250 graph_description::empty,
251 t.report(""),
252 [&t](const graph_t& g) -> const graph_t& {
253 t.check_exception_thrown<std::out_of_range>("cedges throws for empty graph", [&g]() { return g.cedges(0); });
254 return g;
255 }
256 },
257 {
258 graph_description::empty,
259 t.report(""),
260 [&t](const graph_t& g) -> const graph_t& {
261 t.check_exception_thrown<std::out_of_range>("swapping nodes throws for empty graph", [g{g}]() mutable { g.swap_nodes(0, 0); });
262 return g;
263 }
264 },
265 {
266 graph_description::empty,
267 t.report(""),
268 [&t](const graph_t& g) -> const graph_t& {
269 t.check_exception_thrown<std::out_of_range>("swapping edges throws for empty graph", [g{g}]() mutable { g.swap_edges(0, 0, 0); });
270 return g;
271 }
272 },
273 {
274 graph_description::empty,
275 t.report(""),
276 [&t](const graph_t& g) -> const graph_t& {
277 t.check_exception_thrown<std::out_of_range>("joining nodes throws for empty graph", [g{g}]() mutable { g.join(0, 0); });
278 return g;
279 }
280 },
281 {
282 graph_description::empty,
283 t.report("Clear empty graph"),
284 [](graph_t g) -> graph_t {
285 g.clear();
286 return g;
287 }
288 },
289 {
290 graph_description::node,
291 t.report("Add node to empty graph"),
292 [&t](graph_t g) -> graph_t {
293 t.check(equality, "Index of added node is 0", g.add_node(), 0uz);
294 return g;
295 }
296 },
297 {
298 graph_description::node,
299 t.report("insert node into empty graph"),
300 [&t](graph_t g) -> graph_t {
301 t.check(equality, "Index of added node is 0", g.insert_node(0), 0uz);
302 return g;
303 }
304 }
305 }, // end 'empty'
306 { // begin 'node'
307 {
308 graph_description::node,
309 t.report(""),
310 [&t](const graph_t& g) -> const graph_t& {
311 t.check_exception_thrown<std::out_of_range>("cbegin_edges throws when index is out of range", [&g]() { return g.cbegin_edges(1); });
312 return g;
313 }
314 },
315 {
316 graph_description::node,
317 t.report(""),
318 [&t](const graph_t& g) -> const graph_t& {
319 t.check_exception_thrown<std::out_of_range>("cend_edges throws when index is out of range", [&g]() { return g.cend_edges(1); });
320 return g;
321 }
322 },
323 {
324 graph_description::node,
325 t.report(""),
326 [&t](const graph_t& g) -> const graph_t& {
327 t.check_exception_thrown<std::out_of_range>("crbegin_edges throws when index is out of range", [&g]() { return g.crbegin_edges(1); });
328 return g;
329 }
330 },
331 {
332 graph_description::node,
333 t.report(""),
334 [&t](const graph_t& g) -> const graph_t& {
335 t.check_exception_thrown<std::out_of_range>("crend_edges throws when index is out of range", [&g]() { return g.crend_edges(1); });
336 return g;
337 }
338 },
339 {
340 graph_description::node,
341 t.report(""),
342 [&t](const graph_t& g) -> const graph_t& {
343 t.check_exception_thrown<std::out_of_range>("cedges throws when index is out of range", [&g]() { return g.cedges(1); });
344 return g;
345 }
346 },
347 {
348 graph_description::node,
349 t.report(""),
350 [&t](const graph_t& g) -> const graph_t& {
351 t.check_exception_thrown<std::out_of_range>("swapping nodes throws if first index out of range", [g{g}]() mutable { g.swap_nodes(1, 0); });
352 return g;
353 }
354 },
355 {
356 graph_description::node,
357 t.report(""),
358 [&t](const graph_t& g) -> const graph_t& {
359 t.check_exception_thrown<std::out_of_range>("swapping nodes throws if second index out of range", [g{g}]() mutable { g.swap_nodes(0, 1); });
360 return g;
361 }
362 },
363 {
364 graph_description::node,
365 t.report(""),
366 [&t](const graph_t& g) -> const graph_t& {
367 t.check_exception_thrown<std::out_of_range>("joining nodes throws if first index out of range", [g{g}]() mutable { g.join(1, 0); });
368 return g;
369 }
370 },
371 {
372 graph_description::node,
373 t.report(""),
374 [&t](const graph_t& g) -> const graph_t& {
375 t.check_exception_thrown<std::out_of_range>("joining nodes throws if second index out of range", [g{g}]() mutable { g.join(0, 1); });
376 return g;
377 }
378 },
379 {
380 graph_description::empty,
381 t.report("Clear graph"),
382 [](graph_t g) -> graph_t {
383 g.clear();
384 return g;
385 }
386 },
387 {
388 graph_description::empty,
389 t.report("Erase node to give empty graph"),
390 [](graph_t g) -> graph_t {
391 g.erase_node(0);
392 return g;
393 }
394 },
395 {
396 graph_description::node,
397 t.report("Attempt to erase edge past the end"),
398 [](graph_t g) -> const graph_t {
399 g.erase_edge(g.cend_edges(0));
400 return g;
401 }
402 },
403 {
404 graph_description::node_0,
405 t.report("Add loop"),
406 [](graph_t g) -> graph_t {
407 g.join(0, 0);
408 return g;
409 }
410 },
411 {
412 graph_description::node_node,
413 t.report("Add second node"),
414 [&t](graph_t g) -> graph_t {
415 t.check(equality, "Index of added node is 1", g.add_node(), 1uz);
416 return g;
417 }
418 },
419 {
420 graph_description::node_node,
421 t.report("Insert second node"),
422 [&t](graph_t g) -> graph_t {
423 t.check(equality, "Index of added node is 0", g.insert_node(0), 0uz);
424 return g;
425 }
426 },
427 {
428 graph_description::node_node,
429 t.report("Insert second node at end"),
430 [&t](graph_t g) -> graph_t {
431 t.check(equality, "Index of added node is 1", g.insert_node(1), 1uz);
432 return g;
433 }
434 },
435 {
436 graph_description::node,
437 t.report("Swap node with self"),
438 [](graph_t g) -> graph_t {
439 g.swap_nodes(0,0);
440 return g;
441 }
442 }
443 }, // end 'node'
444 { // begin 'node_0'
445 {
446 graph_description::empty,
447 t.report("Clear graph"),
448 [](graph_t g) -> graph_t {
449 g.clear();
450 return g;
451 }
452 },
453 {
454 graph_description::node,
455 t.report("Remove loop"),
456 [](graph_t g) -> graph_t {
457 g.erase_edge(g.cbegin_edges(0));
458 return g;
459 }
460 },
461 {
462 graph_description::node_0_0,
463 t.report("Add a second loop"),
464 [](graph_t g) -> graph_t {
465 g.join(0, 0);
466 return g;
467 }
468 },
469 {
470 graph_description::node_node_1,
471 t.report("Insert node"),
472 [&t](graph_t g) -> graph_t {
473 t.check(equality, "Index of added node is 0", g.insert_node(0), 0uz);
474 return g;
475 }
476 },
477 {
478 graph_description::node_0_node,
479 t.report("Insert node at end"),
480 [&t](graph_t g) -> graph_t {
481 t.check(equality, "Index of added node is 1", g.insert_node(1), 1uz);
482 return g;
483 }
484 },
485 {
486 graph_description::node_0,
487 t.report("Swap node with self"),
488 [](graph_t g) -> graph_t {
489 g.swap_nodes(0,0);
490 return g;
491 }
492 },
493 {
494 graph_description::node_0,
495 t.report("Swap edge with self"),
496 [](graph_t g) -> graph_t {
497 g.swap_edges(0, 0, 0);
498 return g;
499 }
500 },
501 {
502 graph_description::node_0,
503 t.report(""),
504 [&t](const graph_t& g) -> const graph_t& {
505 t.check_exception_thrown<std::out_of_range>("swapping edges throws for first edge index out of range", [g{g}]() mutable { g.swap_edges(0, 1, 0); });
506 return g;
507 }
508 },
509 {
510 graph_description::node_0,
511 t.report(""),
512 [&t](const graph_t& g) -> const graph_t& {
513 t.check_exception_thrown<std::out_of_range>("swapping edges throws for second edge index out of range", [g{g}]() mutable { g.swap_edges(0, 0, 1); });
514 return g;
515 }
516 },
517 {
518 graph_description::node_0,
519 t.report(""),
520 [&t](const graph_t& g) -> const graph_t& {
521 t.check_exception_thrown<std::out_of_range>("swapping edges throws for node index out of range", [g{g}]() mutable { g.swap_edges(1, 0, 0); });
522 return g;
523 }
524 }
525 }, // end 'node_0'
526 { // begin 'node_0_0'
527 {
528 graph_description::empty,
529 t.report("Clear graph"),
530 [](graph_t g) -> graph_t {
531 g.clear();
532 return g;
533 }
534 },
535 {
536 graph_description::node_0,
537 t.report("Remove first loop"),
538 [](graph_t g) -> graph_t {
539 g.erase_edge(g.cbegin_edges(0));
540 return g;
541 }
542 },
543 {
544 graph_description::node_0,
545 t.report("Remove second loop"),
546 [](graph_t g) -> graph_t {
547 g.erase_edge(std::ranges::next(g.cbegin_edges(0)));
548 return g;
549 }
550 },
551 {
552 graph_description::node_0_0,
553 t.report("Swap loops"),
554 [](graph_t g) -> graph_t {
555 g.swap_edges(0, 0, 1);
556 return g;
557 }
558 },
559 {
560 graph_description::node_0_0,
561 t.report("Swap loops"),
562 [](graph_t g) -> graph_t {
563 g.swap_edges(0, 1, 0);
564 return g;
565 }
566 }
567 }, // end 'node_0_0'
568 { // begin 'node_node'
569 {
570 graph_description::empty,
571 t.report("Clear graph"),
572 [](graph_t g) -> graph_t {
573 g.clear();
574 return g;
575 }
576 },
577 {
578 graph_description::node,
579 t.report("Erase node 0"),
580 [](graph_t g) -> graph_t {
581 g.erase_node(0);
582 return g;
583 }
584 },
585 {
586 graph_description::node,
587 t.report("Erase node 1"),
588 [](graph_t g) -> graph_t {
589 g.erase_node(1);
590 return g;
591 }
592 },
593 {
594 graph_description::node_1_node,
595 t.report("Join nodes 0,1"),
596 [](graph_t g) -> graph_t {
597 g.join(0, 1);
598 return g;
599 }
600 }
601 }, // end 'node_node'
602 { // begin 'node_1_node'
603 {
604 graph_description::empty,
605 t.report("Clear graph"),
606 [](graph_t g) -> graph_t {
607 g.clear();
608 return g;
609 }
610 },
611 {
612 graph_description::node,
613 t.report("Erase node 0"),
614 [](graph_t g) -> graph_t {
615 g.erase_node(0);
616 return g;
617 }
618 },
619 {
620 graph_description::node,
621 t.report("Erase node 1"),
622 [](graph_t g) -> graph_t {
623 g.erase_node(1);
624 return g;
625 }
626 },
627 {
628 graph_description::node_0_1_node,
629 t.report("Add loop to node 0 and then swap it with link"),
630 [](graph_t g) -> graph_t {
631 g.join(0, 0);
632 g.swap_edges(0, 0, 1);
633 return g;
634 }
635 },
636 {
637 graph_description::node_node_0,
638 t.report("Swap nodes {0,1}"),
639 [](graph_t g) -> graph_t {
640 g.swap_nodes(0,1);
641 return g;
642 }
643 },
644 {
645 graph_description::node_node_0,
646 t.report("Swap nodes {1,0}"),
647 [](graph_t g) -> graph_t {
648 g.swap_nodes(1,0);
649 return g;
650 }
651 },
652 {
653 graph_description::node_1_1_node,
654 t.report("Join {0,1}"),
655 [](graph_t g) {
656 g.join(0, 1);
657 return g;
658 }
659 }
660 }, // end 'node_1_node'
661 { // begin node_node_0
662 {
663 graph_description::empty,
664 t.report("Clear graph"),
665 [](graph_t g) -> graph_t {
666 g.clear();
667 return g;
668 }
669 },
670 {
671 graph_description::node,
672 t.report("Erase node 0"),
673 [](graph_t g) -> graph_t {
674 g.erase_node(0);
675 return g;
676 }
677 },
678 {
679 graph_description::node,
680 t.report("Erase node 1"),
681 [](graph_t g) -> graph_t {
682 g.erase_node(1);
683 return g;
684 }
685 },
686 {
687 graph_description::node_1_node,
688 t.report("Swap nodes {0,1}"),
689 [](graph_t g) -> graph_t {
690 g.swap_nodes(0,1);
691 return g;
692 }
693 },
694 {
695 graph_description::node_1_node,
696 t.report("Swap nodes {1,0}"),
697 [](graph_t g) -> graph_t {
698 g.swap_nodes(1,0);
699 return g;
700 }
701 },
702 {
703 graph_description::node_1_node_0,
704 t.report("Join nodes {0,1}"),
705 [](graph_t g) {
706 g.join(0, 1);
707 return g;
708 }
709 }
710 }, // end 'node_node_0'
711 { // begin 'node_0_1_node'
712 {
713 graph_description::empty,
714 t.report("Clear graph"),
715 [](graph_t g) -> graph_t {
716 g.clear();
717 return g;
718 }
719 },
720 {
721 graph_description::node,
722 t.report("Erase node 0"),
723 [](graph_t g) -> graph_t {
724 g.erase_node(0);
725 return g;
726 }
727 },
728 {
729 graph_description::node_0,
730 t.report("Erase node 1"),
731 [](graph_t g) -> graph_t {
732 g.erase_node(1);
733 return g;
734 }
735 },
736 {
737 graph_description::node_1_node,
738 t.report("Remove loop"),
739 [](graph_t g) -> graph_t {
740 g.erase_edge(g.cbegin_edges(0));
741 return g;
742 }
743 },
744 {
745 graph_description::node_0_node,
746 t.report("Remove link"),
747 [](graph_t g) -> graph_t {
748 g.erase_edge(std::ranges::next(g.cbegin_edges(0)));
749 return g;
750 }
751 }
752 }, // end 'node_0_1_node'
753 { // begin 'node_0_node'
754 {
755 graph_description::empty,
756 t.report("Clear graph"),
757 [](graph_t g) -> graph_t {
758 g.clear();
759 return g;
760 }
761 },
762 {
763 graph_description::node_node,
764 t.report("Remove link"),
765 [](graph_t g) -> graph_t {
766 g.erase_edge(g.cbegin_edges(0));
767 return g;
768 }
769 },
770 {
771 graph_description::node_node_1_node,
772 t.report("Insert node"),
773 [&t](graph_t g) -> graph_t {
774 t.check(equality, "Index of added node is 0", g.insert_node(0), 0uz);
775 return g;
776 }
777 },
778 {
779 graph_description::node_node_1,
780 t.report("Swap nodes"),
781 [](graph_t g) -> graph_t {
782 g.swap_nodes(0,1);
783 return g;
784 }
785 }
786 }, // end 'node_0_node'
787 { // begin 'node_node_1'
788 {
789 graph_description::empty,
790 t.report("Clear graph"),
791 [](graph_t g) -> graph_t {
792 g.clear();
793 return g;
794 }
795 },
796 {
797 graph_description::node_0,
798 t.report("Erase node 0"),
799 [](graph_t g) -> graph_t {
800 g.erase_node(0);
801 return g;
802 }
803 },
804 {
805 graph_description::node,
806 t.report("Erase node 1"),
807 [](graph_t g) -> graph_t {
808 g.erase_node(1);
809 return g;
810 }
811 },
812 {
813 graph_description::node_node,
814 t.report("Remove link"),
815 [](graph_t g) -> graph_t {
816 g.erase_edge(g.cbegin_edges(1));
817 return g;
818 }
819 },
820 {
821 graph_description::node_0_node,
822 t.report("swap nodes"),
823 [](graph_t g) -> graph_t {
824 g.swap_nodes(0,1);
825 return g;
826 }
827 }
828 }, // end 'node_node_1'
829 { // begin 'node_1_1_node'
830
831 {
832 graph_description::empty,
833 t.report("Clear graph"),
834 [](graph_t g) -> graph_t {
835 g.clear();
836 return g;
837 }
838 },
839 {
840 graph_description::node,
841 t.report("Erase node 0"),
842 [](graph_t g) -> graph_t {
843 g.erase_node(0);
844 return g;
845 }
846 },
847 {
848 graph_description::node,
849 t.report("Erase node 1"),
850 [](graph_t g) -> graph_t {
851 g.erase_node(1);
852 return g;
853 }
854 },
855 {
856 graph_description::node_1_node,
857 t.report("Erase node 0 zeroth link"),
858 [](graph_t g) -> graph_t {
859 g.erase_edge(g.cbegin_edges(0));
860 return g;
861 }
862 },
863 {
864 graph_description::node_1_node,
865 t.report("Erase node 0 first link"),
866 [](graph_t g) -> graph_t {
867 g.erase_edge(g.cbegin_edges(0)+1);
868 return g;
869 }
870 },
871 {
872 graph_description::node_1_1_node,
873 t.report("Swap edges"),
874 [](graph_t g) -> graph_t {
875 g.swap_edges(0, 0, 1);
876 return g;
877 }
878 },
879 {
880 graph_description::node_1_1_node,
881 t.report("Swap edges"),
882 [](graph_t g) -> graph_t {
883 g.swap_edges(0, 1, 0);
884 return g;
885 }
886 }
887 }, // end 'node_1_1_node'
888 { // beging 'node_1_node_0'
889 {
890 graph_description::empty,
891 t.report("Clear graph"),
892 [](graph_t g) -> graph_t {
893 g.clear();
894 return g;
895 }
896 },
897 {
898 graph_description::node,
899 t.report("Erase node 0"),
900 [](graph_t g) -> graph_t {
901 g.erase_node(0);
902 return g;
903 }
904 },
905 {
906 graph_description::node,
907 t.report("Erase node 1"),
908 [](graph_t g) -> graph_t {
909 g.erase_node(1);
910 return g;
911 }
912 },
913 {
914 graph_description::node_node_0,
915 t.report("Erase node 0 link"),
916 [](graph_t g) -> graph_t {
917 g.erase_edge(g.cbegin_edges(0));
918 return g;
919 }
920 },
921 {
922 graph_description::node_1_node,
923 t.report("Erase node 1 link"),
924 [](graph_t g) -> graph_t {
925 g.erase_edge(g.cbegin_edges(1));
926 return g;
927 }
928 },
929 {
930 graph_description::node_1_node_0,
931 t.report("Swap nodes"),
932 [](graph_t g) -> graph_t {
933 g.swap_nodes(1,0);
934 return g;
935 }
936 }
937 }, // end 'node_1_node_0'
938 { // begin 'node_node_node'
939 {
940 graph_description::empty,
941 t.report("Clear graph"),
942 [](graph_t g) -> graph_t {
943 g.clear();
944 return g;
945 }
946 },
947 {
948 graph_description::node_node,
949 t.report("Erase node 0"),
950 [](graph_t g) -> graph_t {
951 g.erase_node(0);
952 return g;
953 }
954 },
955 {
956 graph_description::node_node,
957 t.report("Erase node 1"),
958 [](graph_t g) -> graph_t {
959 g.erase_node(1);
960 return g;
961 }
962 },
963 {
964 graph_description::node_node,
965 t.report("Erase node 2"),
966 [](graph_t g) -> graph_t {
967 g.erase_node(2);
968 return g;
969 }
970 },
971 {
972 graph_description::node_1_node_node,
973 t.report("Join {0,1}"),
974 [](graph_t g) -> graph_t {
975 g.join(0,1);
976 return g;
977 }
978 },
979 {
980 graph_description::node_node_node_1,
981 t.report("Join {2,1}"),
982 [](graph_t g) -> graph_t {
983 g.join(2,1);
984 return g;
985 }
986 }
987 }, // end 'node_node_node'
988 { // begin 'node_1_node_node'
989
990 {
991 graph_description::empty,
992 t.report("Clear graph"),
993 [](graph_t g) -> graph_t {
994 g.clear();
995 return g;
996 }
997 },
998 {
999 graph_description::node_node,
1000 t.report("Erase node 0"),
1001 [](graph_t g) -> graph_t {
1002 g.erase_node(0);
1003 return g;
1004 }
1005 },
1006 {
1007 graph_description::node_node,
1008 t.report("Erase node 1"),
1009 [](graph_t g) -> graph_t {
1010 g.erase_node(1);
1011 return g;
1012 }
1013 },
1014 {
1015 graph_description::node_1_node,
1016 t.report("Erase node 2"),
1017 [](graph_t g) -> graph_t {
1018 g.erase_node(2);
1019 return g;
1020 }
1021 },
1022 {
1023 graph_description::node_node_node,
1024 t.report("Remove link {0,1}"),
1025 [](graph_t g) -> graph_t {
1026 g.erase_edge(g.cbegin_edges(0));
1027 return g;
1028 }
1029 },
1030 {
1031 graph_description::node_1_node_2_node,
1032 t.report("Join {2,1}"),
1033 [](graph_t g) -> graph_t {
1034 g.join(1,2);
1035 return g;
1036 }
1037 },
1038 {
1039 graph_description::node_1_node_node_1,
1040 t.report("Join {2,1}"),
1041 [](graph_t g) -> graph_t {
1042 g.join(2,1);
1043 return g;
1044 }
1045 },
1046 {
1047 graph_description::node_node_node_1,
1048 t.report("Swap nodes {0,2}"),
1049 [](graph_t g) -> graph_t {
1050 g.swap_nodes(0,2);
1051 return g;
1052 }
1053 },
1054 {
1055 graph_description::node_node_node_1,
1056 t.report("Swap nodes {2,0}"),
1057 [](graph_t g) -> graph_t {
1058 g.swap_nodes(2,0);
1059 return g;
1060 }
1061 }
1062 }, // end 'node_1_node_node'
1063 { // begin 'node_node_node_1'
1064 {
1065 graph_description::empty,
1066 t.report("Clear graph"),
1067 [](graph_t g) -> graph_t {
1068 g.clear();
1069 return g;
1070 }
1071 },
1072 {
1073 graph_description::node_node_0,
1074 t.report("Erase node 0"),
1075 [](graph_t g) -> graph_t {
1076 g.erase_node(0);
1077 return g;
1078 }
1079 },
1080 {
1081 graph_description::node_node,
1082 t.report("Erase node 1"),
1083 [](graph_t g) -> graph_t {
1084 g.erase_node(1);
1085 return g;
1086 }
1087 },
1088 {
1089 graph_description::node_node,
1090 t.report("Erase node 2"),
1091 [](graph_t g) -> graph_t {
1092 g.erase_node(2);
1093 return g;
1094 }
1095 },
1096 {
1097 graph_description::node_node_node,
1098 t.report("Remove link {2,1}"),
1099 [](graph_t g) -> graph_t {
1100 g.erase_edge(g.cbegin_edges(2));
1101 return g;
1102 }
1103 },
1104 {
1105 graph_description::node_1_node_node_1,
1106 t.report("Join {0,1}"),
1107 [](graph_t g) -> graph_t {
1108 g.join(0,1);
1109 return g;
1110 }
1111 },
1112 {
1113 graph_description::node_1_node_node,
1114 t.report("Swap nodes {0,2}"),
1115 [](graph_t g) -> graph_t {
1116 g.swap_nodes(0,2);
1117 return g;
1118 }
1119 },
1120 {
1121 graph_description::node_1_node_node,
1122 t.report("Swap nodes {2,0}"),
1123 [](graph_t g) -> graph_t {
1124 g.swap_nodes(2,0);
1125 return g;
1126 }
1127 }
1128 }, // end 'node_node_node_1'
1129 { // begin 'node_1_node_2_node'
1130 {
1131 graph_description::empty,
1132 t.report("Clear graph"),
1133 [](graph_t g) -> graph_t {
1134 g.clear();
1135 return g;
1136 }
1137 },
1138 {
1139 graph_description::node_1_node,
1140 t.report("Erase node 0"),
1141 [](graph_t g) -> graph_t {
1142 g.erase_node(0);
1143 return g;
1144 }
1145 },
1146 {
1147 graph_description::node_node,
1148 t.report("Erase node 1"),
1149 [](graph_t g) -> graph_t {
1150 g.erase_node(1);
1151 return g;
1152 }
1153 },
1154 {
1155 graph_description::node_1_node,
1156 t.report("Erase node 2"),
1157 [](graph_t g) -> graph_t {
1158 g.erase_node(2);
1159 return g;
1160 }
1161 },
1162 {
1163 graph_description::node_1_node_node,
1164 t.report("Remove link {1,2}"),
1165 [](graph_t g) -> graph_t {
1166 g.erase_edge(g.cbegin_edges(1));
1167 return g;
1168 }
1169 }
1170 }, // end 'node_1_node_2_node'
1171 { // begin 'node_1_node_node_1'
1172 {
1173 graph_description::empty,
1174 t.report("Clear graph"),
1175 [](graph_t g) -> graph_t {
1176 g.clear();
1177 return g;
1178 }
1179 },
1180 {
1181 graph_description::node_node_0,
1182 t.report("Erase node 0"),
1183 [](graph_t g) -> graph_t {
1184 g.erase_node(0);
1185 return g;
1186 }
1187 },
1188 {
1189 graph_description::node_node,
1190 t.report("Erase node 1"),
1191 [](graph_t g) -> graph_t {
1192 g.erase_node(1);
1193 return g;
1194 }
1195 },
1196 {
1197 graph_description::node_1_node,
1198 t.report("Erase node 2"),
1199 [](graph_t g) -> graph_t {
1200 g.erase_node(2);
1201 return g;
1202 }
1203 },
1204 {
1205 graph_description::node_node_node_1,
1206 t.report("Remove link {0,1}"),
1207 [](graph_t g) -> graph_t {
1208 g.erase_edge(g.cbegin_edges(0));
1209 return g;
1210 }
1211 },
1212 {
1213 graph_description::node_1_node_node,
1214 t.report("Remove link {2,1}"),
1215 [](graph_t g) -> graph_t {
1216 g.erase_edge(g.cbegin_edges(2));
1217 return g;
1218 }
1219 }
1220 }, // end 'node_1_node_node_1'
1221 { // begin 'node_1_node_2_node_0'
1222 {
1223 graph_description::empty,
1224 t.report("Clear graph"),
1225 [](graph_t g) -> graph_t {
1226 g.clear();
1227 return g;
1228 }
1229 },
1230 {
1231 graph_description::node_1_node,
1232 t.report("Erase node 0"),
1233 [](graph_t g) -> graph_t {
1234 g.erase_node(0);
1235 return g;
1236 }
1237 },
1238 {
1239 graph_description::node_node_0,
1240 t.report("Erase node 1"),
1241 [](graph_t g) -> graph_t {
1242 g.erase_node(1);
1243 return g;
1244 }
1245 },
1246 {
1247 graph_description::node_1_node,
1248 t.report("Erase node 2"),
1249 [](graph_t g) -> graph_t {
1250 g.erase_node(2);
1251 return g;
1252 }
1253 },
1254 {
1255 graph_description::node_1_node_2_node,
1256 t.report("Remove {2,0}"),
1257 [](graph_t g) -> graph_t {
1258 g.erase_edge(g.cbegin_edges(2));
1259 return g;
1260 }
1261 }
1262 }, // end 'node_1_node_2_node_0'
1263 { // begin 'node_node_1_node'
1264 {
1265 graph_description::empty,
1266 t.report("Clear graph"),
1267 [](graph_t g) -> graph_t {
1268 g.clear();
1269 return g;
1270 }
1271 },
1272 {
1273 graph_description::node_0_node,
1274 t.report("Erase node 0"),
1275 [](graph_t g) -> graph_t {
1276 g.erase_node(0);
1277 return g;
1278 }
1279 },
1280 {
1281 graph_description::node_node,
1282 t.report("Erase node 1"),
1283 [](graph_t g) -> graph_t {
1284 g.erase_node(1);
1285 return g;
1286 }
1287 },
1288 {
1289 graph_description::node_node_1,
1290 t.report("Erase node 2"),
1291 [](graph_t g) -> graph_t {
1292 g.erase_node(2);
1293 return g;
1294 }
1295 },
1296 }, // end 'node_node_1_node'
1297 { // begin 'node_1_node_1_node'
1298 {
1299 graph_description::node_0_node,
1300 t.report("Erase node 0"),
1301 [](graph_t g) -> graph_t {
1302 g.erase_node(0);
1303 return g;
1304 }
1305 },
1306 {
1307 graph_description::node_node,
1308 t.report("Erase node 1"),
1309 [](graph_t g) -> graph_t {
1310 g.erase_node(1);
1311 return g;
1312 }
1313 },
1314 {
1315 graph_description::node_node_1_node,
1316 t.report("Remove {0,1}"),
1317 [](graph_t g) -> graph_t {
1318 g.erase_edge(g.cbegin_edges(0));
1319 return g;
1320 }
1321 },
1322 {
1323 graph_description::node_1_node_1_0_node,
1324 t.report("Join {1,0}"),
1325 [](graph_t g) -> graph_t {
1326 g.join(1, 0);
1327 return g;
1328 }
1329 }
1330 }, // end 'node_1_node_1_node'
1331 { // begin 'node_1_node_1_0_node'
1332 {
1333 graph_description::node_0_node,
1334 t.report("Erase node 0"),
1335 [](graph_t g) -> graph_t {
1336 g.erase_node(0);
1337 return g;
1338 }
1339 },
1340 {
1341 graph_description::node_node,
1342 t.report("Erase node 1"),
1343 [](graph_t g) -> graph_t {
1344 g.erase_node(1);
1345 return g;
1346 }
1347 },
1348 {
1349 graph_description::node_1_node_1_node,
1350 t.report("Remove {1,0}"),
1351 [](graph_t g) -> graph_t {
1352 g.erase_edge(++g.cbegin_edges(1));
1353 return g;
1354 }
1355 },
1356 {
1357 graph_description::node_1_node_1_0_2_node,
1358 t.report("Join {1,2}"),
1359 [](graph_t g) -> graph_t {
1360 g.join(1, 2);
1361 return g;
1362 }
1363 }
1364 }, // end 'node_1_node_1_0_node'
1365 { // begin 'node_1_node_1_0_2_node'
1366 {
1367 graph_description::node_0_1_node,
1368 t.report("Erase node 0"),
1369 [](graph_t g) -> graph_t {
1370 g.erase_node(0);
1371 return g;
1372 }
1373 },
1374 {
1375 graph_description::node_node,
1376 t.report("Erase node 1"),
1377 [](graph_t g) -> graph_t {
1378 g.erase_node(1);
1379 return g;
1380 }
1381 },
1382 {
1383 graph_description::node_1_node_1_2_node,
1384 t.report("Remove {1,0}"),
1385 [](graph_t g) -> graph_t {
1386 g.erase_edge(++g.cbegin_edges(1));
1387 return g;
1388 }
1389 },
1390 {
1391 graph_description::node_1_node_1_0_node,
1392 t.report("Remove {1,2}"),
1393 [](graph_t g) -> graph_t {
1394 g.erase_edge(g.cbegin_edges(1)+2);
1395 return g;
1396 }
1397 }
1398 }, // end 'node_1_node_1_0_2_node'
1399 { // begin 'node_1_node_1_2_node'
1400 {
1401 graph_description::node_1_node_2_node,
1402 t.report("Remove {1,1}"),
1403 [](graph_t g) -> graph_t {
1404 g.erase_edge(g.cbegin_edges(1));
1405 return g;
1406 }
1407 }
1408 }, // end 'node_1_node_1_2_node'
1409 { // begin 'node_2_node_node_2'
1410 {
1411 graph_description::node_1_node_1_node,
1412 t.report("Swap {1,2}"),
1413 [](graph_t g) -> graph_t {
1414 g.swap_nodes(1,2);
1415 return g;
1416 }
1417 }
1418 }, // end 'node_2_node_node_2'
1419 { // begin 'node_1_1_2_2_node_2_node'
1420 {
1421 graph_description::node_1_node,
1422 t.report("Erase node 0"),
1423 [](graph_t g) -> graph_t {
1424 g.erase_node(0);
1425 return g;
1426 }
1427 },
1428 {
1429 graph_description::node_1_1_node,
1430 t.report("Erase node 1"),
1431 [](graph_t g) -> graph_t {
1432 g.erase_node(1);
1433 return g;
1434 }
1435 },
1436 {
1437 graph_description::node_1_1_node,
1438 t.report("Erase node 2"),
1439 [](graph_t g) -> graph_t {
1440 g.erase_node(2);
1441 return g;
1442 }
1443 },
1444 {
1445 graph_description::node_1_1_2_2_node_2_node_1,
1446 t.report("Join {2, 1}"),
1447 [](graph_t g) -> graph_t {
1448 g.join(2,1);
1449 return g;
1450 }
1451 }
1452 }, // end 'node_1_1_2_2_node_2_node'
1453 { // begin 'node_1_1_2_2_node_2_node_1'
1454 {
1455 graph_description::node_1_node_0,
1456 t.report("Erase node 0"),
1457 [](graph_t g) -> graph_t {
1458 g.erase_node(0);
1459 return g;
1460 }
1461 },
1462 {
1463 graph_description::node_1_1_node,
1464 t.report("Erase node 1"),
1465 [](graph_t g) -> graph_t {
1466 g.erase_node(1);
1467 return g;
1468 }
1469 },
1470 {
1471 graph_description::node_1_1_node,
1472 t.report("Erase node 2"),
1473 [](graph_t g) -> graph_t {
1474 g.erase_node(2);
1475 return g;
1476 }
1477 },
1478 {
1479 graph_description::node_2_2_1_1_node_2_node_1,
1480 t.report("Swap {1,2}"),
1481 [](graph_t g) -> graph_t {
1482 g.swap_nodes(1,2);
1483 return g;
1484 }
1485 },
1486 {
1487 graph_description::node_2_2_1_1_node_2_node_1,
1488 t.report("Swap {2,1}"),
1489 [](graph_t g) -> graph_t {
1490 g.swap_nodes(2,1);
1491 return g;
1492 }
1493 },
1494 {
1495 graph_description::node_2_2_1_1_node_2_node_1,
1496 t.report("Swap node 0 edges: {0,2}, {1,3}"),
1497 [](graph_t g) -> graph_t {
1498 g.swap_edges(0, 0, 2);
1499 g.swap_edges(0, 1, 3);
1500 return g;
1501 }
1502 }
1503 }, // end 'node_1_1_2_2_node_2_node_1'
1504 { // begin 'node_2_2_1_1_node_2_node_1'
1505 {
1506 graph_description::node_1_1_2_2_node_2_node_1,
1507 t.report("Swap {1,2}"),
1508 [](graph_t g) -> graph_t {
1509 g.swap_nodes(1,2);
1510 return g;
1511 }
1512 },
1513 {
1514 graph_description::node_1_1_2_2_node_2_node_1,
1515 t.report("Swap {2,1}"),
1516 [](graph_t g) -> graph_t {
1517 g.swap_nodes(2,1);
1518 return g;
1519 }
1520 },
1521 {
1522 graph_description::node_1_1_2_2_node_2_node_1,
1523 t.report("Sort Edges for node 0"),
1524 [](graph_t g) -> graph_t {
1525 g.sort_edges(g.cbegin_edges(0), g.cend_edges(0), std::ranges::less{}, [](const auto& lhs) { return lhs.target_node(); });
1526 return g;
1527 }
1528 },
1529 {
1530 graph_description::node_1_1_2_2_node_2_node_1,
1531 t.report("Sort Edges for node 0"),
1532 [](graph_t g) -> graph_t {
1533 g.sort_edges(g.cedges(0), std::ranges::less{}, [](const auto& lhs) { return lhs.target_node(); });
1534 return g;
1535 }
1536 },
1537 {
1538 graph_description::node_1_1_2_2_node_2_node_1,
1539 t.report("Sort Edges for node 0"),
1540 [](graph_t g) -> graph_t {
1541 g.stable_sort_edges(g.cbegin_edges(0), g.cend_edges(0), std::ranges::less{}, [](const auto& lhs) { return lhs.target_node(); });
1542 return g;
1543 }
1544 },
1545 {
1546 graph_description::node_1_1_2_2_node_2_node_1,
1547 t.report("Sort Edges for node 0"),
1548 [](graph_t g) -> graph_t {
1549 g.stable_sort_edges(g.cedges(0), std::ranges::less{}, [](const auto& lhs) { return lhs.target_node(); });
1550 return g;
1551 }
1552 },
1553 {
1554 graph_description::node_1_1_2_2_node_2_node_1,
1555 t.report("Swap node 0 edges: {0,2}, {1,3}"),
1556 [](graph_t g) -> graph_t {
1557 g.swap_edges(0, 0, 2);
1558 g.swap_edges(0, 1, 3);
1559 return g;
1560 }
1561 }
1562 }, // end 'node_2_2_1_1_node_2_node_1'
1563 { // begin 'node_3_1_node_2_node_node'
1564 {
1565 graph_description::node_1_node_node,
1566 t.report("Erase node 0"),
1567 [](graph_t g) -> graph_t {
1568 g.erase_node(0);
1569 return g;
1570 }
1571 }
1572 }, // end 'node_3_1_node_2_node_node'
1573 { // begin 'node_1_node_node_node_2'
1574 {
1575 graph_description::node_2_node_node_node_1,
1576 t.report("Swap {2,1}"),
1577 [](graph_t g) -> graph_t {
1578 g.swap_nodes(2,1);
1579 return g;
1580 }
1581 },
1582 {
1583 graph_description::node_2_node_node_node_1,
1584 t.report("Swap {0,3}"),
1585 [](graph_t g) -> graph_t {
1586 g.swap_nodes(0,3);
1587 return g;
1588 }
1589 }
1590 }, // end 'node_1_node_node_node_2'
1591 { // begin 'node_2_node_node_node_1'
1592 {
1593 graph_description::node_1_node_node_node_2,
1594 t.report("Swap {2,1}"),
1595 [](graph_t g) -> graph_t {
1596 g.swap_nodes(2,1);
1597 return g;
1598 }
1599 },
1600 {
1601 graph_description::node_1_node_node_node_2,
1602 t.report("Swap {0,3}"),
1603 [](graph_t g) -> graph_t {
1604 g.swap_nodes(0,3);
1605 return g;
1606 }
1607 }
1608 }, // end 'node_2_node_node_node_1'
1609 },
1610 {
1611 // 'empty'
1612 make_and_check(t, t.report(""), {}),
1613
1614 // 'node'
1615 make_and_check(t, t.report(""), {{}}),
1616
1617 // 'node_0'
1618 make_and_check(t, t.report(""), {{edge_t{0}}}),
1619
1620 // 'node_0_0'
1621 make_and_check(t, t.report(""), {{edge_t{0}, edge_t{0}}}),
1622
1623 // 'node_node'
1624 make_and_check(t, t.report(""), {{}, {}}),
1625
1626 // 'node_1_node'
1627 make_and_check(t, t.report(""), {{edge_t{1}}, {}}),
1628
1629 // 'node_node_0'
1630 make_and_check(t, t.report(""), {{}, {edge_t{0}}}),
1631
1632 // 'node_0_1_node'
1633 make_and_check(t, t.report(""), {{edge_t{0}, edge_t{1}}, {}}),
1634
1635 // 'node_0_node'
1636 make_and_check(t, t.report(""), {{edge_t{0}}, {}}),
1637
1638 // 'node_node_1'
1639 make_and_check(t, t.report(""), {{}, {edge_t{1}}}),
1640
1641 // 'node_1_1_node'
1642 make_and_check(t, t.report(""), {{edge_t{1}, edge_t{1}}, {}}),
1643
1644 // 'node_1_node_0'
1645 make_and_check(t, t.report(""), {{edge_t{1}}, {edge_t{0}}}),
1646
1647 // 'node_node_node'
1648 make_and_check(t, t.report(""), {{}, {}, {}}),
1649
1650 // 'node_1_node_node'
1651 make_and_check(t, t.report(""), {{edge_t{1}}, {}, {}}),
1652
1653 // 'node_node_node_1'
1654 make_and_check(t, t.report(""), {{}, {}, {edge_t{1}}}),
1655
1656 // 'node_1_node_2_node'
1657 make_and_check(t, t.report(""), {{edge_t{1}}, {edge_t{2}}, {}}),
1658
1659 // 'node_1_node_node_1'
1660 make_and_check(t, t.report(""), {{edge_t{1}}, {}, {edge_t{1}}}),
1661
1662 // 'node_1_node_2_node_0'
1663 make_and_check(t, t.report(""), {{edge_t{1}}, {edge_t{2}}, {edge_t{0}}}),
1664
1665 // 'node_node_1_node'
1666 make_and_check(t, t.report(""), {{}, {edge_t{1}}, {}}),
1667
1668 // 'node_1_node_1_node'
1669 make_and_check(t, t.report(""), {{edge_t{1}}, {edge_t{1}}, {}}),
1670
1671 // 'node_1_node_1_0_node'
1672 make_and_check(t, t.report(""), {{edge_t{1}}, {edge_t{1}, edge_t{0}}, {}}),
1673
1674 // 'node_1_node_1_0_2_node'
1675 make_and_check(t, t.report(""), {{edge_t{1}}, {edge_t{1}, edge_t{0}, edge_t{2}}, {}}),
1676
1677 // 'node_1_node_1_2_node'
1678 make_and_check(t, t.report(""), {{edge_t{1}}, {edge_t{1}, edge_t{2}}, {}}),
1679
1680 // 'node_2_node_node_2'
1681 make_and_check(t, t.report(""), {{edge_t{2}}, {}, {edge_t{2}}}),
1682
1683 // 'node_1_1_2_2_node_2_node'
1684 make_and_check(t, t.report(""), {{edge_t{1}, edge_t{1}, edge_t{2}, edge_t{2}}, {edge_t{2}}, {}}),
1685
1686 // 'node_1_1_2_2_node_2_node_1'
1687 make_and_check(t, t.report(""), {{edge_t{1}, edge_t{1}, edge_t{2}, edge_t{2}}, {edge_t{2}}, {edge_t{1}}}),
1688
1689 // 'node_2_2_1_1_node_2_node_1'
1690 make_and_check(t, t.report(""), {{edge_t{2}, edge_t{2}, edge_t{1}, edge_t{1}}, {edge_t{2}}, {edge_t{1}}}),
1691
1692 // 'node_3_1_node_2_node_node'
1693 make_and_check(t, t.report(""), {{edge_t{3}, edge_t{1}}, {edge_t{2}}, {}, {}}),
1694
1695 // 'node_1_node_node_node_2'
1696 make_and_check(t, t.report(""), {{edge_t{1}}, {}, {}, {edge_t{2}}}),
1697
1698 // 'node_2_node_node_node_1'
1699 make_and_check(t, t.report(""), {{edge_t{2}}, {}, {}, {edge_t{1}}})
1700 }
1701 };
1702 }
1703 };
1704}
graph_description
Convention: the indices following 'node' - separated by underscores - give the target node of the ass...
Definition: DynamicDirectedGraphTestingUtilities.hpp:21
Utilities for checking regular semantics.
Facility to define tests via a graph comprising states of an object and transitions between them.
Definition: DynamicGraph.hpp:303
class template from which all concrete tests should derive.
Definition: FreeTestCore.hpp:144
Exposes elementary check methods, with the option to plug in arbitrary Extenders to compose functiona...
Definition: FreeCheckers.hpp:708
Definition: DynamicDirectedGraphTestingUtilities.hpp:172
Definition: DynamicGraphTestingUtilities.hpp:173
Definition: StateTransitionUtilities.hpp:77