mCRL2
Loading...
Searching...
No Matches
preprocess_state_formula.h
Go to the documentation of this file.
1// Author(s): Wieger Wesselink
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/modal_formula/preprocess_state_formula.h
10/// \brief add your file description here.
11
12#ifndef MCRL2_MODAL_FORMULA_PREPROCESS_STATE_FORMULA_H
13#define MCRL2_MODAL_FORMULA_PREPROCESS_STATE_FORMULA_H
14
15#include "mcrl2/data/detail/find.h"
16#include "mcrl2/data/xyz_identifier_generator.h"
17#include "mcrl2/modal_formula/has_name_clashes.h"
18#include "mcrl2/modal_formula/is_monotonous.h"
19#include "mcrl2/modal_formula/normalize.h"
20#include "mcrl2/modal_formula/resolve_name_clashes.h"
21#include "mcrl2/modal_formula/state_formula_rename.h"
22
23namespace mcrl2::state_formulas
24{
25
26namespace detail
27{
28
30{
32 using super::enter;
33 using super::leave;
34 using super::apply;
35
38
40 {
42 }
43
45 {
46 nesting_depth.push_back(0);
47 }
48
50 {
51 nesting_depth.pop_back();
52 }
53
55 {
56 nesting_depth.back()++;
57 if (nesting_depth.back() > result)
58 {
59 result = nesting_depth.back();
60 }
61 }
62
64 {
65 nesting_depth.back()--;
66 }
67
68 void enter(const must&)
69 {
71 }
72
73 void leave(const must&)
74 {
76 }
77
78 void enter(const may&)
79 {
81 }
82
83 void leave(const may&)
84 {
86 }
87
88 void enter(const mu&)
89 {
91 }
92
93 void leave(const mu&)
94 {
96 }
97
98 void enter(const nu&)
99 {
101 }
102
103 void leave(const nu&)
104 {
106 }
107
108 void enter(const forall&)
109 {
111 }
112
113 void leave(const forall&)
114 {
116 }
117
118 void enter(const exists&)
119 {
121 }
122
123 void leave(const exists&)
124 {
126 }
127};
128
129inline
131{
133 f.apply(x);
134 return f.result;
135}
136
137/// \brief Traverser that detects unscoped modal operators.
139{
141 using super::enter;
142 using super::leave;
143 using super::apply;
144
145 bool result = false;
146
147 /// \brief Stack of the fixpoint operators (mu/nu) that enclose the current node.
148 /// When it is empty, any modal operator that is visited is unscoped.
150
151 void push(const state_formula& x)
152 {
153 fixpoints.push_back(x);
154 }
155
156 void pop()
157 {
158 fixpoints.pop_back();
159 }
160
161 void enter(const must&)
162 {
163 if (fixpoints.empty())
164 {
165 result = true;
166 }
167 }
168
169 void enter(const may&)
170 {
171 if (fixpoints.empty())
172 {
173 result = true;
174 }
175 }
176
177 void enter(const mu& x)
178 {
179 push(x);
180 }
181
182 void leave(const mu&)
183 {
184 pop();
185 }
186
187 void enter(const nu& x)
188 {
189 push(x);
190 }
191
192 void leave(const nu&)
193 {
194 pop();
195 }
196};
197
198/// \brief Checks whether a state formula contains an unscoped modal operator.
199/// A modal operator (must '[a]' or may '<a>') is <em>unscoped</em> when, on the path from the root of
200/// the formula to that operator, it is not preceded by a fixpoint operator (mu or nu). In other words,
201/// the modal operator is not contained in the scope of any fixpoint. For example '[a]true' and
202/// 'true => <a>true' contain an unscoped modal operator, whereas in 'mu X. [a]<b>true' both modal
203/// operators are scoped by the surrounding 'mu X'.
204inline
206{
208 f.apply(x);
209 return f.result;
210}
211
212/// Visitor that transforms state formulas. This can be useful if the state formula contains nested modal operators.
213template <typename IdentifierGenerator>
215{
218 using super::enter;
219 using super::leave;
220 using super::update;
221 using super::apply;
222
223 /// \brief An identifier generator
224 IdentifierGenerator& generator;
226
227 /// \brief Constructor
228 /// \param generator A generator for fresh identifiers
230 : generator(generator)
231 {}
232
233 void push(const state_formula& x)
234 {
235 fixpoints.push_back(x);
236 }
237
238 void pop()
239 {
240 fixpoints.pop_back();
241 }
242
243 bool is_mu()
244 {
245 if (fixpoints.empty())
246 {
247 return true;
248 }
249 return state_formulas::is_mu(fixpoints.back());
250 }
251
252 void enter(const mu& x)
253 {
254 push(x);
255 }
256
257 void leave(const mu&)
258 {
259 pop();
260 }
261
262 void enter(const nu& x)
263 {
264 push(x);
265 }
266
267 void leave(const nu&)
268 {
269 pop();
270 }
271
272 template <class T>
273 void apply(T& result, const must& x)
274 {
275 state_formula operand;
276 apply(operand, x.operand());
278 {
279 make_must(result, x.formula(), operand);
280 return;
281 }
282 core::identifier_string X = generator("X");
283 if (is_mu())
284 {
285 make_must(result, x.formula(), mu(X, {}, operand));
286 return;
287 }
288 else
289 {
290 make_must(result, x.formula(), nu(X, {}, operand));
291 return;
292 }
293 }
294
295 template <class T>
296 void apply(T& result, const may& x)
297 {
298 state_formula operand;
299 apply(operand, x.operand());
301 {
302 make_may(result, x.formula(), operand);
303 return;
304 }
305 core::identifier_string X = generator("X");
306 if (is_mu())
307 {
308 make_may(result, x.formula(), mu(X, {}, operand));
309 return;
310 }
311 else
312 {
313 make_may(result, x.formula(), nu(X, {}, operand));
314 return;
315 }
316 }
317};
318
319/// \brief Utility function for creating a state_formula_preprocess_nested_modal_operators_builder.
320/// \param generator A generator for fresh identifiers
321/// \return a state_formula_preprocess_nested_modal_operators_builder
322template <typename IdentifierGenerator>
324{
325 return state_formula_preprocess_nested_modal_operators_builder<IdentifierGenerator>(generator);
326}
327
328} // namespace detail
329
330/// \brief Preprocesses a state formula that contains (nested) modal operators
331/// \param x A modal formula
332inline
334{
336 std::set<core::identifier_string> ids = state_formulas::find_identifiers(x);
337 generator.add_identifiers(ids);
338 state_formula result;
339 detail::make_state_formula_preprocess_nested_modal_operators_builder(generator).apply(result, x);
340 return result;
341}
342
343/// \brief Renames data variables and predicate variables in the formula \p f, and
344/// wraps the formula inside a 'nu' if needed. This is needed as a preprocessing
345/// step for the algorithm.
346/// \param formula A modal formula.
347/// \param context_ids A set of identifier strings.
348/// \param preprocess_modal_operators A boolean indicating that dummy fixed point symbols can be
349/// inserted which makes subsequent handling easier.
350/// \param warn_for_modal_operator_nesting A boolean enabling warnings for modal operator nesting.
351/// \return The preprocessed formula.
352inline
354 const std::set<core::identifier_string>& context_ids,
355 bool preprocess_modal_operators,
356 bool quantitative = false,
357 bool warn_for_modal_operator_nesting = true
358 )
359{
360 state_formulas::state_formula f = formula;
361
363 {
364 throw mcrl2::runtime_error("The formula " + state_formulas::pp(f) + " is not monotonous!");
365 }
366
367 if (!preprocess_modal_operators && warn_for_modal_operator_nesting && state_formulas::detail::count_modal_operator_nesting(formula) >= 3)
368 {
369 mCRL2log(log::info) <<
370 "Warning: detected nested modal operators. This may result in a long execution time.\n"
371 "Use the option -m (for lps2pbes/lps2pres), -p (for lts2pbes/lts2pres) or insert dummy fix \n"
372 "point operators in between manually to speed up the transformation." << std::endl;
373 }
374
375 mCRL2log(log::debug) << "Formula before preprocessing: " << f << ".\n";
376
377 // rename data variables in f, to prevent name clashes with data variables in the context
378 std::set<core::identifier_string> ids = state_formulas::find_identifiers(f);
379 ids.insert(context_ids.begin(), context_ids.end());
380 f = state_formulas::rename_variables(f, ids);
381
382 // rename predicate variables in f, to prevent name clashes
383 data::xyz_identifier_generator xyz_generator;
384 xyz_generator.add_identifiers(state_formulas::find_identifiers(f));
385 f = rename_predicate_variables(f, xyz_generator);
386
387 mCRL2log(log::debug) << "Formula after renaming variables: " << f << ".\n";
388
389 // add dummy fixpoints between nested modal operators
390 if (preprocess_modal_operators)
391 {
392 state_formula f0 = f;
394 if (f0 != f)
395 {
396 mCRL2log(log::debug) << "Formula after inserting dummy fix points between modal operators: " << f << ".\n";
397 }
398 }
399
400 // remove occurrences of ! and =>
401 if (!state_formulas::is_normalized(f))
402 {
403 f = state_formulas::normalize(f, quantitative); // true indicates that the formula is quantitative.
404 mCRL2log(log::debug) << "Formula after normalization: " << f << ".\n";
405 assert(state_formulas::is_normalized(f));
406 }
407
408 // wrap the formula inside a 'nu' if needed
410 {
412 generator.add_identifiers(state_formulas::find_identifiers(f));
413 core::identifier_string X = generator("X");
414 f = state_formulas::nu(X, data::assignment_list(), f);
415 mCRL2log(log::debug) << "Formula after wrapping the formula inside a 'nu': " << f << ".\n";
416 }
417
418 // resolve name clashes like mu X(n: Nat). forall n: Nat
420 {
421 f = resolve_state_formula_data_variable_name_clashes(f, context_ids);
422 mCRL2log(log::debug) << "formula after removing data variable name clashes: " << f << std::endl;
423 }
424
425 mCRL2log(log::debug) << "formula after preprocessing: " << f << std::endl;
426
427 return f;
428}
429
430} // namespace mcrl2::state_formulas
431
432#endif // MCRL2_MODAL_FORMULA_PREPROCESS_STATE_FORMULA_H
Identifier generator that stores the identifiers of the context in a set. Using the operator()() and ...
Identifier generator that generates names from the range X, Y, Z, X0, Y0, Z0, X1, ....
\brief The existential quantification operator for state formulas
\brief The universal quantification operator for state formulas
\brief The may operator for state formulas
const state_formula & operand() const
const regular_formulas::regular_formula & formula() const
\brief The mu operator for state formulas
\brief The must operator for state formulas
const regular_formulas::regular_formula & formula() const
const state_formula & operand() const
\brief The nu operator for state formulas
nu(const core::identifier_string &name, const data::assignment_list &assignments, const state_formula &operand)
\brief Constructor Z14.
state_formula & operator=(state_formula &&) noexcept=default
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:392
state_formula_preprocess_nested_modal_operators_builder< IdentifierGenerator > make_state_formula_preprocess_nested_modal_operators_builder(IdentifierGenerator &generator)
Utility function for creating a state_formula_preprocess_nested_modal_operators_builder.
bool has_unscoped_modal_formulas(const state_formula &x)
Checks whether a state formula contains an unscoped modal operator. A modal operator (must '[a]' or m...
std::size_t count_modal_operator_nesting(const state_formula &x)
state_formula preprocess_nested_modal_operators(const state_formula &x)
Preprocesses a state formula that contains (nested) modal operators.
bool has_data_variable_name_clashes(const state_formula &x)
Returns true if the formula contains parameter name clashes.
bool is_monotonous(const state_formula &f)
Returns true if the state formula is monotonous.
bool is_nu(const atermpp::aterm &x)
state_formulas::state_formula preprocess_state_formula(const state_formulas::state_formula &formula, const std::set< core::identifier_string > &context_ids, bool preprocess_modal_operators, bool quantitative=false, bool warn_for_modal_operator_nesting=true)
Renames data variables and predicate variables in the formula f, and wraps the formula inside a 'nu' ...
bool is_mu(const atermpp::aterm &x)
std::vector< state_formula > fixpoints
Stack of the fixpoint operators (mu/nu) that enclose the current node. When it is empty,...
Visitor that transforms state formulas. This can be useful if the state formula contains nested modal...