10#ifndef MCRL2_PBES_CONSTELM_H
11#define MCRL2_PBES_CONSTELM_H
15#include "mcrl2/pbes/algorithms.h"
16#include "mcrl2/pbes/pbes_rewriter_type.h"
17#include "mcrl2/pbes/print.h"
18#include "mcrl2/pbes/replace.h"
19#include "mcrl2/pbes/rewriters/enumerate_quantifiers_rewriter.h"
20#include "mcrl2/pbes/detail/pbes_remove_counterexample_info.h"
33 for (
const auto& i : m)
35 result[i.first] = i.second;
68 return !(*
this == other);
83 std::ostringstream out;
84 out << (is_forall() ?
"forall " :
"exists ") << variable() <<
": " << variable().sort() <<
". ";
97 return std::tie(Q, X_e) < std::tie(other.Q, other.X_e);
144 template <
class... Args>
147 condition_fv_stack.emplace_back(std::forward<Args>(args)...);
152 condition_fv_stack.push_back(x);
157 return condition_fv_stack.back();
160 const stack_elem&
top()
const
162 return condition_fv_stack.back();
171 stack_elem result = std::move(condition_fv_stack.back());
172 condition_fv_stack.pop_back();
183 stack_elem&& ec2,
bool negate2,
184 stack_elem& ec,
bool is_conjunctive
188 for (
auto& i: ec1.edges)
190 auto& [Q_X_e, details] = i;
191 details.conditions.insert(negate2 ? ec2.Cneg : ec2.Cpos);
192 (is_conjunctive ? details.conjunctive_context_FV : details.disjunctive_context_FV)
193 .insert(ec2.FV.begin(), ec2.FV.end());
194 ec.edges.insert(std::move(i));
196 for (
auto& i: ec2.edges)
198 auto& [Q_X_e, details] = i;
199 details.conditions.insert(negate1 ? ec1.Cneg : ec1.Cpos);
200 (is_conjunctive ? details.conjunctive_context_FV : details.disjunctive_context_FV)
201 .insert(ec1.FV.begin(), ec1.FV.end());
202 ec.edges.insert(std::move(i));
209 quantified_context.clear();
214 quantified_context.clear();
219 quantified_context.clear();
224 quantified_context.clear();
229 quantified_context.push_back(x);
234 quantified_context.push_back(x);
241 data::optimized_not(cond_not, x);
243 emplace(x, cond_not,
data::find_free_variables(x));
253 stack_elem ec_right =
pop();
254 stack_elem ec_left =
pop();
260 emplace(cond_and, cond_or,
262 merge_conditions(std::move(ec_left),
false, std::move(ec_right),
false, top(),
true);
267 stack_elem ec_right =
pop();
268 stack_elem ec_left =
pop();
275 emplace(cond_or, cond_and,
277 merge_conditions(std::move(ec_left),
true, std::move(ec_right),
true, top(),
false);
282 stack_elem ec_right =
pop();
283 stack_elem ec_left =
pop();
290 emplace(cond_or, cond_and,
292 merge_conditions(std::move(ec_left),
false, std::move(ec_right),
true, top(),
false);
298 stack_elem ec =
pop();
299 for (
auto& [X_e, details]: ec.edges)
301 auto& [cond_set, conj_FV, disj_FV] = details;
304 std::set<data::data_expression> new_conditions;
305 for(
const data::data_expression& e: cond_set)
307 data::data_expression t;
308 data::optimized_exists(t, x.variables(), e,
true);
309 new_conditions.insert(t);
311 cond_set = std::move(new_conditions);
312 data::data_expression forall;
313 data::optimized_forall(forall, x.variables(), ec.Cpos,
true);
315 cond_set.insert(forall);
322 std::set<data::variable> bound_vars{x.variables().begin(), x.variables().end()};
323 ec.FV = utilities::detail::set_difference(ec.FV, bound_vars);
327 if(!quantified_context.empty() && quantified_context.back() == x)
329 quantified_context.pop_back();
336 stack_elem ec =
pop();
337 for (
auto& [X_e, details]: ec.edges)
339 auto& [cond_set, conj_FV, disj_FV] = details;
342 std::set<data::data_expression> new_conditions;
343 for(
const data::data_expression& e: cond_set)
345 data::data_expression t;
346 data::optimized_exists(t, x.variables(), e,
true);
347 new_conditions.insert(t);
349 cond_set = std::move(new_conditions);
351 data::data_expression forall;
352 data::optimized_forall(forall, x.variables(), ec.Cneg,
true);
353 cond_set.insert(forall);
360 std::set<data::variable> bound_vars{x.variables().begin(), x.variables().end()};
361 ec.FV = utilities::detail::set_difference(ec.FV, bound_vars);
365 if(!quantified_context.empty() && quantified_context.back() == x)
367 quantified_context.pop_back();
375 for(
const pbes_expression& expr: quantified_context)
377 assert(is_forall(expr) || is_exists(expr));
378 data::variable_list vars(is_forall(expr) ? atermpp::down_cast<forall>(expr).variables() : atermpp::down_cast<exists>(expr).variables());
379 for(
const data::variable& v: vars)
381 qvars.emplace_back(is_forall(expr), v);
384 QPVI Q_X_e{.Q = qvars, .X_e = x};
388 top().edges.emplace(Q_X_e,
389 edge_details{.conditions = std::set<data::data_expression>{data::sort_bool::true_()},
390 .conjunctive_context_FV = std::set<data::variable>{},
391 .disjunctive_context_FV = std::set<data::variable>{}});
396 assert(condition_fv_stack.size() == 1);
406template <
typename DataRewriter,
typename PbesRewriter>
456 const qvar_list& qvars,
458 const std::set<data::variable>& conj_context,
459 const std::set<data::variable>& disj_context,
474 std::ostringstream out;
475 out <<
"(" << m_source.name() <<
", " << m_target.name() <<
") label = ";
476 for(
const detail::quantified_variable& qv: m_qvars)
478 out << qv.to_string();
480 out << m_target <<
" condition = " << condition();
481 out <<
"; conjunctive context = {";
482 for (
const data::variable& var: m_conj_context)
484 out << var <<
": " << var.sort() <<
", ";
486 out <<
"}; disjunctive context = {";
487 for (
const data::variable& var: m_disj_context)
489 out << var <<
": " << var.sort() <<
", ";
522 const qvar_list& Q = source.quantified_variables();
523 const data::variable_list& par_def = source.variable().parameters();
524 const constraint_map& constraints = source.constraints();
526 data::rewriter::substitution_type sigma;
527 detail::make_constelm_substitution(constraints, sigma);
530 for (
const auto& it: std::ranges::reverse_view(Q))
532 bool is_forall = it.is_forall();
533 const data::variable& var = it.variable();
536 const std::set<data::variable>& context = is_forall ? m_disj_context : m_conj_context;
537 bool none_occurs_in_context =
true;
539 auto it_pvi = m_target.parameters().begin();
540 auto it_def = par_def.begin();
541 for (; it_pvi != m_target.parameters().end(); ++it_pvi, ++it_def)
543 if (context.find(*it_def) != context.end() && data::search_free_variable(rewr(*it_pvi, sigma), var))
545 none_occurs_in_context =
false;
550 if (none_occurs_in_context)
552 result.push_front(it);
585 auto i = m_constraints.find(v);
586 return i != m_constraints.end();
592 std::set<data::variable> free_vars = data::find_free_variables(e);
593 return std::all_of(free_vars.begin(), free_vars.end(), [&](
const data::variable& v)
595 return std::find_if(qvars.begin(), qvars.end(), [&](
const detail::quantified_variable& qvar){
return qvar.variable() == v; }) != qvars.end();
604 while (!deleted_constraints.empty())
606 std::set<data::variable> vars_deleted;
607 for (
const data::data_expression& fi: deleted_constraints)
609 data::find_free_variables(fi, std::inserter(vars_deleted, vars_deleted.end()));
611 deleted_constraints.clear();
613 auto del_i = std::find_if(m_qvars.rbegin(), m_qvars.rend(), [&](
const detail::quantified_variable& qv)
615 return vars_deleted.find(qv.variable()) != vars_deleted.end();
618 m_qvars.erase(m_qvars.begin(), del_i.base());
620 for (
const data::variable& par: m_variable.parameters())
622 auto k = m_constraints.find(par);
623 if(k == m_constraints.end())
627 if(!bound_in_quantifiers(m_qvars, k->second))
629 deleted_constraints.push_back(k->second);
630 m_constraints.erase(k);
661 return m_constraints;
668 std::vector<std::size_t> result;
669 std::size_t index = 0;
670 for (
const data::variable& parameter: m_variable.parameters())
672 if (is_constant(parameter))
674 result.push_back(index);
685 std::ostringstream out;
686 out << m_variable <<
" assertions = ";
687 for(
const detail::quantified_variable& v: quantified_variables())
689 out << v.to_string();
691 for (
const auto& constraint: m_constraints)
693 out <<
"{" << constraint.first <<
" := " << constraint.second <<
"} ";
700 bool update(
const qvar_list& qvars,
const data::data_expression_list& e,
const constraint_map& e_constraints,
const DataRewriter& datar)
702 bool changed =
false;
704 data::variable_list params = m_variable.parameters();
705 data::rewriter::substitution_type sigma;
706 detail::make_constelm_substitution(e_constraints, sigma);
716 std::vector<data::data_expression> deleted_constraints;
717 auto par = params.begin();
718 for (
auto i = e.begin(); i != e.end(); ++i, ++par)
720 data::data_expression e1 = datar(*i, sigma);
721 if (bound_in_quantifiers(m_qvars, e1))
723 m_constraints[*par] = e1;
727 deleted_constraints.push_back(e1);
730 fix_constraints(deleted_constraints);
735 auto mismatch_it = std::mismatch(m_qvars.rbegin(), m_qvars.rend(), qvars.rbegin(), qvars.rend()).first;
736 changed |= mismatch_it != m_qvars.rend();
738 m_qvars.erase(m_qvars.begin(), mismatch_it.base());
742 std::vector<data::data_expression> deleted_constraints;
744 for (
auto par = params.begin(); i != e.end(); ++i, ++par)
746 auto k = m_constraints.find(*par);
747 if(k == m_constraints.end())
751 const data::data_expression& fi = k->second;
752 data::data_expression ei = datar(*i, sigma);
753 if (fi != ei || !bound_in_quantifiers(m_qvars, fi))
756 deleted_constraints.push_back(fi);
757 deleted_constraints.push_back(ei);
758 m_constraints.erase(k);
761 fix_constraints(deleted_constraints);
787 std::ostringstream out;
788 for (
const auto& v: m_vertices)
790 out << v.second.to_string() << std::endl;
798 std::ostringstream out;
799 for (
const auto& [source, targets]: m_edges)
801 for (
const edge& e: targets)
803 out << e.to_string() << std::endl;
811 std::ostringstream out;
812 out <<
"\n<todo list> [";
813 for (
auto i = todo.begin(); i != todo.end(); ++i)
815 if (i != todo.begin())
819 out << core::pp(i->name());
821 out <<
"]" << std::endl;
827 std::ostringstream out;
828 out <<
"\n<updating edge> " << e.to_string() << std::endl;
829 out <<
" <source vertex > " << u.to_string() << std::endl;
830 out <<
" <target vertex before> " << v.to_string() << std::endl;
836 std::ostringstream out;
837 data::rewriter::substitution_type sigma;
838 detail::make_constelm_substitution(u.constraints(), sigma);
839 out <<
" <condition > " << e.condition() << sigma <<
" to " << value << std::endl;
845 std::ostringstream out;
846 data::rewriter::substitution_type sigma;
847 detail::make_constelm_substitution(u.constraints(), sigma);
848 out <<
"\nCould not evaluate condition " << e.condition() << sigma <<
" to true or false";
852 template <
typename E>
855 std::list<E> result(a);
856 result.insert(result.end(), b.begin(), b.end());
1043 data::rewrite_strategy rewrite_strategy,
1044 pbes_rewriter_type rewriter_type,
1045 bool compute_conditions =
false,
1046 bool remove_redundant_equations =
true,
1047 bool check_quantifiers =
true
1051 if (has_counter_example)
1053 mCRL2log(log::warning) <<
"Warning: the PBES has counter example information, which may not be preserved by constant elimination." << std::endl;
1059 switch (rewriter_type)
1061 case pbes_rewriter_type::simplify:
1064 pbes_rewriter pbesr(datar);
1066 algorithm.run(p, compute_conditions, check_quantifiers);
1067 if (remove_redundant_equations)
1069 std::vector<propositional_variable> V = algorithms::remove_unreachable_variables(p);
1070 mCRL2log(log::verbose) << algorithms::print_removed_equations(V);
1074 case pbes_rewriter_type::quantifier_all:
1075 case pbes_rewriter_type::quantifier_finite:
1077 const enumerate_quantifiers_mode enum_mode = (rewriter_type == pbes_rewriter_type::quantifier_all?
1078 expand_infinite_sorts_and_use_data_rewriter:
1079 expand_finite_sorts);
1082 algorithm.run(p, compute_conditions, check_quantifiers);
1083 if (remove_redundant_equations)
1085 std::vector<propositional_variable> V = algorithms::remove_unreachable_variables(p);
1086 mCRL2log(log::verbose) << algorithms::print_removed_equations(V);
data_expression(const data_expression &) noexcept=default
Move semantics.
Rewriter that operates on data expressions.
variable(const variable &) noexcept=default
Move semantics.
\brief The and operator for pbes expressions
pbes_expression make_expr(const pbes_expression &expr) const
std::string to_string() const
bool operator<(const quantified_variable &other) const
quantified_variable(bool is_forall, const data::variable &var)
bool operator==(const quantified_variable &other) const
bool operator!=(const quantified_variable &other) const
\brief The existential quantification operator for pbes expressions
exists(const data::variable_list &variables, const pbes_expression &body)
\brief Constructor Z14.
const data::variable_list & variables() const
\brief The universal quantification operator for pbes expressions
forall(const data::variable_list &variables, const pbes_expression &body)
\brief Constructor Z14.
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
Represents an edge of the dependency graph. The assignments are stored implicitly using the 'right' p...
edge(const propositional_variable &src, const qvar_list &qvars, const propositional_variable_instantiation &tgt, const std::set< data::variable > &conj_context, const std::set< data::variable > &disj_context, data::data_expression c=data::sort_bool::true_())
Constructor.
const propositional_variable_instantiation & target() const
The propositional variable instantiation that determines the target of the edge.
qvar_list quantifier_inside_approximation(const vertex &source, const DataRewriter &rewr) const
Try to guess which quantifiers of Q can end up directly before target, when the quantifier inside rew...
const propositional_variable_instantiation m_target
The propositional variable instantiation that determines the target of the edge.
const qvar_list & quantified_variables() const
const qvar_list m_qvars
The quantifiers in whose direct context the target PVI occurs.
const propositional_variable m_source
The propositional variable at the source of the edge.
const std::set< data::variable > m_disj_context
edge()=default
Constructor.
const data::data_expression & condition() const
The condition of the edge.
const std::set< data::variable > m_conj_context
const propositional_variable & source() const
The propositional variable at the source of the edge.
std::string to_string() const
Returns a string representation of the edge.
Represents a vertex of the dependency graph.
void fix_constraints(std::vector< data::data_expression > deleted_constraints)
Weaken the constraints so they satisfy.
const qvar_list & quantified_variables() const
qvar_list m_qvars
The list of quantified variables that occur in the constraints.
std::string to_string() const
Returns a string representation of the vertex.
bool update(const qvar_list &qvars, const data::data_expression_list &e, const constraint_map &e_constraints, const DataRewriter &datar)
Assign new values to the parameters of this vertex, and update the constraints accordingly....
constraint_map m_constraints
Maps data variables to data expressions. If a parameter is not.
bool m_visited
Indicates whether this vertex has been visited at least once.
const constraint_map & constraints() const
Maps data variables to data expressions. If the right hand side is a data variable,...
bool is_constant(const data::variable &v) const
Returns true if the parameter v has been assigned a constant expression.
propositional_variable m_variable
The propositional variable that corresponds to the vertex.
std::vector< std::size_t > constant_parameter_indices() const
Returns the indices of the constant parameters of this vertex.
const propositional_variable & variable() const
The propositional variable that corresponds to the vertex.
bool bound_in_quantifiers(const qvar_list &qvars, const data::data_expression &e)
Returns true iff all free variables in e are bound in qvars.
vertex(propositional_variable x)
Constructor.
vertex()=default
Constructor.
Algorithm class for the constelm algorithm.
const PbesRewriter & m_pbes_rewriter
Compares data expressions for equality.
std::string print_todo_list(const std::deque< propositional_variable > &todo)
vertex_map m_vertices
The vertices of the dependency graph. They are stored in a map, to support searching for a vertex.
std::string print_edge_update(const edge &e, const vertex &u, const vertex &v)
std::string print_edges()
Logs the edges of the dependency graph.
pbes_constelm_algorithm(const DataRewriter &datar, const PbesRewriter &pbesr)
Constructor.
std::list< E > concat(const std::list< E > a, const std::list< E > b)
std::string print_evaluation_failure(const edge &e, const vertex &u)
const DataRewriter & m_data_rewriter
Compares data expressions for equality.
edge_map m_edges
The edges of the dependency graph. They are stored in a map, to easily access all out-edges correspon...
std::string print_condition(const edge &e, const vertex &u, const pbes_expression &value)
std::string print_vertices() const
Logs the vertices of the dependency graph.
parameterized boolean equation system
\brief A propositional variable instantiation
const data::data_expression_list & parameters() const
propositional_variable_instantiation(const propositional_variable_instantiation &) noexcept=default
Move semantics.
\brief A propositional variable declaration
propositional_variable(const propositional_variable &) noexcept=default
Move semantics.
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Namespace for system defined sort bool_.
const function_symbol & true_()
Constructor for function symbol true.
void make_constelm_substitution(const std::map< data::variable, data::data_expression > &m, data::rewriter::substitution_type &result)
bool has_counter_example_information(const pbes &pbesspec)
Guesses if a pbes has counter example information.
void constelm(pbes &p, data::rewrite_strategy rewrite_strategy, pbes_rewriter_type rewriter_type, bool compute_conditions=false, bool remove_redundant_equations=true, bool check_quantifiers=true)
Apply the constelm algorithm.
void swap(atermpp::aterm &t1, atermpp::aterm &t2) noexcept
Swaps two term_applss.
A quantified predicate variable instantiation.
std::list< quantified_variable > Q
propositional_variable_instantiation X_e
bool operator<(const QPVI &other) const
void leave(const exists &x)
void push(const stack_elem &x)
void leave(const forall &x)
std::vector< stack_elem > condition_fv_stack
const stack_elem & top() const
void leave(const propositional_variable_instantiation &x)
void merge_conditions(stack_elem &&ec1, bool negate1, stack_elem &&ec2, bool negate2, stack_elem &ec, bool is_conjunctive)
void emplace(Args &&... args)
const edge_map & result() const
std::list< pbes_expression > quantified_context
void enter(const forall &x)
void leave(const data::data_expression &x)
void enter(const exists &x)
std::set< data::variable > disjunctive_context_FV
The set of free variables that occur on the other side of the conjunctions this PVI occurs in....
std::set< data::variable > conjunctive_context_FV
The set of free variables that occur on the other side of the conjunctions this PVI occurs in....
std::set< data::data_expression > conditions
Contains expressions that characterise when an edge is enabled. The conjunction of these expressions ...
std::set< data::variable > FV
data::data_expression Cpos
data::data_expression Cneg
edge_traverser_stack_elem(const data::data_expression &cond_pos, const data::data_expression &cond_neg, std::set< data::variable > &&free_vars)
An attempt for improving the efficiency.
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...