mCRL2
Loading...
Searching...
No Matches
eqelm.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/eqelm.h
8/// \brief The eqelm algorithm.
9
10#ifndef MCRL2_PBES_EQELM_H
11#define MCRL2_PBES_EQELM_H
12
13#include "mcrl2/pbes/algorithms.h"
14#include "mcrl2/pbes/pbes_rewriter_type.h"
15#include "mcrl2/pbes/print.h"
16#include "mcrl2/pbes/replace.h"
17#include "mcrl2/pbes/rewriters/enumerate_quantifiers_rewriter.h"
18
19namespace mcrl2::pbes_system
20{
21
22/// \brief Algorithm class for the eqelm algorithm
23template <typename Term, typename DataRewriter, typename PbesRewriter>
25{
26 protected:
28
29 /// \brief Compares data expressions for equality.
30 const DataRewriter& m_data_rewriter;
31
32 /// \brief Compares data expressions for equality.
33 const PbesRewriter& m_pbes_rewriter;
34
35 /// \brief The vertices of the grapth, i.e. the equivalence relations.
36 /// It stores the equivalence sets for each propositional variable, for example
37 /// X -> [ {x1, x3}, {x2, x4} ]. Equivalence sets of size 1 are not stored.
39
40 /// \brief The edges of the graph.
41 /// It is a mapping from X to iocc(X).
43
44 /// \brief The parameters of the propositional variable declarations.
45 /// These are stored inside a vector, for efficiency reasons.
47
48 /// \brief Used for determining if a vertex has been visited before.
50
51 /// \brief Puts all parameters of the same sort in the same equivalence set.
53 {
54 std::map< data::sort_expression, equivalence_class> m;
55 for (const auto & i : X.parameters())
56 {
57 m[i.sort()].insert(i);
58 }
59 std::vector<equivalence_class> result;
60 for (auto & i : m)
61 {
62 if (i.second.size() > 1)
63 {
64 result.push_back(i.second);
65 }
66 }
67 return result;
68 }
69
70 /// \brief Prints the vertices of the dependency graph.
72 {
73 std::ostringstream out;
74 for (const auto& vertex: m_vertices)
75 {
76 out << vertex.first << " -> [ ";
77 const std::vector<equivalence_class>& v = vertex.second;
78 for (auto j = v.begin(); j != v.end(); ++j)
79 {
80 if (j != v.begin())
81 {
82 out << ", ";
83 }
84 out << core::detail::print_set(*j);
85 }
86 out << " ]" << std::endl;
87 }
88 return out.str();
89 }
90
91 /// \brief Prints the edges of the dependency graph.
93 {
94 std::ostringstream out;
95 for (const auto& edge: m_edges)
96 {
97 out << edge.first << " -> " << core::detail::print_set(edge.second) << std::endl;
98 }
99 return out.str();
100 }
101
102 /// \brief Prints the equivalence classes
104 {
105 std::ostringstream out;
106 for (const auto& vertex: m_vertices)
107 {
108 out << " vertex " << vertex.first << ": ";
109 for (const auto& j: vertex.second)
110 {
111 out << core::detail::print_set(j) << " ";
112 }
113 out << std::endl;
114 }
115 return out.str();
116 }
117
118 /// \brief Prints the todo list
119 void log_todo_list(const std::set<core::identifier_string>& todo, const std::string& msg = "") const
120 {
121 mCRL2log(log::debug) << msg;
122 mCRL2log(log::debug) << core::detail::print_set(todo) << "\n";
123 }
124
125 /// \brief Returns true if the vertex X should propagate its values to Y
126 bool evaluate_guard(const core::identifier_string& /* X */, const propositional_variable_instantiation& /* Y */)
127 {
128 return true;
129 }
130
131 /// \brief Returns the index of the element x in the sequence v
132 template <typename VariableContainer>
134 {
135 return static_cast<std::size_t>(std::find(v.begin(), v.end(), x) - v.begin());
136 }
137
138 /// \brief Propagate the equivalence relations given by the substitution vX over the edge Ye.
139 template <typename Substitution>
141 const Substitution& vX,
142 std::set<core::identifier_string>& todo
143 )
144 {
145 const core::identifier_string& Y = Ye.name();
146 std::vector<data::data_expression> e(Ye.parameters().begin(), Ye.parameters().end());
147
148 std::vector<equivalence_class>& cY = m_vertices[Y];
149 std::vector<equivalence_class> cY1;
150 for (auto & equiv : cY)
151 {
152 std::map<data::data_expression, equivalence_class> w;
153 for (const auto & k : equiv)
154 {
155 std::size_t p = index_of(k, m_parameters[Y]);
156 pbes_system::data_rewriter<DataRewriter> rewr(m_data_rewriter);
157 pbes_system::pbes_expression e_p = rewr(atermpp::down_cast<pbes_expression>(e[p]), vX);
158 w[atermpp::down_cast<const data::data_expression>(e_p)].insert(k);
159 }
160 for (auto & i : w)
161 {
162 if (i.second.size() > 1)
163 {
164 cY1.push_back(i.second);
165 }
166 }
167 }
168 if (cY != cY1)
169 {
170 todo.insert(Y);
171 m_discovered[Y] = true;
172 cY = cY1;
173 }
174 else if (!m_discovered[Y])
175 {
176 todo.insert(Y);
177 m_discovered[Y] = true;
178 }
179 }
180
181 /// \brief Computes a substitution that corresponds to the equivalence relations in X
183 {
184 data::mutable_map_substitution<> result;
185 const std::vector<equivalence_class>& cX = m_vertices[X];
186 for (const auto & s : cX)
187 {
188 for (auto j = ++s.begin(); j != s.end(); ++j)
189 {
190 result[*j] = *s.begin();
191 }
192 }
193 return result;
194 }
195
196 /// \brief Chooses one parameter for every equivalence class, and
197 /// removes the others. All occurrences of the removed parameters
198 /// are replaced by the chosen parameter.
199 inline
201 {
202 // first apply the substitutions to the equations
203 for (pbes_equation& eqn: p.equations())
204 {
205 core::identifier_string X = eqn.variable().name();
206 data::mutable_map_substitution<> sigma = compute_substitution(X);
207
208 if (!sigma.empty())
209 {
210 eqn.formula() = pbes_system::replace_variables_capture_avoiding(eqn.formula(), sigma);
211 }
212 }
213
214 // then remove parameters
215 std::map<core::identifier_string, std::vector<std::size_t> > to_be_removed;
216 for (pbes_equation& eqn: p.equations())
217 {
218 core::identifier_string X = eqn.variable().name();
219 const std::vector<equivalence_class>& eq = m_vertices[X];
220 for (const auto & j : eq)
221 {
222 for (auto k = ++j.begin(); k != j.end(); ++k)
223 {
224 to_be_removed[X].push_back(index_of(*k, m_parameters[X]));
225 }
226 std::sort(to_be_removed[X].begin(), to_be_removed[X].end());
227 }
228 }
229
230 pbes_system::algorithms::remove_parameters(p, to_be_removed);
231 }
232
233 public:
234 /// \brief Constructor.
235 /// \param datar A data rewriter
236 /// \param pbesr A PBES rewriter
237 pbes_eqelm_algorithm(const DataRewriter& datar, const PbesRewriter& pbesr)
238 : m_data_rewriter(datar),
239 m_pbes_rewriter(pbesr)
240 {}
241
242 /// \brief Runs the eqelm algorithm
243 /// \param p A pbes
244 /// \param ignore_initial_state If true, the initial state is ignored.
245 void run(pbes& p, bool ignore_initial_state = false)
246 {
247 m_vertices.clear();
248 m_edges.clear();
249 std::set<core::identifier_string> todo;
250
251 // compute the vertices and edges of the graph
252 for (pbes_equation& eqn: p.equations())
253 {
254 core::identifier_string name = eqn.variable().name();
255 m_edges[name] = find_propositional_variable_instantiations(eqn.formula());
256 m_vertices[name] = compute_equivalence_sets(eqn.variable());
257 const data::variable_list& param = eqn.variable().parameters();
258 m_parameters[name] = std::vector<data::variable>(param.begin(), param.end());
259 todo.insert(name);
260 m_discovered[name] = ignore_initial_state;
261 }
262
263 if (!ignore_initial_state)
264 {
265 todo.clear();
267 const core::identifier_string& X = kappa.name();
268 data::mutable_map_substitution<> vX = compute_substitution(X);
269
270 // propagate the equivalence relations in X over the edge kappa
271 if (evaluate_guard(X, kappa))
272 {
273 todo.insert(X);
274 m_discovered[X] = true;
275 update_equivalence_classes(kappa, vX, todo);
276 mCRL2log(log::debug) << "updated equivalence classes using initial state " << kappa << "\n" << print_equivalence_classes();
277 }
278 }
279
280 mCRL2log(log::verbose) << "--- vertices ---\n" << print_vertices();
281 mCRL2log(log::verbose) << "\n--- edges ---\n" << print_edges();
282 mCRL2log(log::debug) << "computed initial equivalence classes\n" << print_equivalence_classes();
283
284 // propagate constraints over the edges until the todo list is empty
285 while (!todo.empty())
286 {
287 mCRL2log(log::debug) << "todo list = " << core::detail::print_set(todo) << "\n";
288 mCRL2log(log::verbose) << "--- vertices ---\n" << print_vertices();
289
290 core::identifier_string X = *todo.begin();
291 todo.erase(X);
292 mCRL2log(log::debug) << "choose todo element " << X << "\n";
293
294 // create a substitution function that corresponds to cX
295 data::mutable_map_substitution<> vX = compute_substitution(X);
296 const std::set<propositional_variable_instantiation>& edges = m_edges[X];
297 for (const auto& Ye : edges)
298 {
299 // propagate the equivalence relations in X over the edge Ye
300 if (evaluate_guard(X, Ye))
301 {
302 update_equivalence_classes(Ye, vX, todo);
303 mCRL2log(log::debug) << "updated equivalence classes using edge " << Ye << "\n" << print_equivalence_classes();
304 }
305 }
306 }
308 mCRL2log(log::verbose) << "\n--- result ---\n" << print_vertices();
309 }
310};
311
312/// \brief Apply the eqelm algorithm
313/// \param p A PBES to which the algorithm is applied.
314/// \param rewrite_strategy A data rewrite strategy.
315/// \param rewriter_type A PBES rewriter type.
316/// \param ignore_initial_state If true, the initial state will be ignored.
317inline
318void eqelm(pbes& p,
319 data::rewrite_strategy rewrite_strategy,
320 pbes_rewriter_type rewriter_type,
321 bool ignore_initial_state = false
322 )
323{
324 // data rewriter
325 data::rewriter datar(p.data(), rewrite_strategy);
326
327 // pbes rewriter
328 switch (rewriter_type)
329 {
330 case pbes_rewriter_type::simplify:
331 {
332 using pbes_rewriter = simplify_data_rewriter<data::rewriter>;
333 pbes_rewriter pbesr(datar);
334 pbes_eqelm_algorithm<pbes_expression, data::rewriter, pbes_rewriter> algorithm(datar, pbesr);
335 algorithm.run(p, ignore_initial_state);
336 break;
337 }
338 case pbes_rewriter_type::quantifier_all:
339 case pbes_rewriter_type::quantifier_finite:
340 {
341 const enumerate_quantifiers_mode enum_mode = (rewriter_type == pbes_rewriter_type::quantifier_all?
342 expand_infinite_sorts_and_use_data_rewriter:
343 expand_finite_sorts);
344 enumerate_quantifiers_rewriter pbesr(datar, p.data(), enum_mode);
346 algorithm.run(p, ignore_initial_state);
347 break;
348 }
349 default:
350 { }
351 }
352}
353
354} // namespace mcrl2::pbes_system
355
356
357
358#endif // MCRL2_PBES_EQELM_H
Rewriter that operates on data expressions.
Definition rewriter.h:84
Algorithm class for the eqelm algorithm.
Definition eqelm.h:25
void log_todo_list(const std::set< core::identifier_string > &todo, const std::string &msg="") const
Prints the todo list.
Definition eqelm.h:119
pbes_eqelm_algorithm(const DataRewriter &datar, const PbesRewriter &pbesr)
Constructor.
Definition eqelm.h:237
bool evaluate_guard(const core::identifier_string &, const propositional_variable_instantiation &)
Returns true if the vertex X should propagate its values to Y.
Definition eqelm.h:126
std::string print_edges() const
Prints the edges of the dependency graph.
Definition eqelm.h:92
data::mutable_map_substitution compute_substitution(const core::identifier_string &X)
Computes a substitution that corresponds to the equivalence relations in X.
Definition eqelm.h:182
const DataRewriter & m_data_rewriter
Compares data expressions for equality.
Definition eqelm.h:30
const PbesRewriter & m_pbes_rewriter
Compares data expressions for equality.
Definition eqelm.h:33
std::map< core::identifier_string, bool > m_discovered
Used for determining if a vertex has been visited before.
Definition eqelm.h:49
std::string print_equivalence_classes() const
Prints the equivalence classes.
Definition eqelm.h:103
std::string print_vertices() const
Prints the vertices of the dependency graph.
Definition eqelm.h:71
void update_equivalence_classes(const propositional_variable_instantiation &Ye, const Substitution &vX, std::set< core::identifier_string > &todo)
Propagate the equivalence relations given by the substitution vX over the edge Ye.
Definition eqelm.h:140
void apply_equivalence_relations(pbes &p)
Chooses one parameter for every equivalence class, and removes the others. All occurrences of the rem...
Definition eqelm.h:200
std::vector< equivalence_class > compute_equivalence_sets(const propositional_variable &X) const
Puts all parameters of the same sort in the same equivalence set.
Definition eqelm.h:52
std::size_t index_of(const data::variable &x, const VariableContainer &v)
Returns the index of the element x in the sequence v.
Definition eqelm.h:133
void run(pbes &p, bool ignore_initial_state=false)
Runs the eqelm algorithm.
Definition eqelm.h:245
parameterized boolean equation system
Definition pbes.h:54
propositional_variable_instantiation & initial_state()
Returns the initial state.
Definition pbes.h:195
\brief A propositional variable instantiation
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:393
void eqelm(pbes &p, data::rewrite_strategy rewrite_strategy, pbes_rewriter_type rewriter_type, bool ignore_initial_state=false)
Apply the eqelm algorithm.
Definition eqelm.h:318
enumerate_quantifiers_rewriter(const data::rewriter &R, const data::data_specification &dataspec, const enumerate_quantifiers_mode enum_mode=expand_infinite_sorts_and_use_data_rewriter)
A rewriter that simplifies boolean expressions in a term, and rewrites data expressions using DataRew...