mCRL2
Loading...
Searching...
No Matches
bqnf_quantifier_rewriter.h
Go to the documentation of this file.
1// Author(s): Gijs Kant
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/detail/bqnf_quantifier_rewriter.h
10/// \brief Replaces universal quantifier over conjuncts with conjuncts over universal quantifiers:
11/// rewrite_bqnf_expression(forall x . /\_i phi_i) =
12/// /\_i forall (x intersection free(phi_i)) . phi_i.
13/// This rewriter is experimental.
14#ifndef MCRL2_PBES_DETAIL_BQNF_QUANTIFIER_REWRITER_H
15#define MCRL2_PBES_DETAIL_BQNF_QUANTIFIER_REWRITER_H
16
17#include "mcrl2/pbes/detail/bqnf_visitor.h"
18
19namespace mcrl2::pbes_system::detail
20{
21
23 {
24 /// \brief Constructor.
26
27 /// \brief Filters the expression e such that subexpressions that are data expression that
28 /// do not refer to variables in the set d are discarded:
29 /// filter(e, d) = e if e is a data expression and the intersection of free(e) and d is not empty;
30 /// filter(e1 'op' e2, d) = filter(e1, d) 'op' filter(e2, d).
31 /// \param e a simple PBES expression.
32 /// \param d a set of variables.
33 /// \return the filtered expression.
34 virtual pbes_expression filter(const pbes_expression& e, const std::set<data::variable>& d)
35 {
36 assert(is_simple_expression(e, false));
37 pbes_expression empty;
38 if (is_data(e))
39 {
40 std::vector<data::variable> intersection;
41 for (const data::variable& var: pbes_system::find_free_variables(e))
42 {
43 if (d.find(var) != d.end())
44 {
45 intersection.push_back(var);
46 }
47 }
48 if (intersection.empty())
49 {
50 return e;
51 }
52 else
53 {
54 return empty;
55 }
56 }
57 else if (is_and(e) || is_or(e) || is_imp(e))
58 {
59 pbes_expression l = filter(pbes_system::accessors::left(e), d);
60 pbes_expression r = filter(pbes_system::accessors::right(e), d);
61 if (l==empty && r==empty)
62 {
63 return empty;
64 }
65 else if (l==empty)
66 {
67 return r;
68 }
69 else if (r==empty)
70 {
71 if (is_imp(e))
72 {
73 return not_(l);
74 }
75 else
76 {
77 return l;
78 }
79 }
80 else
81 {
82 if (is_and(e))
83 {
84 return and_(l, r);
85 }
86 else if (is_or(e))
87 {
88 return or_(l, r);
89 }
90 else // is_imp(e)
91 {
92 return imp(l, r);
93 }
94 }
95 }
96 else
97 {
98 std::clog << "filter: Unexpected expression: " << pp(e) << std::endl;
99 throw(std::runtime_error("filter: Unexpected expression."));
100 }
101 }
102
103
104
105 /// \brief Filters a 'guard' g with respect to a set of variables d and
106 /// an expression phi_i such that parts of g that not relevant for phi_i
107 /// are discarded.
108 /// filter_guard(g, phi_i, d) = ( exists_{d intersects (free(g) - free(phi_i))} . filter(g, {d - free(phi_i)))
109 /// && filter(g, d intersects free(phi_i)).
110 /// \param g a simple expression that functions as guard.
111 /// \param phi_i a PBES expression.
112 /// \param d a set of relevant variables.
113 /// \return the expression g filtered with respect to phi_i and d.
114 virtual pbes_expression filter_guard(const pbes_expression& g, const pbes_expression& phi_i, const data::variable_list& d)
115 {
116 pbes_expression result = true_();
117 data::variable_list free_g = free_variables(g);
118 std::set<data::variable> free_phi_i;
119 for (const data::variable& v: pbes_system::find_free_variables(phi_i))
120 {
121 free_phi_i.insert(v);
122 }
123 std::set<data::variable> free_g_minus_free_phi_i;
124 for (const data::variable& var: free_g)
125 {
126 if (free_phi_i.find(var)==free_phi_i.end()) { // !free_phi_i.contains(v)
127 free_g_minus_free_phi_i.insert(var);
128 }
129 }
130 std::vector<data::variable> d_intersects_free_g_minus_free_phi_i;
131 std::set<data::variable> d_minus_free_phi_i;
132 std::set<data::variable> d_intersects_free_phi_i;
133 for (const data::variable& var: d)
134 {
135 if (free_g_minus_free_phi_i.find(var) != free_g_minus_free_phi_i.end()) // free_g_minus_free_phi_i.contains(v)
136 {
137 d_intersects_free_g_minus_free_phi_i.push_back(var);
138 }
139 if (free_phi_i.find(var) != free_phi_i.end()) // free_phi_i.contains(v)
140 {
141 d_intersects_free_phi_i.insert(var);
142 }
143 else
144 {
145 d_minus_free_phi_i.insert(var);
146 }
147 }
148 // Now I have the sets I need; let's generate terms.
149 pbes_expression e_1 = filter(g, d_minus_free_phi_i);
150 if (!d_intersects_free_g_minus_free_phi_i.empty())
151 {
152 e_1 =
153// data::exists( // N.B. Removing this, since it does not make sense to convert a pbes_system::exists to a data::exists (Wieger).
154 optimized_exists(
155 data::variable_list(d_intersects_free_g_minus_free_phi_i.begin(), d_intersects_free_g_minus_free_phi_i.end()),
156 e_1)
157// )
158 ;
159 }
160 pbes_expression e_2 = filter(g, d_intersects_free_phi_i);
161 pbes_expression empty;
162 if (e_1 == empty)
163 {
164 if (e_2 != empty)
165 {
166 result = e_2;
167 }
168 }
169 else
170 {
171 if (e_2 == empty)
172 {
173 result = e_1;
174 }
175 else
176 {
177 result = and_(e_1, e_2);
178 }
179 }
180 return result;
181 }
182
183
184 /// \brief Rewrites a bounded universal quantifier expression.
185 /// If the subexpression is a conjunction, the quantifier over the conjunction
186 /// is transformed to a conjunction of quantifier expressions.
187 /// rewrite_bounded_forall(forall x . phi => /\_i psi_i) =
188 /// /\_i forall (x intersection free(psi_i)) .
189 /// filter_guard(phi, psi_i, x) => rewrite_bqnf_expression(psi_i).
190 /// \param e a PBES expression
191 /// \return the expression resulting from the transformation.
193 {
194 assert(is_forall(e));
195 data::variable_list qvars = quantifier_variables(e);
197 while (is_forall(qexpr)) {
198 qvars = qvars + quantifier_variables(qexpr);
200 }
201 // forall qvars . qexpr
202 pbes_expression result;
203 if (is_propositional_variable_instantiation(qexpr) || is_simple_expression(qexpr, false)) {
204 // forall d . phi | forall d . X(e)
205 result = e;
206 } else {
207 pbes_expression phi = is_or(qexpr) ? static_cast<const pbes_expression&>(true_()) : static_cast<const pbes_expression&>(false_());
208 pbes_expression psi = qexpr;
209 if (is_or(qexpr) || is_imp(qexpr)) {
212 if (is_simple_expression(l, false)) {
213 phi = l;
214 psi = r;
215 }
216 }
218 // forall d . phi => X(e)
219 result = e;
220 } else if (!qvars.empty() || !(is_or(qexpr) ? is_true(phi) : is_false(phi))) {
221 // forall d . phi => psi
222 std::vector<pbes_expression> conjuncts;
223 if (is_and(psi)) {
224 conjuncts = split_conjuncts(psi);
225 } else {
226 conjuncts.push_back(psi);
227 }
228 pbes_expression conjunction = true_();
229 for (auto phi_i: conjuncts)
230 {
231 pbes_expression r = rewrite_bqnf_expression(phi_i);
232 if (is_or(qexpr)) {
233 if (!is_true(phi)) {
234 phi = filter_guard(phi, r, qvars);
235 r = or_(phi, r);
236 }
237 } else {
238 if (!is_false(phi)) {
239 phi = filter_guard(phi, r, qvars);
240 r = imp(phi, r);
241 }
242 }
243 std::vector<data::variable> qvars_i;
244 std::set<data::variable> free_phi_i;
245 for (const data::variable& v : pbes_system::find_free_variables(phi_i))
246 {
247 free_phi_i.insert(v);
248 }
249 for (const data::variable& var: qvars)
250 {
251 if (free_phi_i.find(var) != free_phi_i.end()) // free_phi_i.contains(v)
252 {
253 qvars_i.push_back(var);
254 }
255 }
256 // qvars_i = qvars intersects free(phi_i)
257 if (!qvars_i.empty()) {
258 r = optimized_forall(data::variable_list(qvars_i.begin(), qvars_i.end()), r);
259 }
260 if (is_true(conjunction)) {
261 conjunction = r;
262 } else {
263 conjunction = and_(conjunction, r);
264 }
265 }
266 result = conjunction;
267 } else {
268 // qexpr not of the form phi => psi
269 //std::clog << "rewrite_bounded_forall: unexpected qexpr = " << pp(qexpr) << std::endl;
270 throw(std::runtime_error("rewrite_bounded_forall: unexpected qexpr."));
271 }
272 }
273 return result;
274 }
275
276
277
278 /// \brief Rewrites a bounded existential quantifier expression.
279 /// rewrite_bounded_exists(exists v . phi) = exists v. rewrite_bqnf_expression(phi)
280 /// \param e a PBES expression
281 /// \return the expression resulting from the transformation.
283 {
284 assert(is_exists(e));
286 data::variable_list qvars = quantifier_variables(e);
287 while (is_exists(qexpr)) {
288 qvars = qvars + quantifier_variables(qexpr);
290 }
292 pbes_expression result = optimized_exists(qvars, r);
293 return result;
294 }
295
296
297 /// \brief Rewrites a conjunctive expression.
298 /// rewrite_imp(/\_i phi_i) = /\_i rewrite_bqnf_expression(phi_i).
299 /// \param e a PBES expression
300 /// \return the expression resulting from the transformation.
302 {
303 pbes_expression conjunction = true_();
304 std::vector<pbes_equation> new_eqns;
305 std::vector<pbes_expression> conjuncts = split_conjuncts(e);
306 for (auto expr: conjuncts)
307 {
308 pbes_expression r = rewrite_bqnf_expression(expr);
309 if (is_true(conjunction)) {
310 conjunction = r;
311 } else {
312 conjunction = and_(conjunction, r);
313 }
314 }
315 return conjunction;
316 }
317
318
319 /// \brief Rewrites a disjunctive expression.
320 /// rewrite_imp(\/_i phi_i) = \/_i rewrite_bqnf_expression(phi_i).
321 /// \param e a PBES expression
322 /// \return the expression resulting from the transformation.
324 {
325 pbes_expression disjunction = false_();
326 std::vector<pbes_expression> new_exprs;
327 std::vector<pbes_expression> disjuncts = split_disjuncts(e);
328 for (auto expr: disjuncts)
329 {
330 pbes_expression r = rewrite_bqnf_expression(expr);
331 if (is_false(disjunction)) {
332 disjunction = r;
333 } else {
334 disjunction = or_(disjunction, r);
335 }
336 }
337 return disjunction;
338 }
339
340
341 /// \brief Rewrites an implication:
342 /// rewrite_imp(phi => psi) =
343 /// rewrite_bqnf_expression(phi) => rewrite_bqnf_expression(psi).
344 /// \param e a PBES expression
345 /// \return the expression resulting from the transformation.
347 {
350 pbes_expression result = imp(l, r);
351 return result;
352 }
353
354
355 /// \brief Rewrites a BQNF expression.
356 /// Replaces universal quantifier over conjuncts with conjuncts over universal quantifiers:
357 /// rewrite_bqnf_expression(forall x . /\_i phi_i) =
358 /// /\_i forall (x intersection free(phi_i)) . phi_i
359 /// For subexpressions the transformation is done in the usual way:
360 /// rewrite_bqnf_expression(phi 'op' psi) =
361 /// rewrite_bqnf_expression(phi) 'op' rewrite_bqnf_expression(psi).
362 /// \param e a PBES expression
363 /// \return the expression resulting from the transformation.
365 {
366 pbes_expression result;
367 if (is_propositional_variable_instantiation(e) || is_simple_expression(e, false)) {
368 // Eqn of the form sigma X(d: D) = phi && Y(h(d, l)), with phi a simple formula.
369 // Add sigma X(d) = e.
370 result = e;
371 } else if (is_forall(e)) {
373 } else if (is_exists(e)) {
375 } else if (is_or(e)) {
376 result = rewrite_or(e);
377 } else if (is_imp(e)) {
378 result = rewrite_imp(e);
379 } else if (is_and(e)) {
380 result = rewrite_and(e);
381 } else {
382 std::clog << "Unexpected expression: " << pp(e) << std::endl;
383 throw(std::runtime_error("Unexpected expression."));
384 }
385 return result;
386 }
387
388 };
389
390 } // namespace mcrl2::pbes_system::detail
391
392#endif // MCRL2_PBES_DETAIL_BQNF_QUANTIFIER_REWRITER_H
\brief The and operator for pbes expressions
and_(const pbes_expression &left, const pbes_expression &right)
\brief Constructor Z14.
\brief The implication operator for pbes expressions
imp(const pbes_expression &left, const pbes_expression &right)
\brief Constructor Z14.
\brief The not operator for pbes expressions
not_(const pbes_expression &operand)
\brief Constructor Z14.
\brief The or operator for pbes expressions
or_(const pbes_expression &left, const pbes_expression &right)
\brief Constructor Z14.
pbes_expression & operator=(pbes_expression &&) noexcept=default
pbes_expression & operator=(const pbes_expression &) noexcept=default
The namespace for accessor functions on pbes expressions.
const pbes_expression & arg(const pbes_expression &t)
Returns the pbes expression argument of expressions of type not, exists and forall.
const pbes_expression & left(const pbes_expression &t)
Returns the left hand side of an expression of type and, or or imp.
const pbes_expression & right(const pbes_expression &t)
Returns the right hand side of an expression of type and, or or imp.
bool is_data(const pbes_expression &t)
Returns true if the term t is a data expression.
const pbes_expression & true_()
bool is_exists(const atermpp::aterm &x)
bool is_or(const atermpp::aterm &x)
bool is_forall(const atermpp::aterm &x)
bool is_propositional_variable_instantiation(const atermpp::aterm &x)
bool is_and(const atermpp::aterm &x)
bool is_imp(const atermpp::aterm &x)
const pbes_expression & false_()
virtual pbes_expression filter_guard(const pbes_expression &g, const pbes_expression &phi_i, const data::variable_list &d)
Filters a 'guard' g with respect to a set of variables d and an expression phi_i such that parts of g...
virtual pbes_expression rewrite_bqnf_expression(const pbes_expression &e)
Rewrites a BQNF expression. Replaces universal quantifier over conjuncts with conjuncts over universa...
virtual pbes_expression rewrite_bounded_forall(const pbes_expression &e)
Rewrites a bounded universal quantifier expression. If the subexpression is a conjunction,...
virtual pbes_expression rewrite_and(const pbes_expression &e)
Rewrites a conjunctive expression. rewrite_imp(/_i phi_i) = /_i rewrite_bqnf_expression(phi_i).
virtual pbes_expression rewrite_imp(const pbes_expression &e)
Rewrites an implication: rewrite_imp(phi => psi) = rewrite_bqnf_expression(phi) => rewrite_bqnf_expre...
virtual pbes_expression rewrite_bounded_exists(const pbes_expression &e)
Rewrites a bounded existential quantifier expression. rewrite_bounded_exists(exists v ....
virtual pbes_expression filter(const pbes_expression &e, const std::set< data::variable > &d)
Filters the expression e such that subexpressions that are data expression that do not refer to varia...
virtual pbes_expression rewrite_or(const pbes_expression &e)
Rewrites a disjunctive expression. rewrite_imp(\/_i phi_i) = \/_i rewrite_bqnf_expression(phi_i).
A visitor class for PBES equations in BQNF. There is a visit_<node> function for each type of node....