PPL  0.12.1
termination.cc
Go to the documentation of this file.
00001 /* Utilities for termination analysis: non-inline, non-template functions.
00002    Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
00003    Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com)
00004 
00005 This file is part of the Parma Polyhedra Library (PPL).
00006 
00007 The PPL is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 The PPL is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this program; if not, write to the Free Software Foundation,
00019 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
00020 
00021 For the most up-to-date information see the Parma Polyhedra Library
00022 site: http://bugseng.com/products/ppl/ . */
00023 
00024 #include "ppl-config.h"
00025 #include "termination.defs.hh"
00026 #include "NNC_Polyhedron.defs.hh"
00027 
00028 namespace Parma_Polyhedra_Library {
00029 
00030 namespace Implementation {
00031 
00032 namespace Termination {
00033 
00034 void
00035 assign_all_inequalities_approximation(const Constraint_System& cs_in,
00036                                       Constraint_System& cs_out) {
00037   if (cs_in.has_strict_inequalities() || cs_in.has_equalities()) {
00038     // Here we have some strict inequality and/or equality constraints:
00039     // translate them into non-strict inequality constraints.
00040     for (Constraint_System::const_iterator i = cs_in.begin(),
00041            i_end = cs_in.end(); i != i_end; ++i) {
00042       const Constraint& c = *i;
00043       if (c.is_equality()) {
00044         // Insert the two corresponding opposing inequalities.
00045         cs_out.insert(Linear_Expression(c) >= 0);
00046         cs_out.insert(Linear_Expression(c) <= 0);
00047       }
00048       else if (c.is_strict_inequality())
00049         // Insert the non-strict approximation.
00050         cs_out.insert(Linear_Expression(c) >= 0);
00051       else
00052         // Insert as is.
00053         cs_out.insert(c);
00054     }
00055   }
00056   else
00057     // No strict inequality and no equality constraints.
00058     cs_out = cs_in;
00059 }
00060 
00061 template <>
00062 void
00063 assign_all_inequalities_approximation(const C_Polyhedron& ph,
00064                                       Constraint_System& cs) {
00065   const Constraint_System& ph_cs = ph.minimized_constraints();
00066   if (ph_cs.has_equalities()) {
00067     // Translate equalities into inequalities.
00068     for (Constraint_System::const_iterator i = ph_cs.begin(),
00069            i_end = ph_cs.end(); i != i_end; ++i) {
00070       const Constraint& c = *i;
00071       if (c.is_equality()) {
00072         // Insert the two corresponding opposing inequalities.
00073         cs.insert(Linear_Expression(c) >= 0);
00074         cs.insert(Linear_Expression(c) <= 0);
00075       }
00076       else
00077         // Insert as is.
00078         cs.insert(c);
00079     }
00080   }
00081   else
00082     // No equality constraints (and no strict inequalities).
00083     cs = ph_cs;
00084 }
00085 
00086 void
00087 shift_unprimed_variables(Constraint_System& cs) {
00088   const dimension_type cs_space_dim = cs.space_dimension();
00089   Constraint_System cs_shifted;
00090   for (Constraint_System::const_iterator i = cs.begin(),
00091          cs_end = cs.end(); i != cs_end; ++i) {
00092     const Constraint& c_i = *i;
00093     Linear_Expression le_i_shifted;
00094     for (dimension_type j = cs_space_dim; j-- > 0; ) {
00095       Coefficient_traits::const_reference a_i_j
00096         = c_i.coefficient(Variable(j));
00097       if (a_i_j != 0)
00098         add_mul_assign(le_i_shifted, a_i_j, Variable(cs_space_dim + j));
00099     }
00100     le_i_shifted += c_i.inhomogeneous_term();
00101     cs_shifted.insert(le_i_shifted >= 0);
00102   }
00103   cs.m_swap(cs_shifted);
00104 }
00105 
00145 void
00146 fill_constraint_systems_MS(const Constraint_System& cs,
00147                            Constraint_System& cs_out1,
00148                            Constraint_System& cs_out2) {
00149   PPL_ASSERT(cs.space_dimension() % 2 == 0);
00150   const dimension_type n = cs.space_dimension() / 2;
00151   const dimension_type m = num_constraints(cs);
00152 
00153 #if PRINT_DEBUG_INFO
00154   Variable::output_function_type* p_default_output_function
00155     = Variable::get_output_function();
00156   Variable::set_output_function(output_function_MS);
00157 
00158   output_function_MS_n = n;
00159   output_function_MS_m = m;
00160 
00161   std::cout << "*** cs ***" << std::endl;
00162   output_function_MS_which = 0;
00163   using namespace IO_Operators;
00164   std::cout << cs << std::endl;
00165 #endif
00166 
00167   dimension_type y_begin = n+1;
00168   dimension_type z_begin = y_begin + ((&cs_out1 == &cs_out2) ? m : 0);
00169 
00170   // Make sure linear expressions are not reallocated multiple times.
00171   Linear_Expression y_le(0*Variable(y_begin + m - 1));
00172   Linear_Expression z_le(0*Variable(z_begin + m + 2 - 1));
00173   std::vector<Linear_Expression> y_les(2*n, y_le);
00174   std::vector<Linear_Expression> z_les(2*n + 1, z_le);
00175 
00176   dimension_type y = y_begin;
00177   dimension_type z = z_begin;
00178   for (Constraint_System::const_iterator i = cs.begin(),
00179          cs_end = cs.end(); i != cs_end; ++i) {
00180     Variable v_y(y);
00181     Variable v_z(z);
00182     ++y;
00183     ++z;
00184     cs_out1.insert(v_y >= 0);
00185     cs_out2.insert(v_z >= 0);
00186     const Constraint& c_i = *i;
00187     Coefficient_traits::const_reference b_i = c_i.inhomogeneous_term();
00188     if (b_i != 0) {
00189       // Note that b_i is to the left ot the relation sign, hence here
00190       // we have -= and not += just to avoid negating b_i.
00191       sub_mul_assign(y_le, b_i, v_y);
00192       sub_mul_assign(z_le, b_i, v_z);
00193     }
00194     for (dimension_type j = 2*n; j-- > 0; ) {
00195       Coefficient_traits::const_reference a_i_j = c_i.coefficient(Variable(j));
00196       if (a_i_j != 0) {
00197         add_mul_assign(y_les[j], a_i_j, v_y);
00198         add_mul_assign(z_les[j], a_i_j, v_z);
00199       }
00200     }
00201   }
00202   z_le += Variable(z);
00203   z_les[2*n] += Variable(z);
00204   cs_out2.insert(Variable(z) >= 0);
00205   ++z;
00206   z_le -= Variable(z);
00207   z_les[2*n] -= Variable(z);
00208   cs_out2.insert(Variable(z) >= 0);
00209   cs_out1.insert(y_le >= 1);
00210   cs_out2.insert(z_le >= 0);
00211   dimension_type j = 2*n;
00212   while (j-- > n) {
00213     cs_out1.insert(y_les[j] == Variable(j-n));
00214     cs_out2.insert(z_les[j] == Variable(j-n));
00215   }
00216   ++j;
00217   while (j-- > 0) {
00218     cs_out1.insert(y_les[j] == -Variable(j));
00219     cs_out2.insert(z_les[j] == 0);
00220   }
00221   cs_out2.insert(z_les[2*n] == Variable(n));
00222 
00223 #if PRINT_DEBUG_INFO
00224   if (&cs_out1 == &cs_out2) {
00225     std::cout << "*** cs_mip ***" << std::endl;
00226     output_function_MS_which = 3;
00227     using namespace IO_Operators;
00228     std::cout << cs_mip << std::endl;
00229   }
00230   else {
00231     std::cout << "*** cs_out1 ***" << std::endl;
00232     output_function_MS_which = 1;
00233     using namespace IO_Operators;
00234     std::cout << cs_out1 << std::endl;
00235 
00236     std::cout << "*** cs_out2 ***" << std::endl;
00237     output_function_MS_which = 2;
00238     using namespace IO_Operators;
00239     std::cout << cs_out2 << std::endl;
00240   }
00241 
00242   Variable::set_output_function(p_default_output_function);
00243 #endif
00244 }
00245 
00357 void
00358 fill_constraint_system_PR(const Constraint_System& cs_before,
00359                           const Constraint_System& cs_after,
00360                           Constraint_System& cs_out,
00361                           Linear_Expression& le_out) {
00362   PPL_ASSERT(cs_after.space_dimension() % 2 == 0);
00363   PPL_ASSERT(2*cs_before.space_dimension() == cs_after.space_dimension());
00364   const dimension_type n = cs_before.space_dimension();
00365   const dimension_type r = num_constraints(cs_before);
00366   const dimension_type s = num_constraints(cs_after);
00367   const dimension_type m = r + s;
00368 
00369   // Make sure linear expressions are not reallocated multiple times.
00370   if (m > 0)
00371     le_out = 0 * Variable(m + r - 1);
00372   std::vector<Linear_Expression> les_eq(2*n, le_out);
00373 
00374   dimension_type row_index = 0;
00375   for (Constraint_System::const_iterator i = cs_before.begin(),
00376          cs_before_end = cs_before.end();
00377        i != cs_before_end;
00378        ++i, ++row_index) {
00379     Variable u1_i(m + row_index);
00380     Variable u2_i(s + row_index);
00381     const Constraint& c_i = *i;
00382     for (dimension_type j = n; j-- > 0; ) {
00383       Coefficient_traits::const_reference A_ij_B = c_i.coefficient(Variable(j));
00384       if (A_ij_B != 0) {
00385         // (u1 - u2) A_B, in the context of j-th constraint.
00386         add_mul_assign(les_eq[j], A_ij_B, u1_i);
00387         sub_mul_assign(les_eq[j], A_ij_B, u2_i);
00388         // u2 A_B, in the context of (j+n)-th constraint.
00389         add_mul_assign(les_eq[j + n], A_ij_B, u2_i);
00390       }
00391     }
00392     Coefficient_traits::const_reference b_B = c_i.inhomogeneous_term();
00393     if (b_B != 0)
00394       // u2 b_B, in the context of the strict inequality constraint.
00395       add_mul_assign(le_out, b_B, u2_i);
00396   }
00397 
00398   row_index = 0;
00399   for (Constraint_System::const_iterator i = cs_after.begin(),
00400          cs_after_end = cs_after.end();
00401        i != cs_after_end;
00402        ++i, ++row_index) {
00403     Variable u3_i(row_index);
00404     const Constraint& c_i = *i;
00405     for (dimension_type j = n; j-- > 0; ) {
00406       Coefficient_traits::const_reference
00407         A_ij_C = c_i.coefficient(Variable(j + n));
00408       if (A_ij_C != 0) {
00409         // - u3 A_C, in the context of the j-th constraint.
00410         sub_mul_assign(les_eq[j], A_ij_C, u3_i);
00411         // u3 A_C, in the context of the (j+n)-th constraint.
00412         add_mul_assign(les_eq[j+n], A_ij_C, u3_i);
00413       }
00414       Coefficient_traits::const_reference
00415         Ap_ij_C = c_i.coefficient(Variable(j));
00416       if (Ap_ij_C != 0)
00417         // u3 Ap_C, in the context of the (j+n)-th constraint.
00418         add_mul_assign(les_eq[j+n], Ap_ij_C, u3_i);
00419     }
00420     Coefficient_traits::const_reference b_C = c_i.inhomogeneous_term();
00421     if (b_C != 0)
00422       // u3 b_C, in the context of the strict inequality constraint.
00423       add_mul_assign(le_out, b_C, u3_i);
00424   }
00425 
00426   // Add the nonnegativity constraints for u_1, u_2 and u_3.
00427   for (dimension_type i = s + 2*r; i-- > 0; )
00428     cs_out.insert(Variable(i) >= 0);
00429 
00430   for (dimension_type j = 2*n; j-- > 0; )
00431     cs_out.insert(les_eq[j] == 0);
00432 }
00433 
00434 void
00435 fill_constraint_system_PR_original(const Constraint_System& cs,
00436                                    Constraint_System& cs_out,
00437                                    Linear_Expression& le_out) {
00438   PPL_ASSERT(cs.space_dimension() % 2 == 0);
00439   const dimension_type n = cs.space_dimension() / 2;
00440   const dimension_type m = num_constraints(cs);
00441 
00442   // Make sure linear expressions are not reallocated multiple times.
00443   if (m > 0)
00444     le_out = 0 * Variable(2*m - 1);
00445   std::vector<Linear_Expression> les_eq(3*n, le_out);
00446 
00447   dimension_type row_index = 0;
00448   for (Constraint_System::const_iterator i = cs.begin(),
00449          cs_end = cs.end(); i != cs_end; ++i, ++row_index) {
00450     const Constraint& c_i = *i;
00451     const Variable lambda1_i(row_index);
00452     const Variable lambda2_i(m + row_index);
00453     for (dimension_type j = n; j-- > 0; ) {
00454       Coefficient_traits::const_reference Ap_ij = c_i.coefficient(Variable(j));
00455       if (Ap_ij != 0) {
00456         // lambda_1 A'
00457         add_mul_assign(les_eq[j], Ap_ij, lambda1_i);
00458         // lambda_2 A'
00459         add_mul_assign(les_eq[j+n+n], Ap_ij, lambda2_i);
00460       }
00461       Coefficient_traits::const_reference A_ij = c_i.coefficient(Variable(j+n));
00462       if (A_ij != 0) {
00463         // (lambda_1 - lambda_2) A
00464         add_mul_assign(les_eq[j+n], A_ij, lambda1_i);
00465         sub_mul_assign(les_eq[j+n], A_ij, lambda2_i);
00466         // lambda_2 A
00467         add_mul_assign(les_eq[j+n+n], A_ij, lambda2_i);
00468       }
00469     }
00470     Coefficient_traits::const_reference b = c_i.inhomogeneous_term();
00471     if (b != 0)
00472       // lambda2 b
00473       add_mul_assign(le_out, b, lambda2_i);
00474   }
00475 
00476   // Add the non-negativity constraints for lambda_1 and lambda_2.
00477   for (dimension_type i = 2*m; i-- > 0; )
00478     cs_out.insert(Variable(i) >= 0);
00479 
00480   for (dimension_type j = 3*n; j-- > 0; )
00481     cs_out.insert(les_eq[j] == 0);
00482 }
00483 
00484 bool
00485 termination_test_MS(const Constraint_System& cs) {
00486   Constraint_System cs_mip;
00487   fill_constraint_systems_MS(cs, cs_mip, cs_mip);
00488 
00489   MIP_Problem mip = MIP_Problem(cs_mip.space_dimension(), cs_mip);
00490   return mip.is_satisfiable();
00491 }
00492 
00493 bool
00494 one_affine_ranking_function_MS(const Constraint_System& cs, Generator& mu) {
00495   Constraint_System cs_mip;
00496   fill_constraint_systems_MS(cs, cs_mip, cs_mip);
00497 
00498   MIP_Problem mip = MIP_Problem(cs_mip.space_dimension(), cs_mip);
00499   if (!mip.is_satisfiable())
00500     return false;
00501 
00502   Generator fp = mip.feasible_point();
00503   PPL_ASSERT(fp.is_point());
00504   Linear_Expression le;
00505   const dimension_type n = cs.space_dimension() / 2;
00506   for (dimension_type i = n+1; i-- > 0; ) {
00507     Variable vi(i);
00508     add_mul_assign(le, fp.coefficient(vi), vi);
00509   }
00510   mu = point(le, fp.divisor());
00511   return true;
00512 }
00513 
00514 void
00515 all_affine_ranking_functions_MS(const Constraint_System& cs,
00516                                 C_Polyhedron& mu_space) {
00517   Constraint_System cs_out1;
00518   Constraint_System cs_out2;
00519   fill_constraint_systems_MS(cs, cs_out1, cs_out2);
00520 
00521   C_Polyhedron ph1(cs_out1);
00522   C_Polyhedron ph2(cs_out2);
00523   const dimension_type n = cs.space_dimension() / 2;
00524   ph1.remove_higher_space_dimensions(n);
00525   ph1.add_space_dimensions_and_embed(1);
00526   ph2.remove_higher_space_dimensions(n+1);
00527 
00528 #if PRINT_DEBUG_INFO
00529   Variable::output_function_type* p_default_output_function
00530     = Variable::get_output_function();
00531   Variable::set_output_function(output_function_MS);
00532 
00533   output_function_MS_n = n;
00534   output_function_MS_m = num_constraints(cs);
00535 
00536   std::cout << "*** ph1 projected ***" << std::endl;
00537   output_function_MS_which = 4;
00538   using namespace IO_Operators;
00539   std::cout << ph1.minimized_constraints() << std::endl;
00540 
00541   std::cout << "*** ph2 projected ***" << std::endl;
00542   std::cout << ph2.minimized_constraints() << std::endl;
00543 #endif
00544 
00545   ph1.intersection_assign(ph2);
00546 
00547 #if PRINT_DEBUG_INFO
00548   std::cout << "*** intersection ***" << std::endl;
00549   using namespace IO_Operators;
00550   std::cout << ph1.minimized_constraints() << std::endl;
00551 
00552   Variable::set_output_function(p_default_output_function);
00553 #endif
00554 
00555   mu_space.m_swap(ph1);
00556 }
00557 
00558 void
00559 all_affine_quasi_ranking_functions_MS(const Constraint_System& cs,
00560                                       C_Polyhedron& decreasing_mu_space,
00561                                       C_Polyhedron& bounded_mu_space) {
00562   Constraint_System cs_out1;
00563   Constraint_System cs_out2;
00564   fill_constraint_systems_MS(cs, cs_out1, cs_out2);
00565 
00566   C_Polyhedron ph1(cs_out1);
00567   C_Polyhedron ph2(cs_out2);
00568   const dimension_type n = cs.space_dimension() / 2;
00569   ph1.remove_higher_space_dimensions(n);
00570   ph1.add_space_dimensions_and_embed(1);
00571   ph2.remove_higher_space_dimensions(n+1);
00572 
00573 #if PRINT_DEBUG_INFO
00574   Variable::output_function_type* p_default_output_function
00575     = Variable::get_output_function();
00576   Variable::set_output_function(output_function_MS);
00577 
00578   output_function_MS_n = n;
00579   output_function_MS_m = num_constraints(cs);
00580 
00581   std::cout << "*** ph1 projected ***" << std::endl;
00582   output_function_MS_which = 4;
00583   using namespace IO_Operators;
00584   std::cout << ph1.minimized_constraints() << std::endl;
00585 
00586   std::cout << "*** ph2 projected ***" << std::endl;
00587   std::cout << ph2.minimized_constraints() << std::endl;
00588 
00589   Variable::set_output_function(p_default_output_function);
00590 #endif
00591 
00592   decreasing_mu_space.m_swap(ph1);
00593   bounded_mu_space.m_swap(ph2);
00594 }
00595 
00596 bool
00597 termination_test_PR_original(const Constraint_System& cs) {
00598   PPL_ASSERT(cs.space_dimension() % 2 == 0);
00599 
00600   Constraint_System cs_mip;
00601   Linear_Expression le_ineq;
00602   fill_constraint_system_PR_original(cs, cs_mip, le_ineq);
00603 
00604   // Turn minimization problem into satisfiability.
00605   cs_mip.insert(le_ineq <= -1);
00606 
00607   MIP_Problem mip(cs_mip.space_dimension(), cs_mip);
00608   return mip.is_satisfiable();
00609 }
00610 
00611 bool
00612 termination_test_PR(const Constraint_System& cs_before,
00613                     const Constraint_System& cs_after) {
00614   Constraint_System cs_mip;
00615   Linear_Expression le_ineq;
00616   fill_constraint_system_PR(cs_before, cs_after, cs_mip, le_ineq);
00617 
00618 #if PRINT_DEBUG_INFO
00619   Variable::output_function_type* p_default_output_function
00620     = Variable::get_output_function();
00621   Variable::set_output_function(output_function_PR);
00622 
00623   output_function_PR_r = num_constraints(cs_before);
00624   output_function_PR_s = num_constraints(cs_after);
00625 
00626   std::cout << "*** cs_mip ***" << std::endl;
00627   using namespace IO_Operators;
00628   std::cout << cs_mip << std::endl;
00629   std::cout << "*** le_ineq ***" << std::endl;
00630   std::cout << le_ineq << std::endl;
00631 
00632   Variable::set_output_function(p_default_output_function);
00633 #endif
00634 
00635   // Turn minimization problem into satisfiability.
00636   cs_mip.insert(le_ineq <= -1);
00637 
00638   MIP_Problem mip(cs_mip.space_dimension(), cs_mip);
00639   return mip.is_satisfiable();
00640 }
00641 
00642 bool
00643 one_affine_ranking_function_PR(const Constraint_System& cs_before,
00644                                const Constraint_System& cs_after,
00645                                Generator& mu) {
00646   Constraint_System cs_mip;
00647   Linear_Expression le_ineq;
00648   fill_constraint_system_PR(cs_before, cs_after, cs_mip, le_ineq);
00649 
00650 #if PRINT_DEBUG_INFO
00651   Variable::output_function_type* p_default_output_function
00652     = Variable::get_output_function();
00653   Variable::set_output_function(output_function_PR);
00654 
00655   output_function_PR_r = num_constraints(cs_before);
00656   output_function_PR_s = num_constraints(cs_after);
00657 
00658   std::cout << "*** cs_mip ***" << std::endl;
00659   using namespace IO_Operators;
00660   std::cout << cs_mip << std::endl;
00661   std::cout << "*** le_ineq ***" << std::endl;
00662   std::cout << le_ineq << std::endl;
00663 
00664   Variable::set_output_function(p_default_output_function);
00665 #endif
00666 
00667   // Turn minimization problem into satisfiability.
00668   cs_mip.insert(le_ineq <= -1);
00669 
00670   MIP_Problem mip(cs_mip.space_dimension(), cs_mip);
00671   if (!mip.is_satisfiable())
00672     return false;
00673 
00674   Generator fp = mip.feasible_point();
00675   PPL_ASSERT(fp.is_point());
00676 
00677   // u_3 corresponds to space dimensions 0, ..., s - 1.
00678   const dimension_type n = cs_before.space_dimension();
00679   Linear_Expression le;
00680   // mu_0 is zero: do this first to avoid reallocations.
00681   le += 0*Variable(n);
00682   // Multiply u_3 by E'_C to obtain mu_1, ..., mu_n.
00683   dimension_type row_index = 0;
00684   PPL_DIRTY_TEMP_COEFFICIENT(k);
00685   for (Constraint_System::const_iterator i = cs_after.begin(),
00686          cs_after_end = cs_after.end();
00687        i != cs_after_end;
00688        ++i, ++row_index) {
00689     Variable vi(row_index);
00690     Coefficient_traits::const_reference fp_i = fp.coefficient(vi);
00691     const Constraint& c_i = *i;
00692     for (dimension_type j = n; j-- > 0; ) {
00693       Variable vj(j);
00694       k = fp_i * c_i.coefficient(vj);
00695       sub_mul_assign(le, k, vj);
00696     }
00697   }
00698   // Note that we can neglect the divisor of `fp' since it is positive.
00699   mu = point(le);
00700   return true;
00701 }
00702 
00703 bool
00704 one_affine_ranking_function_PR_original(const Constraint_System& cs,
00705                                         Generator& mu) {
00706   PPL_ASSERT(cs.space_dimension() % 2 == 0);
00707   const dimension_type n = cs.space_dimension() / 2;
00708   const dimension_type m = num_constraints(cs);
00709 
00710   Constraint_System cs_mip;
00711   Linear_Expression le_ineq;
00712   fill_constraint_system_PR_original(cs, cs_mip, le_ineq);
00713 
00714 #if PRINT_DEBUG_INFO
00715   std::cout << "*** cs_mip ***" << std::endl;
00716   using namespace IO_Operators;
00717   std::cout << cs_mip << std::endl;
00718   std::cout << "*** le_ineq ***" << std::endl;
00719   std::cout << le_ineq << std::endl;
00720 #endif
00721 
00722   // Turn minimization problem into satisfiability.
00723   cs_mip.insert(le_ineq <= -1);
00724 
00725   MIP_Problem mip = MIP_Problem(cs_mip.space_dimension(), cs_mip);
00726   if (!mip.is_satisfiable())
00727     return false;
00728 
00729   Generator fp = mip.feasible_point();
00730   PPL_ASSERT(fp.is_point());
00731   Linear_Expression le;
00732   // mu_0 is zero: do this first to avoid reallocations.
00733   le += 0*Variable(n);
00734   // Multiply -lambda_2 by A' to obtain mu_1, ..., mu_n.
00735   // lambda_2 corresponds to space dimensions m, ..., 2*m - 1.
00736   dimension_type row_index = m;
00737   PPL_DIRTY_TEMP_COEFFICIENT(k);
00738   for (Constraint_System::const_iterator i = cs.begin(),
00739          cs_end = cs.end(); i != cs_end; ++i, ++row_index) {
00740     Variable lambda_2(row_index);
00741     Coefficient_traits::const_reference fp_i = fp.coefficient(lambda_2);
00742     if (fp_i != 0) {
00743       const Constraint& c_i = *i;
00744       for (dimension_type j = n; j-- > 0; ) {
00745         Variable vj(j);
00746         Coefficient_traits::const_reference Ap_ij = c_i.coefficient(vj);
00747         k = fp_i * Ap_ij;
00748         sub_mul_assign(le, k, vj);
00749       }
00750     }
00751   }
00752   // Note that we can neglect the divisor of `fp' since it is positive.
00753   mu = point(le);
00754   return true;
00755 }
00756 
00757 void
00758 all_affine_ranking_functions_PR(const Constraint_System& cs_before,
00759                                 const Constraint_System& cs_after,
00760                                 NNC_Polyhedron& mu_space) {
00761   Constraint_System cs_eqs;
00762   Linear_Expression le_ineq;
00763   fill_constraint_system_PR(cs_before, cs_after, cs_eqs, le_ineq);
00764 
00765 #if PRINT_DEBUG_INFO
00766   Variable::output_function_type* p_default_output_function
00767     = Variable::get_output_function();
00768   Variable::set_output_function(output_function_PR);
00769 
00770   output_function_PR_r = num_constraints(cs_before);
00771   output_function_PR_s = num_constraints(cs_after);
00772 
00773   std::cout << "*** cs_eqs ***" << std::endl;
00774   using namespace IO_Operators;
00775   std::cout << cs_eqs << std::endl;
00776   std::cout << "*** le_ineq ***" << std::endl;
00777   std::cout << le_ineq << std::endl;
00778 #endif
00779 
00780   NNC_Polyhedron ph(cs_eqs);
00781   ph.add_constraint(le_ineq < 0);
00782   // u_3 corresponds to space dimensions 0, ..., s - 1.
00783   const dimension_type s = num_constraints(cs_after);
00784   ph.remove_higher_space_dimensions(s);
00785 
00786 #if PRINT_DEBUG_INFO
00787   std::cout << "*** ph ***" << std::endl;
00788   std::cout << ph << std::endl;
00789 
00790   Variable::set_output_function(p_default_output_function);
00791 #endif
00792 
00793   const dimension_type n = cs_before.space_dimension();
00794 
00795   const Generator_System& gs_in = ph.generators();
00796   Generator_System gs_out;
00797   Generator_System::const_iterator gs_in_it = gs_in.begin();
00798   Generator_System::const_iterator gs_in_end = gs_in.end();
00799   if (gs_in_it == gs_in_end)
00800     // The system is unsatisfiable.
00801     mu_space = NNC_Polyhedron(n + 1, EMPTY);
00802   else {
00803     for ( ; gs_in_it != gs_in_end; ++gs_in_it) {
00804       const Generator& g = *gs_in_it;
00805       Linear_Expression le;
00806       // Set le to the multiplication of Linear_Expression(g) by E'_C.
00807       dimension_type row_index = 0;
00808       PPL_DIRTY_TEMP_COEFFICIENT(k);
00809       for (Constraint_System::const_iterator i = cs_after.begin(),
00810              cs_after_end = cs_after.end();
00811            i != cs_after_end;
00812            ++i, ++row_index) {
00813         Variable vi(row_index);
00814         Coefficient_traits::const_reference g_i = g.coefficient(vi);
00815         if (g_i != 0) {
00816           const Constraint& c_i = *i;
00817           for (dimension_type j = n; j-- > 0; ) {
00818             Variable vj(j);
00819             k = g_i * c_i.coefficient(vj);
00820             sub_mul_assign(le, k, vj);
00821           }
00822         }
00823       }
00824 
00825       // Add to gs_out the transformed generator.
00826       switch (g.type()) {
00827       case Generator::LINE:
00828         if (!le.all_homogeneous_terms_are_zero())
00829           gs_out.insert(line(le));
00830         break;
00831       case Generator::RAY:
00832         if (!le.all_homogeneous_terms_are_zero())
00833           gs_out.insert(ray(le));
00834         break;
00835       case Generator::POINT:
00836         gs_out.insert(point(le, g.divisor()));
00837         break;
00838       case Generator::CLOSURE_POINT:
00839         gs_out.insert(closure_point(le, g.divisor()));
00840         break;
00841       }
00842     }
00843 
00844     mu_space = NNC_Polyhedron(gs_out);
00845     // mu_0 is zero.
00846     mu_space.add_space_dimensions_and_embed(1);
00847   }
00848 }
00849 
00850 void
00851 all_affine_ranking_functions_PR_original(const Constraint_System& cs,
00852                                          NNC_Polyhedron& mu_space) {
00853   PPL_ASSERT(cs.space_dimension() % 2 == 0);
00854   const dimension_type n = cs.space_dimension() / 2;
00855   const dimension_type m = num_constraints(cs);
00856 
00857   if (m == 0) {
00858     // If there are no constraints at all, we have non-termination,
00859     // i.e., no affine ranking function at all.
00860     mu_space = NNC_Polyhedron(n + 1, EMPTY);
00861     return;
00862   }
00863 
00864   Constraint_System cs_eqs;
00865   Linear_Expression le_ineq;
00866   fill_constraint_system_PR_original(cs, cs_eqs, le_ineq);
00867 
00868   NNC_Polyhedron ph(cs_eqs);
00869   ph.add_constraint(le_ineq < 0);
00870   // lambda_2 corresponds to space dimensions m, ..., 2*m-1.
00871   Variables_Set lambda1(Variable(0), Variable(m-1));
00872   ph.remove_space_dimensions(lambda1);
00873 
00874 #if PRINT_DEBUG_INFO
00875   std::cout << "*** ph ***" << std::endl;
00876   std::cout << ph << std::endl;
00877 
00878   Variable::set_output_function(p_default_output_function);
00879 #endif
00880 
00881   const Generator_System& gs_in = ph.generators();
00882   Generator_System::const_iterator gs_in_it = gs_in.begin();
00883   Generator_System::const_iterator gs_in_end = gs_in.end();
00884   if (gs_in_it == gs_in_end)
00885     // The system is unsatisfiable.
00886     mu_space = NNC_Polyhedron(n + 1, EMPTY);
00887   else {
00888     Generator_System gs_out;
00889     for ( ; gs_in_it != gs_in_end; ++gs_in_it) {
00890       const Generator& g = *gs_in_it;
00891       Linear_Expression le;
00892       // Set le to the multiplication of Linear_Expression(g) by E'_C.
00893       dimension_type row_index = 0;
00894       PPL_DIRTY_TEMP_COEFFICIENT(k);
00895       for (Constraint_System::const_iterator i = cs.begin(),
00896              cs_end = cs.end(); i != cs_end; ++i, ++row_index) {
00897         Variable lambda2_i(row_index);
00898         Coefficient_traits::const_reference g_i = g.coefficient(lambda2_i);
00899         if (g_i != 0) {
00900           const Constraint& c_i = *i;
00901           for (dimension_type j = n; j-- > 0; ) {
00902             Variable vj(j);
00903             Coefficient_traits::const_reference Ap_ij = c_i.coefficient(vj);
00904             k = g_i * Ap_ij;
00905             sub_mul_assign(le, k, vj);
00906           }
00907         }
00908       }
00909 
00910       // Add to gs_out the transformed generator.
00911       switch (g.type()) {
00912       case Generator::LINE:
00913         if (!le.all_homogeneous_terms_are_zero())
00914           gs_out.insert(line(le));
00915         break;
00916       case Generator::RAY:
00917         if (!le.all_homogeneous_terms_are_zero())
00918           gs_out.insert(ray(le));
00919         break;
00920       case Generator::POINT:
00921         gs_out.insert(point(le, g.divisor()));
00922         break;
00923       case Generator::CLOSURE_POINT:
00924         gs_out.insert(closure_point(le, g.divisor()));
00925         break;
00926       }
00927     }
00928 
00929     mu_space = NNC_Polyhedron(gs_out);
00930     // mu_0 is zero.
00931     mu_space.add_space_dimensions_and_embed(1);
00932   }
00933 }
00934 
00935 } // namespace Termination
00936 
00937 } // namespace Implementation
00938 
00939 } // namespace Parma_Polyhedra_Library