mCRL2
Loading...
Searching...
No Matches
pbesreach.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
10#ifndef MCRL2_PBES_PBESREACH_H
11#define MCRL2_PBES_PBESREACH_H
12
13#include "mcrl2/pbes/symbolic_pbessolve.h"
14#ifdef MCRL2_ENABLE_SYLVAN
15
16#include "mcrl2/utilities/detail/container_utility.h"
17#include "mcrl2/utilities/stopwatch.h"
18#include "mcrl2/utilities/text_utility.h"
19#include "mcrl2/data/merge_data_specifications.h"
20#include "mcrl2/data/rewriter_tool.h"
21#include "mcrl2/data/substitutions/mutable_map_substitution.h"
22#include "mcrl2/data/join.h"
23#include "mcrl2/pbes/detail/instantiate_global_variables.h"
24#include "mcrl2/pbes/detail/pbes_io.h"
25#include "mcrl2/pbes/normalize.h"
26#include "mcrl2/pbes/pbes_summand_group.h"
27#include "mcrl2/pbes/pbes.h"
28#include "mcrl2/pbes/replace_constants_by_variables.h"
29#include "mcrl2/pbes/resolve_name_clashes.h"
30#include "mcrl2/pbes/rewriters/one_point_rule_rewriter.h"
31#include "mcrl2/pbes/srf_pbes.h"
32#include "mcrl2/pbes/unify_parameters.h"
33#include "mcrl2/symbolic/print.h"
34#include "mcrl2/symbolic/symbolic_reachability.h"
35
36namespace mcrl2::pbes_system {
37
38// Returns a data specification containing a structured sort with the names of the propositional variables
39// in the PBES as elements.
40template<bool allow_ce>
41inline
42data::data_specification construct_propositional_variable_data_specification(const pbes_system::detail::pre_srf_pbes<allow_ce>& pbesspec, const std::string& sort_name)
43{
44 // TODO: it should be possible to add a structured sort to pbesspec.data() directly, but I don't know how
45 std::vector<std::string> names;
46 for (const auto& equation: pbesspec.equations())
47 {
48 names.push_back(equation.variable().name());
49 }
50 std::string text = "sort " + sort_name + " = struct " + utilities::string_join(names, " | ") + ";";
51 return data::parse_data_specification(text);
52}
53
54struct symbolic_reachability_options: public symbolic::symbolic_reachability_options
55{
56 bool compute_strategy = false; // compute strategy during solving and/or symbolic reachability
57 bool check_strategy = false; // check strategy after solving
58 bool make_total = false;
59 bool reset_parameters = false;
60 bool aggressive = false;
61 bool naive_counter_example_instantiation = false;
62 std::size_t solve_strategy = 0;
63 std::size_t split_conditions = 0;
64 std::string srf;
65};
66
67inline
68std::ostream& operator<<(std::ostream& out, const symbolic_reachability_options& options)
69{
70 out << static_cast<const symbolic::symbolic_reachability_options&>(options);
71 out << "solve_strategy = " << options.solve_strategy << std::endl;
72 out << "split_conditions = " << options.split_conditions << std::endl;
73 out << "total = " << std::boolalpha << options.make_total << std::endl;
74 return out;
75}
76
77inline
78pbes_system::srf_pbes split_conditions(const pbes_system::srf_pbes& pbes, std::size_t granularity)
79{
80 mCRL2log(log::debug) << "splitting conditions" << std::endl;
81
82 // Find existing identifiers.
83 data::set_identifier_generator id_generator;
84 for (const srf_equation& equation : pbes.equations())
85 {
86 id_generator.add_identifier(equation.variable().name());
87 }
88
89 // Determine the Xtrue equation.
90 pbes_system::propositional_variable Xtrue = pbes.equations()[pbes.equations().size()-2].variable();
91 pbes_system::propositional_variable Xfalse = pbes.equations()[pbes.equations().size()-1].variable();
92
93 pbes_system::srf_pbes result = pbes;
94 std::vector<srf_equation> added_equations; // These equations are added at the end of the pbes.
95 for (srf_equation& equation : result.equations())
96 {
97 std::vector<srf_summand> split_summands; // The updated summands.
98 for (const srf_summand& summand : equation.summands())
99 {
100 mCRL2log(log::debug) << "splitting summand " << summand << std::endl;
101
102 // Heuristics to determine when to split conjunctive conditions.
103 bool should_split = summand.parameters().empty() && granularity > 1; // && find_free_variables(summand.condition()).size() >= 4;
104
105 if (data::sort_bool::is_or_application(summand.condition()))
106 {
107 // For disjunctive conditions we can introduce one summand per clause.
108 for (const data::data_expression& clause : data::split_or(summand.condition()))
109 {
110 split_summands.emplace_back(summand.parameters(), atermpp::down_cast<pbes_expression>(clause), summand.variable());
111 mCRL2log(log::debug) << "Added summand " << split_summands.back() << std::endl;
112 }
113 }
114 else if (should_split && data::sort_bool::is_and_application(summand.condition()))
115 {
116 // The summand is simple if there is only a dependency on true or false.
117 bool simple = granularity == 3 || summand.variable().name() == Xtrue.name() || summand.variable().name() == Xfalse.name();
118
119 std::vector<srf_summand> split_summands_inner; // The summands for the added equation.
120 for (const data::data_expression& clause : data::split_and(summand.condition()))
121 {
122 if (simple)
123 {
124 // For conjunctive equations add !condition => Xfalse, and !condition && Xtrue otherwise.
125 split_summands_inner.emplace_back(data::variable_list(),
126 atermpp::down_cast<pbes_expression>(data::lazy::not_(clause)),
127 !equation.is_conjunctive()
128 ? propositional_variable_instantiation(Xtrue.name(), {}) :
129 propositional_variable_instantiation(Xfalse.name(), {})
130 );
131 }
132 else
133 {
134 // Add a new equation per clause.
135 const propositional_variable& Y = equation.variable();
136 propositional_variable Y1(id_generator(Y.name()), Y.parameters());
137
138 split_summands_inner.emplace_back(data::variable_list(), true_(), propositional_variable_instantiation(Y1.name(), data::make_data_expression_list(Y1.parameters())));
139 std::vector<srf_summand> summands;
140 summands.emplace_back(data::variable_list(), atermpp::down_cast<pbes_expression>(clause), summand.variable());
141 added_equations.emplace_back(equation.symbol(), Y1, summands, !equation.is_conjunctive());
142 mCRL2log(log::debug) << "Added equation " << added_equations.back() << std::endl;
143 }
144 mCRL2log(log::debug) << "Added summand " << split_summands_inner.back() << std::endl;
145 }
146
147 if (simple)
148 {
149 split_summands_inner.emplace_back(data::variable_list(), true_(), summand.variable());
150 }
151
152 if (equation.summands().size() == 1)
153 {
154 // Change the current equation.
155 split_summands = split_summands_inner;
156 equation.is_conjunctive() = !equation.is_conjunctive();
157 mCRL2log(log::debug) << "Changed equation type (conjunctive or disjunctive)" << std::endl;
158 }
159 else
160 {
161 // Add a new equation.
162 const propositional_variable& Y = equation.variable();
163 propositional_variable Y1(id_generator(Y.name()), Y.parameters());
164
165 split_summands.emplace_back(data::variable_list(), true_(), propositional_variable_instantiation(Y1.name(), data::make_data_expression_list(Y1.parameters())));
166 added_equations.emplace_back(equation.symbol(), Y1, split_summands_inner, !equation.is_conjunctive());
167 mCRL2log(log::debug) << "Added equation " << added_equations.back() << std::endl;
168 }
169 }
170 else
171 {
172 // Do nothing.
173 split_summands.emplace_back(summand);
174 }
175 }
176
177 equation.summands() = split_summands;
178 }
179
180 // The last two equations must be Xfalse and Xtrue.
181 result.equations().insert(result.equations().end()-2, added_equations.begin(), added_equations.end());
182
183 return result;
184}
185
186
187/// Applies necessary preprocessing steps to allow the PBES to be solved symbolically.
188inline
189pbes_system::srf_pbes_with_ce preprocess(pbes_system::pbes pbesspec, const symbolic_reachability_options& options)
190{
191 pbes_system::detail::instantiate_global_variables(pbesspec);
192 normalize(pbesspec);
193
194 if (options.one_point_rule_rewrite)
195 {
196 pbes_system::one_point_rule_rewriter R;
197 pbes_system::replace_pbes_expressions(pbesspec, R, false);
198 }
199
200 if (options.replace_constants_by_variables)
201 {
202 data::mutable_indexed_substitution<> sigma;
203 auto rewr = symbolic::construct_rewriter(pbesspec.data(), options.rewrite_strategy, pbes_system::find_function_symbols(pbesspec), options.remove_unused_rewrite_rules);
204 pbes_system::replace_constants_by_variables(pbesspec, rewr, sigma);
205 }
206
207 auto result = pbes2pre_srf(pbesspec, true);
208
209 // Unify the parameters of the original PBES (which has potential counter example information)
210 unify_parameters(result, true, options.reset_parameters);
211
212 pbes_system::resolve_summand_variable_name_clashes(result, result.equations().front().variable().parameters()); // N.B. This is a required preprocessing step.
213
214 return result;
215}
216
217// Store information per lace worker.
218struct per_worker_information
219{
220 data::mutable_indexed_substitution<> m_sigma;
221 data::rewriter m_rewr;
222};
223
224class pbesreach_algorithm
225{
226 using enumerator_element = data::enumerator_list_element_with_substitution<>;
227
228 template <typename Context, bool ActionLabel>
229 friend void symbolic::learn_successors_callback(WorkerP*, Task*, std::uint32_t* v, std::size_t n, void* context);
230
231 protected:
232 using ldd = sylvan::ldds::ldd;
233 const symbolic_reachability_options& m_options;
234 pbes_system::srf_pbes m_pbes;
235 data::rewriter m_rewr;
236 data::mutable_indexed_substitution<> m_sigma;
237 data::enumerator_identifier_generator m_id_generator;
238 data::enumerator_algorithm<> m_enumerator;
239 data::variable_list m_process_parameters;
240 std::size_t m_n;
241 std::unordered_map<core::identifier_string, data::data_expression> m_propvar_map;
242 std::vector<symbolic::data_expression_index> m_data_index;
243 std::vector<pbes_summand_group> m_summand_groups;
244 data::data_expression_list m_initial_state;
245 std::vector<boost::dynamic_bitset<>> m_summand_patterns;
246 std::vector<boost::dynamic_bitset<>> m_group_patterns;
247 std::vector<std::size_t> m_variable_order;
248
249 ldd m_visited;
250 ldd m_todo;
251 ldd m_deadlocks;
252 ldd m_initial_vertex;
253
254 /// \brief Updates R.L := R.L U {(x,y) in R | x in X}
255 void learn_successors(std::size_t i, pbes_summand_group& R, const ldd& X)
256 {
257 mCRL2log(log::trace) << "learn successors of summand group " << i << " for X = " << print_states(m_data_index, X, R.read) << std::endl;
258
259 using namespace sylvan::ldds;
260 std::pair<pbesreach_algorithm&, pbes_summand_group&> context{*this, R};
261 sat_all_nopar(X, symbolic::learn_successors_callback<std::pair<pbesreach_algorithm&, pbes_summand_group&>, false>, &context);
262 }
263
264 /// Applies further preprocessing steps to the SRF pbes.
265 pbes_system::srf_pbes internal_preprocess(pbes_system::srf_pbes srf_pbes, bool make_total)
266 {
267 if (m_options.split_conditions > 0)
268 {
269 srf_pbes = split_conditions(srf_pbes, m_options.split_conditions);
270 }
271
272 if (make_total)
273 {
274 srf_pbes.make_total();
275 }
276
277 if (!has_unified_parameters(srf_pbes.to_pbes()))
278 {
279 throw mcrl2::runtime_error("The PBES after removing counter example information does not have unified parameters");
280 }
281
282 // add a sort for the propositional variable names
283 data::data_specification propvar_dataspec = construct_propositional_variable_data_specification(srf_pbes, "PropositionalVariable");
284 srf_pbes.data() = data::merge_data_specifications(srf_pbes.data(), propvar_dataspec);
285
286 mCRL2log(log::trace) << "--- srf pbes ---\n" << srf_pbes.to_pbes() << std::endl;
287 return srf_pbes;
288 }
289
290 std::string print_size(const sylvan::ldds::ldd& L)
291 {
292 return symbolic::print_size(L, m_options.print_exact, m_options.print_nodesize);
293 }
294
295 public:
296 pbesreach_algorithm(const pbes_system::srf_pbes& srf_pbes, const symbolic_reachability_options& options_)
297 : m_options(options_),
298 m_pbes(internal_preprocess(srf_pbes, options_.make_total)),
299 m_rewr(symbolic::construct_rewriter(m_pbes.data(), m_options.rewrite_strategy, pbes_system::find_function_symbols(m_pbes.to_pbes()), m_options.remove_unused_rewrite_rules)),
300 m_enumerator(m_rewr, m_pbes.data(), m_rewr, m_id_generator, false)
301 {
302 if (!m_options.srf.empty())
303 {
304 detail::save_pbes(m_pbes.to_pbes(), m_options.srf);
305 }
306
307 data::basic_sort propvar_sort("PropositionalVariable"); // todo: choose a unique name
308 for (const auto& equation: m_pbes.equations())
309 {
310 m_propvar_map[equation.variable().name()] = data::function_symbol(equation.variable().name(), propvar_sort);
311 }
312
313 m_process_parameters = m_pbes.equations().front().variable().parameters();
314 m_process_parameters.push_front(data::variable("propvar", propvar_sort)); // todo: choose a unique name
315 m_n = m_process_parameters.size();
316
317 // Rewrite the initial expressions to normal form,
318 std::vector<data::data_expression> initial_values;
319 for (const data::data_expression& expression : make_state(m_pbes.initial_state(), m_propvar_map))
320 {
321 initial_values.push_back(m_rewr(expression));
322 }
323
324 m_initial_state = data::data_expression_list(initial_values.begin(), initial_values.end());
325
326 m_summand_patterns = compute_read_write_patterns(m_pbes, m_process_parameters);
327 mCRL2log(log::debug) << "Original read/write matrix:" << std::endl;
328 mCRL2log(log::debug) << symbolic::print_read_write_patterns(m_summand_patterns);
329
330 symbolic::adjust_read_write_patterns(m_summand_patterns, m_options);
331
332 m_variable_order = symbolic::compute_variable_order(m_options.variable_order, m_process_parameters.size(), m_summand_patterns, true);
333 assert(m_variable_order[0] == 0); // It is required that the propositional variable name stays up front
334 mCRL2log(log::debug) << "variable order = " << core::detail::print_list(m_variable_order) << std::endl;
335 m_summand_patterns = symbolic::reorder_read_write_patterns(m_summand_patterns, m_variable_order);
336
337 m_process_parameters = symbolic::permute_copy(m_process_parameters, m_variable_order);
338 m_initial_state = symbolic::permute_copy(m_initial_state, m_variable_order);
339 mCRL2log(log::debug) << "process parameters = " << core::detail::print_list(m_process_parameters) << std::endl;
340
341 std::vector<std::set<std::size_t>> groups = symbolic::compute_summand_groups(m_options.summand_groups, m_summand_patterns);
342 for (const auto& group: groups)
343 {
344 mCRL2log(log::debug) << "group " << core::detail::print_set(group) << std::endl;
345 }
346 m_group_patterns = symbolic::compute_summand_group_patterns(m_summand_patterns, groups);
347 for (std::size_t j = 0; j < m_group_patterns.size(); j++)
348 {
349 m_summand_groups.emplace_back(m_pbes, m_process_parameters, m_propvar_map, groups[j], m_group_patterns[j], m_summand_patterns, m_variable_order);
350 }
351
352 for (std::size_t i = 0; i < m_summand_groups.size(); i++)
353 {
354 mCRL2log(log::debug) << "=== summand group " << i << " ===\n" << m_summand_groups[i] << std::endl;
355 }
356
357 for (const data::variable& param: m_process_parameters)
358 {
359 m_data_index.emplace_back(param.sort());
360 }
361
362 mCRL2log(log::debug) << "Final read/write matrix:" << std::endl;
363 mCRL2log(log::debug) << symbolic::print_read_write_patterns(m_summand_patterns);
364 }
365
366 virtual ~pbesreach_algorithm() = default;
367
368 ldd initial_state()
369 {
370 return symbolic::state2ldd(m_initial_state, m_data_index);
371 }
372
373 /// \returns The set of deadlock states.
374 ldd deadlocks()
375 {
376 return m_deadlocks;
377 }
378
379 /// \brief Computes relprod(U, group).
380 ldd relprod_impl(const ldd& U, const pbes_summand_group& group, std::size_t i)
381 {
382 if (m_options.no_relprod)
383 {
384 ldd z = symbolic::alternative_relprod(U, group);
385 mCRL2log(log::trace) << "relprod(" << i << ", todo) = " << print_states(m_data_index, z) << std::endl;
386 return z;
387 }
388 else
389 {
390 ldd z = relprod(U, group.L, group.Ir);
391 mCRL2log(log::trace) << "relprod(" << i << ", todo) = " << print_states(m_data_index, z) << std::endl;
392 return z;
393 }
394 }
395
396 /// \brief Perform a single breadth first step.
397 /// \returns The tuple <visited, todo, deadlocks>
398 std::tuple<ldd, ldd, ldd> step(const ldd& visited, const ldd& todo, bool learn_transitions = true, bool detect_deadlocks = false)
399 {
400 using namespace sylvan::ldds;
401 auto& R = m_summand_groups;
402
403 ldd todo1 = empty_set();
404 ldd potential_deadlocks = detect_deadlocks ? todo : empty_set();
405
406 if (!m_options.saturation)
407 {
408 // regular and chaining.
409 todo1 = m_options.chaining ? todo : empty_set();
410
411 for (std::size_t i = 0; i < R.size(); i++)
412 {
413 if (learn_transitions)
414 {
415 ldd proj = project(m_options.chaining ? todo1 : todo, R[i].Ip);
416 learn_successors(i, R[i], m_options.cached ? minus(proj, R[i].Ldomain) : proj);
417
418 mCRL2log(log::trace) << "L =\n" << print_relation(m_data_index, R[i].L, R[i].read, R[i].write) << std::endl;
419 }
420
421 todo1 = union_(todo1, relprod_impl(m_options.chaining ? todo1 : todo, R[i], i));
422
423 if (detect_deadlocks)
424 {
425 potential_deadlocks = minus(potential_deadlocks, relprev(todo1, R[i].L, R[i].Ir, potential_deadlocks));
426 }
427 }
428 }
429 else
430 {
431 // saturation and chaining
432 todo1 = todo;
433 ldd todo1_old; // the old todo set.
434
435 for (std::size_t i = 0; i < R.size(); i++)
436 {
437 if (learn_transitions)
438 {
439 ldd proj = project(todo1, R[i].Ip);
440 learn_successors(i, R[i], m_options.cached ? minus(proj, R[i].Ldomain) : proj);
441
442 mCRL2log(log::trace) << "L =\n" << print_relation(m_data_index, R[i].L, R[i].read, R[i].write) << std::endl;
443 }
444
445 // Apply one transition relation repeatedly.
446 do
447 {
448 todo1_old = todo1;
449 todo1 = union_(todo1, relprod_impl(todo1, R[i], i));
450 }
451 while (todo1 != todo1_old);
452
453 if (detect_deadlocks)
454 {
455 potential_deadlocks = minus(potential_deadlocks, relprev(todo1, R[i].L, R[i].Ir, potential_deadlocks));
456 }
457
458 // Apply all previously learned transition relations repeatedly.
459 if (m_options.chaining)
460 {
461 do
462 {
463 todo1_old = todo1;
464 for (std::size_t j = 0; j <= i; j++)
465 {
466 todo1 = union_(todo1, relprod_impl(todo1, R[j], j));
467 }
468 }
469 while (todo1 != todo1_old);
470 }
471 }
472 }
473
474 // after all transition groups are applied the remaining potential deadlocks are actual deadlocks.
475 return std::make_tuple(union_(visited, todo), minus(todo1, visited), potential_deadlocks);
476 }
477
478 // post: m_visited contains the visited vertices in the parity game.
479 void run(bool report_states = false)
480 {
481 using namespace sylvan::ldds;
482 auto& R = m_summand_groups;
483 std::size_t iteration_count = 0;
484
485 mCRL2log(log::trace) << "initial state = " << core::detail::print_list(m_initial_state) << std::endl;
486
487 stopwatch timer;
488 m_initial_vertex = initial_state();
489 m_visited = empty_set();
490 m_todo = m_initial_vertex;
491 m_deadlocks = empty_set();
492
493 while (m_todo != empty_set() && !solution_found() && (m_options.max_iterations == 0 || iteration_count < m_options.max_iterations))
494 {
495 stopwatch loop_start;
496 iteration_count++;
497 mCRL2log(log::trace) << "--- iteration " << iteration_count << " ---" << std::endl;
498 mCRL2log(log::trace) << "todo = " << print_states(m_data_index, m_todo) << std::endl;
499 ldd deadlocks = empty_set();
500
501 std::tie(m_visited, m_todo, deadlocks) = step(m_visited, m_todo, true, m_options.detect_deadlocks);
502
503 if (m_options.detect_deadlocks)
504 {
505 m_deadlocks = union_(m_deadlocks, deadlocks);
506 }
507
508 mCRL2log(log::verbose) << "generated " << std::setw(12) << print_size(union_(m_visited, m_todo)) << " BES equations after "
509 << std::setw(3) << iteration_count << " iterations (time = " << std::setprecision(2)
510 << std::fixed << loop_start.seconds() << "s)" << std::endl;
511
512 if (m_options.detect_deadlocks)
513 {
514 mCRL2log(log::verbose) << "found " << std::setw(12) << print_size(m_deadlocks) << " deadlocks" << std::endl;
515 }
516
517 on_end_while_loop();
518 sylvan::sylvan_stats_report(stderr);
519 }
520
521 if (report_states)
522 {
523 std::cout << "number of BES equations = " << print_size(m_visited) << " (time = " << std::setprecision(2) << std::fixed << timer.seconds() << "s)" << std::endl;
524 }
525 else
526 {
527 mCRL2log(log::verbose) << "number of BES equations = " << print_size(m_visited) << " (time = " << std::setprecision(2) << std::fixed << timer.seconds() << "s)" << std::endl;
528 }
529
530 mCRL2log(log::verbose) << "used variable order = " << core::detail::print_list(m_variable_order) << std::endl;
531
532 double total_time = 0.0;
533 for (std::size_t i = 0; i < R.size(); i++)
534 {
535 mCRL2log(log::verbose) << "group " << std::setw(4) << i << " contains " << std::setw(7) << print_size(R[i].L) << " transitions (learn time = "
536 << std::setw(5) << std::setprecision(2) << std::fixed << R[i].learn_time << "s with " << std::setw(9) << R[i].learn_calls
537 << " calls, cached " << print_size(R[i].Ldomain) << " values"
538 << std::endl;
539
540 total_time += R[i].learn_time;
541 }
542 mCRL2log(log::verbose) << "learning transitions took " << total_time << "s" << std::endl;
543
544 std::size_t i = 0;
545 for (const auto& param : m_process_parameters)
546 {
547 auto& table = m_data_index[i];
548
549 mCRL2log(log::verbose) << "Parameter " << i << " (" << param << ")" << " has " << table.size() << " values"<< std::endl;
550 for (const auto& data : table)
551 {
552 mCRL2log(log::debug) << table.index(data) << ": " << data << std::endl;
553 }
554
555 ++i;
556 }
557 }
558
559 /// \brief This function is called right after the while loop is finished.
560 virtual void on_end_while_loop()
561 { }
562
563 /// \returns True iff the solution for the initial state is true.
564 virtual bool solution_found() const
565 {
566 return false;
567 }
568
569 /// \returns LDD containing the vertices that were visited during reachability
570 virtual sylvan::ldds::ldd V() const
571 {
572 return m_visited;
573 }
574
575 /// \returns LDD containing the vertices that were seen but not visited upon completion of reachability.
576 /// Note that these are (potentially) incomplete vertices
577 virtual sylvan::ldds::ldd I() const
578 {
579 return m_todo;
580 }
581
582 /// \returns Partial solution that has been computed during reachability
583 virtual symbolic_solution_t partial_solution() const
584 {
585 return symbolic_solution_t(m_options.compute_strategy);
586 }
587
588 std::vector<symbolic::summand_group> summand_groups() const
589 {
590 std::vector<symbolic::summand_group> result;
591
592 for (const auto& group : m_summand_groups)
593 {
594 result.push_back(group);
595 }
596
597 return result;
598 }
599
600 const srf_pbes& pbes() const
601 {
602 return m_pbes;
603 }
604
605 data::rewriter rewriter() const
606 {
607 return m_rewr;
608 }
609
610 const data::variable_list& process_parameters() const
611 {
612 return m_process_parameters;
613 }
614
615 const std::unordered_map<core::identifier_string, data::data_expression>& propvar_map() const
616 {
617 return m_propvar_map;
618 }
619
620 const std::vector<symbolic::data_expression_index>& data_index() const
621 {
622 return m_data_index;
623 }
624
625 std::vector<symbolic::data_expression_index>& data_index()
626 {
627 return m_data_index;
628 }
629
630 const std::vector<boost::dynamic_bitset<>>& read_write_patterns() const
631 {
632 return m_summand_patterns;
633 }
634
635 const std::vector<boost::dynamic_bitset<>>& read_write_group_patterns() const
636 {
637 return m_group_patterns;
638 }
639};
640
641
642
643} // namespace mcrl2::pbes_system
644
645#endif // MCRL2_ENABLE_SYLVAN
646
647#endif // MCRL2_PBES_PBESREACH_H