mCRL2
Loading...
Searching...
No Matches
enumerator_with_iterator.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//
11
12#ifndef MCRL2_DATA_ENUMERATOR_WITH_ITERATOR_H
13#define MCRL2_DATA_ENUMERATOR_WITH_ITERATOR_H
14
17
18namespace mcrl2 {
19
20namespace data {
21
23{
24 bool operator()(const data_expression& x) const
25 {
27 }
28};
29
31{
32 bool operator()(const data_expression& x) const
33 {
35 }
36};
37
39template <typename Rewriter = data::rewriter, typename DataRewriter = data::rewriter>
41{
42 protected:
44 using super::r;
45 using super::R;
46 using super::dataspec;
49 using super::rewrite;
50
53
54 template <typename EnumeratorListElement>
55 void cannot_enumerate(EnumeratorListElement& e, const std::string& msg) const
56 {
57 e.invalidate();
59 {
60 throw mcrl2::runtime_error(msg);
61 }
62 }
63
64 // add element without additional variables
65 template <typename EnumeratorListElement, typename MutableSubstitution, typename Filter, typename Expression>
67 MutableSubstitution& sigma,
68 Filter accept,
69 const data::variable_list& variables,
70 const Expression& phi,
71 const EnumeratorListElement& p,
72 const data::variable& v,
73 const data::data_expression& e) const
74 {
75 auto phi1 = rewrite(phi, sigma);
76 if (accept(phi1))
77 {
78 P.push_back(EnumeratorListElement(variables, phi1, p, v, e));
79 }
80 }
81
82 // add element with additional variables
83 template <typename EnumeratorListElement, typename MutableSubstitution, typename Filter, typename Expression>
85 MutableSubstitution& sigma,
86 Filter accept,
87 const data::variable_list& variables,
88 const data::variable_list& added_variables,
89 const Expression& phi,
90 const EnumeratorListElement& p,
91 const data::variable& v,
92 const data::data_expression& e) const
93 {
94 auto phi1 = rewrite(phi, sigma);
95 if (accept(phi1))
96 {
97 // Additional variables are put at the end of the list!
98 P.push_back(EnumeratorListElement(variables + added_variables, phi1, p, v, e));
99 }
100 }
101
102 // specialization for enumerator_list_element; in this case we are not interested in the substitutions,
103 // and this allows an optimization
104 template <typename MutableSubstitution, typename Filter, typename Expression>
106 MutableSubstitution& sigma,
107 Filter accept,
108 const data::variable_list& variables,
109 const data::variable_list& added_variables,
110 const Expression& phi,
112 const data::variable& v,
113 const data::data_expression& e) const
114 {
115 auto phi1 = rewrite(phi, sigma);
116 if (accept(phi1))
117 {
118 if (phi1 == phi)
119 {
120 // Discard the added_variables, since we know they do not appear in phi1
121 P.push_back(enumerator_list_element<Expression>(variables, phi1, p, v, e));
122 }
123 else
124 {
125 // Additional variables are put at the end of the list!
126 P.push_back(enumerator_list_element<Expression>(variables + added_variables, phi1, p, v, e));
127 }
128 //mCRL2log(log::debug) << " <add-element> " << P.back() << " with assignment " << v << " := " << e << std::endl;
129 }
130 }
131
132 public:
135 const DataRewriter& r,
137 std::size_t max_count = (std::numeric_limits<std::size_t>::max)(),
138 bool throw_exceptions = false
139 )
141 {}
142
144
145 template <typename T>
147 {
148 bool operator()(const T&) { return false; }
149 };
150
156 template <typename EnumeratorListElement, typename MutableSubstitution, typename Filter>
157 void step(enumerator_queue<EnumeratorListElement>& P, MutableSubstitution& sigma, Filter accept) const
158 {
159 assert(!P.empty());
160
161 auto p = P.front();
162 const auto& v = p.variables();
163 const auto& phi = p.expression();
164 //mCRL2log(log::debug) << " <process-element> " << p << std::endl;
165 P.pop_front();
166
167 const auto& v1 = v.front();
168 const auto& v_tail = v.tail();
169 const auto& v1_sort = v1.sort();
170
171 if (data::is_function_sort(v1_sort))
172 {
173 const function_sort& function = atermpp::down_cast<function_sort>(v1_sort);
174 if (dataspec.is_certainly_finite(function))
175 {
176 data_expression_vector function_sorts;
177 variable_list function_parameter_list;
178 bool result = detail::compute_finite_function_sorts(function, id_generator, dataspec, r, function_sorts, function_parameter_list);
179 if (!result)
180 {
181 cannot_enumerate(p, "Sort " + data::pp(v1_sort) + " has too many elements to enumerate.");
182 }
183
184 data_expression sigma_v1 = sigma(v1);
185 for (const data_expression& f: function_sorts)
186 {
187 sigma[v1] = f;
188 add_element(P, sigma, accept, v_tail, phi, p, v1, f);
189 }
190 sigma[v1] = sigma_v1;
191 }
192 else
193 {
194 cannot_enumerate(p, "Cannot enumerate elements of function sort " + data::pp(v1_sort) + ".");
195 }
196 }
197 else if (sort_set::is_set(v1_sort))
198 {
199 const sort_expression& element_sort = atermpp::down_cast<container_sort>(v1_sort).element_sort();
200 if (dataspec.is_certainly_finite(element_sort))
201 {
202 const data_expression lambda_term = abstraction(lambda_binder(), { variable(id_generator(), element_sort) }, sort_bool::false_());
203 const variable fset_variable(id_generator(), sort_fset::fset(element_sort));
204 data_expression e = sort_set::constructor(element_sort, lambda_term, fset_variable);
205 data_expression sigma_v1 = sigma(v1);
206 sigma[v1] = e;
207 add_element(P, sigma, accept, v_tail, { fset_variable }, phi, p, v1, e);
208 sigma[v1] = sigma_v1;
209 }
210 else
211 {
212 cannot_enumerate(p, "Cannot enumerate elements of set sort " + data::pp(v1_sort) + ".");
213 return;
214 }
215 }
216 else if (sort_fset::is_fset(v1_sort))
217 {
218 const auto& fset = atermpp::down_cast<container_sort>(v1_sort);
220 {
221 data_expression_vector set_elements;
222 bool result = detail::compute_finite_set_elements(fset, dataspec, r, sigma, set_elements, id_generator);
223 if (!result)
224 {
225 cannot_enumerate(p, "Finite set sort " + data::pp(v1_sort) + " has too many elements to enumerate.");
226 }
227
228 data_expression sigma_v1 = sigma(v1);
229 for (const data_expression& e: set_elements)
230 {
231 sigma[v1] = e;
232 add_element(P, sigma, accept, v_tail, phi, p, v1, e);
233 }
234 sigma[v1] = sigma_v1;
235 }
236 else
237 {
238 cannot_enumerate(p, "Cannot enumerate elements of finite set sort " + data::pp(v1_sort) + ".");
239 return;
240 }
241 }
242 else if (sort_bag::is_bag(v1_sort))
243 {
244 cannot_enumerate(p, "Cannot enumerate elements of bag sort " + data::pp(v1_sort) + ".");
245 return;
246 }
247 else if (sort_fbag::is_fbag(v1_sort))
248 {
249 cannot_enumerate(p, "Cannot enumerate elements of finite bag sort " + data::pp(v1_sort) + ".");
250 return;
251 }
252 else
253 {
254 const function_symbol_vector& C = dataspec.constructors(v1_sort);
255 if (!C.empty())
256 {
257 for (const function_symbol& c: C)
258 {
259 if (data::is_function_sort(c.sort()))
260 {
261 auto const& domain = atermpp::down_cast<data::function_sort>(c.sort()).domain();
262 data::variable_list y(domain.begin(), domain.end(), [&](const data::sort_expression& s) { return data::variable(id_generator(), s); });
263 // TODO: We want to apply datar without the substitution sigma, but that is currently an inefficient operation of data::rewriter.
264 data_expression cy = r(application(c, y.begin(), y.end()), sigma);
265 sigma[v1] = cy;
266 add_element(P, sigma, accept, v_tail, y, phi, p, v1, cy);
267 sigma[v1] = v1;
268 }
269 else
270 {
271 // TODO: We want to apply r without the substitution sigma, but that is currently an inefficient operation of data::rewriter.
272 const auto e1 = r(c, sigma);
273 sigma[v1] = e1;
274 add_element(P, sigma, accept, v_tail, phi, p, v1, e1);
275 sigma[v1] = v1;
276 }
277 }
278 }
279 else
280 {
281 cannot_enumerate(p, "Cannot enumerate elements of sort " + data::pp(v1_sort) + " without constructors.");
282 return;
283 }
284 }
285 }
286
294 template <typename EnumeratorListElement, typename MutableSubstitution, typename Filter>
295 std::size_t next(enumerator_queue<EnumeratorListElement>& P, MutableSubstitution& sigma, Filter accept) const
296 {
297 std::size_t count = 0;
298 while (!P.empty())
299 {
300 if (count++ >= m_max_count)
301 {
302 break;
303 }
304 if (P.front().is_solution())
305 {
306 break;
307 }
308 else
309 {
310 step(P, sigma, accept);
311 }
312 }
313 return count;
314 }
315
316 bool throw_exceptions() const
317 {
318 return m_throw_exceptions;
319 }
320};
321
323template <typename Rewriter = data::rewriter, typename EnumeratorListElement = enumerator_list_element_with_substitution<>, typename Filter = data::is_not_false, typename DataRewriter = data::rewriter, typename MutableSubstitution = data::mutable_indexed_substitution<> >
325{
326 protected:
327 Filter m_accept;
328
329 public:
331 using super::rewrite;
332
336 class iterator: public boost::iterator_facade<iterator, const EnumeratorListElement, boost::forward_traversal_tag>
337 {
338 protected:
340 MutableSubstitution* sigma;
342 Filter accept;
343 std::size_t count;
344
346 {
347#ifdef MCRL2_ENABLE_MULTITHREADING
349 thread_local enumerator_queue<EnumeratorListElement> result; // Changed this static variable to thread local,
350 // as it could be the cause of a thread conflict.
351#else
353 static enumerator_queue<EnumeratorListElement> result; // Changed this static variable to thread local,
354#endif
355 return result;
356 }
357
358 public:
361 MutableSubstitution* sigma_,
362 Filter accept_ = Filter()
363 )
364 : E(E_), sigma(sigma_), P(P_), accept(accept_), count(0)
365 {
366 count += E->next(*P, *sigma, accept);
367 }
368
369 explicit iterator(Filter accept_ = Filter())
370 : E(nullptr), sigma(nullptr), P(&default_deque()), accept(accept_), count(0)
371 { }
372
373 protected:
375
377 {
378 assert(!P->empty());
379 P->pop_front();
380 count += E->next(*P, *sigma, accept);
381 if (count >= E->max_count())
382 {
383 if (E->throw_exceptions())
384 {
385 std::ostringstream out;
386 out << "enumeration was aborted, since it did not complete within " << E->max_count() << " iterations";
387 throw mcrl2::runtime_error(out.str());
388 }
389 else
390 {
391 P->clear();
392 return;
393 }
394 }
395 }
396
397 bool equal(iterator const& other) const
398 {
399 return P->size() == other.P->size();
400 }
401
402 const EnumeratorListElement& dereference() const
403 {
404 assert(!P->empty());
405 return P->front();
406 }
407 };
408
410 const Rewriter& R,
412 const DataRewriter& datar,
414 std::size_t max_count = (std::numeric_limits<std::size_t>::max)(),
415 bool throw_exceptions = false,
416 const Filter& f = Filter())
418 , m_accept(f)
419 {}
420
426 {
427 assert(P.size() == 1);
428 auto& p = P.front();
429 p.expression() = rewrite(p.expression(), sigma);
430 if (m_accept(p.expression()))
431 {
433 }
434 else
435 {
436 return end();
437 }
438 }
439
440 const iterator& end()
441 {
442#ifdef MCRL2_ENABLE_MULTITHREADING
444 thread_local iterator result(m_accept);
445#else
447 static iterator result(m_accept);
448#endif
449 return result;
450 }
451};
452
453} // namespace data
454
455} // namespace mcrl2
456
457#endif // MCRL2_DATA_ENUMERATOR_WITH_ITERATOR_H
const_iterator end() const
Returns a const_iterator pointing to the end of the term_list.
Definition aterm_list.h:282
const_iterator begin() const
Returns a const_iterator pointing to the beginning of the term_list.
Definition aterm_list.h:275
An abstraction expression.
Definition abstraction.h:26
An application of a data expression to a number of arguments.
const sort_expression & element_sort() const
bool is_certainly_finite(const sort_expression &s) const
Checks whether a sort is certainly finite.
const function_symbol_vector & constructors() const
Gets all constructors including those that are system defined.
enumerator_algorithm_with_iterator< Rewriter, EnumeratorListElement, Filter, DataRewriter, MutableSubstitution > * E
static enumerator_queue< EnumeratorListElement > & default_deque()
iterator(enumerator_algorithm_with_iterator< Rewriter, EnumeratorListElement, Filter, DataRewriter, MutableSubstitution > *E_, enumerator_queue< EnumeratorListElement > *P_, MutableSubstitution *sigma_, Filter accept_=Filter())
An enumerator algorithm with an iterator interface.
enumerator_algorithm_without_callback< Rewriter, DataRewriter > super
iterator begin(MutableSubstitution &sigma, enumerator_queue< EnumeratorListElement > &P)
Returns an iterator that enumerates solutions for variables that satisfy a condition.
enumerator_algorithm_with_iterator(const Rewriter &R, const data::data_specification &dataspec, const DataRewriter &datar, enumerator_identifier_generator &id_generator, std::size_t max_count=(std::numeric_limits< std::size_t >::max)(), bool throw_exceptions=false, const Filter &f=Filter())
An enumerator algorithm that generates solutions of a condition.
void add_element(enumerator_queue< EnumeratorListElement > &P, MutableSubstitution &sigma, Filter accept, const data::variable_list &variables, const data::variable_list &added_variables, const Expression &phi, const EnumeratorListElement &p, const data::variable &v, const data::data_expression &e) const
void add_element(enumerator_queue< enumerator_list_element< Expression > > &P, MutableSubstitution &sigma, Filter accept, const data::variable_list &variables, const data::variable_list &added_variables, const Expression &phi, const enumerator_list_element< Expression > &p, const data::variable &v, const data::data_expression &e) const
enumerator_algorithm< Rewriter, DataRewriter > super
std::size_t next(enumerator_queue< EnumeratorListElement > &P, MutableSubstitution &sigma, Filter accept) const
Enumerates the front elements of the todo list P until a solution has been found, or until P is empty...
enumerator_algorithm_without_callback(const enumerator_algorithm< Rewriter, DataRewriter > &)=delete
void step(enumerator_queue< EnumeratorListElement > &P, MutableSubstitution &sigma, Filter accept) const
Enumerates the front element of the todo list P.
bool m_throw_exceptions
throw_exceptions If true, an exception is thrown when the enumeration is aborted.
void add_element(enumerator_queue< EnumeratorListElement > &P, MutableSubstitution &sigma, Filter accept, const data::variable_list &variables, const Expression &phi, const EnumeratorListElement &p, const data::variable &v, const data::data_expression &e) const
enumerator_algorithm_without_callback(const Rewriter &R, const data::data_specification &dataspec, const DataRewriter &r, enumerator_identifier_generator &id_generator, std::size_t max_count=(std::numeric_limits< std::size_t >::max)(), bool throw_exceptions=false)
void cannot_enumerate(EnumeratorListElement &e, const std::string &msg) const
An enumerator algorithm that generates solutions of a condition.
Definition enumerator.h:601
std::size_t m_max_count
max_count The enumeration is aborted after max_count iterations
Definition enumerator.h:616
const data::data_specification & dataspec
A data specification.
Definition enumerator.h:607
Expression rewrite(const Expression &phi, MutableSubstitution &sigma) const
Definition enumerator.h:634
The default element for the todo list of the enumerator.
Definition enumerator.h:231
Contains the enumerator queue.
Definition enumerator.h:501
atermpp::deque< EnumeratorListElement >::size_type size() const
Definition enumerator.h:555
void push_back(const EnumeratorListElement &x)
Definition enumerator.h:528
const EnumeratorListElement & front() const
Definition enumerator.h:560
\brief A function sort
\brief A function symbol
\brief Binder for lambda abstraction
\brief A sort expression
\brief A data variable
Definition variable.h:28
Standard exception class for reporting runtime errors.
Definition exception.h:27
The class enumerator.
static RewriterCompilingJitty::substitution_type & sigma(RewriterCompilingJitty *this_rewriter)
bool compute_finite_function_sorts(const function_sort &sort, enumerator_identifier_generator &id_generator, const data::data_specification &dataspec, Rewriter datar, data_expression_vector &result, variable_list &function_parameter_list)
Computes the elements of a finite function sort, and puts them in result. If there are too many eleme...
Definition enumerator.h:109
bool compute_finite_set_elements(const container_sort &sort, const data_specification &dataspec, Rewriter datar, MutableSubstitution &sigma, data_expression_vector &result, enumerator_identifier_generator &id_generator)
Computes the elements of a finite set sort, and puts them in result. If there are too many elements,...
Definition enumerator.h:82
bool is_bag(const sort_expression &e)
Recogniser for sort expression Bag(s)
Definition bag1.h:55
bool is_false_function_symbol(const atermpp::aterm &e)
Recogniser for function false.
Definition bool.h:119
const function_symbol & false_()
Constructor for function symbol false.
Definition bool.h:109
bool is_true_function_symbol(const atermpp::aterm &e)
Recogniser for function true.
Definition bool.h:87
bool is_fbag(const sort_expression &e)
Recogniser for sort expression FBag(s)
Definition fbag1.h:54
bool is_fset(const sort_expression &e)
Recogniser for sort expression FSet(s)
Definition fset1.h:52
container_sort fset(const sort_expression &s)
Constructor for sort expression FSet(S)
Definition fset1.h:41
bool is_set(const sort_expression &e)
Recogniser for sort expression Set(s)
Definition set1.h:53
function_symbol constructor(const sort_expression &s)
Constructor for function symbol @set.
Definition set1.h:76
std::vector< data_expression > data_expression_vector
\brief vector of data_expressions
std::string pp(const abstraction &x)
Definition data.cpp:39
bool is_function_sort(const atermpp::aterm &x)
Returns true if the term t is a function sort.
std::vector< function_symbol > function_symbol_vector
\brief vector of function_symbols
static constexpr bool GlobalThreadSafe
Enables thread safety for the whole toolset.
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
Definition indexed_set.h:72
bool operator()(const data_expression &x) const
bool operator()(const data_expression &x) const