PPL  1.2
termination.cc
Go to the documentation of this file.
1 /* Utilities for termination analysis: non-inline, non-template functions.
2  Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3  Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #include "ppl-config.h"
25 #include "termination_defs.hh"
26 #include "NNC_Polyhedron_defs.hh"
27 
28 namespace Parma_Polyhedra_Library {
29 
30 namespace Implementation {
31 
32 namespace Termination {
33 
34 void
36  Constraint_System& cs_out) {
37  if (cs_in.has_strict_inequalities() || cs_in.has_equalities()) {
38  // Here we have some strict inequality and/or equality constraints:
39  // translate them into non-strict inequality constraints.
41  i_end = cs_in.end(); i != i_end; ++i) {
42  const Constraint& c = *i;
43  if (c.is_equality()) {
44  // Insert the two corresponding opposing inequalities.
45  const Linear_Expression expr(c.expression());
46  cs_out.insert(expr >= 0);
47  cs_out.insert(expr <= 0);
48  }
49  else if (c.is_strict_inequality()) {
50  // Insert the non-strict approximation.
51  const Linear_Expression expr(c.expression());
52  cs_out.insert(expr >= 0);
53  }
54  else {
55  // Insert as is.
56  cs_out.insert(c);
57  }
58  }
59  }
60  else {
61  // No strict inequality and no equality constraints.
62  cs_out = cs_in;
63  }
64 }
65 
66 template <>
67 void
69  Constraint_System& cs) {
70  const Constraint_System& ph_cs = ph.minimized_constraints();
71  if (ph_cs.has_equalities()) {
72  // Translate equalities into inequalities.
74  i_end = ph_cs.end(); i != i_end; ++i) {
75  const Constraint& c = *i;
76  if (c.is_equality()) {
77  // Insert the two corresponding opposing inequalities.
78  const Linear_Expression expr(c.expression());
79  cs.insert(expr >= 0);
80  cs.insert(expr <= 0);
81  }
82  else {
83  // Insert as is.
84  cs.insert(c);
85  }
86  }
87  }
88  else {
89  // No equality constraints (and no strict inequalities).
90  cs = ph_cs;
91  }
92 }
93 
133 void
135  Constraint_System& cs_out1,
136  Constraint_System& cs_out2) {
137  PPL_ASSERT(cs.space_dimension() % 2 == 0);
138  const dimension_type n = cs.space_dimension() / 2;
139  const dimension_type m = num_constraints(cs);
140 
141 #if PRINT_DEBUG_INFO
142  Variable::output_function_type* p_default_output_function
144  Variable::set_output_function(output_function_MS);
145 
146  output_function_MS_n = n;
147  output_function_MS_m = m;
148 
149  std::cout << "*** cs ***" << std::endl;
150  output_function_MS_which = 0;
151  using namespace IO_Operators;
152  std::cout << cs << std::endl;
153 #endif
154 
155  const dimension_type y_begin = n+1;
156  const dimension_type z_begin = y_begin + ((&cs_out1 == &cs_out2) ? m : 0);
157 
158  // Make sure linear expressions have the correct space dimension.
159  Linear_Expression y_le;
160  y_le.set_space_dimension(y_begin + m);
161  Linear_Expression z_le;
162  z_le.set_space_dimension(z_begin + m + 2);
163  std::vector<Linear_Expression> y_les(2*n, y_le);
164  std::vector<Linear_Expression> z_les(2*n + 1, z_le);
165 
166  dimension_type y = y_begin;
167  dimension_type z = z_begin;
169  cs_end = cs.end(); i != cs_end; ++i) {
170  const Variable v_y(y);
171  const Variable v_z(z);
172  ++y;
173  ++z;
174  cs_out1.insert(v_y >= 0);
175  cs_out2.insert(v_z >= 0);
176  const Constraint& c_i = *i;
177  Coefficient_traits::const_reference b_i = c_i.inhomogeneous_term();
178  if (b_i != 0) {
179  // Note that b_i is to the left ot the relation sign, hence here
180  // we have -= and not += just to avoid negating b_i.
181  sub_mul_assign(y_le, b_i, v_y);
182  sub_mul_assign(z_le, b_i, v_z);
183  }
185  j_end = c_i.expression().end(); j != j_end; ++j) {
186  Coefficient_traits::const_reference a_i_j = *j;
187  const Variable v = j.variable();
188  add_mul_assign(y_les[v.id()], a_i_j, v_y);
189  add_mul_assign(z_les[v.id()], a_i_j, v_z);
190  }
191  }
192  z_le += Variable(z);
193  z_les[2*n] += Variable(z);
194  cs_out2.insert(Variable(z) >= 0);
195  ++z;
196  z_le -= Variable(z);
197  z_les[2*n] -= Variable(z);
198  cs_out2.insert(Variable(z) >= 0);
199  cs_out1.insert(y_le >= 1);
200  cs_out2.insert(z_le >= 0);
201  dimension_type j = 2*n;
202  while (j-- > n) {
203  cs_out1.insert(y_les[j] == Variable(j-n));
204  cs_out2.insert(z_les[j] == Variable(j-n));
205  }
206  ++j;
207  while (j-- > 0) {
208  cs_out1.insert(y_les[j] == -Variable(j));
209  cs_out2.insert(z_les[j] == 0);
210  }
211  cs_out2.insert(z_les[2*n] == Variable(n));
212 
213 #if PRINT_DEBUG_INFO
214  if (&cs_out1 == &cs_out2) {
215  std::cout << "*** cs_mip ***" << std::endl;
216  output_function_MS_which = 3;
217  using namespace IO_Operators;
218  std::cout << cs_mip << std::endl;
219  }
220  else {
221  std::cout << "*** cs_out1 ***" << std::endl;
222  output_function_MS_which = 1;
223  using namespace IO_Operators;
224  std::cout << cs_out1 << std::endl;
225 
226  std::cout << "*** cs_out2 ***" << std::endl;
227  output_function_MS_which = 2;
228  using namespace IO_Operators;
229  std::cout << cs_out2 << std::endl;
230  }
231 
232  Variable::set_output_function(p_default_output_function);
233 #endif
234 }
235 
347 void
349  const Constraint_System& cs_after,
350  Constraint_System& cs_out,
351  Linear_Expression& le_out) {
352  PPL_ASSERT(cs_after.space_dimension() % 2 == 0);
353  PPL_ASSERT(2*cs_before.space_dimension() == cs_after.space_dimension());
354  const dimension_type n = cs_before.space_dimension();
355  const dimension_type r = num_constraints(cs_before);
356  const dimension_type s = num_constraints(cs_after);
357  const dimension_type m = r + s;
358 
359  // Make sure linear expressions are not reallocated multiple times.
360  if (m > 0) {
361  le_out.set_space_dimension(m + r);
362  }
363  std::vector<Linear_Expression> les_eq(2*n, le_out);
364 
366  for (Constraint_System::const_iterator i = cs_before.begin(),
367  cs_before_end = cs_before.end();
368  i != cs_before_end;
369  ++i, ++row_index) {
370  const Variable u1_i(m + row_index);
371  const Variable u2_i(s + row_index);
372  const Constraint::expr_type e_i = i->expression();
374  j = e_i.begin(), j_end = e_i.end(); j != j_end; ++j) {
375  Coefficient_traits::const_reference A_ij_B = *j;
376  const Variable v = j.variable();
377  // (u1 - u2) A_B, in the context of j-th constraint.
378  add_mul_assign(les_eq[v.id()], A_ij_B, u1_i);
379  sub_mul_assign(les_eq[v.id()], A_ij_B, u2_i);
380  // u2 A_B, in the context of (j+n)-th constraint.
381  add_mul_assign(les_eq[v.id() + n], A_ij_B, u2_i);
382  }
383  Coefficient_traits::const_reference b_B = e_i.inhomogeneous_term();
384  if (b_B != 0) {
385  // u2 b_B, in the context of the strict inequality constraint.
386  add_mul_assign(le_out, b_B, u2_i);
387  }
388  }
389 
390  row_index = 0;
391  for (Constraint_System::const_iterator i = cs_after.begin(),
392  cs_after_end = cs_after.end();
393  i != cs_after_end;
394  ++i, ++row_index) {
395  const Variable u3_i(row_index);
396  const Constraint::expr_type e_i = i->expression();
398  j = e_i.lower_bound(Variable(n)),
399  j_end = e_i.end(); j != j_end; ++j) {
400  Coefficient_traits::const_reference A_ij_C = *j;
401  const Variable v = j.variable();
402  // - u3 A_C, in the context of the j-th constraint.
403  sub_mul_assign(les_eq[v.id() - n], A_ij_C, u3_i);
404  // u3 A_C, in the context of the (j+n)-th constraint.
405  add_mul_assign(les_eq[v.id()], A_ij_C, u3_i);
406  }
408  j_end = e_i.lower_bound(Variable(n)); j != j_end; ++j) {
409  Coefficient_traits::const_reference Ap_ij_C = *j;
410  // u3 Ap_C, in the context of the (j+n)-th constraint.
411  add_mul_assign(les_eq[j.variable().id() + n], Ap_ij_C, u3_i);
412  }
413  Coefficient_traits::const_reference b_C = e_i.inhomogeneous_term();
414  if (b_C != 0) {
415  // u3 b_C, in the context of the strict inequality constraint.
416  add_mul_assign(le_out, b_C, u3_i);
417  }
418  }
419 
420  // Add the nonnegativity constraints for u_1, u_2 and u_3.
421  for (dimension_type i = s + 2*r; i-- > 0; ) {
422  cs_out.insert(Variable(i) >= 0);
423  }
424 
425  for (dimension_type j = 2*n; j-- > 0; ) {
426  cs_out.insert(les_eq[j] == 0);
427  }
428 }
429 
430 void
432  Constraint_System& cs_out,
433  Linear_Expression& le_out) {
434  PPL_ASSERT(cs.space_dimension() % 2 == 0);
435  const dimension_type n = cs.space_dimension() / 2;
436  const dimension_type m = num_constraints(cs);
437 
438  // Make sure linear expressions are not reallocated multiple times.
439  if (m > 0) {
440  le_out.set_space_dimension(2*m);
441  }
442  std::vector<Linear_Expression> les_eq(3*n, le_out);
443 
446  cs_end = cs.end(); i != cs_end; ++i, ++row_index) {
447  const Constraint::expr_type e_i = i->expression();
448  const Variable lambda1_i(row_index);
449  const Variable lambda2_i(m + row_index);
451  j_end = e_i.lower_bound(Variable(n)); j != j_end; ++j) {
452  Coefficient_traits::const_reference Ap_ij = *j;
453  const Variable v = j.variable();
454  // lambda_1 A'
455  add_mul_assign(les_eq[v.id()], Ap_ij, lambda1_i);
456  // lambda_2 A'
457  add_mul_assign(les_eq[v.id()+n+n], Ap_ij, lambda2_i);
458  }
460  j = e_i.lower_bound(Variable(n)),
461  j_end = e_i.end(); j != j_end; ++j) {
462  Coefficient_traits::const_reference A_ij = *j;
463  const Variable v = j.variable();
464  // (lambda_1 - lambda_2) A
465  add_mul_assign(les_eq[v.id()], A_ij, lambda1_i);
466  sub_mul_assign(les_eq[v.id()], A_ij, lambda2_i);
467  // lambda_2 A
468  add_mul_assign(les_eq[v.id()+n], A_ij, lambda2_i);
469  }
470  Coefficient_traits::const_reference b = e_i.inhomogeneous_term();
471  if (b != 0) {
472  // lambda2 b
473  add_mul_assign(le_out, b, lambda2_i);
474  }
475  }
476 
477  // Add the non-negativity constraints for lambda_1 and lambda_2.
478  for (dimension_type i = 2*m; i-- > 0; ) {
479  cs_out.insert(Variable(i) >= 0);
480  }
481 
482  for (dimension_type j = 3*n; j-- > 0; ) {
483  cs_out.insert(les_eq[j] == 0);
484  }
485 }
486 
487 bool
489  Constraint_System cs_mip;
490  fill_constraint_systems_MS(cs, cs_mip, cs_mip);
491 
492  const MIP_Problem mip = MIP_Problem(cs_mip.space_dimension(), cs_mip);
493  return mip.is_satisfiable();
494 }
495 
496 bool
498  Constraint_System cs_mip;
499  fill_constraint_systems_MS(cs, cs_mip, cs_mip);
500 
501  const MIP_Problem mip = MIP_Problem(cs_mip.space_dimension(), cs_mip);
502  if (!mip.is_satisfiable()) {
503  return false;
504  }
505  const Generator fp = mip.feasible_point();
506  PPL_ASSERT(fp.is_point());
507  const dimension_type n = cs.space_dimension() / 2;
508  const Linear_Expression le(fp.expression(), n + 1);
509  mu = point(le, fp.divisor());
510  return true;
511 }
512 
513 void
515  C_Polyhedron& mu_space) {
516  Constraint_System cs_out1;
517  Constraint_System cs_out2;
518  fill_constraint_systems_MS(cs, cs_out1, cs_out2);
519 
520  C_Polyhedron ph1(cs_out1);
521  C_Polyhedron ph2(cs_out2);
522  const dimension_type n = cs.space_dimension() / 2;
526 
527 #if PRINT_DEBUG_INFO
528  Variable::output_function_type* p_default_output_function
530  Variable::set_output_function(output_function_MS);
531 
532  output_function_MS_n = n;
533  output_function_MS_m = num_constraints(cs);
534 
535  std::cout << "*** ph1 projected ***" << std::endl;
536  output_function_MS_which = 4;
537  using namespace IO_Operators;
538  std::cout << ph1.minimized_constraints() << std::endl;
539 
540  std::cout << "*** ph2 projected ***" << std::endl;
541  std::cout << ph2.minimized_constraints() << std::endl;
542 #endif
543 
544  ph1.intersection_assign(ph2);
545 
546 #if PRINT_DEBUG_INFO
547  std::cout << "*** intersection ***" << std::endl;
548  using namespace IO_Operators;
549  std::cout << ph1.minimized_constraints() << std::endl;
550 
551  Variable::set_output_function(p_default_output_function);
552 #endif
553 
554  mu_space.m_swap(ph1);
555 }
556 
557 void
559  C_Polyhedron& decreasing_mu_space,
560  C_Polyhedron& bounded_mu_space) {
561  Constraint_System cs_out1;
562  Constraint_System cs_out2;
563  fill_constraint_systems_MS(cs, cs_out1, cs_out2);
564 
565  C_Polyhedron ph1(cs_out1);
566  C_Polyhedron ph2(cs_out2);
567  const dimension_type n = cs.space_dimension() / 2;
571 
572 #if PRINT_DEBUG_INFO
573  Variable::output_function_type* p_default_output_function
575  Variable::set_output_function(output_function_MS);
576 
577  output_function_MS_n = n;
578  output_function_MS_m = num_constraints(cs);
579 
580  std::cout << "*** ph1 projected ***" << std::endl;
581  output_function_MS_which = 4;
582  using namespace IO_Operators;
583  std::cout << ph1.minimized_constraints() << std::endl;
584 
585  std::cout << "*** ph2 projected ***" << std::endl;
586  std::cout << ph2.minimized_constraints() << std::endl;
587 
588  Variable::set_output_function(p_default_output_function);
589 #endif
590 
591  decreasing_mu_space.m_swap(ph1);
592  bounded_mu_space.m_swap(ph2);
593 }
594 
595 bool
597  PPL_ASSERT(cs.space_dimension() % 2 == 0);
598 
599  Constraint_System cs_mip;
600  Linear_Expression le_ineq;
601  fill_constraint_system_PR_original(cs, cs_mip, le_ineq);
602 
603  // Turn minimization problem into satisfiability.
604  cs_mip.insert(le_ineq <= -1);
605 
606  const MIP_Problem mip(cs_mip.space_dimension(), cs_mip);
607  return mip.is_satisfiable();
608 }
609 
610 bool
612  const Constraint_System& cs_after) {
613  Constraint_System cs_mip;
614  Linear_Expression le_ineq;
615  fill_constraint_system_PR(cs_before, cs_after, cs_mip, le_ineq);
616 
617 #if PRINT_DEBUG_INFO
618  Variable::output_function_type* p_default_output_function
620  Variable::set_output_function(output_function_PR);
621 
622  output_function_PR_r = num_constraints(cs_before);
623  output_function_PR_s = num_constraints(cs_after);
624 
625  std::cout << "*** cs_mip ***" << std::endl;
626  using namespace IO_Operators;
627  std::cout << cs_mip << std::endl;
628  std::cout << "*** le_ineq ***" << std::endl;
629  std::cout << le_ineq << std::endl;
630 
631  Variable::set_output_function(p_default_output_function);
632 #endif
633 
634  // Turn minimization problem into satisfiability.
635  cs_mip.insert(le_ineq <= -1);
636 
637  const MIP_Problem mip(cs_mip.space_dimension(), cs_mip);
638  return mip.is_satisfiable();
639 }
640 
641 bool
643  const Constraint_System& cs_after,
644  Generator& mu) {
645  return Termination_Helpers
646  ::one_affine_ranking_function_PR(cs_before, cs_after, mu);
647 }
648 
649 bool
651  Generator& mu) {
653 }
654 
655 void
657  const Constraint_System& cs_after,
658  NNC_Polyhedron& mu_space) {
660  mu_space);
661 }
662 
663 void
665  NNC_Polyhedron& mu_space) {
667 }
668 
669 } // namespace Termination
670 
671 } // namespace Implementation
672 
673 bool
676  const Constraint_System& cs_after,
677  Generator& mu) {
678  Constraint_System cs_mip;
679  Linear_Expression le_ineq;
681  ::fill_constraint_system_PR(cs_before, cs_after, cs_mip, le_ineq);
682 
683 #if PRINT_DEBUG_INFO
684  Variable::output_function_type* p_default_output_function
686  Variable::set_output_function(output_function_PR);
687 
688  output_function_PR_r = num_constraints(cs_before);
689  output_function_PR_s = num_constraints(cs_after);
690 
691  std::cout << "*** cs_mip ***" << std::endl;
692  using namespace IO_Operators;
693  std::cout << cs_mip << std::endl;
694  std::cout << "*** le_ineq ***" << std::endl;
695  std::cout << le_ineq << std::endl;
696 
697  Variable::set_output_function(p_default_output_function);
698 #endif
699 
700  // Turn minimization problem into satisfiability.
701  cs_mip.insert(le_ineq <= -1);
702 
703  const MIP_Problem mip(cs_mip.space_dimension(), cs_mip);
704  if (!mip.is_satisfiable()) {
705  return false;
706  }
707 
708  const Generator& fp = mip.feasible_point();
709  PPL_ASSERT(fp.is_point());
710 
711  // u_3 corresponds to space dimensions 0, ..., s - 1.
712  const dimension_type n = cs_before.space_dimension();
713  // mu_0 is zero: properly set space dimension.
715  le.set_space_dimension(1 + n);
716  // Multiply u_3 by E'_C to obtain mu_1, ..., mu_n.
718  for (Constraint_System::const_iterator i = cs_after.begin(),
719  cs_after_end = cs_after.end();
720  i != cs_after_end;
721  ++i, ++row_index) {
722  Coefficient_traits::const_reference
723  fp_i = fp.coefficient(Variable(row_index));
724  if (fp_i != 0) {
725  le.linear_combine(i->expr, 1, -fp_i, 1, n + 1);
726  }
727  }
728  // Note that we can neglect the divisor of `fp' since it is positive.
729  mu = point(le);
730  return true;
731 }
732 
733 bool
736  Generator& mu) {
737  PPL_ASSERT(cs.space_dimension() % 2 == 0);
738  const dimension_type n = cs.space_dimension() / 2;
740 
741  Constraint_System cs_mip;
742  Linear_Expression le_ineq;
744  ::fill_constraint_system_PR_original(cs, cs_mip, le_ineq);
745 
746 #if PRINT_DEBUG_INFO
747  std::cout << "*** cs_mip ***" << std::endl;
748  using namespace IO_Operators;
749  std::cout << cs_mip << std::endl;
750  std::cout << "*** le_ineq ***" << std::endl;
751  std::cout << le_ineq << std::endl;
752 #endif
753 
754  // Turn minimization problem into satisfiability.
755  cs_mip.insert(le_ineq <= -1);
756 
757  const MIP_Problem mip = MIP_Problem(cs_mip.space_dimension(), cs_mip);
758  if (!mip.is_satisfiable()) {
759  return false;
760  }
761  const Generator& fp = mip.feasible_point();
762  PPL_ASSERT(fp.is_point());
763  // mu_0 is zero: properly set space dimension.
765  le.set_space_dimension(1 + n);
766  // Multiply -lambda_2 by A' to obtain mu_1, ..., mu_n.
767  // lambda_2 corresponds to space dimensions m, ..., 2*m - 1.
770  cs_end = cs.end(); i != cs_end; ++i, ++row_index) {
771  const Variable lambda_2(row_index);
772  Coefficient_traits::const_reference fp_i = fp.coefficient(lambda_2);
773  if (fp_i != 0) {
774  le.linear_combine(i->expr, 1, -fp_i, 1, n + 1);
775  }
776  }
777  // Note that we can neglect the divisor of `fp' since it is positive.
778  mu = point(le);
779  return true;
780 }
781 
782 void
785  const Constraint_System& cs_after,
786  NNC_Polyhedron& mu_space) {
787  Constraint_System cs_eqs;
788  Linear_Expression le_ineq;
790  ::fill_constraint_system_PR(cs_before, cs_after, cs_eqs, le_ineq);
791 
792 #if PRINT_DEBUG_INFO
793  Variable::output_function_type* p_default_output_function
795  Variable::set_output_function(output_function_PR);
796 
797  output_function_PR_r = num_constraints(cs_before);
798  output_function_PR_s = num_constraints(cs_after);
799 
800  std::cout << "*** cs_eqs ***" << std::endl;
801  using namespace IO_Operators;
802  std::cout << cs_eqs << std::endl;
803  std::cout << "*** le_ineq ***" << std::endl;
804  std::cout << le_ineq << std::endl;
805 #endif
806 
807  NNC_Polyhedron ph(cs_eqs);
808  ph.add_constraint(le_ineq < 0);
809  // u_3 corresponds to space dimensions 0, ..., s - 1.
812 
813 #if PRINT_DEBUG_INFO
814  std::cout << "*** ph ***" << std::endl;
815  std::cout << ph << std::endl;
816 
817  Variable::set_output_function(p_default_output_function);
818 #endif
819 
820  const dimension_type n = cs_before.space_dimension();
821 
822  const Generator_System& gs_in = ph.generators();
823  Generator_System gs_out;
824  Generator_System::const_iterator gs_in_it = gs_in.begin();
825  Generator_System::const_iterator gs_in_end = gs_in.end();
826  if (gs_in_it == gs_in_end) {
827  // The system is unsatisfiable.
828  mu_space = NNC_Polyhedron(n + 1, EMPTY);
829  }
830  else {
831  for ( ; gs_in_it != gs_in_end; ++gs_in_it) {
832  const Generator& g = *gs_in_it;
834  le.set_space_dimension(n);
835  // Set le to the multiplication of Linear_Expression(g) by E'_C.
837  for (Constraint_System::const_iterator i = cs_after.begin(),
838  cs_after_end = cs_after.end();
839  i != cs_after_end;
840  ++i, ++row_index) {
841  Coefficient_traits::const_reference
842  g_i = g.coefficient(Variable(row_index));
843  if (g_i != 0) {
844  le.linear_combine(i->expr, 1, -g_i, 1, n + 1);
845  }
846  }
847 
848  // Add to gs_out the transformed generator.
849  switch (g.type()) {
850  case Generator::LINE:
851  if (!le.all_homogeneous_terms_are_zero()) {
852  gs_out.insert(line(le));
853  }
854  break;
855  case Generator::RAY:
856  if (!le.all_homogeneous_terms_are_zero()) {
857  gs_out.insert(ray(le));
858  }
859  break;
860  case Generator::POINT:
861  gs_out.insert(point(le, g.divisor()));
862  break;
864  gs_out.insert(closure_point(le, g.divisor()));
865  break;
866  }
867  }
868 
869  mu_space = NNC_Polyhedron(gs_out);
870  // mu_0 is zero.
871  mu_space.add_space_dimensions_and_embed(1);
872  }
873 }
874 
875 void
878  NNC_Polyhedron& mu_space) {
879  PPL_ASSERT(cs.space_dimension() % 2 == 0);
880  const dimension_type n = cs.space_dimension() / 2;
882 
883  if (m == 0) {
884  // If there are no constraints at all, we have non-termination,
885  // i.e., no affine ranking function at all.
886  mu_space = NNC_Polyhedron(n + 1, EMPTY);
887  return;
888  }
889 
890  Constraint_System cs_eqs;
891  Linear_Expression le_ineq;
893  ::fill_constraint_system_PR_original(cs, cs_eqs, le_ineq);
894 
895  NNC_Polyhedron ph(cs_eqs);
896  ph.add_constraint(le_ineq < 0);
897  // lambda_2 corresponds to space dimensions m, ..., 2*m-1.
898  const Variables_Set lambda1(Variable(0), Variable(m-1));
899  ph.remove_space_dimensions(lambda1);
900 
901 #if PRINT_DEBUG_INFO
902  std::cout << "*** ph ***" << std::endl;
903  std::cout << ph << std::endl;
904 
905  Variable::set_output_function(p_default_output_function);
906 #endif
907 
908  const Generator_System& gs_in = ph.generators();
909  Generator_System::const_iterator gs_in_it = gs_in.begin();
910  Generator_System::const_iterator gs_in_end = gs_in.end();
911  if (gs_in_it == gs_in_end) {
912  // The system is unsatisfiable.
913  mu_space = NNC_Polyhedron(n + 1, EMPTY);
914  }
915  else {
916  Generator_System gs_out;
917  for ( ; gs_in_it != gs_in_end; ++gs_in_it) {
918  const Generator& g = *gs_in_it;
920  le.set_space_dimension(n);
921  // Set le to the multiplication of Linear_Expression(g) by E'_C.
924  cs_end = cs.end(); i != cs_end; ++i, ++row_index) {
925  const Variable lambda2_i(row_index);
926  Coefficient_traits::const_reference g_i = g.coefficient(lambda2_i);
927  if (g_i != 0) {
928  le.linear_combine(i->expr, 1, -g_i, 1, n + 1);
929  }
930  }
931 
932  // Add to gs_out the transformed generator.
933  switch (g.type()) {
934  case Generator::LINE:
935  if (!le.all_homogeneous_terms_are_zero()) {
936  gs_out.insert(line(le));
937  }
938  break;
939  case Generator::RAY:
940  if (!le.all_homogeneous_terms_are_zero()) {
941  gs_out.insert(ray(le));
942  }
943  break;
944  case Generator::POINT:
945  gs_out.insert(point(le, g.divisor()));
946  break;
948  gs_out.insert(closure_point(le, g.divisor()));
949  break;
950  }
951  }
952 
953  mu_space = NNC_Polyhedron(gs_out);
954  // mu_0 is zero.
955  mu_space.add_space_dimensions_and_embed(1);
956  }
957 }
958 
959 } // namespace Parma_Polyhedra_Library
void add_space_dimensions_and_embed(dimension_type m)
Adds m new space dimensions and embeds the old polyhedron in the new vector space.
bool is_satisfiable() const
Checks satisfiability of *this.
Definition: MIP_Problem.cc:247
bool one_affine_ranking_function_PR_original(const Constraint_System &cs, Generator &mu)
Definition: termination.cc:650
The empty element, i.e., the empty set.
A linear equality or inequality.
bool is_equality() const
Returns true if and only if *this is an equality constraint.
bool termination_test_MS(const Constraint_System &cs)
Definition: termination.cc:488
void set_space_dimension(dimension_type n)
Sets the dimension of the vector space enclosing *this to n .
size_t dimension_type
An unsigned integral type for representing space dimensions.
An std::set of variables' indexes.
A line, ray, point or closure point.
void assign_all_inequalities_approximation(const Constraint_System &cs_in, Constraint_System &cs_out)
Definition: termination.cc:35
static void all_affine_ranking_functions_PR(const Constraint_System &cs_before, const Constraint_System &cs_after, NNC_Polyhedron &mu_space)
Definition: termination.cc:784
void add_constraint(const Constraint &c)
Adds a copy of constraint c to the system of constraints of *this (without minimizing the result)...
static output_function_type * get_output_function()
Returns the pointer to the current output function.
void add_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
static bool one_affine_ranking_function_PR(const Constraint_System &cs_before, const Constraint_System &cs_after, Generator &mu)
Definition: termination.cc:675
void insert(const Constraint &c)
Inserts in *this a copy of the constraint c, increasing the number of space dimensions if needed...
dimension_type num_constraints(const Constraint_System &cs)
Helper returning number of constraints in system.
expr_type expression() const
Partial read access to the (adapted) internal expression.
void remove_space_dimensions(const Variables_Set &vars)
Removes all the specified dimensions from the vector space.
const_iterator begin() const
Returns the const_iterator pointing to the first constraint, if *this is not empty; otherwise...
static void all_affine_ranking_functions_PR_original(const Constraint_System &cs, NNC_Polyhedron &mu_space)
Definition: termination.cc:877
void output_function_type(std::ostream &s, const Variable v)
Type of output functions.
dimension_type id() const
Returns the index of the Cartesian axis associated to the variable.
A dimension of the vector space.
bool is_strict_inequality() const
Returns true if and only if *this is a strict inequality constraint.
bool one_affine_ranking_function_MS(const Constraint_System &cs, Generator &mu)
Definition: termination.cc:497
void all_affine_quasi_ranking_functions_MS(const Constraint_System &cs, C_Polyhedron &decreasing_mu_space, C_Polyhedron &bounded_mu_space)
Definition: termination.cc:558
bool one_affine_ranking_function_PR(const Constraint_System &cs_before, const Constraint_System &cs_after, Generator &mu)
Definition: termination.cc:642
void all_affine_ranking_functions_PR_original(const Constraint_System &cs, NNC_Polyhedron &mu_space)
Definition: termination.cc:664
void remove_higher_space_dimensions(dimension_type new_dimension)
Removes the higher dimensions of the vector space so that the resulting space will have dimension new...
bool termination_test_PR(const Constraint_System &cs_before, const Constraint_System &cs_after)
Definition: termination.cc:611
void fill_constraint_system_PR_original(const Constraint_System &cs, Constraint_System &cs_out, Linear_Expression &le_out)
Definition: termination.cc:431
void all_affine_ranking_functions_MS(const Constraint_System &cs, C_Polyhedron &mu_space)
Definition: termination.cc:514
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
Type type() const
Returns the generator type of *this.
void fill_constraint_systems_MS(const Constraint_System &cs, Constraint_System &cs_out1, Constraint_System &cs_out2)
Fill the constraint system(s) for the application of the Mesnard and Serebrenik improved termination ...
Definition: termination.cc:134
void fill_constraint_system_PR(const Constraint_System &cs_before, const Constraint_System &cs_after, Constraint_System &cs_out, Linear_Expression &le_out)
Fill the constraint system(s) for the application of the Podelski and Rybalchenko improved terminatio...
Definition: termination.cc:348
const_iterator end() const
Returns the past-the-end const_iterator.
A Mixed Integer (linear) Programming problem.
const_iterator end() const
Iterator pointing after the last nonzero variable coefficient.
const Generator_System & generators() const
Returns the system of generators.
dimension_type row_index
Definition: PIP_Tree.cc:615
A not necessarily closed convex polyhedron.
void intersection_assign(const Polyhedron &y)
Assigns to *this the intersection of *this and y.
A closed convex polyhedron.
bool all_homogeneous_terms_are_zero() const
Returns true if and only if all the homogeneous terms of *this are .
bool is_point() const
Returns true if and only if *this is a point.
bool has_equalities() const
Returns true if and only if *this contains one or more equality constraints.
void all_affine_ranking_functions_PR(const Constraint_System &cs_before, const Constraint_System &cs_after, NNC_Polyhedron &mu_space)
Definition: termination.cc:656
The entire library is confined to this namespace.
Definition: version.hh:61
const Generator & feasible_point() const
Returns a feasible point for *this, if it exists.
Definition: MIP_Problem.cc:225
const_iterator end() const
Returns the past-the-end const_iterator.
const_iterator begin() const
Returns the const_iterator pointing to the first generator, if *this is not empty; otherwise...
base_type::const_iterator const_iterator
The type of const iterators on coefficients.
Coefficient_traits::const_reference coefficient(Variable v) const
Returns the coefficient of v in *this.
void sub_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
Coefficient_traits::const_reference divisor() const
If *this is either a point or a closure point, returns its divisor.
Coefficient c
Definition: PIP_Tree.cc:64
void linear_combine(const Linear_Expression &y, Variable v)
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
static void set_output_function(output_function_type *p)
Sets the output function to be used for printing Variable objects.
expr_type expression() const
Partial read access to the (adapted) internal expression.
const_iterator begin() const
Iterator pointing to the first nonzero variable coefficient.
void insert(const Generator &g)
Inserts in *this a copy of the generator g, increasing the number of space dimensions if needed...
const Constraint_System & minimized_constraints() const
Returns the system of constraints, with no redundant constraint.
An adapter for Linear_Expression that maybe hides the last coefficient.
void m_swap(Polyhedron &y)
Swaps *this with polyhedron y. (*this and y can be dimension-incompatible.)
bool le(Boundary_Type type1, const T1 &x1, const Info1 &info1, Boundary_Type type2, const T2 &x2, const Info2 &info2)
bool termination_test_PR_original(const Constraint_System &cs)
Definition: termination.cc:596
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
static bool one_affine_ranking_function_PR_original(const Constraint_System &cs, Generator &mu)
Definition: termination.cc:735
bool has_strict_inequalities() const
Returns true if and only if *this contains one or more strict inequality constraints.