mCRL2
Loading...
Searching...
No Matches
pbesinst_structure_graph2.h
Go to the documentation of this file.
1// Author(s): Wieger Wesselink
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
9/// \file mcrl2/pbes/pbesinst_structure_graph2.h
10/// \brief add your file description here.
11
12#ifndef MCRL2_PBES_PBESINST_STRUCTURE_GRAPH2_H
13#define MCRL2_PBES_PBESINST_STRUCTURE_GRAPH2_H
14
15#include "mcrl2/atermpp/standard_containers/deque.h"
16#include "mcrl2/atermpp/standard_containers/unordered_set.h"
17#include "mcrl2/atermpp/standard_containers/vector.h"
18#include "mcrl2/pbes/pbesinst_fatal_attractors.h"
19#include "mcrl2/pbes/pbesinst_find_loops.h"
20#include "mcrl2/pbes/pbesinst_partial_solve.h"
21#include "mcrl2/pbes/pbesinst_structure_graph.h"
22#include "mcrl2/pbes/pbessolve_options.h"
23#include "mcrl2/utilities/stopwatch.h"
24
25
26
27namespace mcrl2::pbes_system {
28
29namespace detail {
30
32{
33 protected:
35
36 public:
37 explicit computation_guard(std::size_t initial_count = 64)
39 {}
40
41 bool operator()(std::size_t count)
42 {
43 bool result = count >= m_count;
44 while (m_count <= count)
45 {
46 m_count *= 2;
47 }
48 return result;
49 }
50};
51
53{
54 protected:
57
58 public:
60 {}
61
62 periodic_guard(std::size_t initial_regeneration_period)
64 {}
65
67 {
68 ++m_count;
69 if (m_count >= m_regeneration_period)
70 {
71 m_count=0;
72 return true;
73 }
74 return false;
75 }
76
77 void set_expiration_steps(const std::size_t p)
78 {
79 m_regeneration_period = p;
80 }
81};
82
83} // namespace detail
84
85/// \brief Adds an optimization to pbesinst_structure_graph.
87{
88 protected:
92
93 atermpp::vector<pbes_expression> b; // to store the result of the Rplus computation
96
97 template<typename T>
98 pbes_expression expr(const T& x) const
99 {
100 return static_cast<const pbes_expression&>(x);
101 }
102
104 {
106 using super::enter;
107 using super::leave;
108 using super::apply;
109
110 // A reference_aterm_stack_element is a stack element to be used inside an aterm container.
111 // Its elements are not protected individually, when used outside a container. In that
112 // case the stack_element below should be used.
114 {
119
121 const pbes_expression& b_,
122 const pbes_expression& f_,
123 const pbes_expression& g0_,
124 const pbes_expression& g1_
125 )
126 : b(b_), f(f_), g0(g0_), g1(g1_)
127 {}
128
129 template<class E1, class E2>
131 const E1& b_,
132 const E2& f_,
133 const pbes_expression& g0_,
134 const pbes_expression& g1_
135 )
138 g0(g0_),
139 g1(g1_)
140 {}
141
142 void mark(atermpp::term_mark_stack& todo) const
143 {
144 mark_term(b, todo);
145 mark_term(f, todo);
146 mark_term(g0, todo);
147 mark_term(g1, todo);
148 }
149 };
150
151 // A stack element is an reference_aterm_stack_element of which the elements are protected against garbage collection.
153 {
158
160 : b(s.b), f(s.f), g0(s.g0), g1(s.g1)
161 {}
162 };
163
165
168
169 Rplus_traverser(std::array<vertex_set, 2>& S_, detail::structure_graph_builder& graph_builder_)
170 : S(S_), graph_builder(graph_builder_)
171 {}
172
174 {
175 stack.push_back(elem);
176 }
177
179 {
180 stack_element result(stack.back());
181 stack.pop_back();
182 return result;
183 }
184
185 // Return the top element of result_stack
187 {
188 return stack.back();
189 }
190
191 // Return the top element of result_stack
193 {
194 return stack.back();
195 }
196
197 static bool less(const pbes_expression& x1, const pbes_expression& x2)
198 {
199 return x1 < x2;
200 }
201
202 void leave(const data::data_expression& x)
203 {
204 if (is_true(x) || is_false(x))
205 {
206 stack.emplace_back(x, x, true_(), false_());
207 }
208 else
209 {
210 throw mcrl2::runtime_error("Fail to evaluate the expression " + data::pp(x) + " as it should be equal to true or false.");
211 }
212 }
213
215 {
216 const structure_graph::index_type u = graph_builder.find_vertex(x);
217 if (u == undefined_vertex())
218 {
219 // if x is not yet in the graph, then it certainly isn't in S[0] or S[1]
220 stack.emplace_back(data::undefined_data_expression(), x, true_(), false_());
221 }
222 else if (S[0].contains(u))
223 {
224 stack.emplace_back(true_(), x, x, false_());
225 }
226 else if (S[1].contains(u))
227 {
228 stack.emplace_back(false_(), x, true_(), x);
229 }
230 else
231 {
232 stack.emplace_back(data::undefined_data_expression(), x, true_(), false_());
233 }
234 }
235
236 void leave(const and_& /* x */)
237 {
238 const stack_element elem2 = pop();
240 atermpp::detail::reference_aterm<pbes_expression>& b_1 = elem1.b;
241 atermpp::detail::reference_aterm<pbes_expression>& f1_prime = elem1.f;
242 atermpp::detail::reference_aterm<pbes_expression>& g0_1 = elem1.g0;
243 atermpp::detail::reference_aterm<pbes_expression>& g1_1 = elem1.g1;
244 const pbes_expression& b_2 = elem2.b;
245 const pbes_expression& f2_prime = elem2.f;
246 const pbes_expression& g0_2 = elem2.g0;
247 const pbes_expression& g1_2 = elem2.g1;
248
249 // put the result in (b1, f1_prime, g0, g1)
250 if (is_true(b_1) && is_true(b_2))
251 {
252 b_1 = true_();
253 f1_prime = and_(f1_prime, f2_prime);
254 g0_1 = and_(g0_1, g0_2);
255 g1_1 = false_();
256 }
257 else if (is_false(b_1) && !is_false(b_2))
258 {
259 b_1 = false_();
260 g0_1 = true_();
261 }
262 else if (!is_false(b_1) && is_false(b_2))
263 {
264 b_1 = false_();
265 f1_prime = f2_prime;
266 g0_1 = true_();
267 g1_1 = g1_2;
268 }
269 else if (is_false(b_1) && is_false(b_2))
270 {
271 if (less(f1_prime, f2_prime))
272 {
273 b_1 = false_();
274 g0_1 = true_();
275 }
276 else
277 {
278 b_1 = false_();
279 f1_prime = f2_prime;
280 g0_1 = true_();
281 g1_1 = g1_2;
282 }
283 }
284 else // if (b1 == data::undefined_data_expression() && b2 == data::undefined_data_expression())
285 {
286 b_1 = data::undefined_data_expression();
287 f1_prime = and_(f1_prime, f2_prime);
288 g0_1 = true_();
289 g1_1 = false_();
290 }
291 }
292
293 void leave(const or_& /* x */)
294 {
295 const stack_element elem2 = pop();
297 atermpp::detail::reference_aterm<pbes_expression>& b_1 = elem1.b;
298 atermpp::detail::reference_aterm<pbes_expression>& f1_prime = elem1.f;
299 atermpp::detail::reference_aterm<pbes_expression>& g0_1 = elem1.g0;
300 atermpp::detail::reference_aterm<pbes_expression>& g1_1 = elem1.g1;
301 const pbes_expression& b_2 = elem2.b;
302 const pbes_expression& f2_prime = elem2.f;
303 const pbes_expression& g0_2 = elem2.g0;
304 const pbes_expression& g1_2 = elem2.g1;
305
306 // put the result in (b1, f1_prime, g0, g1)
307 if (is_false(b_1) && is_false(b_2))
308 {
309 b_1 = false_();
310 f1_prime = or_(f1_prime, f2_prime);
311 g0_1 = true_();
312 g1_1 = or_(g1_1, g1_2);
313 }
314 else if (is_true(b_1) && !is_true(b_2))
315 {
316 b_1 = true_();
317 g1_1 = false_();
318 }
319 else if (!is_true(b_1) && is_true(b_2))
320 {
321 b_1 = true_();
322 f1_prime = f2_prime;
323 g0_1 = g0_2;
324 g1_1 = false_();
325 }
326 else if (is_true(b_1) && is_true(b_2))
327 {
328 if (less(f1_prime, f2_prime))
329 {
330 b_1 = true_();
331 g1_1 = false_();
332 }
333 else
334 {
335 b_1 = true_();
336 f1_prime = f2_prime;
337 g0_1 = g0_2;
338 g1_1 = false_();
339 }
340 }
341 else // if (b1 == data::undefined_data_expression() && b2 == data::undefined_data_expression())
342 {
343 b_1 = data::undefined_data_expression();
344 f1_prime = or_(f1_prime, f2_prime);
345 g0_1 = true_();
346 g1_1 = false_();
347 }
348 }
349
350 void enter(const imp& x)
351 {
352 throw mcrl2::runtime_error("Fail to evaluate the expression " + pbes_system::pp(x) + " as the routine Rplus does not expect an implication, which is an internal error.");
353 }
354
355 void leave(const imp& x)
356 {
357 enter(x); // Print an error message, although this should never be reached..
358 }
359
360 void enter(const exists& x)
361 {
362 throw mcrl2::runtime_error("Fail to evaluate the expression " + pbes_system::pp(x) + " as enumeration of this exists is not possible.");
363 }
364
365 void leave(const exists& x)
366 {
367 enter(x); // Print an error message.
368 }
369
370 void enter(const forall& x)
371 {
372 throw mcrl2::runtime_error("Fail to evaluate the expression " + pbes_system::pp(x) + " as enumeration of this forall is not possible.");
373 }
374
375 void leave(const forall& x)
376 {
377 enter(x); // Print an error.
378 }
379 };
380
382 {
383 Rplus_traverser f(S, m_graph_builder);
384 f.apply(x);
385 return Rplus_traverser::stack_element(f.top()); // Protection is added explicitly.
386 }
387
389 {
390 const structure_graph::index_type u = m_graph_builder.find_vertex(init);
391 return S[0].contains(u) || S[1].contains(u);
392 }
393
394 // Returns true if all nodes in the todo list are undefined (i.e. have not been processed yet)
396 {
397 for (const propositional_variable_instantiation& X: todo.elements())
398 {
399 const structure_graph::index_type u = m_graph_builder.find_vertex(X);
400 const structure_graph::vertex& u_ = m_graph_builder.vertex(u);
401 if (u_.is_defined())
402 {
403 return false;
404 }
405 }
406 return true;
407 }
408
411 pbesinst_lazy_todo& todo,
412 std::size_t& calculation_steps)
413 {
414 using utilities::detail::contains;
415 global_current_prune_round++;
416
417 std::size_t old_todo_size = todo.elements().size();
418
420
421 atermpp::deque<pbes_expression> todo1{init};
422 atermpp::indexed_set<pbes_expression> done1;
423 done1.insert(init);
424
425 atermpp::unordered_set<propositional_variable_instantiation> new_todo;
427 while (!todo1.empty())
428 {
429 using utilities::detail::contains;
430
431 X = todo1.front();
432 todo1.pop_front();
433 const structure_graph::index_type u = m_graph_builder.find_vertex(X);
434 const structure_graph::vertex& u_ = m_graph_builder.vertex(u);
435 calculation_steps++;
436 if (u_.decoration == structure_graph::d_none && u_.successors.empty())
437 {
438 assert(is_propositional_variable_instantiation(u_.formula()));
439 new_todo.insert(atermpp::down_cast<propositional_variable_instantiation>(u_.formula()));
440 }
441 else
442 {
443 if (!S[0].contains(u) && !S[1].contains(u))
444 {
445 // todo' := todo' U (succ(u) \ done')
446 for (const structure_graph::index_type& v: G.successors(u))
447 {
448 calculation_steps++;
449 const structure_graph::vertex& v_ = m_graph_builder.vertex(v);
450 const pbes_expression& Y = v_.formula();
451 if (!contains(done1, Y))
452 {
453 todo1.emplace_back(Y);
454 done1.insert(Y);
455 }
456 }
457 }
458 }
459 }
460
461 // new_todo_list := new_todo \cap todo
462 // N.B. An attempt is made to preserve the order of the current todo list, to not
463 // disturb breadth first and depth first search.
464 atermpp::deque<propositional_variable_instantiation> new_todo_list;
465 calculation_steps=calculation_steps+todo.elements().size();
466 for (const propositional_variable_instantiation& X: todo.elements())
467 {
468 if (new_todo.contains(X))
469 {
470 new_todo_list.push_back(X);
471 new_todo.erase(X);
472 }
473 }
474 calculation_steps=calculation_steps+new_todo.size();
475 for(const propositional_variable_instantiation& X: new_todo)
476 {
477 if (m_options.exploration_strategy == breadth_first)
478 {
479 new_todo_list.push_back(X);
480 }
481 else
482 {
483 new_todo_list.push_front(X);
484 }
485 }
486 todo.set_todo(new_todo_list);
488 if (todo.elements().size() == old_todo_size)
489 {
490 mCRL2log(log::verbose) << "Pruning of the todo list had no effect on its size. ";
491 }
492 else if (todo.elements().size() > old_todo_size)
493 {
494 mCRL2log(log::verbose) << "Pruned the todo list. Added " << todo.elements().size() - old_todo_size << " elements. ";
495 }
496 else
497 {
498 mCRL2log(log::verbose) << "Pruned the todo list. Removed " << old_todo_size - todo.elements().size() << " elements. ";
499 }
500 mCRL2log(log::verbose) << "The todo list has size " << todo.elements().size() << ".\n";
501 };
502
503 // Execute a prune_todo_list if m_options.prune_todo_list is set.
506 pbesinst_lazy_todo& todo,
507 std::size_t& calculation_steps)
508 {
510 {
511 prune_todo_list(init, todo, calculation_steps);
512 }
513 }
514
515 // Trigger the prune_todo_list at fixed intervals, provided m_options.prune_todo_list is set,
516 // keeping the workload limited related to other calculations.
517 // Trigger always when the todo set is empty.
520 pbesinst_lazy_todo& todo)
521 {
522 if (m_options.prune_todo_list&&
523 (reset_guard.is_expired() || todo.elements().empty() || m_options.aggressive))
524 {
525 std::size_t calculation_steps=0;
526 prune_todo_list(init, todo, calculation_steps);
527 reset_guard.set_expiration_steps(m_options.prune_and_solve_frequently?calculation_steps:calculation_steps*100);
528 }
529 }
530
531
533 {
535 for (structure_graph::index_type u: S[0].vertices())
536 {
537 if (G.decoration(u) == structure_graph::d_disjunction && tau[0][u] == undefined_vertex())
538 {
539 mCRL2log(log::debug) << "Error: no strategy has been set for disjunctive node " << u << " in S0." << std::endl;
540 mCRL2log(log::debug) << G << std::endl;
541 mCRL2log(log::debug) << "S0 = " << S[0] << std::endl;
542 mCRL2log(log::debug) << "S1 = " << S[1] << std::endl;
543 return false;
544 }
545 }
546 for (structure_graph::index_type u: S[1].vertices())
547 {
548 if (G.decoration(u) == structure_graph::d_conjunction && tau[1][u] == undefined_vertex())
549 {
550 mCRL2log(log::debug) << "Error: no strategy has been set for conjunctive node " << u << " in S1." << std::endl;
551 mCRL2log(log::debug) << G << std::endl;
552 mCRL2log(log::debug) << "S0 = " << S[0] << std::endl;
553 mCRL2log(log::debug) << "S1 = " << S[1] << std::endl;
554 return false;
555 }
556 }
557 return true;
558 }
559
560 public:
562
564 const pbessolve_options& options,
565 const pbes& p,
567 std::optional<data::rewriter> rewriter = std::nullopt
568 )
571 {}
572
573 // Optimization 2 is implemented by overriding the function rewrite_psi.
574 void rewrite_psi(const std::size_t thread_index,
575 pbes_expression& result,
576 const fixpoint_symbol& symbol,
578 const pbes_expression& psi
579 ) override
580 {
581 assert(&result != &psi); // required by super::rewrite_psi
582 super::rewrite_psi(thread_index, result, symbol, X, psi);
583 const Rplus_traverser::stack_element& rplus_result = Rplus(result);
584 b[thread_index] = rplus_result.b;
585 if (is_true(rplus_result.b))
586 {
587 result = rplus_result.g0;
588 return;
589 }
590 else if (is_false(rplus_result.b))
591 {
592 result = rplus_result.g1;
593 return;
594 }
595 result = rplus_result.f;
596 }
597
598 void on_report_equation(const std::size_t thread_index,
600 const pbes_expression& psi, std::size_t k
601 ) override
602 {
603 super::on_report_equation(thread_index, X, psi, k);
604
605 // The structure graph has just been extended, so S[0] and S[1] need to be resized.
606 S[0].resize(m_graph_builder.extent());
607 S[1].resize(m_graph_builder.extent());
608
609 const structure_graph::index_type u = m_graph_builder.find_vertex(X);
610 if (is_true(b[thread_index]))
611 {
612 S[0].insert(u);
613 }
614 else if (is_false(b[thread_index]))
615 {
616 S[1].insert(u);
617 }
618 }
619
621 {
622 mCRL2log(log::verbose) << "Found solution for" << std::setw(12) << S[0].size() + S[1].size() << " BES equations." << std::endl;
623 mCRL2log(log::verbose) << "Finished partial solving (time = " << std::setprecision(2) << std::fixed << timer.seconds() << "s).\n";
624 }
625
626 void on_discovered_elements(const std::set<propositional_variable_instantiation>& elements) override
627 {
628 using utilities::detail::contains;
629 stopwatch timer;
630
632 {
633 if (S_guard[0](S[0].size()))
634 {
636 S[0] = attr_default_with_tau(G, S[0], 0, tau);
637 }
638 if (S_guard[1](S[1].size()))
639 {
641 S[1] = attr_default_with_tau(G, S[1], 1, tau);
642 }
644 }
645 else if (m_options.optimization == partial_solve_strategy::detect_winning_loops_using_fatal_attractor &&
646 (m_options.aggressive || on_the_fly_solve_trigger.is_expired()))
647 {
648 mCRL2log(log::verbose) << "Start partial solving.\n";
649
650 std::size_t calculation_steps=0; // Count how many calculation steps it takes to find loops, and retry this after on_discovered_elements have been called that many times.
652 detail::find_loops2(G, S, tau, calculation_steps, m_iteration_count); // modifies S[0] and S[1]
653 on_the_fly_solve_trigger.set_expiration_steps(m_options.prune_and_solve_frequently?calculation_steps/1000:calculation_steps/10);
656 prune_todo_list_conditional(init, todo, calculation_steps);
657 }
658 else if ((partial_solve_strategy::solve_subgames_using_fatal_attractor_local <= m_options.optimization &&
659 m_options.optimization <= partial_solve_strategy::solve_subgames_using_solver) &&
660 (m_options.aggressive || on_the_fly_solve_trigger.is_expired()))
661 {
662 mCRL2log(log::verbose) << "Start partial solving.\n";
663
664 std::size_t calculation_steps=0; // Count how many calculation steps it takes to find loops, and retry this after on_discovered_elements have been called that many times.
665
668 {
669 detail::fatal_attractors(G, S, tau, calculation_steps, m_iteration_count); // modifies S[0] and S[1]
671 }
673 {
674 detail::fatal_attractors_original(G, S, tau, m_iteration_count); // modifies S[0] and S[1]
676 }
678 {
680 detail::partial_solve(m_graph_builder.m_graph, todo, S, tau, m_iteration_count, m_graph_builder); // modifies S[0] and S[1]
682 }
683 on_the_fly_solve_trigger.set_expiration_steps(m_options.prune_and_solve_frequently?calculation_steps/1000:calculation_steps/10);
685 prune_todo_list_conditional(init, todo, calculation_steps);
686 }
687 else if (m_options.optimization == partial_solve_strategy::detect_winning_loops_original &&
688 (m_options.aggressive || on_the_fly_solve_trigger.is_expired()))
689 {
690 mCRL2log(log::verbose) << "Start partial solving.\n";
691
692 std::size_t calculation_steps=0; // Count how many calculation steps it takes to find loops, and retry this after on_discovered_elements have been called that many times.
693
695 detail::find_loops(G, discovered, todo, S, tau, m_iteration_count, m_graph_builder); // modifies S[0] and S[1]
696 on_the_fly_solve_trigger.set_expiration_steps(m_options.prune_and_solve_frequently?calculation_steps/1000:calculation_steps/10);
698 on_the_fly_solve_trigger.set_expiration_steps(m_options.prune_and_solve_frequently?calculation_steps/1000:calculation_steps/10);
699 prune_todo_list_conditional(init, todo, calculation_steps);
700 }
701
702 prune_todo_list_time_triggered(init, todo);
703 }
704
705 void on_end_while_loop() override
706 {
707 using utilities::detail::contains;
708
710
713
714 std::set<structure_graph::index_type> V = extract_minimal_structure_graph(G, u, S[0], S[1], tau[0], tau[1]);
715
716 std::size_t n = m_graph_builder.extent();
717 vertex_set to_be_removed(n);
718 for (std::size_t v = 0; v < n; v++)
719 {
720 if (!contains(V, v))
721 {
722 to_be_removed.insert(v);
723 }
724 }
726
727 mCRL2log(log::debug) << "\nFinal structure graph " << std::endl;
728 mCRL2log(log::debug) << G << std::endl;
729 }
730};
731
732} // namespace mcrl2::pbes_system
733
734
735
736#endif // MCRL2_PBES_PBESINST_STRUCTURE_GRAPH2_H
Rewriter that operates on data expressions.
Definition rewriter.h:84
\brief The and operator for pbes expressions
periodic_guard(std::size_t initial_regeneration_period)
\brief The existential quantification operator for pbes expressions
\brief The universal quantification operator for pbes expressions
\brief The implication operator for pbes expressions
\brief The or operator for pbes expressions
pbes_expression & operator=(const pbes_expression &) noexcept=default
parameterized boolean equation system
Definition pbes.h:54
const pbessolve_options & m_options
Algorithm options.
propositional_variable_instantiation init
The initial value (after rewriting).
Adds an optimization to pbesinst_structure_graph.
void on_discovered_elements(const std::set< propositional_variable_instantiation > &elements) override
This function is called when new elements are added to discovered.
void prune_todo_list(const propositional_variable_instantiation &init, pbesinst_lazy_todo &todo, std::size_t &calculation_steps)
void rewrite_psi(const std::size_t thread_index, pbes_expression &result, const fixpoint_symbol &symbol, const propositional_variable_instantiation &X, const pbes_expression &psi) override
Rplus_traverser::stack_element Rplus(const pbes_expression &x)
pbesinst_structure_graph_algorithm2(const pbessolve_options &options, const pbes &p, structure_graph &G, std::optional< data::rewriter > rewriter=std::nullopt)
void prune_todo_list_conditional(const propositional_variable_instantiation &init, pbesinst_lazy_todo &todo, std::size_t &calculation_steps)
void prune_todo_list_time_triggered(const propositional_variable_instantiation &init, pbesinst_lazy_todo &todo)
bool solution_found(const propositional_variable_instantiation &init) const override
void on_report_equation(const std::size_t thread_index, const propositional_variable_instantiation &X, const pbes_expression &psi, std::size_t k) override
Reports BES equations that are produced by the algorithm. This function is called for every BES equat...
void on_end_while_loop() override
This function is called right after the while loop is finished.
Variant of pbesinst that will compute a structure graph for a PBES. The result will be put in the str...
\brief A propositional variable instantiation
Implements a simple stopwatch that starts on construction.
Definition stopwatch.h:17
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:393
bool is_false(const data_expression &x)
Test if x is false.
Definition consistency.h:36
bool is_true(const data_expression &x)
Test if x is true.
Definition consistency.h:28
bool is_false(const pbes_expression &t)
Test for the value false.
partial_solve_strategy
Enumeration of partial strategies for solving PBESs.
bool is_true(const pbes_expression &t)
Test for the value true.
index_type find_vertex(const pbes_expression &x) const
reference_aterm_stack_element(const pbes_expression &b_, const pbes_expression &f_, const pbes_expression &g0_, const pbes_expression &g1_)
reference_aterm_stack_element(const E1 &b_, const E2 &f_, const pbes_expression &g0_, const pbes_expression &g1_)
static bool less(const pbes_expression &x1, const pbes_expression &x2)
Rplus_traverser(std::array< vertex_set, 2 > &S_, detail::structure_graph_builder &graph_builder_)