mCRL2
Loading...
Searching...
No Matches
pbeschain.h
Go to the documentation of this file.
1// Author(s): Jore Booy
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/tools/pbeschain.h
10/// \brief This file provides a tool that can simplify PBESs by
11/// substituting PBES equations for variables in the rhs,
12/// simplifying the result, and keeping it when it can
13/// eliminate PBES variables.
14
15#ifndef MCRL2_PBES_TOOLS_PBESCHAIN_H
16#define MCRL2_PBES_TOOLS_PBESCHAIN_H
17
18#include "mcrl2/core/identifier_string.h"
19#include "mcrl2/data/rewrite_strategy.h"
20#include "mcrl2/data/rewriter.h"
21#include "mcrl2/pbes/algorithms.h"
22#include "mcrl2/pbes/detail/instantiate_global_variables.h"
23#include "mcrl2/pbes/detail/iteration_builders.h"
24#include "mcrl2/pbes/detail/srf_transformations.h"
25#include "mcrl2/pbes/detail/stategraph_pbes.h"
26#include "mcrl2/pbes/io.h"
27#include "mcrl2/pbes/pbes_equation.h"
28#include "mcrl2/pbes/pbes_expression.h"
29#include "mcrl2/pbes/resolve_name_clashes.h"
30#include "mcrl2/pbes/rewrite.h"
31#include "mcrl2/pbes/srf_pbes.h"
32#include "mcrl2/pbes/unify_parameters.h"
33#include "mcrl2/utilities/logger.h"
34#include <chrono>
35#include <cstddef>
36#include <iostream>
37#include <iomanip>
38
39namespace mcrl2::pbes_system
40{
41
43{
44 data::rewrite_strategy rewrite_strategy = data::rewrite_strategy::jitty;
45 bool back_substitution = true;
46 bool remove_equation = true;
47 int max_depth = 12;
48 bool count_unique_pvi = false;
49 bool fill_pvi = false;
50 double timeout = 0.0; // timeout in seconds, 0 = no timeout
51 double pvi_pp_factor = 0.0; // factor of the maximum size the chained predicate formula should be after chaining
52 // compared to the size of the original PVI.
53 bool quantifier_free = false;
54 bool avoid_alternating = false;
57 double srf_factor; // factor of the maximum size the chained equation in SRF should be after chaining compared
58 // to the size of the original equation. Default is 1.0
60 bool timings = false;
62};
63
64// Substitutor to target specific path, replace our specific pvi with true/false
65template<template<class> class Builder>
68{
70 using super::apply;
71
75
78 {}
79
81 {
82 m_pvi = x;
83 }
85 {
87 }
88
89 template<class T>
91 {
92 if (x == m_pvi)
93 {
94 result = m_replacement;
95 }
96 else
97 {
98 result = x;
99 }
100 }
101};
102
103template<template<class> class Builder>
105{
107 using super::apply;
108
110
113 {}
114
116 {
117 data::data_expression res = x;
119 {
120 data::application da = atermpp::down_cast<data::application>(x);
121
122 if (data::is_function_symbol(da.head()))
123 {
124 data::function_symbol fname = atermpp::down_cast<data::function_symbol>(da.head());
125 if (fname.name() == atermpp::aterm_string("if") && (da.head().sort().target_sort() == data::bool_()))
126 {
128 res = atermpp::down_cast<data::data_expression>(m_pbes_rewriter(atermpp::down_cast<pbes_expression>(res)));
129 }
130 }
131 }
132 return res;
133 }
134
135 template<class T>
136 void apply(T& result, const data::data_expression& x)
137 {
138 result = atermpp::down_cast<T>(simpl_data(x));
139 }
140};
141
142template<template<class> class Builder>
144{
146 using super::apply;
147
149 core::identifier_string name;
151 bool m_stable = false;
152
155 {}
156
157 void set_stable(bool b)
158 {
159 m_stable = b;
160 }
161
162 bool stable() const
163 {
164 return m_stable;
165 }
166
168 {
169 m_eq = eq;
170 }
171
172 void set_name(const core::identifier_string& s)
173 {
174 name = s;
175 }
176
177 template<class T>
179 {
181 {
183 data::data_expression_list pars = x.parameters();
184 for (const data::variable& v: m_eq.variable().parameters())
185 {
186 data::data_expression par = pars.front();
187 pars.pop_front();
188 if (par.sort() != v.sort())
189 {
190 // Parameters do not match with variables. Ignore this substitution.
191 result = x;
192 return;
193 }
194 sigma[v] = par;
195 }
196 pbes_expression p = pbes_rewrite(m_eq.formula(), m_pbes_rewriter, sigma);
197 std::set<propositional_variable_instantiation> set = find_propositional_variable_instantiations(p);
198 if (std::all_of(set.begin(),
199 set.end(),
200 [this](const propositional_variable_instantiation& v) { return v.name() != m_eq.variable().name(); }))
201 {
202 // The result does not contain the variable m_eq.variable().name() and is therefore considered simpler.
203 mCRL2log(log::log_level_t::debug) << "Replaced in PBES equation for " << name << ":\n" << x << " --> " << p << "\n";
204 result = p;
205 m_stable = false;
206 return;
207 }
208 mCRL2log(log::log_level_t::debug) << "No Replacement in PBES equation for " << name << ":\n" << x << " --> " << p << "\n";
209 result = x;
210 return;
211 }
212 result = x;
213 }
214};
215
216template<template<class> class Builder>
219{
221 using super::apply;
222
225 int i = 0;
226
228 std::vector<detail::predicate_variable> predvars)
231 {}
232
233 template<class T>
235 {
236 result = pbes_rewrite(pbes_expression(x), m_pbes_rewriter, predvars[i].sigma());
237 i++;
238 }
239};
240
241/// \brief Returns all data variables that occur in a range of expressions
242/// \param[in] container a container with expressions
243/// \return All data variables that occur in the term t
244template<typename Container>
246{
247 std::vector<propositional_variable_instantiation> result;
248 pbes_system::find_propositional_variable_instantiations(container, std::inserter(result, result.end()));
249 return result;
250}
251
252/// \brief Helper class to track multiple time measurements and call counts
254{
256 {
258 int call_count = 0;
259
260 void add_measurement(std::chrono::duration<double, std::milli> duration)
261 {
262 total_time += duration;
263 call_count++;
264 }
265
266 double get_total_seconds() const
267 {
268 return std::chrono::duration<double>(total_time).count();
269 }
270 };
271
276
279 {}
280
281 /// \brief Increment the counter of direct Gauss eliminations (replacing a reoccurring pvi with true/false)
283 {
284 gauss_elimination_direct_count++;
285 }
286
287 /// \brief Increment the counter of path Gauss eliminations (replacing a pvi in a loop with true/false)
289 {
290 gauss_elimination_path_count++;
291 }
292
293 /// \brief Start timing an operation (returns the start time for use with end_measurement)
295 {
296 return std::chrono::steady_clock::now();
297 }
298
299 /// \brief End timing an operation and record it
300 void end_measurement(const std::string& label, std::chrono::time_point<std::chrono::steady_clock> measurement_start)
301 {
302 auto duration = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(
303 std::chrono::steady_clock::now() - measurement_start);
304 measurements[label].add_measurement(duration);
305 }
306
307 /// \brief Log all measurements
308 void log_measurements() const
309 {
310 double total_elapsed
311 = std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - start_time).count();
312 mCRL2log(log::log_level_t::verbose) << "Total time: " << total_elapsed << "s" << std::endl;
313
314 if (!measurements.empty())
315 {
316 // Find the longest label name for alignment
317 std::size_t max_label_length = 0;
318 for (const auto& [label, measurement]: measurements)
319 {
320 max_label_length = std::max(max_label_length, label.length() + 4);
321 }
322
323 // Log measurements with aligned values
324 for (const auto& [label, measurement]: measurements)
325 {
326 mCRL2log(log::log_level_t::verbose) << std::left << std::setw(static_cast<int>(max_label_length)) << (label + " ") << ": " << std::right
327 << std::setw(2) << std::fixed << measurement.get_total_seconds() << "s ("
328 << measurement.call_count << " calls)" << std::endl;
329 }
330 }
331
332 mCRL2log(log::log_level_t::verbose) << "Gauss eliminations (path): " << gauss_elimination_path_count << std::endl;
333 mCRL2log(log::log_level_t::verbose) << "Gauss eliminations (direct): " << gauss_elimination_direct_count << std::endl;
334 }
335};
336
337/// \brief Generic decorator to wrap any function call with timing measurements
338template<typename Func>
339inline auto measure_time(timing_tracker& timer, const std::string& name, Func&& func)
340{
341 auto start = timer.start_measurement();
342 if constexpr (std::is_same_v<void, decltype(func())>)
343 {
344 std::forward<Func>(func)();
345 timer.end_measurement(name, start);
346 }
347 else
348 {
349 auto result = std::forward<Func>(func)();
350 timer.end_measurement(name, start);
351 return result;
352 }
353}
354
356 rewrite_if_builder<pbes_system::pbes_expression_builder>& if_substituter,
357 simplify_data_rewriter<data::rewriter>& pbes_rewriter)
358{
359 pbes_expression res = pbes_rewrite(phi, pbes_rewriter);
360 if_substituter.apply(res, res);
361 return res;
362}
363
365{
366 return !(options.quantifier_free) || (find_all_variables(phi).size() - find_free_variables(phi).size()) == 0;
367}
368
369inline bool
371{
372 return !(options.pvi_pp_factor > 0.0) || ((double)pp(phi).size() <= options.pvi_pp_factor * (double)pp(cur_x).size());
373}
374
375inline bool
377{
378 return !(options.avoid_alternating) || new_x.name() == eq.variable().name();
379}
380
381inline void log_number_pvi(std::size_t& initial_size, std::size_t& current_size)
382{
383 mCRL2log(log::log_level_t::status) << "New number of pvi: " << initial_size << " --> " << current_size << "" << std::endl;
384}
385
386inline void self_substitute(pbes_equation& equation,
387 std::size_t initial_size,
388 substitute_propositional_variables_for_true_false_builder<pbes_system::pbes_expression_builder>& pvi_substituter,
389 rewrite_if_builder<pbes_system::pbes_expression_builder>& if_substituter,
390 simplify_data_rewriter<data::rewriter>& pbes_rewriter,
391 simplify_data_rewriter<data::rewriter>& pbes_default_rewriter,
392 pbeschain_options options)
393{
394 bool stable = false;
395 timing_tracker timer;
396
397 if (options.timeout > 0.0)
398 {
399 mCRL2log(log::log_level_t::verbose) << "Starting substitution for equation " << equation.variable().name() << " with timeout "
400 << options.timeout << "s" << std::endl;
401 }
402
403 std::set<propositional_variable_instantiation> stable_set = {}; // To record pvi that have reach a max depth
404 std::size_t previous_size = initial_size;
405 std::size_t current_size = initial_size;
406 while (!stable)
407 {
408 stable = true;
409 std::vector<propositional_variable_instantiation> set
410 = get_propositional_variable_instantiations(equation.formula());
411 current_size = set.size();
412
413 std::set<std::string> parameterNames = {};
414 for (data::variable a: equation.variable().parameters())
415 {
416 parameterNames.insert(a.name());
417 }
418 for (const propositional_variable_instantiation& x: set)
419 {
420 // Check timeout
421 if (options.timeout > 0.0)
422 {
423 std::chrono::time_point current_time = std::chrono::high_resolution_clock::now();
424 double elapsed = std::chrono::duration<double>(current_time - timer.start_time).count();
425 if (elapsed >= options.timeout)
426 {
427 stable = true;
428 mCRL2log(log::log_level_t::verbose) << "Timeout reached (" << options.timeout << "s) for equation "
429 << equation.variable().name() << " after " << elapsed << "s, stopping substitution"
430 << std::endl;
431 break;
432 }
433 }
434 if (equation.variable().name() != x.name())
435 {
436 continue;
437 }
438 if (auto it = stable_set.find(x); it != stable_set.end())
439 {
440 continue;
441 }
442 // Check if during the substitution of the other pvi this one got cancelled out
443 std::set<propositional_variable_instantiation> path = {x};
444
445 propositional_variable_instantiation cur_x = x;
446 pbes_expression result = x;
447
448 mCRL2log(log::log_level_t::debug) << " - - - - - - - - - - - - - - -\n"
449 << "\n\nStart " << (cur_x) << "\n";
450 bool pvi_done = false;
451 int depth = 0;
452 while (!pvi_done)
453 {
454 depth = depth + 1;
455
456 // (1) simplify
457 data::mutable_indexed_substitution sigma;
458 data::data_expression_list pars = cur_x.parameters();
459 for (const data::variable& v: equation.variable().parameters())
460 {
461 data::data_expression par = pars.front();
462 pars.pop_front();
463 if (par.sort() != v.sort())
464 {
465 throw mcrl2::runtime_error("PBES is not well-typed.");
466 }
467 sigma[v] = par;
468 }
469
470 pbes_expression phi = measure_time(timer,
471 "substitution",
472 [&]() { return pbes_rewrite(equation.formula(), pbes_default_rewriter, sigma); });
473
474 std::vector<propositional_variable_instantiation> phi_vector = get_propositional_variable_instantiations(phi);
475
476 // (2) replace all reoccuring with true (nu) and false (mu)
477 auto it = find(phi_vector.begin(), phi_vector.end(), cur_x);
478 if (it != phi_vector.end())
479 {
480 mCRL2log(log::log_level_t::debug) << "Need to replace this with true/false " << pp(cur_x) << "\n";
481 mCRL2log(log::log_level_t::debug) << phi << "\n";
482 mCRL2log(log::log_level_t::debug) << equation.formula() << "\n";
483
484 if (!options.disable_gauss_elimination || pp(cur_x.name()) == "X_true" || pp(cur_x.name()) == "X_false")
485 {
486 pvi_substituter.set_pvi(cur_x);
487 pvi_substituter.set_replacement(equation.symbol().is_nu() ? true_() : false_());
488 pvi_substituter.apply(phi, phi);
489 timer.increment_gauss_elimination_direct_count();
490 }
491
492 mCRL2log(log::log_level_t::debug) << phi << "\n";
493
494 mCRL2log(log::log_level_t::debug) << "- - - - - - - - - - - - - - - - - - - - \n";
495 }
496
497 // Simplify
498 phi = measure_time(timer, "simplify_expr", [&]() { return simplify_expr(phi, if_substituter, pbes_rewriter); });
499
500 phi_vector = get_propositional_variable_instantiations(phi);
501 std::size_t size = phi_vector.size();
502 if (options.count_unique_pvi)
503 {
504 size = std::set(phi_vector.begin(), phi_vector.end()).size();
505 }
506
507 // TODO: Also queue the other PVI in some way
508
509 // (3) check if simpler
510 bool condition_result = (size >= 1 && size <= options.max_number_pvi);
511
512 if (condition_result)
513 {
514 condition_result = measure_time(timer,
515 "is_avoiding_alternation",
516 [&]() {
517 return std::all_of(phi_vector.begin(), phi_vector.end(), [&](const propositional_variable_instantiation& pvi) {
518 return is_avoiding_alternation(options, pvi, equation);
519 });
520 });
521 }
522
523 if (condition_result)
524 {
525 condition_result
526 = measure_time(timer, "is_not_too_big", [&]() { return is_not_too_big(options, cur_x, phi); });
527 }
528
529 if (condition_result)
530 {
531 condition_result
532 = measure_time(timer, "is_quantifier_free", [&]() { return is_quantifier_free(phi, options); });
533 }
534
535 if (condition_result)
536 {
537 std::set<propositional_variable_instantiation> phi_set(phi_vector.begin(), phi_vector.end());
538 bool all_in_path = true;
539 measure_time(timer, "successful_substitutions", [&]() { return true; });
540
541 for (const propositional_variable_instantiation& phi_x: phi_set)
542 {
543 mCRL2log(log::log_level_t::debug) << "Trying loop " << phi_x << " in path with \n";
544 for (const propositional_variable_instantiation& itr: path)
545 {
546 mCRL2log(log::log_level_t::debug) << itr << "\n";
547 }
548
549 if (path.contains(phi_x))
550 {
551 // We have already seen this, so we are in a loop.
552 mCRL2log(log::log_level_t::debug) << "Loop, seen " << phi_x << " in path after " << cur_x << " " << phi << "\n";
553 for (const propositional_variable_instantiation& itr: path)
554 {
555 mCRL2log(log::log_level_t::debug) << itr << "\n";
556 }
557 if (!options.disable_gauss_elimination || pp(cur_x.name()) == "X_true" || pp(cur_x.name()) == "X_false")
558 {
559 pvi_substituter.set_pvi(phi_x);
560 pvi_substituter.set_replacement(equation.symbol().is_nu() ? true_() : false_());
561 pvi_substituter.apply(result, phi);
562 timer.increment_gauss_elimination_path_count();
563 }
564 }
565 else
566 {
567 all_in_path = false;
568 }
569 }
570
571 if (all_in_path && !options.disable_gauss_elimination)
572 {
573 pvi_substituter.set_pvi(cur_x);
574 pvi_substituter.set_replacement(result);
575 pvi_substituter.apply(equation.formula(), equation.formula());
576
577 mCRL2log(log::log_level_t::debug) << "new_phi " << result << "\n";
578 stable = false;
579 pvi_done = true;
580 }
581 else if (all_in_path)
582 {
583 mCRL2log(log::log_level_t::debug) << "Loop, but Gauss elimination is disabled; stop expanding " << cur_x << "\n";
584 stable_set.insert(x);
585 stable_set.insert(cur_x);
586 pvi_done = true;
587 }
588 else
589 {
590 // The result does not contain the variable m_eq.variable().name() and is therefore considered simpler.
591 mCRL2log(log::log_level_t::debug) << "Replaced in PBES equation for " << cur_x << "\n-->\n"
592 << phi << "\n"
593 << core::detail::print_list(phi_set) << "\n";
594
595 pvi_substituter.set_pvi(cur_x);
596 pvi_substituter.set_replacement(phi);
597 pvi_substituter.apply(equation.formula(), equation.formula());
598 // Get the set of elements that have the same name as the equation variable
599 std::set<propositional_variable_instantiation> phi_set_same_name;
600 std::copy_if(phi_set.begin(),
601 phi_set.end(),
602 std::inserter(phi_set_same_name, phi_set_same_name.begin()),
603 [&](const propositional_variable_instantiation& pvi)
604 { return pvi.name() == equation.variable().name(); });
605 stable = false;
606 if (phi_set_same_name.size() == 0)
607 {
608 pvi_done = true;
609 }
610 else
611 {
612 cur_x = *phi_set_same_name.begin();
613 }
614 }
615 }
616 else if (size == 0 && is_quantifier_free(phi, options))
617 {
618 pvi_substituter.set_pvi(cur_x);
619 pvi_substituter.set_replacement(phi);
620 pvi_substituter.apply(equation.formula(), equation.formula());
621 stable = false;
622 mCRL2log(log::log_level_t::debug) << "Replaced in PBES equation for " << cur_x << ":\n" << x << " \n-->\n " << phi << "\n";
623 pvi_done = true;
624 measure_time(timer, "successful_substitutions", [&]() { return true; });
625 }
626 else
627 {
628 mCRL2log(log::log_level_t::debug) << "Not simpler: " << cur_x << " \n--> size: " << phi_vector.size() << "\n " << phi
629 << " and size " << phi_vector.size() << "\n";
630 pvi_done = true;
631 if (depth > 1)
632 {
633 stable = false;
634 }
635 }
636 if (pvi_done)
637 {
638 mCRL2log(log::log_level_t::debug) << "Nothing further to do\n";
639 break;
640 }
641 else if (depth >= options.max_depth)
642 {
643 stable_set.insert(x);
644 stable_set.insert(cur_x);
645 pvi_done = true;
646 break;
647 }
648 }
649
650 std::vector<propositional_variable_instantiation> set
651 = get_propositional_variable_instantiations(equation.formula());
652
653 current_size = set.size();
654 log_number_pvi(initial_size, current_size);
655
656 // Simplify
657 if (current_size == 0 || (previous_size >= current_size + 10))
658 {
659 previous_size = current_size;
660 equation.formula() = measure_time(timer,
661 "simplify_expr",
662 [&]() { return simplify_expr(equation.formula(), if_substituter, pbes_rewriter); });
663 }
664 }
665 }
666
667 log_number_pvi(initial_size, current_size);
668
669 if (current_size == 0)
670 {
671 equation.formula() = measure_time(timer,
672 "simplify_expr",
673 [&]() { return simplify_expr(equation.formula(), if_substituter, pbes_rewriter); });
674 }
675
676 if (options.timings)
677 {
679 }
680}
681
682inline void substitute(pbes_equation& into,
683 const pbes_equation& by,
684 substitute_propositional_variables_builder<pbes_system::pbes_expression_builder>& substituter)
685{
686 substituter.set_equation(by);
687 substituter.set_name(into.variable().name());
689 substituter.apply(p, into.formula());
690 into.formula() = p;
691}
692
693// Fill in the parameters of the pvi based on the guard of each pvi
694inline pbes fill_pvi(pbes& p, data::rewriter data_rewriter)
695{
696 detail::stategraph_pbes stategraph(p, data_rewriter);
697 simplify_data_rewriter<data::rewriter> pbes_default_rewriter(data_rewriter);
698
699 // Preparation
700 for (detail::stategraph_equation& equation: stategraph.equations())
701 {
702 for (detail::predicate_variable& predvar: equation.predicate_variables())
703 {
704 predvar.simplify_guard();
705 }
706 }
708
709 // Reduction
710 std::vector<pbes_equation> eqn = {};
711 for (detail::stategraph_equation& eq: stategraph.equations())
712 {
713 substitute_propositional_variables_i_builder<pbes_system::pbes_expression_builder> substituter(
714 pbes_default_rewriter,
715 eq.predicate_variables());
716
717 pbes_expression new_formula;
718 substituter.apply(new_formula, eq.formula());
719 pbes_equation new_eq(static_cast<const pbes_equation&>(eq));
720 new_eq.formula() = new_formula;
721 eqn.push_back(new_eq);
722 }
723
724 // Back to pbes
725 pbes res(p.data(), p.global_variables(), eqn, p.initial_state());
726 return res;
727}
728
729inline pbes tosrf(pbes_system::pbes pbesspec, bool split_srf_conditions = false)
730{
731 auto result = pbes2srf(pbesspec, true);
732 if (split_srf_conditions)
733 {
734 result = split_conditions(result, 1);
735 }
736 return (result).to_pbes();
737}
738
740{
741 void run(pbes& p, pbeschain_options options)
742 {
743 data::rewriter data_rewriter(p.data(), options.rewrite_strategy);
744 data::rewriter data_default_rewriter(p.data());
745#ifdef MCRL2_ENABLE_JITTYC
746 if (options.rewrite_strategy == data::rewriter::strategy::jitty_compiling
747 || options.rewrite_strategy == data::rewriter::strategy::jitty_compiling_prover)
748 {
749 data_default_rewriter = data_rewriter;
750 }
751#endif // MCRL2_ENABLE_JITTYC
752 simplify_data_rewriter<data::rewriter> pbes_rewriter(data_rewriter);
753 simplify_data_rewriter<data::rewriter> pbes_rewriter2(data_rewriter);
754 simplify_data_rewriter<data::rewriter> pbes_default_rewriter(data_default_rewriter);
755 substitute_propositional_variables_builder<pbes_system::pbes_expression_builder> substituter(pbes_default_rewriter);
756 rewrite_if_builder<pbes_system::pbes_expression_builder> if_rewriter(pbes_default_rewriter);
757 substitute_propositional_variables_for_true_false_builder<pbes_system::pbes_expression_builder> pvi_substituter(
758 pbes_rewriter);
759
760 if (options.fill_pvi)
761 {
762 p = fill_pvi(p, data_rewriter);
763 }
764
765 if (options.max_depth <= 0)
766 {
767 return;
768 }
769
770 std::vector<std::size_t> initial_sizes = {};
771 for (pbes_equation& i: p.equations())
772 {
773 initial_sizes.push_back(get_propositional_variable_instantiations(i.formula()).size());
774 }
775
776 pbes original_pbes;
777 if (options.srf_factor > 0)
778 {
779 original_pbes = p;
780 }
781
782 std::set<core::identifier_string> equations_to_remove;
783
784 for (std::size_t equation_index = p.equations().size(); equation_index > 0; --equation_index)
785 {
786 pbes_equation& i = p.equations()[equation_index - 1];
787 mCRL2log(log::log_level_t::verbose) << "Investigating the equation for " << i.variable().name() << "\n";
788 std::size_t original_i = equation_index - 1;
789
790 self_substitute(i,
791 initial_sizes[original_i],
792 pvi_substituter,
793 if_rewriter,
794 options.rewrite_only_substitution ? pbes_default_rewriter : pbes_rewriter,
795 pbes_default_rewriter,
796 options);
797
798 std::set<propositional_variable_instantiation> pvi_set = find_propositional_variable_instantiations(i.formula());
799
800 // If the SRF form of some equation is too big, replace the formula of that equation with the original formula.
801 if (pvi_set.size() > 0 && options.srf_factor > 0)
802 {
803 // Use the same SRF form as pbessolvesymbolic
804 pbes result_srf_pbes = tosrf(p, options.srf_split_conditions);
805 pbes original_srf_pbes = tosrf(original_pbes, options.srf_split_conditions);
806
807 // Find our equation in both PBESs
808 core::identifier_string original_variable_name = i.variable().name();
809 auto original_eq_it = std::find_if(original_pbes.equations().begin(),
810 original_pbes.equations().end(),
811 [&](const pbes_equation& eq) { return eq.variable().name() == original_variable_name; });
812 if (original_eq_it == original_pbes.equations().end())
813 continue;
814 const pbes_equation& original_eq = *original_eq_it;
815
816 auto result_srf_eq = std::find_if(result_srf_pbes.equations().rbegin(),
817 result_srf_pbes.equations().rend(),
818 [&](const pbes_equation& eq) { return eq.variable().name() == original_variable_name; });
819 if (result_srf_eq == result_srf_pbes.equations().rend())
820 continue;
821
822 auto original_srf_eq = std::find_if(original_srf_pbes.equations().rbegin(),
823 original_srf_pbes.equations().rend(),
824 [&](const pbes_equation& eq) { return eq.variable().name() == original_variable_name; });
825 if (original_srf_eq == original_srf_pbes.equations().rend())
826 continue;
827
828 std::size_t original_size = pp(original_srf_eq->formula()).size();
829 std::size_t new_size = pp(result_srf_eq->formula()).size();
830 mCRL2log(log::log_level_t::verbose) << "Original size: " << original_size << " New size: " << new_size << "\n";
831 if (options.srf_factor * (double)original_size <= (double)new_size)
832 {
833 log_number_pvi(initial_sizes[original_i], initial_sizes[original_i]);
834 i.formula() = original_eq.formula();
835 pvi_set = find_propositional_variable_instantiations(i.formula());
836 }
837 }
838
839 mCRL2log(log::log_level_t::verbose) << "How many unique PVI are left? " << pvi_set.size() << "\n";
840
841 // Substitute back
842 if (pvi_set.size() == 0 && options.back_substitution)
843 {
844 if (options.rewrite_only_substitution)
845 {
846 i.formula() = simplify_expr(i.formula(), if_rewriter, pbes_rewriter);
847 }
848 for (std::size_t j = 0; j < equation_index; ++j)
849 {
850 substitute(p.equations()[j], i, substituter);
851 }
852 equations_to_remove.insert(i.variable().name());
853 }
854 }
855
856 if (options.remove_equation)
857 {
858 std::set<core::identifier_string> removable_equations;
859 for (std::size_t i = 0; i < p.equations().size(); ++i)
860 {
861 const core::identifier_string& name = p.equations()[i].variable().name();
862 if (!equations_to_remove.contains(name))
863 {
864 continue;
865 }
866
867 bool referenced = (p.initial_state().name() == name);
868 for (std::size_t j = 0; j < p.equations().size() && !referenced; ++j)
869 {
870 if (i == j)
871 {
872 continue;
873 }
874 const std::set<propositional_variable_instantiation> pvis
875 = find_propositional_variable_instantiations(p.equations()[j].formula());
876 referenced = std::any_of(pvis.begin(),
877 pvis.end(),
878 [&](const propositional_variable_instantiation& pvi) { return pvi.name() == name; });
879 }
880 if (!referenced)
881 {
882 removable_equations.insert(name);
883 }
884 }
885
886 p.equations().erase(std::remove_if(p.equations().begin(),
887 p.equations().end(),
888 [&](const pbes_equation& equation)
889 { return removable_equations.contains(equation.variable().name()); }),
890 p.equations().end());
891 }
892 }
893};
894
895inline void pbeschain(const std::string& input_filename,
896 const std::string& output_filename,
897 const utilities::file_format& input_format,
898 const utilities::file_format& output_format,
899 pbeschain_options options)
900{
901 pbes p;
902 load_pbes(p, input_filename, input_format);
904 pbeschain_pbes_backward_substituter backward_substituter;
905 backward_substituter.run(p, options);
906 save_pbes(p, output_filename, output_format);
907}
908
909} // namespace mcrl2::pbes_system
910
911#endif // MCRL2_PBES_TOOLS_PBESCHAIN_H
aterm_string & operator=(const aterm_string &t) noexcept=default
sort_expression sort() const
Returns the sort of the data expression.
Definition data.cpp:107
\brief A function symbol
const core::identifier_string & name() const
Rewriter that operates on data expressions.
Definition rewriter.h:84
const sort_expression & target_sort() const
Returns the target sort of this expression.
stategraph_pbes(const pbes &p, const data::rewriter &rewr)
Constructor.
propositional_variable & variable()
Returns the pbes variable of the equation.
pbes_expression & formula()
Returns the predicate formula on the right hand side of the equation.
const propositional_variable & variable() const
Returns the pbes variable of the equation.
pbes_expression & operator=(const pbes_expression &) noexcept=default
parameterized boolean equation system
Definition pbes.h:54
\brief A propositional variable instantiation
propositional_variable_instantiation & operator=(const propositional_variable_instantiation &) noexcept=default
const core::identifier_string & name() const
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:435
data_expression not_(const data_expression &x)
bool is_application(const data_expression &t)
Returns true if the term t is an application.
data_expression or_(const data_expression &x, const data_expression &y)
data_expression and_(const data_expression &x, const data_expression &y)
sort_expression bool_()
bool is_function_symbol(const atermpp::aterm &x)
Returns true if the term t is a function symbol.
void normalize(pbes &x)
The function normalize brings (embedded) pbes expressions into positive normal form,...
The main namespace for the PBES library.
void log_number_pvi(std::size_t &initial_size, std::size_t &current_size)
Definition pbeschain.h:381
auto measure_time(timing_tracker &timer, const std::string &name, Func &&func)
Generic decorator to wrap any function call with timing measurements.
Definition pbeschain.h:339
pbes fill_pvi(pbes &p, data::rewriter data_rewriter)
Definition pbeschain.h:694
bool is_avoiding_alternation(const pbeschain_options &options, const propositional_variable_instantiation &new_x, const pbes_equation &eq)
Definition pbeschain.h:376
void pbeschain(const std::string &input_filename, const std::string &output_filename, const utilities::file_format &input_format, const utilities::file_format &output_format, pbeschain_options options)
Definition pbeschain.h:895
std::vector< propositional_variable_instantiation > get_propositional_variable_instantiations(Container const &container)
Returns all data variables that occur in a range of expressions.
Definition pbeschain.h:245
pbes_expression simplify_expr(pbes_expression &phi, rewrite_if_builder< pbes_system::pbes_expression_builder > &if_substituter, simplify_data_rewriter< data::rewriter > &pbes_rewriter)
Definition pbeschain.h:355
pbes tosrf(pbes_system::pbes pbesspec, bool split_srf_conditions=false)
Definition pbeschain.h:729
bool is_not_too_big(pbeschain_options &options, propositional_variable_instantiation &cur_x, pbes_expression &phi)
Definition pbeschain.h:370
bool is_quantifier_free(pbes_expression &phi, pbeschain_options options)
Definition pbeschain.h:364
std::set< data::variable > find_free_variables(const pbes_system::pbes_expression &x)
Definition pbes.cpp:54
void self_substitute(pbes_equation &equation, std::size_t initial_size, substitute_propositional_variables_for_true_false_builder< pbes_system::pbes_expression_builder > &pvi_substituter, rewrite_if_builder< pbes_system::pbes_expression_builder > &if_substituter, simplify_data_rewriter< data::rewriter > &pbes_rewriter, simplify_data_rewriter< data::rewriter > &pbes_default_rewriter, pbeschain_options options)
Definition pbeschain.h:386
void substitute(pbes_equation &into, const pbes_equation &by, substitute_propositional_variables_builder< pbes_system::pbes_expression_builder > &substituter)
void run(pbes &p, pbeschain_options options)
Definition pbeschain.h:741
simplify_data_rewriter< data::rewriter > m_pbes_rewriter
Definition pbeschain.h:109
data::data_expression simpl_data(const data::data_expression &x)
Definition pbeschain.h:115
rewrite_if_builder(simplify_data_rewriter< data::rewriter > &r)
Definition pbeschain.h:111
void apply(T &result, const data::data_expression &x)
Definition pbeschain.h:136
A rewriter that simplifies boolean expressions in a term, and rewrites data expressions using DataRew...
substitute_propositional_variables_builder(simplify_data_rewriter< data::rewriter > &r)
Definition pbeschain.h:153
simplify_quantifiers_data_rewriter< data::rewriter > m_pbes_rewriter
Definition pbesbackelm.h:46
void apply(T &result, const propositional_variable_instantiation &x)
Definition pbesbackelm.h:74
substitute_propositional_variables_for_true_false_builder(simplify_data_rewriter< data::rewriter > &r)
Definition pbeschain.h:76
void apply(T &result, const propositional_variable_instantiation &x)
Definition pbeschain.h:90
void set_pvi(const propositional_variable_instantiation x)
Definition pbeschain.h:80
std::vector< detail::predicate_variable > predvars
Definition pbeschain.h:224
substitute_propositional_variables_i_builder(simplify_data_rewriter< data::rewriter > &r, std::vector< detail::predicate_variable > predvars)
Definition pbeschain.h:227
simplify_data_rewriter< data::rewriter > m_pbes_rewriter
Definition pbeschain.h:223
void apply(T &result, const propositional_variable_instantiation &x)
Definition pbeschain.h:234
void add_measurement(std::chrono::duration< double, std::milli > duration)
Definition pbeschain.h:260
std::chrono::duration< double, std::milli > total_time
Definition pbeschain.h:257
Helper class to track multiple time measurements and call counts.
Definition pbeschain.h:254
void log_measurements() const
Log all measurements.
Definition pbeschain.h:308
void increment_gauss_elimination_path_count()
Increment the counter of path Gauss eliminations (replacing a pvi in a loop with true/false)
Definition pbeschain.h:288
std::map< std::string, measurement > measurements
Definition pbeschain.h:273
void increment_gauss_elimination_direct_count()
Increment the counter of direct Gauss eliminations (replacing a reoccurring pvi with true/false)
Definition pbeschain.h:282
std::chrono::time_point< std::chrono::high_resolution_clock > start_time
Definition pbeschain.h:272
std::chrono::time_point< std::chrono::steady_clock > start_measurement()
Start timing an operation (returns the start time for use with end_measurement)
Definition pbeschain.h:294
void end_measurement(const std::string &label, std::chrono::time_point< std::chrono::steady_clock > measurement_start)
End timing an operation and record it.
Definition pbeschain.h:300