mCRL2
Loading...
Searching...
No Matches
parelm.h
Go to the documentation of this file.
1// Author(s): Wieger Wesselink
2//
3// Distributed under the Boost Software License, Version 1.0.
4// (See accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6//
7/// \file mcrl2/pbes/parelm.h
8/// \brief The parelm algorithm.
9
10#ifndef MCRL2_PBES_PARELM_H
11#define MCRL2_PBES_PARELM_H
12
13#include "mcrl2/pbes/algorithms.h"
14#include "mcrl2/pbes/detail/find_free_variables.h"
15#include "mcrl2/utilities/detail/iota.h"
16#include "mcrl2/utilities/reachable_nodes.h"
17#include "mcrl2/pbes/detail/pbes_remove_counterexample_info.h"
18
19namespace mcrl2::pbes_system {
20
21namespace detail {
22
23/// \brief Finds the index of a variable in a sequence
24/// \param variables A sequence of data variables
25/// \param d A data variable
26/// \return The index of \p d in \p v, or -1 if the variable wasn't found
27inline
28int variable_index(const data::variable_list& variables, const data::variable& d)
29{
30 int index = 0;
31 for (const data::variable& v: variables)
32 {
33 if (v == d)
34 {
35 return index;
36 }
37 index++;
38 }
39 return -1;
40}
41
42} // namespace detail
43
44/// \brief Algorithm class for the parelm algorithm
46{
47 protected:
48 /// \brief The graph type of the dependency graph
50
51 /// \brief The vertex type of the dependency graph
53
54 /// \brief The edge type of the dependency graph
56
58 {
60 using super::enter;
61 using super::leave;
62 using super::apply;
63
66
67 core::identifier_string X;
68 data::variable_list Xparams;
70
71 parelm_dependency_traverser(graph& G_, const std::map<core::identifier_string, std::size_t>& propvar_offsets_)
73 {}
74
75 void enter(const forall& x)
76 {
77 for (const data::variable& v: x.variables())
78 {
79 bound_variables.insert(v);
80 }
81 }
82
83 void leave(const forall& x)
84 {
85 for (const data::variable& v: x.variables())
86 {
87 bound_variables.erase(v);
88 }
89 }
90
91 void enter(const exists& x)
92 {
93 for (const data::variable& v: x.variables())
94 {
95 bound_variables.insert(v);
96 }
97 }
98
99 void leave(const exists& x)
100 {
101 for (const data::variable& v: x.variables())
102 {
103 bound_variables.erase(v);
104 }
105 }
106
108 {
109 using utilities::detail::contains;
110
111 const core::identifier_string& Y = x.name();
112 int Yindex = 0;
113 for (const data::data_expression& e: x.parameters())
114 {
115 for (const data::variable& var: data::find_free_variables(e))
116 {
117 if (contains(bound_variables, var))
118 {
119 continue;
120 }
121 int Xindex = detail::variable_index(Xparams, var);
122 if (Xindex < 0)
123 {
124 continue;
125 }
126 // parameter (Y, Yindex) is influenced by (X, Xindex)
127 boost::add_edge(propvar_offsets.at(Y) + Yindex, propvar_offsets.at(X) + Xindex, G);
128 }
129 Yindex++;
130 }
131 }
132
133 void apply(const pbes_equation& eqn)
134 {
136 Xparams = eqn.variable().parameters();
137 super::apply(eqn);
138 }
139 };
140
141 /// \brief Finds unbound variables in a pbes expression
142 /// \param t A PBES expression
143 /// \param bound_variables A sequence of data variables
144 /// \return The unbound variables in \p t that are not contained in \p bound_variables
146 {
147 bool search_propositional_variables = false;
148 return detail::find_free_variables(t, bound_variables, search_propositional_variables);
149 }
150
151 /// \brief Finds the predicate variable to which the data parameter with the given index belongs.
152 /// Here index refers to the cumulative index in the array obtained by concatening all parameters
153 /// of the predicate variables in the pbes \p p.
154 /// \param p A pbes
155 /// \param index A positive number
156 /// \return The name of the predicate variable that corresponds with \p index
157 static core::identifier_string find_predicate_variable(const pbes& p, std::size_t index)
158 {
159 std::size_t offset = 0;
160 for (const pbes_equation& eqn: p.equations())
161 {
162 std::size_t size = eqn.variable().parameters().size();
163 if (offset + size > index)
164 {
165 return eqn.variable().name();
166 }
167 offset += eqn.variable().parameters().size();
168 }
169 return core::identifier_string("<not found>");
170 }
171
172 static void compute_dependency_graph(const pbes& p, const std::map<core::identifier_string, std::size_t>& propvar_offsets, graph& G)
173 {
174 parelm_dependency_traverser f(G, propvar_offsets);
175 for (const pbes_equation& eqn: p.equations())
176 {
177 f.apply(eqn);
178 }
179 }
180
181 public:
182 /// \brief Runs the parelm algorithm. The pbes \p is modified by the algorithm
183 /// \param p A pbes
184 /// \param ignore_cex Ignore counter example equations if present
185 void run(pbes& p, bool ignore_cex = false)
186 {
187 data::variable_list global_variables(p.global_variables().begin(), p.global_variables().end());
188 std::vector<data::variable> predicate_variables;
189
190 // compute a mapping from propositional variable names to offsets
191 std::size_t offset = 0;
192 std::map<core::identifier_string, std::size_t> propvar_offsets;
193 for (pbes_equation& eqn: p.equations())
194 {
195 propvar_offsets[eqn.variable().name()] = offset;
196 offset += eqn.variable().parameters().size();
197 predicate_variables.insert(predicate_variables.end(), eqn.variable().parameters().begin(), eqn.variable().parameters().end());
198 }
199 std::size_t N = offset; // # variables
200
201 // compute the initial set v of significant variables
202 std::set<std::size_t> significant_variables;
203 offset = 0;
204 for (pbes_equation& eqn: p.equations())
205 {
206 // Consider all parameters of counter example equations to be significant
207 if (ignore_cex && detail::is_counter_example_equation(eqn))
208 {
209 for (const data::variable& w: eqn.variable().parameters())
210 {
211 int k = detail::variable_index(eqn.variable().parameters(), w);
212 if (k < 0)
213 {
214 throw mcrl2::runtime_error("<variable error>" + data::pp(w));
215 }
216 significant_variables.insert(offset + k);
217 }
218 }
219 else
220 {
221 for (const data::variable& w: unbound_variables(eqn.formula(), global_variables))
222 {
223 int k = detail::variable_index(eqn.variable().parameters(), w);
224 if (k < 0)
225 {
226 throw mcrl2::runtime_error("<variable error>" + data::pp(w));
227 }
228 significant_variables.insert(offset + k);
229 }
230 }
231 offset += eqn.variable().parameters().size();
232 }
233
234 graph G(N);
235 compute_dependency_graph(p, propvar_offsets, G);
236
237 // compute the indices s of the parameters that need to be removed
238 std::vector<std::size_t> r = utilities::reachable_nodes(G, significant_variables.begin(), significant_variables.end());
239 std::sort(r.begin(), r.end());
240 std::vector<std::size_t> q(N);
241 utilities::detail::iota(q.begin(), q.end(), 0);
242 std::vector<std::size_t> s;
243 std::set_difference(q.begin(), q.end(), r.begin(), r.end(), std::back_inserter(s));
244
245 // create a map that specifies the parameters that need to be removed
246 std::map<core::identifier_string, std::vector<std::size_t> > removals;
247 std::size_t index = 0;
248 auto sfirst = s.begin();
249 for (pbes_equation& eqn: p.equations())
250 {
251 std::size_t maxindex = index + eqn.variable().parameters().size();
252 auto slast = std::find_if(sfirst, s.end(), [&](std::size_t i) { return i >= maxindex; });
253 if (slast > sfirst)
254 {
255 std::vector<std::size_t> w(sfirst, slast);
256 std::transform(w.begin(), w.end(), w.begin(), [&](std::size_t i) { return i - index; });
257 removals[eqn.variable().name()] = w;
258 }
259 index = maxindex;
260 sfirst = slast;
261 }
262
263 if (mCRL2logEnabled(log::debug))
264 {
265 print_dependencies(p, predicate_variables, significant_variables, G);
266 }
267
268 // print verbose output
269 if (mCRL2logEnabled(log::verbose))
270 {
271 print_removed_parameters(predicate_variables, propvar_offsets, removals);
272 }
273
274 // remove the parameters
275 pbes_system::algorithms::remove_parameters(p, removals);
276 }
277
278 void print_removed_parameters(const std::vector<data::variable>& predicate_variables,
279 const std::map<core::identifier_string, std::size_t>& propvar_offsets,
281 {
282 mCRL2log(log::verbose) << "\nremoving the following parameters:" << std::endl;
283 for (auto& removal: removals)
284 {
285 core::identifier_string X1 = removal.first;
286 for (std::size_t j: removal.second)
287 {
288 data::variable v1 = predicate_variables[j + propvar_offsets.at(X1)];
289 mCRL2log(log::verbose) << "(" + core::pp(X1) + ", " + data::pp(v1) + ")\n";
290 }
291 }
292 }
293
294 static void print_dependencies(const pbes& p, const std::vector<data::variable>& predicate_variables, const std::set<std::size_t>& significant_variables, const graph& G)
295 {
296 mCRL2log(log::debug) << "\ninfluential parameters:" << std::endl;
297 for (std::size_t i: significant_variables)
298 {
299 core::identifier_string X1 = find_predicate_variable(p, i);
300 data::variable v1 = predicate_variables[i];
301 mCRL2log(log::debug) << "(" + core::pp(X1) + ", " + data::pp(v1) + ")\n";
302 }
303 mCRL2log(log::debug) << "\ndependencies:" << std::endl;
304 using edge_iterator = boost::graph_traits<graph>::edge_iterator;
305 std::pair<edge_iterator, edge_iterator> e = edges(G);
306 edge_iterator first = e.first;
307 edge_iterator last = e.second;
308 for (; first != last; ++first)
309 {
310 edge_descriptor f = *first;
311 std::size_t i1 = boost::source(f, G);
312 core::identifier_string X1 = find_predicate_variable(p, i1);
313 data::variable v1 = predicate_variables[i1];
314 std::size_t i2 = boost::target(f, G);
315 core::identifier_string X2 = find_predicate_variable(p, i2);
316 data::variable v2 = predicate_variables[i2];
317 std::string left = "(" + core::pp(X1) + ", " + data::pp(v1) + ")";
318 std::string right = "(" + core::pp(X2) + ", " + data::pp(v2) + ")";
319 mCRL2log(log::debug) << left << " -> " << right << std::endl;
320 }
321 }
322};
323
324/// \brief Apply the parelm algorithm
325/// \param p A PBES to which the algorithm is applied
326inline
327void parelm(pbes& p, bool ignore_cex)
328{
329 const bool has_counter_example = pbes_system::detail::has_counter_example_information(p);
330 if (has_counter_example)
331 {
332 mCRL2log(log::warning) << "Warning: the PBES has counter example information, which may not be preserved by parameter elimination." << std::endl;
333 }
334 pbes_parelm_algorithm algorithm;
335 algorithm.run(p, ignore_cex);
336}
337
338} // namespace mcrl2::pbes_system
339
340#endif // MCRL2_PBES_PARELM_H
aterm_string & operator=(const aterm_string &t) noexcept=default
\brief A data variable
Definition variable.h:25
\brief The existential quantification operator for pbes expressions
\brief The universal quantification operator for pbes expressions
const propositional_variable & variable() const
Returns the pbes variable of the equation.
Algorithm class for the parelm algorithm.
Definition parelm.h:46
static std::set< data::variable > unbound_variables(const pbes_expression &t, const data::variable_list &bound_variables)
Finds unbound variables in a pbes expression.
Definition parelm.h:145
static void print_dependencies(const pbes &p, const std::vector< data::variable > &predicate_variables, const std::set< std::size_t > &significant_variables, const graph &G)
Definition parelm.h:294
static core::identifier_string find_predicate_variable(const pbes &p, std::size_t index)
Finds the predicate variable to which the data parameter with the given index belongs....
Definition parelm.h:157
static void compute_dependency_graph(const pbes &p, const std::map< core::identifier_string, std::size_t > &propvar_offsets, graph &G)
Definition parelm.h:172
void run(pbes &p, bool ignore_cex=false)
Runs the parelm algorithm. The pbes is modified by the algorithm.
Definition parelm.h:185
void print_removed_parameters(const std::vector< data::variable > &predicate_variables, const std::map< core::identifier_string, std::size_t > &propvar_offsets, const std::map< core::identifier_string, std::vector< std::size_t > > &removals) const
Definition parelm.h:278
parameterized boolean equation system
Definition pbes.h:54
\brief A propositional variable instantiation
const core::identifier_string & name() const
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:393
int variable_index(const data::variable_list &variables, const data::variable &d)
Finds the index of a variable in a sequence.
Definition parelm.h:28
bool has_counter_example_information(const pbes &pbesspec)
Guesses if a pbes has counter example information.
void parelm(pbes &p, bool ignore_cex)
Apply the parelm algorithm.
Definition parelm.h:327
void apply(const propositional_variable_instantiation &x)
Definition parelm.h:107
parelm_dependency_traverser(graph &G_, const std::map< core::identifier_string, std::size_t > &propvar_offsets_)
Definition parelm.h:71
const std::map< core::identifier_string, std::size_t > & propvar_offsets
Definition parelm.h:65