PPL  1.0
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-2012 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  cs_out.insert(Linear_Expression(c) >= 0);
46  cs_out.insert(Linear_Expression(c) <= 0);
47  }
48  else if (c.is_strict_inequality())
49  // Insert the non-strict approximation.
50  cs_out.insert(Linear_Expression(c) >= 0);
51  else
52  // Insert as is.
53  cs_out.insert(c);
54  }
55  }
56  else
57  // No strict inequality and no equality constraints.
58  cs_out = cs_in;
59 }
60 
61 template <>
62 void
64  Constraint_System& cs) {
65  const Constraint_System& ph_cs = ph.minimized_constraints();
66  if (ph_cs.has_equalities()) {
67  // Translate equalities into inequalities.
69  i_end = ph_cs.end(); i != i_end; ++i) {
70  const Constraint& c = *i;
71  if (c.is_equality()) {
72  // Insert the two corresponding opposing inequalities.
73  cs.insert(Linear_Expression(c) >= 0);
74  cs.insert(Linear_Expression(c) <= 0);
75  }
76  else
77  // Insert as is.
78  cs.insert(c);
79  }
80  }
81  else
82  // No equality constraints (and no strict inequalities).
83  cs = ph_cs;
84 }
85 
125 void
127  Constraint_System& cs_out1,
128  Constraint_System& cs_out2) {
129  PPL_ASSERT(cs.space_dimension() % 2 == 0);
130  const dimension_type n = cs.space_dimension() / 2;
131  const dimension_type m = num_constraints(cs);
132 
133 #if PRINT_DEBUG_INFO
134  Variable::output_function_type* p_default_output_function
136  Variable::set_output_function(output_function_MS);
137 
138  output_function_MS_n = n;
139  output_function_MS_m = m;
140 
141  std::cout << "*** cs ***" << std::endl;
142  output_function_MS_which = 0;
143  using namespace IO_Operators;
144  std::cout << cs << std::endl;
145 #endif
146 
147  dimension_type y_begin = n+1;
148  dimension_type z_begin = y_begin + ((&cs_out1 == &cs_out2) ? m : 0);
149 
150  // Make sure linear expressions have the correct space dimension.
151  Linear_Expression y_le;
152  y_le.set_space_dimension(y_begin + m);
153  Linear_Expression z_le;
154  z_le.set_space_dimension(z_begin + m + 2);
155  std::vector<Linear_Expression> y_les(2*n, y_le);
156  std::vector<Linear_Expression> z_les(2*n + 1, z_le);
157 
158  dimension_type y = y_begin;
159  dimension_type z = z_begin;
161  cs_end = cs.end(); i != cs_end; ++i) {
162  Variable v_y(y);
163  Variable v_z(z);
164  ++y;
165  ++z;
166  cs_out1.insert(v_y >= 0);
167  cs_out2.insert(v_z >= 0);
168  const Constraint& c_i = *i;
169  Coefficient_traits::const_reference b_i = c_i.inhomogeneous_term();
170  if (b_i != 0) {
171  // Note that b_i is to the left ot the relation sign, hence here
172  // we have -= and not += just to avoid negating b_i.
173  sub_mul_assign(y_le, b_i, v_y);
174  sub_mul_assign(z_le, b_i, v_z);
175  }
177  j_end = c_i.expression().end(); j != j_end; ++j) {
178  Coefficient_traits::const_reference a_i_j = *j;
179  const Variable v = j.variable();
180  add_mul_assign(y_les[v.id()], a_i_j, v_y);
181  add_mul_assign(z_les[v.id()], a_i_j, v_z);
182  }
183  }
184  z_le += Variable(z);
185  z_les[2*n] += Variable(z);
186  cs_out2.insert(Variable(z) >= 0);
187  ++z;
188  z_le -= Variable(z);
189  z_les[2*n] -= Variable(z);
190  cs_out2.insert(Variable(z) >= 0);
191  cs_out1.insert(y_le >= 1);
192  cs_out2.insert(z_le >= 0);
193  dimension_type j = 2*n;
194  while (j-- > n) {
195  cs_out1.insert(y_les[j] == Variable(j-n));
196  cs_out2.insert(z_les[j] == Variable(j-n));
197  }
198  ++j;
199  while (j-- > 0) {
200  cs_out1.insert(y_les[j] == -Variable(j));
201  cs_out2.insert(z_les[j] == 0);
202  }
203  cs_out2.insert(z_les[2*n] == Variable(n));
204 
205 #if PRINT_DEBUG_INFO
206  if (&cs_out1 == &cs_out2) {
207  std::cout << "*** cs_mip ***" << std::endl;
208  output_function_MS_which = 3;
209  using namespace IO_Operators;
210  std::cout << cs_mip << std::endl;
211  }
212  else {
213  std::cout << "*** cs_out1 ***" << std::endl;
214  output_function_MS_which = 1;
215  using namespace IO_Operators;
216  std::cout << cs_out1 << std::endl;
217 
218  std::cout << "*** cs_out2 ***" << std::endl;
219  output_function_MS_which = 2;
220  using namespace IO_Operators;
221  std::cout << cs_out2 << std::endl;
222  }
223 
224  Variable::set_output_function(p_default_output_function);
225 #endif
226 }
227 
339 void
341  const Constraint_System& cs_after,
342  Constraint_System& cs_out,
343  Linear_Expression& le_out) {
344  PPL_ASSERT(cs_after.space_dimension() % 2 == 0);
345  PPL_ASSERT(2*cs_before.space_dimension() == cs_after.space_dimension());
346  const dimension_type n = cs_before.space_dimension();
347  const dimension_type r = num_constraints(cs_before);
348  const dimension_type s = num_constraints(cs_after);
349  const dimension_type m = r + s;
350 
351  // Make sure linear expressions are not reallocated multiple times.
352  if (m > 0)
353  le_out.set_space_dimension(m + r);
354  std::vector<Linear_Expression> les_eq(2*n, le_out);
355 
357  for (Constraint_System::const_iterator i = cs_before.begin(),
358  cs_before_end = cs_before.end();
359  i != cs_before_end;
360  ++i, ++row_index) {
361  Variable u1_i(m + row_index);
362  Variable u2_i(s + row_index);
363  const Constraint::Expression& e_i = i->expression();
365  j = e_i.begin(), j_end = e_i.end(); j != j_end; ++j) {
366  Coefficient_traits::const_reference A_ij_B = *j;
367  const Variable v = j.variable();
368  // (u1 - u2) A_B, in the context of j-th constraint.
369  add_mul_assign(les_eq[v.id()], A_ij_B, u1_i);
370  sub_mul_assign(les_eq[v.id()], A_ij_B, u2_i);
371  // u2 A_B, in the context of (j+n)-th constraint.
372  add_mul_assign(les_eq[v.id() + n], A_ij_B, u2_i);
373  }
374  Coefficient_traits::const_reference b_B = e_i.inhomogeneous_term();
375  if (b_B != 0)
376  // u2 b_B, in the context of the strict inequality constraint.
377  add_mul_assign(le_out, b_B, u2_i);
378  }
379 
380  row_index = 0;
381  for (Constraint_System::const_iterator i = cs_after.begin(),
382  cs_after_end = cs_after.end();
383  i != cs_after_end;
384  ++i, ++row_index) {
385  Variable u3_i(row_index);
386  const Constraint::Expression& e_i = i->expression();
388  i = e_i.lower_bound(Variable(n)),
389  i_end = e_i.end(); i != i_end; ++i) {
390  Coefficient_traits::const_reference A_ij_C = *i;
391  const Variable v = i.variable();
392  // - u3 A_C, in the context of the j-th constraint.
393  sub_mul_assign(les_eq[v.id() - n], A_ij_C, u3_i);
394  // u3 A_C, in the context of the (j+n)-th constraint.
395  add_mul_assign(les_eq[v.id()], A_ij_C, u3_i);
396  }
398  i_end = e_i.lower_bound(Variable(n)); i != i_end; ++i) {
399  Coefficient_traits::const_reference Ap_ij_C = *i;
400  // u3 Ap_C, in the context of the (j+n)-th constraint.
401  add_mul_assign(les_eq[i.variable().id() + n], Ap_ij_C, u3_i);
402  }
403  Coefficient_traits::const_reference b_C = e_i.inhomogeneous_term();
404  if (b_C != 0)
405  // u3 b_C, in the context of the strict inequality constraint.
406  add_mul_assign(le_out, b_C, u3_i);
407  }
408 
409  // Add the nonnegativity constraints for u_1, u_2 and u_3.
410  for (dimension_type i = s + 2*r; i-- > 0; )
411  cs_out.insert(Variable(i) >= 0);
412 
413  for (dimension_type j = 2*n; j-- > 0; )
414  cs_out.insert(les_eq[j] == 0);
415 }
416 
417 void
419  Constraint_System& cs_out,
420  Linear_Expression& le_out) {
421  PPL_ASSERT(cs.space_dimension() % 2 == 0);
422  const dimension_type n = cs.space_dimension() / 2;
423  const dimension_type m = num_constraints(cs);
424 
425  // Make sure linear expressions are not reallocated multiple times.
426  if (m > 0)
427  le_out.set_space_dimension(2*m);
428  std::vector<Linear_Expression> les_eq(3*n, le_out);
429 
432  cs_end = cs.end(); i != cs_end; ++i, ++row_index) {
433  const Constraint::Expression& e_i = i->expression();
434  const Variable lambda1_i(row_index);
435  const Variable lambda2_i(m + row_index);
437  i_end = e_i.lower_bound(Variable(n)); i != i_end; ++i) {
438  Coefficient_traits::const_reference Ap_ij = *i;
439  const Variable v = i.variable();
440  // lambda_1 A'
441  add_mul_assign(les_eq[v.id()], Ap_ij, lambda1_i);
442  // lambda_2 A'
443  add_mul_assign(les_eq[v.id()+n+n], Ap_ij, lambda2_i);
444  }
446  i = e_i.lower_bound(Variable(n)),
447  i_end = e_i.end(); i != i_end; ++i) {
448  Coefficient_traits::const_reference A_ij = *i;
449  const Variable v = i.variable();
450  // (lambda_1 - lambda_2) A
451  add_mul_assign(les_eq[v.id()], A_ij, lambda1_i);
452  sub_mul_assign(les_eq[v.id()], A_ij, lambda2_i);
453  // lambda_2 A
454  add_mul_assign(les_eq[v.id()+n], A_ij, lambda2_i);
455  }
456  Coefficient_traits::const_reference b = e_i.inhomogeneous_term();
457  if (b != 0)
458  // lambda2 b
459  add_mul_assign(le_out, b, lambda2_i);
460  }
461 
462  // Add the non-negativity constraints for lambda_1 and lambda_2.
463  for (dimension_type i = 2*m; i-- > 0; )
464  cs_out.insert(Variable(i) >= 0);
465 
466  for (dimension_type j = 3*n; j-- > 0; )
467  cs_out.insert(les_eq[j] == 0);
468 }
469 
470 bool
472  Constraint_System cs_mip;
473  fill_constraint_systems_MS(cs, cs_mip, cs_mip);
474 
475  MIP_Problem mip = MIP_Problem(cs_mip.space_dimension(), cs_mip);
476  return mip.is_satisfiable();
477 }
478 
479 bool
481  Constraint_System cs_mip;
482  fill_constraint_systems_MS(cs, cs_mip, cs_mip);
483 
484  MIP_Problem mip = MIP_Problem(cs_mip.space_dimension(), cs_mip);
485  if (!mip.is_satisfiable())
486  return false;
487 
488  Generator fp = mip.feasible_point();
489  PPL_ASSERT(fp.is_point());
490  const dimension_type n = cs.space_dimension() / 2;
491  Linear_Expression le(fp.expression(), n + 1);
492  mu = point(le, fp.divisor());
493  return true;
494 }
495 
496 void
498  C_Polyhedron& mu_space) {
499  Constraint_System cs_out1;
500  Constraint_System cs_out2;
501  fill_constraint_systems_MS(cs, cs_out1, cs_out2);
502 
503  C_Polyhedron ph1(cs_out1);
504  C_Polyhedron ph2(cs_out2);
505  const dimension_type n = cs.space_dimension() / 2;
509 
510 #if PRINT_DEBUG_INFO
511  Variable::output_function_type* p_default_output_function
513  Variable::set_output_function(output_function_MS);
514 
515  output_function_MS_n = n;
516  output_function_MS_m = num_constraints(cs);
517 
518  std::cout << "*** ph1 projected ***" << std::endl;
519  output_function_MS_which = 4;
520  using namespace IO_Operators;
521  std::cout << ph1.minimized_constraints() << std::endl;
522 
523  std::cout << "*** ph2 projected ***" << std::endl;
524  std::cout << ph2.minimized_constraints() << std::endl;
525 #endif
526 
527  ph1.intersection_assign(ph2);
528 
529 #if PRINT_DEBUG_INFO
530  std::cout << "*** intersection ***" << std::endl;
531  using namespace IO_Operators;
532  std::cout << ph1.minimized_constraints() << std::endl;
533 
534  Variable::set_output_function(p_default_output_function);
535 #endif
536 
537  mu_space.m_swap(ph1);
538 }
539 
540 void
542  C_Polyhedron& decreasing_mu_space,
543  C_Polyhedron& bounded_mu_space) {
544  Constraint_System cs_out1;
545  Constraint_System cs_out2;
546  fill_constraint_systems_MS(cs, cs_out1, cs_out2);
547 
548  C_Polyhedron ph1(cs_out1);
549  C_Polyhedron ph2(cs_out2);
550  const dimension_type n = cs.space_dimension() / 2;
554 
555 #if PRINT_DEBUG_INFO
556  Variable::output_function_type* p_default_output_function
558  Variable::set_output_function(output_function_MS);
559 
560  output_function_MS_n = n;
561  output_function_MS_m = num_constraints(cs);
562 
563  std::cout << "*** ph1 projected ***" << std::endl;
564  output_function_MS_which = 4;
565  using namespace IO_Operators;
566  std::cout << ph1.minimized_constraints() << std::endl;
567 
568  std::cout << "*** ph2 projected ***" << std::endl;
569  std::cout << ph2.minimized_constraints() << std::endl;
570 
571  Variable::set_output_function(p_default_output_function);
572 #endif
573 
574  decreasing_mu_space.m_swap(ph1);
575  bounded_mu_space.m_swap(ph2);
576 }
577 
578 bool
580  PPL_ASSERT(cs.space_dimension() % 2 == 0);
581 
582  Constraint_System cs_mip;
583  Linear_Expression le_ineq;
584  fill_constraint_system_PR_original(cs, cs_mip, le_ineq);
585 
586  // Turn minimization problem into satisfiability.
587  cs_mip.insert(le_ineq <= -1);
588 
589  MIP_Problem mip(cs_mip.space_dimension(), cs_mip);
590  return mip.is_satisfiable();
591 }
592 
593 bool
595  const Constraint_System& cs_after) {
596  Constraint_System cs_mip;
597  Linear_Expression le_ineq;
598  fill_constraint_system_PR(cs_before, cs_after, cs_mip, le_ineq);
599 
600 #if PRINT_DEBUG_INFO
601  Variable::output_function_type* p_default_output_function
603  Variable::set_output_function(output_function_PR);
604 
605  output_function_PR_r = num_constraints(cs_before);
606  output_function_PR_s = num_constraints(cs_after);
607 
608  std::cout << "*** cs_mip ***" << std::endl;
609  using namespace IO_Operators;
610  std::cout << cs_mip << std::endl;
611  std::cout << "*** le_ineq ***" << std::endl;
612  std::cout << le_ineq << std::endl;
613 
614  Variable::set_output_function(p_default_output_function);
615 #endif
616 
617  // Turn minimization problem into satisfiability.
618  cs_mip.insert(le_ineq <= -1);
619 
620  MIP_Problem mip(cs_mip.space_dimension(), cs_mip);
621  return mip.is_satisfiable();
622 }
623 
624 bool
626  const Constraint_System& cs_after,
627  Generator& mu) {
628  return Termination_Helpers
629  ::one_affine_ranking_function_PR(cs_before, cs_after, mu);
630 }
631 
632 bool
634  Generator& mu) {
636 }
637 
638 void
640  const Constraint_System& cs_after,
641  NNC_Polyhedron& mu_space) {
643  mu_space);
644 }
645 
646 void
648  NNC_Polyhedron& mu_space) {
650 }
651 
652 } // namespace Termination
653 
654 } // namespace Implementation
655 
656 bool
659  const Constraint_System& cs_after,
660  Generator& mu) {
661  Constraint_System cs_mip;
662  Linear_Expression le_ineq;
664  ::fill_constraint_system_PR(cs_before, cs_after, cs_mip, le_ineq);
665 
666 #if PRINT_DEBUG_INFO
667  Variable::output_function_type* p_default_output_function
669  Variable::set_output_function(output_function_PR);
670 
671  output_function_PR_r = num_constraints(cs_before);
672  output_function_PR_s = num_constraints(cs_after);
673 
674  std::cout << "*** cs_mip ***" << std::endl;
675  using namespace IO_Operators;
676  std::cout << cs_mip << std::endl;
677  std::cout << "*** le_ineq ***" << std::endl;
678  std::cout << le_ineq << std::endl;
679 
680  Variable::set_output_function(p_default_output_function);
681 #endif
682 
683  // Turn minimization problem into satisfiability.
684  cs_mip.insert(le_ineq <= -1);
685 
686  MIP_Problem mip(cs_mip.space_dimension(), cs_mip);
687  if (!mip.is_satisfiable())
688  return false;
689 
690  const Generator& fp = mip.feasible_point();
691  PPL_ASSERT(fp.is_point());
692 
693  // u_3 corresponds to space dimensions 0, ..., s - 1.
694  const dimension_type n = cs_before.space_dimension();
695  // mu_0 is zero: properly set space dimension.
697  le.set_space_dimension(1 + n);
698  // Multiply u_3 by E'_C to obtain mu_1, ..., mu_n.
700  for (Constraint_System::const_iterator i = cs_after.begin(),
701  cs_after_end = cs_after.end();
702  i != cs_after_end;
703  ++i, ++row_index) {
704  Coefficient_traits::const_reference
705  fp_i = fp.coefficient(Variable(row_index));
706  if (fp_i != 0)
707  le.linear_combine(i->expr, 1, -fp_i, 1, n + 1);
708  }
709  // Note that we can neglect the divisor of `fp' since it is positive.
710  mu = point(le);
711  return true;
712 }
713 
714 bool
717  Generator& mu) {
718  PPL_ASSERT(cs.space_dimension() % 2 == 0);
719  const dimension_type n = cs.space_dimension() / 2;
721 
722  Constraint_System cs_mip;
723  Linear_Expression le_ineq;
725  ::fill_constraint_system_PR_original(cs, cs_mip, le_ineq);
726 
727 #if PRINT_DEBUG_INFO
728  std::cout << "*** cs_mip ***" << std::endl;
729  using namespace IO_Operators;
730  std::cout << cs_mip << std::endl;
731  std::cout << "*** le_ineq ***" << std::endl;
732  std::cout << le_ineq << std::endl;
733 #endif
734 
735  // Turn minimization problem into satisfiability.
736  cs_mip.insert(le_ineq <= -1);
737 
738  MIP_Problem mip = MIP_Problem(cs_mip.space_dimension(), cs_mip);
739  if (!mip.is_satisfiable())
740  return false;
741 
742  const Generator& fp = mip.feasible_point();
743  PPL_ASSERT(fp.is_point());
744  // mu_0 is zero: properly set space dimension.
746  le.set_space_dimension(1 + n);
747  // Multiply -lambda_2 by A' to obtain mu_1, ..., mu_n.
748  // lambda_2 corresponds to space dimensions m, ..., 2*m - 1.
751  cs_end = cs.end(); i != cs_end; ++i, ++row_index) {
752  Variable lambda_2(row_index);
753  Coefficient_traits::const_reference fp_i = fp.coefficient(lambda_2);
754  if (fp_i != 0)
755  le.linear_combine(i->expr, 1, -fp_i, 1, n + 1);
756  }
757  // Note that we can neglect the divisor of `fp' since it is positive.
758  mu = point(le);
759  return true;
760 }
761 
762 void
765  const Constraint_System& cs_after,
766  NNC_Polyhedron& mu_space) {
767  Constraint_System cs_eqs;
768  Linear_Expression le_ineq;
770  ::fill_constraint_system_PR(cs_before, cs_after, cs_eqs, le_ineq);
771 
772 #if PRINT_DEBUG_INFO
773  Variable::output_function_type* p_default_output_function
775  Variable::set_output_function(output_function_PR);
776 
777  output_function_PR_r = num_constraints(cs_before);
778  output_function_PR_s = num_constraints(cs_after);
779 
780  std::cout << "*** cs_eqs ***" << std::endl;
781  using namespace IO_Operators;
782  std::cout << cs_eqs << std::endl;
783  std::cout << "*** le_ineq ***" << std::endl;
784  std::cout << le_ineq << std::endl;
785 #endif
786 
787  NNC_Polyhedron ph(cs_eqs);
788  ph.add_constraint(le_ineq < 0);
789  // u_3 corresponds to space dimensions 0, ..., s - 1.
792 
793 #if PRINT_DEBUG_INFO
794  std::cout << "*** ph ***" << std::endl;
795  std::cout << ph << std::endl;
796 
797  Variable::set_output_function(p_default_output_function);
798 #endif
799 
800  const dimension_type n = cs_before.space_dimension();
801 
802  const Generator_System& gs_in = ph.generators();
803  Generator_System gs_out;
804  Generator_System::const_iterator gs_in_it = gs_in.begin();
805  Generator_System::const_iterator gs_in_end = gs_in.end();
806  if (gs_in_it == gs_in_end)
807  // The system is unsatisfiable.
808  mu_space = NNC_Polyhedron(n + 1, EMPTY);
809  else {
810  for ( ; gs_in_it != gs_in_end; ++gs_in_it) {
811  const Generator& g = *gs_in_it;
813  le.set_space_dimension(n);
814  // Set le to the multiplication of Linear_Expression(g) by E'_C.
816  for (Constraint_System::const_iterator i = cs_after.begin(),
817  cs_after_end = cs_after.end();
818  i != cs_after_end;
819  ++i, ++row_index) {
820  Coefficient_traits::const_reference
821  g_i = g.coefficient(Variable(row_index));
822  if (g_i != 0)
823  le.linear_combine(i->expr, 1, -g_i, 1, n + 1);
824  }
825 
826  // Add to gs_out the transformed generator.
827  switch (g.type()) {
828  case Generator::LINE:
830  gs_out.insert(line(le));
831  break;
832  case Generator::RAY:
834  gs_out.insert(ray(le));
835  break;
836  case Generator::POINT:
837  gs_out.insert(point(le, g.divisor()));
838  break;
840  gs_out.insert(closure_point(le, g.divisor()));
841  break;
842  }
843  }
844 
845  mu_space = NNC_Polyhedron(gs_out);
846  // mu_0 is zero.
847  mu_space.add_space_dimensions_and_embed(1);
848  }
849 }
850 
851 void
854  NNC_Polyhedron& mu_space) {
855  PPL_ASSERT(cs.space_dimension() % 2 == 0);
856  const dimension_type n = cs.space_dimension() / 2;
858 
859  if (m == 0) {
860  // If there are no constraints at all, we have non-termination,
861  // i.e., no affine ranking function at all.
862  mu_space = NNC_Polyhedron(n + 1, EMPTY);
863  return;
864  }
865 
866  Constraint_System cs_eqs;
867  Linear_Expression le_ineq;
869  ::fill_constraint_system_PR_original(cs, cs_eqs, le_ineq);
870 
871  NNC_Polyhedron ph(cs_eqs);
872  ph.add_constraint(le_ineq < 0);
873  // lambda_2 corresponds to space dimensions m, ..., 2*m-1.
874  Variables_Set lambda1(Variable(0), Variable(m-1));
875  ph.remove_space_dimensions(lambda1);
876 
877 #if PRINT_DEBUG_INFO
878  std::cout << "*** ph ***" << std::endl;
879  std::cout << ph << std::endl;
880 
881  Variable::set_output_function(p_default_output_function);
882 #endif
883 
884  const Generator_System& gs_in = ph.generators();
885  Generator_System::const_iterator gs_in_it = gs_in.begin();
886  Generator_System::const_iterator gs_in_end = gs_in.end();
887  if (gs_in_it == gs_in_end)
888  // The system is unsatisfiable.
889  mu_space = NNC_Polyhedron(n + 1, EMPTY);
890  else {
891  Generator_System gs_out;
892  for ( ; gs_in_it != gs_in_end; ++gs_in_it) {
893  const Generator& g = *gs_in_it;
895  le.set_space_dimension(n);
896  // Set le to the multiplication of Linear_Expression(g) by E'_C.
899  cs_end = cs.end(); i != cs_end; ++i, ++row_index) {
900  Variable lambda2_i(row_index);
901  Coefficient_traits::const_reference g_i = g.coefficient(lambda2_i);
902  if (g_i != 0)
903  le.linear_combine(i->expr, 1, -g_i, 1, n + 1);
904  }
905 
906  // Add to gs_out the transformed generator.
907  switch (g.type()) {
908  case Generator::LINE:
910  gs_out.insert(line(le));
911  break;
912  case Generator::RAY:
914  gs_out.insert(ray(le));
915  break;
916  case Generator::POINT:
917  gs_out.insert(point(le, g.divisor()));
918  break;
920  gs_out.insert(closure_point(le, g.divisor()));
921  break;
922  }
923  }
924 
925  mu_space = NNC_Polyhedron(gs_out);
926  // mu_0 is zero.
927  mu_space.add_space_dimensions_and_embed(1);
928  }
929 }
930 
931 } // namespace Parma_Polyhedra_Library