mCRL2
Loading...
Searching...
No Matches
explorer.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/lps/explorer.h
10/// \brief Generic state space explorer for (stochastic) linear process specifications.
11
12#ifndef MCRL2_LPS_EXPLORER_H
13#define MCRL2_LPS_EXPLORER_H
14
15#include <optional>
16#include <random>
17#include <thread>
18#include <type_traits>
19#include <condition_variable>
20#include "mcrl2/utilities/detail/io.h"
21#include "mcrl2/utilities/skip.h"
22#include "mcrl2/atermpp/standard_containers/vector.h"
23#include "mcrl2/atermpp/standard_containers/indexed_set.h"
24#include "mcrl2/atermpp/standard_containers/detail/unordered_map_implementation.h"
25#include "mcrl2/data/consistency.h"
26#include "mcrl2/data/enumerator.h"
27#include "mcrl2/data/find_quantifier_variables.h"
28#include "mcrl2/data/detail/enumerator_iteration_limit.h"
29#include "mcrl2/data/substitution_utility.h"
30#include "mcrl2/lps/detail/instantiate_global_variables.h"
31#include "mcrl2/lps/explorer_options.h"
32#include "mcrl2/lps/explorer_todo_set.h"
33#include "mcrl2/lps/explorer_utilities.h"
34#include "mcrl2/lps/find_representative.h"
35#include "mcrl2/lps/one_point_rule_rewrite.h"
36#include "mcrl2/lps/order_summand_variables.h"
37#include "mcrl2/lps/replace_constants_by_variables.h"
38#include "mcrl2/lps/resolve_name_clashes.h"
39#include "mcrl2/lps/stochastic_state.h"
40#include "mcrl2/lps/explorer_projections.h"
41
42#ifdef MCRL2_USE_CONTROL_FLOW
43#include <boost/container/small_vector.hpp>
44#include "mcrl2/lps/explorer_control_flow.h"
45#endif
46
47namespace mcrl2::lps {
48
49template <bool Stochastic, bool Timed, typename Specification>
50class explorer: public abortable
51{
52 public:
55 static constexpr bool is_stochastic = Stochastic;
56 static constexpr bool is_timed = Timed;
57
59
61 {
64
65 transition(lps::multi_action action_, const state_type& state_)
67 {}
68 };
69
70 protected:
72 const explorer_options m_options; // must not be a reference.
73
74 // The four data structures that must be separate per thread.
79
80 Specification m_global_lpsspec;
81 // Mutexes
83 // Mutex locked if a process finds the global buffer empty, and unlocked if it is (attempted to be) refilled
85 std::condition_variable m_signal_global_todo_buffer_filled;
86
88 std::size_t m_n; // m_n = m_process_parameters.size()
89 data::data_expression_list m_initial_state;
91 bool m_recursive = false;
94
95 volatile std::atomic<bool> m_must_abort = false;
96
97 // N.B. The keys are stored in term_appl instead of data_expression_list for performance reasons.
99
101
102 // used by make_timed_state, to avoid needless creation of vectors
104
105#ifdef MCRL2_USE_CONTROL_FLOW
107
108 // Only initialised when control flow reduction is enabled at runtime, i.e. when m_options.use_control_flow
109 // holds and at least one control flow graph was computed. Empty otherwise, in which case no control flow
110 // information is computed or inspected during exploration.
112
113 /// \brief Computes the active control flow graph vertices for the state stored in sigma, if control flow
114 /// reduction is enabled, and returns an empty optional otherwise.
117 {
119 {
120 return std::nullopt;
121 }
123 }
124#endif
125
126 Specification preprocess(const Specification& lpsspec)
127 {
128 Specification result = lpsspec;
129 detail::instantiate_global_variables(result);
130 lps::order_summand_variables(result);
131 resolve_summand_variable_name_clashes(result); // N.B. This is a required preprocessing step.
132 if (m_options.one_point_rule_rewrite)
133 {
134 one_point_rule_rewrite(result);
135 }
136 if (m_options.replace_constants_by_variables)
137 {
138 replace_constants_by_variables(result, m_global_rewr, m_global_sigma);
139 }
140 return result;
141 }
142
143 // Evaluates whether t0 <= t1
145 const data::data_expression& t1,
146 data::mutable_indexed_substitution<>& sigma,
147 data::rewriter& rewr) const
148 {
149 return rewr(data::less_equal(t0, t1),sigma) == data::sort_bool::true_();
150 }
151
152 // Find a unique representative in the confluent tau-graph reachable from u0.
153 template <typename SummandSequence>
154 state find_representative(state& u0,
155 const SummandSequence& summands,
156 data::mutable_indexed_substitution<>& sigma,
157 data::rewriter& rewr,
158 data::enumerator_algorithm<>& enumerator,
160 {
161 bool recursive_undo = m_recursive;
162 m_recursive = true;
163 data::data_expression_list process_parameter_undo = process_parameter_values(sigma);
164 state result = lps::find_representative(u0,
165 [&](const state& u)
166 { return generate_successors(u, summands, sigma, rewr, enumerator, id_generator); });
167 set_process_parameter_values(process_parameter_undo, sigma);
168 m_recursive = recursive_undo;
169 return result;
170 }
171
172 template <typename DataExpressionSequence>
173 void compute_state(state& result,
174 const DataExpressionSequence& v,
175 data::mutable_indexed_substitution<>& sigma,
176 const data::rewriter& rewr) const
177 {
178 lps::make_state(result,
179 v.begin(),
180 m_n,
181 [&](data::data_expression& result, const data::data_expression& x) { rewr(result, x, sigma); return; });
182 }
183
184 template <typename DataExpressionSequence>
186 const stochastic_distribution& distribution,
187 const DataExpressionSequence& next_state,
188 data::mutable_indexed_substitution<>& sigma,
189 const data::rewriter& rewr,
190 const data::enumerator_algorithm<>& enumerator) const
191 {
192 result.clear();
193 if (distribution.is_defined())
194 {
195 enumerator.enumerate<enumerator_element>(
196 distribution.variables(),
197 distribution.distribution(),
198 sigma,
199 [&](const enumerator_element& p)
200 {
201 p.add_assignments(distribution.variables(), sigma, rewr);
202 result.probabilities.push_back(p.expression());
203 result.states.emplace_back();
204 compute_state(result.states.back(), next_state, sigma, rewr);
205 return false;
206 },
207 [](const data::data_expression& x) { return x == data::sort_real::real_zero(); }
208 );
209 data::remove_assignments(sigma, distribution.variables());
210 if (m_options.check_probabilities)
211 {
212 check_stochastic_state(result, rewr);
213 }
214 }
215 else
216 {
217 result.probabilities.push_back(data::sort_real::real_one());
218 result.states.emplace_back();
219 compute_state(result.states.back(),next_state,sigma,rewr);
220 }
221 }
222
223 template <typename DataExpressionSequence, typename IndexSequence>
225 lps::state& result,
226 const DataExpressionSequence& next_state,
227 const IndexSequence& I_w,
228 data::mutable_indexed_substitution<>& sigma,
229 const data::rewriter& rewr) const
230 {
231 lps::make_state(
232 result,
233 I_w.begin(),
234 I_w.size(),
235 [&](data::data_expression& target, std::size_t i)
236 {
237 rewr(target, next_state[i], sigma);
238 }
239 );
240 }
241
242 template <typename DataExpressionSequence, typename IndexSequence>
244 stochastic_state& result,
245 const stochastic_distribution& distribution,
246 const DataExpressionSequence& next_state,
247 const IndexSequence& I_w,
248 data::mutable_indexed_substitution<>& sigma,
249 const data::rewriter& rewr,
250 data::enumerator_algorithm<>& enumerator) const
251 {
252 result.clear();
253 if (distribution.is_defined())
254 {
255 enumerator.enumerate<enumerator_element>(
256 distribution.variables(),
257 distribution.distribution(),
258 sigma,
259 [&](const enumerator_element& p)
260 {
261 p.add_assignments(distribution.variables(), sigma, rewr);
262 result.probabilities.push_back(p.expression());
263 result.states.emplace_back();
264 compute_projected_state(result.states.back(), next_state, I_w, sigma, rewr);
265 return false;
266 },
267 [](const data::data_expression& x) { return x == data::sort_real::real_zero(); }
268 );
269 data::remove_assignments(sigma, distribution.variables());
270
271 if (m_options.check_probabilities)
272 {
273 check_stochastic_state(result, rewr);
274 }
275 }
276 else
277 {
278 result.probabilities.push_back(data::sort_real::real_one());
279 result.states.emplace_back();
280 compute_projected_state(result.states.back(), next_state, I_w, sigma, rewr);
281 }
282 }
283
284 /// Rewrite action a, and put it back in place.
286 const lps::multi_action& a,
287 data::mutable_indexed_substitution<>& sigma,
288 data::rewriter& rewr) const
289 {
290 const process::action_list& actions = a.actions();
291 const data::data_expression& time = a.time();
292 return lps::multi_action(
293 process::action_list(
294 actions.begin(),
295 actions.end(),
296 [&](process::action& result, const process::action& a)
297 {
298 const data::data_expression_list& args = a.arguments();
299 process::make_action(result,
300 a.label(),
301 data::data_expression_list(args.begin(),
302 args.end(),
303 [&](data::data_expression& result,
304 const data::data_expression& x) -> void
305 { rewr(result, x, sigma); }));
306 }
307 ),
308 a.has_time() ? rewr(time, sigma) : time
309 );
310 }
311
312 void check_enumerator_solution(const data::data_expression& p_expression, // WAS: const enumerator_element& p,
313 const explorer_summand& summand,
314 data::mutable_indexed_substitution<>& sigma,
315 data::rewriter& rewr) const
316 {
317 if (p_expression != data::sort_bool::true_())
318 {
319 std::string printed_condition = data::pp(p_expression);
320 data::remove_assignments(sigma, m_process_parameters);
321 data::remove_assignments(sigma, summand.variables);
322 data::data_expression reduced_condition = rewr(summand.condition, sigma);
323
324 if (!data::find_quantifier_variables(p_expression).empty())
325 {
326 mCRL2log(log::log_level_t::info) << "The condition contains quantifiers, which means that rewriting to normal form could fail when the quantifier enumeration limit is too low. Use ---qlimit/-Q to increase the limit." << std::endl;
327 }
328
329 throw data::enumerator_error("Condition " + data::pp(reduced_condition) +
330 " does not rewrite to true or false. \nCulprit: "
331 + printed_condition.substr(0,2000)
332 + (printed_condition.size() > 2000 ? "..." : ""));
333 }
334 }
335
336 // Generic enumeration primitive.
337 // The callback determines whether solutions are:
338 // - consumed immediately,
339 // - stored in an enumeration cache, or
340 // - transformed into projected transitions.
341 template <typename EmitSolution>
343 const explorer_summand& summand,
344 data::mutable_indexed_substitution<>& sigma,
345 data::rewriter& rewr,
346 data::data_expression& condition,
347 data::enumerator_algorithm<>& enumerator,
348 EmitSolution emit_solution
349 )
350 {
351 rewr(condition, summand.condition, sigma);
352 if (data::is_false(condition))
353 {
354 return;
355 }
356
357 if (summand.variables.empty())
358 {
359 // No enumeration needed
360 check_enumerator_solution(condition, summand, sigma, rewr);
361 emit_solution(data::data_expression_list{});
362 }
363 else
364 {
365 enumerator.enumerate<enumerator_element>(
366 summand.variables,
367 condition,
368 sigma,
369 [&](const enumerator_element& p)
370 {
371 check_enumerator_solution(p.expression(), summand, sigma, rewr);
372 emit_solution(p.assign_expressions(summand.variables, rewr));
373 return false;
374 },
375 data::is_false
376 );
377 }
378 }
379
380 // Projects the current state `x` on the read parameters `I_r`.
381 // * The current state x is encoded in the substitution sigma.
382 // * As a side effect the projected state is assigned to `result`.
383 void project(lps::state& result, const std::vector<std::size_t>& I_r, const data::mutable_indexed_substitution<>& sigma)
384 {
385 lps::make_state(
386 result,
387 I_r.begin(),
388 I_r.size(),
389 [&](data::data_expression& target, std::size_t j)
390 {
391 sigma.apply(m_process_parameters[j], target);
392 }
393 );
394 }
395
396 // Generates outgoing transitions for a summand, and reports them via the callback function report_transition.
397 // It is assumed that the substitution sigma contains the assignments corresponding to the current state.
398 template <bool ReportActions = true, typename SummandSequence, typename ReportTransition = utilities::skip>
400 const explorer_summand& summand,
401 const SummandSequence& confluent_summands,
402 data::mutable_indexed_substitution<>& sigma,
403 data::rewriter& rewr,
404 data::data_expression& condition, // These three variables are passed on such
405 state_type& s1, // that they don't have to be declared often.
406 atermpp::aterm key,
407 data::enumerator_algorithm<>& enumerator,
409#ifdef MCRL2_USE_CONTROL_FLOW
411#endif
412 ReportTransition report_transition = ReportTransition()
413 )
414 {
415 bool variables_are_assigned_to_sigma=false;
416
417#ifdef MCRL2_USE_CONTROL_FLOW
418 if (active_cfg_vertices && !cfg_allows_summand(summand.index, *m_control_flow_graphs, *active_cfg_vertices))
419 {
420 return;
421 }
422#endif
423
424 auto process_transition =
425 [&](const data::data_expression_list* assignments)
426 {
427 if (assignments)
428 {
429 data::add_assignments(sigma, summand.variables, *assignments);
430 variables_are_assigned_to_sigma = true;
431 }
432
433 if constexpr (Stochastic)
434 {
435 compute_stochastic_state(s1, summand.distribution, summand.next_state, sigma, rewr, enumerator);
436 }
437 else
438 {
439 compute_state(s1, summand.next_state, sigma, rewr);
440 if (!confluent_summands.empty())
441 {
442 s1 = find_representative(s1, confluent_summands, sigma, rewr, enumerator, id_generator);
443 }
444 }
445
446 if constexpr (ReportActions)
447 {
448 if (m_options.rewrite_actions)
449 {
450 lps::multi_action a = rewrite_action(summand.multi_action, sigma, rewr);
451 report_transition(a, s1);
452 }
453 else
454 {
455 report_transition(summand.multi_action, s1);
456 }
457 }
458 else
459 {
460 report_transition(s1);
461 }
462
463 if (m_recursive && variables_are_assigned_to_sigma)
464 {
465 data::remove_assignments(sigma, summand.variables);
466 variables_are_assigned_to_sigma = false;
467 }
468 };
469
470 auto enumerate_projected_transitions =
471 [&]()
472 {
473 std::vector<projected_transition> result;
474 // Enumerate all satisfying valuations and compute projected transitions (action, projected state).
475 // Results are stored in the projection cache.
476 enumerate_solutions(
477 summand, sigma, rewr, condition, enumerator,
478 [&](const data::data_expression_list& e)
479 {
480 data::add_assignments(sigma, summand.variables, e);
481 lps::multi_action a = m_options.rewrite_actions ? rewrite_action(summand.multi_action, sigma, rewr) : summand.multi_action;
482
483 if constexpr (Stochastic)
484 {
485 // lps::stochastic_state q;
486 // compute_stochastic_projected_state(q, summand.distribution, summand.next_state, summand.I_w, sigma, rewr, enumerator);
487 // out.emplace_back(a, q);
488 throw mcrl2::runtime_error("A stochastic projection cache has not been implemented yet");
489 }
490 else
491 {
492 lps::state q;
493 compute_projected_state(q, summand.next_state, summand.I_w, sigma, rewr);
494 result.emplace_back(a, q);
495 }
496
497 data::remove_assignments(sigma, summand.variables);
498 }
499 );
500 return result;
501 };
502
503 auto consume_projected_transitions =
504 [&](const projected_transition& t)
505 {
506 const lps::multi_action& a = t.first;
507 const lps::state& q = t.second;
508
509 // reconstruct full state from sigma and the projected write values q
510 state s_y;
511 std::size_t j = 0;
512 lps::make_state(
513 s_y,
514 counting_iterator(0),
515 m_n, // total number of process parameters
516 [&](data::data_expression& r, std::size_t i)
517 {
518 if (j < summand.I_w.size() && summand.I_w[j] == i)
519 {
520 r = q[j++];
521 }
522 else
523 {
524 // reconstruct x[i] from the substitution sigma
525 rewr(r, m_process_parameters[i], sigma);
526 }
527 }
528 );
529
530 if constexpr (!Stochastic)
531 {
532 state_type y = s_y;
533 if (!confluent_summands.empty())
534 {
535 y = find_representative(y, confluent_summands, sigma, rewr, enumerator, id_generator);
536 }
537 if constexpr (utilities::is_applicable<ReportTransition, state_type, void>::value)
538 {
539 report_transition(y);
540 }
541 else
542 {
543 report_transition(a, y);
544 }
545 }
546 else
547 {
548 // Convert reconstructed state to a Dirac stochastic state.
549 state_type y;
550 y.clear();
551 y.probabilities.push_back(data::sort_real::real_one());
552 y.states.push_back(s_y);
553 if constexpr (utilities::is_applicable<ReportTransition, state_type, void>::value)
554 {
555 report_transition(y);
556 }
557 else
558 {
559 report_transition(a, y);
560 }
561 }
562 };
563
564 if (!m_recursive)
565 {
566 id_generator.clear();
567 }
568
569 if (m_options.use_projections && !summand.I_r.empty())
570 {
571 lps::state key;
572 project(key, summand.I_r, sigma);
573 utilities::shared_guard g = atermpp::detail::g_thread_term_pool().lock_shared();
574
575 auto it = summand.projection_cache.find(key);
576 if (it == summand.projection_cache.end())
577 {
578 g.unlock();
579
580 std::vector<projected_transition> projected = enumerate_projected_transitions();
581 it = summand.projection_cache.emplace(key, std::move(projected)).first;
582 }
583 else
584 {
585 g.unlock();
586 }
587
588 for (const projected_transition& t : it->second)
589 {
590 consume_projected_transitions(t);
591 }
592 }
593 else if (summand.cache_strategy == caching::none)
594 {
595 // Enumerate and immediately consume all satisfying valuations (no caching, no projection).
596 enumerate_solutions(
597 summand, sigma, rewr, condition, enumerator,
598 [&](const data::data_expression_list& e)
599 {
600 process_transition(&e);
601 }
602 );
603 }
604 else
605 {
606 summand_cache_map& cache = summand.cache_strategy == caching::global ? global_cache : summand.local_cache;
607 utilities::shared_guard g = atermpp::detail::g_thread_term_pool().lock_shared();
608
609 auto q = cache.find(detail::cheap_cache_key(sigma, summand.gamma));
610 if (q == cache.end())
611 {
612 g.unlock();
613
614 atermpp::term_list<data::data_expression_list> solutions;
615 // Enumerate all satisfying valuations for this summand and store them in the cache.
616 enumerate_solutions(
617 summand, sigma, rewr, condition, enumerator,
618 [&](const data::data_expression_list& e)
619 {
620 solutions.push_front(e);
621 }
622 );
623 summand.compute_key(key, sigma);
624 q = cache.insert({key, solutions}).first;
625 }
626 else
627 {
628 g.unlock();
629 }
630
631 for (const auto& e : static_cast<atermpp::term_list<data::data_expression_list>&>(q->second))
632 {
633 process_transition(e.empty() ? nullptr : &e);
634 }
635 }
636
637 if (!m_recursive && variables_are_assigned_to_sigma)
638 {
639 data::remove_assignments(sigma, summand.variables);
640 }
641 }
642
643 template <typename SummandSequence>
651 )
652 {
653 data::data_expression condition; // This variable is used often, and it is time consuming to declare it too often.
654 state_type state_; // The same holds for this variable.
655 atermpp::aterm key;
656 std::list<transition> transitions;
657 data::add_assignments(sigma, m_process_parameters, s);
658#ifdef MCRL2_USE_CONTROL_FLOW
659 auto active_cfg_vertices = compute_active_cfg_vertices_if_enabled(sigma);
660#endif
661 for (const explorer_summand& summand: regular_summands)
662 {
663 generate_transitions(
664 summand,
665 confluent_summands,
666 sigma,
667 rewr,
668 condition,
669 state_,
670 key,
671 enumerator,
672 id_generator,
673#ifdef MCRL2_USE_CONTROL_FLOW
674 active_cfg_vertices,
675#endif
676 [&](const lps::multi_action& a, const state_type& s1)
677 {
678 if constexpr (Timed)
679 {
680 const data::data_expression& t = s[m_n];
681 if (a.has_time() && less_equal(a.time(), t, sigma, rewr))
682 {
683 return;
684 }
685 const data::data_expression& t1 = a.has_time() ? a.time() : t;
686 make_timed_state(state_, s1, t1);
687 transitions.emplace_back(a, state_);
688 }
689 else
690 {
691 transitions.emplace_back(a, s1);
692 }
693 }
694 );
695 }
696 return transitions;
697 }
698
699 // pre: s0 is in normal form
700 template <typename SummandSequence>
702 const state& s0,
709 )
710 {
711 data::data_expression condition;
712 state_type state_;
713 atermpp::aterm key;
714 std::vector<state> result;
715 data::add_assignments(sigma, m_process_parameters, s0);
716#ifdef MCRL2_USE_CONTROL_FLOW
717 auto active_cfg_vertices = compute_active_cfg_vertices_if_enabled(sigma);
718#endif
719 for (const explorer_summand& summand: summands)
720 {
721 generate_transitions<false>(
722 summand,
723 confluent_summands,
724 sigma,
725 rewr,
726 condition,
727 state_,
728 key,
729 enumerator,
730 id_generator,
731#ifdef MCRL2_USE_CONTROL_FLOW
732 active_cfg_vertices,
733#endif
734 // [&](const lps::multi_action& /* a */, const state& s1) OLD. Calculates transitions, that are not used.
735 [&](const state& s1)
736 {
737 result.push_back(s1);
738 }
739 );
740 data::remove_assignments(sigma, summand.variables);
741 }
742 return result;
743 }
744
745 // Add operations on reals that are needed for the exploration.
747 {
748 std::set<data::function_symbol> result = std::move(s);
749 result.insert(data::less_equal(data::sort_real::real_()));
750 result.insert(data::greater_equal(data::sort_real::real_()));
751 result.insert(data::sort_real::plus(data::sort_real::real_(), data::sort_real::real_()));
752 return result;
753 }
754
756 {
757 switch (m_options.search_strategy)
758 {
759 case lps::exploration_strategy::es_breadth: return std::make_unique<breadth_first_todo_set>(init);
760 case lps::exploration_strategy::es_depth: return std::make_unique<depth_first_todo_set>(init);
761 case lps::exploration_strategy::es_highway: return std::make_unique<highway_todo_set>(init, m_options.highway_todo_max);
762 default: throw mcrl2::runtime_error("unsupported search strategy");
763 }
764 }
765
766 template <typename ForwardIterator>
768 {
769 switch (m_options.search_strategy)
770 {
771 case lps::exploration_strategy::es_breadth: return std::make_unique<breadth_first_todo_set>(first, last);
772 case lps::exploration_strategy::es_depth: return std::make_unique<depth_first_todo_set>(first, last);
773 case lps::exploration_strategy::es_highway: return std::make_unique<highway_todo_set>(first, last, m_options.highway_todo_max);
774 default: throw mcrl2::runtime_error("unsupported search strategy");
775 }
776 }
777
778 private:
780 {
781 if (a.actions().empty())
782 {
783 return m_options.confluence_action == "tau";
784 }
785 else if (a.actions().size() == 1)
786 {
787 return std::string(a.actions().front().label().name()) == m_options.confluence_action;
788 }
789 return false;
790 }
791
792 public:
793 explorer(const Specification& lpsspec, const explorer_options& options_, const data::rewriter& rewr
794#ifdef MCRL2_USE_CONTROL_FLOW
796 , bool compute_marking = false
797#endif
798 )
804 {
805#ifdef MCRL2_USE_CONTROL_FLOW
806 // The control flow graphs are only computed when the reduction is enabled at runtime.
807 if constexpr (!Stochastic)
808 {
809 if (m_options.use_control_flow)
810 {
811 lps::specification control_flow_lpsspec = lpsspec;
812 std::vector<cf_graph> graphs = compute_control_flow_graphs(control_flow_lpsspec, stategraph_options, compute_marking);
813 if (mCRL2logEnabled(log::log_level_t::debug))
814 {
815 for (const cf_graph& G: graphs)
816 {
817 print_graph(G);
818 }
819 }
820 // Without any graph there is nothing to restrict, so leave the data structures uninitialised.
821 if (!graphs.empty())
822 {
823 m_control_flow_graphs = std::move(graphs);
824 }
825 }
826 }
827#endif
828
829 const data::variable_list& params = m_global_lpsspec.process().process_parameters();
830 m_process_parameters = std::vector<data::variable>(params.begin(), params.end());
831 m_n = m_process_parameters.size();
832 timed_state.resize(m_n + 1);
833 m_initial_state = m_global_lpsspec.initial_process().expressions();
834 m_initial_distribution = initial_distribution(m_global_lpsspec);
835
836 // Split the summands in regular and confluent summands
837 const auto& lpsspec_summands = m_global_lpsspec.process().action_summands();
838 for (std::size_t i = 0; i < lpsspec_summands.size(); i++)
839 {
840 const auto& summand = lpsspec_summands[i];
841 caching cache_strategy = m_options.cached ? (m_options.global_cache ? lps::caching::global : lps::caching::local) : lps::caching::none;
842 if (is_confluent_tau(summand.multi_action()))
843 {
844 m_confluent_summands.emplace_back(summand, i, m_global_lpsspec.process().process_parameters(), cache_strategy);
845 }
846 else
847 {
848 m_regular_summands.emplace_back(summand, i, m_global_lpsspec.process().process_parameters(), cache_strategy);
849 }
850 }
851
852 // Initialize the read/write projections
853 if (m_options.use_projections)
854 {
855 auto [R, W] = compute_read_write_patterns_separated(lpsspec);
856 for (std::size_t i = 0; i < m_regular_summands.size(); ++i)
857 {
858 m_regular_summands[i].set_projection_attributes(R[i], W[i]);
859 }
860 }
861 }
862
863 ~explorer() override = default;
864
865 // Get the initial state of the specification.
866 const data::data_expression_list& initial_state() const
867 {
868 return m_initial_state;
869 }
870
871 // Make the rewriter available to be used in a class that uses this explorer class.
872 const data::rewriter& get_rewriter() const
873 {
874 return m_global_rewr;
875 }
876
877 // Compute the initial stochastic state
879 {
880 compute_stochastic_state(result, m_initial_distribution, m_initial_state, m_global_sigma, m_global_rewr, m_global_enumerator);
881 }
882
883 // Convenience overload: use internal sigma/rewriter/enumerator
884 template <typename DataExpressionSequence>
886 const stochastic_distribution& distribution,
887 const DataExpressionSequence& next_state) const
888 {
889 compute_stochastic_state(result, distribution, next_state, m_global_sigma, m_global_rewr, m_global_enumerator);
890 }
891
892 // Utility function to obtain the outgoing transitions of the current state.
893 // Should not be used concurrently.
895 {
896 return out_edges(s, m_regular_summands, m_confluent_summands, m_global_sigma, m_global_rewr, m_global_enumerator, m_global_id_generator);
897 }
898
899 // Utility function to obtain the outgoing transitions of the current state.
900 // Only transitions for the summand with the indicated index are generated.
901 // Should not be used concurrently.
903 {
904 assert(summand_index<m_regular_summands.size());
905 return out_edges(s,
906 std::vector(1, m_regular_summands[summand_index]),
907 m_confluent_summands,
908 m_global_sigma, m_global_rewr, m_global_enumerator, m_global_id_generator);
909 }
910
911 // Returns the concatenation of s and [t]
912 void make_timed_state(state& result, const state& s, const data::data_expression& t) const
913 {
914 std::copy(s.begin(), s.end(), timed_state.begin());
915 timed_state.back() = t;
916 lps::make_state(result, timed_state.begin(), m_n + 1);
917 }
918
920 {
921 if constexpr (Stochastic)
922 {
923 return stochastic_state(s);
924 }
925 else
926 {
927 return s;
928 }
929 }
930
932 {
933 return s;
934 }
935
936 template<typename StateType,
937 typename SummandSequence,
938 typename DiscoverState = utilities::skip,
939 typename ExamineTransition = utilities::skip,
940 typename StartState = utilities::skip,
941 typename FinishState = utilities::skip,
942 typename DiscoverInitialState = utilities::skip>
943 void generate_state_space_thread(std::unique_ptr<todo_set>& todo,
944 std::size_t thread_index,
945 std::atomic<std::size_t>& number_of_active_processes,
946 const SummandSequence& regular_summands,
947 const SummandSequence& confluent_summands,
948 indexed_set_for_states_type& discovered,
949 DiscoverState discover_state,
950 ExamineTransition examine_transition,
951 StartState start_state,
952 FinishState finish_state,
953 data::rewriter thread_rewr,
954 data::mutable_indexed_substitution<> thread_sigma // This is intentionally a copy.
955 );
956
957 // pre: s0 is in normal form
958 template <
959 typename StateType,
960 typename SummandSequence,
961 typename DiscoverState = utilities::skip,
962 typename ExamineTransition = utilities::skip,
963 typename StartState = utilities::skip,
964 typename FinishState = utilities::skip,
965 typename DiscoverInitialState = utilities::skip
966 >
968 bool recursive,
969 const StateType& s0,
970 const SummandSequence& regular_summands,
971 const SummandSequence& confluent_summands,
972 indexed_set_for_states_type& discovered,
973 DiscoverState discover_state = DiscoverState(),
974 ExamineTransition examine_transition = ExamineTransition(),
975 StartState start_state = StartState(),
976 FinishState finish_state = FinishState(),
977 [[maybe_unused]]
978 DiscoverInitialState discover_initial_state = DiscoverInitialState()
979 );
980
981 /// \brief Generates the state space, and reports all discovered states and transitions by means of callback
982 /// functions.
983 /// \param discover_state Is invoked when a state is encountered for the first time.
984 /// \param examine_transition Is invoked on every transition.
985 /// \param start_state Is invoked on a state right before its outgoing transitions are being explored.
986 /// \param finish_state Is invoked on a state after all of its outgoing transitions have been explored.
987 template <
988 typename DiscoverState = utilities::skip,
989 typename ExamineTransition = utilities::skip,
990 typename StartState = utilities::skip,
991 typename FinishState = utilities::skip,
992 typename DiscoverInitialState = utilities::skip
993 >
995 bool recursive,
996 DiscoverState discover_state = DiscoverState(),
997 ExamineTransition examine_transition = ExamineTransition(),
998 StartState start_state = StartState(),
999 FinishState finish_state = FinishState(),
1000 DiscoverInitialState discover_initial_state = DiscoverInitialState()
1001 );
1002
1003 /// \brief Generates outgoing transitions for a given state.
1005 const state& d0,
1007 data::rewriter& rewr,
1010 {
1015 atermpp::aterm key;
1017#ifdef MCRL2_USE_CONTROL_FLOW
1019#endif
1021 {
1023 summand,
1025 sigma,
1026 rewr,
1027 condition,
1028 state,
1029 key,
1030 enumerator,
1032#ifdef MCRL2_USE_CONTROL_FLOW
1034#endif
1035 [&](const lps::multi_action& a, const state_type& d1)
1036 {
1038 }
1039 );
1040 }
1042 return result;
1043 }
1044
1045 /// \brief Generates outgoing transitions for a given state, using the global substitution, rewriter, enumerator and id_generator.
1046 /// \details This function is not suitable to be used in parallel threads, but can only be used for pre or post processing.
1048 const state& d0)
1049 {
1050 assert(m_options.number_of_threads==1); // A global rewriter is invoked, and this can only happen in a single threaded setting.
1052 }
1053
1054 /// \brief Generates outgoing transitions for a given state.
1058 data::rewriter& rewr)
1059 {
1060 state d0;
1062 return generate_transitions(d0);
1063 }
1064
1065 /// \brief Generates outgoing transitions for a given state, reachable via the summand with index i.
1068 std::size_t i,
1070 data::rewriter& rewr,
1072 state_type& d0,
1075 {
1080#ifdef MCRL2_USE_CONTROL_FLOW
1082#endif
1086 sigma,
1087 rewr,
1088 condition,
1089 d0,
1090 enumerator,
1092#ifdef MCRL2_USE_CONTROL_FLOW
1094#endif
1095 [&](const lps::multi_action& a, const state_type& d1)
1096 {
1098 }
1099 );
1102 return result;
1103 }
1104
1105 // --- Recursive DFS (core) ---------------------------------------------
1106 // pre: s0 is in normal form
1107 // N.B. Does not support stochastic specifications!
1108 template <
1109 typename SummandSequence,
1110 typename DiscoverState = utilities::skip,
1111 typename ExamineTransition = utilities::skip,
1112 typename TreeEdge = utilities::skip,
1113 typename BackEdge = utilities::skip,
1114 typename ForwardOrCrossEdge = utilities::skip,
1115 typename FinishState = utilities::skip
1116 >
1118 const state& s0,
1129 );
1130
1131 // --- Recursive DFS (entry point) ---------------------------------------
1132 template <
1133 typename DiscoverState = utilities::skip,
1134 typename ExamineTransition = utilities::skip,
1135 typename TreeEdge = utilities::skip,
1136 typename BackEdge = utilities::skip,
1137 typename ForwardOrCrossEdge = utilities::skip,
1138 typename FinishState = utilities::skip
1139 >
1141 bool recursive,
1142 DiscoverState discover_state = DiscoverState(),
1143 ExamineTransition examine_transition = ExamineTransition(),
1144 TreeEdge tree_edge = TreeEdge(),
1145 BackEdge back_edge = BackEdge(),
1146 ForwardOrCrossEdge forward_or_cross_edge = ForwardOrCrossEdge(),
1147 FinishState finish_state = FinishState()
1148 );
1149
1150 // --- Iterative DFS (core) ----------------------------------------------
1151 // pre: s0 is in normal form
1152 // N.B. Does not support stochastic specifications!
1153 template <
1154 typename SummandSequence,
1155 typename DiscoverState = utilities::skip,
1156 typename ExamineTransition = utilities::skip,
1157 typename TreeEdge = utilities::skip,
1158 typename BackEdge = utilities::skip,
1159 typename ForwardOrCrossEdge = utilities::skip,
1160 typename FinishState = utilities::skip
1161 >
1163 const state& s0,
1164 std::unordered_set<state>& discovered,
1165 const SummandSequence& regular_summands,
1166 const SummandSequence& confluent_summands,
1167 DiscoverState discover_state = DiscoverState(),
1168 ExamineTransition examine_transition = ExamineTransition(),
1169 TreeEdge tree_edge = TreeEdge(),
1170 BackEdge back_edge = BackEdge(),
1171 ForwardOrCrossEdge forward_or_cross_edge = ForwardOrCrossEdge(),
1172 FinishState finish_state = FinishState()
1173 );
1174
1175 // --- Iterative DFS (entry point) ---------------------------------------
1176 template <
1177 typename DiscoverState = utilities::skip,
1178 typename ExamineTransition = utilities::skip,
1179 typename TreeEdge = utilities::skip,
1180 typename BackEdge = utilities::skip,
1181 typename ForwardOrCrossEdge = utilities::skip,
1182 typename FinishState = utilities::skip
1183 >
1185 bool recursive,
1186 DiscoverState discover_state = DiscoverState(),
1187 ExamineTransition examine_transition = ExamineTransition(),
1188 TreeEdge tree_edge = TreeEdge(),
1189 BackEdge back_edge = BackEdge(),
1190 ForwardOrCrossEdge forward_or_cross_edge = ForwardOrCrossEdge(),
1191 FinishState finish_state = FinishState()
1192 );
1193
1194 /// \brief Abort the state space generation
1195 // NOLINTNEXTLINE(portability-template-virtual-member-function)
1196 void abort() override
1197 {
1198 m_must_abort = true;
1199 }
1200
1201 /// \brief Returns a mapping containing all discovered states.
1203 {
1204 return m_discovered;
1205 }
1206
1208 {
1209 return m_regular_summands;
1210 }
1211
1213 {
1214 return m_confluent_summands;
1215 }
1216
1218 {
1219 return m_process_parameters;
1220 }
1221
1222 data::data_expression_list process_parameter_values(data::mutable_indexed_substitution<>& sigma) const
1223 {
1224 return data::data_expression_list{m_process_parameters.begin(), m_process_parameters.end(), [&](const data::variable& x) { return sigma(x); }};
1225 }
1226
1227 /// \brief Process parameter values for use in a single thread.
1228 data::data_expression_list process_parameter_values() const
1229 {
1230 assert(m_options.number_of_threads==1); // Using a global sigma is not thread safe.
1231 return process_parameter_values(m_global_sigma);
1232 }
1233 void set_process_parameter_values(const data::data_expression_list& values, data::mutable_indexed_substitution<>& sigma)
1234 {
1235 data::add_assignments(sigma, m_process_parameters, values);
1236 }
1237
1238 void set_process_parameter_values(const data::data_expression_list& values)
1239 {
1240 assert(m_options.number_of_threads==1); // Using a global sigma is not thread safe.
1241 set_process_parameter_values(values, m_global_sigma);
1242 }
1243};
1244
1245} // namespace mcrl2::lps
1246
1247#endif // MCRL2_LPS_EXPLORER_H
1248
1249// implementation
1250#include "mcrl2/lps/explorer_bfs.h"
1251#include "mcrl2/lps/explorer_dfs.h"
A list of aterm objects.
Definition aterm_list.h:26
A unordered_map class in which aterms can be stored.
data_expression & operator=(data_expression &&) noexcept=default
Rewriter that operates on data expressions.
Definition rewriter.h:84
data_expression operator()(const data_expression &d) const
Rewrites a data expression.
Definition rewriter.h:161
std::vector< data::variable > m_process_parameters
Definition explorer.h:87
void make_timed_state(state &result, const state &s, const data::data_expression &t) const
Definition explorer.h:912
data::enumerator_algorithm m_global_enumerator
Definition explorer.h:77
void abort() override
Abort the state space generation.
Definition explorer.h:1196
lps::multi_action rewrite_action(const lps::multi_action &a, data::mutable_indexed_substitution<> &sigma, data::rewriter &rewr) const
Rewrite action a, and put it back in place.
Definition explorer.h:285
std::vector< state > generate_successors(const state &s0, const SummandSequence &summands, data::mutable_indexed_substitution<> &sigma, data::rewriter &rewr, data::enumerator_algorithm<> &enumerator, data::enumerator_identifier_generator &id_generator, const SummandSequence &confluent_summands=SummandSequence())
Definition explorer.h:701
std::condition_variable m_signal_global_todo_buffer_filled
Definition explorer.h:85
void compute_stochastic_state(stochastic_state &result, const stochastic_distribution &distribution, const DataExpressionSequence &next_state) const
Definition explorer.h:885
const state_type & make_state(const stochastic_state &s) const
Definition explorer.h:931
std::size_t m_n
Definition explorer.h:88
void generate_state_space(bool recursive, const StateType &s0, const SummandSequence &regular_summands, const SummandSequence &confluent_summands, indexed_set_for_states_type &discovered, DiscoverState discover_state=DiscoverState(), ExamineTransition examine_transition=ExamineTransition(), StartState start_state=StartState(), FinishState finish_state=FinishState(), DiscoverInitialState discover_initial_state=DiscoverInitialState())
const indexed_set_for_states_type & state_map() const
Returns a mapping containing all discovered states.
Definition explorer.h:1202
bool less_equal(const data::data_expression &t0, const data::data_expression &t1, data::mutable_indexed_substitution<> &sigma, data::rewriter &rewr) const
Definition explorer.h:144
const std::vector< data::variable > & process_parameters() const
Definition explorer.h:1217
const std::vector< explorer_summand > & confluent_summands() const
Definition explorer.h:1212
void set_process_parameter_values(const data::data_expression_list &values, data::mutable_indexed_substitution<> &sigma)
Definition explorer.h:1233
void set_process_parameter_values(const data::data_expression_list &values)
Definition explorer.h:1238
~explorer() override=default
std::set< data::function_symbol > add_real_operators(std::set< data::function_symbol > s) const
Definition explorer.h:746
data::enumerator_identifier_generator m_global_id_generator
Definition explorer.h:78
explorer(const Specification &lpsspec, const explorer_options &options_, const data::rewriter &rewr)
Definition explorer.h:793
void enumerate_solutions(const explorer_summand &summand, data::mutable_indexed_substitution<> &sigma, data::rewriter &rewr, data::data_expression &condition, data::enumerator_algorithm<> &enumerator, EmitSolution emit_solution)
Definition explorer.h:342
Specification m_global_lpsspec
Definition explorer.h:80
data::data_expression_list process_parameter_values() const
Process parameter values for use in a single thread.
Definition explorer.h:1228
void generate_transitions(const explorer_summand &summand, const SummandSequence &confluent_summands, data::mutable_indexed_substitution<> &sigma, data::rewriter &rewr, data::data_expression &condition, state_type &s1, atermpp::aterm key, data::enumerator_algorithm<> &enumerator, data::enumerator_identifier_generator &id_generator, ReportTransition report_transition=ReportTransition())
Definition explorer.h:399
void generate_state_space_dfs_recursive(bool recursive, DiscoverState discover_state=DiscoverState(), ExamineTransition examine_transition=ExamineTransition(), TreeEdge tree_edge=TreeEdge(), BackEdge back_edge=BackEdge(), ForwardOrCrossEdge forward_or_cross_edge=ForwardOrCrossEdge(), FinishState finish_state=FinishState())
static constexpr bool is_timed
Definition explorer.h:56
const data::data_expression_list & initial_state() const
Definition explorer.h:866
void generate_state_space_thread(std::unique_ptr< todo_set > &todo, std::size_t thread_index, std::atomic< std::size_t > &number_of_active_processes, const SummandSequence &regular_summands, const SummandSequence &confluent_summands, indexed_set_for_states_type &discovered, DiscoverState discover_state, ExamineTransition examine_transition, StartState start_state, FinishState finish_state, data::rewriter thread_rewr, data::mutable_indexed_substitution<> thread_sigma)
void generate_state_space(bool recursive, DiscoverState discover_state=DiscoverState(), ExamineTransition examine_transition=ExamineTransition(), StartState start_state=StartState(), FinishState finish_state=FinishState(), DiscoverInitialState discover_initial_state=DiscoverInitialState())
Generates the state space, and reports all discovered states and transitions by means of callback fun...
indexed_set_for_states_type m_discovered
Definition explorer.h:100
state find_representative(state &u0, const SummandSequence &summands, data::mutable_indexed_substitution<> &sigma, data::rewriter &rewr, data::enumerator_algorithm<> &enumerator, data::enumerator_identifier_generator &id_generator)
Definition explorer.h:154
std::vector< explorer_summand > m_regular_summands
Definition explorer.h:92
const explorer_options m_options
Definition explorer.h:72
summand_cache_map global_cache
Definition explorer.h:98
const data::rewriter & get_rewriter() const
Definition explorer.h:872
data::data_expression_list m_initial_state
Definition explorer.h:89
std::mutex m_exclusive_state_access
Definition explorer.h:82
data::mutable_indexed_substitution m_global_sigma
Definition explorer.h:75
data::data_expression_list process_parameter_values(data::mutable_indexed_substitution<> &sigma) const
Definition explorer.h:1222
state_type make_state(const state &s) const
Definition explorer.h:919
lps::stochastic_distribution m_initial_distribution
Definition explorer.h:90
void compute_projected_state(lps::state &result, const DataExpressionSequence &next_state, const IndexSequence &I_w, data::mutable_indexed_substitution<> &sigma, const data::rewriter &rewr) const
Definition explorer.h:224
void compute_state(state &result, const DataExpressionSequence &v, data::mutable_indexed_substitution<> &sigma, const data::rewriter &rewr) const
Definition explorer.h:173
std::vector< explorer_summand > m_confluent_summands
Definition explorer.h:93
void compute_initial_stochastic_state(stochastic_state &result) const
Definition explorer.h:878
volatile std::atomic< bool > m_must_abort
Definition explorer.h:95
data::rewriter m_global_rewr
Definition explorer.h:76
void generate_state_space_dfs_iterative(const state &s0, std::unordered_set< state > &discovered, const SummandSequence &regular_summands, const SummandSequence &confluent_summands, DiscoverState discover_state=DiscoverState(), ExamineTransition examine_transition=ExamineTransition(), TreeEdge tree_edge=TreeEdge(), BackEdge back_edge=BackEdge(), ForwardOrCrossEdge forward_or_cross_edge=ForwardOrCrossEdge(), FinishState finish_state=FinishState())
void check_enumerator_solution(const data::data_expression &p_expression, const explorer_summand &summand, data::mutable_indexed_substitution<> &sigma, data::rewriter &rewr) const
Definition explorer.h:312
void compute_stochastic_state(stochastic_state &result, const stochastic_distribution &distribution, const DataExpressionSequence &next_state, data::mutable_indexed_substitution<> &sigma, const data::rewriter &rewr, const data::enumerator_algorithm<> &enumerator) const
Definition explorer.h:185
const std::vector< explorer_summand > & regular_summands() const
Definition explorer.h:1207
std::unique_ptr< todo_set > make_todo_set(const state &init)
Definition explorer.h:755
std::mutex m_global_todo_buffer_mutex
Definition explorer.h:84
std::unique_ptr< todo_set > make_todo_set(ForwardIterator first, ForwardIterator last)
Definition explorer.h:767
std::list< transition > out_edges(const state &s)
Definition explorer.h:894
std::vector< data::data_expression > timed_state
Definition explorer.h:103
void project(lps::state &result, const std::vector< std::size_t > &I_r, const data::mutable_indexed_substitution<> &sigma)
Definition explorer.h:383
std::list< transition > out_edges(const state &s, const SummandSequence &regular_summands, const SummandSequence &confluent_summands, data::mutable_indexed_substitution<> &sigma, data::rewriter &rewr, data::enumerator_algorithm<> &enumerator, data::enumerator_identifier_generator &id_generator)
Definition explorer.h:644
Specification preprocess(const Specification &lpsspec)
Definition explorer.h:126
std::list< transition > out_edges(const state &s, const std::size_t summand_index)
Definition explorer.h:902
bool is_confluent_tau(const multi_action &a)
Definition explorer.h:779
static constexpr bool is_stochastic
Definition explorer.h:55
void generate_state_space_dfs_iterative(bool recursive, DiscoverState discover_state=DiscoverState(), ExamineTransition examine_transition=ExamineTransition(), TreeEdge tree_edge=TreeEdge(), BackEdge back_edge=BackEdge(), ForwardOrCrossEdge forward_or_cross_edge=ForwardOrCrossEdge(), FinishState finish_state=FinishState())
void compute_stochastic_projected_state(stochastic_state &result, const stochastic_distribution &distribution, const DataExpressionSequence &next_state, const IndexSequence &I_w, data::mutable_indexed_substitution<> &sigma, const data::rewriter &rewr, data::enumerator_algorithm<> &enumerator) const
Definition explorer.h:243
\brief A timed multi-action
const process::action_list & actions() const
const data::data_expression & time() const
Simulation process.
Definition simulation.h:22
void enable_auto_select_probability(bool enable)
If enabled, automatically a probabilistic state is chosen using its intrinsic probability.
void select_transition(std::size_t transition_number)
Choose outgoing transition indexed by transition_number and add its state to the state vector.
void add_new_state(const lps::stochastic_state &s)
std::uniform_int_distribution< std::size_t > m_distrib
Definition simulation.h:87
std::deque< simulator_state_t > m_full_trace
Definition simulation.h:90
void randomly_select_state()
Randomly choose one state among a sequence of probabilistic states.
bool m_auto_select_probabilistic_state
Definition simulation.h:85
void select_state(std::size_t state_number)
Choose one state among a sequence of probabilistic states.
simulation(const stochastic_specification &specification, data::rewrite_strategy strategy=data::rewrite_strategy())
Constructor.
void randomly_select_transition()
Randomly choose an outgoing transition and add its state to the state vector.
std::vector< transition_type > transitions(const lps::state &source_state)
bool match_trace_transition(lts::trace &trace)
void environment(std::vector< std::string > values)
Goto the state indicated by the environment, which is given by a vector of strings.
virtual ~simulation()=default
bool match_trace_probabilistic_state(lts::trace &trace)
data::rewriter m_rewriter
Definition simulation.h:83
void save(const std::string &filename) const
Save the trace to a file.
bool probabilistic_state_must_be_selected(const std::size_t state_index) const
Indicate whether a probabilistic state has been selected.
Definition simulation.h:63
explorer_type m_explorer
Definition simulation.h:84
const std::deque< simulator_state_t > & trace() const
Returns the current annotated state vector.
Definition simulation.h:42
stochastic_specification m_specification
Definition simulation.h:82
void truncate(std::size_t state_number, bool probabilistic)
Remove states from the end of the simulation, making state_number the last state.
void load(const std::string &filename)
Load a trace from a file.
\brief A stochastic distribution
bool is_defined() const
Returns true if the distribution is defined, i.e. it contains a valid distribution....
This class contains a trace consisting of a sequence of (timed) actions possibly with intermediate st...
Definition trace.h:51
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:435
Namespace for system defined sort bool_.
Definition bool.h:29
const function_symbol & true_()
Constructor for function symbol true.
Definition bool.h:74
Namespace for system defined sort real_.
data_expression & real_one()
data_expression & real_zero()
bool is_false(const data_expression &x)
Test if x is false.
Definition consistency.h:36
application greater_equal(const data_expression &arg0, const data_expression &arg1)
Application of function symbol >=.
Definition standard.h:374
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
The main namespace for the LPS library.
Definition constelm.h:18
void check_stochastic_state(const stochastic_state &s, const data::rewriter &rewr)
void check_probability(const data::data_expression &x, const data::rewriter &rewr)
std::string print_probability(const data::data_expression &x)
The main namespace for the Process library.
transition(lps::multi_action action_, const state_type &state_)
Definition explorer.h:65
std::vector< transition_type > transitions
Definition simulation.h:33
void push_back(const data::data_expression &probability, const state &s)
std::vector< data::data_expression > probabilities
std::vector< state > states