mCRL2
Loading...
Searching...
No Matches
pbesinst_lazy.h
Go to the documentation of this file.
1// Author(s): Wieger Wesselink 2017-2019
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//
11
12#include <thread>
13#include <mutex>
14
29
30#ifndef MCRL2_PBES_PBESINST_LAZY_H
31#define MCRL2_PBES_PBESINST_LAZY_H
32
33namespace mcrl2
34{
35
36namespace pbes_system
37{
38
39// This todo set maintains elements that were removed by the reset procedure.
41{
42 protected:
43 std::unordered_set<propositional_variable_instantiation> irrelevant;
45
46 // checks some invariants on the internal state
47 bool check_invariants() const
48 {
50 for (const auto& X: irrelevant)
51 {
52 if (contains(todo, X))
53 {
54 return false;
55 }
56 }
57 std::unordered_set<propositional_variable_instantiation> tmp(todo.begin(), todo.end());
58 return tmp.size() == todo.size();
59 }
60
61 public:
63 {
64 return todo.front();
65 }
66
68 {
69 return todo.back();
70 }
71
72 bool empty() const
73 {
74 return todo.empty() && irrelevant.empty();
75 }
76
77 std::size_t size() const
78 {
79 return todo.size();
80 }
81
83 {
84 return todo;
85 }
86
87 const std::unordered_set<propositional_variable_instantiation>& irrelevant_elements() const
88 {
89 return irrelevant;
90 }
91
92 std::unordered_set<propositional_variable_instantiation>& irrelevant_elements()
93 {
94 return irrelevant;
95 }
96
97 void pop_front()
98 {
99 todo.pop_front();
100 }
101
102 void pop_back()
103 {
104 todo.pop_back();
105 }
106
108 {
109 irrelevant.erase(x);
110 todo.push_back(x);
111 }
112
113 template <typename FwdIter, bool ThreadSafe>
114 void insert(FwdIter first,
115 FwdIter last,
117 const std::size_t thread_index)
118 {
120
121 for (FwdIter i = first; i != last; ++i)
122 {
123 auto j = irrelevant.find(*i);
124 if (j != irrelevant.end())
125 {
126 todo.push_back(*j);
127 irrelevant.erase(j);
128 }
129 else if (!contains(discovered, *i, thread_index))
130 {
131 todo.push_back(*i);
132 }
133 }
134 }
135
137 {
139 std::size_t size_before = todo.size() + irrelevant.size();
140 std::unordered_set<propositional_variable_instantiation> new_irrelevant;
142 {
143 if (!contains(new_todo, x))
144 {
145 new_irrelevant.insert(x);
146 }
147 }
149 {
150 if (!contains(new_todo, x))
151 {
152 new_irrelevant.insert(x);
153 }
154 }
155 std::swap(todo, new_todo);
156 std::swap(irrelevant, new_irrelevant);
157
158 std::size_t size_after = todo.size() + irrelevant.size();
159 if (size_before != size_after)
160 {
161 throw mcrl2::runtime_error("sizes do not match in pbesinst_lazy_todo::set_todo");
162 }
163 assert(check_invariants());
164 }
165};
166
167inline
168std::ostream& operator<<(std::ostream& out, const pbesinst_lazy_todo& todo)
169{
170 return out << "todo = " << core::detail::print_list(todo.elements()) << " irrelevant = " << core::detail::print_list(todo.irrelevant_elements()) << std::endl;
171}
172
175{
176 protected:
179
182
185
188
191
194
197
198 // \brief The number of iterations
199 std::size_t m_iteration_count = 0;
200
201 // The data structures that must be separate per thread.
204
205 // Mutexes
207
208 volatile bool m_must_abort = false;
209
210 // \brief Returns a status message about the progress
211 virtual std::string status_message(std::size_t equation_count)
212 {
213 if (equation_count > 0 && equation_count % 1000 == 0)
214 {
215 std::ostringstream out;
216 out << "Generated " << equation_count << " BES equations" << std::endl;
217 return out.str();
218 }
219 return "";
220 }
221
222 // instantiates global variables
223 // simplifies the pbes
224 pbes preprocess(const pbes& x) const
225 {
226 pbes p = x;
230 for (pbes_equation& eqn: p.equations())
231 {
232 eqn.formula() = order_quantified_variables(one_point_rule_rewriter(simplify_rewriter(eqn.formula())), p.data());
233 }
234 return p;
235 }
236
238 const fixpoint_symbol& symbol,
240 const pbes_expression& psi
241 )
242 {
243 bool changed = false;
245 result,
246 psi,
248 {
249 if (Y == X)
250 {
251 changed = true;
252 if (symbol.is_mu())
253 {
254 return false_();
255 }
256 else
257 {
258 return true_();
259 }
260 }
261 return Y;
262 }
263 );
264 if (changed)
265 {
267 const pbes_expression result1=result;
268 simplify(result, result1);
269 }
270 }
271
273 {
275 {
276 return data::rewriter(pbesspec.data(),
279 }
280 else
281 {
282 return data::rewriter(pbesspec.data(), m_options.rewrite_strategy);
283 }
284 }
285
286 public:
287
294 const pbessolve_options& options,
295 const pbes& p
296 )
297 : m_options(options),
299 m_pbes(preprocess(p)),
301 discovered(m_options.number_of_threads),
302 m_global_R(datar, p.data())
303 { }
304
305 virtual ~pbesinst_lazy_algorithm() = default;
306
309 virtual void on_report_equation(const std::size_t /* thread_index */,
311 const pbes_expression& /* psi */, std::size_t /* k */
312 )
313 { }
314
316 virtual void on_discovered_elements(const std::set<propositional_variable_instantiation>& /* elements */)
317 { }
318
320 virtual void on_end_while_loop()
321 { }
322
324 {
326 {
327 result = todo.front();
328 todo.pop_front();
329 }
330 else
331 {
332 result = todo.back();
333 todo.pop_back();
334 }
335 }
336
337 const fixpoint_symbol& symbol(std::size_t i) const
338 {
339 return m_pbes.equations()[i].symbol();
340 }
341
342 // rewrite the right hand side of the equation X = psi
343 virtual void rewrite_psi(const std::size_t /* thread_index */,
344 pbes_expression& result,
345 const fixpoint_symbol& symbol,
347 const pbes_expression& psi
348 )
349 {
350 if (m_options.optimization >= 1)
351 {
352 rewrite_true_false(result, symbol, X, psi);
353 }
354 else
355 {
356 result = psi;
357 }
358 }
359
360 virtual bool solution_found(const propositional_variable_instantiation& /* init */) const
361 {
362 return false;
363 }
364
365 virtual void run_thread(const std::size_t thread_index,
367 std::atomic<std::size_t>& number_of_active_processes,
370 )
371 {
373
374 if (m_options.number_of_threads > 1) mCRL2log(log::debug) << "Start thread " << thread_index << ".\n";
376
378 pbes_expression psi_e;
379
380 while (number_of_active_processes > 0)
381 {
383 while (!todo.elements().empty() && !m_must_abort)
384 {
388
389 next_todo(X_e);
391
392 std::size_t index = m_equation_index.index(X_e.name());
393 const pbes_equation& eqn = m_pbes.equations()[index];
394 const auto& phi = eqn.formula();
396 R(psi_e, phi, sigma);
399
400 // optional step
402 rewrite_psi(thread_index, psi_e, eqn.symbol(), X_e, psi_e);
404
405 std::set<propositional_variable_instantiation> occ = find_propositional_variable_instantiations(psi_e);
406
407 // report the generated equation
408 std::size_t k = m_equation_index.rank(X_e.name());
410 mCRL2log(log::debug) << "generated equation " << X_e << " = " << psi_e
411 << " with rank " << k << std::endl;
412 on_report_equation(thread_index, X_e, psi_e, k);
413 todo.insert(occ.begin(), occ.end(), discovered, thread_index);
414 for (auto i = occ.begin(); i != occ.end(); ++i)
415 {
416 discovered.insert(*i, thread_index);
417 }
419
420 if (solution_found(init))
421 {
422 break;
423 }
424 }
426
427 // Check whether all processes are ready. If so the
428 // number_of_active_processes becomes 0. Otherwise, this thread becomes
429 // active again, and tries to see whether the todo buffer is not empty,
430 // to take up more work.
431 number_of_active_processes--;
432 std::this_thread::sleep_for(std::chrono::milliseconds(100));
433 if (number_of_active_processes > 0)
434 {
435 number_of_active_processes++;
436 }
437 }
438
439 if (m_options.number_of_threads>1) mCRL2log(log::debug) << "Stop thread " << thread_index << ".\n";
440 }
441
443 virtual void run()
444 {
446
447 const std::size_t number_of_threads = m_options.number_of_threads;
448 const std::size_t initialisation_thread_index = (number_of_threads==1?0:1);
449 std::atomic<std::size_t> number_of_active_processes = number_of_threads;
450 std::vector<std::thread> threads;
451
454 {
456 }
457
458 init = atermpp::down_cast<propositional_variable_instantiation>(m_global_R(m_pbes.initial_state(), sigma));
460 discovered.insert(init, initialisation_thread_index);
461
462 if (number_of_threads>1)
463 {
464 threads.reserve(number_of_threads);
465 for (std::size_t i = 1; i <= number_of_threads; ++i)
466 {
467 std::thread tr([&, i](){
468 run_thread(i,
469 todo,
470 number_of_active_processes,
471 sigma.clone(),
473 );
474 });
475 threads.push_back(std::move(tr));
476 }
477
478 for (std::size_t i = 1; i <= number_of_threads; ++i)
479 {
480 threads[i-1].join();
481 }
482 }
483 else
484 {
485 // There is only one thread. Run the process in the main thread, without cloning sigma or the rewriter.
486 const std::size_t single_thread_index=0;
487 run_thread(single_thread_index,
488 todo,
489 number_of_active_processes,
490 sigma,
492 );
493 }
495 }
496
498 {
499 return m_equation_index;
500 }
501
503 {
504 return m_global_R;
505 }
506};
507
508} // namespace pbes_system
509
510} // namespace mcrl2
511
512#endif // MCRL2_PBES_PBESINST_LAZY_H
A global variable for counting the number of BES equations in pbesinst and parity_game_generator....
A deque class in which aterms can be stored.
Definition deque.h:34
A set that assigns each element an unique index, and protects its internal terms en masse.
Definition indexed_set.h:30
Rewriter that operates on data expressions.
Definition rewriter.h:81
Component for selecting a subset of equations that are actually used in an encompassing specification...
Definition selection.h:37
bool is_mu() const
Returns true if the symbol is mu.
A rewriter that applies one point rule quantifier elimination to a PBES.
const pbes_expression & formula() const
Returns the predicate formula on the right hand side of the equation.
const fixpoint_symbol & symbol() const
Returns the fixpoint symbol of the equation.
const propositional_variable & variable() const
Returns the pbes variable of the equation.
parameterized boolean equation system
Definition pbes.h:58
const data::data_specification & data() const
Returns the data specification.
Definition pbes.h:150
const propositional_variable_instantiation & initial_state() const
Returns the initial state.
Definition pbes.h:192
const std::set< data::variable > & global_variables() const
Returns the declared free variables of the pbes.
Definition pbes.h:178
const std::vector< pbes_equation > & equations() const
Returns the equations.
Definition pbes.h:164
A PBES instantiation algorithm that uses a lazy strategy.
const pbes_equation_index & equation_index() const
const pbessolve_options & m_options
Algorithm options.
void next_todo(propositional_variable_instantiation &result)
virtual void on_report_equation(const std::size_t, const propositional_variable_instantiation &, const pbes_expression &, std::size_t)
Reports BES equations that are produced by the algorithm. This function is called for every BES equat...
virtual void on_end_while_loop()
This function is called right after the while loop is finished.
virtual bool solution_found(const propositional_variable_instantiation &) const
virtual void rewrite_psi(const std::size_t, pbes_expression &result, const fixpoint_symbol &symbol, const propositional_variable_instantiation &X, const pbes_expression &psi)
data::rewriter construct_rewriter(const pbes &pbesspec)
pbesinst_lazy_todo todo
The propositional variable instantiations that need to be handled.
propositional_variable_instantiation init
The initial value (after rewriting).
virtual void on_discovered_elements(const std::set< propositional_variable_instantiation > &)
This function is called when new elements are added to discovered.
virtual void run()
Runs the algorithm. The result is obtained by calling the function get_result.
pbes_equation_index m_equation_index
A lookup map for PBES equations.
enumerate_quantifiers_rewriter m_global_R
The rewriter.
const fixpoint_symbol & symbol(std::size_t i) const
pbesinst_lazy_algorithm(const pbessolve_options &options, const pbes &p)
Constructor.
static void rewrite_true_false(pbes_expression &result, const fixpoint_symbol &symbol, const propositional_variable_instantiation &X, const pbes_expression &psi)
enumerate_quantifiers_rewriter & rewriter()
virtual std::string status_message(std::size_t equation_count)
atermpp::indexed_set< propositional_variable_instantiation, true > discovered
The propositional variable instantiations that have been discovered (not necessarily handled).
virtual void run_thread(const std::size_t thread_index, pbesinst_lazy_todo &todo, std::atomic< std::size_t > &number_of_active_processes, data::mutable_indexed_substitution<> sigma, enumerate_quantifiers_rewriter R)
atermpp::deque< propositional_variable_instantiation > todo
std::unordered_set< propositional_variable_instantiation > irrelevant
const propositional_variable_instantiation & back() const
void insert(const propositional_variable_instantiation &x)
const propositional_variable_instantiation & front() const
const atermpp::deque< propositional_variable_instantiation > & elements() const
void set_todo(atermpp::deque< propositional_variable_instantiation > &new_todo)
void insert(FwdIter first, FwdIter last, const atermpp::indexed_set< propositional_variable_instantiation, ThreadSafe > &discovered, const std::size_t thread_index)
std::unordered_set< propositional_variable_instantiation > & irrelevant_elements()
const std::unordered_set< propositional_variable_instantiation > & irrelevant_elements() const
\brief A propositional variable instantiation
const data::data_expression_list & parameters() const
const data::variable_list & parameters() const
Standard exception class for reporting runtime errors.
Definition exception.h:27
This is simply an exclusive lock based on the standard library with the ability to perform no locks w...
Definition mutex.h:23
static RewriterCompilingJitty::substitution_type & sigma(RewriterCompilingJitty *this_rewriter)
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:391
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.
void add_assignments(data::mutable_indexed_substitution<> &sigma, const VariableSequence &v, const DataExpressionSequence &e)
Adds assignments [v := e] to the substitution sigma for each variable in v.
void remove_assignments(data::mutable_indexed_substitution<> &sigma, const VariableSequence &v)
Removes assignments to variables in v from the substitution sigma.
data::mutable_map_substitution instantiate_global_variables(pbes &p)
Eliminates the global variables of a PBES, by substituting a constant value for them....
void check_bes_equation_limit(std::size_t size)
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 ...
std::ostream & operator<<(std::ostream &os, const absinthe_strategy strategy)
pbes_expression order_quantified_variables(const pbes_expression &x, const data::data_specification &dataspec)
void find_function_symbols(const T &x, OutputIterator o)
Definition find.h:173
void replace_propositional_variables(T &x, const Substitution &sigma, typename std::enable_if< !std::is_base_of< atermpp::aterm, T >::value >::type *=nullptr)
Applies a propositional variable substitution.
Definition replace.h:236
void find_propositional_variable_instantiations(Container const &container, OutputIterator o)
Returns all data variables that occur in a range of expressions.
Definition find.h:196
bool contains(const atermpp::indexed_set< Key, ThreadSafe, Hash, Equals, Allocator, KeyTable > &c, const typename atermpp::indexed_set< Key, ThreadSafe, Hash, Equals, Allocator, KeyTable >::key_type &v, const std::size_t thread_index=0)
Definition indexed_set.h:86
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
Definition indexed_set.h:72
void swap(atermpp::unprotected_aterm_core &t1, atermpp::unprotected_aterm_core &t2) noexcept
Swaps two aterms.
Definition aterm.h:462
add your file description here.
add your file description here.
add your file description here.
add your file description here.
add your file description here.
add your file description here.
add your file description here.
add your file description here.
void thread_initialise()
Initialises this rewriter with thread dependent information.
enumerate_quantifiers_rewriter clone()
Create a clone of the rewriter in which the underlying rewriter is copied, and not passed as a shared...
std::size_t index(const core::identifier_string &name) const
Returns the index of the equation of the variable with the given name.
std::size_t rank(const core::identifier_string &name) const
Returns the rank of the equation of the variable with the given name.
A rewriter that simplifies boolean expressions and quantifiers, and rewrites data expressions.
A rewriter that simplifies boolean expressions in a term.
add your file description here.
Strategies for the generation of a BES from a PBES.
add your file description here.