mCRL2
Loading...
Searching...
No Matches
quantifier_propagate.h
Go to the documentation of this file.
1// Author(s): Thomas Neele
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/quantifier_propagate.h
10
11#ifndef MCRL2_PBES_QUANTIFIER_PROPAGATE_H
12#define MCRL2_PBES_QUANTIFIER_PROPAGATE_H
13
14#include "mcrl2/data/rewriter.h"
15#include "mcrl2/pbes/replace.h"
16
17#include <queue>
18#include <ranges>
19
20namespace mcrl2::pbes_system {
21
22namespace detail {
23
25
26inline
28{
30}
31
32inline
34{
36}
37
38inline
40{
42}
43
45{
46protected:
49
51 {
53 }
54
55public:
58 , m_vars(vars.begin(), vars.end())
59 {}
60
62 {
64 }
65
66 bool is_forall() const
67 {
68 return m_is_forall;
69 }
70
71 const std::set<data::variable>& variables() const
72 {
73 return m_vars;
74 }
75
76 bool operator==(const quantifier& other) const
77 {
79 }
80
81 bool operator<(const quantifier& other) const
82 {
84 }
85
87 {
89 }
90
92 {
94 }
95
97 {
99 out << (is_forall() ? "forall " : "exists ") << core::detail::print_list(variables()) << ". ";
100 return out.str();
101 }
102};
103
105{
106public:
109 using super::apply;
110 using super::enter;
111
112private:
116
118
120 {
121 // Create list of quantified variables around X_e
122 std::list<quantifier> result;
123 for(const pbes_expression& pe: ctx)
124 {
125 assert(is_forall(pe) || is_exists(pe));
126
127 data::variable_list vars(is_forall(pe) ? atermpp::down_cast<forall>(pe).variables() : atermpp::down_cast<exists>(pe).variables());
128
129 if(result.empty() || result.back().is_forall() != is_forall(pe))
130 {
131 result.emplace_back(is_forall(pe), vars);
132 }
133 else
134 {
135 result.back().add_variables(vars);
136 }
137 }
138 return result;
139 }
140
142 {
143 return m_eqn_map.at(X_e.name());
144 }
145
146public:
149 const equation_map_t& eq_idx)
152 , id_gen(ig)
153 {}
154
155 pbes_expression apply_quantifier(bool is_forall, const data::variable_list& vars, const pbes_expression& body)
156 {
157 pbes_expression x = make_quantifier(is_forall, vars, body);
158 quantified_context.push_back(x);
159
160 pbes_expression result;
161 apply(result, body);
162
163 if(quantified_context.empty())
164 {
165 // The body contained some other operator and the stack was cleared
166 // Reconstruct the quantifier
167 return make_quantifier(is_forall, vars, result);
168 }
169 else
170 {
171 // The body contained a QPVI
172 quantified_context.pop_back();
173 if(result == body)
174 {
175 // The body didn't change, we just return ourselves as well
176 return x;
177 }
178 else
179 {
180 // The body changed, it reconstructed the QPVI, we should not
181 // add anything
182 return result;
183 }
184 }
185 }
186
187 template <class T>
188 void apply(T& result, const forall& x)
189 {
191 }
192
193 template <class T>
194 void apply(T& result, const exists& x)
195 {
197 }
198
199 void enter(const and_& /*x*/)
200 {
201 quantified_context.clear();
202 }
203
204 void enter(const or_& /*x*/)
205 {
206 quantified_context.clear();
207 }
208
209 void enter(const imp& /*x*/)
210 {
211 quantified_context.clear();
212 }
213
214 void enter(const not_& /*x*/)
215 {
216 quantified_context.clear();
217 }
218
219 template <class T>
220 void apply(T& result, const propositional_variable_instantiation& X_e)
221 {
222 using utilities::detail::contains;
223 using utilities::detail::set_difference;
224 using utilities::detail::set_includes;
225 using utilities::detail::set_intersection;
226
227 std::list<quantifier> qvars = make_quantifier_list(quantified_context);
228 if(qvars.empty())
229 {
230 result = X_e;
231 return;
232 }
233
234 const std::vector<data::variable> parameters(find_equation(X_e).variable().parameters().begin(), find_equation(X_e).variable().parameters().end());
235 const std::vector<data::data_expression> updates(X_e.parameters().begin(), X_e.parameters().end());
236
237 std::list<std::size_t> independent_pars;
238 std::set<data::variable> quantified_variables;
239 for(const quantifier& qv: qvars)
240 {
241 quantified_variables.insert(qv.variables().begin(), qv.variables().end());
242 }
243
244 // Start building a list of parameters that are constant and can be pushed through X_e
245 std::set<data::variable> seen;
246 std::size_t i = 0;
247 for(const data::data_expression& up: updates)
248 {
249 std::set<data::variable> fv = find_free_variables(up);
250 if(set_includes(quantified_variables, fv))
251 {
252 independent_pars.push_back(i);
253 }
254 else
255 {
256 seen.insert(fv.begin(), fv.end());
257 }
258 i++;
259 }
260 std::queue<data::variable> todo(std::deque<data::variable>(seen.begin(), seen.end()));
261
262 // Add all transitive dependencies, either because they occur together in one
263 // of the updates, or because of their quantifier scopes
264 while(!todo.empty())
265 {
266 data::variable elem = todo.front();
267 todo.pop();
268
269 // Check for each update if it contains elem. If so, elem also influences the
270 // other free variables in that update expression an the parameter is not independent.
271 for(std::list<std::size_t>::const_iterator ip = independent_pars.begin(); ip != independent_pars.end(); )
272 {
273 std::set<data::variable> fv = find_free_variables(updates[*ip]);
274 if(contains(fv, elem))
275 {
276 for(const data::variable& var: set_difference(fv, seen))
277 {
278 todo.push(var);
279 seen.insert(var);
280 }
281 ip = independent_pars.erase(ip);
282 }
283 else
284 {
285 ++ip;
286 }
287 }
288
289 // Check if we need to add quantified variables that have a larger scope and
290 // and are at least one quantifier alternation away from elem
291 bool add_rest = false;
292 for (auto& qvar: std::ranges::reverse_view(qvars))
293 {
294 const std::set<data::variable>& vars = qvar.variables();
295 if(add_rest)
296 {
297 for(const data::variable& var: set_difference(vars, seen))
298 {
299 seen.insert(var);
300 todo.push(var);
301 }
302 }
303 else if(contains(vars, elem))
304 {
305 add_rest = true;
306 }
307 }
308 }
309
310 // Check whether there is at least one independent parameter and we are
311 // propagating at least one quantified variable.
312 if(independent_pars.empty() ||
313 set_difference(qvars.back().variables(), seen).empty())
314 {
315 result = X_e;
316 return;
317 }
318
319 // Build a new equation based on the independent parameters found
320 data::variable_list new_parameter_list;
321 data::data_expression_list new_update_list;
322 i = 0;
323 auto ip = independent_pars.begin();
324 data::rewriter::substitution_type sigma;
325
326 for(const data::variable& par: parameters)
327 {
328 if(ip != independent_pars.end() && *ip == i)
329 {
330 sigma[par] = updates[i];
331 ++ip;
332 }
333 else
334 {
335 new_parameter_list.push_front(par);
336 new_update_list.push_front(updates[i]);
337 }
338 i++;
339 }
340 new_parameter_list = reverse(new_parameter_list);
341 new_update_list = reverse(new_update_list);
342
343 // Construct a new PVI and a new equation
344 core::identifier_string new_name = id_gen(X_e.name());
345 pbes_expression new_rhs_X = pbes_system::replace_free_variables(find_equation(X_e).formula(), sigma);
346 propositional_variable_instantiation new_X_e(new_name, new_update_list);
347 pbes_expression new_Q_X_e = new_X_e;
348 for (auto& qvar: std::ranges::reverse_view(qvars))
349 {
350 new_Q_X_e = qvar.make_expr_include_only(seen, new_Q_X_e);
351 new_rhs_X = qvar.make_expr_exclude(seen, new_rhs_X);
352 }
353 pbes_equation new_eqn(find_equation(X_e).symbol(), propositional_variable(new_name, new_parameter_list), new_rhs_X);
354 m_new_equations.emplace_back(X_e.name(), new_eqn);
355
356 result = new_Q_X_e;
357 }
358};
359
360inline
366{
368 f.update(x);
369}
370
371} // namespace detail
372
373inline
375{
376 std::list<std::pair<core::identifier_string, pbes_equation>> new_equations;
377 detail::quantifier_propagate_builder::equation_map_t m_eqn_map;
379 for(const pbes_equation& eq: p.equations())
380 {
381 id_gen.add_identifier(eq.variable().name());
382 m_eqn_map[eq.variable().name()] = eq;
383 }
384
385 for(pbes_equation& eqn: p.equations())
386 {
387 detail::quantifier_propagate(new_equations, id_gen, m_eqn_map, eqn.formula());
388 }
389
390 // Insert new equations
391 for(const auto& [target, eqn]: new_equations)
392 {
393 // Find the original location, so ranks are preserved
394 p.equations().insert(
395 std::find_if(p.equations().begin(), p.equations().end(),
396 [t = target](const pbes_equation& eq){ return eq.variable().name() == t; }),
397 eqn
398 );
399 }
400}
401
402inline
404{
405 pbes result{p};
407 return result;
408}
409
410} // namespace mcrl2::pbes_system
411
412
413
414#endif // MCRL2_PBES_QUANTIFIER_PROPAGATE_H
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
const pbes_expression & body() const
\brief The universal quantification operator for pbes expressions
const pbes_expression & body() const
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
\brief A propositional variable instantiation
void quantifier_propagate(std::list< std::pair< core::identifier_string, pbes_equation > > &new_equations, data::set_identifier_generator &id_gen, const quantifier_propagate_builder::equation_map_t eqn_map, pbes_expression &x)
pbes_expression make_exists_(std::set< data::variable > vars, const pbes_expression &expr)
pbes_expression quantifier_propagate(const pbes_expression &x)
void quantifier_propagate(pbes &p)
pbes quantifier_propagate(const pbes &p)
quantifier_propagate_builder(std::list< std::pair< core::identifier_string, pbes_equation > > &new_eqns, data::set_identifier_generator &ig, const equation_map_t &eq_idx)
pbes_equation find_equation(const propositional_variable_instantiation &X_e)
void apply(T &result, const propositional_variable_instantiation &X_e)
pbes_expression apply_quantifier(bool is_forall, const data::variable_list &vars, const pbes_expression &body)
std::list< quantifier > make_quantifier_list(const std::list< pbes_expression > &ctx) const