12#ifndef MCRL2_PBES_PBESINST_STRUCTURE_GRAPH2_H
13#define MCRL2_PBES_PBESINST_STRUCTURE_GRAPH2_H
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"
43 bool result = count >= m_count;
44 while (m_count <= count)
69 if (m_count >= m_regeneration_period)
79 m_regeneration_period = p;
129 template<
class E1,
class E2>
142 void mark(atermpp::term_mark_stack& todo)
const
160 :
b(s.b),
f(s.f),
g0(s.g0),
g1(s.g1)
175 stack.push_back(elem);
206 stack.emplace_back(x, x, true_(), false_());
210 throw mcrl2::runtime_error(
"Fail to evaluate the expression " + data::pp(x) +
" as it should be equal to true or false.");
217 if (u == undefined_vertex())
220 stack.emplace_back(data::undefined_data_expression(), x, true_(), false_());
222 else if (S[0].contains(u))
224 stack.emplace_back(true_(), x, x, false_());
226 else if (S[1].contains(u))
228 stack.emplace_back(false_(), x, true_(), x);
232 stack.emplace_back(data::undefined_data_expression(), x, true_(), false_());
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;
250 if (is_true(b_1) && is_true(b_2))
253 f1_prime = and_(f1_prime, f2_prime);
254 g0_1 = and_(g0_1, g0_2);
257 else if (is_false(b_1) && !is_false(b_2))
262 else if (!is_false(b_1) && is_false(b_2))
269 else if (is_false(b_1) && is_false(b_2))
271 if (less(f1_prime, f2_prime))
286 b_1 = data::undefined_data_expression();
287 f1_prime = and_(f1_prime, f2_prime);
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;
307 if (is_false(b_1) && is_false(b_2))
310 f1_prime = or_(f1_prime, f2_prime);
312 g1_1 = or_(g1_1, g1_2);
314 else if (is_true(b_1) && !is_true(b_2))
319 else if (!is_true(b_1) && is_true(b_2))
326 else if (is_true(b_1) && is_true(b_2))
328 if (less(f1_prime, f2_prime))
343 b_1 = data::undefined_data_expression();
344 f1_prime = or_(f1_prime, f2_prime);
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.");
362 throw mcrl2::runtime_error(
"Fail to evaluate the expression " + pbes_system::pp(x) +
" as enumeration of this exists is not possible.");
372 throw mcrl2::runtime_error(
"Fail to evaluate the expression " + pbes_system::pp(x) +
" as enumeration of this forall is not possible.");
391 return S[0].contains(u) || S[1].contains(u);
397 for (
const propositional_variable_instantiation& X: todo.elements())
399 const structure_graph::index_type u = m_graph_builder.find_vertex(X);
400 const structure_graph::vertex& u_ = m_graph_builder.vertex(u);
412 std::size_t& calculation_steps)
415 global_current_prune_round++;
417 std::size_t old_todo_size = todo.elements().size();
421 atermpp::deque<pbes_expression> todo1{init};
422 atermpp::indexed_set<pbes_expression> done1;
425 atermpp::unordered_set<propositional_variable_instantiation> new_todo;
427 while (!todo1.empty())
429 using utilities::detail::contains;
433 const structure_graph::index_type u = m_graph_builder.find_vertex(X);
434 const structure_graph::vertex& u_ = m_graph_builder.vertex(u);
436 if (u_.decoration == structure_graph::d_none && u_.successors.empty())
438 assert(is_propositional_variable_instantiation(u_.formula()));
439 new_todo.insert(atermpp::down_cast<propositional_variable_instantiation>(u_.formula()));
443 if (!S[0].contains(u) && !S[1].contains(u))
446 for (
const structure_graph::index_type& v: G.successors(u))
449 const structure_graph::vertex& v_ = m_graph_builder.vertex(v);
450 const pbes_expression& Y = v_.formula();
451 if (!contains(done1, Y))
453 todo1.emplace_back(Y);
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())
468 if (new_todo.contains(X))
470 new_todo_list.push_back(X);
474 calculation_steps=calculation_steps+new_todo.size();
475 for(
const propositional_variable_instantiation& X: new_todo)
477 if (m_options.exploration_strategy == breadth_first)
479 new_todo_list.push_back(X);
483 new_todo_list.push_front(X);
486 todo.set_todo(new_todo_list);
488 if (todo.elements().size() == old_todo_size)
490 mCRL2log(log::verbose) <<
"Pruning of the todo list had no effect on its size. ";
492 else if (todo.elements().size() > old_todo_size)
494 mCRL2log(log::verbose) <<
"Pruned the todo list. Added " << todo.elements().size() - old_todo_size <<
" elements. ";
498 mCRL2log(log::verbose) <<
"Pruned the todo list. Removed " << old_todo_size - todo.elements().size() <<
" elements. ";
500 mCRL2log(log::verbose) <<
"The todo list has size " << todo.elements().size() <<
".\n";
507 std::size_t& calculation_steps)
511 prune_todo_list(init, todo, calculation_steps);
522 if (m_options.prune_todo_list&&
523 (reset_guard.is_expired() || todo.elements().empty() || m_options.aggressive))
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);
535 for (structure_graph::index_type u: S[0].vertices())
537 if (G.decoration(u) == structure_graph::d_disjunction && tau[0][u] == undefined_vertex())
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;
546 for (structure_graph::index_type u: S[1].vertices())
548 if (G.decoration(u) == structure_graph::d_conjunction && tau[1][u] == undefined_vertex())
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;
581 assert(&result != &psi);
582 super::rewrite_psi(thread_index, result, symbol, X, psi);
584 b[thread_index] = rplus_result.b;
587 result
= rplus_result
.g0;
592 result
= rplus_result
.g1;
595 result
= rplus_result
.f;
603 super::on_report_equation(thread_index, X, psi, k);
606 S[0].resize(m_graph_builder.extent());
607 S[1].resize(m_graph_builder.extent());
610 if (is_true(b[thread_index]))
614 else if (is_false(b[thread_index]))
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";
633 if (S_guard[0](S[0].size()))
636 S[0] = attr_default_with_tau(G, S[0], 0, tau);
638 if (S_guard[1](S[1].size()))
641 S[1] = attr_default_with_tau(G, S[1], 1, tau);
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()))
648 mCRL2log(log::verbose) <<
"Start partial solving.\n";
650 std::size_t calculation_steps=0;
652 detail::find_loops2(G, S, tau, calculation_steps, m_iteration_count);
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);
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()))
662 mCRL2log(log::verbose) <<
"Start partial solving.\n";
664 std::size_t calculation_steps=0;
669 detail::fatal_attractors(G, S, tau, calculation_steps, m_iteration_count);
674 detail::fatal_attractors_original(G, S, tau, m_iteration_count);
680 detail::partial_solve(m_graph_builder.m_graph, todo, S, tau, m_iteration_count, m_graph_builder);
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);
687 else if (m_options.optimization == partial_solve_strategy::detect_winning_loops_original &&
688 (m_options.aggressive || on_the_fly_solve_trigger.is_expired()))
690 mCRL2log(log::verbose) <<
"Start partial solving.\n";
692 std::size_t calculation_steps=0;
695 detail::find_loops(G, discovered, todo, S, tau, m_iteration_count, m_graph_builder);
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);
702 prune_todo_list_time_triggered(init, todo);
714 std::set<structure_graph::index_type> V = extract_minimal_structure_graph(G, u, S[0], S[1], tau[0], tau[1]);
716 std::size_t n = m_graph_builder.extent();
718 for (std::size_t v = 0; v < n; v++)
722 to_be_removed.insert(v);
727 mCRL2log(log::debug) <<
"\nFinal structure graph " << std::endl;
728 mCRL2log(log::debug) << G << std::endl;
Rewriter that operates on data expressions.
\brief The and operator for pbes expressions
computation_guard(std::size_t initial_count=64)
bool operator()(std::size_t count)
periodic_guard(std::size_t initial_regeneration_period)
void set_expiration_steps(const std::size_t p)
std::size_t m_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
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)
detail::periodic_guard on_the_fly_solve_trigger
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)
bool todo_has_only_undefined_nodes() const
pbesinst_structure_graph_algorithm2(const pbessolve_options &options, const pbes &p, structure_graph &G, std::optional< data::rewriter > rewriter=std::nullopt)
std::array< strategy_vector, 2 > tau
atermpp::vector< pbes_expression > b
std::array< vertex_set, 2 > S
void prune_todo_list_conditional(const propositional_variable_instantiation &init, pbesinst_lazy_todo &todo, std::size_t &calculation_steps)
detail::periodic_guard reset_guard
bool strategies_are_set_in_solved_nodes() const
void prune_todo_list_time_triggered(const propositional_variable_instantiation &init, pbesinst_lazy_todo &todo)
pbes_expression expr(const T &x) const
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 report_found_solutions(stopwatch &timer)
void on_end_while_loop() override
This function is called right after the while loop is finished.
std::array< detail::computation_guard, 2 > S_guard
Variant of pbesinst that will compute a structure graph for a PBES. The result will be put in the str...
detail::structure_graph_builder m_graph_builder
\brief A propositional variable instantiation
Implements a simple stopwatch that starts on construction.
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
bool is_false(const data_expression &x)
Test if x is false.
bool is_true(const data_expression &x)
Test if x is true.
bool is_false(const pbes_expression &t)
Test for the value false.
partial_solve_strategy
Enumeration of partial strategies for solving PBESs.
@ propagate_solved_equations_using_attractor
@ solve_subgames_using_solver
@ solve_subgames_using_fatal_attractor_original
@ solve_subgames_using_fatal_attractor_local
bool is_true(const pbes_expression &t)
Test for the value true.
void erase_vertices(const vertex_set &U)
index_type find_vertex(const pbes_expression &x) const
atermpp::detail::reference_aterm< pbes_expression > g1
atermpp::detail::reference_aterm< pbes_expression > f
reference_aterm_stack_element(const pbes_expression &b_, const pbes_expression &f_, const pbes_expression &g0_, const pbes_expression &g1_)
atermpp::detail::reference_aterm< pbes_expression > b
atermpp::detail::reference_aterm< pbes_expression > g0
void mark(atermpp::term_mark_stack &todo) const
reference_aterm_stack_element(const E1 &b_, const E2 &f_, const pbes_expression &g0_, const pbes_expression &g1_)
stack_element(const reference_aterm_stack_element &s)
reference_aterm_stack_element & top()
void enter(const forall &x)
void leave(const exists &x)
detail::structure_graph_builder & graph_builder
const reference_aterm_stack_element & top() const
atermpp::vector< reference_aterm_stack_element > stack
void leave(const data::data_expression &x)
std::array< vertex_set, 2 > & S
void enter(const exists &x)
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_)
void leave(const forall &x)
void leave(const propositional_variable_instantiation &x)
void push(const reference_aterm_stack_element &elem)
partial_solve_strategy optimization