mCRL2
Loading...
Searching...
No Matches
pbesinst_finite_algorithm.h
Go to the documentation of this file.
1// Author(s): Wieger Wesselink; Alexander van Dam
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/pbes/pbesinst_finite_algorithm.h
10/// \brief add your file description here.
11
12#ifndef MCRL2_PBES_PBESINST_FINITE_ALGORITHM_H
13#define MCRL2_PBES_PBESINST_FINITE_ALGORITHM_H
14
15#include "mcrl2/atermpp/aterm.h"
16#include "mcrl2/data/consistency.h"
17#include "mcrl2/data/data_expression.h"
18#include "mcrl2/data/enumerator.h"
19#include "mcrl2/data/replace.h"
20#include "mcrl2/pbes/algorithms.h"
21#include "mcrl2/pbes/detail/pbes_parameter_map.h"
22#include "mcrl2/pbes/join.h"
23#include "mcrl2/pbes/rewriters/data_rewriter.h"
24
25namespace mcrl2::pbes_system
26{
27
28/// \brief Data structure for storing the indices of the variables that should be expanded by the finite pbesinst algorithm.
30
31/// \brief Data structure for storing the variables that should be expanded by the finite pbesinst algorithm.
33
34/// \brief Function object for renaming a propositional variable instantiation
36{
37 protected:
40
41 core::identifier_string rename(const core::identifier_string& name, const data::data_expression_list& parameters) const
42 {
43 std::ostringstream out;
44 out << std::string(name);
45 for (const data::data_expression& param: parameters)
46 {
47 out << "_" << data::pp(param);
48 }
49 return core::identifier_string(out.str());
50 }
51
52 public:
53 /// \brief Renames the propositional variable x.
54 core::identifier_string operator()(const core::identifier_string& name, const data::data_expression_list& parameters) const
55 {
57 auto i = m.find(P);
58 if (i == m.end())
59 {
60 core::identifier_string dest = rename(name, parameters);
61 if (id_generator.has_identifier(dest))
62 {
63 dest = id_generator(dest);
64 }
65 else
66 {
67 id_generator.add_identifier(dest);
68 }
69 m[P] = dest;
70 return dest;
71 }
72 else
73 {
74 return i->second;
75 }
76 }
77};
78
79/// \brief Exception that is used to signal an empty parameter selection
81{
82 explicit empty_parameter_selection(const std::string& msg)
84 {}
85};
86
87namespace detail
88{
89
90/// \brief Computes the subset with variables of finite sort and infinite.
91/// \param X A propositional variable instantiation
92/// \param index_map a container storing the indices of the variables that
93/// should be expanded by the finite pbesinst algorithm.
94/// \param finite A sequence of data expressions
95/// \param infinite A sequence of data expressions
96template <typename PropositionalVariable, typename Parameter>
97void split_parameters(const PropositionalVariable& X,
98 const pbesinst_index_map& index_map,
99 std::vector<Parameter>& finite,
100 std::vector<Parameter>& infinite
101 )
102{
103 auto pi = index_map.find(X.name());
104 assert(pi != index_map.end());
105 const std::vector<std::size_t>& v = pi->second;
106 auto i = X.parameters().begin();
107 std::size_t index = 0;
108 auto j = v.begin();
109 for (; i != X.parameters().end(); ++i, ++index)
110 {
111 if (j != v.end() && index == *j)
112 {
113 finite.push_back(*i);
114 ++j;
115 }
116 else
117 {
118 infinite.push_back(*i);
119 }
120 }
121}
122
123/// \brief Visitor that applies a propositional variable substitution to a pbes expression.
124template <typename DataRewriter, typename SubstitutionFunction>
125struct pbesinst_finite_builder: public pbes_system::detail::data_rewriter_builder<pbesinst_finite_builder<DataRewriter, SubstitutionFunction>, DataRewriter, SubstitutionFunction>
126{
127 using super = pbes_system::detail::data_rewriter_builder<pbesinst_finite_builder, DataRewriter, SubstitutionFunction>;
128 using super::apply;
129 using super::sigma;
130
135
136 pbesinst_finite_builder(const DataRewriter& R,
137 SubstitutionFunction& sigma,
138 const pbesinst_finite_rename& rho,
139 const data::data_specification& data_spec,
140 const pbesinst_index_map& index_map,
141 const pbesinst_variable_map& variable_map
142 )
143 : super(R, sigma),
144 m_rename(rho),
145 m_data_spec(data_spec),
148 {}
149
152 ) const
153 {
154 std::ostringstream out;
155 out << "<finite>";
156 for (const data::data_expression& e: finite_parameters)
157 {
158 out << e << " ";
159 }
160 out << "<infinite>";
161 for (const data::data_expression& e: infinite_parameters)
162 {
163 out << e << " ";
164 }
165 out << std::endl;
166 return out.str();
167 }
168
169 /// \brief Computes the condition 'for all i: variables[i] == expressions[i]'.
170 template <typename VariableContainer, typename ExpressionContainer>
171 data::data_expression make_condition(const VariableContainer& variables, const ExpressionContainer& expressions) const
172 {
173 assert(variables.size() == expressions.size());
174 if (variables.empty())
175 {
176 return data::true_();
177 }
178 auto vi = variables.begin();
179 auto ei = expressions.begin();
180 data::data_expression result = data::equal_to(*vi, *ei);
181 ++vi;
182 ++ei;
183 for (; vi != variables.end(); ++vi, ++ei)
184 {
185 result = data::and_(result, data::equal_to(*vi, *ei));
186 }
187 return result;
188 }
189
190 template <typename DataExpressionContainer>
191 data::data_expression_list rewrite_container(const DataExpressionContainer& v, const data::rewriter& rewr)
192 {
193 return data::data_expression_list(v.begin(), v.end(), [&](const data::data_expression& x) { return rewr(x); });
194 }
195
196 template <typename DataExpressionContainer>
197 data::data_expression_list rewrite_container(const DataExpressionContainer& v, const data::rewriter& rewr, const data::mutable_indexed_substitution<>& sigma)
198 {
199 return data::data_expression_list(v.begin(), v.end(), [&](const data::data_expression& x) { return rewr(x, sigma); });
200 }
201
202 template <class T>
204 {
205 using enumerator_element = data::enumerator_list_element_with_substitution<>;
206
207 // TODO: this code contains too much conversion between vectors and aterm lists
208 std::vector<data::data_expression> finite_parameters;
209 std::vector<data::data_expression> infinite_parameters;
210 split_parameters(x, m_index_map, finite_parameters, infinite_parameters);
211 mCRL2log(log::debug) << print_parameters(finite_parameters, infinite_parameters);
212 data::data_expression_list d(finite_parameters.begin(), finite_parameters.end());
213 data::data_expression_list e(infinite_parameters.begin(), infinite_parameters.end());
214 const core::identifier_string& Xi = x.name();
215 // x = Xi(d,e)
216
217 auto vi = m_variable_map.find(Xi);
218 std::vector<data::variable> di;
219 if (vi != m_variable_map.end())
220 {
221 di = vi->second;
222 }
223
224 std::set<pbes_expression> result_set;
225 bool accept_solutions_with_variables = false;
227 data::enumerator_algorithm<> E(super::R, m_data_spec, super::R, id_generator, accept_solutions_with_variables);
228 const data::variable_list di_list(di.begin(), di.end());
229 data::mutable_indexed_substitution<> local_sigma;
230 E.enumerate(enumerator_element(di_list, data::true_()),
231 local_sigma,
232 [&](const enumerator_element& p) {
233 data::mutable_indexed_substitution<> sigma_i;
234 p.add_assignments(di_list, sigma_i, super::R);
235 data::data_expression_list d_copy = rewrite_container(d, super::R, sigma);
236 data::data_expression_list e_copy = rewrite_container(e, super::R, sigma);
237 data::data_expression_list di_copy(di_list);
238 di_copy = data::replace_free_variables(di_copy, sigma_i);
239 data::data_expression c = make_condition(di_copy, d_copy);
240 core::identifier_string Y = m_rename(Xi, di_copy);
241 result_set.insert(and_(atermpp::down_cast<pbes_expression>(c), propositional_variable_instantiation(Y, e_copy)));
242 return false;
243 }
244 );
245 result = join_or(result_set.begin(), result_set.end());
246 }
247
248 /// \return Visits the initial state
250 {
251 std::vector<data::data_expression> finite_parameters_vector;
252 std::vector<data::data_expression> infinite_parameters_vector;
253 split_parameters(init, m_index_map, finite_parameters_vector, infinite_parameters_vector);
254
255 data::data_expression_list finite_parameters = rewrite_container(finite_parameters_vector, super::R);
256 data::data_expression_list infinite_parameters = rewrite_container(infinite_parameters_vector, super::R);
257 core::identifier_string X = m_rename(init.name(), finite_parameters);
258 return propositional_variable_instantiation(X, infinite_parameters);
259 }
260};
261
262} // namespace detail
263
264/// \brief Algorithm class for the finite pbesinst algorithm.
266{
267 protected:
268 /// \brief The strategy of the data rewriter.
270
271 /// \brief The number of generated equations.
273
274 /// \brief Identifier generator for the enumerator
276
277 /// \brief Returns true if the container contains the given element
278 void compute_index_map(const std::vector<pbes_equation>& equations,
279 const pbesinst_variable_map& variable_map,
280 pbesinst_index_map& index_map)
281 {
282 using utilities::detail::contains;
283 for (const pbes_equation& eqn: equations)
284 {
285 const core::identifier_string& name = eqn.variable().name();
286 const data::variable_list& parameters = eqn.variable().parameters();
287
288 std::vector<std::size_t> v;
289 auto j = variable_map.find(name);
290 if (j != variable_map.end())
291 {
292 std::size_t index = 0;
293 for (auto k = parameters.begin(); k != parameters.end(); ++k, ++index)
294 {
295 if (contains(j->second, *k))
296 {
297 v.push_back(index);
298 }
299 }
300 }
301 index_map[name] = v;
302 }
303 }
304
305 /// \brief Prints a message for every 1000-th equation
307 {
308 if (size > 0 && size % 1000 == 0)
309 {
310 std::ostringstream out;
311 out << "Generated " << size << " BES equations" << std::endl;
312 return out.str();
313 }
314 return "";
315 }
316
317 public:
318
319 /// \brief Constructor.
320 /// \param rewriter_strategy Strategy to be used for the data rewriter.
321 explicit pbesinst_finite_algorithm(data::rewriter::strategy rewriter_strategy = data::jitty)
323 {}
324
325 /// \brief Runs the algorithm.
326 /// \param pbesspec A PBES
327 /// \param variable_map A map containing the finite parameters that should be expanded by the algorithm.
328 void run(pbes& pbesspec, const pbesinst_variable_map& variable_map)
329 {
332 m_equation_count = 0;
333
334 // compute index map corresponding to the variable map
335 pbesinst_index_map index_map;
336 compute_index_map(pbesspec.equations(), variable_map, index_map);
337
338 data::rewriter rewr(pbesspec.data(), m_rewriter_strategy);
339
340 // compute new equations
341 std::vector<pbes_equation> equations;
342 for (const pbes_equation& eqn: pbesspec.equations())
343 {
344 std::vector<data::variable> finite_parameters;
345 std::vector<data::variable> infinite_parameters;
346 detail::split_parameters(eqn.variable(), index_map, finite_parameters, infinite_parameters);
347 data::variable_list infinite(infinite_parameters.begin(), infinite_parameters.end());
348
349 using enumerator_element = data::enumerator_list_element_with_substitution<>;
350 bool accept_solutions_with_variables = false;
351 data::enumerator_algorithm<> E(rewr, pbesspec.data(), rewr, m_id_generator, accept_solutions_with_variables);
352 data::variable_list finite_parameter_list(finite_parameters.begin(), finite_parameters.end());
353 data::mutable_indexed_substitution<> sigma;
354 E.enumerate(enumerator_element(finite_parameter_list, data::true_()),
355 sigma,
356 [&](const enumerator_element& p) {
357 data::mutable_indexed_substitution<> sigma_j;
358 p.add_assignments(finite_parameter_list, sigma_j, rewr);
359 std::vector<data::data_expression> finite;
360 for (const data::variable& v: finite_parameters)
361 {
362 finite.push_back(sigma_j(v));
363 }
364 core::identifier_string name = rename(eqn.variable().name(), data::data_expression_list(finite.begin(), finite.end()));
365 propositional_variable X(name, infinite);
366 detail::pbesinst_finite_builder<data::rewriter, data::mutable_indexed_substitution<>> visitor(rewr, sigma_j, rename, pbesspec.data(), index_map, variable_map);
367 pbes_expression formula;
368 visitor.apply(formula, eqn.formula());
369 equations.emplace_back(eqn.symbol(), X, formula);
370 mCRL2log(log::debug) << print_equation_count(++m_equation_count);
371 mCRL2log(log::debug) << "Added equation " << pbes_system::pp(eqn) << "\n";
372 return false;
373 }
374 );
375 }
376
377 // compute new initial state
378 data::no_substitution sigma;
379 detail::pbesinst_finite_builder<data::rewriter, data::no_substitution> visitor(rewr, sigma, rename, pbesspec.data(), index_map, variable_map);
380 propositional_variable_instantiation initial_state = visitor.visit_initial_state(pbesspec.initial_state());
381
382 // assign the result
383 pbesspec.equations() = equations;
384 pbesspec.initial_state() = initial_state;
385 }
386
387 /// \brief Runs the algorithm.
388 /// \param p A PBES
389 void run(pbes& p)
390 {
391 // put all finite variables in a variable map
392 pbesinst_variable_map variable_map;
393 for (const pbes_equation& eqn: p.equations())
394 {
395 for (const data::variable& v: eqn.variable().parameters())
396 {
397 if (p.data().is_certainly_finite(v.sort()))
398 {
399 variable_map[eqn.variable().name()].push_back(v);
400 }
401 }
402 }
403
404 run(p, variable_map);
405 }
406};
407
408inline
409void pbesinst_finite(pbes& p, data::rewrite_strategy rewrite_strategy, const std::string& finite_parameter_selection)
410{
411 if (finite_parameter_selection.empty())
412 {
413 throw empty_parameter_selection("no finite parameters were selected!");
414 }
415 pbesinst_finite_algorithm algorithm(rewrite_strategy);
416 pbes_system::detail::pbes_parameter_map parameter_map = pbes_system::detail::parse_pbes_parameter_map(p, finite_parameter_selection);
417
418 bool is_empty = true;
419 for (auto& i: parameter_map)
420 {
421 if (!((i.second).empty()))
422 {
423 is_empty = false;
424 break;
425 }
426 }
427 if (is_empty)
428 {
429 mCRL2log(log::verbose) << "Warning: no parameters were found that match the string \"" + finite_parameter_selection + "\"" << std::endl;
430 }
431 else
432 {
433 algorithm.run(p, parameter_map);
434 }
435}
436
437} // namespace mcrl2::pbes_system
438
439#endif // MCRL2_PBES_PBESINST_FINITE_ALGORITHM_H
Rewriter that operates on data expressions.
Definition rewriter.h:84
Identifier generator that stores the identifiers of the context in a set. Using the operator()() and ...
\brief The and operator for pbes expressions
\brief The existential quantification operator for pbes expressions
const data::variable_list & variables() const
\brief The universal quantification operator for pbes expressions
const data::variable_list & variables() const
\brief The implication operator for pbes expressions
\brief The not operator for pbes expressions
\brief The or operator for pbes expressions
parameterized boolean equation system
Definition pbes.h:54
propositional_variable_instantiation & initial_state()
Returns the initial state.
Definition pbes.h:195
Algorithm class for the finite pbesinst algorithm.
data::enumerator_identifier_generator m_id_generator
Identifier generator for the enumerator.
std::size_t m_equation_count
The number of generated equations.
void run(pbes &pbesspec, const pbesinst_variable_map &variable_map)
Runs the algorithm.
std::string print_equation_count(std::size_t size) const
Prints a message for every 1000-th equation.
data::rewriter::strategy m_rewriter_strategy
The strategy of the data rewriter.
void compute_index_map(const std::vector< pbes_equation > &equations, const pbesinst_variable_map &variable_map, pbesinst_index_map &index_map)
Returns true if the container contains the given element.
pbesinst_finite_algorithm(data::rewriter::strategy rewriter_strategy=data::jitty)
Constructor.
\brief A propositional variable instantiation
propositional_variable_instantiation(const core::identifier_string &name, const data::data_expression_list &parameters)
Constructor.
propositional_variable_instantiation & operator=(const propositional_variable_instantiation &) noexcept=default
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:393
data_expression and_(const data_expression &x, const data_expression &y)
const data_expression & true_()
Definition consistency.h:91
std::set< data::variable > significant_variables(const pbes_expression &x)
Returns the significant variables of a pbes expression.
void remove_parameters(pbes &x, const std::set< data::variable > &to_be_removed)
Removes parameters from propositional variable instantiations in a pbes expression.
void remove_parameters(pbes &x, const std::map< core::identifier_string, std::vector< std::size_t > > &to_be_removed)
Removes parameters from propositional variable instantiations in a pbes expression.
void pbesinst_finite(pbes &p, data::rewrite_strategy rewrite_strategy, const std::string &finite_parameter_selection)
Apply finite instantiation to the given PBES.
void instantiate_global_variables(pbes &p)
Attempts to eliminate the free variables of a PBES, by substituting a constant value for them....
Definition pbes.cpp:64
bool is_normalized(const pbes &x)
Checks if a PBEs is normalized.
std::vector< propositional_variable > remove_unreachable_variables(pbes &p)
Removes equations that are not (syntactically) reachable from the initial state of a PBES.
std::string print_removed_equations(const std::vector< propositional_variable > &removed)
Print removed equations.
void normalize(pbes &x)
The function normalize brings (embedded) pbes expressions into positive normal form,...
void split_parameters(const PropositionalVariable &X, const pbesinst_index_map &index_map, std::vector< Parameter > &finite, std::vector< Parameter > &infinite)
Computes the subset with variables of finite sort and infinite.
The main namespace for the PBES library.
pbes_expression make_exists_(const data::variable_list &l, const pbes_expression &p)
Make an existential quantification. It checks for an empty variable list, which is not allowed.
void pbesinst_finite(pbes &p, data::rewrite_strategy rewrite_strategy, const std::string &finite_parameter_selection)
pbes_expression make_forall_(const data::variable_list &l, const pbes_expression &p)
Make a universal quantification. It checks for an empty variable list, which is not allowed.
bool is_normalized(const T &x)
Checks if a pbes expression is normalized.
Definition normalize.h:155
An empty struct that is used to denote the absence of a substitution. Used for rewriters.
Visitor that applies a propositional variable substitution to a pbes expression.
data::data_expression make_condition(const VariableContainer &variables, const ExpressionContainer &expressions) const
Computes the condition 'for all i: variables[i] == expressions[i]'.
void apply(T &result, const propositional_variable_instantiation &x)
data::data_expression_list rewrite_container(const DataExpressionContainer &v, const data::rewriter &rewr, const data::mutable_indexed_substitution<> &sigma)
std::string print_parameters(const std::vector< data::data_expression > &finite_parameters, const std::vector< data::data_expression > &infinite_parameters) const
propositional_variable_instantiation visit_initial_state(const propositional_variable_instantiation &init)
data::data_expression_list rewrite_container(const DataExpressionContainer &v, const data::rewriter &rewr)
pbesinst_finite_builder(const DataRewriter &R, SubstitutionFunction &sigma, const pbesinst_finite_rename &rho, const data::data_specification &data_spec, const pbesinst_index_map &index_map, const pbesinst_variable_map &variable_map)
Exception that is used to signal an empty parameter selection.
Function object for renaming a propositional variable instantiation.
core::identifier_string operator()(const core::identifier_string &name, const data::data_expression_list &parameters) const
Renames the propositional variable x.
std::unordered_map< propositional_variable_instantiation, core::identifier_string > m
core::identifier_string rename(const core::identifier_string &name, const data::data_expression_list &parameters) const