12#ifndef MCRL2_LPS_LPSREACH_H
13#define MCRL2_LPS_LPSREACH_H
15#ifdef MCRL2_ENABLE_SYLVAN
32#include <sylvan_ldd.hpp>
36#include <boost/dynamic_bitset.hpp>
40class lpsreach_algorithm
42 using ldd = sylvan::ldds::ldd;
43 using enumerator_element = data::enumerator_list_element_with_substitution<>;
45 template <
typename Context,
bool ActionLabel>
46 friend void symbolic::learn_successors_callback(WorkerP*, Task*, std::uint32_t* v, std::size_t n,
void* context);
49 const symbolic::symbolic_reachability_options& m_options;
50 data::rewriter m_rewr;
51 data::mutable_indexed_substitution<> m_sigma;
52 data::enumerator_identifier_generator m_id_generator;
53 data::enumerator_algorithm<> m_enumerator;
54 std::vector<boost::dynamic_bitset<>> m_summand_patterns;
55 std::vector<boost::dynamic_bitset<>> m_group_patterns;
56 std::vector<std::size_t> m_variable_order;
60 template<
typename Rewriter,
typename Substitution>
61 lps::multi_action rewrite_action(
const lps::multi_action& a,
const Rewriter& rewr,
const Substitution&
sigma)
63 const process::action_list& actions = a.actions();
64 const data::data_expression& time = a.time();
70 [&](
const process::action& a)
72 const auto& args = a.arguments();
73 return process::action(a.label(), data::data_expression_list(args.begin(), args.end(), [&](const data::data_expression& x) { return rewr(x, sigma); }));
76 a.has_time() ? rewr(time,
sigma) : time
81 void learn_successors(std::size_t i, symbolic::summand_group& R,
const ldd& X)
83 mCRL2log(
log::trace) <<
"learn successors of summand group " << i <<
" for X = " << print_states(m_lts.data_index, X, R.read) << std::endl;
85 using namespace sylvan::ldds;
86 std::pair<lpsreach_algorithm&, symbolic::summand_group&> context{*
this, R};
87 sat_all_nopar(X, symbolic::learn_successors_callback<std::pair<lpsreach_algorithm&, lps_summand_group&>,
true>, &context);
90 template <
typename Specification>
91 Specification preprocess(
const Specification& lpsspec)
93 Specification result = lpsspec;
97 if (m_options.one_point_rule_rewrite)
101 if (m_options.replace_constants_by_variables)
109 std::string print_size(
const sylvan::ldds::ldd& L)
111 return symbolic::print_size(L, m_options.print_exact, m_options.print_nodesize);
115 lpsreach_algorithm(
const lps::specification& lpsspec,
const symbolic::symbolic_reachability_options& options_)
116 : m_options(options_),
118 m_enumerator(m_rewr, lpsspec.data(), m_rewr, m_id_generator, false)
122 lps::specification lpsspec_ = preprocess(lpsspec);
123 m_lts.process_parameters = lpsspec_.process().process_parameters();
126 std::vector<data::data_expression> initial_values;
127 for (
const data::data_expression& expression : lpsspec_.initial_process().expressions())
129 initial_values.push_back(m_rewr(expression));
134 m_summand_patterns = compute_read_write_patterns(lpsspec_);
142 m_lts.process_parameters = symbolic::permute_copy(m_lts.process_parameters, m_variable_order);
143 for (
const data::variable& param : m_lts.process_parameters)
145 m_lts.data_index.push_back(symbolic::data_expression_index(
param.sort()));
148 m_lts.initial_state = symbolic::state2ldd(symbolic::permute_copy(initial_state, m_variable_order), m_lts.data_index);
152 for (
const auto& group: groups)
157 for (std::size_t j = 0; j < m_group_patterns.size(); j++)
159 m_lts.summand_groups.emplace_back(lpsspec_, m_lts.process_parameters, groups[j], m_group_patterns[j], m_summand_patterns, m_variable_order);
162 for (std::size_t i = 0; i < m_lts.summand_groups.size(); i++)
164 mCRL2log(
log::debug) <<
"=== summand group " << i <<
" ===\n" << m_lts.summand_groups[i] << std::endl;
169 ldd relprod_impl(
const ldd& U,
const lps_summand_group& group, std::size_t i)
171 if (m_options.no_relprod)
173 ldd z = symbolic::alternative_relprod(U, group);
174 mCRL2log(
log::trace) <<
"relprod(" << i <<
", todo) = " << print_states(m_lts.data_index, z) << std::endl;
179 ldd z = relprod(U, group.L, group.Ir);
180 mCRL2log(
log::trace) <<
"relprod(" << i <<
", todo) = " << print_states(m_lts.data_index, z) << std::endl;
187 std::tuple<ldd, ldd, ldd> step(
const ldd& visited,
const ldd& todo,
bool learn_transitions =
true,
bool detect_deadlocks =
false)
189 using namespace sylvan::ldds;
190 auto& R = m_lts.summand_groups;
192 ldd todo1 = empty_set();
193 ldd potential_deadlocks = detect_deadlocks ? todo : empty_set();
195 if (!m_options.saturation)
198 todo1 = m_options.chaining ? todo : empty_set();
200 for (std::size_t i = 0; i < R.size(); i++)
202 if (learn_transitions)
204 ldd proj = project(m_options.chaining ? todo1 : todo, R[i].Ip);
205 learn_successors(i, R[i], m_options.cached ?
minus(proj, R[i].Ldomain) : proj);
207 mCRL2log(
log::trace) <<
"L =\n" << print_relation(m_lts.data_index, R[i].L, R[i].read, R[i].write) << std::endl;
210 todo1 =
union_(todo1, relprod_impl(m_options.chaining ? todo1 : todo, R[i], i));
212 if (detect_deadlocks)
214 potential_deadlocks =
minus(potential_deadlocks, relprev(todo1, R[i].L, R[i].Ir, potential_deadlocks));
224 for (std::size_t i = 0; i < R.size(); i++)
226 if (learn_transitions)
228 ldd proj = project(todo1, R[i].Ip);
229 learn_successors(i, R[i], m_options.cached ?
minus(proj, R[i].Ldomain) : proj);
231 mCRL2log(
log::trace) <<
"L =\n" << print_relation(m_lts.data_index, R[i].L, R[i].read, R[i].write) << std::endl;
238 todo1 =
union_(todo1, relprod_impl(todo1, R[i], i));
240 while (todo1 != todo1_old);
242 if (detect_deadlocks)
244 potential_deadlocks =
minus(potential_deadlocks, relprev(todo1, R[i].L, R[i].Ir, potential_deadlocks));
248 if (m_options.chaining)
253 for (std::size_t j = 0; j <= i; j++)
255 todo1 =
union_(todo1, relprod_impl(todo1, R[j], j));
258 while (todo1 != todo1_old);
264 return std::make_tuple(
union_(visited, todo),
minus(todo1, visited), potential_deadlocks);
269 using namespace sylvan::ldds;
270 auto& R = m_lts.summand_groups;
271 std::size_t iteration_count = 0;
275 auto start = std::chrono::steady_clock::now();
276 ldd x = m_lts.initial_state;
277 std::chrono::duration<double> elapsed_seconds = std::chrono::steady_clock::now() - start;
278 ldd visited = empty_set();
280 ldd deadlocks = empty_set();
282 while (todo != empty_set() && (m_options.max_iterations == 0 || iteration_count < m_options.max_iterations))
287 mCRL2log(
log::trace) <<
"todo = " << print_states(m_lts.data_index, todo) << std::endl;
289 std::tie(visited, todo, deadlocks) = step(visited, todo,
true, m_options.detect_deadlocks);
292 << std::setw(3) << iteration_count <<
" iterations (time = " << std::setprecision(2)
293 << std::fixed << loop_start.
seconds() <<
"s)" << std::endl;
294 if (m_options.detect_deadlocks)
296 mCRL2log(
log::verbose) <<
"found " << std::setw(12) << print_size(deadlocks) <<
" deadlocks" << std::endl;
299 sylvan::sylvan_stats_report(stderr);
302 elapsed_seconds = std::chrono::steady_clock::now() - start;
303 std::cout <<
"number of states = " << print_size(visited) <<
" (time = " << std::setprecision(2) << std::fixed << elapsed_seconds.count() <<
"s)" << std::endl;
306 double total_time = 0.0;
307 for (std::size_t i = 0; i < R.size(); i++)
309 mCRL2log(
log::verbose) <<
"group " << std::setw(4) << i <<
" contains " << std::setw(10) << print_size(R[i].L) <<
" transitions (learn time = "
310 << std::setw(5) << std::setprecision(2) << std::fixed << R[i].learn_time <<
"s with " << std::setw(9) << R[i].learn_calls
311 <<
" calls, cached " << print_size(R[i].Ldomain) <<
" values" <<
")" << std::endl;
313 total_time += R[i].learn_time;
318 for (
const auto& param : m_lts.process_parameters)
320 auto& table = m_lts.data_index[i];
323 for (
const auto& data : table)
331 mCRL2log(
log::verbose) <<
"There are " << m_lts.action_index.size() <<
" action labels" << std::endl;
332 for (
const auto& action : m_lts.action_index)
334 mCRL2log(
log::debug) << m_lts.action_index.index(action) <<
": " << action << std::endl;
337 m_lts.states = visited;
341 const std::vector<boost::dynamic_bitset<>>& read_write_patterns()
const
343 return m_summand_patterns;
346 const std::vector<boost::dynamic_bitset<>>& read_write_group_patterns()
const
348 return m_group_patterns;
351 std::vector<symbolic::data_expression_index>& data_index()
353 return m_lts.data_index;
356 utilities::indexed_set<lps::multi_action>& action_index()
358 return m_lts.action_index;
361 const symbolic_lts& get_symbolic_lts()
size_type size() const
Returns the size of the term_list.
Implements a simple stopwatch that starts on construction.
static RewriterCompilingJitty::substitution_type & sigma(RewriterCompilingJitty *this_rewriter)
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
add your file description here.
IO routines for linear process specifications.
add your file description here.
add your file description here.
std::string print_list(const Container &v, const std::string &message="", bool print_index=false, bool boundary_spaces=true)
Creates a string representation of a container.
std::string print_set(const Container &v, const std::string &message="", bool print_index=false, bool boundary_spaces=true)
Creates a string representation of a container.
function_symbol union_(const sort_expression &s, const sort_expression &s0, const sort_expression &s1)
function_symbol minus(const sort_expression &s0, const sort_expression &s1)
rewrite_strategy
The strategy of the rewriter.
atermpp::term_list< data_expression > data_expression_list
\brief list of data_expressions
data::mutable_map_substitution instantiate_global_variables(Specification &lpsspec)
Eliminates the global variables of an LPS, by substituting a constant value for them....
The main namespace for the LPS library.
void find_function_symbols(const T &x, OutputIterator o)
void replace_constants_by_variables(T &x, const data::rewriter &r, data::mutable_indexed_substitution<> &sigma, typename std::enable_if<!std::is_base_of< atermpp::aterm, T >::value >::type *=nullptr)
Replace each constant data application c in x by a fresh variable v, and add extend the substitution ...
void order_summand_variables(Specification &lpsspec)
Order summand variables to make enumeration over these variables more efficient.
void resolve_summand_variable_name_clashes(Specification &spec)
Renames summand variables such that there are no name clashes between summand variables and process p...
void one_point_rule_rewrite(T &x, typename std::enable_if<!std::is_base_of< atermpp::aterm, T >::value >::type *=nullptr)
Applies the one point rule rewriter to all embedded data expressions in an object x.
const data::data_expression_list & param(const pbes_expression &t)
Returns the parameters of a propositional variable instantiation.
std::vector< std::set< std::size_t > > compute_summand_groups(const std::string &text, const std::vector< boost::dynamic_bitset<> > &patterns)
std::string print_read_write_patterns(const std::vector< boost::dynamic_bitset<> > &patterns)
std::vector< boost::dynamic_bitset<> > reorder_read_write_patterns(const std::vector< boost::dynamic_bitset<> > &patterns, const std::vector< std::size_t > &variable_order)
std::vector< std::size_t > compute_variable_order(const std::string &text, std::size_t number_of_variables, const std::vector< boost::dynamic_bitset<> > &summand_groups, bool exclude_first_variable=false)
std::vector< boost::dynamic_bitset<> > compute_summand_group_patterns(const std::vector< boost::dynamic_bitset<> > &patterns, const std::vector< std::set< std::size_t > > groups)
void adjust_read_write_patterns(std::vector< boost::dynamic_bitset<> > &patterns, const Options &options)
std::vector< T > as_vector(const std::set< T > &x)
add your file description here.
add your file description here.