PPL  1.2
Parma_Polyhedra_Library::MIP_Problem Class Reference

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

#include <MIP_Problem_defs.hh>

Collaboration diagram for Parma_Polyhedra_Library::MIP_Problem:

Classes

class  const_iterator
 A read-only iterator on the constraints defining the feasible region. More...
 
struct  Inherit_Constraints
 A tag type to distinguish normal vs. inheriting copy constructor. More...
 
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...
 

Public Member Functions

 MIP_Problem (dimension_type dim=0)
 Builds a trivial MIP problem. More...
 
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. More...
 
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. More...
 
 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. More...
 
 MIP_Problem (const MIP_Problem &y)
 Ordinary copy constructor. More...
 
 ~MIP_Problem ()
 Destructor. More...
 
MIP_Problemoperator= (const MIP_Problem &y)
 Assignment operator. More...
 
dimension_type space_dimension () const
 Returns the space dimension of the MIP problem. More...
 
const Variables_Setinteger_space_dimensions () const
 Returns a set containing all the variables' indexes constrained to be integral. More...
 
const_iterator constraints_begin () const
 Returns a read-only iterator to the first constraint defining the feasible region. More...
 
const_iterator constraints_end () const
 Returns a past-the-end read-only iterator to the sequence of constraints defining the feasible region. More...
 
const Linear_Expressionobjective_function () const
 Returns the objective function. More...
 
Optimization_Mode optimization_mode () const
 Returns the optimization mode. More...
 
void clear ()
 Resets *this to be equal to the trivial MIP problem. More...
 
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. More...
 
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. More...
 
void add_constraint (const Constraint &c)
 Adds a copy of constraint c to the MIP problem. More...
 
void add_constraints (const Constraint_System &cs)
 Adds a copy of the constraints in cs to the MIP problem. More...
 
void set_objective_function (const Linear_Expression &obj)
 Sets the objective function to obj. More...
 
void set_optimization_mode (Optimization_Mode mode)
 Sets the optimization mode to mode. More...
 
bool is_satisfiable () const
 Checks satisfiability of *this. More...
 
MIP_Problem_Status solve () const
 Optimizes the MIP problem. More...
 
void evaluate_objective_function (const Generator &evaluating_point, Coefficient &numer, Coefficient &denom) const
 Sets num and denom so that $\frac{\mathtt{numer}}{\mathtt{denom}}$ is the result of evaluating the objective function on evaluating_point. More...
 
const Generatorfeasible_point () const
 Returns a feasible point for *this, if it exists. More...
 
const Generatoroptimizing_point () const
 Returns an optimal point for *this, if it exists. More...
 
void optimal_value (Coefficient &numer, Coefficient &denom) const
 Sets numer and denom so that $\frac{\mathtt{numer}}{\mathtt{denom}}$ is the solution of the optimization problem. More...
 
bool OK () const
 Checks if all the invariants are satisfied. More...
 
void ascii_dump () const
 Writes to std::cerr an ASCII representation of *this. More...
 
void ascii_dump (std::ostream &s) const
 Writes to s an ASCII representation of *this. More...
 
void print () const
 Prints *this to std::cerr using operator<<. More...
 
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. More...
 
memory_size_type total_memory_in_bytes () const
 Returns the total size in bytes of the memory occupied by *this. More...
 
memory_size_type external_memory_in_bytes () const
 Returns the size in bytes of the memory managed by *this. More...
 
void m_swap (MIP_Problem &y)
 Swaps *this with y. More...
 
Control_Parameter_Value get_control_parameter (Control_Parameter_Name name) const
 Returns the value of the control parameter name. More...
 
void set_control_parameter (Control_Parameter_Value value)
 Sets control parameter value. More...
 

Static Public Member Functions

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

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< Constraint * > Constraint_Sequence
 A type alias for a sequence of constraints. More...
 
typedef Sparse_Row Row
 
typedef Row working_cost_type
 

Private Member Functions

 MIP_Problem (const MIP_Problem &y, Inherit_Constraints)
 Copy constructor inheriting constraints. More...
 
void add_constraint_helper (const Constraint &c)
 Helper method: implements exception safe addition. More...
 
void process_pending_constraints ()
 Processes the pending constraints of *this. More...
 
void second_phase ()
 Optimizes the MIP problem using the second phase of the primal simplex algorithm. More...
 
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. More...
 
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. More...
 
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. More...
 
void pivot (dimension_type entering_var_index, dimension_type exiting_base_index)
 Performs the pivoting operation on the tableau. More...
 
dimension_type textbook_entering_index () const
 Computes the column index of the variable entering the base, using the textbook algorithm with anti-cycling rule. More...
 
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. More...
 
dimension_type steepest_edge_float_entering_index () const
 Same as steepest_edge_exact_entering_index, but using floating points. More...
 
bool compute_simplex_using_exact_pricing ()
 Returns true if and if only the algorithm successfully computed a feasible solution. More...
 
bool compute_simplex_using_steepest_edge_float ()
 Returns true if and if only the algorithm successfully computed a feasible solution. More...
 
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. More...
 
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. More...
 
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. More...
 
bool is_lp_satisfiable () const
 Returns true if and if only the LP problem is satisfiable. More...
 

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. More...
 
static void linear_combine (Dense_Row &x, const Sparse_Row &y, const dimension_type k)
 Linearly combines x with y so that *this[k] is 0. More...
 
static bool is_unbounded_obj_function (const Linear_Expression &obj_function, const std::vector< std::pair< dimension_type, dimension_type > > &mapping, Optimization_Mode optimization_mode)
 
static bool is_satisfied (const Constraint &c, const Generator &g)
 Returns true if and only if c is satisfied by g. More...
 
static bool is_saturated (const Constraint &c, const Generator &g)
 Returns true if and only if c is saturated by g. More...
 
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. More...
 
static bool is_mip_satisfiable (MIP_Problem &mip, const Variables_Set &i_vars, Generator &p)
 Returns true if and if only the MIP problem mip is satisfiable when variables in i_vars can only take integral values. More...
 
static bool choose_branching_variable (const MIP_Problem &mip, const Variables_Set &i_vars, dimension_type &branching_index)
 Returns true if and if only mip.last_generator satisfies all the integrality conditions implicitly stated using by i_vars. More...
 

Private Attributes

dimension_type external_space_dim
 The dimension of the vector space. More...
 
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. More...
 
Matrix< Rowtableau
 The matrix encoding the current feasible region in tableau form. More...
 
working_cost_type working_cost
 The working cost function. More...
 
std::vector< std::pair< dimension_type, dimension_type > > mapping
 A map between the variables of `input_cs' and `tableau'. More...
 
std::vector< dimension_typebase
 The current basic solution. More...
 
Status status
 The internal state of the MIP problem. More...
 
Control_Parameter_Value pricing
 The pricing method in use. More...
 
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(). More...
 
std::vector< Constraint * > input_cs
 The sequence of constraints describing the feasible region. More...
 
dimension_type inherited_constraints
 The number of constraints that are inherited from our parent in the recursion tree built when solving via branch-and-bound. More...
 
dimension_type first_pending_constraint
 The first index of `input_cs' containing a pending constraint. More...
 
Linear_Expression input_obj_function
 The objective function to be optimized. More...
 
Optimization_Mode opt_mode
 The optimization mode requested. More...
 
Generator last_generator
 The last successfully computed feasible or optimizing point. More...
 
Variables_Set i_variables
 A set containing all the indexes of variables that are constrained to have an integer value. More...
 

Friends

struct RAII_Temporary_Real_Relaxation
 

Related Functions

(Note that these are not member functions.)

std::ostream & operator<< (std::ostream &s, const MIP_Problem &mip)
 
std::ostream & operator<< (std::ostream &s, const MIP_Problem &mip)
 Output operator. More...
 
void swap (MIP_Problem &x, MIP_Problem &y)
 Swaps x with y. More...
 
void swap (MIP_Problem &x, MIP_Problem &y)
 

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 dimension of the vector space;
  • the feasible region, by means of a finite set of linear equality and non-strict inequality constraints;
  • the subset of the unknown variables that range over the integers (the other variables implicitly ranging over the reals);
  • the objective function, described by a Linear_Expression;
  • the optimization mode (either maximization or minimization).

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 87 of file MIP_Problem_defs.hh.

Member Typedef Documentation

A type alias for a sequence of constraints.

Definition at line 237 of file MIP_Problem_defs.hh.

Definition at line 508 of file MIP_Problem_defs.hh.

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
dimThe dimension of the vector space enclosing *this (optional argument with default value $0$).
Exceptions
std::length_errorThrown if dim exceeds max_space_dimension().

Definition at line 78 of file MIP_Problem.cc.

References max_space_dimension(), and OK().

79  : external_space_dim(dim),
81  tableau(),
82  working_cost(0),
83  mapping(),
84  base(),
87  initialized(false),
88  input_cs(),
93  last_generator(point()),
94  i_variables() {
95  // Check for space dimension overflow.
96  if (dim > max_space_dimension()) {
97  throw std::length_error("PPL::MIP_Problem::MIP_Problem(dim, cs, obj, "
98  "mode):\n"
99  "dim exceeds the maximum allowed "
100  "space dimension.");
101  }
102  PPL_ASSERT(OK());
103 }
Optimization_Mode opt_mode
The optimization mode requested.
Linear_Expression input_obj_function
The objective function to be optimized.
working_cost_type working_cost
The working cost function.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< dimension_type > base
The current basic solution.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Variables_Set i_variables
A set containing all the indexes of variables that are constrained to have an integer value...
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
bool OK() const
Checks if all the invariants are satisfied.
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
bool initialized
A Boolean encoding whether or not internal data structures have already been properly sized and popul...
Status status
The internal state of the MIP problem.
dimension_type inherited_constraints
The number of constraints that are inherited from our parent in the recursion tree built when solving...
Maximization is requested.
Generator last_generator
The last successfully computed feasible or optimizing point.
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than exte...
Steepest edge pricing method, using floating points (default).
Control_Parameter_Value pricing
The pricing method in use.
dimension_type external_space_dim
The dimension of the vector space.
dimension_type first_pending_constraint
The first index of `input_cs' containing a pending constraint.
static dimension_type max_space_dimension()
Returns the maximum space dimension an MIP_Problem can handle.
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 
)

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
dimThe dimension of the vector space enclosing *this.
firstAn input iterator to the start of the sequence of constraints.
lastA past-the-end input iterator to the sequence of constraints.
int_varsThe set of variables' indexes that are constrained to take integer values.
objThe objective function (optional argument with default value $0$).
modeThe optimization mode (optional argument with default value MAXIMIZATION).
Exceptions
std::length_errorThrown if dim exceeds max_space_dimension().
std::invalid_argumentThrown 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 add_constraint_helper(), external_space_dim, i_variables, input_cs, max_space_dimension(), OK(), Parma_Polyhedra_Library::Variables_Set::space_dimension(), and Parma_Polyhedra_Library::Linear_Expression::space_dimension().

37  : external_space_dim(dim),
39  tableau(),
40  working_cost(0),
41  mapping(),
42  base(),
45  initialized(false),
46  input_cs(),
49  input_obj_function(obj),
50  opt_mode(mode),
51  last_generator(point()),
52  i_variables(int_vars) {
53  // Check that integer Variables_Set does not exceed the space dimension
54  // of the problem.
56  std::ostringstream s;
57  s << "PPL::MIP_Problem::MIP_Problem"
58  << "(dim, first, last, int_vars, obj, mode):\n"
59  << "dim == "<< external_space_dim << " and int_vars.space_dimension() =="
60  << " " << i_variables.space_dimension() << " are dimension"
61  "incompatible.";
62  throw std::invalid_argument(s.str());
63  }
64 
65  // Check for space dimension overflow.
66  if (dim > max_space_dimension()) {
67  throw std::length_error("PPL::MIP_Problem:: MIP_Problem(dim, first, "
68  "last, int_vars, obj, mode):\n"
69  "dim exceeds the maximum allowed"
70  "space dimension.");
71  }
72  // Check the objective function.
73  if (obj.space_dimension() > dim) {
74  std::ostringstream s;
75  s << "PPL::MIP_Problem::MIP_Problem(dim, first, last,"
76  << "int_vars, obj, mode):\n"
77  << "obj.space_dimension() == "<< obj.space_dimension()
78  << " exceeds d == "<< dim << ".";
79  throw std::invalid_argument(s.str());
80  }
81  // Check the constraints.
82  try {
83  for (In i = first; i != last; ++i) {
84  if (i->is_strict_inequality()) {
85  throw std::invalid_argument("PPL::MIP_Problem::"
86  "MIP_Problem(dim, first, last, int_vars,"
87  "obj, mode):\nrange [first, last) contains"
88  "a strict inequality constraint.");
89  }
90  if (i->space_dimension() > dim) {
91  std::ostringstream s;
92  s << "PPL::MIP_Problem::"
93  << "MIP_Problem(dim, first, last, int_vars, obj, mode):\n"
94  << "range [first, last) contains a constraint having space"
95  << "dimension == " << i->space_dimension() << " that exceeds"
96  "this->space_dimension == " << dim << ".";
97  throw std::invalid_argument(s.str());
98  }
100  }
101  } catch (...) {
102  // Delete the allocated constraints, to avoid memory leaks.
103 
104  for (Constraint_Sequence::const_iterator
105  i = input_cs.begin(), i_end = input_cs.end();
106  i != i_end; ++i) {
107  delete *i;
108  }
109 
110  throw;
111  }
112  PPL_ASSERT(OK());
113 }
dimension_type space_dimension() const
Returns the dimension of the smallest vector space enclosing all the variables whose indexes are in t...
Optimization_Mode opt_mode
The optimization mode requested.
Linear_Expression input_obj_function
The objective function to be optimized.
working_cost_type working_cost
The working cost function.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< dimension_type > base
The current basic solution.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Variables_Set i_variables
A set containing all the indexes of variables that are constrained to have an integer value...
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
bool OK() const
Checks if all the invariants are satisfied.
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
bool initialized
A Boolean encoding whether or not internal data structures have already been properly sized and popul...
Status status
The internal state of the MIP problem.
dimension_type inherited_constraints
The number of constraints that are inherited from our parent in the recursion tree built when solving...
void add_constraint_helper(const Constraint &c)
Helper method: implements exception safe addition.
Generator last_generator
The last successfully computed feasible or optimizing point.
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than exte...
Steepest edge pricing method, using floating points (default).
Control_Parameter_Value pricing
The pricing method in use.
dimension_type external_space_dim
The dimension of the vector space.
dimension_type first_pending_constraint
The first index of `input_cs' containing a pending constraint.
static dimension_type max_space_dimension()
Returns the maximum space dimension an MIP_Problem can handle.
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 
)

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
dimThe dimension of the vector space enclosing *this.
firstAn input iterator to the start of the sequence of constraints.
lastA past-the-end input iterator to the sequence of constraints.
objThe objective function (optional argument with default value $0$).
modeThe optimization mode (optional argument with default value MAXIMIZATION).
Exceptions
std::length_errorThrown if dim exceeds max_space_dimension().
std::invalid_argumentThrown 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 116 of file MIP_Problem_templates.hh.

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

120  : external_space_dim(dim),
122  tableau(),
123  working_cost(0),
124  mapping(),
125  base(),
128  initialized(false),
129  input_cs(),
132  input_obj_function(obj),
133  opt_mode(mode),
134  last_generator(point()),
135  i_variables() {
136  // Check for space dimension overflow.
137  if (dim > max_space_dimension()) {
138  throw std::length_error("PPL::MIP_Problem::"
139  "MIP_Problem(dim, first, last, obj, mode):\n"
140  "dim exceeds the maximum allowed space "
141  "dimension.");
142  }
143  // Check the objective function.
144  if (obj.space_dimension() > dim) {
145  std::ostringstream s;
146  s << "PPL::MIP_Problem::MIP_Problem(dim, first, last,"
147  << " obj, mode):\n"
148  << "obj.space_dimension() == "<< obj.space_dimension()
149  << " exceeds d == "<< dim << ".";
150  throw std::invalid_argument(s.str());
151  }
152  // Check the constraints.
153  try {
154  for (In i = first; i != last; ++i) {
155  if (i->is_strict_inequality()) {
156  throw std::invalid_argument("PPL::MIP_Problem::"
157  "MIP_Problem(dim, first, last, obj, mode):"
158  "\n"
159  "range [first, last) contains a strict "
160  "inequality constraint.");
161  }
162  if (i->space_dimension() > dim) {
163  std::ostringstream s;
164  s << "PPL::MIP_Problem::"
165  << "MIP_Problem(dim, first, last, obj, mode):\n"
166  << "range [first, last) contains a constraint having space"
167  << "dimension" << " == " << i->space_dimension() << " that exceeds"
168  "this->space_dimension == " << dim << ".";
169  throw std::invalid_argument(s.str());
170  }
172  }
173  } catch (...) {
174  // Delete the allocated constraints, to avoid memory leaks.
175 
176  for (Constraint_Sequence::const_iterator
177  i = input_cs.begin(), i_end = input_cs.end();
178  i != i_end; ++i) {
179  delete *i;
180  }
181 
182  throw;
183  }
184  PPL_ASSERT(OK());
185 }
Optimization_Mode opt_mode
The optimization mode requested.
Linear_Expression input_obj_function
The objective function to be optimized.
working_cost_type working_cost
The working cost function.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< dimension_type > base
The current basic solution.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Variables_Set i_variables
A set containing all the indexes of variables that are constrained to have an integer value...
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
bool OK() const
Checks if all the invariants are satisfied.
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
bool initialized
A Boolean encoding whether or not internal data structures have already been properly sized and popul...
Status status
The internal state of the MIP problem.
dimension_type inherited_constraints
The number of constraints that are inherited from our parent in the recursion tree built when solving...
void add_constraint_helper(const Constraint &c)
Helper method: implements exception safe addition.
Generator last_generator
The last successfully computed feasible or optimizing point.
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than exte...
Steepest edge pricing method, using floating points (default).
Control_Parameter_Value pricing
The pricing method in use.
dimension_type external_space_dim
The dimension of the vector space.
dimension_type first_pending_constraint
The first index of `input_cs' containing a pending constraint.
static dimension_type max_space_dimension()
Returns the maximum space dimension an MIP_Problem can handle.
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
dimThe dimension of the vector space enclosing *this.
csThe constraint system defining the feasible region.
objThe objective function (optional argument with default value $0$).
modeThe optimization mode (optional argument with default value MAXIMIZATION).
Exceptions
std::length_errorThrown if dim exceeds max_space_dimension().
std::invalid_argumentThrown 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 105 of file MIP_Problem.cc.

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

109  : external_space_dim(dim),
111  tableau(),
112  working_cost(0),
113  mapping(),
114  base(),
117  initialized(false),
118  input_cs(),
121  input_obj_function(obj),
122  opt_mode(mode),
123  last_generator(point()),
124  i_variables() {
125  // Check for space dimension overflow.
126  if (dim > max_space_dimension()) {
127  throw std::length_error("PPL::MIP_Problem::MIP_Problem(dim, cs, obj, "
128  "mode):\n"
129  "dim exceeds the maximum allowed"
130  "space dimension.");
131  }
132  // Check the objective function.
133  if (obj.space_dimension() > dim) {
134  std::ostringstream s;
135  s << "PPL::MIP_Problem::MIP_Problem(dim, cs, obj,"
136  << " mode):\n"
137  << "obj.space_dimension() == "<< obj.space_dimension()
138  << " exceeds dim == "<< dim << ".";
139  throw std::invalid_argument(s.str());
140  }
141  // Check the constraint system.
142  if (cs.space_dimension() > dim) {
143  std::ostringstream s;
144  s << "PPL::MIP_Problem::MIP_Problem(dim, cs, obj, mode):\n"
145  << "cs.space_dimension == " << cs.space_dimension()
146  << " exceeds dim == " << dim << ".";
147  throw std::invalid_argument(s.str());
148  }
149  if (cs.has_strict_inequalities()) {
150  throw std::invalid_argument("PPL::MIP_Problem::"
151  "MIP_Problem(d, cs, obj, m):\n"
152  "cs contains strict inequalities.");
153  }
154  // Actually copy the constraints.
156  i = cs.begin(), i_end = cs.end(); i != i_end; ++i) {
158  }
159 
160  PPL_ASSERT(OK());
161 }
Optimization_Mode opt_mode
The optimization mode requested.
Linear_Expression input_obj_function
The objective function to be optimized.
working_cost_type working_cost
The working cost function.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< dimension_type > base
The current basic solution.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Variables_Set i_variables
A set containing all the indexes of variables that are constrained to have an integer value...
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
bool OK() const
Checks if all the invariants are satisfied.
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
bool initialized
A Boolean encoding whether or not internal data structures have already been properly sized and popul...
Status status
The internal state of the MIP problem.
dimension_type inherited_constraints
The number of constraints that are inherited from our parent in the recursion tree built when solving...
void add_constraint_helper(const Constraint &c)
Helper method: implements exception safe addition.
Generator last_generator
The last successfully computed feasible or optimizing point.
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than exte...
Steepest edge pricing method, using floating points (default).
Control_Parameter_Value pricing
The pricing method in use.
dimension_type external_space_dim
The dimension of the vector space.
dimension_type first_pending_constraint
The first index of `input_cs' containing a pending constraint.
static dimension_type max_space_dimension()
Returns the maximum space dimension an MIP_Problem can handle.
Constraint_System_const_iterator const_iterator
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 add_constraint_helper(), input_cs, and OK().

45  : external_space_dim(y.external_space_dim),
46  internal_space_dim(y.internal_space_dim),
47  tableau(y.tableau),
48  working_cost(y.working_cost),
49  mapping(y.mapping),
50  base(y.base),
51  status(y.status),
52  pricing(y.pricing),
53  initialized(y.initialized),
54  input_cs(),
57  input_obj_function(y.input_obj_function),
58  opt_mode(y.opt_mode),
59  last_generator(y.last_generator),
60  i_variables(y.i_variables) {
61  input_cs.reserve(y.input_cs.size());
62  for (Constraint_Sequence::const_iterator i = y.input_cs.begin(),
63  i_end = y.input_cs.end(); i != i_end; ++i) {
64  add_constraint_helper(*(*i));
65  }
66  PPL_ASSERT(OK());
67 }
Optimization_Mode opt_mode
The optimization mode requested.
Linear_Expression input_obj_function
The objective function to be optimized.
working_cost_type working_cost
The working cost function.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< dimension_type > base
The current basic solution.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Variables_Set i_variables
A set containing all the indexes of variables that are constrained to have an integer value...
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
bool OK() const
Checks if all the invariants are satisfied.
bool initialized
A Boolean encoding whether or not internal data structures have already been properly sized and popul...
Status status
The internal state of the MIP problem.
dimension_type inherited_constraints
The number of constraints that are inherited from our parent in the recursion tree built when solving...
void add_constraint_helper(const Constraint &c)
Helper method: implements exception safe addition.
Generator last_generator
The last successfully computed feasible or optimizing point.
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than exte...
Control_Parameter_Value pricing
The pricing method in use.
dimension_type external_space_dim
The dimension of the vector space.
dimension_type first_pending_constraint
The first index of `input_cs' containing a pending constraint.
Parma_Polyhedra_Library::MIP_Problem::~MIP_Problem ( )
inline

Destructor.

Definition at line 111 of file MIP_Problem_inlines.hh.

References inherited_constraints, input_cs, and Parma_Polyhedra_Library::nth_iter().

111  {
112  // NOTE: do NOT delete inherited constraints; they are owned
113  // (and will eventually be deleted) by ancestors.
114  for (Constraint_Sequence::const_iterator
116  i_end = input_cs.end(); i != i_end; ++i) {
117  delete *i;
118  }
119 }
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
RA_Container::iterator nth_iter(RA_Container &cont, dimension_type n)
dimension_type inherited_constraints
The number of constraints that are inherited from our parent in the recursion tree built when solving...
Parma_Polyhedra_Library::MIP_Problem::MIP_Problem ( const MIP_Problem y,
Inherit_Constraints   
)
inlineprivate

Copy constructor inheriting constraints.

Definition at line 70 of file MIP_Problem_inlines.hh.

References OK().

71  : external_space_dim(y.external_space_dim),
72  internal_space_dim(y.internal_space_dim),
73  tableau(y.tableau),
74  working_cost(y.working_cost),
75  mapping(y.mapping),
76  base(y.base),
77  status(y.status),
78  pricing(y.pricing),
79  initialized(y.initialized),
80  input_cs(y.input_cs),
81  // NOTE: The constraints are inherited, NOT copied!
82  inherited_constraints(y.input_cs.size()),
83  first_pending_constraint(y.first_pending_constraint),
84  input_obj_function(y.input_obj_function),
85  opt_mode(y.opt_mode),
86  last_generator(y.last_generator),
87  i_variables(y.i_variables) {
88  PPL_ASSERT(OK());
89 }
Optimization_Mode opt_mode
The optimization mode requested.
Linear_Expression input_obj_function
The objective function to be optimized.
working_cost_type working_cost
The working cost function.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< dimension_type > base
The current basic solution.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Variables_Set i_variables
A set containing all the indexes of variables that are constrained to have an integer value...
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
bool OK() const
Checks if all the invariants are satisfied.
bool initialized
A Boolean encoding whether or not internal data structures have already been properly sized and popul...
Status status
The internal state of the MIP problem.
dimension_type inherited_constraints
The number of constraints that are inherited from our parent in the recursion tree built when solving...
Generator last_generator
The last successfully computed feasible or optimizing point.
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than exte...
Control_Parameter_Value pricing
The pricing method in use.
dimension_type external_space_dim
The dimension of the vector space.
dimension_type first_pending_constraint
The first index of `input_cs' containing a pending constraint.

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_argumentThrown 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 164 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Constraint::is_strict_inequality(), and Parma_Polyhedra_Library::Constraint::space_dimension().

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().

164  {
165  if (space_dimension() < c.space_dimension()) {
166  std::ostringstream s;
167  s << "PPL::MIP_Problem::add_constraint(c):\n"
168  << "c.space_dimension() == "<< c.space_dimension() << " exceeds "
169  "this->space_dimension == " << space_dimension() << ".";
170  throw std::invalid_argument(s.str());
171  }
172  if (c.is_strict_inequality()) {
173  throw std::invalid_argument("PPL::MIP_Problem::add_constraint(c):\n"
174  "c is a strict inequality.");
175  }
177  if (status != UNSATISFIABLE) {
179  }
180  PPL_ASSERT(OK());
181 }
bool OK() const
Checks if all the invariants are satisfied.
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
Status status
The internal state of the MIP problem.
void add_constraint_helper(const Constraint &c)
Helper method: implements exception safe addition.
Coefficient c
Definition: PIP_Tree.cc:64
dimension_type space_dimension() const
Returns the space dimension of the MIP problem.
void Parma_Polyhedra_Library::MIP_Problem::add_constraint_helper ( const Constraint c)
inlineprivate

Helper method: implements exception safe addition.

Definition at line 92 of file MIP_Problem_inlines.hh.

References Parma_Polyhedra_Library::compute_capacity(), and input_cs.

Referenced by MIP_Problem().

92  {
93  // For exception safety, reserve space for the new element.
94  const dimension_type size = input_cs.size();
95  if (size == input_cs.capacity()) {
96  const dimension_type max_size = input_cs.max_size();
97  if (size == max_size) {
98  throw std::length_error("MIP_Problem::add_constraint(): "
99  "too many constraints");
100  }
101  // Use an exponential grow policy to avoid too many reallocations.
102  input_cs.reserve(compute_capacity(size + 1, max_size));
103  }
104 
105  // This operation does not throw, because the space for the new element
106  // has already been reserved: hence the new-ed Constraint is safe.
107  input_cs.push_back(new Constraint(c));
108 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
dimension_type compute_capacity(dimension_type requested_size, dimension_type maximum_size)
Speculative allocation function.
Coefficient c
Definition: PIP_Tree.cc:64
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_argumentThrown 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 184 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(), and Parma_Polyhedra_Library::Constraint_System::space_dimension().

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().

184  {
185  if (space_dimension() < cs.space_dimension()) {
186  std::ostringstream s;
187  s << "PPL::MIP_Problem::add_constraints(cs):\n"
188  << "cs.space_dimension() == " << cs.space_dimension()
189  << " exceeds this->space_dimension() == " << this->space_dimension()
190  << ".";
191  throw std::invalid_argument(s.str());
192  }
193  if (cs.has_strict_inequalities()) {
194  throw std::invalid_argument("PPL::MIP_Problem::add_constraints(cs):\n"
195  "cs contains strict inequalities.");
196  }
198  i = cs.begin(), i_end = cs.end(); i != i_end; ++i) {
200  }
201  if (status != UNSATISFIABLE) {
203  }
204  PPL_ASSERT(OK());
205 }
bool OK() const
Checks if all the invariants are satisfied.
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
Status status
The internal state of the MIP problem.
void add_constraint_helper(const Constraint &c)
Helper method: implements exception safe addition.
Constraint_System_const_iterator const_iterator
dimension_type space_dimension() const
Returns the space dimension of the MIP problem.
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
mThe number of dimensions to add.
Exceptions
std::length_errorThrown 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 374 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::max_space_dimension().

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

374  {
375  // The space dimension of the resulting MIP problem should not
376  // overflow the maximum allowed space dimension.
377  if (m > max_space_dimension() - space_dimension()) {
378  throw std::length_error("PPL::MIP_Problem::"
379  "add_space_dimensions_and_embed(m):\n"
380  "adding m new space dimensions exceeds "
381  "the maximum allowed space dimension.");
382  }
383  external_space_dim += m;
384  if (status != UNSATISFIABLE) {
386  }
387  PPL_ASSERT(OK());
388 }
bool OK() const
Checks if all the invariants are satisfied.
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
Status status
The internal state of the MIP problem.
dimension_type external_space_dim
The dimension of the vector space.
static dimension_type max_space_dimension()
Returns the maximum space dimension an MIP_Problem can handle.
dimension_type space_dimension() const
Returns the space dimension of the MIP problem.
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_argumentThrown if some index in i_vars does not correspond to a space dimension in *this.

Definition at line 392 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Variables_Set::space_dimension().

392  {
393  if (i_vars.space_dimension() > external_space_dim) {
394  throw std::invalid_argument("PPL::MIP_Problem::"
395  "add_to_integer_space_dimension(i_vars):\n"
396  "*this and i_vars are dimension"
397  "incompatible.");
398  }
399  const dimension_type original_size = i_variables.size();
400  i_variables.insert(i_vars.begin(), i_vars.end());
401  // If a new integral variable was inserted, set the internal status to
402  // PARTIALLY_SATISFIABLE.
403  if (i_variables.size() != original_size && status != UNSATISFIABLE) {
405  }
406 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
Variables_Set i_variables
A set containing all the indexes of variables that are constrained to have an integer value...
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
Status status
The internal state of the MIP problem.
void insert(Variable v)
Inserts the index of variable v into the set.
dimension_type external_space_dim
The dimension of the vector space.
void Parma_Polyhedra_Library::MIP_Problem::ascii_dump ( ) const

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

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

Writes to s an ASCII representation of *this.

Definition at line 2545 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::MAXIMIZATION.

2545  {
2546  using namespace IO_Operators;
2547  s << "\nexternal_space_dim: " << external_space_dim << " \n";
2548  s << "\ninternal_space_dim: " << internal_space_dim << " \n";
2549 
2550  const dimension_type input_cs_size = input_cs.size();
2551 
2552  s << "\ninput_cs( " << input_cs_size << " )\n";
2553  for (dimension_type i = 0; i < input_cs_size; ++i) {
2554  input_cs[i]->ascii_dump(s);
2555  }
2556 
2557  s << "\ninherited_constraints: " << inherited_constraints
2558  << std::endl;
2559 
2560  s << "\nfirst_pending_constraint: " << first_pending_constraint
2561  << std::endl;
2562 
2563  s << "\ninput_obj_function\n";
2565  s << "\nopt_mode "
2566  << ((opt_mode == MAXIMIZATION) ? "MAXIMIZATION" : "MINIMIZATION") << "\n";
2567 
2568  s << "\ninitialized: " << (initialized ? "YES" : "NO") << "\n";
2569  s << "\npricing: ";
2570  switch (pricing) {
2572  s << "PRICING_STEEPEST_EDGE_FLOAT";
2573  break;
2575  s << "PRICING_STEEPEST_EDGE_EXACT";
2576  break;
2577  case PRICING_TEXTBOOK:
2578  s << "PRICING_TEXTBOOK";
2579  break;
2580  }
2581  s << "\n";
2582 
2583  s << "\nstatus: ";
2584  switch (status) {
2585  case UNSATISFIABLE:
2586  s << "UNSATISFIABLE";
2587  break;
2588  case SATISFIABLE:
2589  s << "SATISFIABLE";
2590  break;
2591  case UNBOUNDED:
2592  s << "UNBOUNDED";
2593  break;
2594  case OPTIMIZED:
2595  s << "OPTIMIZED";
2596  break;
2597  case PARTIALLY_SATISFIABLE:
2598  s << "PARTIALLY_SATISFIABLE";
2599  break;
2600  }
2601  s << "\n";
2602 
2603  s << "\ntableau\n";
2604  tableau.ascii_dump(s);
2605  s << "\nworking_cost( " << working_cost.size()<< " )\n";
2607 
2608  const dimension_type base_size = base.size();
2609  s << "\nbase( " << base_size << " )\n";
2610  for (dimension_type i = 0; i != base_size; ++i) {
2611  s << base[i] << ' ';
2612  }
2613 
2614  s << "\nlast_generator\n";
2616 
2617  const dimension_type mapping_size = mapping.size();
2618  s << "\nmapping( " << mapping_size << " )\n";
2619  for (dimension_type i = 1; i < mapping_size; ++i) {
2620  s << "\n"<< i << " -> " << mapping[i].first << " -> " << mapping[i].second
2621  << ' ';
2622  }
2623 
2624  s << "\n\ninteger_variables";
2626 }
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
Optimization_Mode opt_mode
The optimization mode requested.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
size_t dimension_type
An unsigned integral type for representing space dimensions.
Linear_Expression input_obj_function
The objective function to be optimized.
dimension_type size() const
Returns the size of the row.
working_cost_type working_cost
The working cost function.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< dimension_type > base
The current basic solution.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Variables_Set i_variables
A set containing all the indexes of variables that are constrained to have an integer value...
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
The MIP problem is optimized; an optimal solution has been computed.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
bool initialized
A Boolean encoding whether or not internal data structures have already been properly sized and popul...
Status status
The internal state of the MIP problem.
dimension_type inherited_constraints
The number of constraints that are inherited from our parent in the recursion tree built when solving...
Maximization is requested.
Generator last_generator
The last successfully computed feasible or optimizing point.
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than exte...
The MIP problem is unbounded; a feasible solution has been computed.
Steepest edge pricing method, using floating points (default).
Control_Parameter_Value pricing
The pricing method in use.
Steepest edge pricing method, using Coefficient.
dimension_type external_space_dim
The dimension of the vector space.
dimension_type first_pending_constraint
The first index of `input_cs' containing a pending constraint.
The MIP problem is satisfiable; a feasible solution has been computed.
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 2631 of file MIP_Problem.cc.

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

2631  {
2632  std::string str;
2633  if (!(s >> str) || str != "external_space_dim:") {
2634  return false;
2635  }
2636 
2637  if (!(s >> external_space_dim)) {
2638  return false;
2639  }
2640 
2641  if (!(s >> str) || str != "internal_space_dim:") {
2642  return false;
2643  }
2644 
2645  if (!(s >> internal_space_dim)) {
2646  return false;
2647  }
2648 
2649  if (!(s >> str) || str != "input_cs(") {
2650  return false;
2651  }
2652 
2653  dimension_type input_cs_size;
2654 
2655  if (!(s >> input_cs_size)) {
2656  return false;
2657  }
2658 
2659  if (!(s >> str) || str != ")") {
2660  return false;
2661  }
2662 
2663  Constraint c(Constraint::zero_dim_positivity());
2664  input_cs.reserve(input_cs_size);
2665  for (dimension_type i = 0; i < input_cs_size; ++i) {
2666  if (!c.ascii_load(s)) {
2667  return false;
2668  }
2670  }
2671 
2672  if (!(s >> str) || str != "inherited_constraints:") {
2673  return false;
2674  }
2675 
2676  if (!(s >> inherited_constraints)) {
2677  return false;
2678  }
2679  // NOTE: we loaded the number of inherited constraints, but we nonetheless
2680  // reset to zero the corresponding data member, since we do not support
2681  // constraint inheritance via ascii_load.
2683 
2684  if (!(s >> str) || str != "first_pending_constraint:") {
2685  return false;
2686  }
2687  if (!(s >> first_pending_constraint)) {
2688  return false;
2689  }
2690  if (!(s >> str) || str != "input_obj_function") {
2691  return false;
2692  }
2693  if (!input_obj_function.ascii_load(s)) {
2694  return false;
2695  }
2696  if (!(s >> str) || str != "opt_mode") {
2697  return false;
2698  }
2699  if (!(s >> str)) {
2700  return false;
2701  }
2702  if (str == "MAXIMIZATION") {
2704  }
2705  else {
2706  if (str != "MINIMIZATION") {
2707  return false;
2708  }
2710  }
2711 
2712  if (!(s >> str) || str != "initialized:") {
2713  return false;
2714  }
2715  if (!(s >> str)) {
2716  return false;
2717  }
2718  if (str == "YES") {
2719  initialized = true;
2720  }
2721  else if (str == "NO") {
2722  initialized = false;
2723  }
2724  else {
2725  return false;
2726  }
2727 
2728  if (!(s >> str) || str != "pricing:") {
2729  return false;
2730  }
2731  if (!(s >> str)) {
2732  return false;
2733  }
2734  if (str == "PRICING_STEEPEST_EDGE_FLOAT") {
2736  }
2737  else if (str == "PRICING_STEEPEST_EDGE_EXACT") {
2739  }
2740  else if (str == "PRICING_TEXTBOOK") {
2742  }
2743  else {
2744  return false;
2745  }
2746 
2747  if (!(s >> str) || str != "status:") {
2748  return false;
2749  }
2750 
2751  if (!(s >> str)) {
2752  return false;
2753  }
2754 
2755  if (str == "UNSATISFIABLE") {
2757  }
2758  else if (str == "SATISFIABLE") {
2759  status = SATISFIABLE;
2760  }
2761  else if (str == "UNBOUNDED") {
2762  status = UNBOUNDED;
2763  }
2764  else if (str == "OPTIMIZED") {
2765  status = OPTIMIZED;
2766  }
2767  else if (str == "PARTIALLY_SATISFIABLE") {
2769  }
2770  else {
2771  return false;
2772  }
2773 
2774  if (!(s >> str) || str != "tableau") {
2775  return false;
2776  }
2777 
2778  if (!tableau.ascii_load(s)) {
2779  return false;
2780  }
2781 
2782  if (!(s >> str) || str != "working_cost(") {
2783  return false;
2784  }
2785 
2786  dimension_type working_cost_dim;
2787 
2788  if (!(s >> working_cost_dim)) {
2789  return false;
2790  }
2791 
2792  if (!(s >> str) || str != ")") {
2793  return false;
2794  }
2795 
2796  if (!working_cost.ascii_load(s)) {
2797  return false;
2798  }
2799 
2800  if (!(s >> str) || str != "base(") {
2801  return false;
2802  }
2803 
2804  dimension_type base_size;
2805  if (!(s >> base_size)) {
2806  return false;
2807  }
2808 
2809  if (!(s >> str) || str != ")") {
2810  return false;
2811  }
2812 
2813  for (dimension_type i = 0; i != base_size; ++i) {
2814  dimension_type base_value;
2815  if (!(s >> base_value)) {
2816  return false;
2817  }
2818  base.push_back(base_value);
2819  }
2820 
2821  if (!(s >> str) || str != "last_generator") {
2822  return false;
2823  }
2824 
2825  if (!last_generator.ascii_load(s)) {
2826  return false;
2827  }
2828 
2829  if (!(s >> str) || str != "mapping(") {
2830  return false;
2831  }
2832 
2833  dimension_type mapping_size;
2834  if (!(s >> mapping_size)) {
2835  return false;
2836  }
2837  if (!(s >> str) || str != ")") {
2838  return false;
2839  }
2840 
2841  // The first `mapping' index is never used, so we initialize
2842  // it pushing back a dummy value.
2843  if (tableau.num_columns() != 0) {
2844  mapping.push_back(std::make_pair(0, 0));
2845  }
2846 
2847  for (dimension_type i = 1; i < mapping_size; ++i) {
2848  dimension_type index;
2849  if (!(s >> index)) {
2850  return false;
2851  }
2852 
2853  if (!(s >> str) || str != "->") {
2854  return false;
2855  }
2856 
2857  dimension_type first_value;
2858  if (!(s >> first_value)) {
2859  return false;
2860  }
2861 
2862  if (!(s >> str) || str != "->") {
2863  return false;
2864  }
2865 
2866  dimension_type second_value;
2867  if (!(s >> second_value)) {
2868  return false;
2869  }
2870 
2871  mapping.push_back(std::make_pair(first_value, second_value));
2872  }
2873 
2874  if (!(s >> str) || str != "integer_variables") {
2875  return false;
2876  }
2877 
2878  if (!i_variables.ascii_load(s)) {
2879  return false;
2880  }
2881 
2882  PPL_ASSERT(OK());
2883  return true;
2884 }
Minimization is requested.
void set_optimization_mode(Optimization_Mode mode)
Sets the optimization mode to mode.
size_t dimension_type
An unsigned integral type for representing space dimensions.
Linear_Expression input_obj_function
The objective function to be optimized.
bool ascii_load(std::istream &s)
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this ...
bool ascii_load(std::istream &s)
Loads the row from an ASCII representation generated using ascii_dump().
Definition: Sparse_Row.cc:701
working_cost_type working_cost
The working cost function.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< dimension_type > base
The current basic solution.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
bool ascii_load(std::istream &s)
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this ...
Variables_Set i_variables
A set containing all the indexes of variables that are constrained to have an integer value...
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
bool OK() const
Checks if all the invariants are satisfied.
The MIP problem is optimized; an optimal solution has been computed.
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
bool ascii_load(std::istream &s)
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this ...
bool initialized
A Boolean encoding whether or not internal data structures have already been properly sized and popul...
Status status
The internal state of the MIP problem.
dimension_type inherited_constraints
The number of constraints that are inherited from our parent in the recursion tree built when solving...
void add_constraint_helper(const Constraint &c)
Helper method: implements exception safe addition.
Maximization is requested.
static const Constraint & zero_dim_positivity()
The true (zero-dimension space) constraint , also known as positivity constraint. ...
Generator last_generator
The last successfully computed feasible or optimizing point.
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than exte...
The MIP problem is unbounded; a feasible solution has been computed.
Steepest edge pricing method, using floating points (default).
Control_Parameter_Value pricing
The pricing method in use.
Coefficient c
Definition: PIP_Tree.cc:64
Steepest edge pricing method, using Coefficient.
dimension_type external_space_dim
The dimension of the vector space.
dimension_type first_pending_constraint
The first index of `input_cs' containing a pending constraint.
The MIP problem is satisfiable; a feasible solution has been computed.
bool Parma_Polyhedra_Library::MIP_Problem::choose_branching_variable ( const MIP_Problem mip,
const Variables_Set i_vars,
dimension_type branching_index 
)
staticprivate

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

Parameters
mipThe MIP problem. This is assumed to have no integral space dimension (so that it is a pure LP problem).
i_varsThe variables that are constrained to take an integer value.
branching_indexIf false is returned, this will encode the non-integral variable index on which the `branch and bound' algorithm should be applied.

Definition at line 2137 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(), last_generator, PPL_DIRTY_TEMP_COEFFICIENT, and Parma_Polyhedra_Library::Variables_Set::space_dimension().

2139  {
2140  // Insert here the variables that do not satisfy the integrality
2141  // condition.
2142  const std::vector<Constraint*>& input_cs = mip.input_cs;
2143  const Generator& last_generator = mip.last_generator;
2144  Coefficient_traits::const_reference last_generator_divisor
2145  = last_generator.divisor();
2146  Variables_Set candidate_variables;
2147 
2148  // TODO: This can be optimized more, exploiting the (possible)
2149  // sparseness of last_generator, if the size of i_vars is expected to be
2150  // greater than the number of nonzeroes in last_generator in most cases.
2152  for (Variables_Set::const_iterator v_it = i_vars.begin(),
2153  v_end = i_vars.end(); v_it != v_end; ++v_it) {
2154  gcd_assign(gcd,
2155  last_generator.coefficient(Variable(*v_it)),
2156  last_generator_divisor);
2157  if (gcd != last_generator_divisor) {
2158  candidate_variables.insert(*v_it);
2159  }
2160  }
2161  // If this set is empty, we have finished.
2162  if (candidate_variables.empty()) {
2163  return true;
2164  }
2165 
2166  // Check how many `active constraints' we have and track them.
2167  const dimension_type input_cs_num_rows = input_cs.size();
2168  std::deque<bool> satisfiable_constraints(input_cs_num_rows, false);
2169  for (dimension_type i = input_cs_num_rows; i-- > 0; ) {
2170  // An equality is an `active constraint' by definition.
2171  // If we have an inequality, check if it is an `active constraint'.
2172  if (input_cs[i]->is_equality()
2173  || is_saturated(*(input_cs[i]), last_generator)) {
2174  satisfiable_constraints[i] = true;
2175  }
2176  }
2177 
2178  dimension_type winning_num_appearances = 0;
2179 
2180  std::vector<dimension_type>
2181  num_appearances(candidate_variables.space_dimension(), 0);
2182 
2183  // For every candidate variable, check how many times this appear in the
2184  // active constraints.
2185  for (dimension_type i = input_cs_num_rows; i-- > 0; ) {
2186  if (!satisfiable_constraints[i]) {
2187  continue;
2188  }
2189  // TODO: This can be optimized more, exploiting the (possible)
2190  // sparseness of input_cs, if the size of candidate_variables is expected
2191  // to be greater than the number of nonzeroes of most rows.
2192  for (Variables_Set::const_iterator v_it = candidate_variables.begin(),
2193  v_end = candidate_variables.end(); v_it != v_end; ++v_it) {
2194  if (*v_it >= input_cs[i]->space_dimension()) {
2195  break;
2196  }
2197  if (input_cs[i]->coefficient(Variable(*v_it)) != 0) {
2198  ++num_appearances[*v_it];
2199  }
2200  }
2201  }
2202  for (Variables_Set::const_iterator v_it = candidate_variables.begin(),
2203  v_end = candidate_variables.end(); v_it != v_end; ++v_it) {
2204  const dimension_type n = num_appearances[*v_it];
2205  if (n >= winning_num_appearances) {
2206  winning_num_appearances = n;
2207  branching_index = *v_it;
2208  }
2209  }
2210  return false;
2211 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
static bool is_saturated(const Constraint &c, const Generator &g)
Returns true if and only if c is saturated by g.
Definition: MIP_Problem.cc:478
Generator last_generator
The last successfully computed feasible or optimizing point.
void gcd_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
Coefficient_traits::const_reference divisor() const
If *this is either a point or a closure point, returns its divisor.
dimension_type space_dimension() const
Returns the space dimension of the MIP problem.
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 205 of file MIP_Problem_inlines.hh.

References m_swap().

205  {
206  MIP_Problem tmp;
207  m_swap(tmp);
208 }
void m_swap(MIP_Problem &y)
Swaps *this with y.
MIP_Problem(dimension_type dim=0)
Builds a trivial MIP problem.
Definition: MIP_Problem.cc:78
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 1760 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::add_mul_assign(), Parma_Polyhedra_Library::exact_div_assign(), Parma_Polyhedra_Library::Sparse_Row::get(), last_generator, Parma_Polyhedra_Library::lcm_assign(), Parma_Polyhedra_Library::neg_assign(), PPL_DIRTY_TEMP_COEFFICIENT, and Parma_Polyhedra_Library::sub_mul_assign().

1760  {
1761  // Early exit for 0-dimensional problems.
1762  if (external_space_dim == 0) {
1763  MIP_Problem& x = const_cast<MIP_Problem&>(*this);
1764  x.last_generator = point();
1765  return;
1766  }
1767 
1768  // We will store in numer[] and in denom[] the numerators and
1769  // the denominators of every variable of the original problem.
1770  std::vector<Coefficient> numer(external_space_dim);
1771  std::vector<Coefficient> denom(external_space_dim);
1772  dimension_type row = 0;
1773 
1775  // Speculatively allocate temporaries out of loop.
1776  PPL_DIRTY_TEMP_COEFFICIENT(split_numer);
1777  PPL_DIRTY_TEMP_COEFFICIENT(split_denom);
1778 
1779  // We start to compute numer[] and denom[].
1780  for (dimension_type i = external_space_dim; i-- > 0; ) {
1781  Coefficient& numer_i = numer[i];
1782  Coefficient& denom_i = denom[i];
1783  // Get the value of the variable from the tableau
1784  // (if it is not a basic variable, the value is 0).
1785  const dimension_type original_var = mapping[i+1].first;
1786  if (is_in_base(original_var, row)) {
1787  const Row& t_row = tableau[row];
1788  Coefficient_traits::const_reference t_row_original_var
1789  = t_row.get(original_var);
1790  if (t_row_original_var > 0) {
1791  neg_assign(numer_i, t_row.get(0));
1792  denom_i = t_row_original_var;
1793  }
1794  else {
1795  numer_i = t_row.get(0);
1796  neg_assign(denom_i, t_row_original_var);
1797  }
1798  }
1799  else {
1800  numer_i = 0;
1801  denom_i = 1;
1802  }
1803  // Check whether the variable was split.
1804  const dimension_type split_var = mapping[i+1].second;
1805  if (split_var != 0) {
1806  // The variable was split: get the value for the negative component,
1807  // having index mapping[i+1].second .
1808  // Like before, we he have to check if the variable is in base.
1809  if (is_in_base(split_var, row)) {
1810  const Row& t_row = tableau[row];
1811  Coefficient_traits::const_reference t_row_split_var
1812  = t_row.get(split_var);
1813  if (t_row_split_var > 0) {
1814  neg_assign(split_numer, t_row.get(0));
1815  split_denom = t_row_split_var;
1816  }
1817  else {
1818  split_numer = t_row.get(0);
1819  neg_assign(split_denom, t_row_split_var);
1820  }
1821  // We compute the lcm to compute subsequently the difference
1822  // between the 2 variables.
1823  lcm_assign(lcm, denom_i, split_denom);
1824  exact_div_assign(denom_i, lcm, denom_i);
1825  exact_div_assign(split_denom, lcm, split_denom);
1826  numer_i *= denom_i;
1827  sub_mul_assign(numer_i, split_numer, split_denom);
1828  if (numer_i == 0) {
1829  denom_i = 1;
1830  }
1831  else {
1832  denom_i = lcm;
1833  }
1834  }
1835  // Note: if the negative component was not in base, then
1836  // it has value zero and there is nothing left to do.
1837  }
1838  }
1839 
1840  // Compute the lcm of all denominators.
1841  PPL_ASSERT(external_space_dim > 0);
1842  lcm = denom[0];
1843  for (dimension_type i = 1; i < external_space_dim; ++i) {
1844  lcm_assign(lcm, lcm, denom[i]);
1845  }
1846  // Use the denominators to store the numerators' multipliers
1847  // and then compute the normalized numerators.
1848  for (dimension_type i = external_space_dim; i-- > 0; ) {
1849  exact_div_assign(denom[i], lcm, denom[i]);
1850  numer[i] *= denom[i];
1851  }
1852 
1853  // Finally, build the generator.
1854  Linear_Expression expr;
1855  for (dimension_type i = external_space_dim; i-- > 0; ) {
1856  add_mul_assign(expr, numer[i], Variable(i));
1857  }
1858 
1859  MIP_Problem& x = const_cast<MIP_Problem&>(*this);
1860  x.last_generator = point(expr, lcm);
1861 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
bool is_in_base(dimension_type var_index, dimension_type &row_index) const
Definition: MIP_Problem.cc:409
void add_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
void lcm_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
void exact_div_assign(Checked_Number< T, Policy > &x, const Checked_Number< T, Policy > &y, const Checked_Number< T, Policy > &z)
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
PPL_COEFFICIENT_TYPE Coefficient
An alias for easily naming the type of PPL coefficients.
void neg_assign(GMP_Integer &x)
void sub_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
dimension_type external_space_dim
The dimension of the vector space.
MIP_Problem(dimension_type dim=0)
Builds a trivial MIP problem.
Definition: MIP_Problem.cc:78
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 1629 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::maybe_abandon().

1629  {
1630  PPL_ASSERT(tableau.num_columns() == working_cost.size());
1633 
1634  const dimension_type tableau_num_rows = tableau.num_rows();
1635  const bool textbook_pricing
1637 
1638  while (true) {
1639  // Choose the index of the variable entering the base, if any.
1640  const dimension_type entering_var_index
1641  = textbook_pricing
1644  // If no entering index was computed, the problem is solved.
1645  if (entering_var_index == 0) {
1646  return true;
1647  }
1648 
1649  // Choose the index of the row exiting the base.
1650  const dimension_type exiting_base_index
1651  = get_exiting_base_index(entering_var_index);
1652  // If no exiting index was computed, the problem is unbounded.
1653  if (exiting_base_index == tableau_num_rows) {
1654  return false;
1655  }
1656 
1657  // Check if the client has requested abandoning all expensive
1658  // computations. If so, the exception specified by the client
1659  // is thrown now.
1660  maybe_abandon();
1661 
1662  // We have not reached the optimality or unbounded condition:
1663  // compute the new base and the corresponding vertex of the
1664  // feasible region.
1665  pivot(entering_var_index, exiting_base_index);
1666 #if PPL_NOISY_SIMPLEX
1667  ++num_iterations;
1668  if (num_iterations % 200 == 0) {
1669  std::cout << "Primal simplex: iteration " << num_iterations
1670  << "." << std::endl;
1671  }
1672 #endif // PPL_NOISY_SIMPLEX
1673  }
1674 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type size() const
Returns the size of the row.
working_cost_type working_cost
The working cost function.
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-cyc...
Control_Parameter_Value get_control_parameter(Control_Parameter_Name name) const
Returns the value of the control parameter name.
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
void pivot(dimension_type entering_var_index, dimension_type exiting_base_index)
Performs the pivoting operation on the tableau.
dimension_type steepest_edge_exact_entering_index() const
Computes the column index of the variable entering the base, using an exact steepest-edge algorithm w...
dimension_type textbook_entering_index() const
Computes the column index of the variable entering the base, using the textbook algorithm with anti-c...
Steepest edge pricing method, using Coefficient.
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 1531 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::abs_assign(), Parma_Polyhedra_Library::maybe_abandon(), Parma_Polyhedra_Library::neg_assign(), PPL_DIRTY_TEMP_COEFFICIENT, WEIGHT_ADD, and WEIGHT_BEGIN.

1531  {
1532  // We may need to temporarily switch to the textbook pricing.
1533  const unsigned long allowed_non_increasing_loops = 200;
1534  unsigned long non_increased_times = 0;
1535  bool textbook_pricing = false;
1536 
1537  PPL_DIRTY_TEMP_COEFFICIENT(cost_sgn_coeff);
1538  PPL_DIRTY_TEMP_COEFFICIENT(current_numer);
1539  PPL_DIRTY_TEMP_COEFFICIENT(current_denom);
1540  PPL_DIRTY_TEMP_COEFFICIENT(challenger);
1541  PPL_DIRTY_TEMP_COEFFICIENT(current);
1542 
1543  cost_sgn_coeff = working_cost.get(working_cost.size() - 1);
1544  current_numer = working_cost.get(0);
1545  if (cost_sgn_coeff < 0) {
1546  neg_assign(current_numer);
1547  }
1548  abs_assign(current_denom, cost_sgn_coeff);
1549  PPL_ASSERT(tableau.num_columns() == working_cost.size());
1550  const dimension_type tableau_num_rows = tableau.num_rows();
1551 
1552  while (true) {
1553  // Choose the index of the variable entering the base, if any.
1554  const dimension_type entering_var_index
1555  = textbook_pricing
1558 
1559  // If no entering index was computed, the problem is solved.
1560  if (entering_var_index == 0) {
1561  return true;
1562  }
1563 
1564  // Choose the index of the row exiting the base.
1565  const dimension_type exiting_base_index
1566  = get_exiting_base_index(entering_var_index);
1567  // If no exiting index was computed, the problem is unbounded.
1568  if (exiting_base_index == tableau_num_rows) {
1569  return false;
1570  }
1571 
1572  // Check if the client has requested abandoning all expensive
1573  // computations. If so, the exception specified by the client
1574  // is thrown now.
1575  maybe_abandon();
1576 
1577  // We have not reached the optimality or unbounded condition:
1578  // compute the new base and the corresponding vertex of the
1579  // feasible region.
1580  pivot(entering_var_index, exiting_base_index);
1581 
1582  WEIGHT_BEGIN();
1583  // Now begins the objective function's value check to choose between
1584  // the `textbook' and the float `steepest-edge' technique.
1585  cost_sgn_coeff = working_cost.get(working_cost.size() - 1);
1586 
1587  challenger = working_cost.get(0);
1588  if (cost_sgn_coeff < 0) {
1589  neg_assign(challenger);
1590  }
1591  challenger *= current_denom;
1592  abs_assign(current, cost_sgn_coeff);
1593  current *= current_numer;
1594 #if PPL_NOISY_SIMPLEX
1595  ++num_iterations;
1596  if (num_iterations % 200 == 0) {
1597  std::cout << "Primal simplex: iteration " << num_iterations
1598  << "." << std::endl;
1599  }
1600 #endif // PPL_NOISY_SIMPLEX
1601  // If the following condition fails, probably there's a bug.
1602  PPL_ASSERT(challenger >= current);
1603  // If the value of the objective function does not improve,
1604  // keep track of that.
1605  if (challenger == current) {
1606  ++non_increased_times;
1607  // In the following case we will proceed using the `textbook'
1608  // technique, until the objective function is not improved.
1609  if (non_increased_times > allowed_non_increasing_loops) {
1610  textbook_pricing = true;
1611  }
1612  }
1613  // The objective function has an improvement:
1614  // reset `non_increased_times' and `textbook_pricing'.
1615  else {
1616  non_increased_times = 0;
1617  textbook_pricing = false;
1618  }
1619  current_numer = working_cost.get(0);
1620  if (cost_sgn_coeff < 0) {
1621  neg_assign(current_numer);
1622  }
1623  abs_assign(current_denom, cost_sgn_coeff);
1624  WEIGHT_ADD(433);
1625  }
1626 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type size() const
Returns the size of the row.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
void abs_assign(GMP_Integer &x)
working_cost_type working_cost
The working cost function.
#define WEIGHT_ADD(delta)
Definition: globals_defs.hh:83
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-cyc...
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
dimension_type steepest_edge_float_entering_index() const
Same as steepest_edge_exact_entering_index, but using floating points.
void pivot(dimension_type entering_var_index, dimension_type exiting_base_index)
Performs the pivoting operation on the tableau.
#define WEIGHT_BEGIN()
Definition: globals_defs.hh:81
void neg_assign(GMP_Integer &x)
dimension_type textbook_entering_index() const
Computes the column index of the variable entering the base, using the textbook algorithm with anti-c...
Coefficient_traits::const_reference get(dimension_type i) const
Gets the i-th element in the sequence.
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 150 of file MIP_Problem_inlines.hh.

References input_cs.

Referenced by operator<<().

150  {
151  return const_iterator(input_cs.begin());
152 }
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
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 155 of file MIP_Problem_inlines.hh.

References input_cs.

Referenced by operator<<().

155  {
156  return const_iterator(input_cs.end());
157 }
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
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_artificialsThe start of the tableau column index range for artificial variables.
end_artificialsThe end of the tableau column index range for artificial variables. Note that column index end_artificial is excluded from the range.

Definition at line 1679 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Sparse_Row::begin(), Parma_Polyhedra_Library::Sparse_Row::end(), Parma_Polyhedra_Library::CO_Tree::const_iterator::index(), and Parma_Polyhedra_Library::Sparse_Row::m_swap().

1680  {
1681  PPL_ASSERT(0 < begin_artificials && begin_artificials < end_artificials);
1682 
1683  const dimension_type old_last_column = tableau.num_columns() - 1;
1684  dimension_type tableau_n_rows = tableau.num_rows();
1685  // Step 1: try to remove from the base all the remaining slack variables.
1686  for (dimension_type i = 0; i < tableau_n_rows; ++i) {
1687  if (begin_artificials <= base[i] && base[i] < end_artificials) {
1688  // Search for a non-zero element to enter the base.
1689  Row& tableau_i = tableau[i];
1690  bool redundant = true;
1691  Row::const_iterator j = tableau_i.begin();
1692  Row::const_iterator j_end = tableau_i.end();
1693  // Skip the first element
1694  if (j != j_end && j.index() == 0) {
1695  ++j;
1696  }
1697  for ( ; (j != j_end) && (j.index() < begin_artificials); ++j) {
1698  if (*j != 0) {
1699  pivot(j.index(), i);
1700  redundant = false;
1701  break;
1702  }
1703  }
1704  if (redundant) {
1705  // No original variable entered the base:
1706  // the constraint is redundant and should be deleted.
1707  --tableau_n_rows;
1708  if (i < tableau_n_rows) {
1709  // Replace the redundant row with the last one,
1710  // taking care of adjusting the iteration index.
1711  tableau_i.m_swap(tableau[tableau_n_rows]);
1712  base[i] = base[tableau_n_rows];
1713  --i;
1714  }
1715  tableau.remove_trailing_rows(1);
1716  base.pop_back();
1717  }
1718  }
1719  }
1720  // Step 2: Adjust data structures so as to enter phase 2 of the simplex.
1721 
1722  // Resize the tableau.
1723  const dimension_type num_artificials = end_artificials - begin_artificials;
1724  tableau.remove_trailing_columns(num_artificials);
1725 
1726  // Zero the last column of the tableau.
1727  const dimension_type new_last_column = tableau.num_columns() - 1;
1728  for (dimension_type i = tableau_n_rows; i-- > 0; ) {
1729  tableau[i].reset(new_last_column);
1730  }
1731 
1732  // ... then properly set the element in the (new) last column,
1733  // encoding the kind of optimization; ...
1734  {
1735  // This block is equivalent to
1736  //
1737  // <CODE>
1738  // working_cost[new_last_column] = working_cost.get(old_last_column);
1739  // </CODE>
1740  //
1741  // but it avoids storing zeroes.
1742  Coefficient_traits::const_reference old_cost
1743  = working_cost.get(old_last_column);
1744  if (old_cost == 0) {
1745  working_cost.reset(new_last_column);
1746  }
1747  else {
1748  working_cost.insert(new_last_column, old_cost);
1749  }
1750  }
1751 
1752  // ... and finally remove redundant columns.
1753  const dimension_type working_cost_new_size
1754  = working_cost.size() - num_artificials;
1755  working_cost.shrink(working_cost_new_size);
1756 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type size() const
Returns the size of the row.
iterator reset(iterator i)
Resets to zero the value pointed to by i.
working_cost_type working_cost
The working cost function.
std::vector< dimension_type > base
The current basic solution.
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
void pivot(dimension_type entering_var_index, dimension_type exiting_base_index)
Performs the pivoting operation on the tableau.
void shrink(dimension_type n)
Resizes the row to size n.
iterator insert(dimension_type i, Coefficient_traits::const_reference x)
Equivalent to (*this)[i] = x; find(i), but faster.
CO_Tree::const_iterator const_iterator
A const iterator on the row elements.
Coefficient_traits::const_reference get(dimension_type i) const
Gets the i-th element in the sequence.
void Parma_Polyhedra_Library::MIP_Problem::evaluate_objective_function ( const Generator evaluating_point,
Coefficient numer,
Coefficient denom 
) const

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

Parameters
evaluating_pointThe point on which the objective function will be evaluated.
numerOn exit will contain the numerator of the evaluated value.
denomOn exit will contain the denominator of the evaluated value.
Exceptions
std::invalid_argumentThrown if *this and evaluating_point are dimension-incompatible or if the generator evaluating_point is not a point.

Definition at line 1942 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Generator::divisor(), Parma_Polyhedra_Library::Generator::expr, Parma_Polyhedra_Library::Generator::is_point(), Parma_Polyhedra_Library::normalize2(), 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::BD_Shape< T >::max_min(), Parma_Polyhedra_Library::Octagonal_Shape< T >::max_min(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), optimal_value(), and solve_mip().

1944  {
1945  const dimension_type ep_space_dim = evaluating_point.space_dimension();
1946  if (space_dimension() < ep_space_dim) {
1947  throw std::invalid_argument("PPL::MIP_Problem::"
1948  "evaluate_objective_function(p, n, d):\n"
1949  "*this and p are dimension incompatible.");
1950  }
1951  if (!evaluating_point.is_point()) {
1952  throw std::invalid_argument("PPL::MIP_Problem::"
1953  "evaluate_objective_function(p, n, d):\n"
1954  "p is not a point.");
1955  }
1956  // Compute the smallest space dimension between `input_obj_function'
1957  // and `evaluating_point'.
1958  const dimension_type working_space_dim
1959  = std::min(ep_space_dim, input_obj_function.space_dimension());
1961  evaluating_point.expr,
1962  0, working_space_dim + 1);
1963 
1964  // Numerator and denominator should be coprime.
1965  normalize2(numer, evaluating_point.divisor(), numer, denom);
1966 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
Linear_Expression input_obj_function
The objective function to be optimized.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
void normalize2(Coefficient_traits::const_reference x, Coefficient_traits::const_reference y, Coefficient &n_x, Coefficient &n_y)
If is the GCD of x and y, the values of x and y divided by are assigned to n_x and n_y...
void scalar_product_assign(Coefficient &result, const Linear_Expression &y) const
Sets results to the sum of (*this)[i]*y[i], for each i.
dimension_type space_dimension() const
Returns the space dimension of the MIP problem.
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 212 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::Sparse_Row::external_memory_in_bytes(), inherited_constraints, input_cs, input_obj_function, last_generator, mapping, Parma_Polyhedra_Library::nth_iter(), tableau, and working_cost.

Referenced by total_memory_in_bytes().

212  {
215  + tableau.external_memory_in_bytes()
218 
219  // Adding the external memory for `input_cs'.
220  // NOTE: disregard inherited constraints, as they are owned by ancestors.
221  n += input_cs.capacity() * sizeof(Constraint*);
222  for (Constraint_Sequence::const_iterator
224  i_end = input_cs.end(); i != i_end; ++i) {
225  n += ((*i)->total_memory_in_bytes());
226  }
227 
228  // Adding the external memory for `base'.
229  n += base.capacity() * sizeof(dimension_type);
230  // Adding the external memory for `mapping'.
231  n += mapping.capacity() * sizeof(std::pair<dimension_type, dimension_type>);
232  return n;
233 }
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
size_t dimension_type
An unsigned integral type for representing space dimensions.
Linear_Expression input_obj_function
The objective function to be optimized.
working_cost_type working_cost
The working cost function.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< dimension_type > base
The current basic solution.
RA_Container::iterator nth_iter(RA_Container &cont, dimension_type n)
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
dimension_type inherited_constraints
The number of constraints that are inherited from our parent in the recursion tree built when solving...
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
Generator last_generator
The last successfully computed feasible or optimizing point.
size_t memory_size_type
An unsigned integral type for representing memory size in bytes.
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
const PPL::Generator & Parma_Polyhedra_Library::MIP_Problem::feasible_point ( ) const

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

Exceptions
std::domain_errorThrown if the MIP problem is not satisfiable.

Definition at line 225 of file MIP_Problem.cc.

Referenced by Parma_Polyhedra_Library::Implementation::Termination::one_affine_ranking_function_MS(), and Parma_Polyhedra_Library::Termination_Helpers::one_affine_ranking_function_PR_original().

225  {
226  if (is_satisfiable()) {
227  return last_generator;
228  }
229  else {
230  throw std::domain_error("PPL::MIP_Problem::feasible_point():\n"
231  "*this is not satisfiable.");
232  }
233 }
bool is_satisfiable() const
Checks satisfiability of *this.
Definition: MIP_Problem.cc:247
Generator last_generator
The last successfully computed feasible or optimizing point.
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 165 of file MIP_Problem_inlines.hh.

References PPL_USED, PRICING, and pricing.

165  {
166  PPL_USED(name);
167  PPL_ASSERT(name == PRICING);
168  return pricing;
169 }
#define PPL_USED(v)
No-op macro that allows to avoid unused variable warnings from the compiler.
Definition: compiler.hh:39
Control_Parameter_Value pricing
The pricing method in use.
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_indexThe column index of the variable entering the base.

Definition at line 1472 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::abs_assign(), Parma_Polyhedra_Library::exact_div_assign(), Parma_Polyhedra_Library::Sparse_Row::get(), Parma_Polyhedra_Library::lcm_assign(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Boundary_NS::sgn(), WEIGHT_ADD, and WEIGHT_BEGIN.

1472  {
1473  // The variable exiting the base should be associated to a tableau
1474  // constraint such that the ratio
1475  // tableau[i][entering_var_index] / tableau[i][base[i]]
1476  // is strictly positive and minimal.
1477 
1478  // Find the first tableau constraint `c' having a positive value for
1479  // tableau[i][entering_var_index] / tableau[i][base[i]]
1480  const dimension_type tableau_num_rows = tableau.num_rows();
1481  dimension_type exiting_base_index = tableau_num_rows;
1482  for (dimension_type i = 0; i < tableau_num_rows; ++i) {
1483  const Row& t_i = tableau[i];
1484  const int num_sign = sgn(t_i.get(entering_var_index));
1485  if (num_sign != 0 && num_sign == sgn(t_i.get(base[i]))) {
1486  exiting_base_index = i;
1487  break;
1488  }
1489  }
1490  // Check for unboundedness.
1491  if (exiting_base_index == tableau_num_rows) {
1492  return tableau_num_rows;
1493  }
1494 
1495  // Reaching this point means that a variable will definitely exit the base.
1497  PPL_DIRTY_TEMP_COEFFICIENT(current_min);
1498  PPL_DIRTY_TEMP_COEFFICIENT(challenger);
1499  Coefficient t_e0 = tableau[exiting_base_index].get(0);
1500  Coefficient t_ee = tableau[exiting_base_index].get(entering_var_index);
1501  for (dimension_type i = exiting_base_index + 1; i < tableau_num_rows; ++i) {
1502  const Row& t_i = tableau[i];
1503  Coefficient_traits::const_reference t_ie = t_i.get(entering_var_index);
1504  const int t_ie_sign = sgn(t_ie);
1505  if (t_ie_sign != 0 && t_ie_sign == sgn(t_i.get(base[i]))) {
1506  WEIGHT_BEGIN();
1507  Coefficient_traits::const_reference t_i0 = t_i.get(0);
1508  lcm_assign(lcm, t_ee, t_ie);
1509  exact_div_assign(current_min, lcm, t_ee);
1510  current_min *= t_e0;
1511  abs_assign(current_min);
1512  exact_div_assign(challenger, lcm, t_ie);
1513  challenger *= t_i0;
1514  abs_assign(challenger);
1515  current_min -= challenger;
1516  const int sign = sgn(current_min);
1517  if (sign > 0
1518  || (sign == 0 && base[i] < base[exiting_base_index])) {
1519  exiting_base_index = i;
1520  t_e0 = t_i0;
1521  t_ee = t_ie;
1522  }
1523  WEIGHT_ADD(642);
1524  }
1525  }
1526  return exiting_base_index;
1527 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
void abs_assign(GMP_Integer &x)
void lcm_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
#define WEIGHT_ADD(delta)
Definition: globals_defs.hh:83
void exact_div_assign(Checked_Number< T, Policy > &x, const Checked_Number< T, Policy > &y, const Checked_Number< T, Policy > &z)
std::vector< dimension_type > base
The current basic solution.
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
PPL_COEFFICIENT_TYPE Coefficient
An alias for easily naming the type of PPL coefficients.
#define WEIGHT_BEGIN()
Definition: globals_defs.hh:81
int sgn(Boundary_Type type, const T &x, const Info &info)
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 160 of file MIP_Problem_inlines.hh.

References i_variables.

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

160  {
161  return i_variables;
162 }
Variables_Set i_variables
A set containing all the indexes of variables that are constrained to have an integer value...
bool Parma_Polyhedra_Library::MIP_Problem::is_in_base ( dimension_type  var_index,
dimension_type row_index 
) const
private

Definition at line 409 of file MIP_Problem.cc.

410  {
411  for (row_index = base.size(); row_index-- > 0; ) {
412  if (base[row_index] == var_index) {
413  return true;
414  }
415  }
416  return false;
417 }
std::vector< dimension_type > base
The current basic solution.
dimension_type row_index
Definition: PIP_Tree.cc:615
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 1969 of file MIP_Problem.cc.

References external_space_dim, first_pending_constraint, initialized, internal_space_dim, mapping, process_pending_constraints(), and tableau.

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

1969  {
1970 #if PPL_NOISY_SIMPLEX
1971  num_iterations = 0;
1972 #endif // PPL_NOISY_SIMPLEX
1973  switch (status) {
1974  case UNSATISFIABLE:
1975  return false;
1976  case SATISFIABLE:
1977  // Intentionally fall through.
1978  case UNBOUNDED:
1979  // Intentionally fall through.
1980  case OPTIMIZED:
1981  // Intentionally fall through.
1982  return true;
1983  case PARTIALLY_SATISFIABLE:
1984  {
1985  MIP_Problem& x = const_cast<MIP_Problem&>(*this);
1986  // This code tries to handle the case that happens if the tableau is
1987  // empty, so it must be initialized.
1988  if (tableau.num_columns() == 0) {
1989  // Add two columns, the first that handles the inhomogeneous term and
1990  // the second that represent the `sign'.
1991  x.tableau.add_zero_columns(2);
1992  // Sync `mapping' for the inhomogeneous term.
1993  x.mapping.push_back(std::make_pair(0, 0));
1994  // The internal data structures are ready, so prepare for more
1995  // assertion to be checked.
1996  x.initialized = true;
1997  }
1998 
1999  // Apply incrementality to the pending constraint system.
2000  x.process_pending_constraints();
2001  // Update `first_pending_constraint': no more pending.
2002  x.first_pending_constraint = input_cs.size();
2003  // Update also `internal_space_dim'.
2004  x.internal_space_dim = x.external_space_dim;
2005  PPL_ASSERT(OK());
2006  return status != UNSATISFIABLE;
2007  }
2008  }
2009  // We should not be here!
2010  PPL_UNREACHABLE;
2011  return false;
2012 }
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
bool OK() const
Checks if all the invariants are satisfied.
The MIP problem is optimized; an optimal solution has been computed.
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
Status status
The internal state of the MIP problem.
The MIP problem is unbounded; a feasible solution has been computed.
MIP_Problem(dimension_type dim=0)
Builds a trivial MIP problem.
Definition: MIP_Problem.cc:78
The MIP problem is satisfiable; a feasible solution has been computed.
bool Parma_Polyhedra_Library::MIP_Problem::is_mip_satisfiable ( MIP_Problem mip,
const Variables_Set i_vars,
Generator p 
)
staticprivate

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

Parameters
mipThe MIP problem. This is assumed to have no integral space dimension (so that it is a pure LP problem).
i_varsThe variables that are constrained to take integral values.
pIf true is returned, it will encode a feasible point.

Definition at line 2214 of file MIP_Problem.cc.

References add_constraint(), Parma_Polyhedra_Library::assign_r(), 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, PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::ROUND_DOWN, Parma_Polyhedra_Library::ROUND_NOT_NEEDED, Parma_Polyhedra_Library::ROUND_UP, and space_dimension().

2216  {
2217 #if PPL_NOISY_SIMPLEX
2218  ++mip_recursion_level;
2219  std::cout << "MIP_Problem::is_mip_satisfiable(): "
2220  << "entering recursion level " << mip_recursion_level
2221  << "." << std::endl;
2222 #endif // PPL_NOISY_SIMPLEX
2223  PPL_ASSERT(mip.integer_space_dimensions().empty());
2224 
2225  // Solve the MIP problem.
2226  if (!mip.is_lp_satisfiable()) {
2227 #if PPL_NOISY_SIMPLEX
2228  std::cout << "MIP_Problem::is_mip_satisfiable(): "
2229  << "exiting from recursion level " << mip_recursion_level
2230  << "." << std::endl;
2231  --mip_recursion_level;
2232 #endif // PPL_NOISY_SIMPLEX
2233  return false;
2234  }
2235 
2236  PPL_DIRTY_TEMP(mpq_class, tmp_rational);
2237  PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff1);
2238  PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff2);
2239  bool found_satisfiable_generator = true;
2240  dimension_type non_int_dim;
2241  p = mip.last_generator;
2242  Coefficient_traits::const_reference p_divisor = p.divisor();
2243 
2244 #if PPL_SIMPLEX_USE_MIP_HEURISTIC
2245  found_satisfiable_generator
2246  = choose_branching_variable(mip, i_vars, non_int_dim);
2247 #else
2249  // TODO: This can be optimized more, exploiting the (possible)
2250  // sparseness of p, if the size of i_vars is expected to be greater than
2251  // the number of nonzeroes in p in most cases.
2252  for (Variables_Set::const_iterator v_begin = i_vars.begin(),
2253  v_end = i_vars.end(); v_begin != v_end; ++v_begin) {
2254  gcd_assign(gcd, p.coefficient(Variable(*v_begin)), p_divisor);
2255  if (gcd != p_divisor) {
2256  non_int_dim = *v_begin;
2257  found_satisfiable_generator = false;
2258  break;
2259  }
2260  }
2261 #endif
2262 
2263  if (found_satisfiable_generator) {
2264  return true;
2265  }
2266 
2267  PPL_ASSERT(non_int_dim < mip.space_dimension());
2268 
2269  assign_r(tmp_rational.get_num(), p.coefficient(Variable(non_int_dim)),
2271  assign_r(tmp_rational.get_den(), p_divisor, ROUND_NOT_NEEDED);
2272  tmp_rational.canonicalize();
2273  assign_r(tmp_coeff1, tmp_rational, ROUND_DOWN);
2274  assign_r(tmp_coeff2, tmp_rational, ROUND_UP);
2275  {
2276  MIP_Problem mip_aux(mip, Inherit_Constraints());
2277  mip_aux.add_constraint(Variable(non_int_dim) <= tmp_coeff1);
2278 #if PPL_NOISY_SIMPLEX
2279  using namespace IO_Operators;
2280  std::cout << "MIP_Problem::is_mip_satisfiable(): "
2281  << "descending with: "
2282  << (Variable(non_int_dim) <= tmp_coeff1)
2283  << "." << std::endl;
2284 #endif // PPL_NOISY_SIMPLEX
2285  if (is_mip_satisfiable(mip_aux, i_vars, p)) {
2286 #if PPL_NOISY_SIMPLEX
2287  std::cout << "MIP_Problem::is_mip_satisfiable(): "
2288  << "exiting from recursion level " << mip_recursion_level
2289  << "." << std::endl;
2290  --mip_recursion_level;
2291 #endif // PPL_NOISY_SIMPLEX
2292  return true;
2293  }
2294  }
2295  mip.add_constraint(Variable(non_int_dim) >= tmp_coeff2);
2296 #if PPL_NOISY_SIMPLEX
2297  using namespace IO_Operators;
2298  std::cout << "MIP_Problem::is_mip_satisfiable(): "
2299  << "descending with: "
2300  << (Variable(non_int_dim) >= tmp_coeff2)
2301  << "." << std::endl;
2302 #endif // PPL_NOISY_SIMPLEX
2303  const bool satisfiable = is_mip_satisfiable(mip, i_vars, p);
2304 #if PPL_NOISY_SIMPLEX
2305  std::cout << "MIP_Problem::is_mip_satisfiable(): "
2306  << "exiting from recursion level " << mip_recursion_level
2307  << "." << std::endl;
2308  --mip_recursion_level;
2309 #endif // PPL_NOISY_SIMPLEX
2310  return satisfiable;
2311 }
Enable_If< Is_Native_Or_Checked< To >::value &&Is_Special< From >::value, Result >::type assign_r(To &to, const From &, Rounding_Dir dir)
size_t dimension_type
An unsigned integral type for representing space dimensions.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
static bool is_mip_satisfiable(MIP_Problem &mip, const Variables_Set &i_vars, Generator &p)
Returns true if and if only the MIP problem mip is satisfiable when variables in i_vars can only take...
static bool choose_branching_variable(const MIP_Problem &mip, const Variables_Set &i_vars, dimension_type &branching_index)
Returns true if and if only mip.last_generator satisfies all the integrality conditions implicitly st...
#define PPL_DIRTY_TEMP(T, id)
void gcd_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
MIP_Problem(dimension_type dim=0)
Builds a trivial MIP problem.
Definition: MIP_Problem.cc:78
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 247 of file MIP_Problem.cc.

References i_variables, Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::i_vars, is_lp_satisfiable(), last_generator, Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::lp, and status.

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::Implementation::Termination::one_affine_ranking_function_MS(), Parma_Polyhedra_Library::Termination_Helpers::one_affine_ranking_function_PR_original(), Parma_Polyhedra_Library::Implementation::Termination::termination_test_MS(), Parma_Polyhedra_Library::Implementation::Termination::termination_test_PR(), and Parma_Polyhedra_Library::Implementation::Termination::termination_test_PR_original().

247  {
248  // Check `status' to filter out trivial cases.
249  switch (status) {
250  case UNSATISFIABLE:
251  PPL_ASSERT(OK());
252  return false;
253  case SATISFIABLE:
254  // Intentionally fall through
255  case UNBOUNDED:
256  // Intentionally fall through.
257  case OPTIMIZED:
258  PPL_ASSERT(OK());
259  return true;
261  {
262  MIP_Problem& x = const_cast<MIP_Problem&>(*this);
263  // LP case.
264  if (x.i_variables.empty()) {
265  return x.is_lp_satisfiable();
266  }
267  // MIP case.
268  {
269  // Temporarily relax the MIP into an LP problem.
271  Generator p = point();
272  relaxed.lp.is_lp_satisfiable();
273 #if PPL_NOISY_SIMPLEX
274  mip_recursion_level = 0;
275 #endif // PPL_NOISY_SIMPLEX
276  if (is_mip_satisfiable(relaxed.lp, relaxed.i_vars, p)) {
277  x.last_generator = p;
278  x.status = SATISFIABLE;
279  }
280  else {
281  x.status = UNSATISFIABLE;
282  }
283  } // `relaxed' destroyed here: relaxation automatically reset.
284  return (x.status == SATISFIABLE);
285  }
286  }
287  // We should not be here!
288  PPL_UNREACHABLE;
289  return false;
290 }
bool OK() const
Checks if all the invariants are satisfied.
The MIP problem is optimized; an optimal solution has been computed.
static bool is_mip_satisfiable(MIP_Problem &mip, const Variables_Set &i_vars, Generator &p)
Returns true if and if only the MIP problem mip is satisfiable when variables in i_vars can only take...
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
Status status
The internal state of the MIP problem.
The MIP problem is unbounded; a feasible solution has been computed.
MIP_Problem(dimension_type dim=0)
Builds a trivial MIP problem.
Definition: MIP_Problem.cc:78
The MIP problem is satisfiable; a feasible solution has been computed.
bool Parma_Polyhedra_Library::MIP_Problem::is_satisfied ( const Constraint c,
const Generator g 
)
staticprivate

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

Definition at line 467 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().

467  {
468  // Scalar_Products::sign() requires the second argument to be at least
469  // as large as the first one.
470  const int sp_sign
471  = (g.space_dimension() <= c.space_dimension())
473  : Scalar_Products::sign(c, g);
474  return c.is_inequality() ? (sp_sign >= 0) : (sp_sign == 0);
475 }
static int sign(const Linear_Expression &x, const Linear_Expression &y)
Returns the sign of the scalar product between x and y.
Coefficient c
Definition: PIP_Tree.cc:64
bool Parma_Polyhedra_Library::MIP_Problem::is_saturated ( const Constraint c,
const Generator g 
)
staticprivate

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

Definition at line 478 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().

478  {
479  // Scalar_Products::sign() requires the space dimension of the second
480  // argument to be at least as large as the one of the first one.
481  const int sp_sign
482  = (g.space_dimension() <= c.space_dimension())
484  : Scalar_Products::sign(c, g);
485  return sp_sign == 0;
486 }
static int sign(const Linear_Expression &x, const Linear_Expression &y)
Returns the sign of the scalar product between x and y.
Coefficient c
Definition: PIP_Tree.cc:64
bool Parma_Polyhedra_Library::MIP_Problem::is_unbounded_obj_function ( const Linear_Expression obj_function,
const std::vector< std::pair< dimension_type, dimension_type > > &  mapping,
Optimization_Mode  optimization_mode 
)
staticprivate

Definition at line 1420 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Linear_Expression::begin(), Parma_Polyhedra_Library::Linear_Expression::end(), Parma_Polyhedra_Library::MAXIMIZATION, and Parma_Polyhedra_Library::MINIMIZATION.

1423  {
1424 
1425  for (Linear_Expression::const_iterator i = x.begin(),
1426  i_end = x.end(); i != i_end; ++i) {
1427  // If a the value of a variable in the objective function is
1428  // different from zero, the final status is unbounded.
1429  // In the first part the variable is constrained to be greater or equal
1430  // than zero.
1431  if (mapping[i.variable().space_dimension()].second != 0) {
1432  return true;
1433  }
1435  if (*i > 0) {
1436  return true;
1437  }
1438  }
1439  else {
1440  PPL_ASSERT(optimization_mode == MINIMIZATION);
1441  if (*i < 0) {
1442  return true;
1443  }
1444  }
1445  }
1446  return false;
1447 }
Minimization is requested.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Optimization_Mode optimization_mode() const
Returns the optimization mode.
Maximization is requested.
void Parma_Polyhedra_Library::MIP_Problem::linear_combine ( Row x,
const Row y,
const dimension_type  k 
)
staticprivate

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

Parameters
xThe row that will be combined with y object.
yThe row that will be combined with x object.
kThe 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 Row to x and normalizes it.

Definition at line 1360 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Sparse_Row::end(), Parma_Polyhedra_Library::Sparse_Row::find(), Parma_Polyhedra_Library::Sparse_Row::get(), Parma_Polyhedra_Library::Sparse_Row::linear_combine(), Parma_Polyhedra_Library::neg_assign(), Parma_Polyhedra_Library::Sparse_Row::normalize(), Parma_Polyhedra_Library::normalize2(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Sparse_Row::size(), WEIGHT_ADD_MUL, and WEIGHT_BEGIN.

1361  {
1362  PPL_ASSERT(x.size() == y.size());
1363  WEIGHT_BEGIN();
1364  const dimension_type x_size = x.size();
1365  Coefficient_traits::const_reference x_k = x.get(k);
1366  Coefficient_traits::const_reference y_k = y.get(k);
1367  PPL_ASSERT(y_k != 0 && x_k != 0);
1368  // Let g be the GCD between `x[k]' and `y[k]'.
1369  // For each i the following computes
1370  // x[i] = x[i]*y[k]/g - y[i]*x[k]/g.
1371  PPL_DIRTY_TEMP_COEFFICIENT(normalized_x_k);
1372  PPL_DIRTY_TEMP_COEFFICIENT(normalized_y_k);
1373  normalize2(x_k, y_k, normalized_x_k, normalized_y_k);
1374 
1375  neg_assign(normalized_y_k);
1376  x.linear_combine(y, normalized_y_k, normalized_x_k);
1377 
1378  PPL_ASSERT(x.get(k) == 0);
1379 
1380 #if PPL_USE_SPARSE_MATRIX
1381  PPL_ASSERT(x.find(k) == x.end());
1382 #endif
1383 
1384  x.normalize();
1385  WEIGHT_ADD_MUL(31, x_size);
1386 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
#define WEIGHT_ADD_MUL(delta, factor)
Definition: globals_defs.hh:90
#define WEIGHT_BEGIN()
Definition: globals_defs.hh:81
void neg_assign(GMP_Integer &x)
void normalize2(Coefficient_traits::const_reference x, Coefficient_traits::const_reference y, Coefficient &n_x, Coefficient &n_y)
If is the GCD of x and y, the values of x and y divided by are assigned to n_x and n_y...
void Parma_Polyhedra_Library::MIP_Problem::linear_combine ( Dense_Row x,
const Sparse_Row y,
const dimension_type  k 
)
staticprivate

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

Parameters
xThe row that will be combined with y object.
yThe row that will be combined with x object.
kThe 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 Dense_Row to x and normalizes it.

Definition at line 1392 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Dense_Row::get(), Parma_Polyhedra_Library::Sparse_Row::get(), Parma_Polyhedra_Library::linear_combine(), Parma_Polyhedra_Library::neg_assign(), Parma_Polyhedra_Library::Dense_Row::normalize(), Parma_Polyhedra_Library::normalize2(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Sparse_Row::size(), Parma_Polyhedra_Library::Dense_Row::size(), WEIGHT_ADD_MUL, and WEIGHT_BEGIN.

1394  {
1395  PPL_ASSERT(x.size() == y.size());
1396  WEIGHT_BEGIN();
1397  const dimension_type x_size = x.size();
1398  Coefficient_traits::const_reference x_k = x.get(k);
1399  Coefficient_traits::const_reference y_k = y.get(k);
1400  PPL_ASSERT(y_k != 0 && x_k != 0);
1401  // Let g be the GCD between `x[k]' and `y[k]'.
1402  // For each i the following computes
1403  // x[i] = x[i]*y[k]/g - y[i]*x[k]/g.
1404  PPL_DIRTY_TEMP_COEFFICIENT(normalized_x_k);
1405  PPL_DIRTY_TEMP_COEFFICIENT(normalized_y_k);
1406  normalize2(x_k, y_k, normalized_x_k, normalized_y_k);
1407 
1408  neg_assign(normalized_y_k);
1409  Parma_Polyhedra_Library::linear_combine(x, y, normalized_y_k, normalized_x_k);
1410 
1411  PPL_ASSERT(x[k] == 0);
1412 
1413  x.normalize();
1414  WEIGHT_ADD_MUL(83, x_size);
1415 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
void linear_combine(Dense_Row &x, const Dense_Row &y, Coefficient_traits::const_reference coeff1, Coefficient_traits::const_reference coeff2)
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
#define WEIGHT_ADD_MUL(delta, factor)
Definition: globals_defs.hh:90
#define WEIGHT_BEGIN()
Definition: globals_defs.hh:81
void neg_assign(GMP_Integer &x)
void normalize2(Coefficient_traits::const_reference x, Coefficient_traits::const_reference y, Coefficient &n_x, Coefficient &n_y)
If is the GCD of x and y, the values of x and y divided by are assigned to n_x and n_y...
void Parma_Polyhedra_Library::MIP_Problem::m_swap ( MIP_Problem y)
inline

Swaps *this with y.

Definition at line 177 of file MIP_Problem_inlines.hh.

References base, external_space_dim, first_pending_constraint, i_variables, inherited_constraints, initialized, input_cs, input_obj_function, internal_space_dim, last_generator, mapping, opt_mode, pricing, status, swap(), Parma_Polyhedra_Library::swap(), tableau, and working_cost.

Referenced by clear(), operator=(), and swap().

177  {
178  using std::swap;
179  swap(external_space_dim, y.external_space_dim);
180  swap(internal_space_dim, y.internal_space_dim);
181  swap(tableau, y.tableau);
182  swap(working_cost, y.working_cost);
183  swap(mapping, y.mapping);
184  swap(initialized, y.initialized);
185  swap(base, y.base);
186  swap(status, y.status);
187  swap(pricing, y.pricing);
188  swap(input_cs, y.input_cs);
189  swap(inherited_constraints, y.inherited_constraints);
190  swap(first_pending_constraint, y.first_pending_constraint);
191  swap(input_obj_function, y.input_obj_function);
192  swap(opt_mode, y.opt_mode);
193  swap(last_generator, y.last_generator);
194  swap(i_variables, y.i_variables);
195 }
void swap(CO_Tree &x, CO_Tree &y)
Optimization_Mode opt_mode
The optimization mode requested.
Linear_Expression input_obj_function
The objective function to be optimized.
void swap(MIP_Problem &x, MIP_Problem &y)
Swaps x with y.
working_cost_type working_cost
The working cost function.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< dimension_type > base
The current basic solution.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Variables_Set i_variables
A set containing all the indexes of variables that are constrained to have an integer value...
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
bool initialized
A Boolean encoding whether or not internal data structures have already been properly sized and popul...
Status status
The internal state of the MIP problem.
dimension_type inherited_constraints
The number of constraints that are inherited from our parent in the recursion tree built when solving...
Generator last_generator
The last successfully computed feasible or optimizing point.
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than exte...
Control_Parameter_Value pricing
The pricing method in use.
dimension_type external_space_dim
The dimension of the vector space.
dimension_type first_pending_constraint
The first index of `input_cs' containing a pending constraint.
dimension_type Parma_Polyhedra_Library::MIP_Problem::max_space_dimension ( )
inlinestatic

Returns the maximum space dimension an MIP_Problem can handle.

Definition at line 33 of file MIP_Problem_inlines.hh.

References Parma_Polyhedra_Library::Constraint::max_space_dimension().

Referenced by MIP_Problem().

33  {
35 }
static dimension_type max_space_dimension()
Returns the maximum space dimension a Constraint can handle.
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 non-feasible); otherwise not_a_dimension().
Parameters
var_indexThe index of the variable that has to be merged.

Definition at line 420 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::not_a_dimension().

420  {
421  // Initialize the return value to a dummy index.
422  dimension_type unfeasible_tableau_row = not_a_dimension();
423 
424  const dimension_type removing_column = mapping[1+var_index].second;
425 
426  // Check if the negative part of the split variable is in base:
427  // if so, the corresponding row of the tableau becomes non-feasible.
428  {
429  dimension_type base_index;
430  if (is_in_base(removing_column, base_index)) {
431  // Set the return value.
432  unfeasible_tableau_row = base_index;
433  // Reset base[base_index] to zero to remember non-feasibility.
434  base[base_index] = 0;
435  // Since the negative part of the variable is in base,
436  // the positive part can not be in base too.
437  PPL_ASSERT(!is_in_base(mapping[1+var_index].first, base_index));
438  }
439  }
440 
441  tableau.remove_column(removing_column);
442 
443  // var_index is no longer split.
444  mapping[1+var_index].second = 0;
445 
446  // Adjust data structures, `shifting' the proper columns to the left by 1.
447  const dimension_type base_size = base.size();
448  for (dimension_type i = base_size; i-- > 0; ) {
449  if (base[i] > removing_column) {
450  --base[i];
451  }
452  }
453  const dimension_type mapping_size = mapping.size();
454  for (dimension_type i = mapping_size; i-- > 0; ) {
455  if (mapping[i].first > removing_column) {
456  --mapping[i].first;
457  }
458  if (mapping[i].second > removing_column) {
459  --mapping[i].second;
460  }
461  }
462 
463  return unfeasible_tableau_row;
464 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
bool is_in_base(dimension_type var_index, dimension_type &row_index) const
Definition: MIP_Problem.cc:409
dimension_type not_a_dimension()
Returns a value that does not designate a valid dimension.
std::vector< dimension_type > base
The current basic solution.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
const Linear_Expression & Parma_Polyhedra_Library::MIP_Problem::objective_function ( ) const
inline

Returns the objective function.

Definition at line 134 of file MIP_Problem_inlines.hh.

References input_obj_function.

Referenced by operator<<().

134  {
135  return input_obj_function;
136 }
Linear_Expression input_obj_function
The objective function to be optimized.
bool Parma_Polyhedra_Library::MIP_Problem::OK ( ) const

Checks if all the invariants are satisfied.

Definition at line 2314 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::ascii_dump(), Parma_Polyhedra_Library::Sparse_Row::begin(), Parma_Polyhedra_Library::Sparse_Row::end(), Parma_Polyhedra_Library::gcd_assign(), Parma_Polyhedra_Library::CO_Tree::const_iterator::index(), Parma_Polyhedra_Library::Sparse_Row::lower_bound(), and PPL_DIRTY_TEMP_COEFFICIENT.

Referenced by MIP_Problem(), and set_optimization_mode().

2314  {
2315 #ifndef NDEBUG
2316  using std::endl;
2317  using std::cerr;
2318 #endif
2319  const dimension_type input_cs_num_rows = input_cs.size();
2320 
2321  // Check that every member used is OK.
2322 
2323  if (inherited_constraints > input_cs_num_rows) {
2324 #ifndef NDEBUG
2325  cerr << "The MIP_Problem claims to have inherited from its ancestors "
2326  << "more constraints than are recorded in this->input_cs."
2327  << endl;
2328  ascii_dump(cerr);
2329 #endif
2330  return false;
2331  }
2332 
2333  if (first_pending_constraint > input_cs_num_rows) {
2334 #ifndef NDEBUG
2335  cerr << "The MIP_Problem claims to have pending constraints "
2336  << "that are not recorded in this->input_cs."
2337  << endl;
2338  ascii_dump(cerr);
2339 #endif
2340  return false;
2341  }
2342 
2343  if (!tableau.OK() || !last_generator.OK()) {
2344  return false;
2345  }
2346 
2347  // Constraint system should contain no strict inequalities.
2348  for (dimension_type i = input_cs_num_rows; i-- > 0; ) {
2349  if (input_cs[i]->is_strict_inequality()) {
2350 #ifndef NDEBUG
2351  cerr << "The feasible region of the MIP_Problem is defined by "
2352  << "a constraint system containing strict inequalities."
2353  << endl;
2354  ascii_dump(cerr);
2355 #endif
2356  return false;
2357  }
2358 
2359  }
2360 
2362 #ifndef NDEBUG
2363  cerr << "The MIP_Problem claims to have an internal space dimension "
2364  << "greater than its external space dimension."
2365  << endl;
2366  ascii_dump(cerr);
2367 #endif
2368  return false;
2369  }
2370 
2372  && status != UNSATISFIABLE
2373  && status != PARTIALLY_SATISFIABLE) {
2374 #ifndef NDEBUG
2375  cerr << "The MIP_Problem claims to have a pending space dimension "
2376  << "addition, but the status is incompatible."
2377  << endl;
2378  ascii_dump(cerr);
2379 #endif
2380  return false;
2381  }
2382 
2383  // Constraint system and objective function should be dimension compatible.
2385 #ifndef NDEBUG
2386  cerr << "The MIP_Problem and the objective function have "
2387  << "incompatible space dimensions ("
2388  << external_space_dim << " < "
2389  << input_obj_function.space_dimension() << ")."
2390  << endl;
2391  ascii_dump(cerr);
2392 #endif
2393  return false;
2394  }
2395 
2396  if (status != UNSATISFIABLE && initialized) {
2397  // Here `last_generator' has to be meaningful.
2398  // Check for dimension compatibility and actual feasibility.
2400 #ifndef NDEBUG
2401  cerr << "The MIP_Problem and the cached feasible point have "
2402  << "incompatible space dimensions ("
2403  << internal_space_dim << " != "
2404  << last_generator.space_dimension() << ")."
2405  << endl;
2406  ascii_dump(cerr);
2407 #endif
2408  return false;
2409  }
2410 
2411  for (dimension_type i = 0; i < first_pending_constraint; ++i) {
2412  if (!is_satisfied(*(input_cs[i]), last_generator)) {
2413 #ifndef NDEBUG
2414  cerr << "The cached feasible point does not belong to "
2415  << "the feasible region of the MIP_Problem."
2416  << endl;
2417  ascii_dump(cerr);
2418 #endif
2419  return false;
2420  }
2421  }
2422 
2423  // Check that every integer declared variable is really integer.
2424  // in the solution found.
2425  if (!i_variables.empty()) {
2427  // TODO: This can be optimized more, exploiting the (possible)
2428  // sparseness of last_generator, if the size of i_variables is expected
2429  // to be greater than the number of nonzeroes in last_generator in most
2430  // cases.
2431  for (Variables_Set::const_iterator v_it = i_variables.begin(),
2432  v_end = i_variables.end(); v_it != v_end; ++v_it) {
2433  gcd_assign(gcd, last_generator.coefficient(Variable(*v_it)),
2435  if (gcd != last_generator.divisor()) {
2436  return false;
2437  }
2438  }
2439  }
2440 
2441  const dimension_type tableau_num_rows = tableau.num_rows();
2442  const dimension_type tableau_num_columns = tableau.num_columns();
2443 
2444  // The number of rows in the tableau and base should be equal.
2445  if (tableau_num_rows != base.size()) {
2446 #ifndef NDEBUG
2447  cerr << "tableau and base have incompatible sizes" << endl;
2448  ascii_dump(cerr);
2449 #endif
2450  return false;
2451  }
2452  // The size of `mapping' should be equal to the internal
2453  // space dimension plus one.
2454  if (mapping.size() != internal_space_dim + 1) {
2455 #ifndef NDEBUG
2456  cerr << "The internal space dimension and `mapping' "
2457  << "have incompatible sizes" << endl;
2458  ascii_dump(cerr);
2459 #endif
2460  return false;
2461  }
2462 
2463  // The number of columns in the tableau and working_cost should be equal.
2464  if (tableau_num_columns != working_cost.size()) {
2465 #ifndef NDEBUG
2466  cerr << "tableau and working_cost have incompatible sizes" << endl;
2467  ascii_dump(cerr);
2468 #endif
2469  return false;
2470  }
2471 
2472  // The vector base should contain indices of tableau's columns.
2473  for (dimension_type i = base.size(); i-- > 0; ) {
2474  if (base[i] > tableau_num_columns) {
2475 #ifndef NDEBUG
2476  cerr << "base contains an invalid column index" << endl;
2477  ascii_dump(cerr);
2478 #endif
2479  return false;
2480  }
2481  }
2482 
2483  {
2484  // Needed to sort accesses to tableau_j, improving performance.
2485  typedef std::vector<std::pair<dimension_type, dimension_type> >
2486  pair_vector_t;
2487  pair_vector_t vars_in_base;
2488  for (dimension_type i = base.size(); i-- > 0; ) {
2489  vars_in_base.push_back(std::make_pair(base[i], i));
2490  }
2491 
2492  std::sort(vars_in_base.begin(), vars_in_base.end());
2493 
2494  for (dimension_type j = tableau_num_rows; j-- > 0; ) {
2495  const Row& tableau_j = tableau[j];
2496  pair_vector_t::iterator i = vars_in_base.begin();
2497  pair_vector_t::iterator i_end = vars_in_base.end();
2498  Row::const_iterator itr = tableau_j.begin();
2499  Row::const_iterator itr_end = tableau_j.end();
2500  for ( ; i != i_end && itr != itr_end; ++i) {
2501  // tableau[i][base[j]], with i different from j, must be zero.
2502  if (itr.index() < i->first) {
2503  itr = tableau_j.lower_bound(itr, itr.index());
2504  }
2505  if (i->second != j && itr.index() == i->first && *itr != 0) {
2506 #ifndef NDEBUG
2507  cerr << "tableau[i][base[j]], with i different from j, must be "
2508  << "zero" << endl;
2509  ascii_dump(cerr);
2510 #endif
2511  return false;
2512  }
2513  }
2514  }
2515  }
2516  // tableau[i][base[i]] must not be a zero.
2517  for (dimension_type i = base.size(); i-- > 0; ) {
2518  if (tableau[i].get(base[i]) == 0) {
2519 #ifndef NDEBUG
2520  cerr << "tableau[i][base[i]] must not be a zero" << endl;
2521  ascii_dump(cerr);
2522 #endif
2523  return false;
2524  }
2525  }
2526 
2527  // The last column of the tableau must contain only zeroes.
2528  for (dimension_type i = tableau_num_rows; i-- > 0; ) {
2529  if (tableau[i].get(tableau_num_columns - 1) != 0) {
2530 #ifndef NDEBUG
2531  cerr << "the last column of the tableau must contain only"
2532  "zeroes"<< endl;
2533  ascii_dump(cerr);
2534 #endif
2535  return false;
2536  }
2537  }
2538  }
2539 
2540  // All checks passed.
2541  return true;
2542 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
Linear_Expression input_obj_function
The objective function to be optimized.
dimension_type size() const
Returns the size of the row.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
working_cost_type working_cost
The working cost function.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< dimension_type > base
The current basic solution.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
Variables_Set i_variables
A set containing all the indexes of variables that are constrained to have an integer value...
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
bool OK() const
Checks if all the invariants are satisfied.
Definition: Generator.cc:432
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
static bool is_satisfied(const Constraint &c, const Generator &g)
Returns true if and only if c is satisfied by g.
Definition: MIP_Problem.cc:467
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
bool initialized
A Boolean encoding whether or not internal data structures have already been properly sized and popul...
Status status
The internal state of the MIP problem.
dimension_type inherited_constraints
The number of constraints that are inherited from our parent in the recursion tree built when solving...
Generator last_generator
The last successfully computed feasible or optimizing point.
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than exte...
Coefficient_traits::const_reference coefficient(Variable v) const
Returns the coefficient of v in *this.
void gcd_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
Coefficient_traits::const_reference divisor() const
If *this is either a point or a closure point, returns its divisor.
dimension_type external_space_dim
The dimension of the vector space.
dimension_type first_pending_constraint
The first index of `input_cs' containing a pending constraint.
CO_Tree::const_iterator const_iterator
A const iterator on the row elements.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
MIP_Problem & Parma_Polyhedra_Library::MIP_Problem::operator= ( const MIP_Problem y)
inline

Assignment operator.

Definition at line 198 of file MIP_Problem_inlines.hh.

References m_swap().

198  {
199  MIP_Problem tmp(y);
200  m_swap(tmp);
201  return *this;
202 }
void m_swap(MIP_Problem &y)
Swaps *this with y.
MIP_Problem(dimension_type dim=0)
Builds a trivial MIP problem.
Definition: MIP_Problem.cc:78
void Parma_Polyhedra_Library::MIP_Problem::optimal_value ( Coefficient numer,
Coefficient denom 
) const
inline

Sets numer and denom so that $\frac{\mathtt{numer}}{\mathtt{denom}}$ is the solution of the optimization problem.

Exceptions
std::domain_errorThrown if *this does not not have an optimizing point, i.e., if the MIP problem is unbounded or not satisfiable.

Definition at line 144 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::BD_Shape< T >::max_min(), Parma_Polyhedra_Library::Octagonal_Shape< T >::max_min(), and Parma_Polyhedra_Library::Polyhedron::simplify_using_context_assign().

144  {
145  const Generator& g = optimizing_point();
146  evaluate_objective_function(g, numer, denom);
147 }
void evaluate_objective_function(const Generator &evaluating_point, Coefficient &numer, Coefficient &denom) const
Sets num and denom so that is the result of evaluating the objective function on evaluating_point...
const Generator & optimizing_point() const
Returns an optimal point for *this, if it exists.
Definition: MIP_Problem.cc:236
Optimization_Mode Parma_Polyhedra_Library::MIP_Problem::optimization_mode ( ) const
inline

Returns the optimization mode.

Definition at line 139 of file MIP_Problem_inlines.hh.

References opt_mode.

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

139  {
140  return opt_mode;
141 }
Optimization_Mode opt_mode
The optimization mode requested.
const PPL::Generator & Parma_Polyhedra_Library::MIP_Problem::optimizing_point ( ) const

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

Exceptions
std::domain_errorThrown if *this does not not have an optimizing point, i.e., if the MIP problem is unbounded or not satisfiable.

Definition at line 236 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::OPTIMIZED_MIP_PROBLEM.

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

236  {
237  if (solve() == OPTIMIZED_MIP_PROBLEM) {
238  return last_generator;
239  }
240  else {
241  throw std::domain_error("PPL::MIP_Problem::optimizing_point():\n"
242  "*this does not have an optimizing point.");
243  }
244 }
Generator last_generator
The last successfully computed feasible or optimizing point.
MIP_Problem_Status solve() const
Optimizes the MIP problem.
Definition: MIP_Problem.cc:293
The problem has an optimal solution.
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_rowsOn exit, this will store the number of rows that have to be added to the original tableau.
additional_slack_variablesThis will store the number of slack variables that have to be added to the original tableau.
is_tableau_constraintThis 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_inequalityThis 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_variableThis 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_variableThis 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 490 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Expression_Hide_Last< T >::all_zeroes(), Parma_Polyhedra_Library::Constraint::coefficient(), Parma_Polyhedra_Library::Constraint::expression(), Parma_Polyhedra_Library::Expression_Hide_Last< T >::first_nonzero(), Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), Parma_Polyhedra_Library::Constraint::is_equality(), Parma_Polyhedra_Library::Constraint::is_inequality(), Parma_Polyhedra_Library::Boundary_NS::sgn(), Parma_Polyhedra_Library::Boundary_NS::sgn_b(), and Parma_Polyhedra_Library::Constraint::space_dimension().

495  {
496  // Initially all containers are empty.
497  PPL_ASSERT(is_tableau_constraint.empty()
498  && is_satisfied_inequality.empty()
499  && is_nonnegative_variable.empty()
500  && is_remergeable_variable.empty());
501 
502  const dimension_type cs_space_dim = external_space_dim;
503  const dimension_type cs_num_rows = input_cs.size();
504  const dimension_type cs_num_pending
505  = cs_num_rows - first_pending_constraint;
506 
507  // Counters determining the change in dimensions of the tableau:
508  // initialized here, they will be updated while examining `input_cs'.
509  additional_tableau_rows = cs_num_pending;
510  additional_slack_variables = 0;
511 
512  // Resize containers appropriately.
513 
514  // On exit, `is_tableau_constraint[i]' will be true if and only if
515  // `input_cs[first_pending_constraint + i]' is neither a tautology
516  // (e.g., 1 >= 0) nor a non-negativity constraint (e.g., X >= 0).
517  is_tableau_constraint.insert(is_tableau_constraint.end(),
518  cs_num_pending, true);
519 
520  // On exit, `is_satisfied_inequality[i]' will be true if and only if
521  // `input_cs[first_pending_constraint + i]' is an inequality and it is
522  // satisfied by `last_generator'.
523  is_satisfied_inequality.insert(is_satisfied_inequality.end(),
524  cs_num_pending, false);
525 
526  // On exit, `is_nonnegative_variable[j]' will be true if and only if
527  // Variable(j) is bound to be nonnegative in `input_cs'.
528  is_nonnegative_variable.insert(is_nonnegative_variable.end(),
529  cs_space_dim, false);
530 
531  // On exit, `is_remergeable_variable[j]' will be true if and only if
532  // Variable(j) was initially split and is now remergeable.
533  is_remergeable_variable.insert(is_remergeable_variable.end(),
534  internal_space_dim, false);
535 
536  // Check for variables that are already known to be nonnegative
537  // due to non-pending constraints.
538  const dimension_type mapping_size = mapping.size();
539  if (mapping_size > 0) {
540  // Note: mapping[0] is associated to the cost function.
541  for (dimension_type i = std::min(mapping_size - 1, cs_space_dim);
542  i-- > 0; ) {
543  if (mapping[i + 1].second == 0) {
544  is_nonnegative_variable[i] = true;
545  }
546  }
547  }
548 
549  // Process each pending constraint in `input_cs' and
550  // - detect variables that are constrained to be nonnegative;
551  // - detect (non-negativity or tautology) pending constraints that
552  // will not be part of the tableau;
553  // - count the number of new slack variables.
554  for (dimension_type i = cs_num_rows; i-- > first_pending_constraint; ) {
555  const Constraint& cs_i = *(input_cs[i]);
556  const dimension_type cs_i_end = cs_i.space_dimension() + 1;
557 
558  const dimension_type nonzero_coeff_column_index
559  = cs_i.expression().first_nonzero(1, cs_i_end);
560  const bool found_a_nonzero_coeff = (nonzero_coeff_column_index != cs_i_end);
561  const bool found_many_nonzero_coeffs
562  = (found_a_nonzero_coeff
563  && !cs_i.expression().all_zeroes(nonzero_coeff_column_index + 1,
564  cs_i_end));
565 
566  // If more than one coefficient is nonzero,
567  // continue with next constraint.
568  if (found_many_nonzero_coeffs) {
569  if (cs_i.is_inequality()) {
570  ++additional_slack_variables;
571  // CHECKME: Is it true that in the first phase we can apply
572  // `is_satisfied()' with the generator `point()'? If so, the following
573  // code works even if we do not have a feasible point.
574  // Check for satisfiability of the inequality. This can be done if we
575  // have a feasible point of *this.
576  }
577  if (cs_i.is_inequality() && is_satisfied(cs_i, last_generator)) {
578  is_satisfied_inequality[i - first_pending_constraint] = true;
579  }
580  continue;
581  }
582 
583  if (!found_a_nonzero_coeff) {
584  // All coefficients are 0.
585  // The constraint is either trivially true or trivially false.
586  if (cs_i.is_inequality()) {
587  if (cs_i.inhomogeneous_term() < 0) {
588  // A constraint such as -1 >= 0 is trivially false.
589  return false;
590  }
591  }
592  else {
593  // The constraint is an equality.
594  if (cs_i.inhomogeneous_term() != 0) {
595  // A constraint such as 1 == 0 is trivially false.
596  return false;
597  }
598  }
599  // Here the constraint is trivially true.
600  is_tableau_constraint[i - first_pending_constraint] = false;
601  --additional_tableau_rows;
602  continue;
603  }
604  else {
605  // Here we have only one nonzero coefficient.
606  /*
607 
608  We have the following methods:
609  A) Do split the variable and do add the constraint
610  in the tableau.
611  B) Do not split the variable and do add the constraint
612  in the tableau.
613  C) Do not split the variable and do not add the constraint
614  in the tableau.
615 
616  Let the constraint be (a*v + b relsym 0).
617  These are the 12 possible combinations we can have:
618  a | b | relsym | method
619  ----------------------------------
620  1) >0 | >0 | >= | A
621  2) >0 | >0 | == | A
622  3) <0 | <0 | >= | A
623  4) >0 | =0 | == | B
624  5) >0 | <0 | == | B
625  Note: <0 | >0 | == | impossible by strong normalization
626  Note: <0 | =0 | == | impossible by strong normalization
627  Note: <0 | <0 | == | impossible by strong normalization
628  6) >0 | <0 | >= | B
629  7) >0 | =0 | >= | C
630  8) <0 | >0 | >= | A
631  9) <0 | =0 | >= | A
632 
633  The next lines will apply the correct method to each case.
634  */
635 
636  // The variable index is not equal to the column index.
637  const dimension_type nonzero_var_index = nonzero_coeff_column_index - 1;
638 
639  const int sgn_a = sgn(cs_i.coefficient(Variable(nonzero_var_index)));
640  const int sgn_b = sgn(cs_i.inhomogeneous_term());
641 
642  // Cases 1-3: apply method A.
643  if (sgn_a == sgn_b) {
644  if (cs_i.is_inequality()) {
645  ++additional_slack_variables;
646  }
647  }
648  // Cases 4-5: apply method B.
649  else if (cs_i.is_equality()) {
650  is_nonnegative_variable[nonzero_var_index] = true;
651  // Case 6: apply method B.
652  }
653  else if (sgn_b < 0) {
654  is_nonnegative_variable[nonzero_var_index] = true;
655  ++additional_slack_variables;
656  }
657  // Case 7: apply method C.
658  else if (sgn_a > 0) {
659  if (!is_nonnegative_variable[nonzero_var_index]) {
660  is_nonnegative_variable[nonzero_var_index] = true;
661  if (nonzero_coeff_column_index < mapping_size) {
662  // Remember to merge back the positive and negative parts.
663  PPL_ASSERT(nonzero_var_index < internal_space_dim);
664  is_remergeable_variable[nonzero_var_index] = true;
665  }
666  }
667  is_tableau_constraint[i - first_pending_constraint] = false;
668  --additional_tableau_rows;
669  }
670  // Cases 8-9: apply method A.
671  else {
672  PPL_ASSERT(cs_i.is_inequality());
673  ++additional_slack_variables;
674  }
675  }
676  }
677  return true;
678 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
static bool is_satisfied(const Constraint &c, const Generator &g)
Returns true if and only if c is satisfied by g.
Definition: MIP_Problem.cc:467
Generator last_generator
The last successfully computed feasible or optimizing point.
int sgn_b(Boundary_Type type, const T &x, const Info &info)
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than exte...
int sgn(Boundary_Type type, const T &x, const Info &info)
dimension_type external_space_dim
The dimension of the vector space.
dimension_type first_pending_constraint
The first index of `input_cs' containing a pending constraint.
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_indexThe index of the variable entering the base.
exiting_base_indexThe index of the row exiting the base.

Definition at line 1451 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Sparse_Row::get(), and Parma_Polyhedra_Library::linear_combine().

1452  {
1453  const Row& tableau_out = tableau[exiting_base_index];
1454  // Linearly combine the constraints.
1455  for (dimension_type i = tableau.num_rows(); i-- > 0; ) {
1456  Row& tableau_i = tableau[i];
1457  if (i != exiting_base_index && tableau_i.get(entering_var_index) != 0) {
1458  linear_combine(tableau_i, tableau_out, entering_var_index);
1459  }
1460  }
1461  // Linearly combine the cost function.
1462  if (working_cost.get(entering_var_index) != 0) {
1463  linear_combine(working_cost, tableau_out, entering_var_index);
1464  }
1465  // Adjust the base.
1466  base[exiting_base_index] = entering_var_index;
1467 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
static void linear_combine(Row &x, const Row &y, const dimension_type k)
Linearly combines x with y so that *this[k] is 0.
working_cost_type working_cost
The working cost function.
std::vector< dimension_type > base
The current basic solution.
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
Coefficient_traits::const_reference get(dimension_type i) const
Gets the i-th element in the sequence.
void Parma_Polyhedra_Library::MIP_Problem::print ( ) const

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

void Parma_Polyhedra_Library::MIP_Problem::process_pending_constraints ( )
private

Processes the pending constraints of *this.

Definition at line 681 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Expression_Adapter< T >::begin(), Parma_Polyhedra_Library::Sparse_Row::begin(), c, Parma_Polyhedra_Library::Coefficient_one(), Parma_Polyhedra_Library::Expression_Hide_Last< T >::end(), Parma_Polyhedra_Library::Sparse_Row::end(), Parma_Polyhedra_Library::Constraint::expression(), Parma_Polyhedra_Library::Sparse_Row::get(), Parma_Polyhedra_Library::CO_Tree::const_iterator::index(), Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), Parma_Polyhedra_Library::Sparse_Row::insert(), Parma_Polyhedra_Library::Constraint::is_inequality(), Parma_Polyhedra_Library::linear_combine(), Parma_Polyhedra_Library::neg_assign(), and Parma_Polyhedra_Library::not_a_dimension().

Referenced by is_lp_satisfiable().

681  {
682  // Check the pending constraints to adjust the data structures.
683  // If `false' is returned, they are trivially unfeasible.
684  dimension_type additional_tableau_rows = 0;
685  dimension_type additional_slack_vars = 0;
686  std::deque<bool> is_tableau_constraint;
687  std::deque<bool> is_satisfied_inequality;
688  std::deque<bool> is_nonnegative_variable;
689  std::deque<bool> is_remergeable_variable;
690  if (!parse_constraints(additional_tableau_rows,
691  additional_slack_vars,
692  is_tableau_constraint,
693  is_satisfied_inequality,
694  is_nonnegative_variable,
695  is_remergeable_variable)) {
697  return;
698  }
699 
700  // Merge back any variable that was previously split into a positive
701  // and a negative part and is now known to be nonnegative.
702  std::vector<dimension_type> unfeasible_tableau_rows;
703  for (dimension_type i = internal_space_dim; i-- > 0; ) {
704  if (!is_remergeable_variable[i]) {
705  continue;
706  }
707  // TODO: merging all rows in a single shot may be more efficient
708  // as it would require a single call to permute_columns().
709  const dimension_type unfeasible_row = merge_split_variable(i);
710  if (unfeasible_row != not_a_dimension()) {
711  unfeasible_tableau_rows.push_back(unfeasible_row);
712  }
713  }
714 
715  const dimension_type old_tableau_num_rows = tableau.num_rows();
716  const dimension_type old_tableau_num_cols = tableau.num_columns();
717  const dimension_type first_free_tableau_index = old_tableau_num_cols - 1;
718 
719  // Update mapping for the new problem variables (if any).
720  dimension_type additional_problem_vars = 0;
723  for (dimension_type i = 0, j = 0; i < space_diff; ++i) {
724  // Let `mapping' associate the variable index with the corresponding
725  // tableau column: split the variable into positive and negative
726  // parts if it is not known to be nonnegative.
727  const dimension_type positive = first_free_tableau_index + j;
728  if (is_nonnegative_variable[internal_space_dim + i]) {
729  // Do not split.
730  mapping.push_back(std::make_pair(positive, 0));
731  ++j;
732  ++additional_problem_vars;
733  }
734  else {
735  // Split: negative index is positive + 1.
736  mapping.push_back(std::make_pair(positive, positive + 1));
737  j += 2;
738  additional_problem_vars += 2;
739  }
740  }
741  }
742 
743  // Resize the tableau: first add additional rows ...
744  if (additional_tableau_rows > 0) {
745  tableau.add_zero_rows(additional_tableau_rows);
746  }
747 
748  // ... then add additional columns.
749  // We need columns for additional (split) problem variables, additional
750  // slack variables and additional artificials.
751  // The number of artificials to be added is computed as:
752  // * number of pending constraints entering the tableau
753  // minus
754  // * pending constraints that are inequalities and are already satisfied
755  // by `last_generator'
756  // plus
757  // * number of non-pending constraints that are no longer satisfied
758  // due to re-merging of split variables.
759 
760  const dimension_type num_satisfied_inequalities
761  = static_cast<dimension_type>(std::count(is_satisfied_inequality.begin(),
762  is_satisfied_inequality.end(),
763  true));
764  const dimension_type unfeasible_tableau_rows_size
765  = unfeasible_tableau_rows.size();
766 
767  PPL_ASSERT(additional_tableau_rows >= num_satisfied_inequalities);
768  const dimension_type additional_artificial_vars
769  = (additional_tableau_rows - num_satisfied_inequalities)
770  + unfeasible_tableau_rows_size;
771 
772  const dimension_type additional_tableau_columns
773  = additional_problem_vars
774  + additional_slack_vars
775  + additional_artificial_vars;
776 
777  if (additional_tableau_columns > 0) {
778  tableau.add_zero_columns(additional_tableau_columns);
779  }
780 
781  // Dimensions of the tableau after resizing.
782  const dimension_type tableau_num_rows = tableau.num_rows();
783  const dimension_type tableau_num_cols = tableau.num_columns();
784 
785  // The following vector will be useful know if a constraint is feasible
786  // and does not require an additional artificial variable.
787  std::deque<bool> worked_out_row(tableau_num_rows, false);
788 
789  // Sync the `base' vector size to the new tableau: fill with zeros
790  // to encode that these rows are not OK and must be adjusted.
791  base.insert(base.end(), additional_tableau_rows, 0);
792  const dimension_type base_size = base.size();
793 
794  // These indexes will be used to insert slack and artificial variables
795  // in the appropriate position.
796  dimension_type slack_index
797  = tableau_num_cols - additional_artificial_vars - 1;
798  dimension_type artificial_index = slack_index;
799 
800  // The first column index of the tableau that contains an
801  // artificial variable. Encode with 0 the fact the there are not
802  // artificial variables.
803  const dimension_type begin_artificials
804  = (additional_artificial_vars > 0)
805  ? artificial_index
806  : 0;
807 
808  // Proceed with the insertion of the constraints.
809  for (dimension_type k = tableau_num_rows,
810  i = input_cs.size() - first_pending_constraint; i-- > 0; ) {
811  if (!is_tableau_constraint[i]) {
812  continue;
813  }
814  // Copy the original constraint in the tableau.
815  Row& tableau_k = tableau[--k];
816  Row::iterator itr = tableau_k.end();
817 
818  const Constraint& c = *(input_cs[i + first_pending_constraint]);
819  const Constraint::expr_type c_e = c.expression();
820  for (Constraint::expr_type::const_iterator j = c_e.begin(),
821  j_end = c_e.end(); j != j_end; ++j) {
822  Coefficient_traits::const_reference coeff_sd = *j;
823  const std::pair<dimension_type, dimension_type> mapped
824  = mapping[j.variable().space_dimension()];
825  itr = tableau_k.insert(itr, mapped.first, coeff_sd);
826  // Split if needed.
827  if (mapped.second != 0) {
828  itr = tableau_k.insert(itr, mapped.second);
829  neg_assign(*itr, coeff_sd);
830  }
831  }
832  Coefficient_traits::const_reference inhomo = c.inhomogeneous_term();
833  if (inhomo != 0) {
834  tableau_k.insert(itr, mapping[0].first, inhomo);
835  // Split if needed.
836  if (mapping[0].second != 0) {
837  itr = tableau_k.insert(itr, mapping[0].second);
838  neg_assign(*itr, inhomo);
839  }
840  }
841 
842  // Add the slack variable, if needed.
843  if (c.is_inequality()) {
844  neg_assign(tableau_k[--slack_index], Coefficient_one());
845  // If the constraint is already satisfied, we will not use artificial
846  // variables to compute a feasible base: this to speed up
847  // the algorithm.
848  if (is_satisfied_inequality[i]) {
849  base[k] = slack_index;
850  worked_out_row[k] = true;
851  }
852  }
853  for (dimension_type j = base_size; j-- > 0; ) {
854  if (k != j && base[j] != 0 && tableau_k.get(base[j]) != 0) {
855  linear_combine(tableau_k, tableau[j], base[j]);
856  }
857  }
858  }
859 
860  // Let all inhomogeneous terms in the tableau be nonpositive,
861  // so as to simplify the insertion of artificial variables
862  // (the coefficient of each artificial variable will be 1).
863  for (dimension_type i = tableau_num_rows; i-- > 0 ; ) {
864  Row& tableau_i = tableau[i];
865  if (tableau_i.get(0) > 0) {
866  for (Row::iterator
867  j = tableau_i.begin(), j_end = tableau_i.end();
868  j != j_end; ++j) {
869  neg_assign(*j);
870  }
871  }
872  }
873 
874  // Reset the working cost function to have the right size.
875  working_cost = working_cost_type(tableau_num_cols);
876 
877  // Set up artificial variables: these will have coefficient 1 in the
878  // constraint, will enter the base and will have coefficient -1 in
879  // the cost function.
880 
881  // This is used as a hint for insertions in working_cost.
883 
884  // First go through non-pending constraints that became unfeasible
885  // due to re-merging of split variables.
886  for (dimension_type i = 0; i < unfeasible_tableau_rows_size; ++i) {
887  tableau[unfeasible_tableau_rows[i]].insert(artificial_index,
888  Coefficient_one());
889  cost_itr = working_cost.insert(cost_itr, artificial_index);
890  *cost_itr = -1;
891  base[unfeasible_tableau_rows[i]] = artificial_index;
892  ++artificial_index;
893  }
894  // Then go through newly added tableau rows, disregarding inequalities
895  // that are already satisfied by `last_generator' (this information
896  // is encoded in `worked_out_row').
897  for (dimension_type i = old_tableau_num_rows; i < tableau_num_rows; ++i) {
898  if (worked_out_row[i]) {
899  continue;
900  }
901  tableau[i].insert(artificial_index, Coefficient_one());
902  cost_itr = working_cost.insert(cost_itr, artificial_index);
903  *cost_itr = -1;
904  base[i] = artificial_index;
905  ++artificial_index;
906  }
907  // One past the last tableau column index containing an artificial variable.
908  const dimension_type end_artificials = artificial_index;
909 
910  // Set the extra-coefficient of the cost functions to record its sign.
911  // This is done to keep track of the possible sign's inversion.
912  const dimension_type last_obj_index = working_cost.size() - 1;
913  working_cost.insert(cost_itr, last_obj_index, Coefficient_one());
914 
915  // Express the problem in terms of the variables in base.
916  {
918  for (dimension_type i = tableau_num_rows; i-- > 0; ) {
919  itr = working_cost.lower_bound(itr, base[i]);
920  if (itr != working_cost.end() && itr.index() == base[i] && *itr != 0) {
922  // itr has been invalidated by the call to linear_combine().
923  itr = working_cost.end();
924  }
925  }
926  }
927 
928  // Deal with zero dimensional problems.
929  if (space_dimension() == 0) {
930  status = OPTIMIZED;
931  last_generator = point();
932  return;
933  }
934  // Deal with trivial cases.
935  // If there is no constraint in the tableau, then the feasible region
936  // is only delimited by non-negativity constraints. Therefore,
937  // the problem is unbounded as soon as the cost function has
938  // a variable with a positive coefficient.
939  if (tableau_num_rows == 0) {
941  // Ensure the right space dimension is obtained.
942  last_generator = point();
944  status = UNBOUNDED;
945  return;
946  }
947 
948  // The problem is neither trivially unfeasible nor trivially unbounded.
949  // The tableau was successful computed and the caller has to figure
950  // out which case applies.
951  status = OPTIMIZED;
952  // Ensure the right space dimension is obtained.
953  last_generator = point();
955  return;
956  }
957 
958  // Now we are ready to solve the first phase.
959  const bool first_phase_successful
963 
964 #if PPL_NOISY_SIMPLEX
965  std::cout << "MIP_Problem::process_pending_constraints(): "
966  << "1st phase ended at iteration " << num_iterations
967  << "." << std::endl;
968 #endif // PPL_NOISY_SIMPLEX
969 
970  if (!first_phase_successful || working_cost.get(0) != 0) {
971  // The feasible region is empty.
973  return;
974  }
975 
976  // Prepare *this for a possible second phase.
977  if (begin_artificials != 0) {
978  erase_artificials(begin_artificials, end_artificials);
979  }
982 }
Expression_Hide_Last< Linear_Expression > expr_type
The type of the (adapted) internal expression.
Optimization_Mode opt_mode
The optimization mode requested.
size_t dimension_type
An unsigned integral type for representing space dimensions.
static void linear_combine(Row &x, const Row &y, const dimension_type k)
Linearly combines x with y so that *this[k] is 0.
Linear_Expression input_obj_function
The objective function to be optimized.
dimension_type size() const
Returns the size of the row.
dimension_type not_a_dimension()
Returns a value that does not designate a valid dimension.
CO_Tree::iterator iterator
An iterator on the row elements.
working_cost_type working_cost
The working cost function.
const iterator & end()
Returns an iterator that points after the last stored element.
std::vector< Constraint * > input_cs
The sequence of constraints describing the feasible region.
std::vector< dimension_type > base
The current basic 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 simp...
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
bool compute_simplex_using_steepest_edge_float()
Returns true if and if only the algorithm successfully computed a feasible solution.
Control_Parameter_Value get_control_parameter(Control_Parameter_Name name) const
Returns the value of the control parameter name.
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
dimension_type merge_split_variable(dimension_type var_index)
Merges back the positive and negative part of a (previously split) variable after detecting a corresp...
Definition: MIP_Problem.cc:420
The MIP problem is optimized; an optimal solution has been computed.
iterator insert(dimension_type i, Coefficient_traits::const_reference x)
Equivalent to (*this)[i] = x; find(i), but faster.
Status status
The internal state of the MIP problem.
void set_space_dimension(dimension_type space_dim)
static bool is_unbounded_obj_function(const Linear_Expression &obj_function, const std::vector< std::pair< dimension_type, dimension_type > > &mapping, Optimization_Mode optimization_mode)
void neg_assign(GMP_Integer &x)
iterator lower_bound(dimension_type i)
Lower bound of index i.
Generator last_generator
The last successfully computed feasible or optimizing point.
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than exte...
The MIP problem is unbounded; a feasible solution has been computed.
base_type::const_iterator const_iterator
The type of const iterators on coefficients.
void compute_generator() const
Computes a valid generator that satisfies all the constraints of the Linear Programming problem assoc...
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.
Definition: MIP_Problem.cc:490
Steepest edge pricing method, using floating points (default).
bool compute_simplex_using_exact_pricing()
Returns true if and if only the algorithm successfully computed a feasible solution.
Coefficient c
Definition: PIP_Tree.cc:64
dimension_type external_space_dim
The dimension of the vector space.
Coefficient_traits::const_reference Coefficient_one()
Returns a const reference to a Coefficient with value 1.
dimension_type index() const
Returns the index of the element pointed to by *this.
dimension_type first_pending_constraint
The first index of `input_cs' containing a pending constraint.
CO_Tree::const_iterator const_iterator
A const iterator on the row elements.
Coefficient_traits::const_reference get(dimension_type i) const
Gets the i-th element in the sequence.
dimension_type space_dimension() const
Returns the space dimension of the MIP problem.
The MIP problem is satisfiable; a feasible solution has been computed.
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 1864 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Sparse_Row::begin(), Parma_Polyhedra_Library::Coefficient_one(), Parma_Polyhedra_Library::Sparse_Row::end(), Parma_Polyhedra_Library::CO_Tree::iterator::index(), Parma_Polyhedra_Library::linear_combine(), Parma_Polyhedra_Library::Sparse_Row::lower_bound(), Parma_Polyhedra_Library::MINIMIZATION, Parma_Polyhedra_Library::neg_assign(), and Parma_Polyhedra_Library::swap().

Referenced by solve(), and solve_mip().

1864  {
1865  // Second_phase requires that *this is satisfiable.
1866  PPL_ASSERT(status == SATISFIABLE
1867  || status == UNBOUNDED
1868  || status == OPTIMIZED);
1869  // In the following cases the problem is already solved.
1870  if (status == UNBOUNDED || status == OPTIMIZED) {
1871  return;
1872  }
1873  // Build the objective function for the second phase.
1874  Row new_cost;
1875  input_obj_function.get_row(new_cost);
1876 
1877  // Negate the cost function if we are minimizing.
1878  if (opt_mode == MINIMIZATION) {
1879  for (Row::iterator i = new_cost.begin(),
1880  i_end = new_cost.end(); i != i_end; ++i) {
1881  neg_assign(*i);
1882  }
1883  }
1884 
1885  const dimension_type cost_zero_size = working_cost.size();
1886 
1887  // Substitute properly the cost function in the `costs' matrix.
1888  {
1889  working_cost_type tmp_cost(cost_zero_size, cost_zero_size);
1890  swap(tmp_cost, working_cost);
1891  }
1892 
1893  {
1895  = working_cost.insert(cost_zero_size - 1, Coefficient_one());
1896 
1897  // Split the variables in the cost function.
1898  for (Row::const_iterator i = new_cost.lower_bound(1),
1899  i_end = new_cost.end(); i != i_end; ++i) {
1900  const dimension_type index = i.index();
1901  const dimension_type original_var = mapping[index].first;
1902  const dimension_type split_var = mapping[index].second;
1903  itr = working_cost.insert(itr, original_var, *i);
1904  if (mapping[index].second != 0) {
1905  itr = working_cost.insert(itr, split_var);
1906  neg_assign(*itr, *i);
1907  }
1908  }
1909  }
1910 
1911  // Here the first phase problem succeeded with optimum value zero.
1912  // Express the old cost function in terms of the computed base.
1913  {
1915  for (dimension_type i = tableau.num_rows(); i-- > 0; ) {
1916  const dimension_type base_i = base[i];
1917  itr = working_cost.lower_bound(itr, base_i);
1918  if (itr != working_cost.end() && itr.index() == base_i && *itr != 0) {
1919  linear_combine(working_cost, tableau[i], base_i);
1920  itr = working_cost.end();
1921  }
1922  }
1923  }
1924 
1925  // Solve the second phase problem.
1926  const bool second_phase_successful
1931 #if PPL_NOISY_SIMPLEX
1932  std::cout << "MIP_Problem::second_phase(): 2nd phase ended at iteration "
1933  << num_iterations
1934  << "." << std::endl;
1935 #endif // PPL_NOISY_SIMPLEX
1936  status = second_phase_successful ? OPTIMIZED : UNBOUNDED;
1937  PPL_ASSERT(OK());
1938 }
Minimization is requested.
Optimization_Mode opt_mode
The optimization mode requested.
size_t dimension_type
An unsigned integral type for representing space dimensions.
static void linear_combine(Row &x, const Row &y, const dimension_type k)
Linearly combines x with y so that *this[k] is 0.
Linear_Expression input_obj_function
The objective function to be optimized.
dimension_type size() const
Returns the size of the row.
void swap(MIP_Problem &x, MIP_Problem &y)
Swaps x with y.
CO_Tree::iterator iterator
An iterator on the row elements.
working_cost_type working_cost
The working cost function.
const iterator & end()
Returns an iterator that points after the last stored element.
void get_row(Dense_Row &r) const
Sets r to a copy of the row that implements *this.
std::vector< dimension_type > base
The current basic solution.
std::vector< std::pair< dimension_type, dimension_type > > mapping
A map between the variables of `input_cs' and `tableau'.
bool compute_simplex_using_steepest_edge_float()
Returns true if and if only the algorithm successfully computed a feasible solution.
Control_Parameter_Value get_control_parameter(Control_Parameter_Name name) const
Returns the value of the control parameter name.
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
bool OK() const
Checks if all the invariants are satisfied.
The MIP problem is optimized; an optimal solution has been computed.
iterator insert(dimension_type i, Coefficient_traits::const_reference x)
Equivalent to (*this)[i] = x; find(i), but faster.
Status status
The internal state of the MIP problem.
void neg_assign(GMP_Integer &x)
iterator lower_bound(dimension_type i)
Lower bound of index i.
The MIP problem is unbounded; a feasible solution has been computed.
void compute_generator() const
Computes a valid generator that satisfies all the constraints of the Linear Programming problem assoc...
Steepest edge pricing method, using floating points (default).
bool compute_simplex_using_exact_pricing()
Returns true if and if only the algorithm successfully computed a feasible solution.
Coefficient_traits::const_reference Coefficient_one()
Returns a const reference to a Coefficient with value 1.
dimension_type index() const
Returns the index of the element pointed to by *this.
CO_Tree::const_iterator const_iterator
A const iterator on the row elements.
The MIP problem is satisfiable; a feasible solution has been computed.
void Parma_Polyhedra_Library::MIP_Problem::set_control_parameter ( Control_Parameter_Value  value)
inline

Sets control parameter value.

Definition at line 172 of file MIP_Problem_inlines.hh.

References pricing, and value.

172  {
173  pricing = value;
174 }
Coefficient value
Definition: PIP_Tree.cc:618
Control_Parameter_Value pricing
The pricing method in use.
void Parma_Polyhedra_Library::MIP_Problem::set_objective_function ( const Linear_Expression obj)

Sets the objective function to obj.

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

Definition at line 208 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Linear_Expression::space_dimension().

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().

208  {
209  if (space_dimension() < obj.space_dimension()) {
210  std::ostringstream s;
211  s << "PPL::MIP_Problem::set_objective_function(obj):\n"
212  << "obj.space_dimension() == " << obj.space_dimension()
213  << " exceeds this->space_dimension == " << space_dimension()
214  << ".";
215  throw std::invalid_argument(s.str());
216  }
217  input_obj_function = obj;
218  if (status == UNBOUNDED || status == OPTIMIZED) {
220  }
221  PPL_ASSERT(OK());
222 }
Linear_Expression input_obj_function
The objective function to be optimized.
bool OK() const
Checks if all the invariants are satisfied.
The MIP problem is optimized; an optimal solution has been computed.
Status status
The internal state of the MIP problem.
The MIP problem is unbounded; a feasible solution has been computed.
dimension_type space_dimension() const
Returns the space dimension of the MIP problem.
The MIP problem is satisfiable; a feasible solution has been computed.
void Parma_Polyhedra_Library::MIP_Problem::set_optimization_mode ( Optimization_Mode  mode)
inline

Sets the optimization mode to mode.

Definition at line 123 of file MIP_Problem_inlines.hh.

References OK(), opt_mode, OPTIMIZED, SATISFIABLE, 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().

123  {
124  if (opt_mode != mode) {
125  opt_mode = mode;
126  if (status == UNBOUNDED || status == OPTIMIZED) {
128  }
129  PPL_ASSERT(OK());
130  }
131 }
Optimization_Mode opt_mode
The optimization mode requested.
bool OK() const
Checks if all the invariants are satisfied.
The MIP problem is optimized; an optimal solution has been computed.
Status status
The internal state of the MIP problem.
The MIP problem is unbounded; a feasible solution has been computed.
The MIP problem is satisfiable; a feasible solution has been computed.
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 293 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, Parma_Polyhedra_Library::OPTIMIZED_MIP_PROBLEM, PPL_DIRTY_TEMP, second_phase(), status, Parma_Polyhedra_Library::UNBOUNDED_MIP_PROBLEM, and Parma_Polyhedra_Library::UNFEASIBLE_MIP_PROBLEM.

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::BD_Shape< T >::bounds(), Parma_Polyhedra_Library::Octagonal_Shape< T >::bounds(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::BD_Shape< T >::max_min(), Parma_Polyhedra_Library::Octagonal_Shape< T >::max_min(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), Parma_Polyhedra_Library::Polyhedron::simplify_using_context_assign(), and Parma_Polyhedra_Library::Polyhedron::strongly_minimize_constraints().

293  {
294  switch (status) {
295  case UNSATISFIABLE:
296  PPL_ASSERT(OK());
297  return UNFEASIBLE_MIP_PROBLEM;
298  case UNBOUNDED:
299  PPL_ASSERT(OK());
300  return UNBOUNDED_MIP_PROBLEM;
301  case OPTIMIZED:
302  PPL_ASSERT(OK());
303  return OPTIMIZED_MIP_PROBLEM;
304  case SATISFIABLE:
305  // Intentionally fall through
307  {
308  MIP_Problem& x = const_cast<MIP_Problem&>(*this);
309  if (x.i_variables.empty()) {
310  // LP case.
311  if (x.is_lp_satisfiable()) {
312  x.second_phase();
313  if (x.status == UNBOUNDED) {
314  return UNBOUNDED_MIP_PROBLEM;
315  }
316  else {
317  PPL_ASSERT(x.status == OPTIMIZED);
318  return OPTIMIZED_MIP_PROBLEM;
319  }
320  }
321  return UNFEASIBLE_MIP_PROBLEM;
322  }
323 
324  // MIP case.
325  MIP_Problem_Status return_value;
326  Generator g = point();
327  {
328  // Temporarily relax the MIP into an LP problem.
330  if (relaxed.lp.is_lp_satisfiable()) {
331  relaxed.lp.second_phase();
332  }
333  else {
334  x.status = UNSATISFIABLE;
335  // NOTE: `relaxed' destroyed: relaxation automatically reset.
336  return UNFEASIBLE_MIP_PROBLEM;
337  }
338  PPL_DIRTY_TEMP(mpq_class, incumbent_solution);
339  bool have_incumbent_solution = false;
340 
341  MIP_Problem lp_copy(relaxed.lp, Inherit_Constraints());
342  PPL_ASSERT(lp_copy.integer_space_dimensions().empty());
343  return_value = solve_mip(have_incumbent_solution,
344  incumbent_solution, g,
345  lp_copy, relaxed.i_vars);
346  } // `relaxed' destroyed here: relaxation automatically reset.
347 
348  switch (return_value) {
350  x.status = UNSATISFIABLE;
351  break;
353  x.status = UNBOUNDED;
354  // A feasible point has been set in `solve_mip()', so that
355  // a call to `feasible_point' will be successful.
356  x.last_generator = g;
357  break;
359  x.status = OPTIMIZED;
360  // Set the internal generator.
361  x.last_generator = g;
362  break;
363  }
364  PPL_ASSERT(OK());
365  return return_value;
366  }
367  }
368  // We should not be here!
369  PPL_UNREACHABLE;
370  return UNFEASIBLE_MIP_PROBLEM;
371 }
bool OK() const
Checks if all the invariants are satisfied.
The MIP problem is optimized; an optimal solution has been computed.
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.
The feasible region of the MIP problem has been changed by adding new space dimensions or new constra...
#define PPL_DIRTY_TEMP(T, id)
Status status
The internal state of the MIP problem.
The MIP problem is unbounded; a feasible solution has been computed.
MIP_Problem(dimension_type dim=0)
Builds a trivial MIP problem.
Definition: MIP_Problem.cc:78
The problem has an optimal solution.
MIP_Problem_Status
Possible outcomes of the MIP_Problem solver.
The MIP problem is satisfiable; a feasible solution has been computed.
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 
)
staticprivate

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

Parameters
have_incumbent_solutionIt is used to store if the solving process has found a provisional optimum point.
incumbent_solution_valueEncodes the evaluated value of the provisional optimum point found.
incumbent_solution_pointIf the method returns `OPTIMIZED', this will contain the optimality point.
mipThe problem that has to be solved.
i_varsThe variables that are constrained to take an integer value.

Definition at line 2015 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(), Parma_Polyhedra_Library::OPTIMIZED_MIP_PROBLEM, PPL_DIRTY_TEMP, PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::ROUND_DOWN, Parma_Polyhedra_Library::ROUND_NOT_NEEDED, Parma_Polyhedra_Library::ROUND_UP, second_phase(), space_dimension(), status, Parma_Polyhedra_Library::UNBOUNDED_MIP_PROBLEM, and Parma_Polyhedra_Library::UNFEASIBLE_MIP_PROBLEM.

2019  {
2020  // Solve the problem as a non MIP one, it must be done internally.
2021  PPL::MIP_Problem_Status mip_status;
2022  if (mip.is_lp_satisfiable()) {
2023  mip.second_phase();
2024  mip_status = (mip.status == OPTIMIZED) ? OPTIMIZED_MIP_PROBLEM
2026  }
2027  else {
2028  return UNFEASIBLE_MIP_PROBLEM;
2029  }
2030  PPL_DIRTY_TEMP(mpq_class, tmp_rational);
2031 
2032  Generator p = point();
2033  PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff1);
2034  PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff2);
2035 
2036  if (mip_status == UNBOUNDED_MIP_PROBLEM) {
2037  p = mip.last_generator;
2038  }
2039  else {
2040  PPL_ASSERT(mip_status == OPTIMIZED_MIP_PROBLEM);
2041  // Do not call optimizing_point().
2042  p = mip.last_generator;
2043  mip.evaluate_objective_function(p, tmp_coeff1, tmp_coeff2);
2044  assign_r(tmp_rational.get_num(), tmp_coeff1, ROUND_NOT_NEEDED);
2045  assign_r(tmp_rational.get_den(), tmp_coeff2, ROUND_NOT_NEEDED);
2046  PPL_ASSERT(is_canonical(tmp_rational));
2047  if (have_incumbent_solution
2048  && ((mip.optimization_mode() == MAXIMIZATION
2049  && tmp_rational <= incumbent_solution_value)
2050  || (mip.optimization_mode() == MINIMIZATION
2051  && tmp_rational >= incumbent_solution_value))) {
2052  // Abandon this path.
2053  return mip_status;
2054  }
2055  }
2056 
2057  bool found_satisfiable_generator = true;
2059  Coefficient_traits::const_reference p_divisor = p.divisor();
2060  dimension_type non_int_dim = mip.space_dimension();
2061  // TODO: This can be optimized more, exploiting the (possible)
2062  // sparseness of p, if the size of i_vars is expected to be greater than
2063  // the number of nonzeroes in p in most cases.
2064  for (Variables_Set::const_iterator v_begin = i_vars.begin(),
2065  v_end = i_vars.end(); v_begin != v_end; ++v_begin) {
2066  gcd_assign(gcd, p.coefficient(Variable(*v_begin)), p_divisor);
2067  if (gcd != p_divisor) {
2068  non_int_dim = *v_begin;
2069  found_satisfiable_generator = false;
2070  break;
2071  }
2072  }
2073  if (found_satisfiable_generator) {
2074  // All the coordinates of `point' are satisfiable.
2075  if (mip_status == UNBOUNDED_MIP_PROBLEM) {
2076  // This is a point that belongs to the MIP_Problem.
2077  // In this way we are sure that we will return every time
2078  // a feasible point if requested by the user.
2079  incumbent_solution_point = p;
2080  return mip_status;
2081  }
2082  if (!have_incumbent_solution
2083  || (mip.optimization_mode() == MAXIMIZATION
2084  && tmp_rational > incumbent_solution_value)
2085  || tmp_rational < incumbent_solution_value) {
2086  incumbent_solution_value = tmp_rational;
2087  incumbent_solution_point = p;
2088  have_incumbent_solution = true;
2089 #if PPL_NOISY_SIMPLEX
2092  mip.evaluate_objective_function(p, numer, denom);
2093  std::cout << "MIP_Problem::solve_mip(): "
2094  << "new value found: " << numer << "/" << denom
2095  << "." << std::endl;
2096 #endif // PPL_NOISY_SIMPLEX
2097  }
2098  return mip_status;
2099  }
2100 
2101  PPL_ASSERT(non_int_dim < mip.space_dimension());
2102 
2103  assign_r(tmp_rational.get_num(), p.coefficient(Variable(non_int_dim)),
2105  assign_r(tmp_rational.get_den(), p_divisor, ROUND_NOT_NEEDED);
2106  tmp_rational.canonicalize();
2107  assign_r(tmp_coeff1, tmp_rational, ROUND_DOWN);
2108  assign_r(tmp_coeff2, tmp_rational, ROUND_UP);
2109  {
2110  MIP_Problem mip_aux(mip, Inherit_Constraints());
2111  mip_aux.add_constraint(Variable(non_int_dim) <= tmp_coeff1);
2112 #if PPL_NOISY_SIMPLEX
2113  using namespace IO_Operators;
2114  std::cout << "MIP_Problem::solve_mip(): "
2115  << "descending with: "
2116  << (Variable(non_int_dim) <= tmp_coeff1)
2117  << "." << std::endl;
2118 #endif // PPL_NOISY_SIMPLEX
2119  solve_mip(have_incumbent_solution, incumbent_solution_value,
2120  incumbent_solution_point, mip_aux, i_vars);
2121  }
2122  // TODO: change this when we will be able to remove constraints.
2123  mip.add_constraint(Variable(non_int_dim) >= tmp_coeff2);
2124 #if PPL_NOISY_SIMPLEX
2125  using namespace IO_Operators;
2126  std::cout << "MIP_Problem::solve_mip(): "
2127  << "descending with: "
2128  << (Variable(non_int_dim) >= tmp_coeff2)
2129  << "." << std::endl;
2130 #endif // PPL_NOISY_SIMPLEX
2131  solve_mip(have_incumbent_solution, incumbent_solution_value,
2132  incumbent_solution_point, mip, i_vars);
2133  return have_incumbent_solution ? mip_status : UNFEASIBLE_MIP_PROBLEM;
2134 }
Minimization is requested.
Enable_If< Is_Native_Or_Checked< To >::value &&Is_Special< From >::value, Result >::type assign_r(To &to, const From &, Rounding_Dir dir)
size_t dimension_type
An unsigned integral type for representing space dimensions.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
bool is_canonical(const mpq_class &x)
Returns true if and only if x is in canonical form.
The MIP problem is optimized; an optimal solution has been computed.
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.
#define PPL_DIRTY_TEMP(T, id)
Maximization is requested.
void gcd_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
MIP_Problem(dimension_type dim=0)
Builds a trivial MIP problem.
Definition: MIP_Problem.cc:78
The problem has an optimal solution.
MIP_Problem_Status
Possible outcomes of the MIP_Problem solver.
dimension_type Parma_Polyhedra_Library::MIP_Problem::space_dimension ( ) const
inline

Returns the space dimension of the MIP problem.

Definition at line 38 of file MIP_Problem_inlines.hh.

References external_space_dim.

Referenced by is_mip_satisfiable(), and solve_mip().

38  {
39  return external_space_dim;
40 }
dimension_type external_space_dim
The dimension of the vector space.
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 does not 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 1134 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::add_mul_assign(), Parma_Polyhedra_Library::Sparse_Row::begin(), Parma_Polyhedra_Library::Sparse_Row::end(), Parma_Polyhedra_Library::exact_div_assign(), Parma_Polyhedra_Library::CO_Tree::const_iterator::index(), Parma_Polyhedra_Library::lcm_assign(), Parma_Polyhedra_Library::Sparse_Row::lower_bound(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Boundary_NS::sgn(), Parma_Polyhedra_Library::swap(), WEIGHT_ADD_MUL, and WEIGHT_BEGIN.

1134  {
1135  using std::swap;
1136  const dimension_type tableau_num_rows = tableau.num_rows();
1137  PPL_ASSERT(tableau_num_rows == base.size());
1138  // The square of the lcm of all the coefficients of variables in base.
1139  PPL_DIRTY_TEMP_COEFFICIENT(squared_lcm_basis);
1140  // The normalization factor for each coefficient in the tableau.
1141  std::vector<Coefficient> norm_factor(tableau_num_rows);
1142  {
1143  WEIGHT_BEGIN();
1144  // Compute the lcm of all the coefficients of variables in base.
1145  PPL_DIRTY_TEMP_COEFFICIENT(lcm_basis);
1146  lcm_basis = 1;
1147  for (dimension_type i = tableau_num_rows; i-- > 0; ) {
1148  lcm_assign(lcm_basis, lcm_basis, tableau[i].get(base[i]));
1149  }
1150  // Compute normalization factors.
1151  for (dimension_type i = tableau_num_rows; i-- > 0; ) {
1152  exact_div_assign(norm_factor[i], lcm_basis, tableau[i].get(base[i]));
1153  }
1154  // Compute the square of `lcm_basis', exploiting the fact that
1155  // `lcm_basis' will no longer be needed.
1156  lcm_basis *= lcm_basis;
1157  swap(squared_lcm_basis, lcm_basis);
1158  WEIGHT_ADD_MUL(444, tableau_num_rows);
1159  }
1160 
1161  PPL_DIRTY_TEMP_COEFFICIENT(challenger_numer);
1162  PPL_DIRTY_TEMP_COEFFICIENT(scalar_value);
1163  PPL_DIRTY_TEMP_COEFFICIENT(challenger_value);
1164  PPL_DIRTY_TEMP_COEFFICIENT(current_value);
1165 
1166  PPL_DIRTY_TEMP_COEFFICIENT(current_numer);
1167  PPL_DIRTY_TEMP_COEFFICIENT(current_denom);
1168  dimension_type entering_index = 0;
1169  const int cost_sign = sgn(working_cost.get(working_cost.size() - 1));
1170 
1171  // These two implementation work for both sparse and dense matrices.
1172  // However, when using sparse matrices the first one is fast and the second
1173  // one is slow, and when using dense matrices the first one is slow and
1174  // the second one is fast.
1175 #if PPL_USE_SPARSE_MATRIX
1176 
1177  const dimension_type tableau_num_columns = tableau.num_columns();
1178  const dimension_type tableau_num_columns_minus_1 = tableau_num_columns - 1;
1179  // This is static to improve performance.
1180  // A pair (i, x) means that sgn(working_cost[i]) == cost_sign and x
1181  // is the denominator of the challenger, for the column i.
1182  static std::vector<std::pair<dimension_type, Coefficient> > columns;
1183  columns.clear();
1184  // tableau_num_columns - 2 is only an upper bound on the required elements.
1185  // This helps to reduce the number of calls to new [] and delete [] and
1186  // the construction/destruction of Coefficient objects.
1187  columns.reserve(tableau_num_columns - 2);
1188  {
1190  // Note that find() is used instead of lower_bound.
1192  = working_cost.find(tableau_num_columns_minus_1);
1193  for ( ; i != i_end; ++i) {
1194  if (sgn(*i) == cost_sign) {
1195  columns.push_back(std::pair<dimension_type, Coefficient>
1196  (i.index(), squared_lcm_basis));
1197  }
1198  }
1199  }
1200  for (dimension_type i = tableau_num_rows; i-- > 0; ) {
1201  const Row& tableau_i = tableau[i];
1202  Row::const_iterator j = tableau_i.begin();
1203  Row::const_iterator j_end = tableau_i.end();
1204  std::vector<std::pair<dimension_type, Coefficient> >::iterator
1205  k = columns.begin();
1206  std::vector<std::pair<dimension_type, Coefficient> >::iterator
1207  k_end = columns.end();
1208  while (j != j_end) {
1209  while (k != k_end && j.index() > k->first) {
1210  ++k;
1211  }
1212  if (k == k_end) {
1213  break;
1214  }
1215  PPL_ASSERT(j.index() <= k->first);
1216  if (j.index() < k->first) {
1217  j = tableau_i.lower_bound(j, k->first);
1218  }
1219  else {
1220  Coefficient_traits::const_reference tableau_ij = *j;
1221  WEIGHT_BEGIN();
1222 #if PPL_USE_SPARSE_MATRIX
1223  scalar_value = tableau_ij * norm_factor[i];
1224  add_mul_assign(k->second, scalar_value, scalar_value);
1225 #else
1226  // The test against 0 gives rise to a consistent speed up in the dense
1227  // implementation: see
1228  // http://www.cs.unipr.it/pipermail/ppl-devel/2009-February/
1229  // 014000.html
1230  if (tableau_ij != 0) {
1231  scalar_value = tableau_ij * norm_factor[i];
1232  add_mul_assign(k->second, scalar_value, scalar_value);
1233  }
1234 #endif
1235  WEIGHT_ADD_MUL(47, tableau_num_rows);
1236  ++k;
1237  ++j;
1238  }
1239  }
1240  }
1242  for (std::vector<std::pair<dimension_type, Coefficient> >::reverse_iterator
1243  k = columns.rbegin(), k_end = columns.rend(); k != k_end; ++k) {
1244  itr = working_cost.lower_bound(itr, k->first);
1245  if (itr != working_cost.end() && itr.index() == k->first) {
1246  // We cannot compute the (exact) square root of abs(\Delta x_j).
1247  // The workaround is to compute the square of `cost[j]'.
1248  challenger_numer = (*itr) * (*itr);
1249  // Initialization during the first loop.
1250  if (entering_index == 0) {
1251  swap(current_numer, challenger_numer);
1252  swap(current_denom, k->second);
1253  entering_index = k->first;
1254  continue;
1255  }
1256  challenger_value = challenger_numer * current_denom;
1257  current_value = current_numer * k->second;
1258  // Update the values, if the challenger wins.
1259  if (challenger_value > current_value) {
1260  swap(current_numer, challenger_numer);
1261  swap(current_denom, k->second);
1262  entering_index = k->first;
1263  }
1264  }
1265  else {
1266  PPL_ASSERT(working_cost.get(k->first) == 0);
1267  // Initialization during the first loop.
1268  if (entering_index == 0) {
1269  current_numer = 0;
1270  swap(current_denom, k->second);
1271  entering_index = k->first;
1272  continue;
1273  }
1274  // Update the values, if the challenger wins.
1275  if (0 > sgn(current_numer) * sgn(k->second)) {
1276  current_numer = 0;
1277  swap(current_denom, k->second);
1278  entering_index = k->first;
1279  }
1280  }
1281  }
1282 
1283 #else // !PPL_USE_SPARSE_MATRIX
1284 
1285  PPL_DIRTY_TEMP_COEFFICIENT(challenger_denom);
1286  for (dimension_type j = tableau.num_columns() - 1; j-- > 1; ) {
1287  Coefficient_traits::const_reference cost_j = working_cost[j];
1288  if (sgn(cost_j) == cost_sign) {
1289  WEIGHT_BEGIN();
1290  // We cannot compute the (exact) square root of abs(\Delta x_j).
1291  // The workaround is to compute the square of `cost[j]'.
1292  challenger_numer = cost_j * cost_j;
1293  // Due to our integer implementation, the `1' term in the denominator
1294  // of the original formula has to be replaced by `squared_lcm_basis'.
1295  challenger_denom = squared_lcm_basis;
1296  for (dimension_type i = tableau_num_rows; i-- > 0; ) {
1297  Coefficient_traits::const_reference tableau_ij = tableau[i][j];
1298  // The test against 0 gives rise to a consistent speed up: see
1299  // http://www.cs.unipr.it/pipermail/ppl-devel/2009-February/
1300  // 014000.html
1301  if (tableau_ij != 0) {
1302  scalar_value = tableau_ij * norm_factor[i];
1303  add_mul_assign(challenger_denom, scalar_value, scalar_value);
1304  }
1305  }
1306  // Initialization during the first loop.
1307  if (entering_index == 0) {
1308  swap(current_numer, challenger_numer);
1309  swap(current_denom, challenger_denom);
1310  entering_index = j;
1311  continue;
1312  }
1313  challenger_value = challenger_numer * current_denom;
1314  current_value = current_numer * challenger_denom;
1315  // Update the values, if the challenger wins.
1316  if (challenger_value > current_value) {
1317  swap(current_numer, challenger_numer);
1318  swap(current_denom, challenger_denom);
1319  entering_index = j;
1320  }
1321  WEIGHT_ADD_MUL(47, tableau_num_rows);
1322  }
1323  }
1324 
1325 #endif // !PPL_USE_SPARSE_MATRIX
1326 
1327  return entering_index;
1328 }
iterator find(dimension_type i)
Looks for an element with index i.
void swap(CO_Tree &x, CO_Tree &y)
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type size() const
Returns the size of the row.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
void swap(MIP_Problem &x, MIP_Problem &y)
Swaps x with y.
void add_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
working_cost_type working_cost
The working cost function.
void lcm_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
const iterator & end()
Returns an iterator that points after the last stored element.
void exact_div_assign(Checked_Number< T, Policy > &x, const Checked_Number< T, Policy > &y, const Checked_Number< T, Policy > &z)
std::vector< dimension_type > base
The current basic solution.
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
#define WEIGHT_ADD_MUL(delta, factor)
Definition: globals_defs.hh:90
#define WEIGHT_BEGIN()
Definition: globals_defs.hh:81
iterator lower_bound(dimension_type i)
Lower bound of index i.
int sgn(Boundary_Type type, const T &x, const Info &info)
dimension_type index() const
Returns the index of the element pointed to by *this.
CO_Tree::const_iterator const_iterator
A const iterator on the row elements.
Coefficient_traits::const_reference get(dimension_type i) const
Gets the i-th element in the sequence.
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 1009 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::Boundary_NS::assign(), Parma_Polyhedra_Library::Sparse_Row::begin(), Parma_Polyhedra_Library::Sparse_Row::end(), Parma_Polyhedra_Library::Sparse_Row::get(), Parma_Polyhedra_Library::CO_Tree::const_iterator::index(), Parma_Polyhedra_Library::CO_Tree::iterator::index(), Parma_Polyhedra_Library::Sparse_Row::lower_bound(), Parma_Polyhedra_Library::Boundary_NS::sgn(), WEIGHT_ADD, WEIGHT_ADD_MUL, and WEIGHT_BEGIN.

1009  {
1010  const dimension_type tableau_num_rows = tableau.num_rows();
1011  const dimension_type tableau_num_columns = tableau.num_columns();
1012  PPL_ASSERT(tableau_num_rows == base.size());
1013  double current_value = 0.0;
1014  // Due to our integer implementation, the `1' term in the denominator
1015  // of the original formula has to be replaced by `squared_lcm_basis'.
1016  double float_tableau_value;
1017  double float_tableau_denom;
1018  dimension_type entering_index = 0;
1019  const int cost_sign = sgn(working_cost.get(working_cost.size() - 1));
1020 
1021  // These two implementation work for both sparse and dense matrices.
1022  // However, when using sparse matrices the first one is fast and the second
1023  // one is slow, and when using dense matrices the first one is slow and
1024  // the second one is fast.
1025 #if PPL_USE_SPARSE_MATRIX
1026 
1027  const dimension_type tableau_num_columns_minus_1 = tableau_num_columns - 1;
1028  // This is static to improve performance.
1029  // A vector of <column_index, challenger_denom> pairs, ordered by
1030  // column_index.
1031  static std::vector<std::pair<dimension_type, double> > columns;
1032  columns.clear();
1033  // (working_cost.size() - 2) is an upper bound only.
1034  columns.reserve(working_cost.size() - 2);
1035  {
1037  // Note that find() is used instead of lower_bound().
1039  = working_cost.find(tableau_num_columns_minus_1);
1040  for ( ; i != i_end; ++i) {
1041  if (sgn(*i) == cost_sign) {
1042  columns.push_back(std::make_pair(i.index(), 1.0));
1043  }
1044  }
1045  }
1046  for (dimension_type i = tableau_num_rows; i-- > 0; ) {
1047  const Row& tableau_i = tableau[i];
1048  assign(float_tableau_denom, tableau_i.get(base[i]));
1049  Row::const_iterator j = tableau_i.begin();
1050  Row::const_iterator j_end = tableau_i.end();
1051  std::vector<std::pair<dimension_type, double> >::iterator k
1052  = columns.begin();
1053  std::vector<std::pair<dimension_type, double> >::iterator k_end
1054  = columns.end();
1055  while (j != j_end && k != k_end) {
1056  const dimension_type column = j.index();
1057  while (k != k_end && column > k->first) {
1058  ++k;
1059  }
1060  if (k == k_end) {
1061  break;
1062  }
1063  if (k->first > column) {
1064  j = tableau_i.lower_bound(j, k->first);
1065  }
1066  else {
1067  PPL_ASSERT(k->first == column);
1068  PPL_ASSERT(tableau_i.get(base[i]) != 0);
1069  WEIGHT_BEGIN();
1070  assign(float_tableau_value, *j);
1071  float_tableau_value /= float_tableau_denom;
1072  float_tableau_value *= float_tableau_value;
1073  k->second += float_tableau_value;
1074  WEIGHT_ADD(22);
1075  ++j;
1076  ++k;
1077  }
1078  }
1079  }
1080  // The candidates are processed backwards to get the same result in both
1081  // this implementation and the dense implementation below.
1082  for (std::vector<std::pair<dimension_type, double> >::const_reverse_iterator
1083  i = columns.rbegin(), i_end = columns.rend(); i != i_end; ++i) {
1084  const double challenger_value = sqrt(i->second);
1085  if (entering_index == 0 || challenger_value > current_value) {
1086  current_value = challenger_value;
1087  entering_index = i->first;
1088  }
1089  }
1090 
1091 #else // !PPL_USE_SPARSE_MATRIX
1092 
1093  double challenger_numer = 0.0;
1094  double challenger_denom = 0.0;
1095  for (dimension_type j = tableau_num_columns - 1; j-- > 1; ) {
1096  Coefficient_traits::const_reference cost_j = working_cost.get(j);
1097  if (sgn(cost_j) == cost_sign) {
1098  WEIGHT_BEGIN();
1099  // We cannot compute the (exact) square root of abs(\Delta x_j).
1100  // The workaround is to compute the square of `cost[j]'.
1101  assign(challenger_numer, cost_j);
1102  challenger_numer = std::abs(challenger_numer);
1103  // Due to our integer implementation, the `1' term in the denominator
1104  // of the original formula has to be replaced by `squared_lcm_basis'.
1105  challenger_denom = 1.0;
1106  for (dimension_type i = tableau_num_rows; i-- > 0; ) {
1107  const Row& tableau_i = tableau[i];
1108  Coefficient_traits::const_reference tableau_ij = tableau_i[j];
1109  if (tableau_ij != 0) {
1110  PPL_ASSERT(tableau_i[base[i]] != 0);
1111  assign(float_tableau_value, tableau_ij);
1112  assign(float_tableau_denom, tableau_i[base[i]]);
1113  float_tableau_value /= float_tableau_denom;
1114  challenger_denom += float_tableau_value * float_tableau_value;
1115  }
1116  }
1117  double challenger_value = sqrt(challenger_denom);
1118  // Initialize `current_value' during the first iteration.
1119  // Otherwise update if the challenger wins.
1120  if (entering_index == 0 || challenger_value > current_value) {
1121  current_value = challenger_value;
1122  entering_index = j;
1123  }
1124  WEIGHT_ADD_MUL(10, tableau_num_rows);
1125  }
1126  }
1127 
1128 #endif // !PPL_USE_SPARSE_MATRIX
1129 
1130  return entering_index;
1131 }
iterator find(dimension_type i)
Looks for an element with index i.
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type size() const
Returns the size of the row.
working_cost_type working_cost
The working cost function.
#define WEIGHT_ADD(delta)
Definition: globals_defs.hh:83
std::vector< dimension_type > base
The current basic solution.
Result assign(Boundary_Type to_type, To &to, To_Info &to_info, Boundary_Type type, const T &x, const Info &info, bool should_shrink=false)
Matrix< Row > tableau
The matrix encoding the current feasible region in tableau form.
#define WEIGHT_ADD_MUL(delta, factor)
Definition: globals_defs.hh:90
#define WEIGHT_BEGIN()
Definition: globals_defs.hh:81
iterator lower_bound(dimension_type i)
Lower bound of index i.
int sgn(Boundary_Type type, const T &x, const Info &info)
CO_Tree::const_iterator const_iterator
A const iterator on the row elements.
Coefficient_traits::const_reference get(dimension_type i) const
Gets the i-th element in the sequence.
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 1333 of file MIP_Problem.cc.

References Parma_Polyhedra_Library::CO_Tree::const_iterator::index(), and Parma_Polyhedra_Library::Boundary_NS::sgn().

1333  {
1334  // The variable entering the base is the first one whose coefficient
1335  // in the cost function has the same sign the cost function itself.
1336  // If no such variable exists, then we met the optimality condition
1337  // (and return 0 to the caller).
1338 
1339  // Get the "sign" of the cost function.
1340  const dimension_type cost_sign_index = working_cost.size() - 1;
1341  const int cost_sign = sgn(working_cost.get(cost_sign_index));
1342  PPL_ASSERT(cost_sign != 0);
1343 
1345  // Note that find() is used instead of lower_bound() because they are
1346  // equivalent when searching the last element in the row.
1348  = working_cost.find(cost_sign_index);
1349  for ( ; i != i_end; ++i) {
1350  if (sgn(*i) == cost_sign) {
1351  return i.index();
1352  }
1353  }
1354  // No variable has to enter the base:
1355  // the cost function was optimized.
1356  return 0;
1357 }
iterator find(dimension_type i)
Looks for an element with index i.
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type size() const
Returns the size of the row.
working_cost_type working_cost
The working cost function.
iterator lower_bound(dimension_type i)
Lower bound of index i.
int sgn(Boundary_Type type, const T &x, const Info &info)
dimension_type index() const
Returns the index of the element pointed to by *this.
CO_Tree::const_iterator const_iterator
A const iterator on the row elements.
Coefficient_traits::const_reference get(dimension_type i) const
Gets the i-th element in the sequence.
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 236 of file MIP_Problem_inlines.hh.

References external_memory_in_bytes().

236  {
237  return sizeof(*this) + external_memory_in_bytes();
238 }
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.

Friends And Related Function Documentation

std::ostream & operator<< ( std::ostream &  s,
const MIP_Problem mip 
)
related

Output operator.

std::ostream & operator<< ( std::ostream &  s,
const MIP_Problem mip 
)
related

Definition at line 2888 of file MIP_Problem.cc.

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

2888  {
2889  s << "Constraints:";
2890  for (MIP_Problem::const_iterator i = mip.constraints_begin(),
2891  i_end = mip.constraints_end(); i != i_end; ++i) {
2892  s << "\n" << *i;
2893  }
2894  s << "\nObjective function: "
2895  << mip.objective_function()
2896  << "\nOptimization mode: "
2897  << ((mip.optimization_mode() == MAXIMIZATION)
2898  ? "MAXIMIZATION"
2899  : "MINIMIZATION");
2900  s << "\nInteger variables: " << mip.integer_space_dimensions();
2901  return s;
2902 }
Maximization is requested.
friend struct RAII_Temporary_Real_Relaxation
friend

Definition at line 620 of file MIP_Problem_defs.hh.

void swap ( MIP_Problem x,
MIP_Problem y 
)
related

Definition at line 320 of file MIP_Problem_inlines.hh.

References m_swap().

320  {
321  x.m_swap(y);
322 }

Member Data Documentation

std::vector<dimension_type> Parma_Polyhedra_Library::MIP_Problem::base
private

The current basic solution.

Definition at line 533 of file MIP_Problem_defs.hh.

Referenced by external_memory_in_bytes(), and m_swap().

dimension_type Parma_Polyhedra_Library::MIP_Problem::external_space_dim
private

The dimension of the vector space.

Definition at line 499 of file MIP_Problem_defs.hh.

Referenced by is_lp_satisfiable(), m_swap(), MIP_Problem(), and space_dimension().

dimension_type Parma_Polyhedra_Library::MIP_Problem::first_pending_constraint
private

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

Definition at line 585 of file MIP_Problem_defs.hh.

Referenced by is_lp_satisfiable(), and m_swap().

Variables_Set Parma_Polyhedra_Library::MIP_Problem::i_variables
private
dimension_type Parma_Polyhedra_Library::MIP_Problem::inherited_constraints
private

The number of constraints that are inherited from our parent in the recursion tree built when solving via branch-and-bound.

The first inherited_constraints elements in input_cs point to the inherited constraints, whose resources are owned by our ancestors. The resources of the other elements in input_cs are owned by *this and should be appropriately released on destruction.

Definition at line 582 of file MIP_Problem_defs.hh.

Referenced by external_memory_in_bytes(), m_swap(), and ~MIP_Problem().

bool Parma_Polyhedra_Library::MIP_Problem::initialized
private

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 568 of file MIP_Problem_defs.hh.

Referenced by is_lp_satisfiable(), and m_swap().

std::vector<Constraint*> Parma_Polyhedra_Library::MIP_Problem::input_cs
private

The sequence of constraints describing the feasible region.

Definition at line 571 of file MIP_Problem_defs.hh.

Referenced by add_constraint_helper(), choose_branching_variable(), constraints_begin(), constraints_end(), external_memory_in_bytes(), m_swap(), MIP_Problem(), and ~MIP_Problem().

Linear_Expression Parma_Polyhedra_Library::MIP_Problem::input_obj_function
private

The objective function to be optimized.

Definition at line 588 of file MIP_Problem_defs.hh.

Referenced by external_memory_in_bytes(), m_swap(), and objective_function().

dimension_type Parma_Polyhedra_Library::MIP_Problem::internal_space_dim
private

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

Definition at line 505 of file MIP_Problem_defs.hh.

Referenced by is_lp_satisfiable(), and m_swap().

Generator Parma_Polyhedra_Library::MIP_Problem::last_generator
private

The last successfully computed feasible or optimizing point.

Definition at line 594 of file MIP_Problem_defs.hh.

Referenced by choose_branching_variable(), compute_generator(), external_memory_in_bytes(), is_mip_satisfiable(), is_satisfiable(), m_swap(), solve(), and solve_mip().

std::vector<std::pair<dimension_type, dimension_type> > Parma_Polyhedra_Library::MIP_Problem::mapping
private

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; if mapping[i].second is not a zero, it 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 530 of file MIP_Problem_defs.hh.

Referenced by external_memory_in_bytes(), is_lp_satisfiable(), and m_swap().

Optimization_Mode Parma_Polyhedra_Library::MIP_Problem::opt_mode
private

The optimization mode requested.

Definition at line 591 of file MIP_Problem_defs.hh.

Referenced by m_swap(), optimization_mode(), and set_optimization_mode().

Control_Parameter_Value Parma_Polyhedra_Library::MIP_Problem::pricing
private

The pricing method in use.

Definition at line 561 of file MIP_Problem_defs.hh.

Referenced by get_control_parameter(), m_swap(), and set_control_parameter().

Status Parma_Polyhedra_Library::MIP_Problem::status
private

The internal state of the MIP problem.

Definition at line 554 of file MIP_Problem_defs.hh.

Referenced by is_satisfiable(), m_swap(), set_optimization_mode(), solve(), and solve_mip().

Matrix<Row> Parma_Polyhedra_Library::MIP_Problem::tableau
private

The matrix encoding the current feasible region in tableau form.

Definition at line 514 of file MIP_Problem_defs.hh.

Referenced by external_memory_in_bytes(), is_lp_satisfiable(), and m_swap().

working_cost_type Parma_Polyhedra_Library::MIP_Problem::working_cost
private

The working cost function.

Definition at line 519 of file MIP_Problem_defs.hh.

Referenced by external_memory_in_bytes(), and m_swap().


The documentation for this class was generated from the following files: