mCRL2
Loading...
Searching...
No Matches
linear_inequalities.h
Go to the documentation of this file.
1// Author(s): Jeroen Keiren and Jan Friso Groote
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 linear_inequalities.h
10/// \brief Contains a class linear_inequality to represent mcrl2 data
11/// expressions that are linear equalities, or inequalities.
12/// Furthermore, it contains some operations on these linear
13/// inequalities, such as Fourier-Motzkin elimination.
14
15
16#ifndef MCRL2_DATA_LINEAR_INEQUALITY_H
17#define MCRL2_DATA_LINEAR_INEQUALITY_H
18
19#include <memory>
20#include <ranges>
21
22#include "mcrl2/data/rewriter.h"
23#include "mcrl2/data/substitutions/map_substitution.h"
24
25namespace mcrl2::data
26{
27
28// Functions below should be made available in the data library.
35bool is_negative(const data_expression& e,const rewriter& r);
36bool is_positive(const data_expression& e,const rewriter& r);
37bool is_zero(const data_expression& e);
38
39
40// Efficient construction of times on reals.
41// The functions times, divide, plus, minus, negate and abs in the data library are not efficient since they determine the sort at runtime.
42inline application real_times(const data_expression& arg0, const data_expression& arg1)
43{
46 return application(times_f,arg0,arg1);
47}
48
49inline application real_plus(const data_expression& arg0, const data_expression& arg1)
50{
53 return application(plus_f,arg0,arg1);
54}
55
56inline application real_divides(const data_expression& arg0, const data_expression& arg1)
57{
60 return application(divides_f,arg0,arg1);
61}
62
63inline application real_minus(const data_expression& arg0, const data_expression& arg1)
64{
67 return application(minus_f,arg0,arg1);
68}
69
70inline application real_negate(const data_expression& arg)
71{
73 assert(arg.sort()==sort_real::real_());
74 return application(negate_f,arg);
75}
76
77inline application real_abs(const data_expression& arg)
78{
80 assert(arg.sort()==sort_real::real_());
81 return application(abs_f,arg);
82}
83
84// End of functions that ought to be defined elsewhere.
85
86
88
89// prototype
91namespace detail
92{
93 class lhs_t;
94}
95
96inline std::string pp(const linear_inequality& l);
97template <class TYPE>
98inline std::string pp_vector(const TYPE& inequalities);
99
100namespace detail
101{
103
104 inline std::string pp(const detail::lhs_t& lhs);
105
107 {
108 switch (t)
109 {
110 case detail::less: return detail::less_eq;
111 case detail::less_eq: return detail::less;
112 case detail::equal: return detail::equal;
113 };
114 return detail::equal; // This return statement should be unreachable. It is added to suppress a compiler warning.
115 }
116
118 {
119 switch (t)
120 {
121 case detail::less: return "<";
122 case detail::less_eq: return "<=";
123 case detail::equal: return "==";
124 };
125 return "##"; // This return statement should be unreachable. It is added to suppress a compiler warning.
126 }
127
129 {
130 static atermpp::function_symbol f("variable_with_a_rational_factor",2);
131 return f;
132 }
133
135 {
136 public:
137 // \brief default constructor
140 {
141 assert(f!=real_zero());
142 }
143
144 // \brief Get the variable in a variable/rational factor pair.
145 const variable& variable_name() const
146 {
148 return atermpp::down_cast<variable>((*this)[0]);
149 }
150
151 // \brief Get the rational factor in a variable/rational factor pair.
152 const data_expression& factor() const
153 {
155 return atermpp::down_cast<data_expression>((*this)[1]);
156 }
157
158 // \brief Check that a term is indeed a variable with a rational factor pair.
160 {
161 return function()==f_variable_with_a_rational_factor();
162 }
163
164 // \brief Transform the variable with factor to a data_expression.
166 {
168 }
169 };
170
172
174 {
175 public:
176 /// \brief Constructor.
179 {}
180
181 /// \brief Constructor from an aterm.
182 explicit lhs_t(const aterm& t)
184 {}
185
186 /// \brief Constructor
187 template <class ITERATOR>
188 lhs_t(const ITERATOR begin, const ITERATOR end)
190 {}
191
192 /// \brief Constructor
193 template <class ITERATOR, class TRANSFORMER>
194 lhs_t(const ITERATOR begin, const ITERATOR end, TRANSFORMER f)
196 {}
197
198 /// \brief Give an iterator of the factor/variable pair for v, or end() if v does not occur.
200 {
201 return std::find_if(begin(),
202 end(),
203 [&](const detail::variable_with_a_rational_factor& p)
204 {return p.variable_name()==v;});
205 }
206
207 /// \brief Erase a variable and its factor.
208 lhs_t erase(const variable& v) const
209 {
210 std::vector <variable_with_a_rational_factor> result;
211 for(const variable_with_a_rational_factor& p: *this)
212 {
213 if (p.variable_name()!=v)
214 {
215 result.push_back(p);
216 }
217 }
218 return lhs_t(result.begin(),result.end());
219 }
220
221 /// \brief Give the factor of variable v.
222 const data_expression& operator[](const variable& v) const
223 {
224 lhs_t::const_iterator i=find(v);
225 if (i==end()) // Not found.
226 {
227 return real_zero();
228 }
229 return i->factor();
230 }
231
232 /// \brief Give the factor of variable v.
233 std::size_t count(const variable& v) const
234 {
235 lhs_t::const_iterator i=find(v);
236 if (i==end()) // Not found.
237 {
238 return 0;
239 }
240 return 1;
241 }
242
243 /// \brief Evaluate the variables in this lhs_t according to the subsitution function.
244 template <IsSubstitution SubstitutionFunction>
245 data_expression evaluate(const SubstitutionFunction& beta, const rewriter& r) const
246 {
248 bool result_defined=false; // save adding the initial zero.
249 for (const variable_with_a_rational_factor& p: *this)
250 {
251 if (result_defined)
252 {
253 result=rewrite_with_memory(real_plus(result,real_times(beta(p.variable_name()),p.factor())), r);
254 }
255 else
256 {
257 result=rewrite_with_memory(real_times(beta(p.variable_name()),p.factor()), r);
258 result_defined=true;
259 }
260
261 }
262 return result;
263 }
264
265 // \brief Transform this lhs to a data_expression.
267 {
268 if (size()==0)
269 {
270 return real_zero();
271 }
273
274 for(const variable_with_a_rational_factor& p: *this)
275 {
276 if (result==real_zero())
277 {
278 result=p.transform_to_data_expression();
279 }
280 else
281 {
282 result=real_plus(result,p.transform_to_data_expression());
283 }
284 }
285 return result;
286 }
287 };
288
289 inline void set_factor_for_a_variable(detail::map_based_lhs_t& new_lhs, const variable& x, const data_expression& e)
290 {
292 if (e==real_zero())
293 {
294 detail::map_based_lhs_t::iterator i=new_lhs.find(x);
295 if (i!=new_lhs.end())
296 {
297 new_lhs.erase(i);
298 }
299 }
300 else
301 {
302 new_lhs[x]=e;
303 }
304 }
305
306 inline lhs_t set_factor_for_a_variable(const lhs_t& lhs, const variable& x, const data_expression& e)
307 {
309 bool inserted=false;
310 std::vector<variable_with_a_rational_factor> result;
311 for(const variable_with_a_rational_factor& p: lhs)
312 {
313 if (!inserted && x<=p.variable_name())
314 {
315 result.emplace_back(x,e);
316 inserted=true;
317 if (x!=p.variable_name())
318 {
319 result.emplace_back(p.variable_name(),p.factor());
320 }
321 }
322 else
323 {
324 result.emplace_back(p.variable_name(), p.factor());
325 }
326 }
327 if (!inserted)
328 {
329 result.emplace_back(x,e);
330 }
331 assert(std::find(result.begin(),result.end(),variable_with_a_rational_factor(x,e))!=result.end());
332 return lhs_t(result.begin(),result.end());
333 }
334
335 inline lhs_t map_to_lhs_type(const map_based_lhs_t& lhs)
336 {
337 lhs_t result;
338 for (const std::pair<const variable, data_expression>& expr: std::ranges::reverse_view(lhs))
339 {
340 result.push_front(variable_with_a_rational_factor(expr.first,expr.second));
341 }
342 return result;
343 }
344
345 inline lhs_t map_to_lhs_type(const map_based_lhs_t& lhs, const data_expression& factor, const rewriter& r)
346 {
347 assert(factor!=real_one() && factor!=real_minus_one());
348 lhs_t result;
349 for (const std::pair<const variable, data_expression>& expr: std::ranges::reverse_view(lhs))
350 {
351 result.push_front(variable_with_a_rational_factor(expr.first, rewrite_with_memory(real_divides(expr.second,factor), r)));
352 }
353 return result;
354 }
355
356 inline bool is_well_formed(const lhs_t& lhs)
357 {
358 if (lhs.empty())
359 {
360 return true;
361 }
362 if (lhs.front().factor()!=real_one() && lhs.front().factor()!=real_minus_one())
363 {
364 return false;
365 }
366 variable last_variable_seen=lhs.front().variable_name();
367 bool first=true;
368 for(const variable_with_a_rational_factor& p: lhs)
369 {
370 if (!first)
371 {
372 first=false;
373 if (p.variable_name()<=last_variable_seen)
374 {
375 return false;
376 }
377 last_variable_seen=p.variable_name();
378 }
379 }
380 return true;
381 }
382
383 inline lhs_t remove_variable_and_divide(const lhs_t& lhs, const variable& v, const data_expression& f, const rewriter& r)
384 {
385 std::vector <variable_with_a_rational_factor> result;
386 for(const variable_with_a_rational_factor& p: lhs)
387 {
388 if (p.variable_name()!=v)
389 {
390 result.emplace_back(p.variable_name(),rewrite_with_memory(real_divides(p.factor(),f), r));
391 }
392 }
393 return lhs_t(result.begin(),result.end());
394 }
395
396 inline void emplace_back_if_not_zero(std::vector<detail::variable_with_a_rational_factor>& r, const variable& v, const data_expression& f)
397 {
398 if (f!=real_zero())
399 {
400 r.emplace_back(v,f);
401 }
402 }
403
404
405 template < application Operation(const data_expression&, const data_expression&) >
407 {
411 {
413 }
414 return lhs_t(result.begin(),result.end());
415 }
416
417 // Template method to add or subtract lhs_t's
418 // template < application Operation(const data_expression&, const data_expression&) >
419 template <class OPERATION>
421 const lhs_t& argument2,
423 const rewriter& r)
424 {
427
430
431 while (i1!=argument1.end() && i2!=argument2.end())
432 {
434 {
436 ++i1;
437 }
438 else if (i1->variable_name()>i2->variable_name())
439 {
441 ++i2;
442 }
443 else
444 {
445 assert(i1->variable_name()==i2->variable_name());
447 ++i1;
448 ++i2;
449 }
450 }
451
452 if (i1==argument1.end())
453 {
454 while (i2!=argument2.end())
455 {
457 ++i2;
458 }
459 }
460 else
461 {
462 while (i1!=argument1.end())
463 {
465 ++i1;
466 }
467 }
468 return lhs_t(result.begin(),result.end());
469 }
470
471 inline lhs_t add(const data_expression& v, const lhs_t& argument, const rewriter& r)
472 {
474 }
475
476 inline lhs_t subtract(const lhs_t& argument, const data_expression& v, const rewriter& r)
477 {
479 }
480
481 inline lhs_t multiply(const lhs_t& argument, const data_expression& v, const rewriter& r)
482 {
484 }
485
486 inline lhs_t divide(const lhs_t& argument, const data_expression& v, const rewriter& r)
487 {
489 }
490
491 inline lhs_t add(const lhs_t& argument, const lhs_t& e, const rewriter& r)
492 {
494 e,
496 { return real_plus(d1,d2); },
497 r);
498 }
499
500 inline lhs_t subtract(const lhs_t& argument, const lhs_t& e, const rewriter& r)
501 {
503 e,
505 { return real_minus(d1,d2); },
506 r);
507 }
508
509 inline std::string pp(const lhs_t& lhs)
510 {
511 std::string s;
512 if (lhs.begin()==lhs.end())
513 {
514 s="0";
515 }
516 for (lhs_t::const_iterator i=lhs.begin(); i!=lhs.end(); ++i)
517 {
518 s=s + (i==lhs.begin()?"":" + ") ;
519
520 if (i->factor()==real_one())
521 {
522 s=s + pp(i->variable_name());
523 }
524 else if (i->factor()==real_minus_one())
525 {
526 s=s + "-" + pp(i->variable_name());
527 }
528 else
529 {
530 s=s + data::pp(i->factor()) + "*" + data::pp(i->variable_name());
531 }
532 }
533 return s;
534 }
535
537 {
538 static atermpp::function_symbol f("linear_inequality_less",2);
539 return f;
540 }
541
542
544 {
545 static atermpp::function_symbol f("linear_inequality_less_equal",2);
546 return f;
547 }
548
549
551 {
552 static atermpp::function_symbol f("linear_inequality_equal",2);
553 return f;
554 }
555
556} // end namespace detail
557
559{
560 // The structure of a linear equality is a function application
561 // to two arguments. The function application is either linear_inequality_less,
562 // linear_inequality_less_equal, or linear_inequality_equal. There are two arguments,
563 // namely an ordered list of pairs of a variable and a factor. This list is ordered
564 // on the variables, and a closed expression which forms the right hand side.
565 // The first variable in the list has a factor one or minus one.
566
567 protected:
568
570 const data_expression& e,
571 detail::map_based_lhs_t& new_lhs,
572 data_expression& new_rhs,
573 const rewriter& r,
574 const bool negate = false,
575 const data_expression& factor = real_one())
576 {
578 {
579 parse_and_store_expression(binary_left1(e),new_lhs,new_rhs,r,negate,factor);
580 parse_and_store_expression(binary_right1(e),new_lhs,new_rhs,r,!negate,factor);
581 }
583 {
584 parse_and_store_expression(unary_operand1(e),new_lhs,new_rhs,r,!negate,factor);
585 }
587 {
588 parse_and_store_expression(binary_left1(e),new_lhs,new_rhs,r,negate,factor);
589 parse_and_store_expression(binary_right1(e),new_lhs,new_rhs,r,negate,factor);
590 }
592 {
593 data_expression lhs = rewrite_with_memory(binary_left1(e),r);
594 data_expression rhs = rewrite_with_memory(binary_right1(e),r);
596 {
597 parse_and_store_expression(rhs,new_lhs,new_rhs,r,negate,real_times(lhs,factor));
598 }
599 else if (is_closed_real_number(rhs))
600 {
601 parse_and_store_expression(lhs,new_lhs,new_rhs,r,negate,real_times(rhs,factor));
602 }
603 else
604 {
605 throw mcrl2::runtime_error("Expect constant multiplies expression: " + pp(e) + "\n");
606 }
607 }
608 else if (is_variable(e))
609 {
610 const variable& v = atermpp::down_cast<variable>(e);
612 {
613 throw mcrl2::runtime_error("Encountered a variable in a real expression which is not of sort real: " + pp(e) + "\n");
614 }
615 const detail::map_based_lhs_t::const_iterator var_factor = new_lhs.find(v);
616
617 const data_expression neg_factor(negate ? real_negate(factor) : factor);
618 const data_expression new_factor(var_factor == new_lhs.end() ? neg_factor : real_plus(var_factor->second, neg_factor));
619 detail::set_factor_for_a_variable(new_lhs, v, rewrite_with_memory(new_factor, r));
620 }
622 {
623 // We are reasoning about the rhs, so apply double negation in case 'negate' is true
624 data_expression add_to_rhs(negate ? e : real_negate(e));
625 if(factor != real_one())
626 {
627 add_to_rhs = real_times(factor, add_to_rhs);
628 }
629 new_rhs = rewrite_with_memory(real_plus(new_rhs, add_to_rhs), r);
630 }
631 else
632 {
633 throw mcrl2::runtime_error("Expect linear expression over reals: " + pp(e) + "\n");
634 }
635 }
636
637
638 public:
639
640 /// \brief Constructor yielding an inconsistent inequality.
643 {}
644
645 /// Basic constructor.
647 : atermpp::aterm((t==detail::less?
650 lhs,r)
651 {
652 assert(detail::is_well_formed(lhs));
653 assert(t==detail::less || t==detail::less_eq || t==detail::equal);
654 }
655
656 /// \brief constructor.
657 linear_inequality(const detail::lhs_t& lhs, const data_expression& rhs, detail::comparison_t comparison, const rewriter& r)
658 {
659 if (lhs.empty())
660 {
661 *this=linear_inequality(detail::lhs_t(),rhs,comparison);
662 return;
663 }
664 // Normalize the linear_inequality such that the first term has factor 1 or -1.
665 data_expression factor=lhs.begin()->factor();
666 if (factor==real_one() || factor==real_minus_one())
667 {
668 *this=linear_inequality(lhs,rhs,comparison);
669 return;
670 }
672
673 *this=linear_inequality(divide(lhs,factor,r),rewrite_with_memory(real_divides(rhs,factor), r),comparison);
674 }
675
676 /// \brief constructor.
678 const data_expression& rhs,
679 const detail::comparison_t comparison,
680 const rewriter& r,
681 const bool negate=false)
682 {
683 detail::map_based_lhs_t new_lhs;
685 parse_and_store_expression(lhs,new_lhs,new_rhs,r,negate);
686 parse_and_store_expression(rhs,new_lhs,new_rhs,r,!negate);
687
688 if (new_lhs.empty())
689 {
690 if ((comparison==detail::equal && new_rhs==real_zero()) ||
691 (comparison==detail::less_eq && (new_rhs == real_zero() || is_positive(new_rhs,r))) ||
692 (comparison==detail::less && is_positive(new_rhs,r)))
693 {
694 // The linear inequality represents true.
696 return;
697 }
698 // The linear inequality represents false.
700 return;
701 }
702
703 // Normalize the linear_inequality such that the first term has factor 1 or -1.
704 data_expression factor=new_lhs.begin()->second;
705 if (factor==real_one() || factor==real_minus_one())
706 {
707 *this=linear_inequality(detail::map_to_lhs_type(new_lhs),new_rhs,comparison);
708 return;
709 }
711
712 *this=linear_inequality(detail::map_to_lhs_type(new_lhs,factor,r),rewrite_with_memory(real_divides(new_rhs,factor), r),comparison);
713 }
714
715
716
717 /// \brief Constructor that constructs a linear inequality out of a data expression.
718 /// \details The data expression e is expected to have the form
719 /// lhs op rhs where op is one of <=,<,==,>,>= and lhs and rhs
720 /// satisfy the syntax t ::= x | c*t | t*c | t+t | t-t | -t where x is
721 /// a variable and c is a real constant.
722 /// \param e Contains the expression to become a linear inequality.
723 /// \param r A rewriter used to evaluate the expression.
724
726 const rewriter& r)
727 {
728 detail::comparison_t comparison;
729 bool negate(false);
730 if (is_equal_to_application(e))
731 {
732 comparison=detail::equal;
733 }
734 else if (is_less_application(e))
735 {
736 comparison=detail::less;
737 }
738 else if (is_less_equal_application(e))
739 {
740 comparison=detail::less_eq;
741 }
742 else if (is_greater_application(e))
743 {
744 comparison=detail::less;
745 negate=true;
746 }
747 else if (is_greater_equal_application(e))
748 {
749 comparison=detail::less_eq;
750 negate=true;
751 }
752 else
753 {
754 throw mcrl2::runtime_error("Unexpected equality or inequality: " + pp(e) + "\n") ;
755 }
756
757 data_expression lhs=data::binary_left(atermpp::down_cast<application>(e));
758 data_expression rhs=data::binary_right(atermpp::down_cast<application>(e));
759 *this=linear_inequality(lhs,rhs,comparison,r,negate);
760
761 }
762
763
765 {
766 return lhs().begin();
767 }
768
770 {
771 return lhs().end();
772 }
773
774 const detail::lhs_t& lhs() const
775 {
776 return atermpp::down_cast<detail::lhs_t>((*this)[0]);
777 }
778
779 const data_expression& rhs() const
780 {
781 return atermpp::down_cast<data_expression>((*this)[1]);
782 }
783
785 {
786 return lhs()[x];
787 }
788
790 {
791 if (this->function()==detail::linear_inequality_less())
792 {
793 return detail::less;
794 }
795 else if (this->function()==detail::linear_inequality_less_equal())
796 {
797 return detail::less_eq;
798 }
799 assert(this->function()==detail::linear_inequality_equal());
800 return detail::equal;
801 }
802
804 {
806 if (c==detail::less_eq)
807 {
809 }
810 if (c==detail::less)
811 {
813 }
814 assert(c==detail::equal);
816 }
817
818 bool is_false(const rewriter& r) const
819 {
820 return lhs().empty() &&
823 }
824
825 bool is_true(const rewriter& r) const
826 {
827 return lhs().empty() &&
830 }
831
832 /// \brief Return this inequality as a typical pair of terms of the form <x1+c2 x2+...+cn xn, d> where c2,...,cn, d are real constants.
833 /// \return The return value indicates whether the left and right hand side have been negated
834 /// when yielding the typical pair.
836 data_expression& lhs_expression,
837 data_expression& rhs_expression,
838 detail::comparison_t& comparison_operator,
839 const rewriter& r) const
840 {
841 if (lhs_begin()==lhs_end())
842 {
843 lhs_expression=real_zero();
844 rhs_expression=rhs();
845 comparison_operator=comparison();
846 return false;
847 }
848
849 data_expression factor=lhs_begin()->factor();
850
851 for (detail::lhs_t::const_iterator i=lhs_begin(); i!=lhs_end(); ++i)
852 {
853 variable v=i->variable_name();
854 data_expression e=real_times(rewrite_with_memory(real_divides(i->factor(),factor),r),
855 data_expression(v));
856 if (i==lhs_begin())
857 {
858 lhs_expression=e;
859 }
860 else
861 {
862 lhs_expression=real_plus(lhs_expression,e);
863 }
864 }
865
867 if (is_negative(factor,r))
868 {
869 comparison_operator=negate(comparison());
870 return true;
871 }
872 else
873 {
874 comparison_operator=comparison();
875 return false;
876 }
877 }
878
880 {
881 const detail::lhs_t new_lhs(lhs().begin(),
882 lhs().end(),
887
890 {
891 return linear_inequality(new_lhs,new_rhs,detail::less_eq);
892 }
894 {
895 return linear_inequality(new_lhs,new_rhs,detail::less);
896 }
897 return linear_inequality(new_lhs,new_rhs,detail::equal);
898 }
899
900 void add_variables(std::set < variable >& variable_set) const
901 {
902 for (const detail::variable_with_a_rational_factor& i : lhs())
903 {
904 variable_set.insert(i.variable_name());
905 }
906 }
907};
908
910{
911 return pp(l.lhs()) + " " + detail::pp(l.comparison()) + " " + pp(l.rhs());
912}
913
914/// \brief Subtract the given equality, multiplied by f1/f2. The result is e1-(f1/f2)e2,
915// where the comparison operator of e1 is kept.
917 const linear_inequality& e2,
918 const data_expression& f1,
919 const data_expression& f2,
920 const rewriter& r)
921{
923 return linear_inequality(
924 detail::meta_operation_lhs(e1.lhs(),e2.lhs(),
925 [&](const data_expression& d1, const data_expression& d2)->data_expression
926 { return real_minus(d1,real_times(f,d2)); },r),
927 rewrite_with_memory(real_minus(e1.rhs(),real_times(f,e2.rhs())),r),
928 e1.comparison(),
929 r);
930}
931
932// Real zero and real one are an ad hoc solution. They should be provided by
933// the data type library.
934
936{
937 static data_expression real_zero=sort_real::real_("0");
938 return real_zero;
939}
940
942{
943 static data_expression real_one=sort_real::real_("1");
944 return real_one;
945}
946
948{
949 static data_expression real_minus_one=sort_real::real_("-1");
950 return real_minus_one;
951}
952
953inline data_expression min(const data_expression& e1,const data_expression& e2,const rewriter& r)
954{
956 {
957 return e1;
958 }
960 {
961 return e2;
962 }
963 throw mcrl2::runtime_error("Fail to determine the minimum of: " + pp(e1) + " and " + pp(e2) + "\n");
964}
965
966inline data_expression max(const data_expression& e1,const data_expression& e2,const rewriter& r)
967{
969 {
970 return e1;
971 }
973 {
974 return e2;
975 }
976 throw mcrl2::runtime_error("Fail to determine the maximum of: " + pp(e1) + " and " + pp(e2) + "\n");
977}
978
980{
982 {
983 return false;
984 }
985
986 std::set < variable > s=find_all_variables(e);
987 return s.empty();
988}
989
990inline bool is_negative(const data_expression& e,const rewriter& r)
991{
993 if (result==sort_bool::true_())
994 {
995 return true;
996 }
997 if (result==sort_bool::false_())
998 {
999 return false;
1000 }
1001 throw mcrl2::runtime_error("Cannot determine that " + pp(e) + " is smaller than 0");
1002}
1003
1004inline bool is_positive(const data_expression& e,const rewriter& r)
1005{
1007 if (result==sort_bool::true_())
1008 {
1009 return true;
1010 }
1011 if (result==sort_bool::false_())
1012 {
1013 return false;
1014 }
1015 throw mcrl2::runtime_error("Cannot determine that " + pp(e) + " is larger than or equal to 0");
1016}
1017
1018inline bool is_zero(const data_expression& e)
1019{
1020 // Assume data_expression is in normal form.
1021 assert(is_closed_real_number(e));
1022 return (e==real_zero());
1023}
1024
1025/// \brief Print the vector of inequalities to stderr in readable form.
1026template <class TYPE>
1028{
1029 std::string s="[";
1030 bool first=true;
1031 for (const linear_inequality& l: inequalities)
1032 {
1033 s=s+ (first?"":", ") + pp(l);
1034 first=false;
1035 }
1036 s=s+ "]";
1037 return s;
1038}
1039
1040bool is_inconsistent(const std::vector<linear_inequality>& inequalities_in, const rewriter& r, bool use_cache = true);
1041
1042// Count the occurrences of variables that occur in inequalities.
1043inline
1044void count_occurrences(
1045 const std::vector < linear_inequality >& inequalities,
1046 std::map < variable, std::size_t>& nr_positive_occurrences,
1047 std::map < variable, std::size_t>& nr_negative_occurrences,
1048 const rewriter& r)
1049{
1050 for (const auto & inequalitie : inequalities)
1051 {
1052 for (detail::lhs_t::const_iterator j=inequalitie.lhs_begin(); j!=inequalitie.lhs_end(); ++j)
1053 {
1054 if (is_positive(j->factor(),r))
1055 {
1056 nr_positive_occurrences[j->variable_name()]=nr_positive_occurrences[j->variable_name()]+1;
1057 }
1058 else
1059 {
1060 nr_negative_occurrences[j->variable_name()]=nr_negative_occurrences[j->variable_name()]+1;
1061 }
1062 }
1063 }
1064}
1065
1066template < class Variable_iterator >
1073 const rewriter& r);
1074
1075
1076
1077/// \brief Indicate whether an inequality from a set of inequalities is redundant.
1078/// \details Return whether the inequality referred to by i is inconsistent.
1079/// It is expected that i refers to an equality in the vector inequalities.
1080/// The vector inequalities might be changed within the procedure, but
1081/// will be restored to its original value when this function terminates.
1082/// \param inequalities A list of inequalities
1083/// \param i An iterator pointing into \a inequalities.
1084/// \param r A rewriter
1085/// \return An indication whether the inequality referred to by i is inconsistent
1086/// in the context of inequalities.
1087inline bool is_a_redundant_inequality(
1088 const std::vector < linear_inequality >& inequalities,
1089 const std::vector<linear_inequality>::iterator i,
1090 const rewriter& r)
1091{
1092#ifndef NDEBUG
1093 // Check that i points to some position in inequalities.
1094 bool found=false;
1095 for (std::vector < linear_inequality >:: const_iterator j=inequalities.begin() ;
1096 j!=inequalities.end() ; ++j)
1097 {
1098 if (j==i)
1099 {
1100 found=true;
1101 break;
1102 }
1103 }
1104 assert(found);
1105#endif
1106 // Check whether the inequalities, with the i-th equality with a reversed comparison operator is inconsistent.
1107 // If yes, the i-th inequality is redundant.
1108 if (i->comparison()==detail::equal)
1109 {
1110 // An inequality t==u is only redundant for equalities if
1111 // t<u and t>u are both inconsistent
1112 const linear_inequality old_inequality=*i;
1113 *i=linear_inequality(i->lhs(),i->rhs(),detail::less);
1114 if (is_inconsistent(inequalities,r))
1115 {
1116 *i=i->invert(r);
1117 if (is_inconsistent(inequalities,r))
1118 {
1119 *i=old_inequality;
1120 return true;
1121 }
1122 }
1123 *i=old_inequality;
1124 return false;
1125 }
1126 else
1127 {
1128 // an inequality t<u, t<=u, t>u and t>=u is redundant in equalities
1129 // if its inversion is inconsistent.
1130 const linear_inequality old_inequality=*i;
1131 *i=i->invert(r);
1132 if (is_inconsistent(inequalities,r))
1133 {
1134 *i=old_inequality;
1135 return true;
1136 }
1137 else
1138 {
1139 *i=old_inequality;
1140 return false;
1141 }
1142 }
1143}
1144
1145/// \brief Remove every redundant inequality from a vector of inequalities.
1146/// \details If inequalities is inconsistent, [false] is returned. Otherwise
1147/// a list of inequalities is returned, from which no inequality can
1148/// be removed without changing the vector of solutions of the inequalities.
1149/// Redundancy of equalities is not checked, because this is quite expensive.
1150/// \param inequalities A list of inequalities
1151/// \param resulting_inequalities A list of inequalities to which the result is stored.
1152// Initially this list must be empty.
1153/// \param r A rewriter
1154
1156 const std::vector < linear_inequality >& inequalities,
1157 std::vector < linear_inequality >& resulting_inequalities,
1158 const rewriter& r)
1159{
1160 assert(resulting_inequalities.empty());
1161 if (inequalities.empty())
1162 {
1163 return;
1164 }
1165
1166 // If false is among the inequalities, [false] is the minimal result.
1167 if (is_inconsistent(inequalities,r))
1168 {
1169 resulting_inequalities.emplace_back();
1170 return;
1171 }
1172
1173 resulting_inequalities=inequalities;
1174 for (std::size_t i=0; i<resulting_inequalities.size();)
1175 {
1176 // Check whether the inequalities, with the i-th equality with a reversed comparison operator is inconsistent.
1177 // If yes, the i-th inequality is redundant.
1178 if (resulting_inequalities[i].comparison()==detail::equal)
1179 {
1180 // Do nothing, as removing redundant inequalities is expensive.
1181 ++i;
1182 }
1183 else
1184 {
1185 if (is_a_redundant_inequality(resulting_inequalities,
1186 resulting_inequalities.begin()+static_cast<std::ptrdiff_t>(i),
1187 r))
1188 {
1189 /* The code below does not preserve the ordering in inequalities.
1190 if (i+1<resulting_inequalities.size())
1191 {
1192 // Copy the last element to the current position.
1193 resulting_inequalities[i].swap(resulting_inequalities.back());
1194 }
1195 resulting_inequalities.pop_back(); */
1196 resulting_inequalities.erase(resulting_inequalities.begin()+static_cast<std::ptrdiff_t>(i));
1197 }
1198 else
1199 {
1200 ++i;
1201 }
1202 }
1203 }
1204}
1205
1206//---------------------------------------------------------------------------------------------------
1207
1208static void pivot_and_update(
1209 const variable& xi, // a basic variable
1210 const variable& xj, // a non basic variable
1211 const data_expression& v,
1212 const data_expression& v_delta_correction,
1213 std::map < variable,data_expression >& beta,
1214 std::map < variable,data_expression >& beta_delta_correction,
1215 std::set < variable >& basic_variables,
1216 std::map < variable, detail::lhs_t >& working_equalities,
1217 const rewriter& r)
1218{
1219 mCRL2log(log::trace) << "Pivoting " << pp(xi) << " " << pp(xj) << "\n";
1220 const data_expression aij=working_equalities[xi][xj];
1221 const data_expression theta=rewrite_with_memory(real_divides(real_minus(v,beta[xi]),aij),r);
1222 const data_expression theta_delta_correction=rewrite_with_memory(real_divides(real_minus(v,beta_delta_correction[xi]),aij),r);
1223 beta[xi]=v;
1224 beta_delta_correction[xi]=v_delta_correction;
1225 beta[xj]=rewrite_with_memory(real_plus(beta[xj],theta),r);
1226 beta_delta_correction[xj]=rewrite_with_memory(real_plus(beta_delta_correction[xj],theta_delta_correction),r);
1227
1228 mCRL2log(log::trace) << "Pivoting phase 0\n";
1229 for (const variable& basic_variable: basic_variables)
1230 {
1231 mCRL2log(log::trace) << "Working equalities " << basic_variable << ": " << pp(working_equalities[basic_variable]) << "\n";
1232 if ((basic_variable!=xi) && (working_equalities[basic_variable].count(xj)>0))
1233 {
1234 const data_expression akj=working_equalities[basic_variable][xj];
1235 beta[basic_variable]=rewrite_with_memory(real_plus(beta[basic_variable],real_times(akj ,theta)),r);
1236 beta_delta_correction[basic_variable]=rewrite_with_memory(real_plus(beta_delta_correction[basic_variable],real_times(akj ,theta_delta_correction)),r);
1237 }
1238 }
1239 // Apply pivoting on variables xi and xj;
1240 mCRL2log(log::trace) << "Pivoting phase 1\n";
1241 basic_variables.erase(xi);
1242 basic_variables.insert(xj);
1243
1244 detail::lhs_t expression_for_xj=working_equalities[xi];
1245 expression_for_xj=expression_for_xj.erase(xj);
1246 expression_for_xj=set_factor_for_a_variable(expression_for_xj,xi,real_minus_one());
1247 expression_for_xj=multiply(expression_for_xj,real_divides(real_minus_one(),aij),r);
1248 mCRL2log(log::trace) << "Expression for xj:" << pp(expression_for_xj) << "\n";
1249 mCRL2log(log::trace) << "Pivoting phase 2\n";
1250 working_equalities.erase(xi);
1251
1252 for (auto & working_equalitie : working_equalities)
1253 {
1254 if (working_equalitie.second.count(xj)>0)
1255 {
1256 const data_expression factor=working_equalitie.second[xj];
1257 mCRL2log(log::trace) << "VAR: " << pp(working_equalitie.first) << " Factor " << pp(factor) << "\n";
1258 working_equalitie.second=working_equalitie.second.erase(xj);
1259 // We need a temporary copy of expression_for_xj as otherwise the multiply
1260 // below will change this expression.
1261 //detail::lhs_t temporary_expression_for_xj(expression_for_xj);
1262 working_equalitie.second=add(working_equalitie.second,multiply(expression_for_xj,factor,r),r);
1263 }
1264 }
1265
1266 working_equalities[xj]=expression_for_xj;
1267
1268 mCRL2log(log::trace) << "Pivoting phase 3\n";
1269 // Calculate the values for beta and beta_delta_correction for the basic variables
1270 for (std::map < variable, detail::lhs_t >::const_iterator i=working_equalities.begin();
1271 i!=working_equalities.end() ; ++i)
1272 {
1273 beta[i->first]=i->second.evaluate(make_map_substitution(beta),r);
1274 beta_delta_correction[i->first]=i->second.evaluate(make_map_substitution(beta_delta_correction),r);
1275 }
1276
1277 mCRL2log(log::trace) << "End pivoting " << pp(xj) << "\n";
1278 if (mCRL2logEnabled(log::trace))
1279 {
1280 for (std::map < variable,data_expression >::const_iterator i=beta.begin();
1281 i!=beta.end(); ++i)
1282 {
1283 mCRL2log(log::trace) << "(1) beta[" << pp(i->first) << "]= " << pp(beta[i->first]) << "+ delta* " << pp(beta_delta_correction[i->first]) << "\n";
1284 }
1285 for (std::map < variable, detail::lhs_t >::const_iterator i=working_equalities.begin();
1286 i!=working_equalities.end() ; ++i)
1287 {
1288 mCRL2log(log::trace) << "EQ: " << pp(i->first) << " := " << pp(i->second) << "\n";
1289 }
1290 }
1291}
1292
1293namespace detail
1294{
1295 /* False end nodes could be associated with NULL */
1297{
1304
1306 {
1309
1310 protected:
1315
1316 public:
1317
1320
1323 {}
1324
1326 const node_type node,
1327 const linear_inequality& inequality,
1328 std::unique_ptr<inequality_inconsistency_cache_base> present_branch,
1329 std::unique_ptr<inequality_inconsistency_cache_base> non_present_branch)
1330 : m_node(node),
1331 m_inequality(inequality),
1334 {}
1335 };
1336
1338 {
1339 protected:
1341
1342 public:
1343
1346
1349 {}
1350
1351 bool is_inconsistent(const std::vector < linear_inequality >& inequalities_in_) const
1352 {
1353 std::set < linear_inequality > inequalities_in(inequalities_in_.begin(),inequalities_in_.end());
1354 const inequality_inconsistency_cache_base* current_root=m_cache.get();
1355 for(const linear_inequality& l: inequalities_in)
1356 {
1357 /* First walk down the three until an endnode is found
1358 that with l<=current_root.m_inequality. */
1359 while (current_root->m_node==intermediate_node && l>current_root->m_inequality)
1360 {
1361 current_root=current_root->m_non_present_branch.get();
1362 }
1363 if (current_root->m_node==intermediate_node)
1364 {
1365 if (l==current_root->m_inequality)
1366 {
1367 current_root=current_root->m_present_branch.get();
1368 }
1369 assert(current_root->m_node!=intermediate_node || l<current_root->m_inequality);
1370 }
1371 else
1372 {
1373 return current_root->m_node==true_end_node;
1374 }
1375 }
1376 return current_root->m_node==true_end_node;
1377 }
1378
1379 void add_inconsistent_inequality_set(const std::vector < linear_inequality >& inequalities_in_)
1380 {
1381 std::set < linear_inequality > inequalities_in(inequalities_in_.begin(),inequalities_in_.end());
1382 std::unique_ptr<inequality_inconsistency_cache_base>* current_root=&m_cache;
1383 for(const linear_inequality& l: inequalities_in)
1384 {
1385 /* First walk down the tree until an endnode is found
1386 that with l<=current_root->m_inequality. */
1387 while ((*current_root)->m_node==intermediate_node && l>(*current_root)->m_inequality)
1388 {
1389 current_root=&((*current_root)->m_non_present_branch);
1390 }
1391 if ((*current_root)->m_node==intermediate_node)
1392 {
1393 if (l==(*current_root)->m_inequality)
1394 {
1395 current_root=&((*current_root)->m_present_branch);
1396 assert((*current_root)->m_node!=intermediate_node || l<(*current_root)->m_inequality);
1397 }
1398 else
1399 {
1400 // Add the node.
1401 *current_root = std::make_unique<inequality_inconsistency_cache_base>(intermediate_node,l,
1402 std::make_unique<inequality_inconsistency_cache_base>(false_end_node),std::move(*current_root));
1403 current_root = &((*current_root)->m_present_branch);
1404 }
1405 }
1406 else
1407 {
1408 if ((*current_root)->m_node==true_end_node)
1409 {
1410 // A shorter sequence than the linear inequality set is already inconsistent.
1411 // This should not occur, assuming that the linear inequality sequence is checked
1412 // in in this cache, before being proven inconsistent.
1413 assert(0);
1414 }
1415 else
1416 {
1417 // Add the remaining sequence.
1418 *current_root = std::make_unique<inequality_inconsistency_cache_base>(intermediate_node,l,
1419 std::make_unique<inequality_inconsistency_cache_base>(false_end_node),std::move(*current_root));
1420 current_root = &((*current_root)->m_present_branch);
1421 }
1422 }
1423 }
1424 // At this point the sequence of inequalities has been explored, but the tree has not ended.
1425 // We expect the current node to be a true_end_node. If not, we replace it by one.
1426 if ((*current_root)->m_node!=true_end_node)
1427 {
1428 assert(*current_root!=nullptr);
1429 *current_root=std::make_unique<inequality_inconsistency_cache_base>(true_end_node);
1430 }
1431 }
1432 };
1433
1435 {
1436 protected:
1438
1439 public:
1440
1443
1446 {
1447 }
1448
1449 // Sort the vector inequalities_in if not sorted.
1450 bool is_consistent(const std::vector < linear_inequality >& inequalities_in_) const
1451 {
1452 std::set < linear_inequality > inequalities_in(inequalities_in_.begin(),inequalities_in_.end());
1453 const inequality_inconsistency_cache_base* current_root=m_cache.get();
1454 for(std::set < linear_inequality >::const_iterator i=inequalities_in.begin(); i!=inequalities_in.end(); ++i)
1455 {
1456 while (current_root->m_node==intermediate_node && *i>current_root->m_inequality)
1457 {
1458 current_root=current_root->m_non_present_branch.get();
1459 }
1460 if (current_root->m_node==intermediate_node)
1461 {
1462 if (*i==current_root->m_inequality)
1463 {
1464 current_root=current_root->m_present_branch.get();
1465 }
1466 else
1467 {
1468 return false; // there are more inequalities than available in the tree. We know nothing about it being consistent.
1469 }
1470 assert(current_root->m_node!=intermediate_node || *i<current_root->m_inequality);
1471 }
1472 else
1473 {
1474 return current_root->m_node!=false_end_node && i==inequalities_in.end();
1475 }
1476 }
1477 return true;
1478 }
1479
1480 void add_consistent_inequality_set(const std::vector < linear_inequality >& inequalities_in_)
1481 {
1482 std::set < linear_inequality > inequalities_in(inequalities_in_.begin(),inequalities_in_.end());
1483 std::unique_ptr<inequality_inconsistency_cache_base>* current_root=&m_cache;
1484 for(const linear_inequality& l: inequalities_in)
1485 {
1486 /* First walk down the three until an endnode is found
1487 with l<=current_root->m_inequality. */
1488 while ((*current_root)->m_node==intermediate_node && l>(*current_root)->m_inequality)
1489 {
1490 current_root=&((*current_root)->m_non_present_branch);
1491 }
1492 if ((*current_root)->m_node==intermediate_node)
1493 {
1494 if (l==(*current_root)->m_inequality)
1495 {
1496 current_root=&((*current_root)->m_present_branch);
1497 assert((*current_root)->m_node!=intermediate_node || l<(*current_root)->m_inequality);
1498 }
1499 else
1500 {
1501 // Add the node.
1502 *current_root = std::make_unique<inequality_inconsistency_cache_base>(intermediate_node,l,
1503 std::make_unique<inequality_inconsistency_cache_base>(true_end_node),std::move(*current_root));
1504 current_root = &((*current_root)->m_present_branch);
1505 }
1506 }
1507 else
1508 {
1509 // Add the remaining sequence.
1510 *current_root = std::make_unique<inequality_inconsistency_cache_base>(intermediate_node,l,
1511 std::make_unique<inequality_inconsistency_cache_base>(true_end_node),std::move(*current_root));
1512 current_root = &((*current_root)->m_present_branch);
1513 }
1514 }
1515 }
1516 };
1517
1518}
1519
1520
1521/// \brief Determine whether a list of data expressions is inconsistent.
1522/// \details First it is checked whether false is among the input. If
1523/// not, Fourier-Motzkin is applied to all variables in the
1524/// inequalities. If the empty vector of equalities is the result,
1525/// the input was consistent. Otherwise the resulting vector contains
1526/// an inconsistent inequality.
1527/// The implementation uses a feasible point detection algorithm as described by
1528/// Bruno Dutertre and Leonardo de Moura. Integrating Simplex with DPLL(T).
1529/// CSL Technical Report SRI-CSL-06-01, 2006.
1530/// \param inequalities_in A list of inequalities.
1531/// \param r A rewriter.
1532/// \param use_cache A boolean indicating whether results can be cahced.
1533/// \return true if the system of inequalities can be determined to be
1534/// inconsistent, false otherwise.
1535inline bool is_inconsistent(
1536 const std::vector < linear_inequality >& inequalities_in,
1537 const rewriter& r,
1538 const bool use_cache/*=true*/)
1539{
1540 // Transform the linear inequalities into a vector of equalities and a
1541 // sequence of constraints on variables. All variables, including
1542 // those that will be generated as slack variables will have values indicated
1543 // by beta, which must lie between the lowerbounds and the upperbounds.
1544
1545 // First remove all equalities by Gauss elimination and make a fresh variable
1546 // generator.
1547
1548 mCRL2log(log::trace) << "Starting an inconsistency check on " + pp_vector(inequalities_in) << "\n";
1549
1550 static detail::inequality_inconsistency_cache inconsistency_cache;
1551 static detail::inequality_consistency_cache consistency_cache;
1552
1553 if (use_cache && consistency_cache.is_consistent(inequalities_in))
1554 {
1555 assert(!is_inconsistent(inequalities_in,r,false));
1556 return false;
1557 }
1558 if (use_cache && inconsistency_cache.is_inconsistent(inequalities_in))
1559 {
1560 assert(is_inconsistent(inequalities_in,r,false));
1561 return true;
1562 }
1563 // The required data structures
1564 std::map < variable,data_expression > lowerbounds;
1565 std::map < variable,data_expression > upperbounds;
1566 std::map < variable,data_expression > beta;
1567 std::map < variable,data_expression > lowerbounds_delta_correction;
1568 std::map < variable,data_expression > upperbounds_delta_correction;
1569 std::map < variable,data_expression > beta_delta_correction;
1570 std::set < variable > non_basic_variables;
1571 std::set < variable > basic_variables;
1572 std::map < variable, detail::lhs_t > working_equalities;
1573
1574 set_identifier_generator fresh_variable_name;
1575
1576 for (std::vector < linear_inequality >::const_iterator i=inequalities_in.begin();
1577 i!=inequalities_in.end(); ++i)
1578 {
1579 if (i->is_false(r))
1580 {
1581 mCRL2log(log::trace) << "Inconsistent, because linear inequalities contains an inconsistent inequality\n";
1582 if (use_cache)
1583 {
1584 inconsistency_cache.add_inconsistent_inequality_set(inequalities_in); // Necessary? Only false should be added.
1585 assert(inconsistency_cache.is_inconsistent(inequalities_in));
1586 }
1587 return true;
1588 }
1589 i->add_variables(non_basic_variables);
1590 for (detail::lhs_t::const_iterator j=i->lhs_begin();
1591 j!=i->lhs_end(); ++j)
1592 {
1593 fresh_variable_name.add_identifier(j->variable_name().name());
1594 }
1595 }
1596
1597 std::vector < linear_inequality > inequalities;
1598 std::vector < linear_inequality > equalities;
1599 non_basic_variables=
1600 gauss_elimination(inequalities_in,
1601 equalities, // Store all resulting equalities here.
1602 inequalities, // Store all resulting non equalities here.
1603 non_basic_variables.begin(),
1604 non_basic_variables.end(),
1605 r);
1606
1607 assert(equalities.size()==0); // There are no resulting equalities left.
1608 non_basic_variables.clear(); // gauss_elimination has removed certain variables. So, we reconstruct the non
1609 // basic variables again below.
1610
1611 mCRL2log(log::trace) << "Resulting equalities " << pp_vector(equalities) << "\n";
1612 mCRL2log(log::trace) << "Resulting inequalities " << pp_vector(inequalities) << "\n";
1613
1614 // Now bring the linear equalities in the basic form described
1615 // in the article by Bruno Dutertre and Leonardo de Moura.
1616
1617 // First set lower and upperbounds, and introduce slack variables
1618 // if required.
1619 for (linear_inequality& inequality: inequalities)
1620 {
1621 mCRL2log(log::trace) << "Investigate inequality: " << ":=" << pp(inequality) << " || " << pp(inequality.lhs()) << "\n";
1622 if (inequality.is_false(r))
1623 {
1624 mCRL2log(log::trace) << "Inconsistent, because linear inequalities contains an inconsistent inequality after Gauss elimination\n";
1625 if (use_cache)
1626 {
1627 inconsistency_cache.add_inconsistent_inequality_set(inequalities_in); // Necessary? Only false should be added.
1628 assert(inconsistency_cache.is_inconsistent(inequalities_in));
1629 }
1630 return true;
1631 }
1632 if (!inequality.is_true(r)) // This inequality is redundant and can be skipped.
1633 {
1634 assert(inequality.comparison()!=detail::equal);
1635 assert(inequality.lhs().size()>0); // this signals a redundant or an inconsistent inequality.
1636 inequality.add_variables(non_basic_variables);
1637
1638 if (inequality.lhs().size()==1) // the left hand side consists of a single variable.
1639 {
1640 variable v=inequality.lhs_begin()->variable_name();
1641 data_expression factor=inequality.lhs_begin()->factor();
1642 assert(factor!=real_zero());
1643 data_expression bound=rewrite_with_memory(real_divides(inequality.rhs(),factor),r);
1644 if (is_positive(factor,r))
1645 {
1646 // The inequality has the shape factor*v<=c or factor*v<c with factor positive
1647 if ((upperbounds.count(v)==0) ||
1648 (rewrite_with_memory(less(bound,upperbounds[v]),r)==sort_bool::true_()))
1649 {
1650 upperbounds[v]=bound;
1651 upperbounds_delta_correction[v]=
1652 ((inequality.comparison()==detail::less)?real_minus_one():real_zero());
1653
1654 }
1655 else
1656 {
1657 if (bound==upperbounds[v])
1658 {
1659 upperbounds_delta_correction[v]=
1660 min(upperbounds_delta_correction[v],
1661 ((inequality.comparison()==detail::less)?real_minus_one():real_zero()),r);
1662 }
1663 }
1664 }
1665 else
1666 {
1667 // The inequality has the shape factor*v<=c or factor*v<c with factor negative
1668 if ((lowerbounds.count(v)==0) ||
1669 (rewrite_with_memory(less(lowerbounds[v],bound),r)==sort_bool::true_()))
1670 {
1671 lowerbounds[v]=bound;
1672 lowerbounds_delta_correction[v]=
1673 ((inequality.comparison()==detail::less)?real_one():real_zero());
1674 }
1675 else
1676 {
1677 if (bound==lowerbounds[v])
1678 {
1679 lowerbounds_delta_correction[v]=
1680 max(lowerbounds_delta_correction[v],
1681 ((inequality.comparison()==detail::less)?real_one():real_zero()),r);
1682 }
1683 }
1684 }
1685 }
1686 else
1687 {
1688 // The inequality has more than one variable at the left hand side.
1689 // We transform it into an equation with a new slack variable.
1690 variable new_basic_variable(fresh_variable_name("slack_var"), sort_real::real_());
1691 basic_variables.insert(new_basic_variable);
1692 upperbounds[new_basic_variable]=inequality.rhs();
1693 upperbounds_delta_correction[new_basic_variable]=
1694 ((inequality.comparison()==detail::less)?real_minus_one():real_zero());
1695 working_equalities[new_basic_variable]=inequality.lhs();
1696 mCRL2log(log::trace) << "New slack variable: " << pp(new_basic_variable) << ":=" << pp(inequality) << " " << pp(inequality.lhs()) << "\n";
1697 }
1698 }
1699 }
1700 // Now set the values for beta:
1701 // The beta values for the non basic variables must satisfy the lower and
1702 // upperbounds.
1703 for (const auto & non_basic_variable : non_basic_variables)
1704 {
1705 if (lowerbounds.count(non_basic_variable)>0)
1706 {
1707 if ((upperbounds.count(non_basic_variable)>0) &&
1708 ((rewrite_with_memory(less(upperbounds[non_basic_variable],lowerbounds[non_basic_variable]),r)==sort_bool::true_()) ||
1709 ((upperbounds[non_basic_variable]==lowerbounds[non_basic_variable]) &&
1710 (rewrite_with_memory(less(upperbounds_delta_correction[non_basic_variable],lowerbounds_delta_correction[non_basic_variable]),r)==sort_bool::true_()))))
1711 {
1712 mCRL2log(log::trace) << "Inconsistent, preprocessing " << pp(non_basic_variable) << "\n";
1713 if (use_cache)
1714 {
1715 inconsistency_cache.add_inconsistent_inequality_set(inequalities_in);
1716 assert(inconsistency_cache.is_inconsistent(inequalities_in));
1717 }
1718 return true; // Inconsistent.
1719 }
1720 beta[non_basic_variable]=lowerbounds[non_basic_variable];
1721 beta_delta_correction[non_basic_variable]=lowerbounds_delta_correction[non_basic_variable];
1722 }
1723 else if (upperbounds.count(non_basic_variable)>0)
1724 {
1725 beta[non_basic_variable]=upperbounds[non_basic_variable];
1726 beta_delta_correction[non_basic_variable]=upperbounds_delta_correction[non_basic_variable];
1727 }
1728 else // *i has neither a lower or an upperbound
1729 {
1730 beta[non_basic_variable]=real_zero();
1731 beta_delta_correction[non_basic_variable]=real_zero();
1732 }
1733 mCRL2log(log::trace) << "(2) beta[" << pp(non_basic_variable) << "]=" << pp(beta[non_basic_variable])<< "+delta*" << pp(beta_delta_correction[non_basic_variable]) <<"\n";
1734 }
1735
1736 // Subsequently set the values for the basic variables
1737 for (const auto & basic_variable : basic_variables)
1738 {
1739 beta[basic_variable]=working_equalities[basic_variable].evaluate(make_map_substitution(beta),r);
1740 beta_delta_correction[basic_variable]=working_equalities[basic_variable].
1741 evaluate(make_map_substitution(beta_delta_correction),r);
1742 mCRL2log(log::trace) << "(3) beta[" << pp(basic_variable) << "]=" << pp(beta[basic_variable])<< "+delta*" << pp(beta_delta_correction[basic_variable]) <<"\n";
1743 }
1744
1745 // Now the basic data structure has been set up.
1746 // We must find the first basic variable that does not satisfy its
1747 // upper and bounds. This is essentially the check algorithm in the
1748 // article by Bruno Dutertre and Leonardo de Moura.
1749
1750 for (; true ;)
1751 {
1752 // select the smallest basic variable that does not satisfy the bounds.
1753 bool found=false;
1754 bool lowerbound_violation = false;
1755 variable xi;
1756 for (const auto & basic_variable : basic_variables)
1757 {
1758 mCRL2log(log::trace) << "Evaluate start\n";
1759 assert(!found);
1760 data_expression value=beta[basic_variable]; // working_equalities[*i].evaluate(beta,r);
1761 data_expression value_delta_correction=beta_delta_correction[basic_variable]; // working_equalities[*i].evaluate(beta_delta_correction,r);
1762 mCRL2log(log::trace) << "Evaluate end\n";
1763 if ((upperbounds.count(basic_variable)>0) &&
1764 ((rewrite_with_memory(less(upperbounds[basic_variable],value),r)==sort_bool::true_()) ||
1765 ((upperbounds[basic_variable]==value) &&
1766 (rewrite_with_memory(less(upperbounds_delta_correction[basic_variable],value_delta_correction),r)==sort_bool::true_()))))
1767 {
1768 // The value of variable *i does not satisfy its upperbound. This must
1769 // be corrected using pivoting.
1770 mCRL2log(log::trace) << "Upperbound violation " << pp(basic_variable) << " bound: " << pp(upperbounds[basic_variable]) << "\n";
1771 found=true;
1772 xi=basic_variable;
1773 lowerbound_violation=false;
1774 break;
1775 }
1776 else if ((lowerbounds.count(basic_variable)>0) &&
1777 ((rewrite_with_memory(less(value,lowerbounds[basic_variable]),r)==sort_bool::true_()) ||
1778 ((lowerbounds[basic_variable]==value) &&
1779 (rewrite_with_memory(less(value_delta_correction,lowerbounds_delta_correction[basic_variable]),r)==sort_bool::true_()))))
1780 {
1781 // The value of variable *i does not satisfy its upperbound. This must
1782 // be corrected using pivoting.
1783 mCRL2log(log::trace) << "Lowerbound violation " << pp(basic_variable) << " bound: " << pp(lowerbounds[basic_variable]) << "\n";
1784 found=true;
1785 xi=basic_variable;
1786 lowerbound_violation=true;
1787 break;
1788 }
1789 }
1790 if (!found)
1791 {
1792 // The inequalities are consistent. Return false.
1793 mCRL2log(log::trace) << "Consistent while pivoting\n";
1794 if (use_cache)
1795 {
1796 consistency_cache.add_consistent_inequality_set(inequalities_in);
1797 assert(consistency_cache.is_consistent(inequalities_in));
1798 }
1799 return false;
1800 }
1801
1802 mCRL2log(log::trace) << "The smallest basic variable that does not satisfy the bounds is " << pp(xi) << "\n";
1803 if (lowerbound_violation)
1804 {
1805 mCRL2log(log::trace) << "Lowerbound violation \n";
1806 // select the smallest non-basic variable with which pivoting can take place.
1807 bool found=false;
1808 const detail::lhs_t& lhs=working_equalities[xi];
1809 for (const detail::variable_with_a_rational_factor& lh : lhs)
1810 {
1811 const variable xj = lh.variable_name();
1812 mCRL2log(log::trace) << pp(xj) << " -- " << pp(lh.factor()) << "\n";
1813 if ((is_positive(lh.factor(), r)
1814 && ((upperbounds.count(xj) == 0)
1815 || ((rewrite_with_memory(less(beta[xj], upperbounds[xj]), r) == sort_bool::true_())
1816 || ((beta[xj] == upperbounds[xj])
1817 && (rewrite_with_memory(less(beta_delta_correction[xj], upperbounds_delta_correction[xj]),
1818 r)
1819 == sort_bool::true_())))))
1820 || (is_negative(lh.factor(), r)
1821 && ((lowerbounds.count(xj) == 0)
1822 || ((rewrite_with_memory(greater(beta[xj], lowerbounds[xj]), r) == sort_bool::true_())
1823 || ((beta[xj] == lowerbounds[xj])
1824 && (rewrite_with_memory(
1825 greater(beta_delta_correction[xj], lowerbounds_delta_correction[xj]),
1826 r)
1827 == sort_bool::true_()))))))
1828 {
1829 found=true;
1830 pivot_and_update(xi,xj,lowerbounds[xi],lowerbounds_delta_correction[xi],
1831 beta, beta_delta_correction,
1832 basic_variables,working_equalities,r);
1833 break;
1834 }
1835 }
1836 if (!found)
1837 {
1838 // The inequalities are inconsistent.
1839 mCRL2log(log::trace) << "Inconsistent while pivoting\n";
1840 if (use_cache)
1841 {
1842 inconsistency_cache.add_inconsistent_inequality_set(inequalities_in);
1843 assert(inconsistency_cache.is_inconsistent(inequalities_in));
1844 }
1845 return true;
1846 }
1847
1848 }
1849 else // Upperbound violation.
1850 {
1851 mCRL2log(log::trace) << "Upperbound violation \n";
1852 // select the smallest non-basic variable with which pivoting can take place.
1853 bool found=false;
1854 for (detail::lhs_t::const_iterator xj_it=working_equalities[xi].begin();
1855 xj_it!=working_equalities[xi].end(); ++xj_it)
1856 {
1857 const variable xj=xj_it->variable_name();
1858 mCRL2log(log::trace) << pp(xj) << " -- " << pp(xj_it->factor()) << " POS " << is_positive(xj_it->factor(),r) << "\n";
1859 if ((is_negative(xj_it->factor(),r) &&
1860 ((upperbounds.count(xj)==0) ||
1861 ((rewrite_with_memory(less(beta[xj],upperbounds[xj]),r)==sort_bool::true_()) ||
1862 ((beta[xj]==upperbounds[xj])&& (rewrite_with_memory(less(beta_delta_correction[xj],upperbounds_delta_correction[xj]),r)==sort_bool::true_()))))) ||
1863 (is_positive(xj_it->factor(),r) &&
1864 ((lowerbounds.count(xj)==0) ||
1865 ((rewrite_with_memory(greater(beta[xj],lowerbounds[xj]),r)==sort_bool::true_()) ||
1866 ((beta[xj]==lowerbounds[xj]) && (rewrite_with_memory(greater(beta_delta_correction[xj],lowerbounds_delta_correction[xj]),r)==sort_bool::true_()))))))
1867 {
1868 found=true;
1869 pivot_and_update(xi,xj,upperbounds[xi],upperbounds_delta_correction[xi],
1870 beta,beta_delta_correction,
1871 basic_variables,working_equalities,r);
1872 break;
1873 }
1874 }
1875 if (!found)
1876 {
1877 // The inequalities are inconsistent.
1878 mCRL2log(log::trace) << "Inconsistent while pivoting (1)\n";
1879 if (use_cache)
1880 {
1881 inconsistency_cache.add_inconsistent_inequality_set(inequalities_in);
1882 assert(inconsistency_cache.is_inconsistent(inequalities_in));
1883 }
1884 return true;
1885 }
1886 }
1887 }
1888}
1889
1890//---------------------------------------------------------------------------------------------------
1891
1892
1893/// \brief Try to eliminate variables from a system of inequalities using Gauss elimination.
1894/// \details For all variables yi in y1,...,yn indicated by variables_begin to variables_end, it
1895/// attempted to find and equation among inequalities of the form yi==expression. All
1896/// occurrences of yi in equalities are subsequently replaced by yi. If no equation of
1897/// the form yi can be found, yi is added to the list of variables that is returned by
1898/// this function. If the input contains an inconsistent inequality, resulting_equalities
1899/// becomes empty, resulting_inequalities contains false and the returned list of variables
1900/// is also empty. The resulting equalities and inequalities do not contain linear inequalites
1901/// equivalent to true.
1902/// \param inequalities A list of inequalities over real numbers
1903/// \param resulting_equalities A list with the resulting equalities.
1904/// \param resulting_inequalities A list of the resulting inequalities
1905/// \param variables_begin An iterator indicating the beginning of the eliminatable variables.
1906/// \param variables_end An iterator indicating the end of the eliminatable variables.
1907/// \param r A rewriter.
1908/// \post variables contains the list of variables that have not been eliminated
1909/// \return The variables that could not be removed by gauss elimination.
1910
1911template < class Variable_iterator >
1918 const rewriter& r)
1919{
1920 std::set < variable > remaining_variables;
1921
1922 // First copy equalities to the resulting_equalities and the inequalites to resulting_inequalities.
1923 for (const linear_inequality& inequality: inequalities)
1924 {
1925 if (inequality.is_false(r))
1926 {
1927 // The input contains false. Return false and stop.
1928 resulting_equalities.clear();
1929 resulting_inequalities.clear();
1930 resulting_inequalities.emplace_back();
1931 return remaining_variables;
1932 }
1933 else if (!inequality.is_true(r)) // Do not consider redundant equations.
1934 {
1935 if (inequality.comparison()==detail::equal)
1936 {
1937 resulting_equalities.push_back(inequality);
1938 }
1939 else
1940 {
1941 resulting_inequalities.push_back(inequality);
1942 }
1943 }
1944 }
1945
1946 // Now find out whether there are variables that occur in an equality, so
1947 // that we can perform gauss elimination.
1948 for (Variable_iterator i = variables_begin; i != variables_end; ++i)
1949 {
1950 std::size_t j;
1951 for (j=0; j<resulting_equalities.size(); ++j)
1952 {
1953 bool check_equalities_for_redundant_inequalities(false);
1954 std::set < variable > vars;
1955 resulting_equalities[j].add_variables(vars);
1956 if (vars.count(*i)>0)
1957 {
1958 // Equality *j contains data variable *i.
1959 // Perform gauss elimination, and break the loop.
1960
1961 for (std::size_t k = 0; k < resulting_inequalities.size();)
1962 {
1963 resulting_inequalities[k]=subtract(resulting_inequalities[k],
1964 resulting_equalities[j],
1965 resulting_inequalities[k].get_factor_for_a_variable(*i),
1966 resulting_equalities[j].get_factor_for_a_variable(*i),
1967 r);
1968 if (resulting_inequalities[k].is_false(r))
1969 {
1970 // The input is inconsistent. Return false.
1971 resulting_equalities.clear();
1972 resulting_inequalities.clear();
1973 resulting_inequalities.emplace_back();
1974 remaining_variables.clear();
1975 return remaining_variables;
1976 }
1977 else if (resulting_inequalities[k].is_true(r))
1978 {
1979 // Inequality k has become redundant, and can be removed.
1980 if ((k+1)<resulting_inequalities.size())
1981 {
1982 resulting_inequalities[k].swap(resulting_inequalities.back());
1983 }
1984 resulting_inequalities.pop_back();
1985 }
1986 else
1987 {
1988 ++k;
1989 }
1990 }
1991
1992 for (std::size_t k = 0; k<resulting_equalities.size();)
1993 {
1994 if (k==j)
1995 {
1996 ++k;
1997 }
1998 else
1999 {
2000 resulting_equalities[k]=subtract(
2001 resulting_equalities[k],
2002 resulting_equalities[j],
2003 resulting_equalities[k].get_factor_for_a_variable(*i),
2004 resulting_equalities[j].get_factor_for_a_variable(*i),
2005 r);
2006 if (resulting_equalities[k].is_false(r))
2007 {
2008 // The input is inconsistent. Return false.
2009 resulting_equalities.clear();
2010 resulting_inequalities.clear();
2011 resulting_inequalities.emplace_back();
2012 remaining_variables.clear();
2013 return remaining_variables;
2014 }
2015 else if (resulting_equalities[k].is_true(r))
2016 {
2017 // Equality k has become redundant, and can be removed.
2018 if (j+1==resulting_equalities.size())
2019 {
2020 // It is not possible to move move the last element of resulting
2021 // inequalities to position k, because j is at this last position.
2022 // Hence, we must recall to check the resulting_equalities for inequalities
2023 // that are true.
2024 check_equalities_for_redundant_inequalities=true;
2025 }
2026 else
2027 {
2028 if ((k+1)<resulting_equalities.size())
2029 {
2030 resulting_equalities[k].swap(resulting_equalities.back());
2031 }
2032 resulting_equalities.pop_back();
2033 }
2034 }
2035 else
2036 {
2037 ++k;
2038 }
2039 }
2040 }
2041
2042 // Remove equation j.
2043
2044 if (j+1<resulting_equalities.size())
2045 {
2046 resulting_equalities[j].swap(resulting_equalities.back());
2047 }
2048 resulting_equalities.pop_back();
2049
2050 // If there are unremoved resulting equalities, remove them now.
2051 if (check_equalities_for_redundant_inequalities)
2052 {
2053 for (std::size_t k = 0; k<resulting_equalities.size();)
2054 {
2055 if (resulting_equalities[k].is_true(r))
2056 {
2057 // Equality k is redundant, and can be removed.
2058 if ((k+1)<resulting_equalities.size())
2059 {
2060 resulting_equalities[k].swap(resulting_equalities.back());
2061 }
2062 resulting_equalities.pop_back();
2063 }
2064 else
2065 {
2066 ++k;
2067 }
2068 }
2069 }
2070 }
2071 }
2072 remaining_variables.insert(*i);
2073 }
2074
2075 return remaining_variables;
2076}
2077
2078// The introduction of the function rewrite_with_memory using a
2079// hash table here is a temporary trick, to boost
2080// performance, which is slow due to translations necessary from and to
2081// rewrite format.
2082
2084 const data_expression& t,const rewriter& r)
2085{
2086 static std::map < data_expression, data_expression > rewrite_hash_table;
2087 std::map < data_expression, data_expression > :: iterator i=rewrite_hash_table.find(t);
2088 if (i==rewrite_hash_table.end())
2089 {
2090 data_expression t1=r(t);
2091 rewrite_hash_table.insert(std::make_pair(t, t1));
2092 return t1;
2093 }
2094 return i->second;
2095}
2096
2097} // namespace mcrl2::data
2098
2099#endif // MCRL2_DATA_LINEAR_INEQUALITY_H
aterm_string & operator=(const aterm_string &t) noexcept=default
A list of aterm objects.
Definition aterm_list.h:26
A unordered_map class in which aterms can be stored.
An abstraction expression.
Definition abstraction.h:23
const variable_list & variables() const
Definition abstraction.h:60
const data_expression & body() const
Definition abstraction.h:65
const binder_type & binding_operator() const
Definition abstraction.h:55
\brief A sort alias
Definition alias.h:23
alias(const basic_sort &name, const sort_expression &reference)
\brief Constructor Z12.
Definition alias.h:39
\brief Assignment of a data expression to a variable
Definition assignment.h:88
const data_expression & rhs() const
Definition assignment.h:119
const variable & lhs() const
Definition assignment.h:114
\brief A basic sort
Definition basic_sort.h:25
data_expression & operator=(const data_expression &) noexcept=default
data_expression()
\brief Default constructor X3.
data_expression & operator=(data_expression &&) noexcept=default
sort_expression sort() const
Returns the sort of the data expression.
Definition data.cpp:107
data_expression(const data_expression &) noexcept=default
Move semantics.
void add_consistent_inequality_set(const std::vector< linear_inequality > &inequalities_in_)
inequality_consistency_cache & operator=(const inequality_consistency_cache &)=delete
inequality_consistency_cache(const inequality_consistency_cache &)=delete
bool is_consistent(const std::vector< linear_inequality > &inequalities_in_) const
std::unique_ptr< inequality_inconsistency_cache_base > m_cache
inequality_inconsistency_cache_base & operator=(const inequality_inconsistency_cache_base &)=delete
std::unique_ptr< inequality_inconsistency_cache_base > m_present_branch
std::unique_ptr< inequality_inconsistency_cache_base > m_non_present_branch
inequality_inconsistency_cache_base(const node_type node, const linear_inequality &inequality, std::unique_ptr< inequality_inconsistency_cache_base > present_branch, std::unique_ptr< inequality_inconsistency_cache_base > non_present_branch)
inequality_inconsistency_cache_base(const inequality_inconsistency_cache_base &)=delete
bool is_inconsistent(const std::vector< linear_inequality > &inequalities_in_) const
inequality_inconsistency_cache & operator=(const inequality_consistency_cache &)=delete
inequality_inconsistency_cache(const inequality_inconsistency_cache &)=delete
void add_inconsistent_inequality_set(const std::vector< linear_inequality > &inequalities_in_)
std::unique_ptr< inequality_inconsistency_cache_base > m_cache
lhs_t(const aterm &t)
Constructor from an aterm.
const data_expression & operator[](const variable &v) const
Give the factor of variable v.
data_expression transform_to_data_expression() const
lhs_t erase(const variable &v) const
Erase a variable and its factor.
std::size_t count(const variable &v) const
Give the factor of variable v.
lhs_t(const ITERATOR begin, const ITERATOR end, TRANSFORMER f)
Constructor.
data_expression evaluate(const SubstitutionFunction &beta, const rewriter &r) const
Evaluate the variables in this lhs_t according to the subsitution function.
lhs_t::const_iterator find(const variable &v) const
Give an iterator of the factor/variable pair for v, or end() if v does not occur.
lhs_t(const ITERATOR begin, const ITERATOR end)
Constructor.
variable_with_a_rational_factor(const variable &v, const data_expression &f)
\brief A function sort
\brief A function symbol
function_symbol & operator=(function_symbol &&) noexcept=default
function_symbol()
Default constructor.
const detail::lhs_t & lhs() const
linear_inequality invert(const rewriter &r)
bool typical_pair(data_expression &lhs_expression, data_expression &rhs_expression, detail::comparison_t &comparison_operator, const rewriter &r) const
Return this inequality as a typical pair of terms of the form <x1+c2 x2+...+cn xn,...
linear_inequality()
Constructor yielding an inconsistent inequality.
bool is_true(const rewriter &r) const
void add_variables(std::set< variable > &variable_set) const
bool is_false(const rewriter &r) const
linear_inequality(const data_expression &e, const rewriter &r)
Constructor that constructs a linear inequality out of a data expression.
linear_inequality(const data_expression &lhs, const data_expression &rhs, const detail::comparison_t comparison, const rewriter &r, const bool negate=false)
constructor.
data_expression transform_to_data_expression() const
static void parse_and_store_expression(const data_expression &e, detail::map_based_lhs_t &new_lhs, data_expression &new_rhs, const rewriter &r, const bool negate=false, const data_expression &factor=real_one())
linear_inequality(const detail::lhs_t &lhs, const data_expression &r, detail::comparison_t t)
Basic constructor.
detail::lhs_t::const_iterator lhs_begin() const
detail::lhs_t::const_iterator lhs_end() const
linear_inequality(const detail::lhs_t &lhs, const data_expression &rhs, detail::comparison_t comparison, const rewriter &r)
constructor.
const data_expression & rhs() const
data_expression get_factor_for_a_variable(const variable &x)
detail::comparison_t comparison() const
Wrapper clas s for internal storage and substitution updates using operator()
assignment(const variable_type &v, Substitution &sigma, std::multiset< variable_type > &variables_in_rhs, std::set< variable_type > &scratch_set)
Constructor.
assignment & operator=(const expression_type &e)
Actual assignment.
Wrapper that extends any substitution to a substitution maintaining the vars in its rhs.
bool variable_occurs_in_a_rhs(const variable_type &v)
Indicates whether a variable occurs in some rhs of this substitution.
assignment operator[](variable_type const &v)
Assigment operator.
const std::multiset< variable > & variables_in_rhs()
Provides a set of variables that occur in the right hand sides of the assignments.
maintain_variables_in_rhs()=default
Default constructor.
std::multiset< variable_type > m_variables_in_rhs
Rewriter that operates on data expressions.
Definition rewriter.h:84
data_expression operator()(const data_expression &d) const
Rewrites a data expression.
Definition rewriter.h:161
Identifier generator that stores the identifiers of the context in a set. Using the operator()() and ...
\brief A sort expression
sort_expression & operator=(const sort_expression &) noexcept=default
\brief A constructor for a structured sort
function_symbol constructor_function(const sort_expression &s) const
Returns the constructor function for this constructor, assuming it is internally represented with sor...
function_symbol recogniser_function(const sort_expression &s) const
Returns the function corresponding to the recogniser of this constructor, such that it is usable in t...
\brief A data variable
Definition variable.h:25
const core::identifier_string & name() const
Definition variable.h:35
variable & operator=(variable &&) noexcept=default
const sort_expression & sort() const
Definition variable.h:40
\brief A where expression
where_clause(const atermpp::aterm &term)
bool has_time() const
Returns true if time is available.
Algorithm class for elimination of constant parameters.
Definition constelm.h:23
LPS summand containing a deadlock.
data_expression & constraint()
Obtain a reference to the constraint.
LPS summand containing a multi-action.
\brief A stochastic distribution
stochastic_distribution & operator=(stochastic_distribution &&) noexcept=default
stochastic_distribution()
\brief Default constructor X3.
const data::variable_list & variables() const
stochastic_distribution(const data::variable_list &variables, const data::data_expression &distribution)
\brief Constructor Z12.
const data::data_expression & distribution() const
stochastic_process_initializer(const data::data_expression_list &expressions, const stochastic_distribution &distribution)
Constructor.
\brief An action label
const core::identifier_string & name() const
action(const atermpp::aterm &term)
const data::data_expression_list & arguments() const
const action_label & label() const
\brief The allow operator
allow(const atermpp::aterm &term)
const process_expression & operand() const
\brief The at operator
at(const atermpp::aterm &term)
at(const process_expression &operand, const data::data_expression &time_stamp)
\brief Constructor Z14.
const data::data_expression & time_stamp() const
const process_expression & operand() const
\brief The block operator
const process_expression & operand() const
block(const atermpp::aterm &term)
\brief The choice operator
choice(const atermpp::aterm &term)
const process_expression & left() const
choice(const process_expression &left, const process_expression &right)
\brief Constructor Z14.
const process_expression & right() const
\brief The communication operator
comm(const atermpp::aterm &term)
const process_expression & operand() const
\brief The value delta
delta()
\brief Default constructor X3.
\brief The hide operator
hide(const atermpp::aterm &term)
const process_expression & operand() const
\brief The if-then-else operator
const process_expression & else_case() const
const process_expression & then_case() const
if_then_else(const atermpp::aterm &term)
const data::data_expression & condition() const
if_then_else(const data::data_expression &condition, const process_expression &then_case, const process_expression &else_case)
\brief Constructor Z14.
\brief The if-then operator
const process_expression & then_case() const
if_then(const data::data_expression &condition, const process_expression &then_case)
\brief Constructor Z14.
if_then(const atermpp::aterm &term)
const data::data_expression & condition() const
\brief The merge operator
merge(const atermpp::aterm &term)
const process_expression & right() const
const process_expression & left() const
\brief A process expression
process_expression & operator=(const process_expression &) noexcept=default
process_expression(const process_expression &) noexcept=default
Move semantics.
process_expression()
\brief Default constructor X3.
process_expression & operator=(process_expression &&) noexcept=default
\brief A process identifier
process_identifier(const process_identifier &) noexcept=default
Move semantics.
process_identifier & operator=(const process_identifier &) noexcept=default
const core::identifier_string & name() const
process_identifier & operator=(process_identifier &&) noexcept=default
process_instance_assignment(const process_instance_assignment &) noexcept=default
Move semantics.
process_instance_assignment(const process_identifier &identifier, const data::assignment_list &assignments)
\brief Constructor Z14.
const data::assignment_list & assignments() const
process_instance_assignment(const atermpp::aterm &term)
const process_identifier & identifier() const
const data::data_expression_list & actual_parameters() const
const process_identifier & identifier() const
Process specification consisting of a data specification, action labels, a sequence of process equati...
process_expression & init()
Returns the initialization of the process specification.
process::action_label_list & action_labels()
Returns the action label specification.
\brief The rename operator
rename(const atermpp::aterm &term)
const process_expression & operand() const
\brief The sequential composition
const process_expression & right() const
seq(const atermpp::aterm &term)
const process_expression & left() const
seq(const process_expression &left, const process_expression &right)
\brief Constructor Z14.
\brief The distribution operator
const data::variable_list & variables() const
const data::data_expression & distribution() const
const process_expression & operand() const
stochastic_operator(const data::variable_list &variables, const data::data_expression &distribution, const process_expression &operand)
\brief Constructor Z14.
\brief The sum operator
const process_expression & operand() const
sum(const data::variable_list &variables, const process_expression &operand)
\brief Constructor Z14.
sum(const atermpp::aterm &term)
const data::variable_list & variables() const
\brief The synchronization operator
const process_expression & left() const
sync(const process_expression &left, const process_expression &right)
\brief Constructor Z14.
const process_expression & right() const
sync(const atermpp::aterm &term)
\brief The value tau
tau()
\brief Default constructor X3.
process_expression processbody
objectdatatype(const objectdatatype &o)=default
process_expression representedprocess
~objectdatatype()=default
process::action_label_list multi_action_names
processstatustype processstatus
identifier_string objectname
std::set< variable > get_free_variables() const
objectdatatype()=default
objectdatatype & operator=(const objectdatatype &o)=default
objecttype object
process_identifier process_representing_action
variable_list parameters
enumeratedtype(const enumeratedtype &e)
enumeratedtype(const std::size_t n, specification_basic_type &spec)
enumeratedtype & operator=(const enumeratedtype &e)=default
enumtype(const enumtype &)=delete
enumtype & operator=(const enumtype &)=delete
enumtype(std::size_t n, const sort_expression_list &fsorts, const sort_expression_list &gsorts, specification_basic_type &spec)
process_pid_pair & operator=(const process_pid_pair &other)=default
const process_expression & process_body() const
const process_identifier & process_id() const
process_pid_pair(const process_pid_pair &other)=default
process_pid_pair & operator=(process_pid_pair &&other)=default
process_pid_pair(const process_expression &process_body, const process_identifier &pid)
process_pid_pair(process_pid_pair &&other)=default
static stackoperations * find_suitable_stack_operations(const variable_list &parameters, stackoperations *stack_operations_list)
stacklisttype & operator=(const stacklisttype &)=delete
stacklisttype(const variable_list &parlist, specification_basic_type &spec, const bool regular, const std::set< process_identifier > &pCRLprocs, const bool singlecontrolstate)
Constructor.
stacklisttype(const stacklisttype &)=delete
stackoperations & operator=(const stackoperations &)=delete
stackoperations(const stackoperations &)=delete
stackoperations(const variable_list &pl, specification_basic_type &spec)
process_expression procstorealGNFbody(const process_expression &body, variableposition v, std::vector< process_identifier > &todo, const bool regular, processstatustype mode, const variable_list &freevars, const std::set< variable > &variables_bound_in_sum)
data_expression construct_binary_case_tree(std::size_t n, const variable_list &sums, data_expression_list terms, const sort_expression &termsort, const enumtype &e)
data::maintain_variables_in_rhs< data::mutable_map_substitution<> > make_unique_variables(const variable_list &var_list, const std::string &hint)
variable_list parscollect(const process_expression &oldbody, process_expression &newbody)
stochastic_action_summand collect_sum_arg_arg_cond(const enumtype &e, const stochastic_action_summand_vector &action_summands, const variable_list &parameters)
action_list linMergeMultiActionList(const action_list &ma1, const action_list &ma2)
void generateLPEpCRL(stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands, const process_identifier &procId, const bool containstime, const bool regular, variable_list &parameters, data_expression_list &init, stochastic_distribution &initial_stochastic_distribution)
variable get_fresh_variable(const std::string &s, const sort_expression &sort, const int reuse_index=-1)
process_expression distributeActionOverConditions(const process_expression &act, const data_expression &condition, const process_expression &restterm, const variable_list &freevars, const std::set< variable > &variables_bound_in_sum)
data_expression construct_binary_case_tree_rec(std::size_t n, const variable_list &sums, data_expression_list &terms, const sort_expression &termsort, const enumtype &e)
static void complete_proc_identifier_map(std::map< process_identifier, process_identifier > &identifier_identifier_map)
process_expression to_regular_form(const process_expression &t, std::vector< process_identifier > &todo, const variable_list &freevars, const std::set< variable > &variables_bound_in_sum)
void collectsumlistterm(const process_identifier &procId, stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands, const process_expression &body, const variable_list &pars, const stacklisttype &stack, const bool regular, const bool singlestate, const std::set< process_identifier > &pCRLprocs)
data_expression_list findarguments(const variable_list &pars, const variable_list &parlist, const assignment_list &args, const data_expression_list &t2, const stacklisttype &stack, const variable_list &vars, const std::set< variable > &free_variables_in_body, const variable_list &stochastic_variables)
void calculate_communication_merge(const stochastic_action_summand_vector &action_summands1, const deadlock_summand_vector &deadlock_summands1, const stochastic_action_summand_vector &action_summands2, const deadlock_summand_vector &deadlock_summands2, const action_name_multiset_list &allowlist, const bool is_allow, const bool is_block, stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands)
void insertvariable(const variable &var, const bool mustbenew)
process_identifier storeinit(const process_expression &init)
static action_list to_sorted_action_list(const process_expression &p)
Convert the process expression to a sorted action list.
process_expression pCRLrewrite(const process_expression &t)
data_expression_list pushdummy_regular_data_expressions(const variable_list &pars, const stacklisttype &stack)
void define_equations_for_case_function(const std::size_t index, const data::function_symbol &functionname, const sort_expression &sort)
void alphaconvert(variable_list &sumvars, MutableSubstitution &sigma, const variable_list &occurvars, const data_expression_list &occurterms)
bool canterminatebody(const process_expression &t)
data_expression transform_matching_list(const variable_list &matchinglist)
void add_summands(const process_identifier &procId, stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands, process_expression summandterm, const std::set< process_identifier > &pCRLprocs, const stacklisttype &stack, const bool regular, const bool singlestate, const variable_list &process_parameters)
bool isDeltaAtZero(const process_expression &t)
data::function_symbol find_case_function(std::size_t index, const sort_expression &sort) const
data_expression_list make_initialstate(const process_identifier &initialProcId, const stacklisttype &stack, const std::set< process_identifier > &pcrlprcs, const bool regular, const bool singlecontrolstate, const stochastic_distribution &initial_stochastic_distribution)
static bool summandsCanBeClustered(const stochastic_action_summand &summand1, const stochastic_action_summand &summand2)
static sort_expression_list getActionSorts(const action_list &actionlist)
void filter_vars_by_multiaction(const action_list &multiaction, const std::set< variable > &vars_set, std::set< variable > &vars_result_set)
static process_identifier get_last(const process_identifier &id, const std::map< process_identifier, process_identifier > &identifier_identifier_map)
static bool check_real_variable_occurrence(const variable_list &sumvars, const data_expression &actiontime, const data_expression &condition)
process_identifier newprocess(const variable_list &parameters, const process_expression &body, const processstatustype ps, const bool canterminate, const bool containstime)
void make_pCRL_procs(const process_identifier &id, std::set< process_identifier > &reachable_process_identifiers)
void filter_vars_by_term(const data_expression &t, const std::set< variable > &vars_set, std::set< variable > &vars_result_set)
data_expression_list pushdummy_stack(const variable_list &parameters, const stacklisttype &stack, const variable_list &stochastic_variables)
void procstorealGNFrec(const process_identifier &procIdDecl, const variableposition v, std::vector< process_identifier > &todo, const bool regular)
static action_label_list getnames(const process_expression &multiAction)
variable_list getparameters_rec(const process_expression &multiAction, std::set< variable > &occurs_set)
static int match_sequence(const std::vector< process_instance_assignment > &s1, const std::vector< process_instance_assignment > &s2, const bool regular2)
assignment_list argscollect_regular2(const process_expression &t, variable_list &vl)
assignment_list make_optimised_assignment_list(const variable_list &parameters, const data_expression_list &resultnextstate, const variable_list &sum_vars, const variable_list &stoch_vars)
void calculate_left_merge_action(const lps::detail::ultimate_delay &ultimate_delay_condition, const stochastic_action_summand_vector &action_summands1, const action_name_multiset_list &allowlist, const bool is_allow, const bool is_block, stochastic_action_summand_vector &action_summands)
process_expression split_body(const process_expression &t, std::map< process_identifier, process_identifier > &visited_id, std::map< process_expression, process_expression > &visited_proc, const variable_list &parameters)
void parallelcomposition(const stochastic_action_summand_vector &action_summands1, const deadlock_summand_vector &deadlock_summands1, const variable_list &pars1, const data_expression_list &init1, const stochastic_distribution &initial_stochastic_distribution1, const lps::detail::ultimate_delay &ultimate_delay_condition1, const stochastic_action_summand_vector &action_summands2, const deadlock_summand_vector &deadlock_summands2, const variable_list &pars2, const data_expression_list &init2, const stochastic_distribution &initial_stochastic_distribution2, const lps::detail::ultimate_delay &ultimate_delay_condition2, const action_name_multiset_list &allowlist1, const bool is_allow, const bool is_block, stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands, variable_list &pars_result, data_expression_list &init_result, stochastic_distribution &initial_stochastic_distribution, lps::detail::ultimate_delay &ultimate_delay_condition)
bool occursintermlist(const variable &var, const assignment_list &r, const process_identifier &proc_name) const
void transform_process_arguments(const process_identifier &procId)
objectdatatype & insert_process_declaration(const process_identifier &procId, const variable_list &parameters, const process_expression &body, processstatustype s, const bool canterminate, const bool containstime)
static void set_proc_identifier_map(std::map< process_identifier, process_identifier > &identifier_identifier_map, const process_identifier &id1_, const process_identifier &id2_, const process_identifier &initial_process)
bool canterminate_rec(const process_identifier &procId, bool &stable, std::set< process_identifier > &visited)
set_identifier_generator fresh_identifier_generator
std::set< process_identifier > remove_stochastic_operators_from_front(const std::set< process_identifier > &reachable_process_identifiers, process_identifier &initial_process_id, stochastic_distribution &initial_stochastic_distribution)
void filter_vars_by_termlist(Iterator begin, const Iterator &end, const std::set< variable > &vars_set, std::set< variable > &vars_result_set)
bool searchProcDeclaration(const variable_list &parameters, const process_expression &body, const processstatustype s, const bool canterminate, const bool containstime, process_identifier &p) const
process_identifier splitmCRLandpCRLprocsAndAddTerminatedAction(const process_identifier &procId)
action_list linMergeMultiActionListProcess(const process_expression &ma1, const process_expression &ma2)
std::vector< process_equation > procs
action_list adapt_multiaction_to_stack(const action_list &multiAction, const stacklisttype &stack, const variable_list &vars)
void determinewhetherprocessescanterminate(const process_identifier &procId)
process_expression distribute_condition(const process_expression &body1, const data_expression &condition)
bool containstime_rec(const process_identifier &procId, bool *stable, std::set< process_identifier > &visited, bool &contains_if_then)
void collectsumlist(stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands, const std::set< process_identifier > &pCRLprocs, const variable_list &pars, const stacklisttype &stack, bool regular, bool singlestate)
data_expression correctstatecond(const process_identifier &procId, const std::set< process_identifier > &pCRLproc, const stacklisttype &stack, int regular)
void calculate_communication_merge_action_summands(const stochastic_action_summand_vector &action_summands1, const stochastic_action_summand_vector &action_summands2, const action_name_multiset_list &allowlist, const bool is_allow, const bool is_block, stochastic_action_summand_vector &action_summands)
processstatustype determine_process_statusterm(const process_expression &body, const processstatustype status)
void calculate_communication_merge_action_deadlock_summands(const stochastic_action_summand_vector &action_summands1, const deadlock_summand_vector &deadlock_summands1, const stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands)
data_expression getvar(const variable &var, const stacklisttype &stack) const
variable_list initdatavars
lps::detail::ultimate_delay combine_ultimate_delays(const lps::detail::ultimate_delay &delay1, const lps::detail::ultimate_delay &delay2)
Returns the conjunction of the two delay conditions and the join of the variables,...
process_expression distributeTime(const process_expression &body, const data_expression &time, const variable_list &freevars, data_expression &timecondition)
data_expression_list pushdummyrec_stack(const variable_list &totalpars, const variable_list &pars, const stacklisttype &stack, const variable_list &stochastic_variables)
static action_list to_action_list(const process_expression &p)
std::set< data::variable > sigma_variables(const Substitution &sigma)
void combine_summand_lists(const stochastic_action_summand_vector &action_summands1, const deadlock_summand_vector &deadlock_summands1, const lps::detail::ultimate_delay &ultimate_delay_condition1, const stochastic_action_summand_vector &action_summands2, const deadlock_summand_vector &deadlock_summands2, const lps::detail::ultimate_delay &ultimate_delay_condition2, const variable_list &par1, const variable_list &par3, const action_name_multiset_list &allowlist1, const bool is_allow, const bool is_block, stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands)
process_expression cut_off_unreachable_tail(const process_expression &t)
std::vector< enumeratedtype > enumeratedtypes
data_expression find_(const variable &s, const assignment_list &args, const stacklisttype &stack, const variable_list &vars, const std::set< variable > &free_variables_in_body, const variable_list &stochastic_variables)
process::action_label_list acts
assignment_list make_procargs_regular(const process_expression &t, const stacklisttype &stack, const std::set< process_identifier > &pcrlprcs, const bool singlestate, const variable_list &stochastic_variables)
std::size_t create_enumeratedtype(const std::size_t n)
void generateLPEmCRL(stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands, const process_identifier &procIdDecl, const bool regular, variable_list &pars, data_expression_list &init, stochastic_distribution &initial_stochastic_distribution, lps::detail::ultimate_delay &ultimate_delay_condition)
process_instance_assignment expand_process_instance_assignment(const process_instance_assignment &t)
static process_expression delta_at_zero()
assignment_list rewrite_assignments(const assignment_list &t)
assignment_list push_regular(const process_identifier &procId, const assignment_list &args, const stacklisttype &stack, const std::set< process_identifier > &pCRLprocs, bool singlestate, const variable_list &stochastic_variables)
void transform_process_arguments(const process_identifier &procId, std::set< process_identifier > &visited_processes)
std::set< process_identifier > minimize_set_of_reachable_process_identifiers(const std::set< process_identifier > &reachable_process_identifiers, const process_identifier &initial_process)
void collectPcrlProcesses(const process_identifier &procDecl, std::vector< process_identifier > &pcrlprocesses, std::set< process_identifier > &visited)
variable_list make_binary_sums(std::size_t n, const sort_expression &enumtypename, data_expression &condition, const variable_list &tail)
variable_list SieveProcDataVarsAssignments(const std::set< variable > &vars, const data_expression_list &initial_state_expressions)
data_expression_list extend_conditions(const variable &var, const data_expression_list &conditionlist)
bool check_valid_process_instance_assignment(const process_identifier &id, const assignment_list &assignments)
void calculate_left_merge_deadlock(const lps::detail::ultimate_delay &ultimate_delay_condition, const deadlock_summand_vector &deadlock_summands1, const bool is_allow, const bool is_block, const stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands)
void addString(const identifier_string &str)
void procstovarheadGNF(const std::vector< process_identifier > &procs)
static process_expression action_list_to_process(const action_list &ma)
process_expression distribute_sum_over_a_stochastic_operator(const variable_list &sumvars, const variable_list &stochastic_variables, const data_expression &distribution, const process_expression &body)
void alphaconvertprocess(variable_list &sumvars, MutableSubstitution &sigma, const process_expression &p)
process_expression obtain_initial_distribution_term(const process_expression &t)
data_expression push_stack(const process_identifier &procId, const assignment_list &args, const data_expression_list &t2, const stacklisttype &stack, const std::set< process_identifier > &pCRLprocs, const variable_list &vars, const variable_list &stochastic_variables)
void calculate_left_merge(const stochastic_action_summand_vector &action_summands1, const deadlock_summand_vector &deadlock_summands1, const lps::detail::ultimate_delay &ultimate_delay_condition2, const action_name_multiset_list &allowlist, const bool is_allow, const bool is_block, stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands)
void declare_control_state(const std::set< process_identifier > &pCRLprocs)
void create_case_function_on_enumeratedtype(const sort_expression &sort, const std::size_t enumeratedtype_index)
variable_list SieveProcDataVarsSummands(const std::set< variable > &vars, const stochastic_action_summand_vector &action_summands, const deadlock_summand_vector &deadlock_summands, const variable_list &parameters)
static data_expression_list extend(const data_expression &c, const data_expression_list &cl)
specification_basic_type & operator=(const specification_basic_type &)=delete
static bool occursinvarandremove(const variable &var, variable_list &vl)
process_expression bodytovarheadGNF(const process_expression &body, const state s, const variable_list &freevars, const variableposition v, const std::set< variable > &variables_bound_in_sum)
process_identifier terminatedProcId
process_expression distribute_sum(const variable_list &sumvars, const process_expression &body1)
data_expression variables_are_equal_to_default_values(const variable_list &vl)
void procstorealGNF(const process_identifier &procsIdDecl, const bool regular)
static bool check_assignment_list(const assignment_list &assignments, const variable_list &parameters)
data_expression RewriteTerm(const data_expression &t)
void alphaconversion(const process_identifier &procId, const variable_list &parameters)
bool all_equal(const atermpp::term_list< T > &l)
void cluster_actions(stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands, const variable_list &pars)
process_expression transform_initial_distribution_term(const process_expression &t, const std::map< process_identifier, process_pid_pair > &processes_with_initial_distribution)
process_expression create_regular_invocation(process_expression sequence, std::vector< process_identifier > &todo, const variable_list &freevars, const std::set< variable > &variables_bound_in_sum)
process_expression transform_process_arguments_body(const process_expression &t, const std::set< variable > &bound_variables, std::set< process_identifier > &visited_processes)
static assignment_list parameters_to_assignment_list(const variable_list &parameters, const std::set< variable > &variables_bound_in_sum)
assignment_list dummyparameterlist(const stacklisttype &stack, const bool singlestate)
mcrl2::data::rewriter rewr
void make_pCRL_procs(const process_expression &t, std::set< process_identifier > &reachable_process_identifiers)
stackoperations * stack_operations_list
process_expression wraptime(const process_expression &body, const data_expression &time, const variable_list &freevars)
objectdatatype & objectIndex(const process_identifier &o)
process_identifier split_process(const process_identifier &procId, std::map< process_identifier, process_identifier > &visited_id, std::map< process_expression, process_expression > &visited_proc)
bool mergeoccursin(variable &var, const variable_list &v, variable_list &matchinglist, variable_list &pars, data_expression_list &args, const variable_list &process_parameters)
static bool occursintermlist(const variable &var, const data_expression_list &r)
bool exists_variable_for_sequence(const std::vector< process_instance_assignment > &process_names, process_identifier &result)
std::set< variable > find_free_variables_process(const process_expression &p)
process_expression alphaconversionterm(const process_expression &t, const variable_list &parameters, maintain_variables_in_rhs< mutable_map_substitution<> > sigma)
process_expression putbehind(const process_expression &body1, const process_expression &body2)
assignment_list substitute_assignmentlist(const assignment_list &assignments, const variable_list &parameters, const bool replacelhs, const bool replacerhs, Substitution &sigma)
process_instance_assignment transform_process_instance_to_process_instance_assignment(const process_instance &procId, const std::set< variable > &bound_variables=std::set< variable >())
process_instance_assignment RewriteProcess(const process_instance_assignment &t)
process_identifier delta_process
const objectdatatype & objectIndex(const process_identifier &o) const
void insert_summand(stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands, const variable_list &sumvars, const data_expression &condition, const action_list &multiAction, const data_expression &actTime, const stochastic_distribution &distribution, const assignment_list &procargs, const bool has_time, const bool is_deadlock_summand)
bool alreadypresent(variable &var, const variable_list &vl, mutable_indexed_substitution<> &parameter_renaming)
variable_list parameters_that_occur_in_body(const variable_list &parameters, const process_expression &body)
process_expression enumerate_distribution_and_sums(const variable_list &sumvars, const variable_list &stochvars, const data_expression &distribution, const process_expression &body)
bool containstimebody(const process_expression &t)
assignment_list make_procargs(const process_expression &t, const stacklisttype &stack, const std::set< process_identifier > &pcrlprcs, const variable_list &vars, const bool regular, const bool singlestate, const variable_list &stochastic_variables)
data_expression adapt_term_to_stack(const data_expression &t, const stacklisttype &stack, const variable_list &vars, const variable_list &stochastic_variables)
data_expression_list processencoding(std::size_t i, const data_expression_list &t1, const stacklisttype &stack)
process_expression RewriteMultAct(const process_expression &t)
void generateLPEmCRLterm(stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands, const process_expression &t, const bool regular, const bool rename_variables, variable_list &pars, data_expression_list &init, stochastic_distribution &initial_stochastic_distribution, lps::detail::ultimate_delay &ultimate_delay_condition)
Linearise a process indicated by procIdDecl.
variable_list make_pars(const sort_expression_list &sortlist)
specification_basic_type(const specification_basic_type &)=delete
static data_expression real_times_optimized(const data_expression &r1, const data_expression &r2)
bool occursinpCRLterm(const variable &var, const process_expression &p, const bool strict)
void collectPcrlProcesses(const process_identifier &procDecl, std::vector< process_identifier > &pcrlprocesses)
static std::size_t upperpowerof2(std::size_t i)
void extract_names(const process_expression &sequence, std::vector< process_instance_assignment > &result)
std::map< aterm, objectdatatype > objectdata
action RewriteAction(const action &t)
data_expression_vector adapt_termlist_to_stack(Iterator begin, const Iterator &end, const stacklisttype &stack, const variable_list &vars, const variable_list &stochastic_variables)
data_expression make_procargs_stack(const process_expression &t, const stacklisttype &stack, const std::set< process_identifier > &pcrlprcs, const variable_list &vars, const variable_list &stochastic_variables)
specification_basic_type(const process::action_label_list &as, const std::vector< process_equation > &ps, const variable_list &idvs, const data_specification &ds, const std::set< data::variable > &glob_vars, const t_lin_options &opt, const process_specification &procspec)
variable_list getparameters(const process_expression &multiAction)
data_expression makesingleultimatedelaycondition(const variable_list &sumvars, const variable_list &freevars, const data_expression &condition, const bool has_time, const variable &timevariable, const data_expression &actiontime, variable_list &used_sumvars)
void collectPcrlProcesses_term(const process_expression &body, std::vector< process_identifier > &pcrlprocesses, std::set< process_identifier > &visited)
data_expression representative_generator_internal(const sort_expression &s, const bool allow_dont_care_var=true)
assignment_list processencoding(std::size_t i, const assignment_list &t1, const stacklisttype &stack)
objectdatatype & addMultiAction(const process_expression &multiAction, bool &isnew)
void storeprocs(const std::vector< process_equation > &procs)
process_expression substitute_pCRLproc(const process_expression &p, Substitution &sigma)
void make_parameters_and_sum_variables_unique(stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands, variable_list &pars, lps::detail::ultimate_delay &ultimate_delay_condition, const std::string &hint="")
std::set< variable > global_variables
static data_expression getRHSassignment(const variable &var, const assignment_list &as)
variable_list construct_renaming(const variable_list &pars1, const variable_list &pars2, variable_list &pars3, variable_list &pars4, const bool unique=true)
void determine_process_status(const process_identifier &procDecl, const processstatustype status)
static action_list makemultiaction(const process::action_label_list &actionIds, const data_expression_list &args)
void insertvariables(const variable_list &vars, const bool mustbenew)
variable_list collectparameterlist(std::set< process_identifier > &pCRLprocs)
data_expression_list RewriteTermList(const data_expression_list &t)
data_specification data
variable_list make_parameters_rec(const data_expression_list &l, std::set< variable > &occurs_set)
void detail_check_objectdata(const process_identifier &o) const
static assignment_list filter_assignments(const assignment_list &assignments, const variable_list &parameters)
variable_list merge_var(const variable_list &v1, const variable_list &v2, std::vector< variable_list > &renamings_pars, std::vector< data_expression_list > &renamings_args, data_expression_list &conditionlist, const variable_list &process_parameters)
bool containstimebody(const process_expression &t, bool *stable, std::set< process_identifier > &visited, bool allowrecursion, bool &contains_if_then)
static assignment_list sort_assignments(const assignment_list &ass, const variable_list &parameters)
assignment_list find_dummy_arguments(const variable_list &parlist, const assignment_list &args, const std::set< variable > &free_variables_in_body, const variable_list &stochastic_variables)
process_identifier tau_process
static sort_expression_list get_sorts(const List &l)
std::vector< process_identifier > seq_varnames
void storeact(const process::action_label_list &acts)
bool is_global_variable(const data_expression &d) const
variable_list joinparameters(const variable_list &par1, const variable_list &par2, mutable_indexed_substitution<> &parameter_renaming)
static bool occursin(const variable &name, const variable_list &pars)
bool canterminatebody(const process_expression &t, bool &stable, std::set< process_identifier > &visited, const bool allowrecursion)
void AddTerminationActionIfNecessary(const stochastic_action_summand_vector &summands)
bool determinewhetherprocessescontaintime(const process_identifier &procId)
void filter_vars_by_assignmentlist(const assignment_list &assignments, const variable_list &parameters, const std::set< variable > &vars_set, std::set< variable > &vars_result_set)
data_expression_list addcondition(const variable_list &matchinglist, const data_expression_list &conditionlist)
void calculate_communication_merge_deadlock_summands(const deadlock_summand_vector &deadlock_summands1, const deadlock_summand_vector &deadlock_summands2, const stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands)
void transform(const process_identifier &init, stochastic_action_summand_vector &action_summands, deadlock_summand_vector &deadlock_summands, variable_list &parameters, data_expression_list &initial_state, stochastic_distribution &initial_stochastic_distribution)
process_expression obtain_initial_distribution(const process_identifier &procId)
objectdatatype & insertAction(const action_label &actionId)
Expression replace_variables_capture_avoiding_alt(const Expression &e, Substitution &sigma)
process_instance_assignment expand_process_instance_assignment(const process_instance_assignment &t, std::set< process_identifier > &visited_processes)
assignment_list pushdummy_regular(const variable_list &pars, const stacklisttype &stack, const variable_list &stochastic_variables)
assignment_list argscollect_regular(const process_expression &t, const variable_list &vl, const std::set< variable > &variables_bound_in_sum)
static data_expression_list getarguments(const action_list &multiAction)
lps::detail::ultimate_delay getUltimateDelayCondition(const stochastic_action_summand_vector &action_summands, const deadlock_summand_vector &deadlock_summands, const variable_list &freevars)
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:392
lhs_t map_to_lhs_type(const map_based_lhs_t &lhs, const data_expression &factor, const rewriter &r)
lhs_t map_to_lhs_type(const map_based_lhs_t &lhs)
std::string pp(const detail::comparison_t t)
lhs_t set_factor_for_a_variable(const lhs_t &lhs, const variable &x, const data_expression &e)
bool is_well_formed(const lhs_t &lhs)
detail::comparison_t negate(const detail::comparison_t t)
lhs_t remove_variable_and_divide(const lhs_t &lhs, const variable &v, const data_expression &f, const rewriter &r)
std::string pp(const detail::lhs_t &lhs)
void set_factor_for_a_variable(detail::map_based_lhs_t &new_lhs, const variable &x, const data_expression &e)
atermpp::function_symbol f_variable_with_a_rational_factor()
A collection of utilities for lazy expression construction.
data_expression and_(data_expression const &p, data_expression const &q)
Returns an expression equivalent to p or q.
Namespace for system defined sort bool_.
Definition bool.h:29
const basic_sort & bool_()
Constructor for sort expression Bool.
Definition bool.h:41
const function_symbol & false_()
Constructor for function symbol false.
Definition bool.h:106
const function_symbol & true_()
Constructor for function symbol true.
Definition bool.h:74
Namespace for system defined sort real_.
function_symbol plus(const sort_expression &s0, const sort_expression &s1)
Definition real1.h:1056
function_symbol times(const sort_expression &s0, const sort_expression &s1)
Definition real1.h:1234
function_symbol divides(const sort_expression &s0, const sort_expression &s1)
Definition real1.h:1404
data_expression & real_one()
bool is_plus_application(const atermpp::aterm &e)
Recogniser for application of +.
Definition real1.h:1133
data_expression & real_zero()
function_symbol minus(const sort_expression &s0, const sort_expression &s1)
Definition real1.h:1149
const basic_sort & real_()
Constructor for sort expression Real.
Definition real1.h:45
application times(const data_expression &arg0, const data_expression &arg1)
Application of function symbol *.
Definition real1.h:1282
function_symbol abs(const sort_expression &s0)
Definition real1.h:732
bool is_times_application(const atermpp::aterm &e)
Recogniser for application of *.
Definition real1.h:1303
function_symbol negate(const sort_expression &s0)
Definition real1.h:807
bool is_negate_application(const atermpp::aterm &e)
Recogniser for application of -.
Definition real1.h:874
bool is_minus_application(const atermpp::aterm &e)
Recogniser for application of -.
Definition real1.h:1218
linear_inequality subtract(const linear_inequality &e1, const linear_inequality &e2, const data_expression &f1, const data_expression &f2, const rewriter &r)
Subtract the given equality, multiplied by f1/f2. The result is e1-(f1/f2)e2,.
application real_times(const data_expression &arg0, const data_expression &arg1)
data_expression & real_one()
bool is_closed_real_number(const data_expression &e)
bool is_application(const data_expression &t)
Returns true if the term t is an application.
application real_plus(const data_expression &arg0, const data_expression &arg1)
data_expression & real_minus_one()
bool is_positive(const data_expression &e, const rewriter &r)
bool is_where_clause(const atermpp::aterm &x)
Returns true if the term t is a where clause.
application less_equal(const data_expression &arg0, const data_expression &arg1)
Application of function symbol <=.
Definition standard.h:291
application real_abs(const data_expression &arg)
application less(const data_expression &arg0, const data_expression &arg1)
Application of function symbol <.
Definition standard.h:254
std::string pp_vector(const TYPE &inequalities)
Print the vector of inequalities to stderr in readable form.
bool is_abstraction(const atermpp::aterm &x)
Returns true if the term t is an abstraction.
application if_(const data_expression &arg0, const data_expression &arg1, const data_expression &arg2)
Application of function symbol if.
Definition standard.h:215
void remove_redundant_inequalities(const std::vector< linear_inequality > &inequalities, std::vector< linear_inequality > &resulting_inequalities, const rewriter &r)
Remove every redundant inequality from a vector of inequalities.
application real_minus(const data_expression &arg0, const data_expression &arg1)
void fourier_motzkin(const data_expression &e_in, const variable_list &vars_in, data_expression &e_out, variable_list &vars_out, const rewriter &r)
Eliminate variables from a data expression using Gauss elimination and Fourier-Motzkin elimination.
std::string pp(const linear_inequality &l)
application real_divides(const data_expression &arg0, const data_expression &arg1)
std::set< variable > gauss_elimination(const std::vector< linear_inequality > &inequalities, std::vector< linear_inequality > &resulting_equalities, std::vector< linear_inequality > &resulting_inequalities, Variable_iterator variables_begin, Variable_iterator variables_end, const rewriter &r)
Try to eliminate variables from a system of inequalities using Gauss elimination.
bool is_zero(const data_expression &e)
bool is_function_symbol(const atermpp::aterm &x)
Returns true if the term t is a function symbol.
void fourier_motzkin(const std::vector< linear_inequality > &inequalities_in, Data_variable_iterator variables_begin, Data_variable_iterator variables_end, std::vector< linear_inequality > &resulting_inequalities, const rewriter &r)
data_expression rewrite_with_memory(const data_expression &t, const rewriter &r)
data_expression & real_zero()
application greater(const data_expression &arg0, const data_expression &arg1)
Application of function symbol >
Definition standard.h:328
application real_negate(const data_expression &arg)
bool is_inconsistent(const std::vector< linear_inequality > &inequalities_in, const rewriter &r, bool use_cache=true)
Determine whether a list of data expressions is inconsistent.
data_expression max(const data_expression &e1, const data_expression &e2, const rewriter &)
bool is_machine_number(const atermpp::aterm &x)
Returns true if the term t is a machine_number.
bool is_negative(const data_expression &e, const rewriter &r)
const data_expression_list & variable_list_to_data_expression_list(const variable_list &l)
Transform a variable_list into a data_expression_list.
application equal_to(const data_expression &arg0, const data_expression &arg1)
Application of function symbol ==.
Definition standard.h:140
data_expression min(const data_expression &e1, const data_expression &e2, const rewriter &)
bool is_variable(const atermpp::aterm &x)
Returns true if the term t is a variable.
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
The main namespace for the LPS library.
Definition constelm.h:18
void complete_data_specification(stochastic_specification &spec)
Adds all sorts that appear in the process of l to the data specification of l.
bool occursinterm(const data::data_expression &t, const data::variable &var)
mcrl2::lps::stochastic_specification linearise(const mcrl2::process::process_specification &type_checked_spec, const mcrl2::lps::t_lin_options &lin_options=t_lin_options())
Linearises a process specification.
The main namespace for the Process library.
bool is_at(const atermpp::aterm &x)
bool is_process_instance(const atermpp::aterm &x)
bool is_process_instance_assignment(const atermpp::aterm &x)
bool is_tau(const atermpp::aterm &x)
bool is_seq(const atermpp::aterm &x)
bool is_merge(const atermpp::aterm &x)
bool is_allow(const atermpp::aterm &x)
bool is_bounded_init(const atermpp::aterm &x)
bool is_delta(const atermpp::aterm &x)
bool is_sum(const atermpp::aterm &x)
bool is_block(const atermpp::aterm &x)
bool is_if_then_else(const atermpp::aterm &x)
bool is_comm(const atermpp::aterm &x)
void alphabet_reduce(process_specification &procspec, std::size_t duplicate_equation_limit=(std::numeric_limits< size_t >::max)())
Applies alphabet reduction to a process specification.
Definition process.cpp:82
bool is_action(const atermpp::aterm &x)
bool is_left_merge(const atermpp::aterm &x)
bool is_hide(const atermpp::aterm &x)
bool is_if_then(const atermpp::aterm &x)
bool is_choice(const atermpp::aterm &x)
bool is_stochastic_operator(const atermpp::aterm &x)
bool is_rename(const atermpp::aterm &x)
bool is_sync(const atermpp::aterm &x)
void swap(atermpp::aterm &t1, atermpp::aterm &t2) noexcept
Swaps two term_applss.
Definition aterm.h:364
A unary function that can be used in combination with replace_data_expressions to eliminate real numb...
fourier_motzkin_sigma(const rewriter &rewr_)
data_expression apply(const abstraction &d, bool negate) const
data_expression operator()(const data_expression &d) const
static constexpr bool is_identity_substitution
Options for linearisation.
Definition linearise.h:25
make_substitution(const std::map< process_identifier, process_identifier > &map)
process_identifier operator()(const process_identifier &id) const
const std::map< process_identifier, process_identifier > & m_map