12#ifndef MCRL2_PBES_SOLVE_STRUCTURE_GRAPH_H
13#define MCRL2_PBES_SOLVE_STRUCTURE_GRAPH_H
15#include "mcrl2/atermpp/standard_containers/vector.h"
16#include "mcrl2/data/join.h"
17#include "mcrl2/lts/lts_algorithm.h"
18#include "mcrl2/pbes/pbes_equation_index.h"
19#include "mcrl2/pbes/pbessolve_attractors.h"
20#include "mcrl2/pbes/detail/pbes_remove_counterexample_info.h"
27 std::size_t min_rank = (std::numeric_limits<std::size_t>::max)();
28 std::size_t max_rank = 0;
29 std::vector<structure_graph::index_type> M;
30 std::size_t N = G.all_vertices().size();
32 for (std::size_t vi = 0; vi < N; vi++)
38 const auto& v = G.find_vertex(vi);
39 if (v.rank <= min_rank)
41 if (v.rank < min_rank)
48 if (v.rank > max_rank)
53 return std::make_tuple(min_rank, max_rank, vertex_set(N, M.begin(), M.end()));
67 for (structure_graph::index_type v: G.successors(u))
71 return undefined_vertex();
78 auto result = undefined_vertex();
79 for (structure_graph::index_type v: G.successors(u))
95 auto exclude = G.exclude() | A.include();
96 std::swap(G.exclude(), exclude);
98 std::swap(G.exclude(), exclude);
110 mCRL2log(log::debug) <<
"\n --- solve_recursive input ---\n" << G << std::endl;
111 std::size_t N = G.extent();
115 return { vertex_set(N), vertex_set(N) };
118 auto q = get_minmax_rank(G);
119 std::size_t m = std::get<0>(q);
122 std::size_t alpha = m % 2;
125 for (structure_graph::index_type ui: U.vertices())
127 const auto& u = G.find_vertex(ui);
128 if (u.decoration == alpha)
131 auto v = succ(G, ui, U);
132 if (v != undefined_vertex())
134 global_strategy<structure_graph>(G).set_strategy(ui, v);
139 vertex_set W[2] = { vertex_set(N), vertex_set(N) };
143 std::tie(W_1[0], W_1[1]) = solve_recursive(G, A);
149 vertex_set B = attr_default(G, W_1[1 - alpha], 1 - alpha);
150 if (W_1[1 - alpha].size() == B.size())
152 W[alpha] = set_union(A, W_1[alpha]);
157 std::tie(W[0], W[1]) = solve_recursive(G, B);
158 W[1 - alpha] = set_union(W[1 - alpha], B);
164 if (W_1[1 - alpha].is_empty())
166 W[alpha] = set_union(A, W_1[alpha]);
167 W[1 - alpha].clear();
171 vertex_set B = attr_default(G, W_1[1 - alpha], 1 - alpha);
172 std::tie(W[0], W[1]) = solve_recursive(G, B);
173 W[1 - alpha] = set_union(W[1 - alpha], B);
177 mCRL2log(log::debug) <<
"\n --- solution for solve_recursive input ---\n" << G;
178 mCRL2log(log::debug) <<
" W0 = " << W[0] << std::endl;
179 mCRL2log(log::debug) <<
" W1 = " << W[1] << std::endl;
180 assert(W[0].size() + W[1].size() + G.exclude().count() == N);
181 return { W[0], W[1] };
188 mCRL2log(log::debug) <<
"\n --- solve_recursive_extended input ---\n" << G << std::endl;
190 std::size_t N = G.extent();
195 for (std::size_t vi = 0; vi < N; vi++)
201 const auto& v = G.find_vertex(vi);
202 if (v.decoration == structure_graph::d_false)
206 else if (v.decoration == structure_graph::d_true)
215 Vconj = attr_default(G, Vconj, 1);
219 Vdisj = attr_default(G, Vdisj, 0);
225 return solve_recursive(G);
232 std::tie(Wdisj, Wconj) = solve_recursive(G, Vunion);
233 return std::make_pair(set_union(Wdisj, Vdisj), set_union(Wconj, Vconj));
242 if (!contains(u.successors, vi))
244 u.successors.push_back(vi);
245 v.predecessors.push_back(ui);
253 mCRL2log(log::debug) <<
"\n--- CHECK STRATEGY ---" << std::endl;
254 log_vertex_set(G, Wconj,
"Wconj");
255 log_vertex_set(G, Wdisj,
"Wdisj");
261 structure_graph::vertex_vector V = G.all_vertices();
264 v.successors.clear();
265 v.predecessors.clear();
268 std::set<structure_graph::index_type> todo = { init };
269 std::set<structure_graph::index_type> done;
271 while (!todo.empty())
273 structure_graph::index_type u = *todo.begin();
274 todo.erase(todo.begin());
276 if ((is_disjunctive && G.decoration(u) == structure_graph::d_disjunction) || (!is_disjunctive && G.decoration(u) == structure_graph::d_conjunction))
279 structure_graph::index_type v = G.strategy(u);
280 insert_edge(V, u, v);
281 if (v != undefined_vertex() && !contains(done, v))
289 for (structure_graph::index_type v: G.successors(u))
291 insert_edge(V, u, v);
292 if (!contains(done, v))
304 std::tie(Wdisj1, Wconj1) = solve_recursive_extended(Gcopy);
305 bool is_disjunctive1;
308 is_disjunctive1 =
true;
312 is_disjunctive1 =
false;
316 throw mcrl2::runtime_error(
"No solution found!!!");
318 if (is_disjunctive != is_disjunctive1)
320 log_vertex_set(Gcopy, Wconj1,
"Wconj1");
321 log_vertex_set(Gcopy, Wdisj1,
"Wdisj1");
322 throw mcrl2::runtime_error(
"check_solve_recursive_solution failed!");
339 if (W.first.contains(G.initial_vertex()))
341 is_disjunctive =
true;
345 is_disjunctive =
false;
348 return is_disjunctive;
355 mCRL2log(log::verbose) <<
"Solving parity game..." << std::endl;
356 mCRL2log(log::debug) << G << std::endl;
357 assert(G.extent() > 0);
359 auto W = solve_recursive_extended(G);
361 if (W.first.contains(G.initial_vertex()))
363 is_disjunctive =
true;
365 else if (W.second.contains(G.initial_vertex()))
367 is_disjunctive =
false;
371 throw mcrl2::runtime_error(
"No solution found!!!");
376 check_solve_recursive_solution(G, is_disjunctive, W.first, W.second);
379 mCRL2log(log::debug) <<
"\nSolved structure graph " << std::endl;
380 mCRL2log(log::debug) << G << std::endl;
392 result.process().action_summands().clear();
393 result.process().deadlock_summands().clear();
394 auto& action_summands = result.process().action_summands();
395 std::regex re(
"Z(neg|pos)_(\\d+)_.*");
396 std::size_t n = lpsspec.process().process_parameters().size();
398 for (structure_graph::index_type vi: V)
400 const auto& v = G.find_vertex(vi);
401 if (is_propositional_variable_instantiation(v.formula()))
405 const auto Z = atermpp::down_cast<propositional_variable_instantiation>(v.formula());
406 std::string Zname = Z.name();
408 if (std::regex_match(Zname, match, re))
410 std::size_t summand_index = std::stoul(match[2]);
411 if (summand_index >= lpsspec.process().action_summands().size())
413 throw mcrl2::runtime_error(
"Counter-example cannot be reconstructed from this LPS. Did you supply the correct file?");
417 lps::action_summand summand = lpsspec.process().action_summands().at(summand_index);
418 std::size_t equation_index = p_index.index(Z.name());
419 const pbes_equation& eqn = p.equations().at(equation_index);
420 const data::variable_list& d = eqn.variable().parameters();
421 data::variable_vector d1(d.begin(), d.end());
423 const data::data_expression_list& e = Z.parameters();
424 data::data_expression_vector e1(e.begin(), e.end());
426 data::data_expression_vector condition;
427 data::assignment_vector next_state_assignments;
428 std::size_t m = d.size() - 2 * n;
430 for (std::size_t i = 0; i < n; i++)
432 condition.push_back(data::equal_to(d1.at(i), e1.at(i)));
433 next_state_assignments.emplace_back(d1.at(i), e1.at(n + m + i));
436 process::action_vector actions;
437 std::size_t index = 0;
438 for (
const process::action& a: summand.multi_action().actions())
440 if (index > e1.size() || index + a.arguments().size() > e1.size())
442 throw mcrl2::runtime_error(
"Invalid parameter index");
445 process::action a1(a.label(), data::data_expression_list(e1.begin() +
static_cast<std::ptrdiff_t>(n + index), e1.begin() +
static_cast<std::ptrdiff_t>(n + index + a.arguments().size())));
446 actions.push_back(a1);
447 index = index + a.arguments().size();
450 summand.summation_variables() = data::variable_list();
451 summand.condition() = data::join_and(condition.begin(), condition.end());
452 summand.multi_action() = lps::multi_action(process::action_list(actions.begin(), actions.end()),summand.multi_action().time());
453 summand.assignments() = data::assignment_list(next_state_assignments.begin(), next_state_assignments.end());
455 action_summands.push_back(summand);
462 throw mcrl2::runtime_error(
"The counter example LPS is not well typed, either wrong file provided or an internal error occurred.");
467 catch (
const std::exception& e)
469 throw mcrl2::runtime_error(std::string(
"Counter-example cannot be reconstructed, either wrong file provided or an internal error occurred. ") + e.what());
484 if (!lpsspec.global_variables().empty())
486 throw mcrl2::runtime_error(
"solve_with_counter_example requires an LPS without global variables.");
488 if (!p.global_variables().empty())
490 throw mcrl2::runtime_error(
"solve_with_counter_example requires a PBES without global variables.");
493 mCRL2log(log::verbose) <<
"Solving parity game..." << std::endl;
496 std::tie(Wdisj, Wconj) = solve_recursive_extended(G);
499 mCRL2log(log::verbose) <<
"Extracting evidence..." << std::endl;
500 std::set<structure_graph::index_type> W = extract_minimal_structure_graph(G, init, Wdisj, Wconj);
501 return { Wdisj.contains(init), create_counter_example_lps(G, W, lpsspec, p, p_index) };
514 const auto& lts_transitions = ltsspec.get_transitions();
515 std::vector<lts::transition> transitions;
516 for (std::size_t i: transition_indices)
518 if (i >= lts_transitions.size())
520 throw mcrl2::runtime_error(
"Counter-example cannot be reconstructed from this LTS. Did you supply the correct file?");
522 transitions.push_back(lts_transitions.at(i));
524 ltsspec.get_transitions() = transitions;
527 lts::reachability_check(ltsspec,
true);
534 std::regex re(
"Z(neg|pos)_(\\d+)_.*");
538 std::set<std::size_t> transition_indices;
539 for (structure_graph::index_type vi: V)
541 const auto& v = G.find_vertex(vi);
542 if (is_propositional_variable_instantiation(v.formula()))
544 const propositional_variable_instantiation& Z = atermpp::down_cast<propositional_variable_instantiation>(v.formula());
545 std::string Zname = Z.name();
547 if (std::regex_match(Zname, match, re))
549 std::size_t transition_index = std::stoul(match[2]);
550 transition_indices.insert(transition_index);
554 filter_transitions(ltsspec, transition_indices);
556 catch (
const std::exception& e)
558 throw mcrl2::runtime_error(std::string(
"Counter-example cannot be reconstructed, either wrong file provided or an internal error occurred. ") + e.what());
571 mCRL2log(log::verbose) <<
"Solving parity game..." << std::endl;
574 std::tie(Wdisj, Wconj) = solve_recursive_extended(G);
577 mCRL2log(log::verbose) <<
"Extracting evidence..." << std::endl;
578 std::set<structure_graph::index_type> W = extract_minimal_structure_graph(G, init, Wdisj, Wconj);
579 create_counter_example_lts(G, W, ltsspec);
587 bool use_toms_optimization = !check_strategy;
627 return algorithm.solve_with_counter_example(G, lpsspec, p, p_index);
Linear process specification.
This class contains labelled transition systems in .lts format.
std::pair< bool, lps::specification > solve_with_counter_example(structure_graph &G, const lps::specification &lpsspec, const pbes &p, const pbes_equation_index &p_index)
Solve a pbes for some equation, while constructing a counter example or wittness based on the accompa...
lps_solve_structure_graph_algorithm()=default
static lps::specification create_counter_example_lps(structure_graph &G, const std::set< structure_graph::index_type > &V, const lps::specification &lpsspec, const pbes &p, const pbes_equation_index &p_index)
static void filter_transitions(lts::lts_lts_t <sspec, const std::set< std::size_t > &transition_indices)
lts_solve_structure_graph_algorithm()=default
bool solve_with_counter_example(structure_graph &G, lts::lts_lts_t <sspec)
Solve a boolean equation system while generating a counter example.
static void create_counter_example_lts(structure_graph &G, const std::set< structure_graph::index_type > &V, lts::lts_lts_t <sspec)
parameterized boolean equation system
bool use_toms_optimization
std::pair< vertex_set, vertex_set > solve_recursive(structure_graph &G, const vertex_set &A)
static void insert_edge(structure_graph::vertex_vector &V, structure_graph::index_type ui, structure_graph::index_type vi)
solve_structure_graph_algorithm(bool check_strategy_=false, bool use_toms_optimization_=false)
static structure_graph::index_type succ(const structure_graph &G, structure_graph::index_type u)
void check_solve_recursive_solution(const structure_graph &G, bool is_disjunctive, const vertex_set &Wdisj, const vertex_set &Wconj)
bool solve(structure_graph &G)
Returns the winning player (alpha)
std::pair< vertex_set, vertex_set > solve_recursive(structure_graph &G)
static structure_graph::index_type succ(const structure_graph &G, structure_graph::index_type u, const vertex_set &U)
std::pair< vertex_set, vertex_set > solve_partitions(structure_graph &G)
Returns the winning partition.
std::pair< vertex_set, vertex_set > solve_recursive_extended(structure_graph &G)
index_type initial_vertex() const
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
The main namespace for the LPS library.
bool check_well_typedness(const specification &x)
bool solve_structure_graph(structure_graph &G, bool check_strategy=false)
vertex_set set_union(const vertex_set &V, const vertex_set &W)
std::pair< bool, lps::specification > solve_structure_graph_with_counter_example(structure_graph &G, const lps::specification &lpsspec, const pbes &p, const pbes_equation_index &p_index)
std::tuple< std::size_t, std::size_t, vertex_set > get_minmax_rank(const structure_graph &G)
bool solve_structure_graph_with_counter_example(structure_graph &G, lts::lts_lts_t <sspec)
Solve this pbes_system using a structure graph generating a counter example.
bool contains(structure_graph::index_type u) const