Parma_Polyhedra_Library::MIP_Problem Class Reference
[C++ Language Interface]

A Mixed Integer (linear) Programming problem. More...

#include <MIP_Problem.defs.hh>

Collaboration diagram for Parma_Polyhedra_Library::MIP_Problem:
Collaboration graph
[legend]

List of all members.

Classes

struct  RAII_Temporary_Real_Relaxation
 A helper class to temporarily relax a MIP problem using RAII. More...

Public Types

enum  Control_Parameter_Name { PRICING }
 

Names of MIP problems' control parameters.

More...
enum  Control_Parameter_Value { PRICING_STEEPEST_EDGE_FLOAT, PRICING_STEEPEST_EDGE_EXACT, PRICING_TEXTBOOK }
 

Possible values for MIP problem's control parameters.

More...
typedef
Constraint_Sequence::const_iterator 
const_iterator
 A type alias for the read-only iterator on the constraints defining the feasible region.

Public Member Functions

 MIP_Problem (dimension_type dim=0)
 Builds a trivial MIP problem.
template<typename In >
 MIP_Problem (dimension_type dim, In first, In last, const Variables_Set &int_vars, const Linear_Expression &obj=Linear_Expression::zero(), Optimization_Mode mode=MAXIMIZATION)
 Builds an MIP problem having space dimension dim from the sequence of constraints in the range $[\mathrm{first}, \mathrm{last})$, the objective function obj and optimization mode mode; those dimensions whose indices occur in int_vars are constrained to take an integer value.
template<typename In >
 MIP_Problem (dimension_type dim, In first, In last, const Linear_Expression &obj=Linear_Expression::zero(), Optimization_Mode mode=MAXIMIZATION)
 Builds an MIP problem having space dimension dim from the sequence of constraints in the range $[\mathrm{first}, \mathrm{last})$, the objective function obj and optimization mode mode.
 MIP_Problem (dimension_type dim, const Constraint_System &cs, const Linear_Expression &obj=Linear_Expression::zero(), Optimization_Mode mode=MAXIMIZATION)
 Builds an MIP problem having space dimension dim from the constraint system cs, the objective function obj and optimization mode mode.
 MIP_Problem (const MIP_Problem &y)
 Ordinary copy constructor.
 ~MIP_Problem ()
 Destructor.
MIP_Problemoperator= (const MIP_Problem &y)
 Assignment operator.
dimension_type space_dimension () const
 Returns the space dimension of the MIP problem.
const Variables_Setinteger_space_dimensions () const
 Returns a set containing all the variables' indexes constrained to be integral.
const_iterator constraints_begin () const
 Returns a read-only iterator to the first constraint defining the feasible region.
const_iterator constraints_end () const
 Returns a past-the-end read-only iterator to the sequence of constraints defining the feasible region.
const Linear_Expressionobjective_function () const
 Returns the objective function.
Optimization_Mode optimization_mode () const
 Returns the optimization mode.
void clear ()
 Resets *this to be equal to the trivial MIP problem.
void add_space_dimensions_and_embed (dimension_type m)
 Adds m new space dimensions and embeds the old MIP problem in the new vector space.
void add_to_integer_space_dimensions (const Variables_Set &i_vars)
 Sets the variables whose indexes are in set i_vars to be integer space dimensions.
void add_constraint (const Constraint &c)
 Adds a copy of constraint c to the MIP problem.
void add_constraints (const Constraint_System &cs)
 Adds a copy of the constraints in cs to the MIP problem.
void set_objective_function (const Linear_Expression &obj)
 Sets the objective function to obj.
void set_optimization_mode (Optimization_Mode mode)
 Sets the optimization mode to mode.
bool is_satisfiable () const
 Checks satisfiability of *this.
MIP_Problem_Status solve () const
 Optimizes the MIP problem.
void evaluate_objective_function (const Generator &evaluating_point, Coefficient &num, Coefficient &den) const
 Sets num and den so that $\frac{num}{den}$ is the result of evaluating the objective function on evaluating_point.
const Generatorfeasible_point () const
 Returns a feasible point for *this, if it exists.
const Generatoroptimizing_point () const
 Returns an optimal point for *this, if it exists.
void optimal_value (Coefficient &num, Coefficient &den) const
 Sets num and den so that $\frac{num}{den}$ is the solution of the optimization problem.
bool OK () const
 Checks if all the invariants are satisfied.
void ascii_dump () const
 Writes to std::cerr an ASCII representation of *this.
void ascii_dump (std::ostream &s) const
 Writes to s an ASCII representation of *this.
void print () const
 Prints *this to std::cerr using operator<<.
bool ascii_load (std::istream &s)
 Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this accordingly. Returns true if successful, false otherwise.
memory_size_type total_memory_in_bytes () const
 Returns the total size in bytes of the memory occupied by *this.
memory_size_type external_memory_in_bytes () const
 Returns the size in bytes of the memory managed by *this.
void swap (MIP_Problem &y)
 Swaps *this with y.
Control_Parameter_Value get_control_parameter (Control_Parameter_Name name) const
 Returns the value of the control parameter name.
void set_control_parameter (Control_Parameter_Value value)
 Sets control parameter value.

Static Public Member Functions

static dimension_type max_space_dimension ()
 Returns the maximum space dimension an MIP_Problem can handle.

Private Types

enum  Status {
  UNSATISFIABLE, SATISFIABLE, UNBOUNDED, OPTIMIZED,
  PARTIALLY_SATISFIABLE
}
 

An enumerated type describing the internal status of the MIP problem.

More...
typedef std::vector< ConstraintConstraint_Sequence
 A type alias for a sequence of constraints.

Private Member Functions

bool process_pending_constraints ()
 Processes the pending constraints of *this.
void second_phase ()
 Optimizes the MIP problem using the second phase of the primal simplex algorithm.
MIP_Problem_Status compute_tableau (std::vector< dimension_type > &worked_out_row)
 Assigns to this->tableau a simplex tableau representing the MIP problem, inserting into this->mapping the information that is required to recover the original MIP problem.
bool parse_constraints (dimension_type &additional_tableau_rows, dimension_type &additional_slack_variables, std::deque< bool > &is_tableau_constraint, std::deque< bool > &is_satisfied_inequality, std::deque< bool > &is_nonnegative_variable, std::deque< bool > &is_remergeable_variable) const
 Parses the pending constraints to gather information on how to resize the tableau.
dimension_type get_exiting_base_index (dimension_type entering_var_index) const
 Computes the row index of the variable exiting the base of the MIP problem. Implemented with anti-cycling rule.
void pivot (dimension_type entering_var_index, dimension_type exiting_base_index)
 Performs the pivoting operation on the tableau.
dimension_type textbook_entering_index () const
 Computes the column index of the variable entering the base, using the textbook algorithm with anti-cycling rule.
dimension_type steepest_edge_exact_entering_index () const
 Computes the column index of the variable entering the base, using an exact steepest-edge algorithm with anti-cycling rule.
dimension_type steepest_edge_float_entering_index () const
 Same as steepest_edge_exact_entering_index, but using floating points.
bool compute_simplex_using_exact_pricing ()
 Returns true if and if only the algorithm successfully computed a feasible solution.
bool compute_simplex_using_steepest_edge_float ()
 Returns true if and if only the algorithm successfully computed a feasible solution.
void erase_artificials (dimension_type begin_artificials, dimension_type end_artificials)
 Drop unnecessary artificial variables from the tableau and get ready for the second phase of the simplex algorithm.
bool is_in_base (dimension_type var_index, dimension_type &row_index) const
void compute_generator () const
 Computes a valid generator that satisfies all the constraints of the Linear Programming problem associated to *this.
dimension_type merge_split_variable (dimension_type var_index)
 Merges back the positive and negative part of a (previously split) variable after detecting a corresponding nonnegativity constraint.
bool is_lp_satisfiable () const
 Returns true if and if only the LP problem is satisfiable.

Static Private Member Functions

static void linear_combine (Row &x, const Row &y, const dimension_type k)
 Linearly combines x with y so that *this[k] is 0.
static bool is_satisfied (const Constraint &c, const Generator &g)
 Returns true if and only if c is satisfied by g.
static bool is_saturated (const Constraint &c, const Generator &g)
 Returns true if and only if c is saturated by g.
static MIP_Problem_Status solve_mip (bool &have_incumbent_solution, mpq_class &incumbent_solution_value, Generator &incumbent_solution_point, MIP_Problem &mip, const Variables_Set &i_vars)
 Returns a status that encodes the solution of the MIP problem.
static bool is_mip_satisfiable (MIP_Problem &lp, const Variables_Set &i_vars, Generator &p)
 Returns true if and if only the LP problem lp is satisfiable when variables in i_vars can only take integral values.
static bool choose_branching_variable (const MIP_Problem &lp, const Variables_Set &i_vars, dimension_type &branching_index)
 Returns true if and if only mip.last_generator satisfies all the integrality coditions implicitly stated using by i_vars.

Private Attributes

dimension_type external_space_dim
 The dimension of the vector space.
dimension_type internal_space_dim
 The space dimension of the current (partial) solution of the MIP problem; it may be smaller than external_space_dim.
Matrix tableau
 The matrix encoding the current feasible region in tableau form.
Row working_cost
 The working cost function.
std::vector< std::pair
< dimension_type,
dimension_type > > 
mapping
 A map between the variables of `input_cs' and `tableau'.
std::vector< dimension_typebase
 The current basic solution.
Status status
 The internal state of the MIP problem.
Control_Parameter_Value pricing
 The pricing method in use.
bool initialized
 A Boolean encoding whether or not internal data structures have already been properly sized and populated: useful to allow for deeper checks in method OK().
Constraint_Sequence input_cs
 The sequence of constraints describing the feasible region.
dimension_type first_pending_constraint
 The first index of `input_cs' containing a pending constraint.
Linear_Expression input_obj_function
 The objective function to be optimized.
Optimization_Mode opt_mode
 The optimization mode requested.
Generator last_generator
 The last successfully computed feasible or optimizing point.
Variables_Set i_variables
 A set containing all the indexes of variables that are constrained to have an integer value.

Friends

class RAII_Temporary_Real_Relaxation

Related Functions

(Note that these are not member functions.)



std::ostream & operator<< (std::ostream &s, const MIP_Problem &lp)
 Output operator.
void swap (Parma_Polyhedra_Library::MIP_Problem &x, Parma_Polyhedra_Library::MIP_Problem &y)
 Specializes std::swap.

Detailed Description

A Mixed Integer (linear) Programming problem.

An object of this class encodes a mixed integer (linear) programming problem. The MIP problem is specified by providing:

The class provides support for the (incremental) solution of the MIP problem based on variations of the revised simplex method and on branch-and-bound techniques. The result of the resolution process is expressed in terms of an enumeration, encoding the feasibility and the unboundedness of the optimization problem. The class supports simple feasibility tests (i.e., no optimization), as well as the extraction of an optimal (resp., feasible) point, provided the MIP_Problem is optimizable (resp., feasible).

By exploiting the incremental nature of the solver, it is possible to reuse part of the computational work already done when solving variants of a given MIP_Problem: currently, incremental resolution supports the addition of space dimensions, the addition of constraints, the change of objective function and the change of optimization mode.

Definition at line 80 of file MIP_Problem.defs.hh.


Member Typedef Documentation

typedef Constraint_Sequence::const_iterator Parma_Polyhedra_Library::MIP_Problem::const_iterator

A type alias for the read-only iterator on the constraints defining the feasible region.

Definition at line 237 of file MIP_Problem.defs.hh.

A type alias for a sequence of constraints.

Definition at line 230 of file MIP_Problem.defs.hh.


Member Enumeration Documentation

Names of MIP problems' control parameters.

Enumerator:
PRICING 

The pricing rule.

Definition at line 402 of file MIP_Problem.defs.hh.

00402                               {
00404     PRICING
00405   };

Possible values for MIP problem's control parameters.

Enumerator:
PRICING_STEEPEST_EDGE_FLOAT 

Steepest edge pricing method, using floating points (default).

PRICING_STEEPEST_EDGE_EXACT 

Steepest edge pricing method, using Coefficient.

PRICING_TEXTBOOK 

Textbook pricing method.

Definition at line 408 of file MIP_Problem.defs.hh.

An enumerated type describing the internal status of the MIP problem.

Enumerator:
UNSATISFIABLE 

The MIP problem is unsatisfiable.

SATISFIABLE 

The MIP problem is satisfiable; a feasible solution has been computed.

UNBOUNDED 

The MIP problem is unbounded; a feasible solution has been computed.

OPTIMIZED 

The MIP problem is optimized; an optimal solution has been computed.

PARTIALLY_SATISFIABLE 

The feasible region of the MIP problem has been changed by adding new space dimensions or new constraints; a feasible solution for the old feasible region is still available.

Definition at line 454 of file MIP_Problem.defs.hh.

00454               {
00456     UNSATISFIABLE,
00458     SATISFIABLE,
00460     UNBOUNDED,
00462     OPTIMIZED,
00468     PARTIALLY_SATISFIABLE
00469   };


Constructor & Destructor Documentation

Parma_Polyhedra_Library::MIP_Problem::MIP_Problem ( dimension_type  dim = 0  )  [explicit]

Builds a trivial MIP problem.

A trivial MIP problem requires to maximize the objective function $0$ on a vector space under no constraints at all: the origin of the vector space is an optimal solution.

Parameters:
dim The dimension of the vector space enclosing *this (optional argument with default value $0$).
Exceptions:
std::length_error Thrown if dim exceeds max_space_dimension().

Definition at line 65 of file MIP_Problem.cc.

References max_space_dimension(), and OK().

00066   : external_space_dim(dim),
00067     internal_space_dim(0),
00068     tableau(),
00069     working_cost(0, Row::Flags()),
00070     mapping(),
00071     base(),
00072     status(PARTIALLY_SATISFIABLE),
00073     pricing(PRICING_STEEPEST_EDGE_FLOAT),
00074     initialized(false),
00075     input_cs(),
00076     first_pending_constraint(0),
00077     input_obj_function(),
00078     opt_mode(MAXIMIZATION),
00079     last_generator(point()),
00080     i_variables() {
00081   // Check for space dimension overflow.
00082   if (dim > max_space_dimension())
00083     throw std::length_error("PPL::MIP_Problem::MIP_Problem(dim, cs, obj, "
00084                             "mode):\n"
00085                             "dim exceeds the maximum allowed "
00086                             "space dimension.");
00087   PPL_ASSERT(OK());
00088 }

template<typename In >
Parma_Polyhedra_Library::MIP_Problem::MIP_Problem ( dimension_type  dim,
In  first,
In  last,
const Variables_Set int_vars,
const Linear_Expression obj = Linear_Expression::zero(),
Optimization_Mode  mode = MAXIMIZATION 
) [inline]

Builds an MIP problem having space dimension dim from the sequence of constraints in the range $[\mathrm{first}, \mathrm{last})$, the objective function obj and optimization mode mode; those dimensions whose indices occur in int_vars are constrained to take an integer value.

Parameters:
dim The dimension of the vector space enclosing *this.
first An input iterator to the start of the sequence of constraints.
last A past-the-end input iterator to the sequence of constraints.
int_vars The set of variables' indexes that are constrained to take integer values.
obj The objective function (optional argument with default value $0$).
mode The optimization mode (optional argument with default value MAXIMIZATION).
Exceptions:
std::length_error Thrown if dim exceeds max_space_dimension().
std::invalid_argument Thrown if a constraint in the sequence is a strict inequality, if the space dimension of a constraint (resp., of the objective function or of the integer variables) or the space dimension of the integer variable set is strictly greater than dim.

Definition at line 32 of file MIP_Problem.templates.hh.

References external_space_dim, i_variables, input_cs, max_space_dimension(), OK(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), and Parma_Polyhedra_Library::Variables_Set::space_dimension().

00038   : external_space_dim(dim),
00039     internal_space_dim(0),
00040     tableau(),
00041     working_cost(0, Row::Flags()),
00042     mapping(),
00043     base(),
00044     status(PARTIALLY_SATISFIABLE),
00045     pricing(PRICING_STEEPEST_EDGE_FLOAT),
00046     initialized(false),
00047     input_cs(),
00048     first_pending_constraint(0),
00049     input_obj_function(obj),
00050     opt_mode(mode),
00051     last_generator(point()),
00052     i_variables(int_vars) {
00053   // Check that integer Variables_Set does not exceed the space dimension
00054   // of the problem.
00055   if (i_variables.space_dimension() > external_space_dim) {
00056     std::ostringstream s;
00057     s << "PPL::MIP_Problem::MIP_Problem"
00058       << "(dim, first, last, int_vars, obj, mode):\n"
00059       << "dim == "<< external_space_dim << " and int_vars.space_dimension() =="
00060       << " " << i_variables.space_dimension() << " are dimension"
00061       "incompatible.";
00062     throw std::invalid_argument(s.str());
00063   }
00064 
00065    // Check for space dimension overflow.
00066    if (dim > max_space_dimension())
00067      throw std::length_error("PPL::MIP_Problem:: MIP_Problem(dim, first, "
00068                              "last, int_vars, obj, mode):\n"
00069                              "dim exceeds the maximum allowed"
00070                              "space dimension.");
00071    // Check the objective function.
00072    if (obj.space_dimension() > dim) {
00073      std::ostringstream s;
00074      s << "PPL::MIP_Problem::MIP_Problem(dim, first, last,"
00075        << "int_vars, obj, mode):\n"
00076        << "obj.space_dimension() == "<< obj.space_dimension()
00077        << " exceeds d == "<< dim << ".";
00078      throw std::invalid_argument(s.str());
00079    }
00080    // Check the constraints.
00081    for (In i = first; i != last; ++i) {
00082      if (i->is_strict_inequality())
00083        throw std::invalid_argument("PPL::MIP_Problem::"
00084                                    "MIP_Problem(dim, first, last, int_vars,"
00085                                    "obj, mode):\nrange [first, last) contains"
00086                                    "a strict inequality constraint.");
00087      if (i->space_dimension() > dim) {
00088        std::ostringstream s;
00089        s << "PPL::MIP_Problem::"
00090          << "MIP_Problem(dim, first, last, int_vars, obj, mode):\n"
00091          << "range [first, last) contains a constraint having space"
00092          << "dimension  == " << i->space_dimension() << " that exceeds"
00093          "this->space_dimension == " << dim << ".";
00094        throw std::invalid_argument(s.str());
00095      }
00096      input_cs.push_back(*i);
00097    }
00098    PPL_ASSERT(OK());
00099 }

template<typename In >
Parma_Polyhedra_Library::MIP_Problem::MIP_Problem ( dimension_type  dim,
In  first,
In  last,
const Linear_Expression obj = Linear_Expression::zero(),
Optimization_Mode  mode = MAXIMIZATION 
) [inline]

Builds an MIP problem having space dimension dim from the sequence of constraints in the range $[\mathrm{first}, \mathrm{last})$, the objective function obj and optimization mode mode.

Parameters:
dim The dimension of the vector space enclosing *this.
first An input iterator to the start of the sequence of constraints.
last A past-the-end input iterator to the sequence of constraints.
obj The objective function (optional argument with default value $0$).
mode The optimization mode (optional argument with default value MAXIMIZATION).
Exceptions:
std::length_error Thrown if dim exceeds max_space_dimension().
std::invalid_argument Thrown if a constraint in the sequence is a strict inequality or if the space dimension of a constraint (resp., of the objective function or of the integer variables) is strictly greater than dim.

Definition at line 102 of file MIP_Problem.templates.hh.

References input_cs, max_space_dimension(), OK(), and Parma_Polyhedra_Library::Linear_Expression::space_dimension().

00106   : external_space_dim(dim),
00107     internal_space_dim(0),
00108     tableau(),
00109     working_cost(0, Row::Flags()),
00110     mapping(),
00111     base(),
00112     status(PARTIALLY_SATISFIABLE),
00113     pricing(PRICING_STEEPEST_EDGE_FLOAT),
00114     initialized(false),
00115     input_cs(),
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::"
00124                             "MIP_Problem(dim, first, last, obj, mode):\n"
00125                             "dim exceeds the maximum allowed space "
00126                             "dimension.");
00127   // Check the objective function.
00128   if (obj.space_dimension() > dim) {
00129     std::ostringstream s;
00130     s << "PPL::MIP_Problem::MIP_Problem(dim, first, last,"
00131       << " obj, mode):\n"
00132       << "obj.space_dimension() == "<< obj.space_dimension()
00133       << " exceeds d == "<< dim << ".";
00134     throw std::invalid_argument(s.str());
00135   }
00136   // Check the constraints.
00137   for (In i = first; i != last; ++i) {
00138     if (i->is_strict_inequality())
00139       throw std::invalid_argument("PPL::MIP_Problem::"
00140                                   "MIP_Problem(dim, first, last, obj, mode):\n"
00141                                   "range [first, last) contains a strict "
00142                                   "inequality constraint.");
00143     if (i->space_dimension() > dim) {
00144       std::ostringstream s;
00145       s << "PPL::MIP_Problem::"
00146         << "MIP_Problem(dim, first, last, obj, mode):\n"
00147         << "range [first, last) contains a constraint having space"
00148         << "dimension" << " == " << i->space_dimension() << " that exceeds"
00149         "this->space_dimension == " << dim << ".";
00150       throw std::invalid_argument(s.str());
00151     }
00152     input_cs.push_back(*i);
00153   }
00154   PPL_ASSERT(OK());
00155 }

Parma_Polyhedra_Library::MIP_Problem::MIP_Problem ( dimension_type  dim,
const Constraint_System cs,
const Linear_Expression obj = Linear_Expression::zero(),
Optimization_Mode  mode = MAXIMIZATION 
)

Builds an MIP problem having space dimension dim from the constraint system cs, the objective function obj and optimization mode mode.

Parameters:
dim The dimension of the vector space enclosing *this.
cs The constraint system defining the feasible region.
obj The objective function (optional argument with default value $0$).
mode The optimization mode (optional argument with default value MAXIMIZATION).
Exceptions:
std::length_error Thrown if dim exceeds max_space_dimension().
std::invalid_argument Thrown if the constraint system contains any strict inequality or if the space dimension of the constraint system (resp., the objective function) is strictly greater than dim.

Definition at line 90 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Constraint_System::begin(), Parma_Polyhedra_Library::Constraint_System::end(), Parma_Polyhedra_Library::Constraint_System::has_strict_inequalities(), input_cs, max_space_dimension(), OK(), Parma_Polyhedra_Library::Constraint_System::space_dimension(), and Parma_Polyhedra_Library::Linear_Expression::space_dimension().

00094   : external_space_dim(dim),
00095     internal_space_dim(0),
00096     tableau(),
00097     working_cost(0, Row::Flags()),
00098     mapping(),
00099     base(),
00100     status(PARTIALLY_SATISFIABLE),
00101     pricing(PRICING_STEEPEST_EDGE_FLOAT),
00102     initialized(false),
00103     input_cs(),
00104     first_pending_constraint(0),
00105     input_obj_function(obj),
00106     opt_mode(mode),
00107     last_generator(point()),
00108     i_variables() {
00109   // Check for space dimension overflow.
00110   if (dim > max_space_dimension())
00111     throw std::length_error("PPL::MIP_Problem::MIP_Problem(dim, cs, obj, "
00112                             "mode):\n"
00113                             "dim exceeds the maximum allowed"
00114                             "space dimension.");
00115   // Check the objective function.
00116   if (obj.space_dimension() > dim) {
00117     std::ostringstream s;
00118     s << "PPL::MIP_Problem::MIP_Problem(dim, cs, obj,"
00119       << " mode):\n"
00120       << "obj.space_dimension() == "<< obj.space_dimension()
00121       << " exceeds dim == "<< dim << ".";
00122     throw std::invalid_argument(s.str());
00123   }
00124   // Check the constraint system.
00125   if (cs.space_dimension() > dim) {
00126     std::ostringstream s;
00127     s << "PPL::MIP_Problem::MIP_Problem(dim, cs, obj, mode):\n"
00128       << "cs.space_dimension == " << cs.space_dimension() << " exceeds dim == "
00129       << dim << ".";
00130     throw std::invalid_argument(s.str());
00131   }
00132   if (cs.has_strict_inequalities())
00133     throw std::invalid_argument("PPL::MIP_Problem::"
00134                                 "MIP_Problem(d, cs, obj, m):\n"
00135                                 "cs contains strict inequalities.");
00136   // Actually copy the constraints.
00137   input_cs.insert(input_cs.end(), cs.begin(), cs.end());
00138   PPL_ASSERT(OK());
00139 }

Parma_Polyhedra_Library::MIP_Problem::MIP_Problem ( const MIP_Problem y  )  [inline]

Ordinary copy constructor.

Definition at line 44 of file MIP_Problem.inlines.hh.

References OK().

00045   : external_space_dim(y.external_space_dim),
00046     internal_space_dim(y.internal_space_dim),
00047     tableau(y.tableau),
00048     working_cost(y.working_cost),
00049     mapping(y.mapping),
00050     base(y.base),
00051     status(y.status),
00052     pricing(y.pricing),
00053     initialized(y.initialized),
00054     input_cs(y.input_cs),
00055     first_pending_constraint(y.first_pending_constraint),
00056     input_obj_function(y.input_obj_function),
00057     opt_mode(y.opt_mode),
00058     last_generator(y.last_generator),
00059     i_variables(y.i_variables) {
00060   PPL_ASSERT(OK());
00061 }

Parma_Polyhedra_Library::MIP_Problem::~MIP_Problem (  )  [inline]

Destructor.

Definition at line 64 of file MIP_Problem.inlines.hh.

00064                           {
00065 }


Member Function Documentation

void Parma_Polyhedra_Library::MIP_Problem::add_constraint ( const Constraint c  ) 

Adds a copy of constraint c to the MIP problem.

Exceptions:
std::invalid_argument Thrown if the constraint c is a strict inequality or if its space dimension is strictly greater than the space dimension of *this.

Definition at line 142 of file MIP_Problem.cc.

References input_cs, Parma_Polyhedra_Library::Constraint::is_strict_inequality(), OK(), PARTIALLY_SATISFIABLE, Parma_Polyhedra_Library::Constraint::space_dimension(), space_dimension(), status, and UNSATISFIABLE.

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::BD_Shape< T >::BFT00_upper_bound_assign_if_exact(), Parma_Polyhedra_Library::Box< ITV >::Box(), is_mip_satisfiable(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), Parma_Polyhedra_Library::Polyhedron::simplify_using_context_assign(), and solve_mip().

00142                                                   {
00143   if (space_dimension() < c.space_dimension()) {
00144     std::ostringstream s;
00145     s << "PPL::MIP_Problem::add_constraint(c):\n"
00146       << "c.space_dimension() == "<< c.space_dimension() << " exceeds "
00147       "this->space_dimension == " << space_dimension() << ".";
00148     throw std::invalid_argument(s.str());
00149   }
00150   if (c.is_strict_inequality())
00151     throw std::invalid_argument("PPL::MIP_Problem::add_constraint(c):\n"
00152                                 "c is a strict inequality.");
00153   input_cs.push_back(c);
00154   if (status != UNSATISFIABLE)
00155     status = PARTIALLY_SATISFIABLE;
00156   PPL_ASSERT(OK());
00157 }

void Parma_Polyhedra_Library::MIP_Problem::add_constraints ( const Constraint_System cs  ) 

Adds a copy of the constraints in cs to the MIP problem.

Exceptions:
std::invalid_argument Thrown if the constraint system cs contains any strict inequality or if its space dimension is strictly greater than the space dimension of *this.

Definition at line 160 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Constraint_System::begin(), Parma_Polyhedra_Library::Constraint_System::end(), Parma_Polyhedra_Library::Constraint_System::has_strict_inequalities(), input_cs, OK(), PARTIALLY_SATISFIABLE, Parma_Polyhedra_Library::Constraint_System::space_dimension(), space_dimension(), status, and UNSATISFIABLE.

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), Parma_Polyhedra_Library::Polyhedron::simplify_using_context_assign(), and Parma_Polyhedra_Library::Polyhedron::strongly_minimize_constraints().

00160                                                            {
00161   if (space_dimension() < cs.space_dimension()) {
00162     std::ostringstream s;
00163     s << "PPL::MIP_Problem::add_constraints(cs):\n"
00164       << "cs.space_dimension() == " << cs.space_dimension()
00165       << " exceeds this->space_dimension() == " << this->space_dimension()
00166       << ".";
00167     throw std::invalid_argument(s.str());
00168   }
00169   if (cs.has_strict_inequalities())
00170     throw std::invalid_argument("PPL::MIP_Problem::add_constraints(cs):\n"
00171                                 "cs contains strict inequalities.");
00172   input_cs.insert(input_cs.end(), cs.begin(), cs.end());
00173   if (status != UNSATISFIABLE)
00174     status = PARTIALLY_SATISFIABLE;
00175   PPL_ASSERT(OK());
00176 }

void Parma_Polyhedra_Library::MIP_Problem::add_space_dimensions_and_embed ( dimension_type  m  ) 

Adds m new space dimensions and embeds the old MIP problem in the new vector space.

Parameters:
m The number of dimensions to add.
Exceptions:
std::length_error Thrown if adding m new space dimensions would cause the vector space to exceed dimension max_space_dimension().

The new space dimensions will be those having the highest indexes in the new MIP problem; they are initially unconstrained.

Definition at line 335 of file MIP_Problem.cc.

References external_space_dim, max_space_dimension(), OK(), PARTIALLY_SATISFIABLE, space_dimension(), status, and UNSATISFIABLE.

Referenced by Parma_Polyhedra_Library::Polyhedron::simplify_using_context_assign(), and Parma_Polyhedra_Library::Polyhedron::strongly_minimize_constraints().

00335                                                                      {
00336   // The space dimension of the resulting MIP problem should not
00337   // overflow the maximum allowed space dimension.
00338   if (m > max_space_dimension() - space_dimension())
00339     throw std::length_error("PPL::MIP_Problem::"
00340                             "add_space_dimensions_and_embed(m):\n"
00341                             "adding m new space dimensions exceeds "
00342                             "the maximum allowed space dimension.");
00343   external_space_dim += m;
00344   if (status != UNSATISFIABLE)
00345     status = PARTIALLY_SATISFIABLE;
00346   PPL_ASSERT(OK());
00347 }

void Parma_Polyhedra_Library::MIP_Problem::add_to_integer_space_dimensions ( const Variables_Set i_vars  ) 

Sets the variables whose indexes are in set i_vars to be integer space dimensions.

Exceptions:
std::invalid_argument Thrown if some index in i_vars does not correspond to a space dimension in *this.

Definition at line 351 of file MIP_Problem.cc.

References external_space_dim, i_variables, Parma_Polyhedra_Library::Variables_Set::insert(), PARTIALLY_SATISFIABLE, Parma_Polyhedra_Library::Variables_Set::space_dimension(), status, and UNSATISFIABLE.

00351                                                              {
00352   if (i_vars.space_dimension() > external_space_dim)
00353     throw std::invalid_argument("PPL::MIP_Problem::"
00354                                 "add_to_integer_space_dimension(i_vars):\n"
00355                                 "*this and i_vars are dimension"
00356                                 "incompatible.");
00357   const dimension_type original_size = i_variables.size();
00358   i_variables.insert(i_vars.begin(), i_vars.end());
00359   // If a new integral variable was inserted, set the internal status to
00360   // PARTIALLY_SATISFIABLE.
00361   if (i_variables.size() != original_size && status != UNSATISFIABLE)
00362     status = PARTIALLY_SATISFIABLE;
00363 }

void Parma_Polyhedra_Library::MIP_Problem::ascii_dump ( std::ostream &  s  )  const

Writes to s an ASCII representation of *this.

Definition at line 2027 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Variables_Set::ascii_dump(), Parma_Polyhedra_Library::Generator::ascii_dump(), Parma_Polyhedra_Library::Row::ascii_dump(), Parma_Polyhedra_Library::Matrix::ascii_dump(), Parma_Polyhedra_Library::Linear_Expression::ascii_dump(), ascii_dump(), base, external_space_dim, first_pending_constraint, i_variables, initialized, input_cs, input_obj_function, internal_space_dim, last_generator, mapping, Parma_Polyhedra_Library::MAXIMIZATION, opt_mode, OPTIMIZED, PARTIALLY_SATISFIABLE, pricing, PRICING_STEEPEST_EDGE_EXACT, PRICING_STEEPEST_EDGE_FLOAT, PRICING_TEXTBOOK, SATISFIABLE, Parma_Polyhedra_Library::Row::size(), status, tableau, UNBOUNDED, UNSATISFIABLE, and working_cost.

02027                                               {
02028   using namespace IO_Operators;
02029   s << "\nexternal_space_dim: " << external_space_dim << " \n";
02030   s << "\ninternal_space_dim: " << internal_space_dim << " \n";
02031 
02032   const dimension_type input_cs_size = input_cs.size();
02033 
02034   s << "\ninput_cs( " << input_cs_size << " )\n";
02035   for (dimension_type i = 0; i < input_cs_size; ++i)
02036     input_cs[i].ascii_dump(s);
02037 
02038   s << "\nfirst_pending_constraint: " <<  first_pending_constraint
02039     << std::endl;
02040 
02041   s << "\ninput_obj_function\n";
02042   input_obj_function.ascii_dump(s);
02043   s << "\nopt_mode "
02044     << (opt_mode == MAXIMIZATION ? "MAXIMIZATION" : "MINIMIZATION") << "\n";
02045 
02046   s << "\ninitialized: " << (initialized ? "YES" : "NO") << "\n";
02047   s << "\npricing: ";
02048   switch (pricing) {
02049   case PRICING_STEEPEST_EDGE_FLOAT:
02050     s << "PRICING_STEEPEST_EDGE_FLOAT";
02051     break;
02052   case PRICING_STEEPEST_EDGE_EXACT:
02053     s << "PRICING_STEEPEST_EDGE_EXACT";
02054     break;
02055   case PRICING_TEXTBOOK:
02056     s << "PRICING_TEXTBOOK";
02057     break;
02058   }
02059   s << "\n";
02060 
02061   s << "\nstatus: ";
02062   switch (status) {
02063   case UNSATISFIABLE:
02064     s << "UNSATISFIABLE";
02065     break;
02066   case SATISFIABLE:
02067     s << "SATISFIABLE";
02068     break;
02069   case UNBOUNDED:
02070     s << "UNBOUNDED";
02071     break;
02072   case OPTIMIZED:
02073     s << "OPTIMIZED";
02074     break;
02075   case PARTIALLY_SATISFIABLE:
02076     s << "PARTIALLY_SATISFIABLE";
02077     break;
02078   }
02079   s << "\n";
02080 
02081   s << "\ntableau\n";
02082   tableau.ascii_dump(s);
02083   s << "\nworking_cost( " << working_cost.size()<< " )\n";
02084   working_cost.ascii_dump(s);
02085 
02086   const dimension_type base_size = base.size();
02087   s << "\nbase( " << base_size << " )\n";
02088   for (dimension_type i = 0; i != base_size; ++i)
02089     s << base[i] << ' ';
02090 
02091   s << "\nlast_generator\n";
02092   last_generator.ascii_dump(s);
02093 
02094   const dimension_type mapping_size = mapping.size();
02095   s << "\nmapping( " << mapping_size << " )\n";
02096   for (dimension_type i = 1; i < mapping_size; ++i)
02097     s << "\n"<< i << " -> " << mapping[i].first << " -> " << mapping[i].second
02098       << ' ';
02099 
02100   s << "\n\ninteger_variables";
02101   i_variables.ascii_dump(s);
02102 }

void Parma_Polyhedra_Library::MIP_Problem::ascii_dump (  )  const

Writes to std::cerr an ASCII representation of *this.

Referenced by ascii_dump(), and OK().

bool Parma_Polyhedra_Library::MIP_Problem::ascii_load ( std::istream &  s  ) 

Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this accordingly. Returns true if successful, false otherwise.

Definition at line 2107 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Constraint::ascii_load(), Parma_Polyhedra_Library::MAXIMIZATION, Parma_Polyhedra_Library::MINIMIZATION, and Parma_Polyhedra_Library::Constraint::zero_dim_positivity().

02107                                         {
02108   std::string str;
02109   if (!(s >> str) || str != "external_space_dim:")
02110     return false;
02111 
02112   if (!(s >> external_space_dim))
02113     return false;
02114 
02115   if (!(s >> str) || str != "internal_space_dim:")
02116     return false;
02117 
02118   if (!(s >> internal_space_dim))
02119     return false;
02120 
02121   if (!(s >> str) || str != "input_cs(")
02122     return false;
02123 
02124   dimension_type input_cs_size;
02125 
02126   if (!(s >> input_cs_size))
02127     return false;
02128 
02129   if (!(s >> str) || str != ")")
02130     return false;
02131 
02132   Constraint c(Constraint::zero_dim_positivity());
02133   for (dimension_type i = 0; i < input_cs_size; ++i) {
02134     if (!c.ascii_load(s))
02135       return false;
02136     input_cs.push_back(c);
02137   }
02138 
02139   if (!(s >> str) || str != "first_pending_constraint:")
02140     return false;
02141 
02142   if (!(s >> first_pending_constraint))
02143     return false;
02144 
02145   if (!(s >> str) || str != "input_obj_function")
02146     return false;
02147 
02148   if (!input_obj_function.ascii_load(s))
02149     return false;
02150 
02151   if (!(s >> str) || str != "opt_mode")
02152     return false;
02153 
02154   if (!(s >> str))
02155     return false;
02156 
02157   if (str == "MAXIMIZATION")
02158     set_optimization_mode(MAXIMIZATION);
02159   else {
02160     if (str != "MINIMIZATION")
02161       return false;
02162     set_optimization_mode(MINIMIZATION);
02163   }
02164 
02165   if (!(s >> str) || str != "initialized:")
02166     return false;
02167   if (!(s >> str))
02168     return false;
02169   if (str == "YES")
02170     initialized = true;
02171   else if (str == "NO")
02172     initialized = false;
02173   else
02174     return false;
02175 
02176   if (!(s >> str) || str != "pricing:")
02177     return false;
02178   if (!(s >> str))
02179     return false;
02180   if (str == "PRICING_STEEPEST_EDGE_FLOAT")
02181     pricing = PRICING_STEEPEST_EDGE_FLOAT;
02182   else if (str == "PRICING_STEEPEST_EDGE_EXACT")
02183     pricing = PRICING_STEEPEST_EDGE_EXACT;
02184   else if (str == "PRICING_TEXTBOOK")
02185     pricing = PRICING_TEXTBOOK;
02186   else
02187     return false;
02188 
02189   if (!(s >> str) || str != "status:")
02190     return false;
02191 
02192   if (!(s >> str))
02193     return false;
02194 
02195   if (str == "UNSATISFIABLE")
02196     status = UNSATISFIABLE;
02197   else if (str == "SATISFIABLE")
02198     status = SATISFIABLE;
02199   else if (str == "UNBOUNDED")
02200     status = UNBOUNDED;
02201   else if (str == "OPTIMIZED")
02202     status = OPTIMIZED;
02203   else if (str == "PARTIALLY_SATISFIABLE")
02204     status = PARTIALLY_SATISFIABLE;
02205   else
02206     return false;
02207 
02208   if (!(s >> str) || str != "tableau")
02209     return false;
02210 
02211   if (!tableau.ascii_load(s))
02212     return false;
02213 
02214   if (!(s >> str) || str != "working_cost(")
02215     return false;
02216 
02217   dimension_type working_cost_dim;
02218 
02219   if (!(s >> working_cost_dim))
02220     return false;
02221 
02222   if (!(s >> str) || str != ")")
02223     return false;
02224 
02225   if (!working_cost.ascii_load(s))
02226     return false;
02227 
02228   if (!(s >> str) || str != "base(")
02229     return false;
02230 
02231   dimension_type base_size;
02232   if (!(s >> base_size))
02233     return false;
02234 
02235   if (!(s >> str) || str != ")")
02236     return false;
02237 
02238   dimension_type base_value;
02239   for (dimension_type i = 0; i != base_size; ++i) {
02240     if (!(s >> base_value))
02241       return false;
02242     base.push_back(base_value);
02243   }
02244 
02245   if (!(s >> str) || str != "last_generator")
02246     return false;
02247 
02248   if (!last_generator.ascii_load(s))
02249     return false;
02250 
02251   if (!(s >> str) || str != "mapping(")
02252     return false;
02253 
02254   dimension_type mapping_size;
02255   if (!(s >> mapping_size))
02256     return false;
02257 
02258   if (!(s >> str) || str != ")")
02259     return false;
02260 
02261   dimension_type first_value;
02262   dimension_type second_value;
02263   dimension_type index;
02264 
02265   // The first `mapping' index is never used, so we initialize
02266   // it pushing back a dummy value.
02267   if (tableau.num_columns() != 0)
02268     mapping.push_back(std::make_pair(0, 0));
02269 
02270   for (dimension_type i = 1; i < mapping_size; ++i) {
02271     if (!(s >> index))
02272       return false;
02273     if (!(s >> str) || str != "->")
02274       return false;
02275     if (!(s >> first_value))
02276       return false;
02277     if (!(s >> str) || str != "->")
02278       return false;
02279     if (!(s >> second_value))
02280       return false;
02281     mapping.push_back(std::make_pair(first_value, second_value));
02282   }
02283 
02284   if (!(s >> str) || str != "integer_variables")
02285     return false;
02286 
02287   if (!i_variables.ascii_load(s))
02288     return false;
02289 
02290   PPL_ASSERT(OK());
02291   return true;
02292 }

bool Parma_Polyhedra_Library::MIP_Problem::choose_branching_variable ( const MIP_Problem lp,
const Variables_Set i_vars,
dimension_type branching_index 
) [static, private]

Returns true if and if only mip.last_generator satisfies all the integrality coditions implicitly stated using by i_vars.

Parameters:
lp The LP problem. This is assumed to have no integral space dimension.
i_vars The variables that are constrained to take an integer value.
branching_index If false is returned, this will encode the non-integral variable index on which the `branch and bound' algorithm should be applied.

Definition at line 1722 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Generator::coefficient(), Parma_Polyhedra_Library::Generator::divisor(), Parma_Polyhedra_Library::gcd_assign(), input_cs, Parma_Polyhedra_Library::Variables_Set::insert(), is_saturated(), last_generator, PPL_DIRTY_TEMP_COEFFICIENT, and space_dimension().

Referenced by is_mip_satisfiable().

01724                                                                              {
01725   // Insert here the variables that don't satisfy the integrality condition.
01726   const Constraint_Sequence& input_cs = lp.input_cs;
01727   const Generator& last_generator = lp.last_generator;
01728   const Coefficient& last_generator_divisor = last_generator.divisor();
01729   Variables_Set candidate_variables;
01730 
01731   PPL_DIRTY_TEMP_COEFFICIENT(gcd);
01732   for (Variables_Set::const_iterator v_it = i_vars.begin(),
01733          v_end = i_vars.end(); v_it != v_end; ++v_it) {
01734     gcd_assign(gcd,
01735                last_generator.coefficient(Variable(*v_it)),
01736                last_generator_divisor);
01737     if (gcd != last_generator_divisor)
01738       candidate_variables.insert(*v_it);
01739   }
01740   // If this set is empty, we have finished.
01741   if (candidate_variables.empty())
01742     return true;
01743 
01744   // Check how many `active constraints' we have and track them.
01745   const dimension_type input_cs_num_rows = input_cs.size();
01746   std::deque<bool> satisfiable_constraints (input_cs_num_rows, false);
01747   for (dimension_type i = input_cs_num_rows; i-- > 0; )
01748     // An equality is an `active constraint' by definition.
01749     // If we have an inequality, check if it is an `active constraint'.
01750     if (input_cs[i].is_equality()
01751         || is_saturated(input_cs[i], last_generator))
01752       satisfiable_constraints[i] = true;
01753 
01754   dimension_type current_num_appearances = 0;
01755   dimension_type winning_num_appearances = 0;
01756 
01757   // For every candidate variable, check how many times this appear in the
01758   // active constraints.
01759   for (Variables_Set::const_iterator v_it = candidate_variables.begin(),
01760          v_end = candidate_variables.end(); v_it != v_end; ++v_it) {
01761     current_num_appearances = 0;
01762     for (dimension_type i = input_cs_num_rows; i-- > 0; )
01763       if (satisfiable_constraints[i]
01764           && *v_it < input_cs[i].space_dimension()
01765           && input_cs[i].coefficient(Variable(*v_it)) != 0)
01766         ++current_num_appearances;
01767     if (current_num_appearances >= winning_num_appearances) {
01768       winning_num_appearances = current_num_appearances;
01769       branching_index = *v_it;
01770     }
01771   }
01772   return false;
01773 }

void Parma_Polyhedra_Library::MIP_Problem::clear (  )  [inline]

Resets *this to be equal to the trivial MIP problem.

The space dimension is reset to $0$.

Definition at line 148 of file MIP_Problem.inlines.hh.

References swap().

00148                    {
00149   MIP_Problem tmp;
00150   swap(tmp);
00151 }

void Parma_Polyhedra_Library::MIP_Problem::compute_generator (  )  const [private]

Computes a valid generator that satisfies all the constraints of the Linear Programming problem associated to *this.

Definition at line 1386 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::add_mul_assign(), Parma_Polyhedra_Library::exact_div_assign(), external_space_dim, is_in_base(), last_generator, Parma_Polyhedra_Library::lcm_assign(), mapping, Parma_Polyhedra_Library::neg_assign(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::sub_mul_assign(), and tableau.

Referenced by process_pending_constraints(), and second_phase().

01386                                         {
01387   // We will store in num[] and in den[] the numerators and
01388   // the denominators of every variable of the original problem.
01389   std::vector<Coefficient> num(external_space_dim);
01390   std::vector<Coefficient> den(external_space_dim);
01391   dimension_type row = 0;
01392 
01393   PPL_DIRTY_TEMP_COEFFICIENT(lcm);
01394   // Speculatively allocate temporaries out of loop.
01395   PPL_DIRTY_TEMP_COEFFICIENT(split_num);
01396   PPL_DIRTY_TEMP_COEFFICIENT(split_den);
01397 
01398   // We start to compute num[] and den[].
01399   for (dimension_type i = external_space_dim; i-- > 0; ) {
01400     Coefficient& num_i = num[i];
01401     Coefficient& den_i = den[i];
01402     // Get the value of the variable from the tableau
01403     // (if it is not a basic variable, the value is 0).
01404     const dimension_type original_var = mapping[i+1].first;
01405     if (is_in_base(original_var, row)) {
01406       const Row& t_row = tableau[row];
01407       if (t_row[original_var] > 0) {
01408         neg_assign(num_i, t_row[0]);
01409         den_i = t_row[original_var];
01410       }
01411       else {
01412         num_i = t_row[0];
01413         neg_assign(den_i, t_row[original_var]);
01414       }
01415     }
01416     else {
01417       num_i = 0;
01418       den_i = 1;
01419     }
01420     // Check whether the variable was split.
01421     const dimension_type split_var = mapping[i+1].second;
01422     if (split_var != 0) {
01423       // The variable was split: get the value for the negative component,
01424       // having index mapping[i+1].second .
01425       // Like before, we he have to check if the variable is in base.
01426       if (is_in_base(split_var, row)) {
01427         const Row& t_row = tableau[row];
01428         if (t_row[split_var] > 0) {
01429           neg_assign(split_num, t_row[0]);
01430           split_den = t_row[split_var];
01431         }
01432         else {
01433           split_num = t_row[0];
01434           neg_assign(split_den, t_row[split_var]);
01435         }
01436         // We compute the lcm to compute subsequently the difference
01437         // between the 2 variables.
01438         lcm_assign(lcm, den_i, split_den);
01439         exact_div_assign(den_i, lcm, den_i);
01440         exact_div_assign(split_den, lcm, split_den);
01441         num_i *= den_i;
01442         sub_mul_assign(num_i, split_num, split_den);
01443         if (num_i == 0)
01444           den_i = 1;
01445         else
01446           den_i = lcm;
01447       }
01448       // Note: if the negative component was not in base, then
01449       // it has value zero and there is nothing left to do.
01450     }
01451   }
01452 
01453   // Compute the lcm of all denominators.
01454   lcm = den[0];
01455   for (dimension_type i = 1; i < external_space_dim; ++i)
01456     lcm_assign(lcm, lcm, den[i]);
01457   // Use the denominators to store the numerators' multipliers
01458   // and then compute the normalized numerators.
01459   for (dimension_type i = external_space_dim; i-- > 0; ) {
01460     exact_div_assign(den[i], lcm, den[i]);
01461     num[i] *= den[i];
01462   }
01463 
01464   // Finally, build the generator.
01465   Linear_Expression expr;
01466   for (dimension_type i = external_space_dim; i-- > 0; )
01467     add_mul_assign(expr, num[i], Variable(i));
01468 
01469   MIP_Problem& x = const_cast<MIP_Problem&>(*this);
01470   x.last_generator = point(expr, lcm);
01471 }

bool Parma_Polyhedra_Library::MIP_Problem::compute_simplex_using_exact_pricing (  )  [private]

Returns true if and if only the algorithm successfully computed a feasible solution.

Note:
Uses an exact pricing method (either textbook or exact steepest edge), so that the result is deterministic across different architectures.

Definition at line 1281 of file MIP_Problem.cc.

References get_control_parameter(), get_exiting_base_index(), Parma_Polyhedra_Library::maybe_abandon(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), pivot(), PRICING, PRICING_STEEPEST_EDGE_EXACT, PRICING_TEXTBOOK, Parma_Polyhedra_Library::Row::size(), steepest_edge_exact_entering_index(), tableau, textbook_entering_index(), and working_cost.

Referenced by process_pending_constraints(), and second_phase().

01281                                                     {
01282   PPL_ASSERT(tableau.num_columns() == working_cost.size());
01283   PPL_ASSERT(get_control_parameter(PRICING) == PRICING_STEEPEST_EDGE_EXACT
01284          || get_control_parameter(PRICING) == PRICING_TEXTBOOK);
01285 
01286   const dimension_type tableau_num_rows = tableau.num_rows();
01287   const bool textbook_pricing
01288     = (PRICING_TEXTBOOK == get_control_parameter(PRICING));
01289 
01290   while (true) {
01291     // Choose the index of the variable entering the base, if any.
01292     const dimension_type entering_var_index
01293       = textbook_pricing
01294       ? textbook_entering_index()
01295       : steepest_edge_exact_entering_index();
01296     // If no entering index was computed, the problem is solved.
01297     if (entering_var_index == 0)
01298       return true;
01299 
01300     // Choose the index of the row exiting the base.
01301     const dimension_type exiting_base_index
01302       = get_exiting_base_index(entering_var_index);
01303     // If no exiting index was computed, the problem is unbounded.
01304     if (exiting_base_index == tableau_num_rows)
01305       return false;
01306 
01307     // Check if the client has requested abandoning all expensive
01308     // computations. If so, the exception specified by the client
01309     // is thrown now.
01310     maybe_abandon();
01311 
01312     // We have not reached the optimality or unbounded condition:
01313     // compute the new base and the corresponding vertex of the
01314     // feasible region.
01315     pivot(entering_var_index, exiting_base_index);
01316 #if PPL_NOISY_SIMPLEX
01317     ++num_iterations;
01318     if (num_iterations % 200 == 0)
01319       std::cout << "Primal simplex: iteration " << num_iterations
01320                 << "." << std::endl;
01321 #endif // PPL_NOISY_SIMPLEX
01322   }
01323 }

bool Parma_Polyhedra_Library::MIP_Problem::compute_simplex_using_steepest_edge_float (  )  [private]

Returns true if and if only the algorithm successfully computed a feasible solution.

Note:
Uses a floating point implementation of the steepest edge pricing method, so that the result is correct, but not deterministic across different architectures.

Definition at line 1190 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::abs_assign(), get_exiting_base_index(), Parma_Polyhedra_Library::maybe_abandon(), Parma_Polyhedra_Library::neg_assign(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), pivot(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Row::size(), steepest_edge_float_entering_index(), tableau, textbook_entering_index(), WEIGHT_ADD, WEIGHT_BEGIN, and working_cost.

Referenced by process_pending_constraints(), and second_phase().

01190                                                           {
01191   // We may need to temporarily switch to the textbook pricing.
01192   const unsigned long allowed_non_increasing_loops = 200;
01193   unsigned long non_increased_times = 0;
01194   bool textbook_pricing = false;
01195 
01196   PPL_DIRTY_TEMP_COEFFICIENT(cost_sgn_coeff);
01197   PPL_DIRTY_TEMP_COEFFICIENT(current_num);
01198   PPL_DIRTY_TEMP_COEFFICIENT(current_den);
01199   PPL_DIRTY_TEMP_COEFFICIENT(challenger);
01200   PPL_DIRTY_TEMP_COEFFICIENT(current);
01201 
01202   cost_sgn_coeff = working_cost[working_cost.size()-1];
01203   current_num = working_cost[0];
01204   if (cost_sgn_coeff < 0)
01205     neg_assign(current_num);
01206   abs_assign(current_den, cost_sgn_coeff);
01207   PPL_ASSERT(tableau.num_columns() == working_cost.size());
01208   const dimension_type tableau_num_rows = tableau.num_rows();
01209 
01210   while (true) {
01211     // Choose the index of the variable entering the base, if any.
01212     const dimension_type entering_var_index
01213       = textbook_pricing
01214       ? textbook_entering_index()
01215       : steepest_edge_float_entering_index();
01216 
01217     // If no entering index was computed, the problem is solved.
01218     if (entering_var_index == 0)
01219       return true;
01220 
01221     // Choose the index of the row exiting the base.
01222     const dimension_type exiting_base_index
01223       = get_exiting_base_index(entering_var_index);
01224     // If no exiting index was computed, the problem is unbounded.
01225     if (exiting_base_index == tableau_num_rows)
01226       return false;
01227 
01228     // Check if the client has requested abandoning all expensive
01229     // computations. If so, the exception specified by the client
01230     // is thrown now.
01231     maybe_abandon();
01232 
01233     // We have not reached the optimality or unbounded condition:
01234     // compute the new base and the corresponding vertex of the
01235     // feasible region.
01236     pivot(entering_var_index, exiting_base_index);
01237 
01238     WEIGHT_BEGIN();
01239     // Now begins the objective function's value check to choose between
01240     // the `textbook' and the float `steepest-edge' technique.
01241     cost_sgn_coeff = working_cost[working_cost.size()-1];
01242 
01243     challenger = working_cost[0];
01244     if (cost_sgn_coeff < 0)
01245       neg_assign(challenger);
01246     challenger *= current_den;
01247     abs_assign(current, cost_sgn_coeff);
01248     current *= current_num;
01249 #if PPL_NOISY_SIMPLEX
01250     ++num_iterations;
01251     if (num_iterations % 200 == 0)
01252       std::cout << "Primal simplex: iteration " << num_iterations
01253                 << "." << std::endl;
01254 #endif // PPL_NOISY_SIMPLEX
01255     // If the following condition fails, probably there's a bug.
01256     PPL_ASSERT(challenger >= current);
01257     // If the value of the objective function does not improve,
01258     // keep track of that.
01259     if (challenger == current) {
01260       ++non_increased_times;
01261       // In the following case we will proceed using the `textbook'
01262       // technique, until the objective function is not improved.
01263       if (non_increased_times > allowed_non_increasing_loops)
01264         textbook_pricing = true;
01265     }
01266     // The objective function has an improvement:
01267     // reset `non_increased_times' and `textbook_pricing'.
01268     else {
01269       non_increased_times = 0;
01270       textbook_pricing = false;
01271     }
01272     current_num = working_cost[0];
01273     if (cost_sgn_coeff < 0)
01274       neg_assign(current_num);
01275     abs_assign(current_den, cost_sgn_coeff);
01276     WEIGHT_ADD(566);
01277   }
01278 }

MIP_Problem_Status Parma_Polyhedra_Library::MIP_Problem::compute_tableau ( std::vector< dimension_type > &  worked_out_row  )  [private]

Assigns to this->tableau a simplex tableau representing the MIP problem, inserting into this->mapping the information that is required to recover the original MIP problem.

Returns:
UNFEASIBLE_MIP_PROBLEM if the constraint system contains any trivially unfeasible constraint (tableau was not computed); UNBOUNDED_MIP_PROBLEM if the problem is trivially unbounded (the computed tableau contains no constraints); OPTIMIZED_MIP_PROBLEM> if the problem is neither trivially unfeasible nor trivially unbounded (the tableau was computed successfully).
MIP_Problem::const_iterator Parma_Polyhedra_Library::MIP_Problem::constraints_begin (  )  const [inline]

Returns a read-only iterator to the first constraint defining the feasible region.

Definition at line 95 of file MIP_Problem.inlines.hh.

References input_cs.

Referenced by operator<<().

00095                                      {
00096   return input_cs.begin();
00097 }

MIP_Problem::const_iterator Parma_Polyhedra_Library::MIP_Problem::constraints_end (  )  const [inline]

Returns a past-the-end read-only iterator to the sequence of constraints defining the feasible region.

Definition at line 100 of file MIP_Problem.inlines.hh.

References input_cs.

Referenced by operator<<().

00100                                    {
00101   return input_cs.end();
00102 }

void Parma_Polyhedra_Library::MIP_Problem::erase_artificials ( dimension_type  begin_artificials,
dimension_type  end_artificials 
) [private]

Drop unnecessary artificial variables from the tableau and get ready for the second phase of the simplex algorithm.

Note:
The two parameters denote a STL-like half-open range. It is assumed that begin_artificials is strictly greater than 0 and smaller than end_artificials.
Parameters:
begin_artificials The start of the tableau column index range for artificial variables.
end_artificials The end of the tableau column index range for artificial variables. Note that column index end_artificial is excluded from the range.

Definition at line 1328 of file MIP_Problem.cc.

References base, Parma_Polyhedra_Library::Matrix::erase_to_end(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), pivot(), Parma_Polyhedra_Library::Matrix::remove_trailing_columns(), Parma_Polyhedra_Library::Row::shrink(), Parma_Polyhedra_Library::Row::size(), Parma_Polyhedra_Library::Row::swap(), tableau, and working_cost.

Referenced by process_pending_constraints().

01329                                                                           {
01330   PPL_ASSERT(0 < begin_artificials && begin_artificials < end_artificials);
01331 
01332   const dimension_type old_last_column = tableau.num_columns() - 1;
01333   dimension_type tableau_n_rows = tableau.num_rows();
01334   // Step 1: try to remove from the base all the remaining slack variables.
01335   for (dimension_type i = 0; i < tableau_n_rows; ++i)
01336     if (begin_artificials <= base[i] && base[i] < end_artificials) {
01337       // Search for a non-zero element to enter the base.
01338       Row& tableau_i = tableau[i];
01339       bool redundant = true;
01340       for (dimension_type j = end_artificials; j-- > 1; )
01341         if (!(begin_artificials <= j && j < end_artificials)
01342             && tableau_i[j] != 0) {
01343           pivot(j, i);
01344           redundant = false;
01345           break;
01346         }
01347       if (redundant) {
01348         // No original variable entered the base:
01349         // the constraint is redundant and should be deleted.
01350         --tableau_n_rows;
01351         if (i < tableau_n_rows) {
01352           // Replace the redundant row with the last one,
01353           // taking care of adjusting the iteration index.
01354           tableau_i.swap(tableau[tableau_n_rows]);
01355           base[i] = base[tableau_n_rows];
01356           --i;
01357         }
01358         tableau.erase_to_end(tableau_n_rows);
01359         base.pop_back();
01360       }
01361     }
01362 
01363 
01364   // Step 2: Adjust data structures so as to enter phase 2 of the simplex.
01365 
01366   // Resize the tableau.
01367   const dimension_type num_artificials = end_artificials - begin_artificials;
01368   tableau.remove_trailing_columns(num_artificials);
01369 
01370   // Zero the last column of the tableau.
01371   const dimension_type new_last_column = tableau.num_columns() - 1;
01372   for (dimension_type i = tableau_n_rows; i-- > 0; )
01373     tableau[i][new_last_column] = 0;
01374 
01375   // ... then properly set the element in the (new) last column,
01376   // encoding the kind of optimization; ...
01377   working_cost[new_last_column] = working_cost[old_last_column];
01378   // ... and finally remove redundant columns.
01379   const dimension_type working_cost_new_size
01380     = working_cost.size() - num_artificials;
01381   working_cost.shrink(working_cost_new_size);
01382 }

void Parma_Polyhedra_Library::MIP_Problem::evaluate_objective_function ( const Generator evaluating_point,
Coefficient num,
Coefficient den 
) const

Sets num and den so that $\frac{num}{den}$ is the result of evaluating the objective function on evaluating_point.

Parameters:
evaluating_point The point on which the objective function will be evaluated.
num On exit will contain the numerator of the evaluated value.
den On exit will contain the denominator of the evaluated value.
Exceptions:
std::invalid_argument Thrown if *this and evaluating_point are dimension-incompatible or if the generator evaluating_point is not a point.

Definition at line 1532 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Linear_Expression::coefficient(), Parma_Polyhedra_Library::Generator::coefficient(), Parma_Polyhedra_Library::Generator::divisor(), Parma_Polyhedra_Library::Linear_Expression::inhomogeneous_term(), input_obj_function, Parma_Polyhedra_Library::Generator::is_point(), Parma_Polyhedra_Library::normalize2(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), space_dimension(), and Parma_Polyhedra_Library::Generator::space_dimension().

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::Octagonal_Shape< T >::max_min(), Parma_Polyhedra_Library::BD_Shape< T >::max_min(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), optimal_value(), and solve_mip().

01534                                                         {
01535   const dimension_type ep_space_dim = evaluating_point.space_dimension();
01536   if (space_dimension() < ep_space_dim)
01537     throw std::invalid_argument("PPL::MIP_Problem::"
01538                                 "evaluate_objective_function(p, n, d):\n"
01539                                 "*this and p are dimension incompatible.");
01540   if (!evaluating_point.is_point())
01541     throw std::invalid_argument("PPL::MIP_Problem::"
01542                                 "evaluate_objective_function(p, n, d):\n"
01543                                 "p is not a point.");
01544 
01545   // Compute the smallest space dimension  between `input_obj_function'
01546   // and `evaluating_point'.
01547   const dimension_type working_space_dim
01548     = std::min(ep_space_dim, input_obj_function.space_dimension());
01549   // Compute the optimal value of the cost function.
01550   const Coefficient& divisor = evaluating_point.divisor();
01551   ext_n = input_obj_function.inhomogeneous_term() * divisor;
01552   for (dimension_type i = working_space_dim; i-- > 0; )
01553     ext_n += evaluating_point.coefficient(Variable(i))
01554       * input_obj_function.coefficient(Variable(i));
01555   // Numerator and denominator should be coprime.
01556   normalize2(ext_n, divisor, ext_n, ext_d);
01557 }

memory_size_type Parma_Polyhedra_Library::MIP_Problem::external_memory_in_bytes (  )  const [inline]

Returns the size in bytes of the memory managed by *this.

Definition at line 154 of file MIP_Problem.inlines.hh.

References base, Parma_Polyhedra_Library::Generator::external_memory_in_bytes(), Parma_Polyhedra_Library::Linear_Expression::external_memory_in_bytes(), Parma_Polyhedra_Library::Row::external_memory_in_bytes(), Parma_Polyhedra_Library::Matrix::external_memory_in_bytes(), input_cs, input_obj_function, last_generator, mapping, tableau, and working_cost.

Referenced by total_memory_in_bytes().

00154                                             {
00155   memory_size_type n
00156     = tableau.external_memory_in_bytes()
00157     + working_cost.external_memory_in_bytes()
00158     + input_obj_function.external_memory_in_bytes()
00159     + last_generator.external_memory_in_bytes();
00160   // Adding the external memory for `input_cs'.
00161   n += input_cs.capacity() * sizeof(Constraint);
00162   for (const_iterator i = input_cs.begin(),
00163          i_end = input_cs.end(); i != i_end; ++i)
00164     n += (i->external_memory_in_bytes());
00165   // Adding the external memory for `base'.
00166   n += base.capacity() * sizeof(dimension_type);
00167   // Adding the external memory for `mapping'.
00168   n += mapping.capacity() * sizeof(std::pair<dimension_type, dimension_type>);
00169   return n;
00170 }

const PPL::Generator & Parma_Polyhedra_Library::MIP_Problem::feasible_point (  )  const

Returns a feasible point for *this, if it exists.

Exceptions:
std::domain_error Thrown if the MIP problem is not satisfiable.

Definition at line 195 of file MIP_Problem.cc.

References is_satisfiable(), and last_generator.

00195                                      {
00196   if (is_satisfiable())
00197     return last_generator;
00198   else
00199     throw std::domain_error("PPL::MIP_Problem::feasible_point():\n"
00200                             "*this is not satisfiable.");
00201 }

MIP_Problem::Control_Parameter_Value Parma_Polyhedra_Library::MIP_Problem::get_control_parameter ( Control_Parameter_Name  name  )  const [inline]

Returns the value of the control parameter name.

Definition at line 110 of file MIP_Problem.inlines.hh.

References pricing, and PRICING.

Referenced by compute_simplex_using_exact_pricing(), process_pending_constraints(), and second_phase().

00110                                                                     {
00111   used(name);
00112   PPL_ASSERT(name == PRICING);
00113   return pricing;
00114 }

PPL::dimension_type Parma_Polyhedra_Library::MIP_Problem::get_exiting_base_index ( dimension_type  entering_var_index  )  const [private]

Computes the row index of the variable exiting the base of the MIP problem. Implemented with anti-cycling rule.

Returns:
The row index of the variable exiting the base.
Parameters:
entering_var_index The column index of the variable entering the base.

Definition at line 1135 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::abs_assign(), base, Parma_Polyhedra_Library::exact_div_assign(), Parma_Polyhedra_Library::lcm_assign(), Parma_Polyhedra_Library::Matrix::num_rows(), PPL_DIRTY_TEMP_COEFFICIENT, tableau, WEIGHT_ADD, and WEIGHT_BEGIN.

Referenced by compute_simplex_using_exact_pricing(), and compute_simplex_using_steepest_edge_float().

01135                                                                        {
01136   // The variable exiting the base should be associated to a tableau
01137   // constraint such that the ratio
01138   // tableau[i][entering_var_index] / tableau[i][base[i]]
01139   // is strictly positive and minimal.
01140 
01141   // Find the first tableau constraint `c' having a positive value for
01142   // tableau[i][entering_var_index] / tableau[i][base[i]]
01143   const dimension_type tableau_num_rows = tableau.num_rows();
01144   dimension_type exiting_base_index = tableau_num_rows;
01145   for (dimension_type i = 0; i < tableau_num_rows; ++i) {
01146     const Row& t_i = tableau[i];
01147     const int num_sign = sgn(t_i[entering_var_index]);
01148     if (num_sign != 0 && num_sign == sgn(t_i[base[i]])) {
01149       exiting_base_index = i;
01150       break;
01151     }
01152   }
01153   // Check for unboundedness.
01154   if (exiting_base_index == tableau_num_rows)
01155     return tableau_num_rows;
01156 
01157   // Reaching this point means that a variable will definitely exit the base.
01158   PPL_DIRTY_TEMP_COEFFICIENT(lcm);
01159   PPL_DIRTY_TEMP_COEFFICIENT(current_min);
01160   PPL_DIRTY_TEMP_COEFFICIENT(challenger);
01161   for (dimension_type i = exiting_base_index + 1; i < tableau_num_rows; ++i) {
01162     const Row& t_i = tableau[i];
01163     const Coefficient& t_ie = t_i[entering_var_index];
01164     const Coefficient& t_ib = t_i[base[i]];
01165     const int t_ie_sign = sgn(t_ie);
01166     if (t_ie_sign != 0 && t_ie_sign == sgn(t_ib)) {
01167       WEIGHT_BEGIN();
01168       const Row& t_e = tableau[exiting_base_index];
01169       const Coefficient& t_ee = t_e[entering_var_index];
01170       lcm_assign(lcm, t_ee, t_ie);
01171       exact_div_assign(current_min, lcm, t_ee);
01172       current_min *= t_e[0];
01173       abs_assign(current_min);
01174       exact_div_assign(challenger, lcm, t_ie);
01175       challenger *= t_i[0];
01176       abs_assign(challenger);
01177       current_min -= challenger;
01178       const int sign = sgn(current_min);
01179       if (sign > 0
01180           || (sign == 0 && base[i] < base[exiting_base_index]))
01181         exiting_base_index = i;
01182       WEIGHT_ADD(1044);
01183     }
01184   }
01185   return exiting_base_index;
01186 }

const Variables_Set & Parma_Polyhedra_Library::MIP_Problem::integer_space_dimensions (  )  const [inline]

Returns a set containing all the variables' indexes constrained to be integral.

Definition at line 105 of file MIP_Problem.inlines.hh.

References i_variables.

Referenced by is_mip_satisfiable(), operator<<(), and solve().

00105                                             {
00106   return i_variables;
00107 }

bool Parma_Polyhedra_Library::MIP_Problem::is_in_base ( dimension_type  var_index,
dimension_type row_index 
) const [private]

Definition at line 366 of file MIP_Problem.cc.

References base.

Referenced by compute_generator(), and merge_split_variable().

00367                                                               {
00368   for (row_index = base.size(); row_index-- > 0; )
00369     if (base[row_index] == var_index)
00370       return true;
00371   return false;
00372 }

bool Parma_Polyhedra_Library::MIP_Problem::is_lp_satisfiable (  )  const [private]

Returns true if and if only the LP problem is satisfiable.

Definition at line 1560 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Matrix::add_zero_columns(), external_space_dim, first_pending_constraint, initialized, input_cs, internal_space_dim, mapping, Parma_Polyhedra_Library::Matrix::num_columns(), OK(), OPTIMIZED, PARTIALLY_SATISFIABLE, process_pending_constraints(), SATISFIABLE, status, tableau, UNBOUNDED, and UNSATISFIABLE.

Referenced by is_mip_satisfiable(), is_satisfiable(), solve(), and solve_mip().

01560                                         {
01561 #if PPL_NOISY_SIMPLEX
01562   num_iterations = 0;
01563 #endif // PPL_NOISY_SIMPLEX
01564   switch (status) {
01565   case UNSATISFIABLE:
01566     return false;
01567   case SATISFIABLE:
01568     // Intentionally fall through.
01569   case UNBOUNDED:
01570     // Intentionally fall through.
01571   case OPTIMIZED:
01572     // Intentionally fall through.
01573     return true;
01574   case PARTIALLY_SATISFIABLE:
01575     {
01576       MIP_Problem& x = const_cast<MIP_Problem&>(*this);
01577       // This code tries to handle the case that happens if the tableau is
01578       // empty, so it must be initialized.
01579       if (tableau.num_columns() == 0) {
01580         // Add two columns, the first that handles the inhomogeneous term and
01581         // the second that represent the `sign'.
01582         x.tableau.add_zero_columns(2);
01583         // Sync `mapping' for the inhomogeneous term.
01584         x.mapping.push_back(std::make_pair(0, 0));
01585         // The internal data structures are ready, so prepare for more
01586         // assertion to be checked.
01587         x.initialized = true;
01588       }
01589 
01590       // Apply incrementality to the pending constraint system.
01591       x.process_pending_constraints();
01592       // Update `first_pending_constraint': no more pending.
01593       x.first_pending_constraint = input_cs.size();
01594       // Update also `internal_space_dim'.
01595       x.internal_space_dim = x.external_space_dim;
01596       PPL_ASSERT(OK());
01597       return status != UNSATISFIABLE;
01598     }
01599   }
01600   // We should not be here!
01601   throw std::runtime_error("PPL internal error");
01602 }

bool Parma_Polyhedra_Library::MIP_Problem::is_mip_satisfiable ( MIP_Problem lp,
const Variables_Set i_vars,
Generator p 
) [static, private]

Returns true if and if only the LP problem lp is satisfiable when variables in i_vars can only take integral values.

Parameters:
lp The LP problem. This is assumed to have no integral space dimension.
i_vars The variables that are constrained to take integral values.
p If true is returned, it will encode a feasible point.

Definition at line 1776 of file MIP_Problem.cc.

References add_constraint(), Parma_Polyhedra_Library::assign_r(), choose_branching_variable(), Parma_Polyhedra_Library::Generator::coefficient(), Parma_Polyhedra_Library::Generator::divisor(), Parma_Polyhedra_Library::gcd_assign(), integer_space_dimensions(), is_lp_satisfiable(), last_generator, PPL_DIRTY_TEMP_COEFFICIENT, and space_dimension().

Referenced by is_satisfiable().

01778                                                    {
01779 #if PPL_NOISY_SIMPLEX
01780   ++mip_recursion_level;
01781   std::cout << "MIP_Problem::is_mip_satisfiable(): "
01782             << "entering recursion level " << mip_recursion_level
01783             << "." << std::endl;
01784 #endif // PPL_NOISY_SIMPLEX
01785   PPL_ASSERT(lp.integer_space_dimensions().empty());
01786 
01787   // Solve the LP problem.
01788   if (!lp.is_lp_satisfiable()) {
01789 #if PPL_NOISY_SIMPLEX
01790     std::cout << "MIP_Problem::is_mip_satisfiable(): "
01791               << "exiting from recursion level " << mip_recursion_level
01792               << "." << std::endl;
01793     --mip_recursion_level;
01794 #endif // PPL_NOISY_SIMPLEX
01795     return false;
01796   }
01797 
01798   PPL_DIRTY_TEMP0(mpq_class, tmp_rational);
01799   PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff1);
01800   PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff2);
01801   bool found_satisfiable_generator = true;
01802   dimension_type nonint_dim;
01803   p = lp.last_generator;
01804   const Coefficient& p_divisor = p.divisor();
01805 
01806 #if PPL_SIMPLEX_USE_MIP_HEURISTIC
01807   found_satisfiable_generator
01808     = choose_branching_variable(lp, i_vars, nonint_dim);
01809 #else
01810   PPL_DIRTY_TEMP_COEFFICIENT(gcd);
01811   for (Variables_Set::const_iterator v_begin = i_vars.begin(),
01812          v_end = i_vars.end(); v_begin != v_end; ++v_begin) {
01813     gcd_assign(gcd, p.coefficient(Variable(*v_begin)), p_divisor);
01814     if (gcd != p_divisor) {
01815       nonint_dim = *v_begin;
01816       found_satisfiable_generator = false;
01817       break;
01818     }
01819   }
01820 #endif
01821 
01822   if (found_satisfiable_generator)
01823     return true;
01824 
01825   PPL_ASSERT(nonint_dim < lp.space_dimension());
01826 
01827   assign_r(tmp_rational.get_num(), p.coefficient(Variable(nonint_dim)),
01828            ROUND_NOT_NEEDED);
01829   assign_r(tmp_rational.get_den(), p_divisor, ROUND_NOT_NEEDED);
01830   tmp_rational.canonicalize();
01831   assign_r(tmp_coeff1, tmp_rational, ROUND_DOWN);
01832   assign_r(tmp_coeff2, tmp_rational, ROUND_UP);
01833   {
01834     MIP_Problem lp_aux = lp;
01835     lp_aux.add_constraint(Variable(nonint_dim) <= tmp_coeff1);
01836 #if PPL_NOISY_SIMPLEX
01837     using namespace IO_Operators;
01838     std::cout << "MIP_Problem::is_mip_satisfiable(): "
01839               << "descending with: "
01840               << (Variable(nonint_dim) <= tmp_coeff1)
01841               << "." << std::endl;
01842 #endif // PPL_NOISY_SIMPLEX
01843     if (is_mip_satisfiable(lp_aux, i_vars, p)) {
01844 #if PPL_NOISY_SIMPLEX
01845       std::cout << "MIP_Problem::is_mip_satisfiable(): "
01846                 << "exiting from recursion level " << mip_recursion_level
01847                 << "." << std::endl;
01848       --mip_recursion_level;
01849 #endif // PPL_NOISY_SIMPLEX
01850       return true;
01851     }
01852   }
01853   lp.add_constraint(Variable(nonint_dim) >= tmp_coeff2);
01854 #if PPL_NOISY_SIMPLEX
01855   using namespace IO_Operators;
01856   std::cout << "MIP_Problem::is_mip_satisfiable(): "
01857             << "descending with: "
01858             << (Variable(nonint_dim) >= tmp_coeff2)
01859             << "." << std::endl;
01860 #endif // PPL_NOISY_SIMPLEX
01861   bool satisfiable = is_mip_satisfiable(lp, i_vars, p);
01862 #if PPL_NOISY_SIMPLEX
01863   std::cout << "MIP_Problem::is_mip_satisfiable(): "
01864             << "exiting from recursion level " << mip_recursion_level
01865             << "." << std::endl;
01866   --mip_recursion_level;
01867 #endif // PPL_NOISY_SIMPLEX
01868   return satisfiable;
01869 }

bool Parma_Polyhedra_Library::MIP_Problem::is_satisfiable (  )  const

Checks satisfiability of *this.

Returns:
true if and only if the MIP problem is satisfiable.

Definition at line 213 of file MIP_Problem.cc.

References i_variables, Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::i_vars, is_lp_satisfiable(), is_mip_satisfiable(), last_generator, Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::lp, OK(), OPTIMIZED, PARTIALLY_SATISFIABLE, SATISFIABLE, status, UNBOUNDED, and UNSATISFIABLE.

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::Box< ITV >::Box(), feasible_point(), and Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape().

00213                                      {
00214   // Check `status' to filter out trivial cases.
00215   switch (status) {
00216   case UNSATISFIABLE:
00217     PPL_ASSERT(OK());
00218     return false;
00219   case SATISFIABLE:
00220     // Intentionally fall through
00221   case UNBOUNDED:
00222     // Intentionally fall through.
00223   case OPTIMIZED:
00224     PPL_ASSERT(OK());
00225     return true;
00226   case PARTIALLY_SATISFIABLE:
00227     {
00228       MIP_Problem& x = const_cast<MIP_Problem&>(*this);
00229       // LP case.
00230       if (x.i_variables.empty())
00231         return x.is_lp_satisfiable();
00232 
00233       // MIP case.
00234       {
00235         // Temporarily relax the MIP into an LP problem.
00236         RAII_Temporary_Real_Relaxation relaxed(x);
00237         Generator p = point();
00238         relaxed.lp.is_lp_satisfiable();
00239 #if PPL_NOISY_SIMPLEX
00240         mip_recursion_level = 0;
00241 #endif // PPL_NOISY_SIMPLEX
00242         if (is_mip_satisfiable(relaxed.lp, relaxed.i_vars, p)) {
00243           x.last_generator = p;
00244           x.status = SATISFIABLE;
00245         }
00246         else
00247           x.status = UNSATISFIABLE;
00248       } // `relaxed' destroyed here: relaxation automatically reset.
00249       return (x.status == SATISFIABLE);
00250     }
00251   }
00252   // We should not be here!
00253   throw std::runtime_error("PPL internal error");
00254 }

bool Parma_Polyhedra_Library::MIP_Problem::is_satisfied ( const Constraint c,
const Generator g 
) [static, private]

Returns true if and only if c is satisfied by g.

Definition at line 432 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Constraint::is_inequality(), Parma_Polyhedra_Library::Scalar_Products::sign(), Parma_Polyhedra_Library::Constraint::space_dimension(), and Parma_Polyhedra_Library::Generator::space_dimension().

Referenced by OK(), and parse_constraints().

00432                                                                     {
00433   // Scalar_Products::sign() requires the second argument to be at least
00434   // as large as the first one.
00435   int sp_sign = g.space_dimension() <= c.space_dimension()
00436     ? Scalar_Products::sign(g, c)
00437     : Scalar_Products::sign(c, g);
00438   return c.is_inequality() ? sp_sign >= 0 : sp_sign == 0;
00439 }

bool Parma_Polyhedra_Library::MIP_Problem::is_saturated ( const Constraint c,
const Generator g 
) [static, private]

Returns true if and only if c is saturated by g.

Definition at line 442 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Scalar_Products::sign(), Parma_Polyhedra_Library::Constraint::space_dimension(), and Parma_Polyhedra_Library::Generator::space_dimension().

Referenced by choose_branching_variable().

00442                                                                     {
00443   // Scalar_Products::sign() requires the space dimension of the second
00444   // argument to be at least as large as the one of the first one.
00445   int sp_sign = g.space_dimension() <= c.space_dimension()
00446     ? Scalar_Products::sign(g, c)
00447     : Scalar_Products::sign(c, g);
00448   return sp_sign == 0;
00449 }

void Parma_Polyhedra_Library::MIP_Problem::linear_combine ( Row x,
const Row y,
const dimension_type  k 
) [static, private]

Linearly combines x with y so that *this[k] is 0.

Parameters:
x The Row that will be combined with y object.
y The Row that will be combined with x object.
k The position of *this that have to be $0$.

Computes a linear combination of x and y having the element of index k equal to $0$. Then it assigns the resulting Linear_Row to x and normalizes it.

Definition at line 1086 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Row::normalize(), Parma_Polyhedra_Library::normalize2(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Row::size(), Parma_Polyhedra_Library::sub_mul_assign(), WEIGHT_ADD_MUL, and WEIGHT_BEGIN.

Referenced by pivot(), process_pending_constraints(), and second_phase().

01088                                                          {
01089   WEIGHT_BEGIN();
01090   const dimension_type x_size = x.size();
01091   PPL_ASSERT(x_size == y.size());
01092   PPL_ASSERT(y[k] != 0 && x[k] != 0);
01093   // Let g be the GCD between `x[k]' and `y[k]'.
01094   // For each i the following computes
01095   //   x[i] = x[i]*y[k]/g - y[i]*x[k]/g.
01096   PPL_DIRTY_TEMP_COEFFICIENT(normalized_x_k);
01097   PPL_DIRTY_TEMP_COEFFICIENT(normalized_y_k);
01098   normalize2(x[k], y[k], normalized_x_k, normalized_y_k);
01099   for (dimension_type i = x_size; i-- > 0; )
01100     if (i != k) {
01101       Coefficient& x_i = x[i];
01102       x_i *= normalized_y_k;
01103       // The test against 0 gives rise to a consistent speed up: see
01104       // http://www.cs.unipr.it/pipermail/ppl-devel/2009-February/014000.html
01105       const Coefficient& y_i = y[i];
01106       if (y_i != 0)
01107         sub_mul_assign(x_i, y_i, normalized_x_k);
01108     }
01109   x[k] = 0;
01110   x.normalize();
01111   WEIGHT_ADD_MUL(83, x_size);
01112 }

dimension_type Parma_Polyhedra_Library::MIP_Problem::max_space_dimension (  )  [inline, static]

Returns the maximum space dimension an MIP_Problem can handle.

Definition at line 33 of file MIP_Problem.inlines.hh.

Referenced by add_space_dimensions_and_embed(), and MIP_Problem().

00033                                  {
00034   return Constraint::max_space_dimension();
00035 }

PPL::dimension_type Parma_Polyhedra_Library::MIP_Problem::merge_split_variable ( dimension_type  var_index  )  [private]

Merges back the positive and negative part of a (previously split) variable after detecting a corresponding nonnegativity constraint.

Returns:
If the negative part of var_index was in base, the index of the corresponding tableau row (which has become nonfeasible); otherwise not_a_dimension().
Parameters:
var_index The index of the variable that has to be merged.

Definition at line 375 of file MIP_Problem.cc.

References base, is_in_base(), mapping, Parma_Polyhedra_Library::not_a_dimension(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::permute_columns(), Parma_Polyhedra_Library::Matrix::remove_trailing_columns(), and tableau.

Referenced by process_pending_constraints().

00375                                                              {
00376   // Initialize the return value to a dummy index.
00377   dimension_type unfeasible_tableau_row = not_a_dimension();
00378 
00379   const dimension_type removing_column = mapping[1+var_index].second;
00380 
00381   // Check if the negative part of the split variable is in base:
00382   // if so, the corresponding tableau row becomes nonfeasible.
00383   {
00384     dimension_type base_index;
00385     if (is_in_base(removing_column, base_index)) {
00386       // Set the return value.
00387       unfeasible_tableau_row = base_index;
00388       // Reset base[base_index] to zero to remember nonfeasibility.
00389       base[base_index] = 0;
00390 #ifndef NDEBUG
00391       // Since the negative part of the variable is in base,
00392       // the positive part can not be in base too.
00393       PPL_ASSERT(!is_in_base(mapping[1+var_index].first, base_index));
00394 #endif
00395     }
00396   }
00397 
00398   // Remove the column:
00399   // first, make sure it is the last one in the tableau ...
00400   const dimension_type tableau_num_cols = tableau.num_columns();
00401   if (removing_column != tableau_num_cols - 1) {
00402     std::vector<dimension_type> cycle;
00403     for (dimension_type j = tableau_num_cols - 1; j >= removing_column; --j)
00404       cycle.push_back(j);
00405     cycle.push_back(0);
00406     tableau.permute_columns(cycle);
00407   }
00408   // ... and then actually remove it.
00409   tableau.remove_trailing_columns(1);
00410 
00411   // var_index is no longer split.
00412   mapping[1+var_index].second = 0;
00413 
00414   // Adjust data structured, `shifting' the proper columns to the left by 1.
00415   const dimension_type base_size = base.size();
00416   for (dimension_type i = base_size; i-- > 0; ) {
00417     if (base[i] > removing_column)
00418       --base[i];
00419   }
00420   const dimension_type mapping_size = mapping.size();
00421   for (dimension_type i = mapping_size; i-- > 0; ) {
00422     if (mapping[i].first > removing_column)
00423       --mapping[i].first;
00424     if (mapping[i].second > removing_column)
00425       --mapping[i].second;
00426   }
00427 
00428   return unfeasible_tableau_row;
00429 }

const Linear_Expression & Parma_Polyhedra_Library::MIP_Problem::objective_function (  )  const [inline]

Returns the objective function.

Definition at line 79 of file MIP_Problem.inlines.hh.

References input_obj_function.

Referenced by operator<<().

00079                                       {
00080   return input_obj_function;
00081 }

bool Parma_Polyhedra_Library::MIP_Problem::OK (  )  const

Checks if all the invariants are satisfied.

Definition at line 1872 of file MIP_Problem.cc.

References ascii_dump(), base, Parma_Polyhedra_Library::Generator::coefficient(), Parma_Polyhedra_Library::Generator::divisor(), external_space_dim, first_pending_constraint, Parma_Polyhedra_Library::gcd_assign(), i_variables, initialized, input_cs, input_obj_function, is_satisfied(), last_generator, mapping, Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Generator::OK(), Parma_Polyhedra_Library::Linear_Expression::OK(), Parma_Polyhedra_Library::Matrix::OK(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Row::size(), Parma_Polyhedra_Library::Generator::space_dimension(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), status, tableau, UNSATISFIABLE, and working_cost.

Referenced by add_constraint(), add_constraints(), add_space_dimensions_and_embed(), is_lp_satisfiable(), is_satisfiable(), MIP_Problem(), process_pending_constraints(), second_phase(), set_objective_function(), set_optimization_mode(), and solve().

01872                          {
01873 #ifndef NDEBUG
01874   using std::endl;
01875   using std::cerr;
01876 #endif
01877   const dimension_type input_cs_num_rows = input_cs.size();
01878   // Check that every member used is OK.
01879 
01880   for (dimension_type i = input_cs_num_rows; i-- > 0; )
01881     if (!input_cs[i].OK())
01882       return false;
01883 
01884   if (!tableau.OK() || !input_obj_function.OK() || !last_generator.OK())
01885     return false;
01886 
01887   // Constraint system should contain no strict inequalities.
01888   for (dimension_type i = input_cs_num_rows; i-- > 0; )
01889     if (input_cs[i].is_strict_inequality()) {
01890 #ifndef NDEBUG
01891       cerr << "The feasible region of the MIP_Problem is defined by "
01892            << "a constraint system containing strict inequalities."
01893            << endl;
01894       ascii_dump(cerr);
01895 #endif
01896       return false;
01897     }
01898 
01899   // Constraint system and objective function should be dimension compatible.
01900   if (external_space_dim < input_obj_function.space_dimension()) {
01901 #ifndef NDEBUG
01902     cerr << "The MIP_Problem and the objective function have "
01903          << "incompatible space dimensions ("
01904          << external_space_dim << " < "
01905          << input_obj_function.space_dimension() << ")."
01906          << endl;
01907     ascii_dump(cerr);
01908 #endif
01909     return false;
01910   }
01911 
01912   if (status != UNSATISFIABLE && initialized) {
01913     // Here `last_generator' has to be meaningful.
01914     // Check for dimension compatibility and actual feasibility.
01915     if (external_space_dim != last_generator.space_dimension()) {
01916 #ifndef NDEBUG
01917       cerr << "The MIP_Problem and the cached feasible point have "
01918            << "incompatible space dimensions ("
01919            << external_space_dim << " != "
01920            << last_generator.space_dimension() << ")."
01921            << endl;
01922       ascii_dump(cerr);
01923 #endif
01924       return false;
01925     }
01926 
01927     for (dimension_type i = 0; i < first_pending_constraint; ++i)
01928       if (!is_satisfied(input_cs[i], last_generator)) {
01929 #ifndef NDEBUG
01930         cerr << "The cached feasible point does not belong to "
01931              << "the feasible region of the MIP_Problem."
01932              << endl;
01933         ascii_dump(cerr);
01934 #endif
01935         return false;
01936       }
01937 
01938     // Check that every integer declared variable is really integer.
01939     // in the solution found.
01940     if (!i_variables.empty()) {
01941       PPL_DIRTY_TEMP_COEFFICIENT(gcd);
01942       for (Variables_Set::const_iterator v_it = i_variables.begin(),
01943              v_end = i_variables.end(); v_it != v_end; ++v_it) {
01944         gcd_assign(gcd, last_generator.coefficient(Variable(*v_it)),
01945                    last_generator.divisor());
01946         if (gcd != last_generator.divisor())
01947           return false;
01948       }
01949     }
01950 
01951     const dimension_type tableau_nrows = tableau.num_rows();
01952     const dimension_type tableau_ncols = tableau.num_columns();
01953 
01954     // The number of rows in the tableau and base should be equal.
01955     if (tableau_nrows != base.size()) {
01956 #ifndef NDEBUG
01957       cerr << "tableau and base have incompatible sizes" << endl;
01958       ascii_dump(cerr);
01959 #endif
01960       return false;
01961     }
01962     // The size of `mapping' should be equal to the space dimension
01963     // of `input_cs' plus one.
01964     if (mapping.size() != external_space_dim + 1) {
01965 #ifndef NDEBUG
01966       cerr << "`input_cs' and `mapping' have incompatible sizes" << endl;
01967       ascii_dump(cerr);
01968 #endif
01969       return false;
01970     }
01971 
01972     // The number of columns in the tableau and working_cost should be equal.
01973     if (tableau_ncols != working_cost.size()) {
01974 #ifndef NDEBUG
01975       cerr << "tableau and working_cost have incompatible sizes" << endl;
01976       ascii_dump(cerr);
01977 #endif
01978       return false;
01979     }
01980 
01981     // The vector base should contain indices of tableau's columns.
01982     for (dimension_type i = base.size(); i-- > 0; ) {
01983       if (base[i] > tableau_ncols) {
01984 #ifndef NDEBUG
01985         cerr << "base contains an invalid column index" << endl;
01986         ascii_dump(cerr);
01987 #endif
01988         return false;
01989       }
01990       // tableau[i][base[i] must be different from zero.
01991       // tableau[i][base[j], with i different from j, must not be a zero.
01992       for (dimension_type j = tableau_nrows; j-- > 0; )
01993         if (i != j && tableau[j][base[i]] != 0) {
01994 #ifndef NDEBUG
01995           cerr << "tableau[i][base[i] must be different from zero" << endl;
01996           ascii_dump(cerr);
01997 #endif
01998           return false;
01999         }
02000       if (tableau[i][base[i]] == 0) {
02001 #ifndef NDEBUG
02002         cerr << "tableau[i][base[j], with i different from j, must not be "
02003              << "a zero" << endl;
02004         ascii_dump(cerr);
02005 #endif
02006         return false;
02007       }
02008     }
02009 
02010     // The last column of the tableau must contain only zeroes.
02011     for (dimension_type i = tableau_nrows; i-- > 0; )
02012       if (tableau[i][tableau_ncols-1] != 0) {
02013 #ifndef NDEBUG
02014         cerr << "the last column of the tableau must contain only"
02015           "zeroes"<< endl;
02016         ascii_dump(cerr);
02017 #endif
02018         return false;
02019       }
02020    }
02021 
02022    // All checks passed.
02023    return true;
02024 }

MIP_Problem & Parma_Polyhedra_Library::MIP_Problem::operator= ( const MIP_Problem y  )  [inline]

Assignment operator.

Definition at line 141 of file MIP_Problem.inlines.hh.

References swap().

00141                                            {
00142   MIP_Problem tmp(y);
00143   swap(tmp);
00144   return *this;
00145 }

void Parma_Polyhedra_Library::MIP_Problem::optimal_value ( Coefficient num,
Coefficient den 
) const [inline]

Sets num and den so that $\frac{num}{den}$ is the solution of the optimization problem.

Exceptions:
std::domain_error Thrown if *this doesn't not have an optimizing point, i.e., if the MIP problem is unbounded or not satisfiable.

Definition at line 89 of file MIP_Problem.inlines.hh.

References evaluate_objective_function(), and optimizing_point().

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BFT00_upper_bound_assign_if_exact(), Parma_Polyhedra_Library::Octagonal_Shape< T >::max_min(), and Parma_Polyhedra_Library::BD_Shape< T >::max_min().

00089                                                                    {
00090   const Generator& g = optimizing_point();
00091   evaluate_objective_function(g, num, den);
00092 }

Optimization_Mode Parma_Polyhedra_Library::MIP_Problem::optimization_mode (  )  const [inline]

Returns the optimization mode.

Definition at line 84 of file MIP_Problem.inlines.hh.

References opt_mode.

Referenced by operator<<(), and solve_mip().

00084                                      {
00085   return opt_mode;
00086 }

const PPL::Generator & Parma_Polyhedra_Library::MIP_Problem::optimizing_point (  )  const

Returns an optimal point for *this, if it exists.

Exceptions:
std::domain_error Thrown if *this doesn't not have an optimizing point, i.e., if the MIP problem is unbounded or not satisfiable.

Definition at line 204 of file MIP_Problem.cc.

References last_generator, Parma_Polyhedra_Library::OPTIMIZED_MIP_PROBLEM, and solve().

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::Octagonal_Shape< T >::max_min(), Parma_Polyhedra_Library::BD_Shape< T >::max_min(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), and optimal_value().

00204                                        {
00205   if (solve() == OPTIMIZED_MIP_PROBLEM)
00206     return last_generator;
00207   else
00208     throw std::domain_error("PPL::MIP_Problem::optimizing_point():\n"
00209                             "*this doesn't have an optimizing point.");
00210 }

bool Parma_Polyhedra_Library::MIP_Problem::parse_constraints ( dimension_type additional_tableau_rows,
dimension_type additional_slack_variables,
std::deque< bool > &  is_tableau_constraint,
std::deque< bool > &  is_satisfied_inequality,
std::deque< bool > &  is_nonnegative_variable,
std::deque< bool > &  is_remergeable_variable 
) const [private]

Parses the pending constraints to gather information on how to resize the tableau.

Note:
All of the method parameters are output parameters; their value is only meaningful when the function exit returning value true.
Returns:
false if a trivially false constraint is detected, true otherwise.
Parameters:
additional_tableau_rows On exit, this will store the number of rows that have to be added to the original tableau.
additional_slack_variables This will store the number of slack variables that have to be added to the original tableau.
is_tableau_constraint This container of Boolean flags is initially empty. On exit, it size will be equal to the number of pending constraints in input_cs. For each pending constraint index i, the corresponding element of this container (having index i - first_pending_constraint) will be set to true if and only if the constraint has to be included in the tableau.
is_satisfied_inequality This container of Boolean flags is initially empty. On exit, its size will be equal to the number of pending constraints in input_cs. For each pending constraint index i, the corresponding element of this container (having index i - first_pending_constraint) will be set to true if and only if it is an inequality and it is already satisfied by last_generator (hence it does not require the introduction of an artificial variable).
is_nonnegative_variable This container of Boolean flags is initially empty. On exit, it size is equal to external_space_dim. For each variable (index), the corresponding element of this container is true if the variable is known to be nonnegative (and hence should not be split into a positive and a negative part).
is_remergeable_variable This container of Boolean flags is initially empty. On exit, it size is equal to internal_space_dim. For each variable (index), the corresponding element of this container is true if the variable was previously split into positive and negative parts that can now be merged back, since it is known that the variable is nonnegative.

Definition at line 453 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Constraint::coefficient(), external_space_dim, first_pending_constraint, Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), input_cs, internal_space_dim, Parma_Polyhedra_Library::Constraint::is_equality(), Parma_Polyhedra_Library::Constraint::is_inequality(), is_satisfied(), last_generator, mapping, and Parma_Polyhedra_Library::Constraint::space_dimension().

Referenced by process_pending_constraints().

00458                                                                    {
00459   // Initially all containers are empty.
00460   PPL_ASSERT(is_tableau_constraint.empty()
00461              && is_satisfied_inequality.empty()
00462              && is_nonnegative_variable.empty()
00463              && is_remergeable_variable.empty());
00464 
00465   const dimension_type cs_space_dim = external_space_dim;
00466   const dimension_type cs_num_rows = input_cs.size();
00467   const dimension_type cs_num_pending = cs_num_rows - first_pending_constraint;
00468 
00469   // Counters determining the change in dimensions of the tableau:
00470   // initialized here, they will be updated while examining `input_cs'.
00471   additional_tableau_rows = cs_num_pending;
00472   additional_slack_variables = 0;
00473 
00474   // Resize containers appropriately.
00475 
00476   // On exit, `is_tableau_constraint[i]' will be true if and only if
00477   // `input_cs[first_pending_constraint + i]' is neither a tautology
00478   // (e.g., 1 >= 0) nor a non-negativity constraint (e.g., X >= 0).
00479   is_tableau_constraint.insert(is_tableau_constraint.end(),
00480                                cs_num_pending, true);
00481 
00482   // On exit, `is_satisfied_inequality[i]' will be true if and only if
00483   // `input_cs[first_pending_constraint + i]' is an inequality and it is
00484   // satisfied by `last_generator'.
00485   is_satisfied_inequality.insert(is_satisfied_inequality.end(),
00486                                  cs_num_pending, false);
00487 
00488   // On exit, `is_nonnegative_variable[j]' will be true if and only if
00489   // Variable(j) is bound to be nonnegative in `input_cs'.
00490   is_nonnegative_variable.insert(is_nonnegative_variable.end(),
00491                                  cs_space_dim, false);
00492 
00493   // On exit, `is_remergeable_variable[j]' will be true if and only if
00494   // Variable(j) was initially split and is now remergeable.
00495   is_remergeable_variable.insert(is_remergeable_variable.end(),
00496                                  internal_space_dim, false);
00497 
00498   // Check for variables that are already known to be nonnegative
00499   // due to nonpending constraints.
00500   const dimension_type mapping_size = mapping.size();
00501   if (mapping_size > 0) {
00502     // Note: mapping[0] is associated to the cost function.
00503     for (dimension_type i = std::min(mapping_size - 1, cs_space_dim); i-- > 0; )
00504       if (mapping[i + 1].second == 0)
00505         is_nonnegative_variable[i] = true;
00506   }
00507 
00508   // Process each pending constraint in `input_cs' and
00509   //  - detect variables that are constrained to be nonnegative;
00510   //  - detect (non-negativity or tautology) pending constraints that
00511   //    will not be part of the tableau;
00512   //  - count the number of new slack variables.
00513   for (dimension_type i = cs_num_rows; i-- > first_pending_constraint; ) {
00514     const Constraint& cs_i = input_cs[i];
00515     bool found_a_nonzero_coeff = false;
00516     bool found_many_nonzero_coeffs = false;
00517     dimension_type nonzero_coeff_column_index = 0;
00518     for (dimension_type sd = cs_i.space_dimension(); sd-- > 0; ) {
00519       if (cs_i.coefficient(Variable(sd)) != 0) {
00520         if (found_a_nonzero_coeff) {
00521           found_many_nonzero_coeffs = true;
00522           if (cs_i.is_inequality())
00523             ++additional_slack_variables;
00524           break;
00525         }
00526         else {
00527           nonzero_coeff_column_index = sd + 1;
00528           found_a_nonzero_coeff = true;
00529         }
00530       }
00531     }
00532     // If more than one coefficient is nonzero,
00533     // continue with next constraint.
00534     if (found_many_nonzero_coeffs) {
00535       // CHECKME: Is it true that in the first phase we can apply
00536       // `is_satisfied()' with the generator `point()'?  If so, the following
00537       // code works even if we do not have a feasible point.
00538       // Check for satisfiability of the inequality. This can be done if we
00539       // have a feasible point of *this.
00540       if (cs_i.is_inequality() && is_satisfied(cs_i, last_generator))
00541         is_satisfied_inequality[i - first_pending_constraint] = true;
00542       continue;
00543     }
00544 
00545     if (!found_a_nonzero_coeff) {
00546       // All coefficients are 0.
00547       // The constraint is either trivially true or trivially false.
00548       if (cs_i.is_inequality()) {
00549         if (cs_i.inhomogeneous_term() < 0)
00550           // A constraint such as -1 >= 0 is trivially false.
00551           return false;
00552       }
00553       else
00554         // The constraint is an equality.
00555         if (cs_i.inhomogeneous_term() != 0)
00556           // A constraint such as 1 == 0 is trivially false.
00557           return false;
00558       // Here the constraint is trivially true.
00559       is_tableau_constraint[i - first_pending_constraint] = false;
00560       --additional_tableau_rows;
00561       continue;
00562     }
00563     else {
00564       // Here we have only one nonzero coefficient.
00565       /*
00566 
00567       We have the following methods:
00568       A) Do split the variable and do add the constraint
00569          in the tableau.
00570       B) Do not split the variable and do add the constraint
00571          in the tableau.
00572       C) Do not split the variable and do not add the constraint
00573          in the tableau.
00574 
00575       Let the constraint be (a*v + b relsym 0).
00576       These are the 12 possible combinations we can have:
00577                 a |  b | relsym | method
00578       ----------------------------------
00579       1)       >0 | >0 |   >=   |   A
00580       2)       >0 | >0 |   ==   |   A
00581       3)       <0 | <0 |   >=   |   A
00582       4)       >0 | =0 |   ==   |   B
00583       5)       >0 | <0 |   ==   |   B
00584       Note:    <0 | >0 |   ==   | impossible by strong normalization
00585       Note:    <0 | =0 |   ==   | impossible by strong normalization
00586       Note:    <0 | <0 |   ==   | impossible by strong normalization
00587       6)       >0 | <0 |   >=   |   B
00588       7)       >0 | =0 |   >=   |   C
00589       8)       <0 | >0 |   >=   |   A
00590       9)       <0 | =0 |   >=   |   A
00591 
00592       The next lines will apply the correct method to each case.
00593       */
00594 
00595       // The variable index is not equal to the column index.
00596       const dimension_type nonzero_var_index = nonzero_coeff_column_index - 1;
00597 
00598       const int sgn_a = sgn(cs_i.coefficient(Variable(nonzero_var_index)));
00599       const int sgn_b = sgn(cs_i.inhomogeneous_term());
00600 
00601       // Cases 1-3: apply method A.
00602       if (sgn_a == sgn_b) {
00603         if (cs_i.is_inequality())
00604           ++additional_slack_variables;
00605       }
00606       // Cases 4-5: apply method B.
00607       else if (cs_i.is_equality())
00608         is_nonnegative_variable[nonzero_var_index] = true;
00609       // Case 6: apply method B.
00610       else if (sgn_b < 0) {
00611         is_nonnegative_variable[nonzero_var_index] = true;
00612         ++additional_slack_variables;
00613       }
00614       // Case 7: apply method C.
00615       else if (sgn_a > 0) {
00616         if (!is_nonnegative_variable[nonzero_var_index]) {
00617           is_nonnegative_variable[nonzero_var_index] = true;
00618           if (nonzero_coeff_column_index < mapping_size) {
00619             // Remember to merge back the positive and negative parts.
00620             PPL_ASSERT(nonzero_var_index < internal_space_dim);
00621             is_remergeable_variable[nonzero_var_index] = true;
00622           }
00623         }
00624         is_tableau_constraint[i - first_pending_constraint] = false;
00625         --additional_tableau_rows;
00626       }
00627       // Cases 8-9: apply method A.
00628       else {
00629         PPL_ASSERT(cs_i.is_inequality());
00630         ++additional_slack_variables;
00631       }
00632     }
00633   }
00634   return true;
00635 }

void Parma_Polyhedra_Library::MIP_Problem::pivot ( dimension_type  entering_var_index,
dimension_type  exiting_base_index 
) [private]

Performs the pivoting operation on the tableau.

Parameters:
entering_var_index The index of the variable entering the base.
exiting_base_index The index of the row exiting the base.

Definition at line 1116 of file MIP_Problem.cc.

References base, linear_combine(), Parma_Polyhedra_Library::Matrix::num_rows(), tableau, and working_cost.

Referenced by compute_simplex_using_exact_pricing(), compute_simplex_using_steepest_edge_float(), and erase_artificials().

01117                                                                  {
01118   const Row& tableau_out = tableau[exiting_base_index];
01119   // Linearly combine the constraints.
01120   for (dimension_type i = tableau.num_rows(); i-- > 0; ) {
01121     Row& tableau_i = tableau[i];
01122     if (i != exiting_base_index && tableau_i[entering_var_index] != 0)
01123       linear_combine(tableau_i, tableau_out, entering_var_index);
01124   }
01125   // Linearly combine the cost function.
01126   if (working_cost[entering_var_index] != 0)
01127     linear_combine(working_cost, tableau_out, entering_var_index);
01128   // Adjust the base.
01129   base[exiting_base_index] = entering_var_index;
01130 }

void Parma_Polyhedra_Library::MIP_Problem::print (  )  const

Prints *this to std::cerr using operator<<.

bool Parma_Polyhedra_Library::MIP_Problem::process_pending_constraints (  )  [private]

Processes the pending constraints of *this.

Returns:
true if and only if the MIP problem is satisfiable after processing the pending constraints, false otherwise.

Definition at line 638 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Matrix::add_zero_columns(), Parma_Polyhedra_Library::Matrix::add_zero_rows(), base, Parma_Polyhedra_Library::Linear_Expression::coefficient(), Parma_Polyhedra_Library::Constraint::coefficient(), compute_generator(), compute_simplex_using_exact_pricing(), compute_simplex_using_steepest_edge_float(), erase_artificials(), external_space_dim, first_pending_constraint, get_control_parameter(), Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), input_cs, input_obj_function, internal_space_dim, Parma_Polyhedra_Library::Constraint::is_inequality(), last_generator, linear_combine(), mapping, Parma_Polyhedra_Library::MAXIMIZATION, merge_split_variable(), Parma_Polyhedra_Library::MINIMIZATION, Parma_Polyhedra_Library::neg_assign(), Parma_Polyhedra_Library::not_a_dimension(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), opt_mode, OPTIMIZED, parse_constraints(), PRICING, PRICING_STEEPEST_EDGE_FLOAT, SATISFIABLE, Parma_Polyhedra_Library::Row::size(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), space_dimension(), Parma_Polyhedra_Library::Constraint::space_dimension(), status, tableau, UNBOUNDED, UNSATISFIABLE, and working_cost.

Referenced by is_lp_satisfiable().

00638                                             {
00639   // Check the pending constraints to adjust the data structures.
00640   // If `false' is returned, they are trivially unfeasible.
00641   dimension_type additional_tableau_rows = 0;
00642   dimension_type additional_slack_vars = 0;
00643   std::deque<bool> is_tableau_constraint;
00644   std::deque<bool> is_satisfied_inequality;
00645   std::deque<bool> is_nonnegative_variable;
00646   std::deque<bool> is_remergeable_variable;
00647   if (!parse_constraints(additional_tableau_rows,
00648                          additional_slack_vars,
00649                          is_tableau_constraint,
00650                          is_satisfied_inequality,
00651                          is_nonnegative_variable,
00652                          is_remergeable_variable)) {
00653     status = UNSATISFIABLE;
00654     return false;
00655   };
00656 
00657   // Merge back any variable that was previously split into a positive
00658   // and a negative part and is now known to be nonnegative.
00659   std::vector<dimension_type> unfeasible_tableau_rows;
00660   for (dimension_type i = internal_space_dim; i-- > 0; ) {
00661     if (!is_remergeable_variable[i])
00662       continue;
00663     // TODO: merging all rows in a single shot may be more efficient
00664     // as it would require a single call to permute_columns().
00665     const dimension_type unfeasible_row = merge_split_variable(i);
00666     if (unfeasible_row != not_a_dimension())
00667       unfeasible_tableau_rows.push_back(unfeasible_row);
00668   }
00669 
00670   const dimension_type old_tableau_num_rows = tableau.num_rows();
00671   const dimension_type old_tableau_num_cols = tableau.num_columns();
00672   const dimension_type first_free_tableau_index = old_tableau_num_cols - 1;
00673 
00674   // Update mapping for the new problem variables (if any).
00675   dimension_type additional_problem_vars = 0;
00676   if (external_space_dim > internal_space_dim) {
00677     const dimension_type space_diff = external_space_dim - internal_space_dim;
00678     for (dimension_type i = 0, j = 0; i < space_diff; ++i) {
00679       // Let `mapping' associate the variable index with the corresponding
00680       // tableau column: split the variable into positive and negative
00681       // parts if it is not known to be nonnegative.
00682       const dimension_type positive = first_free_tableau_index + j;
00683       if (is_nonnegative_variable[internal_space_dim + i]) {
00684         // Do not split.
00685         mapping.push_back(std::make_pair(positive, 0));
00686         ++j;
00687         ++additional_problem_vars;
00688       }
00689       else {
00690         // Split: negative index is positive + 1.
00691         mapping.push_back(std::make_pair(positive, positive + 1));
00692         j += 2;
00693         additional_problem_vars += 2;
00694       }
00695     }
00696   }
00697 
00698   // Resize the tableau: first add additional rows ...
00699   if (additional_tableau_rows > 0)
00700     tableau.add_zero_rows(additional_tableau_rows, Row::Flags());
00701 
00702   // ... then add additional columns.
00703   // We need columns for additional (split) problem variables, additional
00704   // slack variables and additional artificials.
00705   // The number of artificials to be added is computed as:
00706   // * number of pending constraints entering the tableau
00707   //     minus
00708   // * pending constraints that are inequalities and are already satisfied
00709   //   by `last_generator'
00710   //     plus
00711   // * number of non-pending constraints that are no longer satisfied
00712   //   due to re-merging of splitted variables.
00713 
00714   dimension_type num_satisfied_ineqs
00715     = std::count(is_satisfied_inequality.begin(),
00716                  is_satisfied_inequality.end(),
00717                  true);
00718   const dimension_type unfeasible_tableau_rows_size
00719     = unfeasible_tableau_rows.size();
00720 
00721   const dimension_type additional_artificial_vars
00722     = (additional_tableau_rows - num_satisfied_ineqs)
00723     + unfeasible_tableau_rows_size;
00724 
00725   const dimension_type additional_tableau_columns
00726     = additional_problem_vars
00727     + additional_slack_vars
00728     + additional_artificial_vars;
00729 
00730   if (additional_tableau_columns > 0)
00731     tableau.add_zero_columns(additional_tableau_columns);
00732 
00733   // Dimensions of the tableau after resizing.
00734   const dimension_type tableau_num_rows = tableau.num_rows();
00735   const dimension_type tableau_num_cols = tableau.num_columns();
00736 
00737   // The following vector will be useful know if a constraint is feasible
00738   // and does not require an additional artificial variable.
00739   std::deque<bool> worked_out_row (tableau_num_rows, false);
00740 
00741   // Sync the `base' vector size to the new tableau: fill with zeros
00742   // to encode that these rows are not OK and must be adjusted.
00743   base.insert(base.end(), additional_tableau_rows, 0);
00744   const dimension_type base_size = base.size();
00745 
00746   // These indexes will be used to insert slack and artificial variables
00747   // in the appropriate position.
00748   dimension_type slack_index
00749     = tableau_num_cols - additional_artificial_vars - 1;
00750   dimension_type artificial_index = slack_index;
00751 
00752   // The first column of the tableau containing an artificial variable.
00753   // Encode with 0 the fact that there are no artificial variables at all.
00754   const dimension_type begin_artificials
00755     = additional_artificial_vars > 0 ? artificial_index : 0;
00756 
00757   // Proceed with the insertion of the pending constraints.
00758   for (dimension_type k = tableau_num_rows,
00759          i = input_cs.size() - first_pending_constraint; i-- > 0; ) {
00760     // Skip if trivially redundant.
00761     if (!is_tableau_constraint[i])
00762       continue;
00763     const Constraint& c = input_cs[i + first_pending_constraint];
00764     // Copy the original constraint in the tableau.
00765     --k;
00766     Row& tableau_k = tableau[k];
00767     for (dimension_type sd = c.space_dimension(); sd-- > 0; ) {
00768       const Coefficient& coeff_sd = c.coefficient(Variable(sd));
00769       if (coeff_sd != 0) {
00770         tableau_k[mapping[sd+1].first] = coeff_sd;
00771         // Split if needed.
00772         if (mapping[sd+1].second != 0)
00773           neg_assign(tableau_k[mapping[sd+1].second], coeff_sd);
00774       }
00775     }
00776     const Coefficient& inhomo = c.inhomogeneous_term();
00777     if (inhomo != 0) {
00778       tableau_k[mapping[0].first] = inhomo;
00779       // Split if needed.
00780       if (mapping[0].second != 0)
00781         neg_assign(tableau_k[mapping[0].second], inhomo);
00782     }
00783 
00784     // Add the slack variable, if needed.
00785     if (c.is_inequality()) {
00786       --slack_index;
00787       tableau_k[slack_index] = -1;
00788       // If the constraint is already satisfied, we will not add an
00789       // artificial variable and put instead the slack variable in base.
00790       if (is_satisfied_inequality[i]) {
00791         base[k] = slack_index;
00792         worked_out_row[k] = true;
00793       }
00794     }
00795     for (dimension_type j = base_size; j-- > 0; )
00796       if (k != j && tableau_k[base[j]] != 0 && base[j] != 0)
00797         linear_combine(tableau_k, tableau[j], base[j]);
00798   }
00799 
00800   // Let all inhomogeneous terms in the tableau be nonpositive,
00801   // so as to simplify the insertion of artificial variables
00802   // (the coefficient of each artificial variable will be 1).
00803   for (dimension_type i = tableau_num_rows; i-- > 0 ; ) {
00804     Row& tableau_i = tableau[i];
00805     if (tableau_i[0] > 0)
00806       for (dimension_type j = tableau_num_cols; j-- > 0; )
00807         neg_assign(tableau_i[j]);
00808   }
00809 
00810   // Reset the working cost function to have the right size.
00811   working_cost = Row(tableau_num_cols, Row::Flags());
00812 
00813   // Set up artificial variables: these will have coefficient 1 in the
00814   // constraint, will enter the base and will have coefficient -1 in
00815   // the cost function.
00816 
00817   // First go through nonpending constraints that became unfeasible
00818   // due to re-merging of split variables.
00819   for (dimension_type i = 0; i < unfeasible_tableau_rows_size; ++i) {
00820     tableau[unfeasible_tableau_rows[i]][artificial_index] = 1;
00821     working_cost[artificial_index] = -1;
00822     base[unfeasible_tableau_rows[i]] = artificial_index;
00823     ++artificial_index;
00824   }
00825   // Then go through newly added tableau rows, disregarding inequalities
00826   // that are already satisfied by `last_generator' (this information
00827   // is encoded in `worked_out_row').
00828   for (dimension_type i = old_tableau_num_rows; i < tableau_num_rows; ++i) {
00829     if (worked_out_row[i])
00830       continue;
00831     tableau[i][artificial_index] = 1;
00832     working_cost[artificial_index] = -1;
00833     base[i] = artificial_index;
00834     ++artificial_index;
00835   }
00836   // One past the last tableau column index containing an artificial variable.
00837   const dimension_type end_artificials = artificial_index;
00838 
00839   // Set the extra-coefficient of the cost functions to record its sign.
00840   // This is done to keep track of the possible sign's inversion.
00841   const dimension_type last_obj_index = working_cost.size() - 1;
00842   working_cost[last_obj_index] = 1;
00843 
00844   // Express the problem in terms of the variables in base.
00845   for (dimension_type i = tableau_num_rows; i-- > 0; )
00846     if (working_cost[base[i]] != 0)
00847       linear_combine(working_cost, tableau[i], base[i]);
00848 
00849   // Deal with zero dimensional problems.
00850   if (space_dimension() == 0) {
00851     status = OPTIMIZED;
00852     last_generator = point();
00853     return true;
00854   }
00855   // Deal with trivial cases.
00856   // If there is no constraint in the tableau, then the feasible region
00857   // is only delimited by non-negativity constraints. Therefore,
00858   // the problem is unbounded as soon as the cost function has
00859   // a variable with a positive coefficient.
00860   if (tableau_num_rows == 0) {
00861     const dimension_type input_obj_function_size
00862       = input_obj_function.space_dimension();
00863     for (dimension_type i = input_obj_function_size; i-- > 0; )
00864       // If a the value of a variable in the objective function is
00865       // different from zero, the final status is unbounded.
00866       // In the first part the variable is constrained to be greater or equal
00867       // than zero.
00868       if ((((input_obj_function.coefficient(Variable(i)) > 0
00869              && opt_mode == MAXIMIZATION)
00870             || (input_obj_function.coefficient(Variable(i)) < 0
00871                 && opt_mode == MINIMIZATION)) && mapping[i].second == 0)
00872           // In the following case the variable is unconstrained.
00873           || (input_obj_function.coefficient(Variable(i)) != 0
00874               && mapping[i].second != 0)) {
00875         // Ensure the right space dimension is obtained.
00876         last_generator = point(0 * Variable(space_dimension()-1));
00877         status = UNBOUNDED;
00878         return true;
00879       }
00880 
00881     // The problem is neither trivially unfeasible nor trivially unbounded.
00882     // The tableau was successful computed and the caller has to figure
00883     // out which case applies.
00884     status = OPTIMIZED;
00885     // Ensure the right space dimension is obtained.
00886     last_generator = point(0*Variable(space_dimension()-1));
00887     PPL_ASSERT(OK());
00888     return true;
00889   }
00890 
00891   // Now we are ready to solve the first phase.
00892   bool first_phase_succesful
00893     = (get_control_parameter(PRICING) == PRICING_STEEPEST_EDGE_FLOAT)
00894     ? compute_simplex_using_steepest_edge_float()
00895     : compute_simplex_using_exact_pricing();
00896 
00897 #if PPL_NOISY_SIMPLEX
00898   std::cout << "MIP_Problem::process_pending_constraints(): "
00899             << "1st phase ended at iteration " << num_iterations
00900             << "." << std::endl;
00901 #endif // PPL_NOISY_SIMPLEX
00902 
00903   if (!first_phase_succesful || working_cost[0] != 0) {
00904     // The feasible region is empty.
00905     status = UNSATISFIABLE;
00906     return false;
00907   }
00908 
00909   // Prepare *this for a possible second phase.
00910   if (begin_artificials != 0)
00911     erase_artificials(begin_artificials, end_artificials);
00912   compute_generator();
00913   status = SATISFIABLE;
00914   PPL_ASSERT(OK());
00915   return true;
00916 }

void Parma_Polyhedra_Library::MIP_Problem::second_phase (  )  [private]

Optimizes the MIP problem using the second phase of the primal simplex algorithm.

Definition at line 1474 of file MIP_Problem.cc.

References base, Parma_Polyhedra_Library::Linear_Expression::coefficient(), compute_generator(), compute_simplex_using_exact_pricing(), compute_simplex_using_steepest_edge_float(), get_control_parameter(), Parma_Polyhedra_Library::Linear_Expression::inhomogeneous_term(), input_obj_function, linear_combine(), mapping, Parma_Polyhedra_Library::MINIMIZATION, Parma_Polyhedra_Library::neg_assign(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), opt_mode, OPTIMIZED, PRICING, PRICING_STEEPEST_EDGE_FLOAT, SATISFIABLE, Parma_Polyhedra_Library::Row::size(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), status, Parma_Polyhedra_Library::Row::swap(), tableau, UNBOUNDED, and working_cost.

Referenced by solve(), and solve_mip().

01474                              {
01475   // Second_phase requires that *this is satisfiable.
01476   PPL_ASSERT(status == SATISFIABLE || status == UNBOUNDED || status == OPTIMIZED);
01477   // In the following cases the problem is already solved.
01478   if (status == UNBOUNDED || status == OPTIMIZED)
01479     return;
01480 
01481   // Build the objective function for the second phase.
01482   const dimension_type input_obj_function_sd
01483     = input_obj_function.space_dimension();
01484   Row new_cost(input_obj_function_sd + 1, Row::Flags());
01485   for (dimension_type i = input_obj_function_sd; i-- > 0; )
01486     new_cost[i+1] = input_obj_function.coefficient(Variable(i));
01487   new_cost[0] = input_obj_function.inhomogeneous_term();
01488 
01489   // Negate the cost function if we are minimizing.
01490   if (opt_mode == MINIMIZATION)
01491     for (dimension_type i = new_cost.size(); i-- > 0; )
01492       neg_assign(new_cost[i]);
01493 
01494   // Substitute properly the cost function in the `costs' matrix.
01495   const dimension_type cost_zero_size = working_cost.size();
01496   Row tmp_cost = Row(new_cost, cost_zero_size, cost_zero_size);
01497   tmp_cost.swap(working_cost);
01498   working_cost[cost_zero_size-1] = 1;
01499 
01500   // Split the variables the cost function.
01501   for (dimension_type i = new_cost.size(); i-- > 1; ) {
01502     const dimension_type original_var = mapping[i].first;
01503     const dimension_type split_var = mapping[i].second;
01504     working_cost[original_var] = new_cost[i];
01505     if (mapping[i].second != 0)
01506       neg_assign(working_cost[split_var], new_cost[i]);
01507   }
01508   // Here the first phase problem succeeded with optimum value zero.
01509   // Express the old cost function in terms of the computed base.
01510   for (dimension_type i = tableau.num_rows(); i-- > 0; ) {
01511     const dimension_type base_i = base[i];
01512     if (working_cost[base_i] != 0)
01513       linear_combine(working_cost, tableau[i], base_i);
01514   }
01515   // Solve the second phase problem.
01516   bool second_phase_successful
01517     = (get_control_parameter(PRICING) == PRICING_STEEPEST_EDGE_FLOAT)
01518     ? compute_simplex_using_steepest_edge_float()
01519     : compute_simplex_using_exact_pricing();
01520   compute_generator();
01521 #if PPL_NOISY_SIMPLEX
01522   std::cout << "MIP_Problem::second_phase(): 2nd phase ended at iteration "
01523             << num_iterations
01524             << "." << std::endl;
01525 #endif // PPL_NOISY_SIMPLEX
01526   status = second_phase_successful ? OPTIMIZED : UNBOUNDED;
01527   PPL_ASSERT(OK());
01528 }

void Parma_Polyhedra_Library::MIP_Problem::set_control_parameter ( Control_Parameter_Value  value  )  [inline]

Sets control parameter value.

Definition at line 117 of file MIP_Problem.inlines.hh.

References pricing.

00117                                                                 {
00118   pricing = value;
00119 }

void Parma_Polyhedra_Library::MIP_Problem::set_objective_function ( const Linear_Expression obj  ) 

Sets the objective function to obj.

Exceptions:
std::invalid_argument Thrown if the space dimension of obj is strictly greater than the space dimension of *this.

Definition at line 179 of file MIP_Problem.cc.

References input_obj_function, OK(), OPTIMIZED, SATISFIABLE, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), space_dimension(), status, and UNBOUNDED.

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), and Parma_Polyhedra_Library::Polyhedron::strongly_minimize_constraints().

00179                                                                    {
00180   if (space_dimension() < obj.space_dimension()) {
00181     std::ostringstream s;
00182     s << "PPL::MIP_Problem::set_objective_function(obj):\n"
00183       << "obj.space_dimension() == " << obj.space_dimension()
00184       << " exceeds this->space_dimension == " << space_dimension()
00185       << ".";
00186     throw std::invalid_argument(s.str());
00187   }
00188   input_obj_function = obj;
00189   if (status == UNBOUNDED || status == OPTIMIZED)
00190     status = SATISFIABLE;
00191   PPL_ASSERT(OK());
00192 }

void Parma_Polyhedra_Library::MIP_Problem::set_optimization_mode ( Optimization_Mode  mode  )  [inline]
PPL::MIP_Problem_Status Parma_Polyhedra_Library::MIP_Problem::solve (  )  const

Optimizes the MIP problem.

Returns:
An MIP_Problem_Status flag indicating the outcome of the optimization attempt (unfeasible, unbounded or optimized problem).

Definition at line 257 of file MIP_Problem.cc.

References i_variables, Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::i_vars, integer_space_dimensions(), is_lp_satisfiable(), last_generator, Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::lp, OK(), OPTIMIZED, Parma_Polyhedra_Library::OPTIMIZED_MIP_PROBLEM, PARTIALLY_SATISFIABLE, SATISFIABLE, second_phase(), solve_mip(), status, UNBOUNDED, Parma_Polyhedra_Library::UNBOUNDED_MIP_PROBLEM, Parma_Polyhedra_Library::UNFEASIBLE_MIP_PROBLEM, and UNSATISFIABLE.

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::BD_Shape< T >::BFT00_upper_bound_assign_if_exact(), Parma_Polyhedra_Library::Octagonal_Shape< T >::bounds(), Parma_Polyhedra_Library::BD_Shape< T >::bounds(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::Octagonal_Shape< T >::max_min(), Parma_Polyhedra_Library::BD_Shape< T >::max_min(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), optimizing_point(), Parma_Polyhedra_Library::Polyhedron::simplify_using_context_assign(), and Parma_Polyhedra_Library::Polyhedron::strongly_minimize_constraints().

00257                            {
00258   switch (status) {
00259   case UNSATISFIABLE:
00260     PPL_ASSERT(OK());
00261     return UNFEASIBLE_MIP_PROBLEM;
00262   case UNBOUNDED:
00263     PPL_ASSERT(OK());
00264     return UNBOUNDED_MIP_PROBLEM;
00265   case OPTIMIZED:
00266     PPL_ASSERT(OK());
00267     return OPTIMIZED_MIP_PROBLEM;
00268   case SATISFIABLE:
00269     // Intentionally fall through
00270   case PARTIALLY_SATISFIABLE:
00271     {
00272       MIP_Problem& x = const_cast<MIP_Problem&>(*this);
00273       if (x.i_variables.empty()) {
00274         // LP case.
00275         if (x.is_lp_satisfiable()) {
00276           x.second_phase();
00277           if (x.status == UNBOUNDED)
00278             return UNBOUNDED_MIP_PROBLEM;
00279           else {
00280             PPL_ASSERT(x.status == OPTIMIZED);
00281             return OPTIMIZED_MIP_PROBLEM;
00282           }
00283         }
00284         return UNFEASIBLE_MIP_PROBLEM;
00285       }
00286 
00287       // MIP case.
00288       MIP_Problem_Status return_value;
00289       Generator g = point();
00290       {
00291         // Temporarily relax the MIP into an LP problem.
00292         RAII_Temporary_Real_Relaxation relaxed(x);
00293         if (relaxed.lp.is_lp_satisfiable())
00294           relaxed.lp.second_phase();
00295         else {
00296           x.status = UNSATISFIABLE;
00297           // NOTE: `relaxed' destroyed: relaxation automatically reset.
00298           return UNFEASIBLE_MIP_PROBLEM;
00299         }
00300         PPL_DIRTY_TEMP0(mpq_class, incumbent_solution);
00301         bool have_incumbent_solution = false;
00302 
00303         MIP_Problem lp_copy(relaxed.lp);
00304         PPL_ASSERT(lp_copy.integer_space_dimensions().empty());
00305         return_value = solve_mip(have_incumbent_solution,
00306                                  incumbent_solution, g,
00307                                  lp_copy, relaxed.i_vars);
00308       } // `relaxed' destroyed here: relaxation automatically reset.
00309 
00310       switch (return_value) {
00311       case UNFEASIBLE_MIP_PROBLEM:
00312         x.status = UNSATISFIABLE;
00313         break;
00314       case UNBOUNDED_MIP_PROBLEM:
00315         x.status = UNBOUNDED;
00316         // A feasible point has been set in `solve_mip()', so that
00317         // a call to `feasible_point' will be successful.
00318         x.last_generator = g;
00319         break;
00320       case OPTIMIZED_MIP_PROBLEM:
00321         x.status = OPTIMIZED;
00322         // Set the internal generator.
00323         x.last_generator = g;
00324         break;
00325       }
00326       PPL_ASSERT(OK());
00327       return return_value;
00328     }
00329   }
00330   // We should not be here!
00331   throw std::runtime_error("PPL internal error");
00332 }

PPL::MIP_Problem_Status Parma_Polyhedra_Library::MIP_Problem::solve_mip ( bool &  have_incumbent_solution,
mpq_class &  incumbent_solution_value,
Generator incumbent_solution_point,
MIP_Problem mip,
const Variables_Set i_vars 
) [static, private]

Returns a status that encodes the solution of the MIP problem.

Parameters:
have_incumbent_solution It is used to store if the solving process has found a provisional optimum point.
incumbent_solution_value Encodes the evaluated value of the provisional optimum point found.
incumbent_solution_point If the method returns `OPTIMIZED', this will contain the optimality point.
mip The problem that has to be solved.
i_vars The variables that are constrained to take an integer value.

Definition at line 1605 of file MIP_Problem.cc.

References add_constraint(), Parma_Polyhedra_Library::assign_r(), Parma_Polyhedra_Library::Generator::coefficient(), Parma_Polyhedra_Library::Generator::divisor(), evaluate_objective_function(), Parma_Polyhedra_Library::gcd_assign(), Parma_Polyhedra_Library::is_canonical(), is_lp_satisfiable(), last_generator, Parma_Polyhedra_Library::MAXIMIZATION, Parma_Polyhedra_Library::MINIMIZATION, optimization_mode(), OPTIMIZED, Parma_Polyhedra_Library::OPTIMIZED_MIP_PROBLEM, PPL_DIRTY_TEMP_COEFFICIENT, second_phase(), space_dimension(), status, Parma_Polyhedra_Library::UNBOUNDED_MIP_PROBLEM, and Parma_Polyhedra_Library::UNFEASIBLE_MIP_PROBLEM.

Referenced by solve().

01609                                                          {
01610   // Solve the problem as a non MIP one, it must be done internally.
01611   PPL::MIP_Problem_Status lp_status;
01612   if (lp.is_lp_satisfiable()) {
01613     lp.second_phase();
01614     lp_status = (lp.status == OPTIMIZED) ? OPTIMIZED_MIP_PROBLEM
01615       : UNBOUNDED_MIP_PROBLEM;
01616   }
01617   else
01618     return UNFEASIBLE_MIP_PROBLEM;
01619 
01620   PPL_DIRTY_TEMP0(mpq_class, tmp_rational);
01621 
01622   Generator p = point();
01623   PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff1);
01624   PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff2);
01625 
01626   if (lp_status == UNBOUNDED_MIP_PROBLEM)
01627     p = lp.last_generator;
01628   else {
01629     PPL_ASSERT(lp_status == OPTIMIZED_MIP_PROBLEM);
01630     // Do not call optimizing_point().
01631     p = lp.last_generator;
01632     lp.evaluate_objective_function(p, tmp_coeff1, tmp_coeff2);
01633     assign_r(tmp_rational.get_num(), tmp_coeff1, ROUND_NOT_NEEDED);
01634     assign_r(tmp_rational.get_den(), tmp_coeff2, ROUND_NOT_NEEDED);
01635     PPL_ASSERT(is_canonical(tmp_rational));
01636     if (have_incumbent_solution
01637         && ((lp.optimization_mode() == MAXIMIZATION
01638              && tmp_rational <= incumbent_solution_value)
01639             || (lp.optimization_mode() == MINIMIZATION
01640                 && tmp_rational >= incumbent_solution_value)))
01641       // Abandon this path.
01642       return lp_status;
01643   }
01644 
01645   bool found_satisfiable_generator = true;
01646   PPL_DIRTY_TEMP_COEFFICIENT(gcd);
01647   const Coefficient& p_divisor = p.divisor();
01648   dimension_type nonint_dim = lp.space_dimension();
01649   for (Variables_Set::const_iterator v_begin = i_vars.begin(),
01650          v_end = i_vars.end(); v_begin != v_end; ++v_begin) {
01651     gcd_assign(gcd, p.coefficient(Variable(*v_begin)), p_divisor);
01652     if (gcd != p_divisor) {
01653       nonint_dim = *v_begin;
01654       found_satisfiable_generator = false;
01655       break;
01656     }
01657   }
01658   if (found_satisfiable_generator) {
01659     // All the coordinates of `point' are satisfiable.
01660     if (lp_status == UNBOUNDED_MIP_PROBLEM) {
01661       // This is a point that belongs to the MIP_Problem.
01662       // In this way we are sure that we will return every time
01663       // a feasible point if requested by the user.
01664       incumbent_solution_point = p;
01665       return lp_status;
01666     }
01667     if (!have_incumbent_solution
01668         || (lp.optimization_mode() == MAXIMIZATION
01669             && tmp_rational > incumbent_solution_value)
01670         || tmp_rational < incumbent_solution_value) {
01671       incumbent_solution_value = tmp_rational;
01672       incumbent_solution_point = p;
01673       have_incumbent_solution = true;
01674 #if PPL_NOISY_SIMPLEX
01675       PPL_DIRTY_TEMP_COEFFICIENT(num);
01676       PPL_DIRTY_TEMP_COEFFICIENT(den);
01677       lp.evaluate_objective_function(p, num, den);
01678       std::cout << "MIP_Problem::solve_mip(): "
01679                 << "new value found: " << num << "/" << den
01680                 << "." << std::endl;
01681 #endif // PPL_NOISY_SIMPLEX
01682     }
01683     return lp_status;
01684   }
01685 
01686   PPL_ASSERT(nonint_dim < lp.space_dimension());
01687 
01688   assign_r(tmp_rational.get_num(), p.coefficient(Variable(nonint_dim)),
01689            ROUND_NOT_NEEDED);
01690   assign_r(tmp_rational.get_den(), p_divisor, ROUND_NOT_NEEDED);
01691   tmp_rational.canonicalize();
01692   assign_r(tmp_coeff1, tmp_rational, ROUND_DOWN);
01693   assign_r(tmp_coeff2, tmp_rational, ROUND_UP);
01694   {
01695     MIP_Problem lp_aux = lp;
01696     lp_aux.add_constraint(Variable(nonint_dim) <= tmp_coeff1);
01697 #if PPL_NOISY_SIMPLEX
01698     using namespace IO_Operators;
01699     std::cout << "MIP_Problem::solve_mip(): "
01700               << "descending with: "
01701               << (Variable(nonint_dim) <= tmp_coeff1)
01702               << "." << std::endl;
01703 #endif // PPL_NOISY_SIMPLEX
01704     solve_mip(have_incumbent_solution, incumbent_solution_value,
01705               incumbent_solution_point, lp_aux, i_vars);
01706   }
01707   // TODO: change this when we will be able to remove constraints.
01708   lp.add_constraint(Variable(nonint_dim) >= tmp_coeff2);
01709 #if PPL_NOISY_SIMPLEX
01710   using namespace IO_Operators;
01711   std::cout << "MIP_Problem::solve_mip(): "
01712             << "descending with: "
01713             << (Variable(nonint_dim) >= tmp_coeff2)
01714             << "." << std::endl;
01715 #endif // PPL_NOISY_SIMPLEX
01716   solve_mip(have_incumbent_solution, incumbent_solution_value,
01717             incumbent_solution_point, lp, i_vars);
01718   return have_incumbent_solution ? lp_status : UNFEASIBLE_MIP_PROBLEM;
01719 }

dimension_type Parma_Polyhedra_Library::MIP_Problem::space_dimension (  )  const [inline]
PPL::dimension_type Parma_Polyhedra_Library::MIP_Problem::steepest_edge_exact_entering_index (  )  const [private]

Computes the column index of the variable entering the base, using an exact steepest-edge algorithm with anti-cycling rule.

Returns:
The column index of the variable that enters the base. If no such variable exists, optimality was achieved and 0 is returned.

To compute the entering_index, the steepest edge algorithm chooses the index `j' such that $\frac{d_{j}}{\|\Delta x^{j} \|}$ is the largest in absolute value, where

\[ \|\Delta x^{j} \| = \left( 1+\sum_{i=1}^{m} \alpha_{ij}^2 \right)^{\frac{1}{2}}. \]

Recall that, due to the exact integer implementation of the algorithm, our tableau doesn't contain the ``real'' $\alpha$ values, but these can be computed dividing the value of the coefficient by the value of the variable in base. Obviously the result may not be an integer, so we will proceed in another way: we compute the lcm of all the variables in base to get the good ``weight'' of each Coefficient of the tableau.

Definition at line 989 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::add_mul_assign(), base, Parma_Polyhedra_Library::exact_div_assign(), Parma_Polyhedra_Library::lcm_assign(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Row::size(), swap(), tableau, WEIGHT_ADD_MUL, WEIGHT_BEGIN, and working_cost.

Referenced by compute_simplex_using_exact_pricing().

00989                                                          {
00990   const dimension_type tableau_num_rows = tableau.num_rows();
00991   PPL_ASSERT(tableau_num_rows == base.size());
00992   // The square of the lcm of all the coefficients of variables in base.
00993   PPL_DIRTY_TEMP_COEFFICIENT(squared_lcm_basis);
00994   // The normalization factor for each coefficient in the tableau.
00995   std::vector<Coefficient> norm_factor(tableau_num_rows);
00996   {
00997     WEIGHT_BEGIN();
00998     // Compute the lcm of all the coefficients of variables in base.
00999     PPL_DIRTY_TEMP_COEFFICIENT(lcm_basis);
01000     lcm_basis = 1;
01001     for (dimension_type i = tableau_num_rows; i-- > 0; )
01002       lcm_assign(lcm_basis, lcm_basis, tableau[i][base[i]]);
01003     // Compute normalization factors.
01004     for (dimension_type i = tableau_num_rows; i-- > 0; )
01005       exact_div_assign(norm_factor[i], lcm_basis, tableau[i][base[i]]);
01006     // Compute the square of `lcm_basis', exploiting the fact that
01007     // `lcm_basis' will no longer be needed.
01008     lcm_basis *= lcm_basis;
01009     std::swap(squared_lcm_basis, lcm_basis);
01010     WEIGHT_ADD_MUL(444, tableau_num_rows);
01011   }
01012 
01013   // Defined here to avoid repeated (de-)allocations.
01014   PPL_DIRTY_TEMP_COEFFICIENT(challenger_num);
01015   PPL_DIRTY_TEMP_COEFFICIENT(scalar_value);
01016   PPL_DIRTY_TEMP_COEFFICIENT(challenger_den);
01017   PPL_DIRTY_TEMP_COEFFICIENT(challenger_value);
01018   PPL_DIRTY_TEMP_COEFFICIENT(current_value);
01019 
01020   PPL_DIRTY_TEMP_COEFFICIENT(current_num);
01021   PPL_DIRTY_TEMP_COEFFICIENT(current_den);
01022   dimension_type entering_index = 0;
01023   const int cost_sign = sgn(working_cost[working_cost.size() - 1]);
01024   for (dimension_type j = tableau.num_columns() - 1; j-- > 1; ) {
01025     const Coefficient& cost_j = working_cost[j];
01026     if (sgn(cost_j) == cost_sign) {
01027       WEIGHT_BEGIN();
01028       // We cannot compute the (exact) square root of abs(\Delta x_j).
01029       // The workaround is to compute the square of `cost[j]'.
01030       challenger_num = cost_j * cost_j;
01031       // Due to our integer implementation, the `1' term in the denominator
01032       // of the original formula has to be replaced by `squared_lcm_basis'.
01033       challenger_den = squared_lcm_basis;
01034       for (dimension_type i = tableau_num_rows; i-- > 0; ) {
01035         const Coefficient& tableau_ij = tableau[i][j];
01036         // The test against 0 gives rise to a consistent speed up: see
01037         // http://www.cs.unipr.it/pipermail/ppl-devel/2009-February/014000.html
01038         if (tableau_ij != 0) {
01039           scalar_value = tableau_ij * norm_factor[i];
01040           add_mul_assign(challenger_den, scalar_value, scalar_value);
01041         }
01042       }
01043       // Initialization during the first loop.
01044       if (entering_index == 0) {
01045         std::swap(current_num, challenger_num);
01046         std::swap(current_den, challenger_den);
01047         entering_index = j;
01048         continue;
01049       }
01050       challenger_value = challenger_num * current_den;
01051       current_value = current_num * challenger_den;
01052       // Update the values, if the challenger wins.
01053       if (challenger_value > current_value) {
01054         std::swap(current_num, challenger_num);
01055         std::swap(current_den, challenger_den);
01056         entering_index = j;
01057       }
01058       WEIGHT_ADD_MUL(47, tableau_num_rows);
01059     }
01060   }
01061   return entering_index;
01062 }

PPL::dimension_type Parma_Polyhedra_Library::MIP_Problem::steepest_edge_float_entering_index (  )  const [private]

Same as steepest_edge_exact_entering_index, but using floating points.

Note:
Due to rounding errors, the index of the variable entering the base of the MIP problem is not predictable across different architectures. Hence, the overall simplex computation may differ in the path taken to reach the optimum. Anyway, the exact final result will be computed for the MIP_Problem.

Definition at line 943 of file MIP_Problem.cc.

References base, Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Row::size(), tableau, WEIGHT_ADD_MUL, WEIGHT_BEGIN, and working_cost.

Referenced by compute_simplex_using_steepest_edge_float().

00943                                                          {
00944   const dimension_type tableau_num_rows = tableau.num_rows();
00945   PPL_ASSERT(tableau_num_rows == base.size());
00946   double challenger_num = 0.0;
00947   double challenger_den = 0.0;
00948   double current_value = 0.0;
00949   double float_tableau_value = 0.0;
00950   double float_tableau_denum = 0.0;
00951   dimension_type entering_index = 0;
00952   const int cost_sign = sgn(working_cost[working_cost.size() - 1]);
00953   for (dimension_type j = tableau.num_columns() - 1; j-- > 1; ) {
00954     const Coefficient& cost_j = working_cost[j];
00955     if (sgn(cost_j) == cost_sign) {
00956       WEIGHT_BEGIN();
00957       // We cannot compute the (exact) square root of abs(\Delta x_j).
00958       // The workaround is to compute the square of `cost[j]'.
00959       assign(challenger_num, cost_j);
00960       challenger_num = std::abs(challenger_num);
00961       // Due to our integer implementation, the `1' term in the denominator
00962       // of the original formula has to be replaced by `squared_lcm_basis'.
00963       challenger_den = 1.0;
00964       for (dimension_type i = tableau_num_rows; i-- > 0; ) {
00965         const Row& tableau_i = tableau[i];
00966         const Coefficient& tableau_ij = tableau_i[j];
00967         if (tableau_ij != 0) {
00968           PPL_ASSERT(tableau_i[base[i]] != 0);
00969           assign(float_tableau_value, tableau_ij);
00970           assign(float_tableau_denum, tableau_i[base[i]]);
00971           float_tableau_value /= float_tableau_denum;
00972           challenger_den += float_tableau_value * float_tableau_value;
00973         }
00974       }
00975       double challenger_value = sqrt(challenger_den);
00976       // Initialize `current_value' during the first iteration.
00977       // Otherwise update if the challenger wins.
00978       if (entering_index == 0 || challenger_value > current_value) {
00979         current_value = challenger_value;
00980         entering_index = j;
00981       }
00982       WEIGHT_ADD_MUL(338, tableau_num_rows);
00983     }
00984   }
00985   return entering_index;
00986 }

void Parma_Polyhedra_Library::MIP_Problem::swap ( MIP_Problem y  )  [inline]

Swaps *this with y.

Definition at line 122 of file MIP_Problem.inlines.hh.

References base, external_space_dim, first_pending_constraint, i_variables, initialized, input_cs, input_obj_function, internal_space_dim, last_generator, mapping, opt_mode, pricing, status, tableau, and working_cost.

Referenced by clear(), operator=(), Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::RAII_Temporary_Real_Relaxation(), steepest_edge_exact_entering_index(), swap(), and Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::~RAII_Temporary_Real_Relaxation().

00122                                 {
00123   std::swap(external_space_dim, y.external_space_dim);
00124   std::swap(internal_space_dim, y.internal_space_dim);
00125   std::swap(tableau, y.tableau);
00126   std::swap(working_cost, y.working_cost);
00127   std::swap(mapping, y.mapping);
00128   std::swap(initialized, y.initialized);
00129   std::swap(base, y.base);
00130   std::swap(status, y.status);
00131   std::swap(pricing, y.pricing);
00132   std::swap(input_cs, y.input_cs);
00133   std::swap(first_pending_constraint, y.first_pending_constraint);
00134   std::swap(input_obj_function, y.input_obj_function);
00135   std::swap(opt_mode, y.opt_mode);
00136   std::swap(last_generator, y.last_generator);
00137   std::swap(i_variables, y.i_variables);
00138 }

PPL::dimension_type Parma_Polyhedra_Library::MIP_Problem::textbook_entering_index (  )  const [private]

Computes the column index of the variable entering the base, using the textbook algorithm with anti-cycling rule.

Returns:
The column index of the variable that enters the base. If no such variable exists, optimality was achieved and 0 is returned.

Definition at line 1067 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Row::size(), and working_cost.

Referenced by compute_simplex_using_exact_pricing(), and compute_simplex_using_steepest_edge_float().

01067                                               {
01068   // The variable entering the base is the first one whose coefficient
01069   // in the cost function has the same sign the cost function itself.
01070   // If no such variable exists, then we met the optimality condition
01071   // (and return 0 to the caller).
01072 
01073   // Get the "sign" of the cost function.
01074   const dimension_type cost_sign_index = working_cost.size() - 1;
01075   const int cost_sign = sgn(working_cost[cost_sign_index]);
01076   PPL_ASSERT(cost_sign != 0);
01077   for (dimension_type i = 1; i < cost_sign_index; ++i)
01078     if (sgn(working_cost[i]) == cost_sign)
01079       return i;
01080   // No variable has to enter the base:
01081   // the cost function was optimized.
01082   return 0;
01083 }

memory_size_type Parma_Polyhedra_Library::MIP_Problem::total_memory_in_bytes (  )  const [inline]

Returns the total size in bytes of the memory occupied by *this.

Definition at line 173 of file MIP_Problem.inlines.hh.

References external_memory_in_bytes().

00173                                          {
00174   return sizeof(*this) + external_memory_in_bytes();
00175 }


Friends And Related Function Documentation

std::ostream & operator<< ( std::ostream &  s,
const MIP_Problem lp 
) [related]

Output operator.

Definition at line 2296 of file MIP_Problem.cc.

References constraints_begin(), constraints_end(), integer_space_dimensions(), Parma_Polyhedra_Library::MAXIMIZATION, objective_function(), and optimization_mode().

02296                                                                 {
02297   s << "Constraints:";
02298   for (MIP_Problem::const_iterator i = lp.constraints_begin(),
02299          i_end = lp.constraints_end(); i != i_end; ++i)
02300     s << "\n" << *i;
02301   s << "\nObjective function: "
02302     << lp.objective_function()
02303     << "\nOptimization mode: "
02304     << (lp.optimization_mode() == MAXIMIZATION
02305         ? "MAXIMIZATION"
02306         : "MINIMIZATION");
02307   s << "\nInteger variables: " << lp.integer_space_dimensions();
02308   return s;
02309 }

friend class RAII_Temporary_Real_Relaxation [friend]

Definition at line 525 of file MIP_Problem.defs.hh.

Specializes std::swap.

Definition at line 183 of file MIP_Problem.inlines.hh.

References swap().

00184                                             {
00185   x.swap(y);
00186 }


Member Data Documentation

The first index of `input_cs' containing a pending constraint.

Definition at line 492 of file MIP_Problem.defs.hh.

Referenced by ascii_dump(), is_lp_satisfiable(), OK(), parse_constraints(), process_pending_constraints(), and swap().

A Boolean encoding whether or not internal data structures have already been properly sized and populated: useful to allow for deeper checks in method OK().

Definition at line 486 of file MIP_Problem.defs.hh.

Referenced by ascii_dump(), is_lp_satisfiable(), OK(), and swap().

The space dimension of the current (partial) solution of the MIP problem; it may be smaller than external_space_dim.

Definition at line 432 of file MIP_Problem.defs.hh.

Referenced by ascii_dump(), is_lp_satisfiable(), parse_constraints(), process_pending_constraints(), and swap().

A map between the variables of `input_cs' and `tableau'.

Contains all the pairs (i, j) such that mapping[i].first encodes the index of the column in the tableau where input_cs[i] is stored; mapping[i].second not a zero, encodes the split part of the tableau of input_cs[i]. The "positive" one is represented by mapping[i].first and the "negative" one is represented by mapping[i].second.

Definition at line 448 of file MIP_Problem.defs.hh.

Referenced by ascii_dump(), compute_generator(), external_memory_in_bytes(), is_lp_satisfiable(), merge_split_variable(), OK(), parse_constraints(), process_pending_constraints(), second_phase(), and swap().

The optimization mode requested.

Definition at line 498 of file MIP_Problem.defs.hh.

Referenced by ascii_dump(), optimization_mode(), process_pending_constraints(), second_phase(), set_optimization_mode(), and swap().

The pricing method in use.

Definition at line 479 of file MIP_Problem.defs.hh.

Referenced by ascii_dump(), get_control_parameter(), set_control_parameter(), and swap().


The documentation for this class was generated from the following files:
Generated on Sun Feb 27 16:20:23 2011 for PPL by  doxygen 1.6.3