12#ifndef MCRL2_PBES_PARTIAL_ORDER_REDUCTION_H
13#define MCRL2_PBES_PARTIAL_ORDER_REDUCTION_H
16#include <boost/dynamic_bitset.hpp>
17#include "mcrl2/data/rewriters/one_point_rule_rewriter.h"
18#include "mcrl2/data/rewriters/quantifiers_inside_rewriter.h"
19#include "mcrl2/data/substitution_utility.h"
20#include "mcrl2/data/substitutions/maintain_variables_in_rhs.h"
21#include "mcrl2/pbes/replace_capture_avoiding_with_an_identifier_generator.h"
22#include "mcrl2/pbes/rewriters/enumerate_quantifiers_rewriter.h"
23#include "mcrl2/pbes/pbes_equation_index.h"
24#include "mcrl2/pbes/unify_parameters.h"
25#include "mcrl2/smt/solver.h"
26#include "mcrl2/utilities/skip.h"
45 for (; xi != x.end(); ++xi, ++yi)
47 result = data::lazy::and_(result, data::equal_to(*xi, *yi));
60 std::ostringstream buf;
62 for (std::size_t k = s.find_first(); k != summand_set::npos; k = s.find_next(k))
64 buf << (first ?
"" :
", ") << k;
106 return !nxt[i].empty();
111 bool depends(std::size_t i, std::size_t j)
const
115 return contains(nxt[i], j);
118 void print(std::ostream& out,
const std::set<std::size_t>& s,
const std::size_t N)
const
122 for (std::size_t i = 0; i < N; i++)
124 out << (contains(s, i) ?
'1' :
'0');
130 out <<
"deterministic = " << std::boolalpha << is_deterministic << std::endl;
131 out <<
"NES = " << print_summand_set(NES) << std::endl;
132 out <<
"DNA = " << print_summand_set(DNA) << std::endl;
133 out <<
"DNS = " << print_summand_set(DNS) << std::endl;
134 out <<
"DNL = " << print_summand_set(DNL) << std::endl;
159 return std::tie(e, f, g) < std::tie(other.e, other.f, other.g);
164 return std::tie(e, f, g) == std::tie(other.e, other.f, other.g);
178 std::size_t seed = std::hash<atermpp::aterm>()(x.f);
181 seed = std::hash<atermpp::aterm>()(x.e) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
185 seed = std::hash<atermpp::aterm>()(x.g) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
214 return a_result && b(a_result ==
no);
234 data::rewrite_strategy rewrite_strategy =
data::rewrite_strategy::jitty;
255 return std::tie(Twork, Ts) < std::tie(other.Twork, other.Ts);
339 return data::sort_bool::and_(condition1_k1, data::replace_variables_capture_avoiding(condition1_k, sigma_k1, id_gen));
344 data::
data_expression parameters_equal = detail::equal_to(data::replace_variables_capture_avoiding(updates2_k, sigma_k1, id_gen),
345 data::replace_variables_capture_avoiding(updates2_k1, sigma_k, id_gen));
348 data::replace_variables_capture_avoiding(condition2_k1, sigma_k, id_gen),
351 return make_exists_if_strong(qvars2_k + qvars2_k1, body);
361 data::
data_expression parameters_equal = detail::equal_to(data::replace_variables_capture_avoiding(updates2_k, sigma_k1, id_gen),
362 data::replace_variables_capture_avoiding(updates2_k1, sigma_k, id_gen));
364 data::replace_variables_capture_avoiding(condition2_k, sigma_k1, id_gen),
365 data::replace_variables_capture_avoiding(condition2_k1, sigma_k, id_gen),
368 return make_exists_if_strong(qvars2_k + qvars2_k1, body);
373 data::
data_expression parameters_equal = detail::equal_to(updates1_k1, data::replace_variables_capture_avoiding(updates1_k1, sigma_k, id_gen));
374 return data::sort_bool::and_(
375 data::replace_variables_capture_avoiding(condition1_k1, sigma_k, id_gen),
382 data::
data_expression parameters_equal = detail::equal_to(updates2_k1, data::replace_variables_capture_avoiding(updates2_k1, sigma_k, id_gen));
384 data::replace_variables_capture_avoiding(condition2_k1, sigma_k, id_gen),
387 return make_exists_if_strong(qvars2_k1, body);
395 if (affect_set && !needs_yes)
401 data::
data_expression yes_condition = make_forall_(combined_quantified_vars, data::sort_bool::not_(antecedent));
413 data::
data_expression condition = make_forall_(combined_quantified_vars, data::sort_bool::implies(antecedent, consequent));
423 const summand_class& summand_k = parent.m_summand_classes[k];
424 const summand_class& summand_k1 = parent.m_summand_classes[k1];
426 const data::variable_list& parameters =
parent.m_pbes.equations()[0].variable().parameters();
427 for(
const data::variable& v: parameters)
429 id_gen.add_identifier(v.name());
438 data::add_assignments(sigma_k, parameters, updates1_k);
439 data::add_assignments(sigma_k1, parameters, updates1_k1);
456 combined_quantified_vars = parameters + qvars1_k + qvars1_k1;
462 combined_quantified_vars,
463 data::sort_bool::not_(
465 data::sort_bool::not_(condition1_k),
467 data::replace_variables_capture_avoiding(condition1_k, sigma_k1, id_gen)
501 auto i = m_summand_index.find(summand_equivalence_key(summand));
502 assert(i != m_summand_index.end());
508 auto i = m_parameter_positions.find(v);
514 return m_summand_classes[k].DNA;
519 return m_summand_classes[k].DNA;
524 return m_summand_classes[k].DNS;
529 return m_summand_classes[k].DNS;
534 return m_summand_classes[k].DNL;
539 return m_summand_classes[k].DNL;
544 return m_summand_classes[k].NES;
549 return m_summand_classes[k].NES;
554 std::size_t N = m_summand_classes.size();
556 summand_set result(N);
557 std::size_t i = m_equation_index.index(X_e.name());
558 const data::variable_list& d = m_pbes.equations()[i].variable().parameters();
560 for (std::size_t k = 0; k < N; k++)
566 const summand_class& summand_k = m_summand_classes[k];
567 const data::variable_list& e_k = summand_k.e;
568 const data::data_expression& f_k = summand_k.f;
572 add_assignments(m_sigma, d, e);
573 m_enumerator.enumerate(enumerator_element(e_k, f_k),
575 [&](
const enumerator_element&) {
582 remove_assignments(m_sigma, e_k);
584 remove_assignments(m_sigma, d);
596 if(!depends(m_equation_index.index(X_e.name()), k))
598 return m_dependency_nes[m_equation_index.index(X_e.name())];
602 return m_summand_classes[k].NES;
621 if (!m_options.compute_left_accordance)
626 summand_set Twork_Ts = Twork | Ts;
628 summand_set T1 = Twork_Ts | en_X_e;
629 summand_set T2 = Twork_Ts & en_X_e;
631 auto h = [&](
const summand_set& A)
633 return (A - T1).count() + m_largest_equation_size * (A - T2).count();
636 return h(DNS(k)) <= h(DNL(k)) ? DNS(k) : DNL(k);
648 std::size_t N = m_summand_classes.size();
650 struct compare_invis_pair
653 mutable summand_set temp_set;
654 const summand_set& m_en_X_e;
656 explicit compare_invis_pair(
const summand_set& en)
660 std::size_t size(
const invis_pair& p)
const
664 temp_set &= m_en_X_e;
665 return temp_set.count();
670 std::size_t sizex = size(x);
671 std::size_t sizey = size(y);
672 return std::tie(sizex, x) < std::tie(sizey, y);
677 std::set<invis_pair, compare_invis_pair> C{compare_invis_pair(en_X_e)};
678 auto invis_en_X_e = invis(en_X_e);
679 for (std::size_t k = invis_en_X_e.find_first(); k != summand_set::npos; k = invis_en_X_e.find_next(k))
683 if(m_summand_classes[k].is_deterministic || m_options.compute_left_accordance)
685 invis_pair pair_k{summand_set(N), summand_set(N)};
698 auto p = C.extract(C.begin());
699 auto& Twork = p.value().Twork;
700 auto& Ts = p.value().Ts;
704 summand_set T = Ts & en_X_e;
705 for (std::size_t k = T.find_first(); k != summand_set::npos; k = T.find_next(k))
707 if (DNA(k).is_subset_of(Ts))
712 std::size_t k = T.find_first();
713 Twork |= (DNA(k) - Ts);
717 std::size_t k = Twork.find_first();
732 auto& DNS_or_DNL = DNX(k, Twork, Ts, en_X_e);
733 Twork |= (DNS_or_DNL - Ts);
737 auto& NES = choose_minimal_NES(k, X_e);
742 C.insert(std::move(p));
749 const auto& d = m_parameters;
752 std::set<propositional_variable_instantiation> result;
753 std::size_t i = m_equation_index.index(X_e.name());
754 for (std::size_t k = K.find_first(); k != summand_set::npos; k = K.find_next(k))
756 const summand_class& summand_k = m_summand_classes[k];
757 const data::variable_list& e_k = summand_k.e;
758 const data::data_expression& f_k = summand_k.f;
759 const data::data_expression_list& g_k = summand_k.g;
760 const auto& J = summand_k.nxt[i];
765 data::add_assignments(m_sigma, d, e);
766 data::remove_assignments(m_sigma, e_k);
767 m_enumerator.enumerate(enumerator_element(e_k, f_k),
769 [&](
const enumerator_element& p) {
770 p.add_assignments(e_k, m_sigma, m_rewr);
771 data::data_expression_list g(g_k.begin(), g_k.end(), [&](
const data::data_expression& x) {
return m_rewr(x, m_sigma); });
772 for (std::size_t j: J)
774 const core::identifier_string& X_j = m_pbes.equations()[j].variable().name();
775 result.insert(propositional_variable_instantiation(X_j, g));
781 data::remove_assignments(m_sigma, e_k);
788 std::size_t n = m_pbes.equations().size();
789 for (std::size_t i = 0; i < n; i++)
791 const srf_equation& eqn = m_pbes.equations()[i];
792 for (
const srf_summand& summand: eqn.summands())
794 std::size_t j = m_equation_index.index(summand.variable().name());
795 std::size_t k = summand_index(summand);
796 m_summand_classes[k].nxt[i].insert(j);
804 std::set<std::size_t> result;
805 for (
const data::variable& v: find_free_variables(x))
807 result.insert(parameter_position(v));
814 if(m_solver !=
nullptr)
820 const data::
forall& f = atermpp::down_cast<data::forall>(expr);
823 switch(m_solver->solve(data::variable_list(), expr, m_options.smt_timeout))
825 case smt::answer::SAT:
return negate ^
true;
826 case smt::answer::UNSAT:
return negate ^
false;
827 case smt::answer::UNKNOWN:
return false;
835 mCRL2log(log::verbose) <<
"Cannot rewrite " << result <<
" any further" << std::endl;
847 std::size_t N = m_summand_classes.size();
849 std::set<std::size_t> reachable_after_k;
852 for (std::size_t i = 0; i < m_pbes.equations().size(); i++)
854 reachable_after_k.insert(summand_k.nxt[i].begin(), summand_k.nxt[i].end());
858 std::list<std::size_t> todo(reachable_after_k.begin(), reachable_after_k.end());
859 while (!todo.empty())
861 std::size_t i = todo.front();
863 for (std::size_t k2 = 0; k2 < N; k2++)
865 for (
const std::size_t j: m_summand_classes[k2].nxt[i])
867 if (reachable_after_k.count(j) == 0)
870 reachable_after_k.insert(j);
876 return !std::any_of(reachable_after_k.begin(), reachable_after_k.end(),
877 [&](
const std::size_t i) {
return depends(i, k1); });
885 std::size_t n = m_pbes.equations().size();
886 std::size_t N = m_summand_classes.size();
888 for (std::size_t i = 0; i < n; i++)
890 m_dependency_nes[i].resize(N);
891 for (std::size_t k = 0; k < N; k++)
893 const std::set<std::size_t>& J = m_summand_classes[k].nxt[i];
894 if (J.size() > 1 || (J.size() == 1 && *J.begin() != i))
896 m_dependency_nes[i].set(k);
903 bool depends(std::size_t i, std::size_t k, std::size_t j)
const
905 return m_summand_classes[k].depends(i, j);
910 bool depends(std::size_t i, std::size_t k)
const
912 std::size_t n = m_pbes.equations().size();
913 for (std::size_t j = 0; j < n; j++)
915 if (depends(i, k, j))
925 std::vector<data::variable> new_variables;
926 data::maintain_variables_in_rhs< data::mutable_map_substitution<> > sigma;
927 for (
const data::variable& var: summ.e)
929 core::identifier_string new_name = id_gen(var.name());
930 if (new_name != var.name())
932 sigma[var] = data::variable(new_name, var.sort());
934 new_variables.emplace_back(new_name, var.sort());
939 return data::replace_variables_capture_avoiding_with_an_identifier_generator(e, sigma, id_gen);
942 return summand_equivalence_key(
943 data::variable_list(new_variables.begin(), new_variables.end()),
944 replace_vars(summ.f),
945 data::data_expression_list(summ.g.begin(), summ.g.end(), replace_vars)
951 std::size_t n = m_pbes.equations().size();
954 for (std::size_t i = 0; i < n; i++)
956 for (std::size_t i1 = 0; i1 < n; i1++)
958 bool X_k1_X1 = depends(i, k1, i1);
959 for (std::size_t i_prime = 0; i_prime < n; i_prime++)
961 bool X1_k_Xprime = depends(i1, k, i_prime);
962 if (X_k1_X1 && X1_k_Xprime)
966 for (std::size_t i2 = 0; i2 < n; i2++)
968 bool X_k_X2 = depends(i, k, i2);
969 bool X2_k1_Xprime = depends(i2, k1, i_prime);
970 if (X_k_X2 && X2_k1_Xprime)
988 std::size_t n = m_pbes.equations().size();
991 for (std::size_t i = 0; i < n; i++)
993 for (std::size_t i1 = 0; i1 < n; i1++)
995 bool X_k1_X1 = depends(i, k1, i1);
996 for (std::size_t i2 = 0; i2 < n; i2++)
998 bool X_k_X2 = depends(i, k, i2);
999 if (X_k1_X1 && X_k_X2)
1003 for (std::size_t i_prime = 0; i_prime < n; i_prime++)
1005 bool X1_k_Xprime = depends(i1, k, i_prime);
1006 bool X2_k1_Xprime = depends(i2, k1, i_prime);
1007 if (X1_k_Xprime && X2_k1_Xprime)
1026 std::size_t n = m_pbes.equations().size();
1029 for (std::size_t i = 0; i < n; i++)
1031 for (std::size_t i1 = 0; i1 < n; i1++)
1033 bool X_k1_X1 = depends(i, k1, i1);
1034 for (std::size_t i2 = 0; i2 < n; i2++)
1036 bool X_k_X2 = depends(i, k, i2);
1037 bool X2_k1_X1 = depends(i2, k1, i1);
1038 if (X_k1_X1 && X_k_X2)
1059 std::size_t N = m_summand_classes.size();
1061 auto Rs = [&](
const std::size_t k) {
return info[k].Rs; };
1062 auto Ts = [&](
const std::size_t k) {
return info[k].Ts; };
1063 auto Vs = [&](
const std::size_t k) {
return info[k].Vs; };
1064 auto Ws = [&](
const std::size_t k) {
return info[k].Ws; };
1066 for (std::size_t k = 0; k < N; k++)
1068 mCRL2log(log::verbose) << std::setw(3) << k <<
" = ";
1069 for (std::size_t k1 = 0; k1 < N; k1++)
1076 bool DNL_DNS_affect_sets = has_empty_intersection(set_intersection(Vs(k), Vs(k1)), set_union(Ws(k), Ws(k1)));
1077 bool DNT_affect_sets = has_empty_intersection(Ws(k), Rs(k1)) && has_empty_intersection(Ws(k), Ts(k1)) && set_includes(Ws(k1), Ws(k));
1079 summand_relations_data summand_data(*
this, k, k1);
1081 bool left_accords = m_options.compute_left_accordance &&
1082 ([&]{
return left_accords_equations(k, k1); } &&
1083 [&](
bool needs_yes) {
return summand_data.left_accords_data(DNL_DNS_affect_sets, needs_yes); });
1085 bool square_accords = (k1 < k && !DNS(k1).test(k)) ||
1087 ([&]{
return square_accords_equations(k, k1); } &&
1088 [&](
bool needs_yes) {
return summand_data.square_accords_data(DNL_DNS_affect_sets, needs_yes); }));
1089 bool accords = square_accords ||
1090 (m_options.compute_triangle_accordance && ([&]{
return triangle_accords_equations(k, k1); } &&
1091 [&](
bool needs_yes) {
return summand_data.triangle_accords_data(DNT_affect_sets, needs_yes); }));
1092 bool can_enable = !m_options.compute_NES ||
1093 (!dependency_permanently_disables(k1, k) && !has_empty_intersection(Ts(k), Ws(k1)) && summand_data.can_enable());
1099 if (!square_accords)
1110 mCRL2log(log::verbose) << (DNL_DNS_affect_sets ?
": " :
"+ ");
1112 mCRL2log(log::verbose) << std::flush;
1124 if (!m_options.reduction)
1131 std::size_t N = m_summand_classes.size();
1132 std::vector<parameter_info> info(N);
1133 const std::vector<data::variable>& d = m_parameters;
1138 std::set<data::variable> FV = find_free_variables(summand.f);
1139 for (
const data::variable& v: summand.e)
1143 for (
const data::variable& v: FV)
1145 info.Ts.insert(parameter_position(v));
1149 auto gi = summand.g.begin();
1150 auto di = d.begin();
1151 for ( ; di != d.end(); ++di, ++gi)
1155 std::size_t i = di - d.begin();
1158 for (
const data::variable& v: find_free_variables(*gi))
1160 info.Rs.insert(parameter_position(v));
1166 info.Vs = set_union(info.Ts, set_union(info.Ws, info.Rs));
1169 for (std::size_t k = 0; k < N; k++)
1171 compute_parameter_info(m_summand_classes[k], info[k]);
1175 compute_DNA_DNL_NES(info);
1182 std::size_t n = m_pbes.equations().size();
1183 for (std::size_t i = 0; i < n; i++)
1185 if (summand_k.nxt[i].size() >= 2)
1197 const data::variable_list& parameters = m_pbes.equations()[0].variable().parameters();
1199 for(
const data::variable& v: parameters)
1201 id_gen.add_identifier(v.name());
1211 auto it1_k = updates1_k.begin();
1212 auto it2_k = updates2_k.begin();
1213 while (it1_k != updates1_k.end())
1215 consequent = data::lazy::and_(consequent, data::equal_to(*it1_k, *it2_k));
1218 data::
data_expression condition = make_forall_(parameters + qvars1_k + qvars2_k, data::sort_bool::implies(antecedent, consequent));
1225 if (!m_options.compute_determinism || !m_options.reduction)
1229 std::size_t N = m_summand_classes.size();
1230 for (std::size_t k = 0; k < N; k++)
1232 m_summand_classes[k].is_deterministic = compute_deterministic_equations(k) && compute_deterministic_data(k);
1238 std::size_t n = m_pbes.equations().size();
1240 for (
const srf_equation& eqn: m_pbes.equations())
1242 for (
const srf_summand& summand: eqn.summands())
1244 summand_equivalence_key key(summand);
1245 auto i = m_summand_index.find(key);
1246 if (i == m_summand_index.end())
1248 std::size_t k = m_summand_index.size();
1249 m_summand_index[key] = k;
1250 m_summand_classes.emplace_back(summand.parameters(), summand.condition(), summand.variable().parameters(), n);
1254 for(summand_class& s: m_summand_classes)
1256 s.set_num_summands(m_summand_classes.size());
1268 std::size_t n = m_pbes.equations().size();
1269 std::size_t N = m_summand_classes.size();
1272 for (std::size_t i = 0; i < n; i++)
1274 const srf_equation& eqn = m_pbes.equations()[i];
1275 const core::identifier_string& X_i = eqn.variable().name();
1276 bool op_i = eqn.is_conjunctive();
1277 std::size_t rank_i = m_equation_index.rank(X_i);
1279 for (
const srf_summand& summand: eqn.summands())
1281 const core::identifier_string& X_j = summand.variable().name();
1282 std::size_t j = m_equation_index.index(X_j);
1283 std::size_t rank_j = m_equation_index.rank(X_j);
1284 bool op_j = m_pbes.equations()[j].is_conjunctive();
1285 bool is_invisible = op_i == op_j && rank_i == rank_j;
1288 std::size_t k = summand_index(summand);
1301 std::ostringstream out;
1302 for (
auto i = v.begin(); i != v.end(); ++i)
1308 out << *i <<
": " << i->sort();
1315 std::size_t k = summand_index(summand);
1316 mCRL2log(log::verbose) <<
" (" << k <<
") ";
1317 if (!summand.parameters().empty())
1319 mCRL2log(log::verbose) << (is_conjunctive ?
"forall " :
"exists ") << print_variables(summand.parameters()) <<
". ";
1321 mCRL2log(log::verbose) << summand.condition()
1322 << (is_conjunctive ?
" => " :
" && ")
1323 << summand.variable()
1329 mCRL2log(log::verbose) <<
"srf_pbes" << std::endl;
1330 for (
const srf_equation& eqn: m_pbes.equations())
1332 mCRL2log(log::verbose) << eqn.symbol() <<
" " << eqn.variable() <<
" = " << (eqn.is_conjunctive() ?
"conjunction" :
"disjunction") <<
" of summands\n";
1333 for (
const srf_summand& summand: eqn.summands())
1335 print_summand(summand, eqn.is_conjunctive());
1337 mCRL2log(log::verbose) << std::endl;
1345 if(mCRL2logEnabled(log::verbose))
1347 std::size_t N = m_summand_classes.size();
1348 for (std::size_t k = 0; k < N; k++)
1350 const summand_class& summand = m_summand_classes[k];
1351 mCRL2log(log::verbose) <<
"\n--- summand class " << k <<
" ---" << std::endl;
1352 mCRL2log(log::verbose) <<
"visible = " << std::boolalpha << m_vis.test(k) <<
"\n";
1353 summand.print(log::logger(log::verbose).get());
1355 for (std::size_t i = 0; i < m_pbes.equations().size(); i++)
1357 mCRL2log(log::verbose) <<
"dependency NES[" << std::setw(3) << i <<
"] " << print_summand_set(m_dependency_nes[i]) << std::endl;
1377 unify_parameters(m_pbes,
false,
true);
1380 const data::variable_list& parameters = m_pbes.equations().front().variable().parameters();
1381 m_parameters = std::vector<data::variable>{parameters.begin(), parameters.end()};
1382 for (std::size_t m = 0; m < m_parameters.size(); m++)
1384 m_parameter_positions[m_parameters[m]] = m;
1387 const std::chrono::time_point<std::chrono::high_resolution_clock> t_start =
1388 std::chrono::high_resolution_clock::now();
1391 m_static_analysis_duration = std::chrono::high_resolution_clock::now() - t_start;
1394 for (
const srf_equation& eq: m_pbes.equations())
1396 m_largest_equation_size = std::max(m_largest_equation_size, eq.summands().size());
1404 return m_pbes.initial_state();
1409 return m_parameters;
1414 std::size_t i = m_equation_index.index(X);
1415 return m_pbes.equations()[i].symbol();
1429 EmitNode emit_node = EmitNode(),
1430 EmitEdge emit_edge = EmitEdge()
1440 const std::chrono::time_point<std::chrono::high_resolution_clock> t_start =
1441 std::chrono::high_resolution_clock::now();
1450 using todo_pair = std::pair<propositional_variable_instantiation, todo_state>;
1455 std::unordered_map<propositional_variable_instantiation, std::pair<std::size_t,
bool>> seen;
1456 std::deque<todo_pair> todo{todo_pair(X_init, NEW)};
1459 std::size_t index = 0;
1462 std::size_t rank = m_equation_index.rank(X_init.name());
1463 std::size_t i = m_equation_index.index(X_init.name());
1464 bool is_conjunctive = m_pbes.equations()[i].is_conjunctive();
1465 emit_node(X_init, is_conjunctive, rank);
1466 seen.insert(std::make_pair(X_init, std::make_pair(index,
true)));
1470 std::size_t iteration = 0;
1471 while (!todo.empty())
1473 todo_pair& p = todo.back();
1474 const propositional_variable_instantiation X_e = p.first;
1475 todo_state& s = p.second;
1476 mCRL2log(log::debug) <<
"choose X_e = " << X_e << std::endl;
1478 if (s == DONE || s == DONE_PARTIALLY)
1481 seen[X_e].second =
false;
1485 std::set<propositional_variable_instantiation> next;
1486 summand_set en_X_e = en(X_e);
1490 summand_set stubborn_set_X_e = stubborn_set(X_e, en_X_e);
1491 mCRL2log(log::debug) <<
"stubborn_set(X_e) = " << print_summand_set(stubborn_set_X_e) << std::endl;
1492 next = succ(X_e, stubborn_set_X_e & en_X_e);
1494 bool vis_expanded = m_vis.is_subset_of(stubborn_set_X_e);
1495 s = vis_expanded ? DONE : DONE_PARTIALLY;
1498 seen[X_e].second =
true;
1501 if (m_options.use_condition_L)
1506 std::size_t num_cycles = 0;
1507 propositional_variable_instantiation min_node;
1508 for (
const propositional_variable_instantiation& Y_f: next)
1510 auto node = seen.find(Y_f);
1511 if (node == seen.end())
1515 std::size_t node_instack = node->second.second;
1526 if (num_cycles == 1)
1528 auto it = std::find_if(todo.rbegin(), todo.rend(), [&](
const auto& pair){
return pair.first == min_node; });
1529 assert(it != todo.rend());
1530 auto& [Y_f, Y_f_state] = *it;
1531 if(Y_f_state == DONE_PARTIALLY)
1533 Y_f_state = STARTS_CYCLE;
1534 seen[Y_f].second =
false;
1537 else if (num_cycles > 1 && s == DONE_PARTIALLY)
1540 for (
auto& Y_f: succ(X_e, en_X_e - stubborn_set_X_e))
1545 seen[X_e].second =
false;
1551 assert(s == STARTS_CYCLE);
1552 next = succ(X_e, en_X_e);
1556 mCRL2log(log::debug) <<
"next = " << core::detail::print_set(next) << std::endl;
1557 for (
const propositional_variable_instantiation& Y_f: next)
1559 if (seen.find(Y_f) == seen.end())
1561 std::size_t rank = m_equation_index.rank(Y_f.name());
1562 std::size_t i = m_equation_index.index(Y_f.name());
1563 bool is_conjunctive = m_pbes.equations()[i].is_conjunctive();
1564 emit_node(Y_f, is_conjunctive, rank);
1565 seen.insert(std::make_pair(Y_f, std::make_pair(index,
false)));
1567 todo.emplace_back(Y_f, NEW);
1570 for (
const propositional_variable_instantiation& Y_f: next)
1572 emit_edge(X_e, Y_f);
1576 if(iteration == 100)
1578 mCRL2log(log::status) <<
"Found " << seen.size() <<
" nodes. Todo set contains " << todo.size() <<
" nodes.\n";
1582 mCRL2log(log::verbose) <<
"Finished exploration, found " << seen.size() <<
" nodes." << std::endl;
1584 m_exploration_duration = std::chrono::high_resolution_clock::now() - t_start;
1585 mCRL2log(log::info) <<
"timing pbespor (wall clock time in seconds):"
1586 "\n static analysis: " << std::chrono::duration<
double>(m_static_analysis_duration).count() <<
1587 "\n exploration: " << std::chrono::duration<
double>(m_exploration_duration).count() << std::endl;
1596 EmitNode emit_node = EmitNode(),
1597 EmitEdge emit_edge = EmitEdge()
1600 const std::chrono::time_point<std::chrono::high_resolution_clock> t_start =
1601 std::chrono::high_resolution_clock::now();
1603 std::unordered_set<propositional_variable_instantiation> seen;
1604 std::deque<propositional_variable_instantiation> todo{ X_init };
1607 std::size_t rank = m_equation_index.rank(X_init.name());
1608 std::size_t i = m_equation_index.index(X_init.name());
1609 bool is_conjunctive = m_pbes.equations()[i].is_conjunctive();
1610 emit_node(X_init, is_conjunctive, rank);
1611 seen.insert(X_init);
1614 std::size_t N = m_summand_classes.size();
1615 summand_set summands_X(N);
1617 std::size_t iteration = 0;
1618 while (!todo.empty())
1620 const propositional_variable_instantiation X_e = todo.back();
1622 mCRL2log(log::debug) <<
"choose X_e = " << X_e << std::endl;
1624 std::size_t X_index = m_equation_index.index(X_e.name());
1625 for(std::size_t i = 0; i < N; i++)
1627 if (depends(X_index, i))
1632 mCRL2log(log::debug) <<
"enabled according to dependencies = " << print_summand_set(summands_X) << std::endl;
1633 std::set<propositional_variable_instantiation> next = succ(X_e, summands_X);
1634 mCRL2log(log::debug) <<
"next = " << core::detail::print_set(next) << std::endl;
1637 for (
const propositional_variable_instantiation& Y_f: next)
1639 if (seen.find(Y_f) == seen.end())
1641 std::size_t rank = m_equation_index.rank(Y_f.name());
1642 std::size_t i = m_equation_index.index(Y_f.name());
1643 bool is_conjunctive = m_pbes.equations()[i].is_conjunctive();
1644 emit_node(Y_f, is_conjunctive, rank);
1646 todo.emplace_back(Y_f);
1649 for (
const propositional_variable_instantiation& Y_f: next)
1651 emit_edge(X_e, Y_f);
1655 if(iteration == 100)
1657 mCRL2log(log::status) <<
"Found " << seen.size() <<
" nodes. Todo set contains " << todo.size() <<
" nodes.\n";
1661 mCRL2log(log::verbose) <<
"Finished exploration, found " << seen.size() <<
" nodes." << std::endl;
1663 m_exploration_duration = std::chrono::high_resolution_clock::now() - t_start;
1664 mCRL2log(log::info) <<
"timing pbespor (wall clock time in seconds):"
1665 "\n exploration: " << std::chrono::duration<
double>(m_exploration_duration).count() << std::endl;
const variable_list & variables() const
const data_expression & body() const
data_expression & operator=(const data_expression &) noexcept=default
data_expression & operator=(data_expression &&) noexcept=default
data_expression(const data_expression &) noexcept=default
Move semantics.
An element for the todo list of the enumerator that collects the substitution corresponding to the ex...
universal quantification.
Rewriter that operates on data expressions.
Identifier generator that stores the identifiers of the context in a set. Using the operator()() and ...
data::data_expression make_exists_if_strong(const data::variable_list &vars, const data::data_expression &body)
tribool triangle_accords_data(bool affect_set, bool needs_yes)
data::variable_list combined_quantified_vars
data::data_expression square_accords_consequent()
data::data_expression condition2_k1
data::variable_list qvars1_k
data::variable_list qvars2_k1
data::data_expression triangle_accords_consequent_weak()
data::data_expression condition1_k
data::set_identifier_generator id_gen
data::mutable_indexed_substitution sigma_k1
bool compute_weak_conditions
data::data_expression condition1_k1
data::data_expression_list updates2_k
data::data_expression left_accords_consequent()
data::data_expression coenabled_antecedent()
data::data_expression condition2_k
tribool square_accords_data(bool affect_set, bool needs_yes)
data::mutable_indexed_substitution sigma_k
data::data_expression_list updates2_k1
partial_order_reduction_algorithm & parent
data::data_expression_list updates1_k
data::data_expression triangle_accords_consequent()
summand_relations_data(partial_order_reduction_algorithm &p, const std::size_t k, const std::size_t k1)
data::data_expression left_accords_antecedent()
data::variable_list qvars2_k
tribool accords_data(bool affect_set, bool needs_yes, const std::function< data::data_expression()> &make_antecedent, const std::function< data::data_expression()> &make_consequent)
data::data_expression_list updates1_k1
tribool left_accords_data(bool affect_set, bool needs_yes)
data::variable_list qvars1_k1
std::size_t parameter_position(const data::variable &v) const
std::size_t summand_index(const srf_summand &summand) const
std::chrono::high_resolution_clock::duration m_static_analysis_duration
partial_order_reduction_algorithm(const pbes &p, pbespor_options options)
data::enumerator_identifier_generator m_id_generator
tribool triangle_accords_equations(std::size_t k, std::size_t k1) const
summand_set & DNA(std::size_t k)
const fixpoint_symbol & symbol(const core::identifier_string &X) const
bool depends(std::size_t i, std::size_t k) const
summand_set stubborn_set(const propositional_variable_instantiation &X_e, const summand_set &en_X_e)
void compute_summand_classes()
tribool square_accords_equations(std::size_t k, std::size_t k1) const
const summand_set & DNX(std::size_t k, const summand_set &Twork, const summand_set &Ts, const summand_set &en_X_e) const
void print_summand(const srf_summand &summand, bool is_conjunctive) const
std::string print_variables(const data::variable_list &v) const
pbespor_options m_options
std::vector< summand_class > m_summand_classes
const summand_set & DNA(std::size_t k) const
summand_set & NES(std::size_t k)
std::chrono::high_resolution_clock::duration m_exploration_duration
const propositional_variable_instantiation & initial_state() const
summand_set en(const propositional_variable_instantiation &X_e)
void explore(const propositional_variable_instantiation &X_init, EmitNode emit_node=EmitNode(), EmitEdge emit_edge=EmitEdge())
const summand_set & NES(std::size_t k) const
std::size_t m_largest_equation_size
static summand_equivalence_key rename_duplicate_variables(data::set_identifier_generator &id_gen, const summand_equivalence_key &summ)
summand_set invis(const summand_set &K)
std::set< std::size_t > FV(const pbes_expression &x) const
std::vector< summand_set > m_dependency_nes
void compute_deterministic()
summand_set & DNS(std::size_t k)
data::mutable_indexed_substitution m_sigma
const std::vector< data::variable > & parameters() const
void compute_DNA_DNL_NES(const std::vector< parameter_info > &info)
std::set< propositional_variable_instantiation > succ(const propositional_variable_instantiation &X_e, const summand_set &K)
void compute_NES_DNA_DNL()
const summand_set & DNL(std::size_t k) const
void compute_dependency_NES()
const summand_set & choose_minimal_NES(std::size_t k, const propositional_variable_instantiation &X_e) const
summand_set & DNL(std::size_t k)
bool compute_deterministic_data(std::size_t k)
void explore_full(const propositional_variable_instantiation &X_init, EmitNode emit_node=EmitNode(), EmitEdge emit_edge=EmitEdge())
bool depends(std::size_t i, std::size_t k, std::size_t j) const
std::unique_ptr< smt::smt_solver > m_solver
bool compute_deterministic_equations(std::size_t k)
bool dependency_permanently_disables(const std::size_t k, const std::size_t k1) const
Return true iff k1 can never happen after k happens, as deduced from predicate dependencies.
pbes_equation_index m_equation_index
std::vector< data::variable > m_parameters
void print_summand_classes() const
tribool left_accords_equations(std::size_t k, std::size_t k1) const
const summand_set & DNS(std::size_t k) const
bool is_true(data::data_expression expr)
data::enumerator_algorithm m_enumerator
parameterized boolean equation system
\brief A propositional variable instantiation
const data::data_expression_list & parameters() const
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Namespace for system defined sort bool_.
application not_(const data_expression &arg0)
Application of function symbol !.
application and_(const data_expression &arg0, const data_expression &arg1)
Application of function symbol &&.
const function_symbol & false_()
Constructor for function symbol false.
const function_symbol & true_()
Constructor for function symbol true.
data_expression make_exists_(const data::variable_list &v, const data_expression &x)
Make an existential quantification. It checks for an empty variable list, which is not allowed.
data_expression and_(const data_expression &x, const data_expression &y)
bool is_forall(const atermpp::aterm &x)
Returns true if the term t is a universal quantification.
data::data_expression equal_to(const data::data_expression_list &x, const data::data_expression_list &y)
data::data_expression make_and(const data::data_expression &x1, const data::data_expression &x2, const data::data_expression &x3)
std::string print_summand_set(const summand_set &s)
static bool operator&&(tribool a, tribool b)
static bool operator&&(const std::function< tribool()> &a, const std::function< tribool(bool)> &b)
invis_pair(summand_set Twork_, summand_set Ts_)
bool operator<(const invis_pair &other) const
std::set< std::size_t > Vs
std::set< std::size_t > Ws
std::set< std::size_t > Ts
std::set< std::size_t > Rs
std::chrono::milliseconds smt_timeout
bool compute_weak_conditions
bool compute_left_accordance
bool compute_triangle_accordance
void print(std::ostream &out, const std::set< std::size_t > &s, const std::size_t N) const
void print(std::ostream &out) const
std::vector< std::set< std::size_t > > nxt
Encodes the dependency relation belonging to this summand_class \detail nxt[i] contains j iff X_i –th...
void set_num_summands(const std::size_t N)
bool depends(std::size_t i, std::size_t j) const
summand_class(data::variable_list e_, data::data_expression f_, data::data_expression_list g_, std::size_t n)
bool depends(std::size_t i) const
data::data_expression_list g
summand_equivalence_key(const summand_class &summand)
bool operator==(const summand_equivalence_key &other) const
data::data_expression_list g
summand_equivalence_key(const srf_summand &summand)
bool operator<(const summand_equivalence_key &other) const
summand_equivalence_key(data::variable_list e_, data::data_expression f_, data::data_expression_list g_)
std::size_t operator()(const mcrl2::pbes_system::summand_equivalence_key &x) const