PPL  0.12.1
MIP_Problem.cc
Go to the documentation of this file.
00001 /* MIP_Problem class implementation: non-inline 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 "MIP_Problem.defs.hh"
00026 #include "globals.defs.hh"
00027 #include "Checked_Number.defs.hh"
00028 #include "Linear_Expression.defs.hh"
00029 #include "Constraint.defs.hh"
00030 #include "Constraint_System.defs.hh"
00031 #include "Constraint_System.inlines.hh"
00032 #include "Generator.defs.hh"
00033 #include "Scalar_Products.defs.hh"
00034 #include <stdexcept>
00035 #include <deque>
00036 #include <vector>
00037 #include <algorithm>
00038 #include <cmath>
00039 
00040 // TODO: Remove this when the sparse working cost has been tested enough.
00041 #if PPL_USE_SPARSE_MATRIX
00042 
00043 // These are needed for the linear_combine() method that takes a Dense_Row and
00044 // a Sparse_Row.
00045 #include "Dense_Row.defs.hh"
00046 #include "Sparse_Row.defs.hh"
00047 
00048 #endif // PPL_USE_SPARSE_MATRIX
00049 
00050 #ifndef PPL_NOISY_SIMPLEX
00051 #define PPL_NOISY_SIMPLEX 0
00052 #endif
00053 
00054 #ifndef PPL_SIMPLEX_USE_MIP_HEURISTIC
00055 #define PPL_SIMPLEX_USE_MIP_HEURISTIC 1
00056 #endif
00057 
00058 #if PPL_NOISY_SIMPLEX
00059 #include <iostream>
00060 #endif
00061 
00062 
00063 namespace PPL = Parma_Polyhedra_Library;
00064 
00065 #if PPL_NOISY_SIMPLEX
00066 namespace {
00067 
00068 unsigned long num_iterations = 0;
00069 
00070 unsigned mip_recursion_level = 0;
00071 
00072 } // namespace
00073 #endif // PPL_NOISY_SIMPLEX
00074 
00075 PPL::MIP_Problem::MIP_Problem(const dimension_type dim)
00076   : external_space_dim(dim),
00077     internal_space_dim(0),
00078     tableau(),
00079     working_cost(0, Row_Flags()),
00080     mapping(),
00081     base(),
00082     status(PARTIALLY_SATISFIABLE),
00083     pricing(PRICING_STEEPEST_EDGE_FLOAT),
00084     initialized(false),
00085     input_cs(),
00086     inherited_constraints(0),
00087     first_pending_constraint(0),
00088     input_obj_function(),
00089     opt_mode(MAXIMIZATION),
00090     last_generator(point()),
00091     i_variables() {
00092   // Check for space dimension overflow.
00093   if (dim > max_space_dimension())
00094     throw std::length_error("PPL::MIP_Problem::MIP_Problem(dim, cs, obj, "
00095                             "mode):\n"
00096                             "dim exceeds the maximum allowed "
00097                             "space dimension.");
00098   PPL_ASSERT(OK());
00099 }
00100 
00101 PPL::MIP_Problem::MIP_Problem(const dimension_type dim,
00102                               const Constraint_System& cs,
00103                               const Linear_Expression& obj,
00104                               const Optimization_Mode mode)
00105   : external_space_dim(dim),
00106     internal_space_dim(0),
00107     tableau(),
00108     working_cost(0, Row_Flags()),
00109     mapping(),
00110     base(),
00111     status(PARTIALLY_SATISFIABLE),
00112     pricing(PRICING_STEEPEST_EDGE_FLOAT),
00113     initialized(false),
00114     input_cs(),
00115     inherited_constraints(0),
00116     first_pending_constraint(0),
00117     input_obj_function(obj),
00118     opt_mode(mode),
00119     last_generator(point()),
00120     i_variables() {
00121   // Check for space dimension overflow.
00122   if (dim > max_space_dimension())
00123     throw std::length_error("PPL::MIP_Problem::MIP_Problem(dim, cs, obj, "
00124                             "mode):\n"
00125                             "dim exceeds the maximum allowed"
00126                             "space dimension.");
00127   // Check the objective function.
00128   if (obj.space_dimension() > dim) {
00129     std::ostringstream s;
00130     s << "PPL::MIP_Problem::MIP_Problem(dim, cs, obj,"
00131       << " mode):\n"
00132       << "obj.space_dimension() == "<< obj.space_dimension()
00133       << " exceeds dim == "<< dim << ".";
00134     throw std::invalid_argument(s.str());
00135   }
00136   // Check the constraint system.
00137   if (cs.space_dimension() > dim) {
00138     std::ostringstream s;
00139     s << "PPL::MIP_Problem::MIP_Problem(dim, cs, obj, mode):\n"
00140       << "cs.space_dimension == " << cs.space_dimension()
00141       << " exceeds dim == " << dim << ".";
00142     throw std::invalid_argument(s.str());
00143   }
00144   if (cs.has_strict_inequalities())
00145     throw std::invalid_argument("PPL::MIP_Problem::"
00146                                 "MIP_Problem(d, cs, obj, m):\n"
00147                                 "cs contains strict inequalities.");
00148   // Actually copy the constraints.
00149   for (Constraint_System::const_iterator
00150          i = cs.begin(), i_end = cs.end(); i != i_end; ++i)
00151     add_constraint_helper(*i);
00152 
00153   PPL_ASSERT(OK());
00154 }
00155 
00156 void
00157 PPL::MIP_Problem::add_constraint(const Constraint& c) {
00158   if (space_dimension() < c.space_dimension()) {
00159     std::ostringstream s;
00160     s << "PPL::MIP_Problem::add_constraint(c):\n"
00161       << "c.space_dimension() == "<< c.space_dimension() << " exceeds "
00162          "this->space_dimension == " << space_dimension() << ".";
00163     throw std::invalid_argument(s.str());
00164   }
00165   if (c.is_strict_inequality())
00166     throw std::invalid_argument("PPL::MIP_Problem::add_constraint(c):\n"
00167                                 "c is a strict inequality.");
00168   add_constraint_helper(c);
00169   if (status != UNSATISFIABLE)
00170     status = PARTIALLY_SATISFIABLE;
00171   PPL_ASSERT(OK());
00172 }
00173 
00174 void
00175 PPL::MIP_Problem::add_constraints(const Constraint_System& cs) {
00176   if (space_dimension() < cs.space_dimension()) {
00177     std::ostringstream s;
00178     s << "PPL::MIP_Problem::add_constraints(cs):\n"
00179       << "cs.space_dimension() == " << cs.space_dimension()
00180       << " exceeds this->space_dimension() == " << this->space_dimension()
00181       << ".";
00182     throw std::invalid_argument(s.str());
00183   }
00184   if (cs.has_strict_inequalities())
00185     throw std::invalid_argument("PPL::MIP_Problem::add_constraints(cs):\n"
00186                                 "cs contains strict inequalities.");
00187   for (Constraint_System::const_iterator
00188          i = cs.begin(), i_end = cs.end(); i != i_end; ++i)
00189     add_constraint_helper(*i);
00190   if (status != UNSATISFIABLE)
00191     status = PARTIALLY_SATISFIABLE;
00192   PPL_ASSERT(OK());
00193 }
00194 
00195 void
00196 PPL::MIP_Problem::set_objective_function(const Linear_Expression& obj) {
00197   if (space_dimension() < obj.space_dimension()) {
00198     std::ostringstream s;
00199     s << "PPL::MIP_Problem::set_objective_function(obj):\n"
00200       << "obj.space_dimension() == " << obj.space_dimension()
00201       << " exceeds this->space_dimension == " << space_dimension()
00202       << ".";
00203     throw std::invalid_argument(s.str());
00204   }
00205   input_obj_function = obj;
00206   if (status == UNBOUNDED || status == OPTIMIZED)
00207     status = SATISFIABLE;
00208   PPL_ASSERT(OK());
00209 }
00210 
00211 const PPL::Generator&
00212 PPL::MIP_Problem::feasible_point() const {
00213   if (is_satisfiable())
00214     return last_generator;
00215   else
00216     throw std::domain_error("PPL::MIP_Problem::feasible_point():\n"
00217                             "*this is not satisfiable.");
00218 }
00219 
00220 const PPL::Generator&
00221 PPL::MIP_Problem::optimizing_point() const {
00222   if (solve() == OPTIMIZED_MIP_PROBLEM)
00223     return last_generator;
00224   else
00225     throw std::domain_error("PPL::MIP_Problem::optimizing_point():\n"
00226                             "*this does not have an optimizing point.");
00227 }
00228 
00229 bool
00230 PPL::MIP_Problem::is_satisfiable() const {
00231   // Check `status' to filter out trivial cases.
00232   switch (status) {
00233   case UNSATISFIABLE:
00234     PPL_ASSERT(OK());
00235     return false;
00236   case SATISFIABLE:
00237     // Intentionally fall through
00238   case UNBOUNDED:
00239     // Intentionally fall through.
00240   case OPTIMIZED:
00241     PPL_ASSERT(OK());
00242     return true;
00243   case PARTIALLY_SATISFIABLE:
00244     {
00245       MIP_Problem& x = const_cast<MIP_Problem&>(*this);
00246       // LP case.
00247       if (x.i_variables.empty())
00248         return x.is_lp_satisfiable();
00249 
00250       // MIP case.
00251       {
00252         // Temporarily relax the MIP into an LP problem.
00253         RAII_Temporary_Real_Relaxation relaxed(x);
00254         Generator p = point();
00255         relaxed.lp.is_lp_satisfiable();
00256 #if PPL_NOISY_SIMPLEX
00257         mip_recursion_level = 0;
00258 #endif // PPL_NOISY_SIMPLEX
00259         if (is_mip_satisfiable(relaxed.lp, relaxed.i_vars, p)) {
00260           x.last_generator = p;
00261           x.status = SATISFIABLE;
00262         }
00263         else
00264           x.status = UNSATISFIABLE;
00265       } // `relaxed' destroyed here: relaxation automatically reset.
00266       return (x.status == SATISFIABLE);
00267     }
00268   }
00269   // We should not be here!
00270   PPL_UNREACHABLE;
00271   return false;
00272 }
00273 
00274 PPL::MIP_Problem_Status
00275 PPL::MIP_Problem::solve() const{
00276   switch (status) {
00277   case UNSATISFIABLE:
00278     PPL_ASSERT(OK());
00279     return UNFEASIBLE_MIP_PROBLEM;
00280   case UNBOUNDED:
00281     PPL_ASSERT(OK());
00282     return UNBOUNDED_MIP_PROBLEM;
00283   case OPTIMIZED:
00284     PPL_ASSERT(OK());
00285     return OPTIMIZED_MIP_PROBLEM;
00286   case SATISFIABLE:
00287     // Intentionally fall through
00288   case PARTIALLY_SATISFIABLE:
00289     {
00290       MIP_Problem& x = const_cast<MIP_Problem&>(*this);
00291       if (x.i_variables.empty()) {
00292         // LP case.
00293         if (x.is_lp_satisfiable()) {
00294           x.second_phase();
00295           if (x.status == UNBOUNDED)
00296             return UNBOUNDED_MIP_PROBLEM;
00297           else {
00298             PPL_ASSERT(x.status == OPTIMIZED);
00299             return OPTIMIZED_MIP_PROBLEM;
00300           }
00301         }
00302         return UNFEASIBLE_MIP_PROBLEM;
00303       }
00304 
00305       // MIP case.
00306       MIP_Problem_Status return_value;
00307       Generator g = point();
00308       {
00309         // Temporarily relax the MIP into an LP problem.
00310         RAII_Temporary_Real_Relaxation relaxed(x);
00311         if (relaxed.lp.is_lp_satisfiable())
00312           relaxed.lp.second_phase();
00313         else {
00314           x.status = UNSATISFIABLE;
00315           // NOTE: `relaxed' destroyed: relaxation automatically reset.
00316           return UNFEASIBLE_MIP_PROBLEM;
00317         }
00318         PPL_DIRTY_TEMP(mpq_class, incumbent_solution);
00319         bool have_incumbent_solution = false;
00320 
00321         MIP_Problem lp_copy(relaxed.lp, Inherit_Constraints());
00322         PPL_ASSERT(lp_copy.integer_space_dimensions().empty());
00323         return_value = solve_mip(have_incumbent_solution,
00324                                  incumbent_solution, g,
00325                                  lp_copy, relaxed.i_vars);
00326       } // `relaxed' destroyed here: relaxation automatically reset.
00327 
00328       switch (return_value) {
00329       case UNFEASIBLE_MIP_PROBLEM:
00330         x.status = UNSATISFIABLE;
00331         break;
00332       case UNBOUNDED_MIP_PROBLEM:
00333         x.status = UNBOUNDED;
00334         // A feasible point has been set in `solve_mip()', so that
00335         // a call to `feasible_point' will be successful.
00336         x.last_generator = g;
00337         break;
00338       case OPTIMIZED_MIP_PROBLEM:
00339         x.status = OPTIMIZED;
00340         // Set the internal generator.
00341         x.last_generator = g;
00342         break;
00343       }
00344       PPL_ASSERT(OK());
00345       return return_value;
00346     }
00347   }
00348   // We should not be here!
00349   PPL_UNREACHABLE;
00350   return UNFEASIBLE_MIP_PROBLEM;
00351 }
00352 
00353 void
00354 PPL::MIP_Problem::add_space_dimensions_and_embed(const dimension_type m) {
00355   // The space dimension of the resulting MIP problem should not
00356   // overflow the maximum allowed space dimension.
00357   if (m > max_space_dimension() - space_dimension())
00358     throw std::length_error("PPL::MIP_Problem::"
00359                             "add_space_dimensions_and_embed(m):\n"
00360                             "adding m new space dimensions exceeds "
00361                             "the maximum allowed space dimension.");
00362   external_space_dim += m;
00363   if (status != UNSATISFIABLE)
00364     status = PARTIALLY_SATISFIABLE;
00365   PPL_ASSERT(OK());
00366 }
00367 
00368 void
00369 PPL::MIP_Problem
00370 ::add_to_integer_space_dimensions(const Variables_Set& i_vars) {
00371   if (i_vars.space_dimension() > external_space_dim)
00372     throw std::invalid_argument("PPL::MIP_Problem::"
00373                                 "add_to_integer_space_dimension(i_vars):\n"
00374                                 "*this and i_vars are dimension"
00375                                 "incompatible.");
00376   const dimension_type original_size = i_variables.size();
00377   i_variables.insert(i_vars.begin(), i_vars.end());
00378   // If a new integral variable was inserted, set the internal status to
00379   // PARTIALLY_SATISFIABLE.
00380   if (i_variables.size() != original_size && status != UNSATISFIABLE)
00381     status = PARTIALLY_SATISFIABLE;
00382 }
00383 
00384 bool
00385 PPL::MIP_Problem::is_in_base(const dimension_type var_index,
00386                              dimension_type& row_index) const {
00387   for (row_index = base.size(); row_index-- > 0; )
00388     if (base[row_index] == var_index)
00389       return true;
00390   return false;
00391 }
00392 
00393 PPL::dimension_type
00394 PPL::MIP_Problem::merge_split_variable(dimension_type var_index) {
00395   // Initialize the return value to a dummy index.
00396   dimension_type unfeasible_tableau_row = not_a_dimension();
00397 
00398   const dimension_type removing_column = mapping[1+var_index].second;
00399 
00400   // Check if the negative part of the split variable is in base:
00401   // if so, the corresponding row of the tableau becomes non-feasible.
00402   {
00403     dimension_type base_index;
00404     if (is_in_base(removing_column, base_index)) {
00405       // Set the return value.
00406       unfeasible_tableau_row = base_index;
00407       // Reset base[base_index] to zero to remember non-feasibility.
00408       base[base_index] = 0;
00409       // Since the negative part of the variable is in base,
00410       // the positive part can not be in base too.
00411       PPL_ASSERT(!is_in_base(mapping[1+var_index].first, base_index));
00412     }
00413   }
00414 
00415   tableau.remove_column(removing_column);
00416 
00417   // var_index is no longer split.
00418   mapping[1+var_index].second = 0;
00419 
00420   // Adjust data structures, `shifting' the proper columns to the left by 1.
00421   const dimension_type base_size = base.size();
00422   for (dimension_type i = base_size; i-- > 0; ) {
00423     if (base[i] > removing_column)
00424       --base[i];
00425   }
00426   const dimension_type mapping_size = mapping.size();
00427   for (dimension_type i = mapping_size; i-- > 0; ) {
00428     if (mapping[i].first > removing_column)
00429       --mapping[i].first;
00430     if (mapping[i].second > removing_column)
00431       --mapping[i].second;
00432   }
00433 
00434   return unfeasible_tableau_row;
00435 }
00436 
00437 bool
00438 PPL::MIP_Problem::is_satisfied(const Constraint& c, const Generator& g) {
00439   // Scalar_Products::sign() requires the second argument to be at least
00440   // as large as the first one.
00441   int sp_sign
00442     = (g.space_dimension() <= c.space_dimension())
00443     ? Scalar_Products::sign(g, c)
00444     : Scalar_Products::sign(c, g);
00445   return c.is_inequality() ? (sp_sign >= 0) : (sp_sign == 0);
00446 }
00447 
00448 bool
00449 PPL::MIP_Problem::is_saturated(const Constraint& c, const Generator& g) {
00450   // Scalar_Products::sign() requires the space dimension of the second
00451   // argument to be at least as large as the one of the first one.
00452   int sp_sign
00453     = (g.space_dimension() <= c.space_dimension())
00454     ? Scalar_Products::sign(g, c)
00455     : Scalar_Products::sign(c, g);
00456   return sp_sign == 0;
00457 }
00458 
00459 bool
00460 PPL::MIP_Problem
00461 ::parse_constraints(dimension_type& additional_tableau_rows,
00462                     dimension_type& additional_slack_variables,
00463                     std::deque<bool>& is_tableau_constraint,
00464                     std::deque<bool>& is_satisfied_inequality,
00465                     std::deque<bool>& is_nonnegative_variable,
00466                     std::deque<bool>& is_remergeable_variable) const {
00467   // Initially all containers are empty.
00468   PPL_ASSERT(is_tableau_constraint.empty()
00469              && is_satisfied_inequality.empty()
00470              && is_nonnegative_variable.empty()
00471              && is_remergeable_variable.empty());
00472 
00473   const dimension_type cs_space_dim = external_space_dim;
00474   const dimension_type cs_num_rows = input_cs.size();
00475   const dimension_type cs_num_pending
00476     = cs_num_rows - first_pending_constraint;
00477 
00478   // Counters determining the change in dimensions of the tableau:
00479   // initialized here, they will be updated while examining `input_cs'.
00480   additional_tableau_rows = cs_num_pending;
00481   additional_slack_variables = 0;
00482 
00483   // Resize containers appropriately.
00484 
00485   // On exit, `is_tableau_constraint[i]' will be true if and only if
00486   // `input_cs[first_pending_constraint + i]' is neither a tautology
00487   // (e.g., 1 >= 0) nor a non-negativity constraint (e.g., X >= 0).
00488   is_tableau_constraint.insert(is_tableau_constraint.end(),
00489                                cs_num_pending, true);
00490 
00491   // On exit, `is_satisfied_inequality[i]' will be true if and only if
00492   // `input_cs[first_pending_constraint + i]' is an inequality and it is
00493   // satisfied by `last_generator'.
00494   is_satisfied_inequality.insert(is_satisfied_inequality.end(),
00495                                  cs_num_pending, false);
00496 
00497   // On exit, `is_nonnegative_variable[j]' will be true if and only if
00498   // Variable(j) is bound to be nonnegative in `input_cs'.
00499   is_nonnegative_variable.insert(is_nonnegative_variable.end(),
00500                                  cs_space_dim, false);
00501 
00502   // On exit, `is_remergeable_variable[j]' will be true if and only if
00503   // Variable(j) was initially split and is now remergeable.
00504   is_remergeable_variable.insert(is_remergeable_variable.end(),
00505                                  internal_space_dim, false);
00506 
00507   // Check for variables that are already known to be nonnegative
00508   // due to non-pending constraints.
00509   const dimension_type mapping_size = mapping.size();
00510   if (mapping_size > 0) {
00511     // Note: mapping[0] is associated to the cost function.
00512     for (dimension_type i = std::min(mapping_size - 1, cs_space_dim);
00513          i-- > 0; )
00514       if (mapping[i + 1].second == 0)
00515         is_nonnegative_variable[i] = true;
00516   }
00517 
00518   // Process each pending constraint in `input_cs' and
00519   //  - detect variables that are constrained to be nonnegative;
00520   //  - detect (non-negativity or tautology) pending constraints that
00521   //    will not be part of the tableau;
00522   //  - count the number of new slack variables.
00523   for (dimension_type i = cs_num_rows; i-- > first_pending_constraint; ) {
00524     const Constraint& cs_i = *(input_cs[i]);
00525     bool found_a_nonzero_coeff = false;
00526     bool found_many_nonzero_coeffs = false;
00527     dimension_type nonzero_coeff_column_index = 0;
00528     for (dimension_type sd = cs_i.space_dimension(); sd-- > 0; ) {
00529       if (cs_i.coefficient(Variable(sd)) != 0) {
00530         if (found_a_nonzero_coeff) {
00531           found_many_nonzero_coeffs = true;
00532           if (cs_i.is_inequality())
00533             ++additional_slack_variables;
00534           break;
00535         }
00536         else {
00537           nonzero_coeff_column_index = sd + 1;
00538           found_a_nonzero_coeff = true;
00539         }
00540       }
00541     }
00542     // If more than one coefficient is nonzero,
00543     // continue with next constraint.
00544     if (found_many_nonzero_coeffs) {
00545       // CHECKME: Is it true that in the first phase we can apply
00546       // `is_satisfied()' with the generator `point()'?  If so, the following
00547       // code works even if we do not have a feasible point.
00548       // Check for satisfiability of the inequality. This can be done if we
00549       // have a feasible point of *this.
00550       if (cs_i.is_inequality() && is_satisfied(cs_i, last_generator))
00551         is_satisfied_inequality[i - first_pending_constraint] = true;
00552       continue;
00553     }
00554 
00555     if (!found_a_nonzero_coeff) {
00556       // All coefficients are 0.
00557       // The constraint is either trivially true or trivially false.
00558       if (cs_i.is_inequality()) {
00559         if (cs_i.inhomogeneous_term() < 0)
00560           // A constraint such as -1 >= 0 is trivially false.
00561           return false;
00562       }
00563       else
00564         // The constraint is an equality.
00565         if (cs_i.inhomogeneous_term() != 0)
00566           // A constraint such as 1 == 0 is trivially false.
00567           return false;
00568       // Here the constraint is trivially true.
00569       is_tableau_constraint[i - first_pending_constraint] = false;
00570       --additional_tableau_rows;
00571       continue;
00572     }
00573     else {
00574       // Here we have only one nonzero coefficient.
00575       /*
00576 
00577       We have the following methods:
00578       A) Do split the variable and do add the constraint
00579          in the tableau.
00580       B) Do not split the variable and do add the constraint
00581          in the tableau.
00582       C) Do not split the variable and do not add the constraint
00583          in the tableau.
00584 
00585       Let the constraint be (a*v + b relsym 0).
00586       These are the 12 possible combinations we can have:
00587                 a |  b | relsym | method
00588       ----------------------------------
00589       1)       >0 | >0 |   >=   |   A
00590       2)       >0 | >0 |   ==   |   A
00591       3)       <0 | <0 |   >=   |   A
00592       4)       >0 | =0 |   ==   |   B
00593       5)       >0 | <0 |   ==   |   B
00594       Note:    <0 | >0 |   ==   | impossible by strong normalization
00595       Note:    <0 | =0 |   ==   | impossible by strong normalization
00596       Note:    <0 | <0 |   ==   | impossible by strong normalization
00597       6)       >0 | <0 |   >=   |   B
00598       7)       >0 | =0 |   >=   |   C
00599       8)       <0 | >0 |   >=   |   A
00600       9)       <0 | =0 |   >=   |   A
00601 
00602       The next lines will apply the correct method to each case.
00603       */
00604 
00605       // The variable index is not equal to the column index.
00606       const dimension_type nonzero_var_index = nonzero_coeff_column_index - 1;
00607 
00608       const int sgn_a = sgn(cs_i.coefficient(Variable(nonzero_var_index)));
00609       const int sgn_b = sgn(cs_i.inhomogeneous_term());
00610 
00611       // Cases 1-3: apply method A.
00612       if (sgn_a == sgn_b) {
00613         if (cs_i.is_inequality())
00614           ++additional_slack_variables;
00615       }
00616       // Cases 4-5: apply method B.
00617       else if (cs_i.is_equality())
00618         is_nonnegative_variable[nonzero_var_index] = true;
00619       // Case 6: apply method B.
00620       else if (sgn_b < 0) {
00621         is_nonnegative_variable[nonzero_var_index] = true;
00622         ++additional_slack_variables;
00623       }
00624       // Case 7: apply method C.
00625       else if (sgn_a > 0) {
00626         if (!is_nonnegative_variable[nonzero_var_index]) {
00627           is_nonnegative_variable[nonzero_var_index] = true;
00628           if (nonzero_coeff_column_index < mapping_size) {
00629             // Remember to merge back the positive and negative parts.
00630             PPL_ASSERT(nonzero_var_index < internal_space_dim);
00631             is_remergeable_variable[nonzero_var_index] = true;
00632           }
00633         }
00634         is_tableau_constraint[i - first_pending_constraint] = false;
00635         --additional_tableau_rows;
00636       }
00637       // Cases 8-9: apply method A.
00638       else {
00639         PPL_ASSERT(cs_i.is_inequality());
00640         ++additional_slack_variables;
00641       }
00642     }
00643   }
00644   return true;
00645 }
00646 
00647 bool
00648 PPL::MIP_Problem::process_pending_constraints() {
00649   // Check the pending constraints to adjust the data structures.
00650   // If `false' is returned, they are trivially unfeasible.
00651   dimension_type additional_tableau_rows = 0;
00652   dimension_type additional_slack_vars = 0;
00653   std::deque<bool> is_tableau_constraint;
00654   std::deque<bool> is_satisfied_inequality;
00655   std::deque<bool> is_nonnegative_variable;
00656   std::deque<bool> is_remergeable_variable;
00657   if (!parse_constraints(additional_tableau_rows,
00658                          additional_slack_vars,
00659                          is_tableau_constraint,
00660                          is_satisfied_inequality,
00661                          is_nonnegative_variable,
00662                          is_remergeable_variable)) {
00663     status = UNSATISFIABLE;
00664     return false;
00665   }
00666 
00667   // Merge back any variable that was previously split into a positive
00668   // and a negative part and is now known to be nonnegative.
00669   std::vector<dimension_type> unfeasible_tableau_rows;
00670   for (dimension_type i = internal_space_dim; i-- > 0; ) {
00671     if (!is_remergeable_variable[i])
00672       continue;
00673     // TODO: merging all rows in a single shot may be more efficient
00674     // as it would require a single call to permute_columns().
00675     const dimension_type unfeasible_row = merge_split_variable(i);
00676     if (unfeasible_row != not_a_dimension())
00677       unfeasible_tableau_rows.push_back(unfeasible_row);
00678   }
00679 
00680   const dimension_type old_tableau_num_rows = tableau.num_rows();
00681   const dimension_type old_tableau_num_cols = tableau.num_columns();
00682   const dimension_type first_free_tableau_index = old_tableau_num_cols - 1;
00683 
00684   // Update mapping for the new problem variables (if any).
00685   dimension_type additional_problem_vars = 0;
00686   if (external_space_dim > internal_space_dim) {
00687     const dimension_type space_diff = external_space_dim - internal_space_dim;
00688     for (dimension_type i = 0, j = 0; i < space_diff; ++i) {
00689       // Let `mapping' associate the variable index with the corresponding
00690       // tableau column: split the variable into positive and negative
00691       // parts if it is not known to be nonnegative.
00692       const dimension_type positive = first_free_tableau_index + j;
00693       if (is_nonnegative_variable[internal_space_dim + i]) {
00694         // Do not split.
00695         mapping.push_back(std::make_pair(positive, 0));
00696         ++j;
00697         ++additional_problem_vars;
00698       }
00699       else {
00700         // Split: negative index is positive + 1.
00701         mapping.push_back(std::make_pair(positive, positive + 1));
00702         j += 2;
00703         additional_problem_vars += 2;
00704       }
00705     }
00706   }
00707 
00708   // Resize the tableau: first add additional rows ...
00709   if (additional_tableau_rows > 0)
00710     tableau.add_zero_rows(additional_tableau_rows, Row_Flags());
00711 
00712   // ... then add additional columns.
00713   // We need columns for additional (split) problem variables, additional
00714   // slack variables and additional artificials.
00715   // The number of artificials to be added is computed as:
00716   // * number of pending constraints entering the tableau
00717   //     minus
00718   // * pending constraints that are inequalities and are already satisfied
00719   //   by `last_generator'
00720   //     plus
00721   // * number of non-pending constraints that are no longer satisfied
00722   //   due to re-merging of split variables.
00723 
00724   const dimension_type num_satisfied_inequalities
00725     = static_cast<dimension_type>(std::count(is_satisfied_inequality.begin(),
00726                                              is_satisfied_inequality.end(),
00727                                              true));
00728   const dimension_type unfeasible_tableau_rows_size
00729     = unfeasible_tableau_rows.size();
00730 
00731   PPL_ASSERT(additional_tableau_rows >= num_satisfied_inequalities);
00732   const dimension_type additional_artificial_vars
00733     = (additional_tableau_rows - num_satisfied_inequalities)
00734     + unfeasible_tableau_rows_size;
00735 
00736   const dimension_type additional_tableau_columns
00737     = additional_problem_vars
00738     + additional_slack_vars
00739     + additional_artificial_vars;
00740 
00741   if (additional_tableau_columns > 0)
00742     tableau.add_zero_columns(additional_tableau_columns);
00743 
00744   // Dimensions of the tableau after resizing.
00745   const dimension_type tableau_num_rows = tableau.num_rows();
00746   const dimension_type tableau_num_cols = tableau.num_columns();
00747 
00748   // The following vector will be useful know if a constraint is feasible
00749   // and does not require an additional artificial variable.
00750   std::deque<bool> worked_out_row (tableau_num_rows, false);
00751 
00752   // Sync the `base' vector size to the new tableau: fill with zeros
00753   // to encode that these rows are not OK and must be adjusted.
00754   base.insert(base.end(), additional_tableau_rows, 0);
00755   const dimension_type base_size = base.size();
00756 
00757   // These indexes will be used to insert slack and artificial variables
00758   // in the appropriate position.
00759   dimension_type slack_index
00760     = tableau_num_cols - additional_artificial_vars - 1;
00761   dimension_type artificial_index = slack_index;
00762 
00763   // The first column index of the tableau that contains an
00764   // artificial variable. Encode with 0 the fact the there are not
00765   // artificial variables.
00766   const dimension_type begin_artificials
00767     = (additional_artificial_vars > 0)
00768     ? artificial_index
00769     : 0;
00770 
00771   // Proceed with the insertion of the constraints.
00772   for (dimension_type k = tableau_num_rows,
00773        i = input_cs.size() - first_pending_constraint; i-- > 0; ) {
00774     if (!is_tableau_constraint[i])
00775       continue;
00776     // Copy the original constraint in the tableau.
00777     Row& tableau_k = tableau[--k];
00778     Row::iterator itr = tableau_k.end();
00779 
00780     const Constraint& c = *(input_cs[i + first_pending_constraint]);
00781     for (dimension_type sd = c.space_dimension(); sd-- > 0; ) {
00782       Coefficient_traits::const_reference coeff_sd
00783         = c.coefficient(Variable(sd));
00784       if (coeff_sd != 0) {
00785         itr = tableau_k.insert(itr, mapping[sd+1].first, coeff_sd);
00786         // Split if needed.
00787         if (mapping[sd+1].second != 0) {
00788           itr = tableau_k.insert(itr, mapping[sd+1].second);
00789           neg_assign(*itr, coeff_sd);
00790         }
00791       }
00792     }
00793     Coefficient_traits::const_reference inhomo
00794       = c.inhomogeneous_term();
00795     if (inhomo != 0) {
00796       tableau_k.insert(itr, mapping[0].first, inhomo);
00797       // Split if needed.
00798       if (mapping[0].second != 0) {
00799         itr = tableau_k.insert(itr, mapping[0].second);
00800         neg_assign(*itr, inhomo);
00801       }
00802     }
00803 
00804     // Add the slack variable, if needed.
00805     if (c.is_inequality()) {
00806       neg_assign(tableau_k[--slack_index], Coefficient_one());
00807       // If the constraint is already satisfied, we will not use artificial
00808       // variables to compute a feasible base: this to speed up
00809       // the algorithm.
00810       if (is_satisfied_inequality[i]) {
00811         base[k] = slack_index;
00812         worked_out_row[k] = true;
00813       }
00814     }
00815     for (dimension_type j = base_size; j-- > 0; )
00816       if (k != j && base[j] != 0 && tableau_k.get(base[j]) != 0)
00817         linear_combine(tableau_k, tableau[j], base[j]);
00818   }
00819 
00820   // Let all inhomogeneous terms in the tableau be nonpositive,
00821   // so as to simplify the insertion of artificial variables
00822   // (the coefficient of each artificial variable will be 1).
00823   for (dimension_type i = tableau_num_rows; i-- > 0 ; ) {
00824     Row& tableau_i = tableau[i];
00825     if (tableau_i.get(0) > 0) {
00826       for (Row::iterator
00827            j = tableau_i.begin(), j_end = tableau_i.end(); j != j_end; ++j)
00828         neg_assign(*j);
00829     }
00830   }
00831 
00832   // Reset the working cost function to have the right size.
00833   working_cost = working_cost_type(tableau_num_cols, Row_Flags());
00834 
00835   // Set up artificial variables: these will have coefficient 1 in the
00836   // constraint, will enter the base and will have coefficient -1 in
00837   // the cost function.
00838 
00839   // This is used as a hint for insertions in working_cost.
00840   working_cost_type::iterator cost_itr = working_cost.end();
00841 
00842   // First go through non-pending constraints that became unfeasible
00843   // due to re-merging of split variables.
00844   for (dimension_type i = 0; i < unfeasible_tableau_rows_size; ++i) {
00845     tableau[unfeasible_tableau_rows[i]].insert(artificial_index,
00846                                                Coefficient_one());
00847     cost_itr = working_cost.insert(cost_itr, artificial_index);
00848     *cost_itr = -1;
00849     base[unfeasible_tableau_rows[i]] = artificial_index;
00850     ++artificial_index;
00851   }
00852   // Then go through newly added tableau rows, disregarding inequalities
00853   // that are already satisfied by `last_generator' (this information
00854   // is encoded in `worked_out_row').
00855   for (dimension_type i = old_tableau_num_rows; i < tableau_num_rows; ++i) {
00856     if (worked_out_row[i])
00857       continue;
00858     tableau[i].insert(artificial_index, Coefficient_one());
00859     cost_itr = working_cost.insert(cost_itr, artificial_index);
00860     *cost_itr = -1;
00861     base[i] = artificial_index;
00862     ++artificial_index;
00863   }
00864   // One past the last tableau column index containing an artificial variable.
00865   const dimension_type end_artificials = artificial_index;
00866 
00867   // Set the extra-coefficient of the cost functions to record its sign.
00868   // This is done to keep track of the possible sign's inversion.
00869   const dimension_type last_obj_index = working_cost.size() - 1;
00870   working_cost.insert(cost_itr, last_obj_index, Coefficient_one());
00871 
00872   // Express the problem in terms of the variables in base.
00873   {
00874     working_cost_type::const_iterator itr = working_cost.end();
00875     for (dimension_type i = tableau_num_rows; i-- > 0; ) {
00876       itr = working_cost.lower_bound(itr, base[i]);
00877       if (itr != working_cost.end() && itr.index() == base[i] && *itr != 0) {
00878         linear_combine(working_cost, tableau[i], base[i]);
00879         // itr has been invalidated by the call to linear_combine().
00880         itr = working_cost.end();
00881       }
00882     }
00883   }
00884 
00885   // Deal with zero dimensional problems.
00886   if (space_dimension() == 0) {
00887     status = OPTIMIZED;
00888     last_generator = point();
00889     return true;
00890   }
00891   // Deal with trivial cases.
00892   // If there is no constraint in the tableau, then the feasible region
00893   // is only delimited by non-negativity constraints. Therefore,
00894   // the problem is unbounded as soon as the cost function has
00895   // a variable with a positive coefficient.
00896   if (tableau_num_rows == 0) {
00897     const dimension_type input_obj_function_size
00898       = input_obj_function.space_dimension();
00899     for (dimension_type i = input_obj_function_size; i-- > 0; )
00900       // If a the value of a variable in the objective function is
00901       // different from zero, the final status is unbounded.
00902       // In the first part the variable is constrained to be greater or equal
00903       // than zero.
00904       if ((((input_obj_function.coefficient(Variable(i)) > 0
00905              && opt_mode == MAXIMIZATION)
00906             || (input_obj_function.coefficient(Variable(i)) < 0
00907         && opt_mode == MINIMIZATION)) && mapping[i].second == 0)
00908           // In the following case the variable is unconstrained.
00909           || (input_obj_function.coefficient(Variable(i)) != 0
00910               && mapping[i].second != 0)) {
00911         // Ensure the right space dimension is obtained.
00912         last_generator = point(0 * Variable(space_dimension() - 1));
00913         status = UNBOUNDED;
00914         return true;
00915       }
00916 
00917     // The problem is neither trivially unfeasible nor trivially unbounded.
00918     // The tableau was successful computed and the caller has to figure
00919     // out which case applies.
00920     status = OPTIMIZED;
00921     // Ensure the right space dimension is obtained.
00922     last_generator = point(0 * Variable(space_dimension() - 1));
00923     PPL_ASSERT(OK());
00924     return true;
00925   }
00926 
00927   // Now we are ready to solve the first phase.
00928   bool first_phase_successful
00929     = (get_control_parameter(PRICING) == PRICING_STEEPEST_EDGE_FLOAT)
00930     ? compute_simplex_using_steepest_edge_float()
00931     : compute_simplex_using_exact_pricing();
00932 
00933 #if PPL_NOISY_SIMPLEX
00934   std::cout << "MIP_Problem::process_pending_constraints(): "
00935             << "1st phase ended at iteration " << num_iterations
00936             << "." << std::endl;
00937 #endif // PPL_NOISY_SIMPLEX
00938 
00939   if (!first_phase_successful || working_cost.get(0) != 0) {
00940     // The feasible region is empty.
00941     status = UNSATISFIABLE;
00942     return false;
00943   }
00944 
00945   // Prepare *this for a possible second phase.
00946   if (begin_artificials != 0)
00947     erase_artificials(begin_artificials, end_artificials);
00948   compute_generator();
00949   status = SATISFIABLE;
00950   PPL_ASSERT(OK());
00951   return true;
00952 }
00953 
00954 namespace {
00955 
00956 // NOTE: the following two `assign' helper functions are needed to
00957 // handle the assignment of a Coefficient to a double in method
00958 //     MIP_Problem::steepest_edge_float_entering_index().
00959 // We cannot use assign_r(double, Coefficient, Rounding_Dir) as it would
00960 // lead to a compilation error on those platforms (e.g., ARM) where
00961 // controlled floating point rounding is not available (even if the
00962 // rounding mode would be set to ROUND_IGNORE).
00963 
00964 inline void
00965 assign(double& d, const mpz_class& c) {
00966   d = c.get_d();
00967 }
00968 
00969 template <typename T, typename Policy>
00970 inline void
00971 assign(double& d,
00972        const Parma_Polyhedra_Library::Checked_Number<T, Policy>& c) {
00973   d = raw_value(c);
00974 }
00975 
00976 } // namespace
00977 
00978 PPL::dimension_type
00979 PPL::MIP_Problem::steepest_edge_float_entering_index() const {
00980   const dimension_type tableau_num_rows = tableau.num_rows();
00981   const dimension_type tableau_num_columns = tableau.num_columns();
00982   PPL_ASSERT(tableau_num_rows == base.size());
00983   double current_value = 0.0;
00984   // Due to our integer implementation, the `1' term in the denominator
00985   // of the original formula has to be replaced by `squared_lcm_basis'.
00986   double float_tableau_value;
00987   double float_tableau_denom;
00988   dimension_type entering_index = 0;
00989   const int cost_sign = sgn(working_cost.get(working_cost.size() - 1));
00990 
00991   // These two implementation work for both sparse and dense matrices.
00992   // However, when using sparse matrices the first one is fast and the second
00993   // one is slow, and when using dense matrices the first one is slow and
00994   // the second one is fast.
00995 #if PPL_USE_SPARSE_MATRIX
00996 
00997   const dimension_type tableau_num_columns_minus_1 = tableau_num_columns - 1;
00998   // This is static to improve performance.
00999   // A vector of <column_index, challenger_denom> pairs, ordered by
01000   // column_index.
01001   static std::vector<std::pair<dimension_type, double> > columns;
01002   columns.clear();
01003   // (working_cost.size() - 2) is an upper bound only.
01004   columns.reserve(working_cost.size() - 2);
01005   {
01006     working_cost_type::const_iterator i = working_cost.lower_bound(1);
01007     // Note that find() is used instead of lower_bound().
01008     working_cost_type::const_iterator i_end
01009       = working_cost.find(tableau_num_columns_minus_1);
01010     for ( ; i != i_end; ++i)
01011       if (sgn(*i) == cost_sign)
01012         columns.push_back(std::make_pair(i.index(), 1.0));
01013   }
01014   for (dimension_type i = tableau_num_rows; i-- > 0; ) {
01015     const Row& tableau_i = tableau[i];
01016     assign(float_tableau_denom, tableau_i.get(base[i]));
01017     Row::const_iterator j = tableau_i.begin();
01018     Row::const_iterator j_end = tableau_i.end();
01019     std::vector<std::pair<dimension_type, double> >::iterator k
01020       = columns.begin();
01021     std::vector<std::pair<dimension_type, double> >::iterator k_end
01022       = columns.end();
01023     while (j != j_end && k != k_end) {
01024       const dimension_type column = j.index();
01025       while (k != k_end && column > k->first)
01026         ++k;
01027       if (k == k_end)
01028         break;
01029       if (k->first > column) {
01030         j = tableau_i.lower_bound(j, k->first);
01031       }
01032       else {
01033         PPL_ASSERT(k->first == column);
01034         PPL_ASSERT(tableau_i.get(base[i]) != 0);
01035         WEIGHT_BEGIN();
01036         assign(float_tableau_value, *j);
01037         float_tableau_value /= float_tableau_denom;
01038         float_tableau_value *= float_tableau_value;
01039         k->second += float_tableau_value;
01040         WEIGHT_ADD(22);
01041         ++j;
01042         ++k;
01043       }
01044     }
01045   }
01046   // The candidates are processed backwards to get the same result in both
01047   // this implementation and the dense implementation below.
01048   for (std::vector<std::pair<dimension_type, double> >::const_reverse_iterator
01049        i = columns.rbegin(), i_end = columns.rend(); i != i_end; ++i) {
01050     double challenger_value = sqrt(i->second);
01051     if (entering_index == 0 || challenger_value > current_value) {
01052       current_value = challenger_value;
01053       entering_index = i->first;
01054     }
01055   }
01056 
01057 #else // !PPL_USE_SPARSE_MATRIX
01058 
01059   double challenger_numer = 0.0;
01060   double challenger_denom = 0.0;
01061   for (dimension_type j = tableau_num_columns - 1; j-- > 1; ) {
01062     Coefficient_traits::const_reference cost_j = working_cost.get(j);
01063     if (sgn(cost_j) == cost_sign) {
01064       WEIGHT_BEGIN();
01065       // We cannot compute the (exact) square root of abs(\Delta x_j).
01066       // The workaround is to compute the square of `cost[j]'.
01067       assign(challenger_numer, cost_j);
01068       challenger_numer = std::abs(challenger_numer);
01069       // Due to our integer implementation, the `1' term in the denominator
01070       // of the original formula has to be replaced by `squared_lcm_basis'.
01071       challenger_denom = 1.0;
01072       for (dimension_type i = tableau_num_rows; i-- > 0; ) {
01073         const Row& tableau_i = tableau[i];
01074         Coefficient_traits::const_reference tableau_ij = tableau_i[j];
01075         if (tableau_ij != 0) {
01076           PPL_ASSERT(tableau_i[base[i]] != 0);
01077           assign(float_tableau_value, tableau_ij);
01078           assign(float_tableau_denom, tableau_i[base[i]]);
01079           float_tableau_value /= float_tableau_denom;
01080           challenger_denom += float_tableau_value * float_tableau_value;
01081         }
01082       }
01083       double challenger_value = sqrt(challenger_denom);
01084       // Initialize `current_value' during the first iteration.
01085       // Otherwise update if the challenger wins.
01086       if (entering_index == 0 || challenger_value > current_value) {
01087         current_value = challenger_value;
01088         entering_index = j;
01089       }
01090       WEIGHT_ADD_MUL(10, tableau_num_rows);
01091     }
01092   }
01093 
01094 #endif // !PPL_USE_SPARSE_MATRIX
01095 
01096   return entering_index;
01097 }
01098 
01099 PPL::dimension_type
01100 PPL::MIP_Problem::steepest_edge_exact_entering_index() const {
01101   using std::swap;
01102   const dimension_type tableau_num_rows = tableau.num_rows();
01103   PPL_ASSERT(tableau_num_rows == base.size());
01104   // The square of the lcm of all the coefficients of variables in base.
01105   PPL_DIRTY_TEMP_COEFFICIENT(squared_lcm_basis);
01106   // The normalization factor for each coefficient in the tableau.
01107   std::vector<Coefficient> norm_factor(tableau_num_rows);
01108   {
01109     WEIGHT_BEGIN();
01110     // Compute the lcm of all the coefficients of variables in base.
01111     PPL_DIRTY_TEMP_COEFFICIENT(lcm_basis);
01112     lcm_basis = 1;
01113     for (dimension_type i = tableau_num_rows; i-- > 0; )
01114       lcm_assign(lcm_basis, lcm_basis, tableau[i].get(base[i]));
01115     // Compute normalization factors.
01116     for (dimension_type i = tableau_num_rows; i-- > 0; )
01117       exact_div_assign(norm_factor[i], lcm_basis, tableau[i].get(base[i]));
01118     // Compute the square of `lcm_basis', exploiting the fact that
01119     // `lcm_basis' will no longer be needed.
01120     lcm_basis *= lcm_basis;
01121     swap(squared_lcm_basis, lcm_basis);
01122     WEIGHT_ADD_MUL(444, tableau_num_rows);
01123   }
01124 
01125   PPL_DIRTY_TEMP_COEFFICIENT(challenger_numer);
01126   PPL_DIRTY_TEMP_COEFFICIENT(scalar_value);
01127   PPL_DIRTY_TEMP_COEFFICIENT(challenger_value);
01128   PPL_DIRTY_TEMP_COEFFICIENT(current_value);
01129 
01130   PPL_DIRTY_TEMP_COEFFICIENT(current_numer);
01131   PPL_DIRTY_TEMP_COEFFICIENT(current_denom);
01132   dimension_type entering_index = 0;
01133   const int cost_sign = sgn(working_cost.get(working_cost.size() - 1));
01134 
01135   // These two implementation work for both sparse and dense matrices.
01136   // However, when using sparse matrices the first one is fast and the second
01137   // one is slow, and when using dense matrices the first one is slow and
01138   // the second one is fast.
01139 #if PPL_USE_SPARSE_MATRIX
01140 
01141   const dimension_type tableau_num_columns = tableau.num_columns();
01142   const dimension_type tableau_num_columns_minus_1 = tableau_num_columns - 1;
01143   // This is static to improve performance.
01144   // A pair (i, x) means that sgn(working_cost[i]) == cost_sign and x
01145   // is the denominator of the challenger, for the column i.
01146   static std::vector<std::pair<dimension_type, Coefficient> > columns;
01147   columns.clear();
01148   // tableau_num_columns - 2 is only an upper bound on the required elements.
01149   // This helps to reduce the number of calls to new [] and delete [] and
01150   // the construction/destruction of Coefficient objects.
01151   columns.reserve(tableau_num_columns - 2);
01152   {
01153     working_cost_type::const_iterator i = working_cost.lower_bound(1);
01154     // Note that find() is used instead of lower_bound.
01155     working_cost_type::const_iterator i_end
01156       = working_cost.find(tableau_num_columns_minus_1);
01157     for ( ; i != i_end; ++i)
01158       if (sgn(*i) == cost_sign)
01159         columns.push_back(std::pair<dimension_type, Coefficient>
01160                           (i.index(), squared_lcm_basis));
01161   }
01162   for (dimension_type i = tableau_num_rows; i-- > 0; ) {
01163     const Row& tableau_i = tableau[i];
01164     Row::const_iterator j = tableau_i.begin();
01165     Row::const_iterator j_end = tableau_i.end();
01166     std::vector<std::pair<dimension_type, Coefficient> >::iterator
01167       k = columns.begin();
01168     std::vector<std::pair<dimension_type, Coefficient> >::iterator
01169       k_end = columns.end();
01170     while (j != j_end) {
01171       while (k != k_end && j.index() > k->first)
01172         ++k;
01173       if (k == k_end)
01174         break;
01175       PPL_ASSERT(j.index() <= k->first);
01176       if (j.index() < k->first)
01177         j = tableau_i.lower_bound(j, k->first);
01178       else {
01179         Coefficient_traits::const_reference tableau_ij = *j;
01180         WEIGHT_BEGIN();
01181 #if PPL_USE_SPARSE_MATRIX
01182         scalar_value = tableau_ij * norm_factor[i];
01183         add_mul_assign(k->second, scalar_value, scalar_value);
01184 #else
01185         // The test against 0 gives rise to a consistent speed up in the dense
01186         // implementation: see
01187         // http://www.cs.unipr.it/pipermail/ppl-devel/2009-February/
01188         // 014000.html
01189         if (tableau_ij != 0) {
01190           scalar_value = tableau_ij * norm_factor[i];
01191           add_mul_assign(k->second, scalar_value, scalar_value);
01192         }
01193 #endif
01194         WEIGHT_ADD_MUL(47, tableau_num_rows);
01195         ++k;
01196         ++j;
01197       }
01198     }
01199   }
01200   working_cost_type::const_iterator itr = working_cost.end();
01201   for (std::vector<std::pair<dimension_type, Coefficient> >::reverse_iterator
01202        k = columns.rbegin(), k_end = columns.rend(); k != k_end; ++k) {
01203     itr = working_cost.lower_bound(itr, k->first);
01204     if (itr != working_cost.end() && itr.index() == k->first) {
01205       // We cannot compute the (exact) square root of abs(\Delta x_j).
01206       // The workaround is to compute the square of `cost[j]'.
01207       challenger_numer = (*itr) * (*itr);
01208       // Initialization during the first loop.
01209       if (entering_index == 0) {
01210         swap(current_numer, challenger_numer);
01211         swap(current_denom, k->second);
01212         entering_index = k->first;
01213         continue;
01214       }
01215       challenger_value = challenger_numer * current_denom;
01216       current_value = current_numer * k->second;
01217       // Update the values, if the challenger wins.
01218       if (challenger_value > current_value) {
01219         swap(current_numer, challenger_numer);
01220         swap(current_denom, k->second);
01221         entering_index = k->first;
01222       }
01223     } else {
01224       PPL_ASSERT(working_cost.get(k->first) == 0);
01225       // Initialization during the first loop.
01226       if (entering_index == 0) {
01227         current_numer = 0;
01228         swap(current_denom, k->second);
01229         entering_index = k->first;
01230         continue;
01231       }
01232       // Update the values, if the challenger wins.
01233       if (0 > sgn(current_numer) * sgn(k->second)) {
01234         current_numer = 0;
01235         swap(current_denom, k->second);
01236         entering_index = k->first;
01237       }
01238     }
01239   }
01240 
01241 #else // !PPL_USE_SPARSE_MATRIX
01242 
01243   PPL_DIRTY_TEMP_COEFFICIENT(challenger_denom);
01244   for (dimension_type j = tableau.num_columns() - 1; j-- > 1; ) {
01245     Coefficient_traits::const_reference cost_j = working_cost[j];
01246     if (sgn(cost_j) == cost_sign) {
01247       WEIGHT_BEGIN();
01248       // We cannot compute the (exact) square root of abs(\Delta x_j).
01249       // The workaround is to compute the square of `cost[j]'.
01250       challenger_numer = cost_j * cost_j;
01251       // Due to our integer implementation, the `1' term in the denominator
01252       // of the original formula has to be replaced by `squared_lcm_basis'.
01253       challenger_denom = squared_lcm_basis;
01254       for (dimension_type i = tableau_num_rows; i-- > 0; ) {
01255         Coefficient_traits::const_reference tableau_ij = tableau[i][j];
01256         // The test against 0 gives rise to a consistent speed up: see
01257         // http://www.cs.unipr.it/pipermail/ppl-devel/2009-February/
01258         // 014000.html
01259         if (tableau_ij != 0) {
01260           scalar_value = tableau_ij * norm_factor[i];
01261           add_mul_assign(challenger_denom, scalar_value, scalar_value);
01262         }
01263       }
01264       // Initialization during the first loop.
01265       if (entering_index == 0) {
01266         swap(current_numer, challenger_numer);
01267         swap(current_denom, challenger_denom);
01268         entering_index = j;
01269         continue;
01270       }
01271       challenger_value = challenger_numer * current_denom;
01272       current_value = current_numer * challenger_denom;
01273       // Update the values, if the challenger wins.
01274       if (challenger_value > current_value) {
01275         swap(current_numer, challenger_numer);
01276         swap(current_denom, challenger_denom);
01277         entering_index = j;
01278       }
01279       WEIGHT_ADD_MUL(47, tableau_num_rows);
01280     }
01281   }
01282 
01283 #endif // !PPL_USE_SPARSE_MATRIX
01284 
01285   return entering_index;
01286 }
01287 
01288 
01289 // See page 47 of [PapadimitriouS98].
01290 PPL::dimension_type
01291 PPL::MIP_Problem::textbook_entering_index() const {
01292   // The variable entering the base is the first one whose coefficient
01293   // in the cost function has the same sign the cost function itself.
01294   // If no such variable exists, then we met the optimality condition
01295   // (and return 0 to the caller).
01296 
01297   // Get the "sign" of the cost function.
01298   const dimension_type cost_sign_index = working_cost.size() - 1;
01299   const int cost_sign = sgn(working_cost.get(cost_sign_index));
01300   PPL_ASSERT(cost_sign != 0);
01301 
01302   working_cost_type::const_iterator i = working_cost.lower_bound(1);
01303   // Note that find() is used instead of lower_bound() because they are
01304   // equivalent when searching the last element in the row.
01305   working_cost_type::const_iterator i_end
01306     = working_cost.find(cost_sign_index);
01307   for ( ; i != i_end; ++i)
01308     if (sgn(*i) == cost_sign)
01309       return i.index();
01310   // No variable has to enter the base:
01311   // the cost function was optimized.
01312   return 0;
01313 }
01314 
01315 void
01316 PPL::MIP_Problem::linear_combine(Row& x, const Row& y,
01317                                  const dimension_type k) {
01318   PPL_ASSERT(x.size() == y.size());
01319   WEIGHT_BEGIN();
01320   const dimension_type x_size = x.size();
01321   Coefficient_traits::const_reference x_k = x.get(k);
01322   Coefficient_traits::const_reference y_k = y.get(k);
01323   PPL_ASSERT(y_k != 0 && x_k != 0);
01324   // Let g be the GCD between `x[k]' and `y[k]'.
01325   // For each i the following computes
01326   //   x[i] = x[i]*y[k]/g - y[i]*x[k]/g.
01327   PPL_DIRTY_TEMP_COEFFICIENT(normalized_x_k);
01328   PPL_DIRTY_TEMP_COEFFICIENT(normalized_y_k);
01329   normalize2(x_k, y_k, normalized_x_k, normalized_y_k);
01330 
01331   neg_assign(normalized_y_k);
01332   x.linear_combine(y, normalized_y_k, normalized_x_k);
01333 
01334   PPL_ASSERT(x.get(k) == 0);
01335 
01336 #if PPL_USE_SPARSE_MATRIX
01337   PPL_ASSERT(x.find(k) == x.end());
01338 #endif
01339 
01340   x.normalize();
01341   WEIGHT_ADD_MUL(31, x_size);
01342 }
01343 
01344 // TODO: Remove this when the sparse working cost has been tested enough.
01345 #if PPL_USE_SPARSE_MATRIX
01346 
01347 void
01348 PPL::MIP_Problem::linear_combine(Dense_Row& x,
01349                                  const Sparse_Row& y,
01350                                  const dimension_type k) {
01351   PPL_ASSERT(x.size() == y.size());
01352   WEIGHT_BEGIN();
01353   const dimension_type x_size = x.size();
01354   Coefficient_traits::const_reference x_k = x.get(k);
01355   Coefficient_traits::const_reference y_k = y.get(k);
01356   PPL_ASSERT(y_k != 0 && x_k != 0);
01357   // Let g be the GCD between `x[k]' and `y[k]'.
01358   // For each i the following computes
01359   //   x[i] = x[i]*y[k]/g - y[i]*x[k]/g.
01360   PPL_DIRTY_TEMP_COEFFICIENT(normalized_x_k);
01361   PPL_DIRTY_TEMP_COEFFICIENT(normalized_y_k);
01362   normalize2(x_k, y_k, normalized_x_k, normalized_y_k);
01363   Sparse_Row::const_iterator j = y.begin();
01364   Sparse_Row::const_iterator j_end = y.end();
01365   dimension_type i;
01366   for (i = 0; j != j_end; ++i) {
01367     PPL_ASSERT(i < x_size);
01368     PPL_ASSERT(j.index() >= i);
01369     if (j.index() == i) {
01370       if (i != k) {
01371         Coefficient& x_i = x[i];
01372         x_i *= normalized_y_k;
01373         Coefficient_traits::const_reference y_i = *j;
01374         sub_mul_assign(x_i, y_i, normalized_x_k);
01375       }
01376       ++j;
01377     } else {
01378       if (i != k)
01379         x[i] *= normalized_y_k;
01380     }
01381   }
01382   PPL_ASSERT(j == j_end);
01383   for ( ; i < x_size; ++i)
01384     if (i != k)
01385       x[i] *= normalized_y_k;
01386 
01387   x[k] = 0;
01388   x.normalize();
01389   WEIGHT_ADD_MUL(83, x_size);
01390 }
01391 
01392 #endif // defined(PPL_USE_SPARSE_MATRIX)
01393 
01394 // See pages 42-43 of [PapadimitriouS98].
01395 void
01396 PPL::MIP_Problem::pivot(const dimension_type entering_var_index,
01397                         const dimension_type exiting_base_index) {
01398   const Row& tableau_out = tableau[exiting_base_index];
01399   // Linearly combine the constraints.
01400   for (dimension_type i = tableau.num_rows(); i-- > 0; ) {
01401     Row& tableau_i = tableau[i];
01402     if (i != exiting_base_index && tableau_i.get(entering_var_index) != 0)
01403       linear_combine(tableau_i, tableau_out, entering_var_index);
01404   }
01405   // Linearly combine the cost function.
01406   if (working_cost.get(entering_var_index) != 0)
01407     linear_combine(working_cost, tableau_out, entering_var_index);
01408   // Adjust the base.
01409   base[exiting_base_index] = entering_var_index;
01410 }
01411 
01412 // See pages 47 and 50 of [PapadimitriouS98].
01413 PPL::dimension_type
01414 PPL::MIP_Problem
01415 ::get_exiting_base_index(const dimension_type entering_var_index) const {
01416   // The variable exiting the base should be associated to a tableau
01417   // constraint such that the ratio
01418   // tableau[i][entering_var_index] / tableau[i][base[i]]
01419   // is strictly positive and minimal.
01420 
01421   // Find the first tableau constraint `c' having a positive value for
01422   // tableau[i][entering_var_index] / tableau[i][base[i]]
01423   const dimension_type tableau_num_rows = tableau.num_rows();
01424   dimension_type exiting_base_index = tableau_num_rows;
01425   for (dimension_type i = 0; i < tableau_num_rows; ++i) {
01426     const Row& t_i = tableau[i];
01427     const int num_sign = sgn(t_i.get(entering_var_index));
01428     if (num_sign != 0 && num_sign == sgn(t_i.get(base[i]))) {
01429       exiting_base_index = i;
01430       break;
01431     }
01432   }
01433   // Check for unboundedness.
01434   if (exiting_base_index == tableau_num_rows)
01435     return tableau_num_rows;
01436 
01437   // Reaching this point means that a variable will definitely exit the base.
01438   PPL_DIRTY_TEMP_COEFFICIENT(lcm);
01439   PPL_DIRTY_TEMP_COEFFICIENT(current_min);
01440   PPL_DIRTY_TEMP_COEFFICIENT(challenger);
01441   Coefficient t_e0 = tableau[exiting_base_index].get(0);
01442   Coefficient t_ee = tableau[exiting_base_index].get(entering_var_index);
01443   for (dimension_type i = exiting_base_index + 1; i < tableau_num_rows; ++i) {
01444     const Row& t_i = tableau[i];
01445     Coefficient_traits::const_reference t_ie = t_i.get(entering_var_index);
01446     const int t_ie_sign = sgn(t_ie);
01447     if (t_ie_sign != 0 && t_ie_sign == sgn(t_i.get(base[i]))) {
01448       WEIGHT_BEGIN();
01449       Coefficient_traits::const_reference t_i0 = t_i.get(0);
01450       lcm_assign(lcm, t_ee, t_ie);
01451       exact_div_assign(current_min, lcm, t_ee);
01452       current_min *= t_e0;
01453       abs_assign(current_min);
01454       exact_div_assign(challenger, lcm, t_ie);
01455       challenger *= t_i0;
01456       abs_assign(challenger);
01457       current_min -= challenger;
01458       const int sign = sgn(current_min);
01459       if (sign > 0
01460           || (sign == 0 && base[i] < base[exiting_base_index])) {
01461         exiting_base_index = i;
01462         t_e0 = t_i0;
01463         t_ee = t_ie;
01464       }
01465       WEIGHT_ADD(642);
01466     }
01467   }
01468   return exiting_base_index;
01469 }
01470 
01471 // See page 49 of [PapadimitriouS98].
01472 bool
01473 PPL::MIP_Problem::compute_simplex_using_steepest_edge_float() {
01474   // We may need to temporarily switch to the textbook pricing.
01475   const unsigned long allowed_non_increasing_loops = 200;
01476   unsigned long non_increased_times = 0;
01477   bool textbook_pricing = false;
01478 
01479   PPL_DIRTY_TEMP_COEFFICIENT(cost_sgn_coeff);
01480   PPL_DIRTY_TEMP_COEFFICIENT(current_numer);
01481   PPL_DIRTY_TEMP_COEFFICIENT(current_denom);
01482   PPL_DIRTY_TEMP_COEFFICIENT(challenger);
01483   PPL_DIRTY_TEMP_COEFFICIENT(current);
01484 
01485   cost_sgn_coeff = working_cost.get(working_cost.size() - 1);
01486   current_numer = working_cost.get(0);
01487   if (cost_sgn_coeff < 0)
01488     neg_assign(current_numer);
01489   abs_assign(current_denom, cost_sgn_coeff);
01490   PPL_ASSERT(tableau.num_columns() == working_cost.size());
01491   const dimension_type tableau_num_rows = tableau.num_rows();
01492 
01493   while (true) {
01494     // Choose the index of the variable entering the base, if any.
01495     const dimension_type entering_var_index
01496       = textbook_pricing
01497       ? textbook_entering_index()
01498       : steepest_edge_float_entering_index();
01499 
01500     // If no entering index was computed, the problem is solved.
01501     if (entering_var_index == 0)
01502       return true;
01503 
01504     // Choose the index of the row exiting the base.
01505     const dimension_type exiting_base_index
01506       = get_exiting_base_index(entering_var_index);
01507     // If no exiting index was computed, the problem is unbounded.
01508     if (exiting_base_index == tableau_num_rows)
01509       return false;
01510 
01511     // Check if the client has requested abandoning all expensive
01512     // computations. If so, the exception specified by the client
01513     // is thrown now.
01514     maybe_abandon();
01515 
01516     // We have not reached the optimality or unbounded condition:
01517     // compute the new base and the corresponding vertex of the
01518     // feasible region.
01519     pivot(entering_var_index, exiting_base_index);
01520 
01521     WEIGHT_BEGIN();
01522     // Now begins the objective function's value check to choose between
01523     // the `textbook' and the float `steepest-edge' technique.
01524     cost_sgn_coeff = working_cost.get(working_cost.size() - 1);
01525 
01526     challenger = working_cost.get(0);
01527     if (cost_sgn_coeff < 0)
01528       neg_assign(challenger);
01529     challenger *= current_denom;
01530     abs_assign(current, cost_sgn_coeff);
01531     current *= current_numer;
01532 #if PPL_NOISY_SIMPLEX
01533     ++num_iterations;
01534     if (num_iterations % 200 == 0)
01535       std::cout << "Primal simplex: iteration " << num_iterations
01536                 << "." << std::endl;
01537 #endif // PPL_NOISY_SIMPLEX
01538     // If the following condition fails, probably there's a bug.
01539     PPL_ASSERT(challenger >= current);
01540     // If the value of the objective function does not improve,
01541     // keep track of that.
01542     if (challenger == current) {
01543       ++non_increased_times;
01544       // In the following case we will proceed using the `textbook'
01545       // technique, until the objective function is not improved.
01546       if (non_increased_times > allowed_non_increasing_loops)
01547         textbook_pricing = true;
01548     }
01549     // The objective function has an improvement:
01550     // reset `non_increased_times' and `textbook_pricing'.
01551     else {
01552       non_increased_times = 0;
01553       textbook_pricing = false;
01554     }
01555     current_numer = working_cost.get(0);
01556     if (cost_sgn_coeff < 0)
01557       neg_assign(current_numer);
01558     abs_assign(current_denom, cost_sgn_coeff);
01559     WEIGHT_ADD(433);
01560   }
01561 }
01562 
01563 bool
01564 PPL::MIP_Problem::compute_simplex_using_exact_pricing() {
01565   PPL_ASSERT(tableau.num_columns() == working_cost.size());
01566   PPL_ASSERT(get_control_parameter(PRICING) == PRICING_STEEPEST_EDGE_EXACT
01567          || get_control_parameter(PRICING) == PRICING_TEXTBOOK);
01568 
01569   const dimension_type tableau_num_rows = tableau.num_rows();
01570   const bool textbook_pricing
01571     = (PRICING_TEXTBOOK == get_control_parameter(PRICING));
01572 
01573   while (true) {
01574     // Choose the index of the variable entering the base, if any.
01575     const dimension_type entering_var_index
01576       = textbook_pricing
01577       ? textbook_entering_index()
01578       : steepest_edge_exact_entering_index();
01579     // If no entering index was computed, the problem is solved.
01580     if (entering_var_index == 0)
01581       return true;
01582 
01583     // Choose the index of the row exiting the base.
01584     const dimension_type exiting_base_index
01585       = get_exiting_base_index(entering_var_index);
01586     // If no exiting index was computed, the problem is unbounded.
01587     if (exiting_base_index == tableau_num_rows)
01588       return false;
01589 
01590     // Check if the client has requested abandoning all expensive
01591     // computations. If so, the exception specified by the client
01592     // is thrown now.
01593     maybe_abandon();
01594 
01595     // We have not reached the optimality or unbounded condition:
01596     // compute the new base and the corresponding vertex of the
01597     // feasible region.
01598     pivot(entering_var_index, exiting_base_index);
01599 #if PPL_NOISY_SIMPLEX
01600     ++num_iterations;
01601     if (num_iterations % 200 == 0)
01602       std::cout << "Primal simplex: iteration " << num_iterations
01603                 << "." << std::endl;
01604 #endif // PPL_NOISY_SIMPLEX
01605   }
01606 }
01607 
01608 
01609 // See pages 55-56 of [PapadimitriouS98].
01610 void
01611 PPL::MIP_Problem::erase_artificials(const dimension_type begin_artificials,
01612                                     const dimension_type end_artificials) {
01613   PPL_ASSERT(0 < begin_artificials && begin_artificials < end_artificials);
01614 
01615   const dimension_type old_last_column = tableau.num_columns() - 1;
01616   dimension_type tableau_n_rows = tableau.num_rows();
01617   // Step 1: try to remove from the base all the remaining slack variables.
01618   for (dimension_type i = 0; i < tableau_n_rows; ++i)
01619     if (begin_artificials <= base[i] && base[i] < end_artificials) {
01620       // Search for a non-zero element to enter the base.
01621       Row& tableau_i = tableau[i];
01622       bool redundant = true;
01623       Row::const_iterator j = tableau_i.begin();
01624       Row::const_iterator j_end = tableau_i.end();
01625       // Skip the first element
01626       if (j != j_end && j.index() == 0)
01627         ++j;
01628       for ( ; (j != j_end) && (j.index() < begin_artificials); ++j)
01629         if (*j != 0) {
01630           pivot(j.index(), i);
01631           redundant = false;
01632           break;
01633         }
01634       if (redundant) {
01635         // No original variable entered the base:
01636         // the constraint is redundant and should be deleted.
01637         --tableau_n_rows;
01638         if (i < tableau_n_rows) {
01639           // Replace the redundant row with the last one,
01640           // taking care of adjusting the iteration index.
01641           tableau_i.m_swap(tableau[tableau_n_rows]);
01642           base[i] = base[tableau_n_rows];
01643           --i;
01644         }
01645         tableau.remove_trailing_rows(1);
01646         base.pop_back();
01647       }
01648     }
01649 
01650   // Step 2: Adjust data structures so as to enter phase 2 of the simplex.
01651 
01652   // Resize the tableau.
01653   const dimension_type num_artificials = end_artificials - begin_artificials;
01654   tableau.remove_trailing_columns(num_artificials);
01655 
01656   // Zero the last column of the tableau.
01657   const dimension_type new_last_column = tableau.num_columns() - 1;
01658   for (dimension_type i = tableau_n_rows; i-- > 0; )
01659     tableau[i].reset(new_last_column);
01660 
01661   // ... then properly set the element in the (new) last column,
01662   // encoding the kind of optimization; ...
01663   {
01664     // This block is equivalent to
01665     //
01666     // <CODE>
01667     //   working_cost[new_last_column] = working_cost.get(old_last_column);
01668     // </CODE>
01669     //
01670     // but it avoids storing zeroes.
01671     Coefficient_traits::const_reference old_cost
01672       = working_cost.get(old_last_column);
01673     if (old_cost == 0)
01674       working_cost.reset(new_last_column);
01675     else
01676       working_cost.insert(new_last_column, old_cost);
01677   }
01678 
01679   // ... and finally remove redundant columns.
01680   const dimension_type working_cost_new_size
01681     = working_cost.size() - num_artificials;
01682   working_cost.shrink(working_cost_new_size);
01683 }
01684 
01685 // See page 55 of [PapadimitriouS98].
01686 void
01687 PPL::MIP_Problem::compute_generator() const {
01688   // Early exit for 0-dimensional problems.
01689   if (external_space_dim == 0) {
01690     MIP_Problem& x = const_cast<MIP_Problem&>(*this);
01691     x.last_generator = point();
01692     return;
01693   }
01694 
01695   // We will store in numer[] and in denom[] the numerators and
01696   // the denominators of every variable of the original problem.
01697   std::vector<Coefficient> numer(external_space_dim);
01698   std::vector<Coefficient> denom(external_space_dim);
01699   dimension_type row = 0;
01700 
01701   PPL_DIRTY_TEMP_COEFFICIENT(lcm);
01702   // Speculatively allocate temporaries out of loop.
01703   PPL_DIRTY_TEMP_COEFFICIENT(split_numer);
01704   PPL_DIRTY_TEMP_COEFFICIENT(split_denom);
01705 
01706   // We start to compute numer[] and denom[].
01707   for (dimension_type i = external_space_dim; i-- > 0; ) {
01708     Coefficient& numer_i = numer[i];
01709     Coefficient& denom_i = denom[i];
01710     // Get the value of the variable from the tableau
01711     // (if it is not a basic variable, the value is 0).
01712     const dimension_type original_var = mapping[i+1].first;
01713     if (is_in_base(original_var, row)) {
01714       const Row& t_row = tableau[row];
01715       Coefficient_traits::const_reference t_row_original_var
01716         = t_row.get(original_var);
01717       if (t_row_original_var > 0) {
01718         neg_assign(numer_i, t_row.get(0));
01719         denom_i = t_row_original_var;
01720       }
01721       else {
01722         numer_i = t_row.get(0);
01723         neg_assign(denom_i, t_row_original_var);
01724       }
01725     }
01726     else {
01727       numer_i = 0;
01728       denom_i = 1;
01729     }
01730     // Check whether the variable was split.
01731     const dimension_type split_var = mapping[i+1].second;
01732     if (split_var != 0) {
01733       // The variable was split: get the value for the negative component,
01734       // having index mapping[i+1].second .
01735       // Like before, we he have to check if the variable is in base.
01736       if (is_in_base(split_var, row)) {
01737         const Row& t_row = tableau[row];
01738         Coefficient_traits::const_reference t_row_split_var
01739           = t_row.get(split_var);
01740         if (t_row_split_var > 0) {
01741           neg_assign(split_numer, t_row.get(0));
01742           split_denom = t_row_split_var;
01743         }
01744         else {
01745           split_numer = t_row.get(0);
01746           neg_assign(split_denom, t_row_split_var);
01747         }
01748         // We compute the lcm to compute subsequently the difference
01749         // between the 2 variables.
01750         lcm_assign(lcm, denom_i, split_denom);
01751         exact_div_assign(denom_i, lcm, denom_i);
01752         exact_div_assign(split_denom, lcm, split_denom);
01753         numer_i *= denom_i;
01754         sub_mul_assign(numer_i, split_numer, split_denom);
01755         if (numer_i == 0)
01756           denom_i = 1;
01757         else
01758           denom_i = lcm;
01759       }
01760       // Note: if the negative component was not in base, then
01761       // it has value zero and there is nothing left to do.
01762     }
01763   }
01764 
01765   // Compute the lcm of all denominators.
01766   PPL_ASSERT(external_space_dim > 0);
01767   lcm = denom[0];
01768   for (dimension_type i = 1; i < external_space_dim; ++i)
01769     lcm_assign(lcm, lcm, denom[i]);
01770   // Use the denominators to store the numerators' multipliers
01771   // and then compute the normalized numerators.
01772   for (dimension_type i = external_space_dim; i-- > 0; ) {
01773     exact_div_assign(denom[i], lcm, denom[i]);
01774     numer[i] *= denom[i];
01775   }
01776 
01777   // Finally, build the generator.
01778   Linear_Expression expr;
01779   for (dimension_type i = external_space_dim; i-- > 0; )
01780     add_mul_assign(expr, numer[i], Variable(i));
01781 
01782   MIP_Problem& x = const_cast<MIP_Problem&>(*this);
01783   x.last_generator = point(expr, lcm);
01784 }
01785 
01786 void
01787 PPL::MIP_Problem::second_phase() {
01788   // Second_phase requires that *this is satisfiable.
01789   PPL_ASSERT(status == SATISFIABLE
01790              || status == UNBOUNDED
01791              || status == OPTIMIZED);
01792   // In the following cases the problem is already solved.
01793   if (status == UNBOUNDED || status == OPTIMIZED)
01794     return;
01795 
01796   // Build the objective function for the second phase.
01797   const dimension_type input_obj_function_sd
01798     = input_obj_function.space_dimension();
01799   Row new_cost(input_obj_function_sd + 1, Row_Flags());
01800   {
01801     // This will be used as a hint.
01802     Row::iterator itr = new_cost.end();
01803     for (dimension_type i = input_obj_function_sd; i-- > 0; ) {
01804       Coefficient_traits::const_reference c
01805         = input_obj_function.coefficient(Variable(i));
01806       if (c != 0)
01807         itr = new_cost.insert(itr, i + 1, c);
01808     }
01809     if (input_obj_function.inhomogeneous_term() != 0)
01810       itr = new_cost.insert(itr, 0, input_obj_function.inhomogeneous_term());
01811   }
01812 
01813   // Negate the cost function if we are minimizing.
01814   if (opt_mode == MINIMIZATION)
01815     for (Row::iterator
01816          i = new_cost.begin(), i_end = new_cost.end(); i != i_end; ++i)
01817       neg_assign(*i);
01818 
01819   const dimension_type cost_zero_size = working_cost.size();
01820 
01821   // Substitute properly the cost function in the `costs' matrix.
01822   {
01823     working_cost_type tmp_cost
01824       = working_cost_type(cost_zero_size, cost_zero_size, new_cost.flags());
01825     tmp_cost.m_swap(working_cost);
01826   }
01827 
01828   {
01829     working_cost_type::iterator itr
01830       = working_cost.insert(cost_zero_size - 1, Coefficient_one());
01831 
01832     // Split the variables in the cost function.
01833     for (Row::const_iterator
01834          i = new_cost.lower_bound(1), i_end = new_cost.end();
01835          i != i_end; ++i) {
01836       const dimension_type index = i.index();
01837       const dimension_type original_var = mapping[index].first;
01838       const dimension_type split_var = mapping[index].second;
01839       itr = working_cost.insert(itr, original_var, *i);
01840       if (mapping[index].second != 0) {
01841         itr = working_cost.insert(itr, split_var);
01842         neg_assign(*itr, *i);
01843       }
01844     }
01845   }
01846 
01847   // Here the first phase problem succeeded with optimum value zero.
01848   // Express the old cost function in terms of the computed base.
01849   {
01850     working_cost_type::iterator itr = working_cost.end();
01851     for (dimension_type i = tableau.num_rows(); i-- > 0; ) {
01852       const dimension_type base_i = base[i];
01853       itr = working_cost.lower_bound(itr, base_i);
01854       if (itr != working_cost.end() && itr.index() == base_i && *itr != 0) {
01855         linear_combine(working_cost, tableau[i], base_i);
01856         itr = working_cost.end();
01857       }
01858     }
01859   }
01860 
01861   // Solve the second phase problem.
01862   bool second_phase_successful
01863     = (get_control_parameter(PRICING) == PRICING_STEEPEST_EDGE_FLOAT)
01864     ? compute_simplex_using_steepest_edge_float()
01865     : compute_simplex_using_exact_pricing();
01866   compute_generator();
01867 #if PPL_NOISY_SIMPLEX
01868   std::cout << "MIP_Problem::second_phase(): 2nd phase ended at iteration "
01869             << num_iterations
01870             << "." << std::endl;
01871 #endif // PPL_NOISY_SIMPLEX
01872   status = second_phase_successful ? OPTIMIZED : UNBOUNDED;
01873   PPL_ASSERT(OK());
01874 }
01875 
01876 void
01877 PPL::MIP_Problem
01878 ::evaluate_objective_function(const Generator& evaluating_point,
01879                               Coefficient& numer,
01880                               Coefficient& denom) const {
01881   const dimension_type ep_space_dim = evaluating_point.space_dimension();
01882   if (space_dimension() < ep_space_dim)
01883     throw std::invalid_argument("PPL::MIP_Problem::"
01884                                 "evaluate_objective_function(p, n, d):\n"
01885                                 "*this and p are dimension incompatible.");
01886   if (!evaluating_point.is_point())
01887     throw std::invalid_argument("PPL::MIP_Problem::"
01888                                 "evaluate_objective_function(p, n, d):\n"
01889                                 "p is not a point.");
01890 
01891   // Compute the smallest space dimension  between `input_obj_function'
01892   // and `evaluating_point'.
01893   const dimension_type working_space_dim
01894     = std::min(ep_space_dim, input_obj_function.space_dimension());
01895   // Compute the optimal value of the cost function.
01896   Coefficient_traits::const_reference divisor = evaluating_point.divisor();
01897   numer = input_obj_function.inhomogeneous_term() * divisor;
01898   for (dimension_type i = working_space_dim; i-- > 0; )
01899     numer += evaluating_point.coefficient(Variable(i))
01900       * input_obj_function.coefficient(Variable(i));
01901   // Numerator and denominator should be coprime.
01902   normalize2(numer, divisor, numer, denom);
01903 }
01904 
01905 bool
01906 PPL::MIP_Problem::is_lp_satisfiable() const {
01907 #if PPL_NOISY_SIMPLEX
01908   num_iterations = 0;
01909 #endif // PPL_NOISY_SIMPLEX
01910   switch (status) {
01911   case UNSATISFIABLE:
01912     return false;
01913   case SATISFIABLE:
01914     // Intentionally fall through.
01915   case UNBOUNDED:
01916     // Intentionally fall through.
01917   case OPTIMIZED:
01918     // Intentionally fall through.
01919     return true;
01920   case PARTIALLY_SATISFIABLE:
01921     {
01922       MIP_Problem& x = const_cast<MIP_Problem&>(*this);
01923       // This code tries to handle the case that happens if the tableau is
01924       // empty, so it must be initialized.
01925       if (tableau.num_columns() == 0) {
01926         // Add two columns, the first that handles the inhomogeneous term and
01927         // the second that represent the `sign'.
01928         x.tableau.add_zero_columns(2);
01929         // Sync `mapping' for the inhomogeneous term.
01930         x.mapping.push_back(std::make_pair(0, 0));
01931         // The internal data structures are ready, so prepare for more
01932         // assertion to be checked.
01933         x.initialized = true;
01934       }
01935 
01936       // Apply incrementality to the pending constraint system.
01937       x.process_pending_constraints();
01938       // Update `first_pending_constraint': no more pending.
01939       x.first_pending_constraint = input_cs.size();
01940       // Update also `internal_space_dim'.
01941       x.internal_space_dim = x.external_space_dim;
01942       PPL_ASSERT(OK());
01943       return status != UNSATISFIABLE;
01944     }
01945   }
01946   // We should not be here!
01947   PPL_UNREACHABLE;
01948   return false;
01949 }
01950 
01951 PPL::MIP_Problem_Status
01952 PPL::MIP_Problem::solve_mip(bool& have_incumbent_solution,
01953                             mpq_class& incumbent_solution_value,
01954                             Generator& incumbent_solution_point,
01955                             MIP_Problem& mip,
01956                             const Variables_Set& i_vars) {
01957   // Solve the problem as a non MIP one, it must be done internally.
01958   PPL::MIP_Problem_Status mip_status;
01959   if (mip.is_lp_satisfiable()) {
01960     mip.second_phase();
01961     mip_status = (mip.status == OPTIMIZED) ? OPTIMIZED_MIP_PROBLEM
01962       : UNBOUNDED_MIP_PROBLEM;
01963   }
01964   else
01965     return UNFEASIBLE_MIP_PROBLEM;
01966 
01967   PPL_DIRTY_TEMP(mpq_class, tmp_rational);
01968 
01969   Generator p = point();
01970   PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff1);
01971   PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff2);
01972 
01973   if (mip_status == UNBOUNDED_MIP_PROBLEM)
01974     p = mip.last_generator;
01975   else {
01976     PPL_ASSERT(mip_status == OPTIMIZED_MIP_PROBLEM);
01977     // Do not call optimizing_point().
01978     p = mip.last_generator;
01979     mip.evaluate_objective_function(p, tmp_coeff1, tmp_coeff2);
01980     assign_r(tmp_rational.get_num(), tmp_coeff1, ROUND_NOT_NEEDED);
01981     assign_r(tmp_rational.get_den(), tmp_coeff2, ROUND_NOT_NEEDED);
01982     PPL_ASSERT(is_canonical(tmp_rational));
01983     if (have_incumbent_solution
01984         && ((mip.optimization_mode() == MAXIMIZATION
01985               && tmp_rational <= incumbent_solution_value)
01986             || (mip.optimization_mode() == MINIMIZATION
01987                 && tmp_rational >= incumbent_solution_value)))
01988       // Abandon this path.
01989       return mip_status;
01990   }
01991 
01992   bool found_satisfiable_generator = true;
01993   PPL_DIRTY_TEMP_COEFFICIENT(gcd);
01994   Coefficient_traits::const_reference p_divisor = p.divisor();
01995   dimension_type non_int_dim = mip.space_dimension();
01996   for (Variables_Set::const_iterator v_begin = i_vars.begin(),
01997          v_end = i_vars.end(); v_begin != v_end; ++v_begin) {
01998     gcd_assign(gcd, p.coefficient(Variable(*v_begin)), p_divisor);
01999     if (gcd != p_divisor) {
02000       non_int_dim = *v_begin;
02001       found_satisfiable_generator = false;
02002       break;
02003     }
02004   }
02005   if (found_satisfiable_generator) {
02006     // All the coordinates of `point' are satisfiable.
02007     if (mip_status == UNBOUNDED_MIP_PROBLEM) {
02008       // This is a point that belongs to the MIP_Problem.
02009       // In this way we are sure that we will return every time
02010       // a feasible point if requested by the user.
02011       incumbent_solution_point = p;
02012       return mip_status;
02013     }
02014     if (!have_incumbent_solution
02015         || (mip.optimization_mode() == MAXIMIZATION
02016             && tmp_rational > incumbent_solution_value)
02017         || tmp_rational < incumbent_solution_value) {
02018       incumbent_solution_value = tmp_rational;
02019       incumbent_solution_point = p;
02020       have_incumbent_solution = true;
02021 #if PPL_NOISY_SIMPLEX
02022       PPL_DIRTY_TEMP_COEFFICIENT(numer);
02023       PPL_DIRTY_TEMP_COEFFICIENT(denom);
02024       mip.evaluate_objective_function(p, numer, denom);
02025       std::cout << "MIP_Problem::solve_mip(): "
02026                 << "new value found: " << numer << "/" << denom
02027                 << "." << std::endl;
02028 #endif // PPL_NOISY_SIMPLEX
02029     }
02030     return mip_status;
02031   }
02032 
02033   PPL_ASSERT(non_int_dim < mip.space_dimension());
02034 
02035   assign_r(tmp_rational.get_num(), p.coefficient(Variable(non_int_dim)),
02036            ROUND_NOT_NEEDED);
02037   assign_r(tmp_rational.get_den(), p_divisor, ROUND_NOT_NEEDED);
02038   tmp_rational.canonicalize();
02039   assign_r(tmp_coeff1, tmp_rational, ROUND_DOWN);
02040   assign_r(tmp_coeff2, tmp_rational, ROUND_UP);
02041   {
02042     MIP_Problem mip_aux(mip, Inherit_Constraints());
02043     mip_aux.add_constraint(Variable(non_int_dim) <= tmp_coeff1);
02044 #if PPL_NOISY_SIMPLEX
02045     using namespace IO_Operators;
02046     std::cout << "MIP_Problem::solve_mip(): "
02047               << "descending with: "
02048               << (Variable(non_int_dim) <= tmp_coeff1)
02049               << "." << std::endl;
02050 #endif // PPL_NOISY_SIMPLEX
02051     solve_mip(have_incumbent_solution, incumbent_solution_value,
02052               incumbent_solution_point, mip_aux, i_vars);
02053   }
02054   // TODO: change this when we will be able to remove constraints.
02055   mip.add_constraint(Variable(non_int_dim) >= tmp_coeff2);
02056 #if PPL_NOISY_SIMPLEX
02057   using namespace IO_Operators;
02058   std::cout << "MIP_Problem::solve_mip(): "
02059             << "descending with: "
02060             << (Variable(non_int_dim) >= tmp_coeff2)
02061             << "." << std::endl;
02062 #endif // PPL_NOISY_SIMPLEX
02063   solve_mip(have_incumbent_solution, incumbent_solution_value,
02064             incumbent_solution_point, mip, i_vars);
02065   return have_incumbent_solution ? mip_status : UNFEASIBLE_MIP_PROBLEM;
02066 }
02067 
02068 bool
02069 PPL::MIP_Problem::choose_branching_variable(const MIP_Problem& mip,
02070                                             const Variables_Set& i_vars,
02071                                             dimension_type& branching_index) {
02072   // Insert here the variables that do not satisfy the integrality
02073   // condition.
02074   const std::vector<Constraint*>& input_cs = mip.input_cs;
02075   const Generator& last_generator = mip.last_generator;
02076   Coefficient_traits::const_reference last_generator_divisor
02077     = last_generator.divisor();
02078   Variables_Set candidate_variables;
02079 
02080   PPL_DIRTY_TEMP_COEFFICIENT(gcd);
02081   for (Variables_Set::const_iterator v_it = i_vars.begin(),
02082          v_end = i_vars.end(); v_it != v_end; ++v_it) {
02083     gcd_assign(gcd,
02084                last_generator.coefficient(Variable(*v_it)),
02085                last_generator_divisor);
02086     if (gcd != last_generator_divisor)
02087       candidate_variables.insert(*v_it);
02088   }
02089   // If this set is empty, we have finished.
02090   if (candidate_variables.empty())
02091     return true;
02092 
02093   // Check how many `active constraints' we have and track them.
02094   const dimension_type input_cs_num_rows = input_cs.size();
02095   std::deque<bool> satisfiable_constraints (input_cs_num_rows, false);
02096   for (dimension_type i = input_cs_num_rows; i-- > 0; )
02097     // An equality is an `active constraint' by definition.
02098     // If we have an inequality, check if it is an `active constraint'.
02099     if (input_cs[i]->is_equality()
02100         || is_saturated(*(input_cs[i]), last_generator))
02101       satisfiable_constraints[i] = true;
02102 
02103   dimension_type current_num_appearances = 0;
02104   dimension_type winning_num_appearances = 0;
02105 
02106   // For every candidate variable, check how many times this appear in the
02107   // active constraints.
02108   for (Variables_Set::const_iterator v_it = candidate_variables.begin(),
02109          v_end = candidate_variables.end(); v_it != v_end; ++v_it) {
02110     current_num_appearances = 0;
02111     for (dimension_type i = input_cs_num_rows; i-- > 0; )
02112       if (satisfiable_constraints[i]
02113           && *v_it < input_cs[i]->space_dimension()
02114           && input_cs[i]->coefficient(Variable(*v_it)) != 0)
02115         ++current_num_appearances;
02116     if (current_num_appearances >= winning_num_appearances) {
02117       winning_num_appearances = current_num_appearances;
02118       branching_index = *v_it;
02119     }
02120   }
02121   return false;
02122 }
02123 
02124 bool
02125 PPL::MIP_Problem::is_mip_satisfiable(MIP_Problem& mip,
02126                                      const Variables_Set& i_vars,
02127                                      Generator& p) {
02128 #if PPL_NOISY_SIMPLEX
02129   ++mip_recursion_level;
02130   std::cout << "MIP_Problem::is_mip_satisfiable(): "
02131             << "entering recursion level " << mip_recursion_level
02132             << "." << std::endl;
02133 #endif // PPL_NOISY_SIMPLEX
02134   PPL_ASSERT(mip.integer_space_dimensions().empty());
02135 
02136   // Solve the MIP problem.
02137   if (!mip.is_lp_satisfiable()) {
02138 #if PPL_NOISY_SIMPLEX
02139     std::cout << "MIP_Problem::is_mip_satisfiable(): "
02140               << "exiting from recursion level " << mip_recursion_level
02141               << "." << std::endl;
02142     --mip_recursion_level;
02143 #endif // PPL_NOISY_SIMPLEX
02144     return false;
02145   }
02146 
02147   PPL_DIRTY_TEMP(mpq_class, tmp_rational);
02148   PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff1);
02149   PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff2);
02150   bool found_satisfiable_generator = true;
02151   dimension_type non_int_dim;
02152   p = mip.last_generator;
02153   Coefficient_traits::const_reference p_divisor = p.divisor();
02154 
02155 #if PPL_SIMPLEX_USE_MIP_HEURISTIC
02156   found_satisfiable_generator
02157     = choose_branching_variable(mip, i_vars, non_int_dim);
02158 #else
02159   PPL_DIRTY_TEMP_COEFFICIENT(gcd);
02160   for (Variables_Set::const_iterator v_begin = i_vars.begin(),
02161          v_end = i_vars.end(); v_begin != v_end; ++v_begin) {
02162     gcd_assign(gcd, p.coefficient(Variable(*v_begin)), p_divisor);
02163     if (gcd != p_divisor) {
02164       non_int_dim = *v_begin;
02165       found_satisfiable_generator = false;
02166       break;
02167     }
02168   }
02169 #endif
02170 
02171   if (found_satisfiable_generator)
02172     return true;
02173 
02174   PPL_ASSERT(non_int_dim < mip.space_dimension());
02175 
02176   assign_r(tmp_rational.get_num(), p.coefficient(Variable(non_int_dim)),
02177            ROUND_NOT_NEEDED);
02178   assign_r(tmp_rational.get_den(), p_divisor, ROUND_NOT_NEEDED);
02179   tmp_rational.canonicalize();
02180   assign_r(tmp_coeff1, tmp_rational, ROUND_DOWN);
02181   assign_r(tmp_coeff2, tmp_rational, ROUND_UP);
02182   {
02183     MIP_Problem mip_aux(mip, Inherit_Constraints());
02184     mip_aux.add_constraint(Variable(non_int_dim) <= tmp_coeff1);
02185 #if PPL_NOISY_SIMPLEX
02186     using namespace IO_Operators;
02187     std::cout << "MIP_Problem::is_mip_satisfiable(): "
02188               << "descending with: "
02189               << (Variable(non_int_dim) <= tmp_coeff1)
02190               << "." << std::endl;
02191 #endif // PPL_NOISY_SIMPLEX
02192     if (is_mip_satisfiable(mip_aux, i_vars, p)) {
02193 #if PPL_NOISY_SIMPLEX
02194       std::cout << "MIP_Problem::is_mip_satisfiable(): "
02195                 << "exiting from recursion level " << mip_recursion_level
02196                 << "." << std::endl;
02197       --mip_recursion_level;
02198 #endif // PPL_NOISY_SIMPLEX
02199       return true;
02200     }
02201   }
02202   mip.add_constraint(Variable(non_int_dim) >= tmp_coeff2);
02203 #if PPL_NOISY_SIMPLEX
02204   using namespace IO_Operators;
02205   std::cout << "MIP_Problem::is_mip_satisfiable(): "
02206             << "descending with: "
02207             << (Variable(non_int_dim) >= tmp_coeff2)
02208             << "." << std::endl;
02209 #endif // PPL_NOISY_SIMPLEX
02210   bool satisfiable = is_mip_satisfiable(mip, i_vars, p);
02211 #if PPL_NOISY_SIMPLEX
02212   std::cout << "MIP_Problem::is_mip_satisfiable(): "
02213             << "exiting from recursion level " << mip_recursion_level
02214             << "." << std::endl;
02215   --mip_recursion_level;
02216 #endif // PPL_NOISY_SIMPLEX
02217   return satisfiable;
02218 }
02219 
02220 bool
02221 PPL::MIP_Problem::OK() const {
02222 #ifndef NDEBUG
02223   using std::endl;
02224   using std::cerr;
02225 #endif
02226   const dimension_type input_cs_num_rows = input_cs.size();
02227 
02228   // Check that every member used is OK.
02229 
02230   if (inherited_constraints > input_cs_num_rows) {
02231 #ifndef NDEBUG
02232     cerr << "The MIP_Problem claims to have inherited from its ancestors "
02233          << "more constraints than are recorded in this->input_cs."
02234          << endl;
02235     ascii_dump(cerr);
02236 #endif
02237     return false;
02238   }
02239 
02240   if (first_pending_constraint > input_cs_num_rows) {
02241 #ifndef NDEBUG
02242     cerr << "The MIP_Problem claims to have pending constraints "
02243          << "that are not recorded in this->input_cs."
02244          << endl;
02245     ascii_dump(cerr);
02246 #endif
02247     return false;
02248   }
02249 
02250   for (dimension_type i = input_cs_num_rows; i-- > 0; )
02251     if (!input_cs[i]->OK())
02252       return false;
02253 
02254   if (!tableau.OK() || !input_obj_function.OK() || !last_generator.OK())
02255     return false;
02256 
02257   // Constraint system should contain no strict inequalities.
02258   for (dimension_type i = input_cs_num_rows; i-- > 0; )
02259     if (input_cs[i]->is_strict_inequality()) {
02260 #ifndef NDEBUG
02261       cerr << "The feasible region of the MIP_Problem is defined by "
02262            << "a constraint system containing strict inequalities."
02263            << endl;
02264       ascii_dump(cerr);
02265 #endif
02266       return false;
02267     }
02268 
02269   // Constraint system and objective function should be dimension compatible.
02270   if (external_space_dim < input_obj_function.space_dimension()) {
02271 #ifndef NDEBUG
02272     cerr << "The MIP_Problem and the objective function have "
02273          << "incompatible space dimensions ("
02274          << external_space_dim << " < "
02275          << input_obj_function.space_dimension() << ")."
02276          << endl;
02277     ascii_dump(cerr);
02278 #endif
02279     return false;
02280   }
02281 
02282   if (status != UNSATISFIABLE && initialized) {
02283     // Here `last_generator' has to be meaningful.
02284     // Check for dimension compatibility and actual feasibility.
02285     if (external_space_dim != last_generator.space_dimension()) {
02286 #ifndef NDEBUG
02287       cerr << "The MIP_Problem and the cached feasible point have "
02288            << "incompatible space dimensions ("
02289            << external_space_dim << " != "
02290            << last_generator.space_dimension() << ")."
02291            << endl;
02292       ascii_dump(cerr);
02293 #endif
02294       return false;
02295     }
02296 
02297     for (dimension_type i = 0; i < first_pending_constraint; ++i)
02298       if (!is_satisfied(*(input_cs[i]), last_generator)) {
02299 #ifndef NDEBUG
02300         cerr << "The cached feasible point does not belong to "
02301              << "the feasible region of the MIP_Problem."
02302              << endl;
02303         ascii_dump(cerr);
02304 #endif
02305         return false;
02306       }
02307 
02308     // Check that every integer declared variable is really integer.
02309     // in the solution found.
02310     if (!i_variables.empty()) {
02311       PPL_DIRTY_TEMP_COEFFICIENT(gcd);
02312       for (Variables_Set::const_iterator v_it = i_variables.begin(),
02313             v_end = i_variables.end(); v_it != v_end; ++v_it) {
02314         gcd_assign(gcd, last_generator.coefficient(Variable(*v_it)),
02315                    last_generator.divisor());
02316         if (gcd != last_generator.divisor())
02317           return false;
02318       }
02319     }
02320 
02321     const dimension_type tableau_num_rows = tableau.num_rows();
02322     const dimension_type tableau_num_columns = tableau.num_columns();
02323 
02324     // The number of rows in the tableau and base should be equal.
02325     if (tableau_num_rows != base.size()) {
02326 #ifndef NDEBUG
02327       cerr << "tableau and base have incompatible sizes" << endl;
02328       ascii_dump(cerr);
02329 #endif
02330       return false;
02331     }
02332     // The size of `mapping' should be equal to the space dimension
02333     // of `input_cs' plus one.
02334     if (mapping.size() != external_space_dim + 1) {
02335 #ifndef NDEBUG
02336       cerr << "`input_cs' and `mapping' have incompatible sizes" << endl;
02337       ascii_dump(cerr);
02338 #endif
02339       return false;
02340     }
02341 
02342     // The number of columns in the tableau and working_cost should be equal.
02343     if (tableau_num_columns != working_cost.size()) {
02344 #ifndef NDEBUG
02345       cerr << "tableau and working_cost have incompatible sizes" << endl;
02346       ascii_dump(cerr);
02347 #endif
02348       return false;
02349     }
02350 
02351     // The vector base should contain indices of tableau's columns.
02352     for (dimension_type i = base.size(); i-- > 0; ) {
02353       if (base[i] > tableau_num_columns) {
02354 #ifndef NDEBUG
02355         cerr << "base contains an invalid column index" << endl;
02356         ascii_dump(cerr);
02357 #endif
02358         return false;
02359       }
02360     }
02361     {
02362       // Needed to sort accesses to tableau_j, improving performance.
02363       typedef std::vector<std::pair<dimension_type, dimension_type> >
02364         pair_vector_t;
02365       pair_vector_t vars_in_base;
02366       for (dimension_type i = base.size(); i-- > 0; )
02367         vars_in_base.push_back(std::make_pair(base[i], i));
02368 
02369       std::sort(vars_in_base.begin(), vars_in_base.end());
02370 
02371       for (dimension_type j = tableau_num_rows; j-- > 0; ) {
02372         const Row& tableau_j = tableau[j];
02373         pair_vector_t::iterator i = vars_in_base.begin();
02374         pair_vector_t::iterator i_end = vars_in_base.end();
02375         Row::const_iterator itr = tableau_j.begin();
02376         Row::const_iterator itr_end = tableau_j.end();
02377         for ( ; i != i_end && itr != itr_end; ++i) {
02378           // tableau[i][base[j]], with i different from j, must be zero.
02379           if (itr.index() < i->first)
02380             itr = tableau_j.lower_bound(itr, itr.index());
02381           if (i->second != j && itr.index() == i->first && *itr != 0) {
02382 #ifndef NDEBUG
02383             cerr << "tableau[i][base[j]], with i different from j, must be "
02384                  << "zero" << endl;
02385             ascii_dump(cerr);
02386 #endif
02387             return false;
02388           }
02389         }
02390       }
02391     }
02392     // tableau[i][base[i]] must not be a zero.
02393     for (dimension_type i = base.size(); i-- > 0; ) {
02394       if (tableau[i].get(base[i]) == 0) {
02395 #ifndef NDEBUG
02396         cerr << "tableau[i][base[i]] must not be a zero" << endl;
02397         ascii_dump(cerr);
02398 #endif
02399         return false;
02400       }
02401     }
02402 
02403     // The last column of the tableau must contain only zeroes.
02404     for (dimension_type i = tableau_num_rows; i-- > 0; )
02405       if (tableau[i].get(tableau_num_columns - 1) != 0) {
02406 #ifndef NDEBUG
02407         cerr << "the last column of the tableau must contain only"
02408           "zeroes"<< endl;
02409         ascii_dump(cerr);
02410 #endif
02411         return false;
02412       }
02413   }
02414 
02415   // All checks passed.
02416   return true;
02417 }
02418 
02419 void
02420 PPL::MIP_Problem::ascii_dump(std::ostream& s) const {
02421   using namespace IO_Operators;
02422   s << "\nexternal_space_dim: " << external_space_dim << " \n";
02423   s << "\ninternal_space_dim: " << internal_space_dim << " \n";
02424 
02425   const dimension_type input_cs_size = input_cs.size();
02426 
02427   s << "\ninput_cs( " << input_cs_size << " )\n";
02428   for (dimension_type i = 0; i < input_cs_size; ++i)
02429     input_cs[i]->ascii_dump(s);
02430 
02431   s << "\ninherited_constraints: " <<  inherited_constraints
02432     << std::endl;
02433 
02434   s << "\nfirst_pending_constraint: " <<  first_pending_constraint
02435     << std::endl;
02436 
02437   s << "\ninput_obj_function\n";
02438   input_obj_function.ascii_dump(s);
02439   s << "\nopt_mode "
02440     << ((opt_mode == MAXIMIZATION) ? "MAXIMIZATION" : "MINIMIZATION") << "\n";
02441 
02442   s << "\ninitialized: " << (initialized ? "YES" : "NO") << "\n";
02443   s << "\npricing: ";
02444   switch (pricing) {
02445   case PRICING_STEEPEST_EDGE_FLOAT:
02446     s << "PRICING_STEEPEST_EDGE_FLOAT";
02447     break;
02448   case PRICING_STEEPEST_EDGE_EXACT:
02449     s << "PRICING_STEEPEST_EDGE_EXACT";
02450     break;
02451   case PRICING_TEXTBOOK:
02452     s << "PRICING_TEXTBOOK";
02453     break;
02454   }
02455   s << "\n";
02456 
02457   s << "\nstatus: ";
02458   switch (status) {
02459   case UNSATISFIABLE:
02460     s << "UNSATISFIABLE";
02461     break;
02462   case SATISFIABLE:
02463     s << "SATISFIABLE";
02464     break;
02465   case UNBOUNDED:
02466     s << "UNBOUNDED";
02467     break;
02468   case OPTIMIZED:
02469     s << "OPTIMIZED";
02470     break;
02471   case PARTIALLY_SATISFIABLE:
02472     s << "PARTIALLY_SATISFIABLE";
02473     break;
02474   }
02475   s << "\n";
02476 
02477   s << "\ntableau\n";
02478   tableau.ascii_dump(s);
02479   s << "\nworking_cost( " << working_cost.size()<< " )\n";
02480   working_cost.ascii_dump(s);
02481 
02482   const dimension_type base_size = base.size();
02483   s << "\nbase( " << base_size << " )\n";
02484   for (dimension_type i = 0; i != base_size; ++i)
02485     s << base[i] << ' ';
02486 
02487   s << "\nlast_generator\n";
02488   last_generator.ascii_dump(s);
02489 
02490   const dimension_type mapping_size = mapping.size();
02491   s << "\nmapping( " << mapping_size << " )\n";
02492   for (dimension_type i = 1; i < mapping_size; ++i)
02493     s << "\n"<< i << " -> " << mapping[i].first << " -> " << mapping[i].second
02494       << ' ';
02495 
02496   s << "\n\ninteger_variables";
02497   i_variables.ascii_dump(s);
02498 }
02499 
02500 PPL_OUTPUT_DEFINITIONS(MIP_Problem)
02501 
02502 bool
02503 PPL::MIP_Problem::ascii_load(std::istream& s) {
02504   std::string str;
02505   if (!(s >> str) || str != "external_space_dim:")
02506     return false;
02507 
02508   if (!(s >> external_space_dim))
02509     return false;
02510 
02511   if (!(s >> str) || str != "internal_space_dim:")
02512     return false;
02513 
02514   if (!(s >> internal_space_dim))
02515     return false;
02516 
02517   if (!(s >> str) || str != "input_cs(")
02518     return false;
02519 
02520   dimension_type input_cs_size;
02521 
02522   if (!(s >> input_cs_size))
02523     return false;
02524 
02525   if (!(s >> str) || str != ")")
02526     return false;
02527 
02528   Constraint c(Constraint::zero_dim_positivity());
02529   input_cs.reserve(input_cs_size);
02530   for (dimension_type i = 0; i < input_cs_size; ++i) {
02531     if (!c.ascii_load(s))
02532       return false;
02533     add_constraint_helper(c);
02534   }
02535 
02536   if (!(s >> str) || str != "inherited_constraints:")
02537     return false;
02538 
02539   if (!(s >> inherited_constraints))
02540     return false;
02541   // NOTE: we loaded the number of inherited constraints, but we nonetheless
02542   // reset to zero the corresponding data member, since we do not support
02543   // constraint inheritance via ascii_load.
02544   inherited_constraints = 0;
02545 
02546   if (!(s >> str) || str != "first_pending_constraint:")
02547     return false;
02548 
02549   if (!(s >> first_pending_constraint))
02550     return false;
02551 
02552   if (!(s >> str) || str != "input_obj_function")
02553     return false;
02554 
02555   if (!input_obj_function.ascii_load(s))
02556     return false;
02557 
02558   if (!(s >> str) || str != "opt_mode")
02559     return false;
02560 
02561   if (!(s >> str))
02562     return false;
02563 
02564   if (str == "MAXIMIZATION")
02565     set_optimization_mode(MAXIMIZATION);
02566   else {
02567     if (str != "MINIMIZATION")
02568       return false;
02569     set_optimization_mode(MINIMIZATION);
02570   }
02571 
02572   if (!(s >> str) || str != "initialized:")
02573     return false;
02574   if (!(s >> str))
02575     return false;
02576   if (str == "YES")
02577     initialized = true;
02578   else if (str == "NO")
02579     initialized = false;
02580   else
02581     return false;
02582 
02583   if (!(s >> str) || str != "pricing:")
02584     return false;
02585   if (!(s >> str))
02586     return false;
02587   if (str == "PRICING_STEEPEST_EDGE_FLOAT")
02588     pricing = PRICING_STEEPEST_EDGE_FLOAT;
02589   else if (str == "PRICING_STEEPEST_EDGE_EXACT")
02590     pricing = PRICING_STEEPEST_EDGE_EXACT;
02591   else if (str == "PRICING_TEXTBOOK")
02592     pricing = PRICING_TEXTBOOK;
02593   else
02594     return false;
02595 
02596   if (!(s >> str) || str != "status:")
02597     return false;
02598 
02599   if (!(s >> str))
02600     return false;
02601 
02602   if (str == "UNSATISFIABLE")
02603     status = UNSATISFIABLE;
02604   else if (str == "SATISFIABLE")
02605     status = SATISFIABLE;
02606   else if (str == "UNBOUNDED")
02607     status = UNBOUNDED;
02608   else if (str == "OPTIMIZED")
02609     status = OPTIMIZED;
02610   else if (str == "PARTIALLY_SATISFIABLE")
02611     status = PARTIALLY_SATISFIABLE;
02612   else
02613     return false;
02614 
02615   if (!(s >> str) || str != "tableau")
02616     return false;
02617 
02618   if (!tableau.ascii_load(s))
02619     return false;
02620 
02621   if (!(s >> str) || str != "working_cost(")
02622     return false;
02623 
02624   dimension_type working_cost_dim;
02625 
02626   if (!(s >> working_cost_dim))
02627     return false;
02628 
02629   if (!(s >> str) || str != ")")
02630     return false;
02631 
02632   if (!working_cost.ascii_load(s))
02633     return false;
02634 
02635   if (!(s >> str) || str != "base(")
02636     return false;
02637 
02638   dimension_type base_size;
02639   if (!(s >> base_size))
02640     return false;
02641 
02642   if (!(s >> str) || str != ")")
02643     return false;
02644 
02645   for (dimension_type i = 0; i != base_size; ++i) {
02646     dimension_type base_value;
02647     if (!(s >> base_value))
02648       return false;
02649     base.push_back(base_value);
02650   }
02651 
02652   if (!(s >> str) || str != "last_generator")
02653     return false;
02654 
02655   if (!last_generator.ascii_load(s))
02656     return false;
02657 
02658   if (!(s >> str) || str != "mapping(")
02659     return false;
02660 
02661   dimension_type mapping_size;
02662   if (!(s >> mapping_size))
02663     return false;
02664 
02665   if (!(s >> str) || str != ")")
02666     return false;
02667 
02668   // The first `mapping' index is never used, so we initialize
02669   // it pushing back a dummy value.
02670   if (tableau.num_columns() != 0)
02671     mapping.push_back(std::make_pair(0, 0));
02672 
02673   for (dimension_type i = 1; i < mapping_size; ++i) {
02674     dimension_type index;
02675     if (!(s >> index))
02676       return false;
02677 
02678     if (!(s >> str) || str != "->")
02679       return false;
02680 
02681     dimension_type first_value;
02682     if (!(s >> first_value))
02683       return false;
02684 
02685     if (!(s >> str) || str != "->")
02686       return false;
02687 
02688     dimension_type second_value;
02689     if (!(s >> second_value))
02690       return false;
02691 
02692     mapping.push_back(std::make_pair(first_value, second_value));
02693   }
02694 
02695   if (!(s >> str) || str != "integer_variables")
02696     return false;
02697 
02698   if (!i_variables.ascii_load(s))
02699     return false;
02700 
02701   PPL_ASSERT(OK());
02702   return true;
02703 }
02704 
02706 std::ostream&
02707 PPL::IO_Operators::operator<<(std::ostream& s, const MIP_Problem& mip) {
02708   s << "Constraints:";
02709   for (MIP_Problem::const_iterator i = mip.constraints_begin(),
02710          i_end = mip.constraints_end(); i != i_end; ++i)
02711     s << "\n" << *i;
02712   s << "\nObjective function: "
02713     << mip.objective_function()
02714     << "\nOptimization mode: "
02715     << ((mip.optimization_mode() == MAXIMIZATION)
02716         ? "MAXIMIZATION"
02717         : "MINIMIZATION");
02718   s << "\nInteger variables: " << mip.integer_space_dimensions();
02719   return s;
02720 }