A Mixed Integer (linear) Programming problem. More...
#include <MIP_Problem.defs.hh>

Classes | |
| struct | RAII_Temporary_Real_Relaxation |
| A helper class to temporarily relax a MIP problem using RAII. More... | |
Public Types | |
| enum | Control_Parameter_Name { PRICING } |
Names of MIP problems' control parameters. More... | |
| enum | Control_Parameter_Value { PRICING_STEEPEST_EDGE_FLOAT, PRICING_STEEPEST_EDGE_EXACT, PRICING_TEXTBOOK } |
Possible values for MIP problem's control parameters. More... | |
| typedef Constraint_Sequence::const_iterator | const_iterator |
| A type alias for the read-only iterator on the constraints defining the feasible region. | |
Public Member Functions | |
| MIP_Problem (dimension_type dim=0) | |
| Builds a trivial MIP problem. | |
| template<typename In > | |
| MIP_Problem (dimension_type dim, In first, In last, const Variables_Set &int_vars, const Linear_Expression &obj=Linear_Expression::zero(), Optimization_Mode mode=MAXIMIZATION) | |
Builds an MIP problem having space dimension dim from the sequence of constraints in the range , the objective function obj and optimization mode mode; those dimensions whose indices occur in int_vars are constrained to take an integer value. | |
| template<typename In > | |
| MIP_Problem (dimension_type dim, In first, In last, const Linear_Expression &obj=Linear_Expression::zero(), Optimization_Mode mode=MAXIMIZATION) | |
Builds an MIP problem having space dimension dim from the sequence of constraints in the range , the objective function obj and optimization mode mode. | |
| MIP_Problem (dimension_type dim, const Constraint_System &cs, const Linear_Expression &obj=Linear_Expression::zero(), Optimization_Mode mode=MAXIMIZATION) | |
Builds an MIP problem having space dimension dim from the constraint system cs, the objective function obj and optimization mode mode. | |
| MIP_Problem (const MIP_Problem &y) | |
| Ordinary copy constructor. | |
| ~MIP_Problem () | |
| Destructor. | |
| MIP_Problem & | operator= (const MIP_Problem &y) |
| Assignment operator. | |
| dimension_type | space_dimension () const |
| Returns the space dimension of the MIP problem. | |
| const Variables_Set & | integer_space_dimensions () const |
| Returns a set containing all the variables' indexes constrained to be integral. | |
| const_iterator | constraints_begin () const |
| Returns a read-only iterator to the first constraint defining the feasible region. | |
| const_iterator | constraints_end () const |
| Returns a past-the-end read-only iterator to the sequence of constraints defining the feasible region. | |
| const Linear_Expression & | objective_function () const |
| Returns the objective function. | |
| Optimization_Mode | optimization_mode () const |
| Returns the optimization mode. | |
| void | clear () |
Resets *this to be equal to the trivial MIP problem. | |
| void | add_space_dimensions_and_embed (dimension_type m) |
Adds m new space dimensions and embeds the old MIP problem in the new vector space. | |
| void | add_to_integer_space_dimensions (const Variables_Set &i_vars) |
Sets the variables whose indexes are in set i_vars to be integer space dimensions. | |
| void | add_constraint (const Constraint &c) |
Adds a copy of constraint c to the MIP problem. | |
| void | add_constraints (const Constraint_System &cs) |
Adds a copy of the constraints in cs to the MIP problem. | |
| void | set_objective_function (const Linear_Expression &obj) |
Sets the objective function to obj. | |
| void | set_optimization_mode (Optimization_Mode mode) |
Sets the optimization mode to mode. | |
| bool | is_satisfiable () const |
Checks satisfiability of *this. | |
| MIP_Problem_Status | solve () const |
| Optimizes the MIP problem. | |
| void | evaluate_objective_function (const Generator &evaluating_point, Coefficient &num, Coefficient &den) const |
Sets num and den so that is the result of evaluating the objective function on evaluating_point. | |
| const Generator & | feasible_point () const |
Returns a feasible point for *this, if it exists. | |
| const Generator & | optimizing_point () const |
Returns an optimal point for *this, if it exists. | |
| void | optimal_value (Coefficient &num, Coefficient &den) const |
Sets num and den so that is the solution of the optimization problem. | |
| bool | OK () const |
| Checks if all the invariants are satisfied. | |
| void | ascii_dump () const |
Writes to std::cerr an ASCII representation of *this. | |
| void | ascii_dump (std::ostream &s) const |
Writes to s an ASCII representation of *this. | |
| void | print () const |
Prints *this to std::cerr using operator<<. | |
| bool | ascii_load (std::istream &s) |
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this accordingly. Returns true if successful, false otherwise. | |
| memory_size_type | total_memory_in_bytes () const |
Returns the total size in bytes of the memory occupied by *this. | |
| memory_size_type | external_memory_in_bytes () const |
Returns the size in bytes of the memory managed by *this. | |
| void | swap (MIP_Problem &y) |
Swaps *this with y. | |
| Control_Parameter_Value | get_control_parameter (Control_Parameter_Name name) const |
Returns the value of the control parameter name. | |
| void | set_control_parameter (Control_Parameter_Value value) |
Sets control parameter value. | |
Static Public Member Functions | |
| static dimension_type | max_space_dimension () |
| Returns the maximum space dimension an MIP_Problem can handle. | |
Private Types | |
| enum | Status { UNSATISFIABLE, SATISFIABLE, UNBOUNDED, OPTIMIZED, PARTIALLY_SATISFIABLE } |
An enumerated type describing the internal status of the MIP problem. More... | |
| typedef std::vector< Constraint > | Constraint_Sequence |
| A type alias for a sequence of constraints. | |
Private Member Functions | |
| bool | process_pending_constraints () |
Processes the pending constraints of *this. | |
| void | second_phase () |
| Optimizes the MIP problem using the second phase of the primal simplex algorithm. | |
| MIP_Problem_Status | compute_tableau (std::vector< dimension_type > &worked_out_row) |
Assigns to this->tableau a simplex tableau representing the MIP problem, inserting into this->mapping the information that is required to recover the original MIP problem. | |
| bool | parse_constraints (dimension_type &additional_tableau_rows, dimension_type &additional_slack_variables, std::deque< bool > &is_tableau_constraint, std::deque< bool > &is_satisfied_inequality, std::deque< bool > &is_nonnegative_variable, std::deque< bool > &is_remergeable_variable) const |
| Parses the pending constraints to gather information on how to resize the tableau. | |
| dimension_type | get_exiting_base_index (dimension_type entering_var_index) const |
| Computes the row index of the variable exiting the base of the MIP problem. Implemented with anti-cycling rule. | |
| void | pivot (dimension_type entering_var_index, dimension_type exiting_base_index) |
| Performs the pivoting operation on the tableau. | |
| dimension_type | textbook_entering_index () const |
| Computes the column index of the variable entering the base, using the textbook algorithm with anti-cycling rule. | |
| dimension_type | steepest_edge_exact_entering_index () const |
| Computes the column index of the variable entering the base, using an exact steepest-edge algorithm with anti-cycling rule. | |
| dimension_type | steepest_edge_float_entering_index () const |
| Same as steepest_edge_exact_entering_index, but using floating points. | |
| bool | compute_simplex_using_exact_pricing () |
Returns true if and if only the algorithm successfully computed a feasible solution. | |
| bool | compute_simplex_using_steepest_edge_float () |
Returns true if and if only the algorithm successfully computed a feasible solution. | |
| void | erase_artificials (dimension_type begin_artificials, dimension_type end_artificials) |
| Drop unnecessary artificial variables from the tableau and get ready for the second phase of the simplex algorithm. | |
| bool | is_in_base (dimension_type var_index, dimension_type &row_index) const |
| void | compute_generator () const |
Computes a valid generator that satisfies all the constraints of the Linear Programming problem associated to *this. | |
| dimension_type | merge_split_variable (dimension_type var_index) |
| Merges back the positive and negative part of a (previously split) variable after detecting a corresponding nonnegativity constraint. | |
| bool | is_lp_satisfiable () const |
Returns true if and if only the LP problem is satisfiable. | |
Static Private Member Functions | |
| static void | linear_combine (Row &x, const Row &y, const dimension_type k) |
Linearly combines x with y so that *this[k] is 0. | |
| static bool | is_satisfied (const Constraint &c, const Generator &g) |
Returns true if and only if c is satisfied by g. | |
| static bool | is_saturated (const Constraint &c, const Generator &g) |
Returns true if and only if c is saturated by g. | |
| static MIP_Problem_Status | solve_mip (bool &have_incumbent_solution, mpq_class &incumbent_solution_value, Generator &incumbent_solution_point, MIP_Problem &mip, const Variables_Set &i_vars) |
| Returns a status that encodes the solution of the MIP problem. | |
| static bool | is_mip_satisfiable (MIP_Problem &lp, const Variables_Set &i_vars, Generator &p) |
Returns true if and if only the LP problem lp is satisfiable when variables in i_vars can only take integral values. | |
| static bool | choose_branching_variable (const MIP_Problem &lp, const Variables_Set &i_vars, dimension_type &branching_index) |
Returns true if and if only mip.last_generator satisfies all the integrality coditions implicitly stated using by i_vars. | |
Private Attributes | |
| dimension_type | external_space_dim |
| The dimension of the vector space. | |
| dimension_type | internal_space_dim |
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than external_space_dim. | |
| Matrix | tableau |
| The matrix encoding the current feasible region in tableau form. | |
| Row | working_cost |
| The working cost function. | |
| std::vector< std::pair < dimension_type, dimension_type > > | mapping |
| A map between the variables of `input_cs' and `tableau'. | |
| std::vector< dimension_type > | base |
| The current basic solution. | |
| Status | status |
| The internal state of the MIP problem. | |
| Control_Parameter_Value | pricing |
| The pricing method in use. | |
| bool | initialized |
| A Boolean encoding whether or not internal data structures have already been properly sized and populated: useful to allow for deeper checks in method OK(). | |
| Constraint_Sequence | input_cs |
| The sequence of constraints describing the feasible region. | |
| dimension_type | first_pending_constraint |
| The first index of `input_cs' containing a pending constraint. | |
| Linear_Expression | input_obj_function |
| The objective function to be optimized. | |
| Optimization_Mode | opt_mode |
| The optimization mode requested. | |
| Generator | last_generator |
| The last successfully computed feasible or optimizing point. | |
| Variables_Set | i_variables |
| A set containing all the indexes of variables that are constrained to have an integer value. | |
Friends | |
| class | RAII_Temporary_Real_Relaxation |
Related Functions | |
(Note that these are not member functions.) | |
| std::ostream & | operator<< (std::ostream &s, const MIP_Problem &lp) |
| Output operator. | |
| void | swap (Parma_Polyhedra_Library::MIP_Problem &x, Parma_Polyhedra_Library::MIP_Problem &y) |
Specializes std::swap. | |
A Mixed Integer (linear) Programming problem.
An object of this class encodes a mixed integer (linear) programming problem. The MIP problem is specified by providing:
The class provides support for the (incremental) solution of the MIP problem based on variations of the revised simplex method and on branch-and-bound techniques. The result of the resolution process is expressed in terms of an enumeration, encoding the feasibility and the unboundedness of the optimization problem. The class supports simple feasibility tests (i.e., no optimization), as well as the extraction of an optimal (resp., feasible) point, provided the MIP_Problem is optimizable (resp., feasible).
By exploiting the incremental nature of the solver, it is possible to reuse part of the computational work already done when solving variants of a given MIP_Problem: currently, incremental resolution supports the addition of space dimensions, the addition of constraints, the change of objective function and the change of optimization mode.
Definition at line 80 of file MIP_Problem.defs.hh.
| typedef Constraint_Sequence::const_iterator Parma_Polyhedra_Library::MIP_Problem::const_iterator |
A type alias for the read-only iterator on the constraints defining the feasible region.
Definition at line 237 of file MIP_Problem.defs.hh.
typedef std::vector<Constraint> Parma_Polyhedra_Library::MIP_Problem::Constraint_Sequence [private] |
A type alias for a sequence of constraints.
Definition at line 230 of file MIP_Problem.defs.hh.
Names of MIP problems' control parameters.
Definition at line 402 of file MIP_Problem.defs.hh.
00402 { 00404 PRICING 00405 };
Possible values for MIP problem's control parameters.
Definition at line 408 of file MIP_Problem.defs.hh.
00408 { 00410 PRICING_STEEPEST_EDGE_FLOAT, 00412 PRICING_STEEPEST_EDGE_EXACT, 00414 PRICING_TEXTBOOK 00415 };
enum Parma_Polyhedra_Library::MIP_Problem::Status [private] |
An enumerated type describing the internal status of the MIP problem.
Definition at line 454 of file MIP_Problem.defs.hh.
00454 { 00456 UNSATISFIABLE, 00458 SATISFIABLE, 00460 UNBOUNDED, 00462 OPTIMIZED, 00468 PARTIALLY_SATISFIABLE 00469 };
| 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
on a vector space under no constraints at all: the origin of the vector space is an optimal solution.
| dim | The dimension of the vector space enclosing *this (optional argument with default value ). |
| std::length_error | Thrown if dim exceeds max_space_dimension(). |
Definition at line 65 of file MIP_Problem.cc.
References max_space_dimension(), and OK().
00066 : external_space_dim(dim), 00067 internal_space_dim(0), 00068 tableau(), 00069 working_cost(0, Row::Flags()), 00070 mapping(), 00071 base(), 00072 status(PARTIALLY_SATISFIABLE), 00073 pricing(PRICING_STEEPEST_EDGE_FLOAT), 00074 initialized(false), 00075 input_cs(), 00076 first_pending_constraint(0), 00077 input_obj_function(), 00078 opt_mode(MAXIMIZATION), 00079 last_generator(point()), 00080 i_variables() { 00081 // Check for space dimension overflow. 00082 if (dim > max_space_dimension()) 00083 throw std::length_error("PPL::MIP_Problem::MIP_Problem(dim, cs, obj, " 00084 "mode):\n" 00085 "dim exceeds the maximum allowed " 00086 "space dimension."); 00087 PPL_ASSERT(OK()); 00088 }
| Parma_Polyhedra_Library::MIP_Problem::MIP_Problem | ( | dimension_type | dim, | |
| In | first, | |||
| In | last, | |||
| const Variables_Set & | int_vars, | |||
| const Linear_Expression & | obj = Linear_Expression::zero(), |
|||
| Optimization_Mode | mode = MAXIMIZATION | |||
| ) | [inline] |
Builds an MIP problem having space dimension dim from the sequence of constraints in the range
, the objective function obj and optimization mode mode; those dimensions whose indices occur in int_vars are constrained to take an integer value.
| dim | The dimension of the vector space enclosing *this. | |
| first | An input iterator to the start of the sequence of constraints. | |
| last | A past-the-end input iterator to the sequence of constraints. | |
| int_vars | The set of variables' indexes that are constrained to take integer values. | |
| obj | The objective function (optional argument with default value ). | |
| mode | The optimization mode (optional argument with default value MAXIMIZATION). |
| std::length_error | Thrown if dim exceeds max_space_dimension(). | |
| std::invalid_argument | Thrown if a constraint in the sequence is a strict inequality, if the space dimension of a constraint (resp., of the objective function or of the integer variables) or the space dimension of the integer variable set is strictly greater than dim. |
Definition at line 32 of file MIP_Problem.templates.hh.
References external_space_dim, i_variables, input_cs, max_space_dimension(), OK(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), and Parma_Polyhedra_Library::Variables_Set::space_dimension().
00038 : external_space_dim(dim), 00039 internal_space_dim(0), 00040 tableau(), 00041 working_cost(0, Row::Flags()), 00042 mapping(), 00043 base(), 00044 status(PARTIALLY_SATISFIABLE), 00045 pricing(PRICING_STEEPEST_EDGE_FLOAT), 00046 initialized(false), 00047 input_cs(), 00048 first_pending_constraint(0), 00049 input_obj_function(obj), 00050 opt_mode(mode), 00051 last_generator(point()), 00052 i_variables(int_vars) { 00053 // Check that integer Variables_Set does not exceed the space dimension 00054 // of the problem. 00055 if (i_variables.space_dimension() > external_space_dim) { 00056 std::ostringstream s; 00057 s << "PPL::MIP_Problem::MIP_Problem" 00058 << "(dim, first, last, int_vars, obj, mode):\n" 00059 << "dim == "<< external_space_dim << " and int_vars.space_dimension() ==" 00060 << " " << i_variables.space_dimension() << " are dimension" 00061 "incompatible."; 00062 throw std::invalid_argument(s.str()); 00063 } 00064 00065 // Check for space dimension overflow. 00066 if (dim > max_space_dimension()) 00067 throw std::length_error("PPL::MIP_Problem:: MIP_Problem(dim, first, " 00068 "last, int_vars, obj, mode):\n" 00069 "dim exceeds the maximum allowed" 00070 "space dimension."); 00071 // Check the objective function. 00072 if (obj.space_dimension() > dim) { 00073 std::ostringstream s; 00074 s << "PPL::MIP_Problem::MIP_Problem(dim, first, last," 00075 << "int_vars, obj, mode):\n" 00076 << "obj.space_dimension() == "<< obj.space_dimension() 00077 << " exceeds d == "<< dim << "."; 00078 throw std::invalid_argument(s.str()); 00079 } 00080 // Check the constraints. 00081 for (In i = first; i != last; ++i) { 00082 if (i->is_strict_inequality()) 00083 throw std::invalid_argument("PPL::MIP_Problem::" 00084 "MIP_Problem(dim, first, last, int_vars," 00085 "obj, mode):\nrange [first, last) contains" 00086 "a strict inequality constraint."); 00087 if (i->space_dimension() > dim) { 00088 std::ostringstream s; 00089 s << "PPL::MIP_Problem::" 00090 << "MIP_Problem(dim, first, last, int_vars, obj, mode):\n" 00091 << "range [first, last) contains a constraint having space" 00092 << "dimension == " << i->space_dimension() << " that exceeds" 00093 "this->space_dimension == " << dim << "."; 00094 throw std::invalid_argument(s.str()); 00095 } 00096 input_cs.push_back(*i); 00097 } 00098 PPL_ASSERT(OK()); 00099 }
| Parma_Polyhedra_Library::MIP_Problem::MIP_Problem | ( | dimension_type | dim, | |
| In | first, | |||
| In | last, | |||
| const Linear_Expression & | obj = Linear_Expression::zero(), |
|||
| Optimization_Mode | mode = MAXIMIZATION | |||
| ) | [inline] |
Builds an MIP problem having space dimension dim from the sequence of constraints in the range
, the objective function obj and optimization mode mode.
| dim | The dimension of the vector space enclosing *this. | |
| first | An input iterator to the start of the sequence of constraints. | |
| last | A past-the-end input iterator to the sequence of constraints. | |
| obj | The objective function (optional argument with default value ). | |
| mode | The optimization mode (optional argument with default value MAXIMIZATION). |
| std::length_error | Thrown if dim exceeds max_space_dimension(). | |
| std::invalid_argument | Thrown if a constraint in the sequence is a strict inequality or if the space dimension of a constraint (resp., of the objective function or of the integer variables) is strictly greater than dim. |
Definition at line 102 of file MIP_Problem.templates.hh.
References input_cs, max_space_dimension(), OK(), and Parma_Polyhedra_Library::Linear_Expression::space_dimension().
00106 : external_space_dim(dim), 00107 internal_space_dim(0), 00108 tableau(), 00109 working_cost(0, Row::Flags()), 00110 mapping(), 00111 base(), 00112 status(PARTIALLY_SATISFIABLE), 00113 pricing(PRICING_STEEPEST_EDGE_FLOAT), 00114 initialized(false), 00115 input_cs(), 00116 first_pending_constraint(0), 00117 input_obj_function(obj), 00118 opt_mode(mode), 00119 last_generator(point()), 00120 i_variables() { 00121 // Check for space dimension overflow. 00122 if (dim > max_space_dimension()) 00123 throw std::length_error("PPL::MIP_Problem::" 00124 "MIP_Problem(dim, first, last, obj, mode):\n" 00125 "dim exceeds the maximum allowed space " 00126 "dimension."); 00127 // Check the objective function. 00128 if (obj.space_dimension() > dim) { 00129 std::ostringstream s; 00130 s << "PPL::MIP_Problem::MIP_Problem(dim, first, last," 00131 << " obj, mode):\n" 00132 << "obj.space_dimension() == "<< obj.space_dimension() 00133 << " exceeds d == "<< dim << "."; 00134 throw std::invalid_argument(s.str()); 00135 } 00136 // Check the constraints. 00137 for (In i = first; i != last; ++i) { 00138 if (i->is_strict_inequality()) 00139 throw std::invalid_argument("PPL::MIP_Problem::" 00140 "MIP_Problem(dim, first, last, obj, mode):\n" 00141 "range [first, last) contains a strict " 00142 "inequality constraint."); 00143 if (i->space_dimension() > dim) { 00144 std::ostringstream s; 00145 s << "PPL::MIP_Problem::" 00146 << "MIP_Problem(dim, first, last, obj, mode):\n" 00147 << "range [first, last) contains a constraint having space" 00148 << "dimension" << " == " << i->space_dimension() << " that exceeds" 00149 "this->space_dimension == " << dim << "."; 00150 throw std::invalid_argument(s.str()); 00151 } 00152 input_cs.push_back(*i); 00153 } 00154 PPL_ASSERT(OK()); 00155 }
| Parma_Polyhedra_Library::MIP_Problem::MIP_Problem | ( | dimension_type | dim, | |
| const Constraint_System & | cs, | |||
| const Linear_Expression & | obj = Linear_Expression::zero(), |
|||
| Optimization_Mode | mode = MAXIMIZATION | |||
| ) |
Builds an MIP problem having space dimension dim from the constraint system cs, the objective function obj and optimization mode mode.
| dim | The dimension of the vector space enclosing *this. | |
| cs | The constraint system defining the feasible region. | |
| obj | The objective function (optional argument with default value ). | |
| mode | The optimization mode (optional argument with default value MAXIMIZATION). |
| std::length_error | Thrown if dim exceeds max_space_dimension(). | |
| std::invalid_argument | Thrown if the constraint system contains any strict inequality or if the space dimension of the constraint system (resp., the objective function) is strictly greater than dim. |
Definition at line 90 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Constraint_System::begin(), Parma_Polyhedra_Library::Constraint_System::end(), Parma_Polyhedra_Library::Constraint_System::has_strict_inequalities(), input_cs, max_space_dimension(), OK(), Parma_Polyhedra_Library::Constraint_System::space_dimension(), and Parma_Polyhedra_Library::Linear_Expression::space_dimension().
00094 : external_space_dim(dim), 00095 internal_space_dim(0), 00096 tableau(), 00097 working_cost(0, Row::Flags()), 00098 mapping(), 00099 base(), 00100 status(PARTIALLY_SATISFIABLE), 00101 pricing(PRICING_STEEPEST_EDGE_FLOAT), 00102 initialized(false), 00103 input_cs(), 00104 first_pending_constraint(0), 00105 input_obj_function(obj), 00106 opt_mode(mode), 00107 last_generator(point()), 00108 i_variables() { 00109 // Check for space dimension overflow. 00110 if (dim > max_space_dimension()) 00111 throw std::length_error("PPL::MIP_Problem::MIP_Problem(dim, cs, obj, " 00112 "mode):\n" 00113 "dim exceeds the maximum allowed" 00114 "space dimension."); 00115 // Check the objective function. 00116 if (obj.space_dimension() > dim) { 00117 std::ostringstream s; 00118 s << "PPL::MIP_Problem::MIP_Problem(dim, cs, obj," 00119 << " mode):\n" 00120 << "obj.space_dimension() == "<< obj.space_dimension() 00121 << " exceeds dim == "<< dim << "."; 00122 throw std::invalid_argument(s.str()); 00123 } 00124 // Check the constraint system. 00125 if (cs.space_dimension() > dim) { 00126 std::ostringstream s; 00127 s << "PPL::MIP_Problem::MIP_Problem(dim, cs, obj, mode):\n" 00128 << "cs.space_dimension == " << cs.space_dimension() << " exceeds dim == " 00129 << dim << "."; 00130 throw std::invalid_argument(s.str()); 00131 } 00132 if (cs.has_strict_inequalities()) 00133 throw std::invalid_argument("PPL::MIP_Problem::" 00134 "MIP_Problem(d, cs, obj, m):\n" 00135 "cs contains strict inequalities."); 00136 // Actually copy the constraints. 00137 input_cs.insert(input_cs.end(), cs.begin(), cs.end()); 00138 PPL_ASSERT(OK()); 00139 }
| Parma_Polyhedra_Library::MIP_Problem::MIP_Problem | ( | const MIP_Problem & | y | ) | [inline] |
Ordinary copy constructor.
Definition at line 44 of file MIP_Problem.inlines.hh.
References OK().
00045 : external_space_dim(y.external_space_dim), 00046 internal_space_dim(y.internal_space_dim), 00047 tableau(y.tableau), 00048 working_cost(y.working_cost), 00049 mapping(y.mapping), 00050 base(y.base), 00051 status(y.status), 00052 pricing(y.pricing), 00053 initialized(y.initialized), 00054 input_cs(y.input_cs), 00055 first_pending_constraint(y.first_pending_constraint), 00056 input_obj_function(y.input_obj_function), 00057 opt_mode(y.opt_mode), 00058 last_generator(y.last_generator), 00059 i_variables(y.i_variables) { 00060 PPL_ASSERT(OK()); 00061 }
| Parma_Polyhedra_Library::MIP_Problem::~MIP_Problem | ( | ) | [inline] |
| void Parma_Polyhedra_Library::MIP_Problem::add_constraint | ( | const Constraint & | c | ) |
Adds a copy of constraint c to the MIP problem.
| std::invalid_argument | Thrown if the constraint c is a strict inequality or if its space dimension is strictly greater than the space dimension of *this. |
Definition at line 142 of file MIP_Problem.cc.
References input_cs, Parma_Polyhedra_Library::Constraint::is_strict_inequality(), OK(), PARTIALLY_SATISFIABLE, Parma_Polyhedra_Library::Constraint::space_dimension(), space_dimension(), status, and UNSATISFIABLE.
Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::BD_Shape< T >::BFT00_upper_bound_assign_if_exact(), Parma_Polyhedra_Library::Box< ITV >::Box(), is_mip_satisfiable(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), Parma_Polyhedra_Library::Polyhedron::simplify_using_context_assign(), and solve_mip().
00142 { 00143 if (space_dimension() < c.space_dimension()) { 00144 std::ostringstream s; 00145 s << "PPL::MIP_Problem::add_constraint(c):\n" 00146 << "c.space_dimension() == "<< c.space_dimension() << " exceeds " 00147 "this->space_dimension == " << space_dimension() << "."; 00148 throw std::invalid_argument(s.str()); 00149 } 00150 if (c.is_strict_inequality()) 00151 throw std::invalid_argument("PPL::MIP_Problem::add_constraint(c):\n" 00152 "c is a strict inequality."); 00153 input_cs.push_back(c); 00154 if (status != UNSATISFIABLE) 00155 status = PARTIALLY_SATISFIABLE; 00156 PPL_ASSERT(OK()); 00157 }
| void Parma_Polyhedra_Library::MIP_Problem::add_constraints | ( | const Constraint_System & | cs | ) |
Adds a copy of the constraints in cs to the MIP problem.
| std::invalid_argument | Thrown if the constraint system cs contains any strict inequality or if its space dimension is strictly greater than the space dimension of *this. |
Definition at line 160 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Constraint_System::begin(), Parma_Polyhedra_Library::Constraint_System::end(), Parma_Polyhedra_Library::Constraint_System::has_strict_inequalities(), input_cs, OK(), PARTIALLY_SATISFIABLE, Parma_Polyhedra_Library::Constraint_System::space_dimension(), space_dimension(), status, and UNSATISFIABLE.
Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), Parma_Polyhedra_Library::Polyhedron::simplify_using_context_assign(), and Parma_Polyhedra_Library::Polyhedron::strongly_minimize_constraints().
00160 { 00161 if (space_dimension() < cs.space_dimension()) { 00162 std::ostringstream s; 00163 s << "PPL::MIP_Problem::add_constraints(cs):\n" 00164 << "cs.space_dimension() == " << cs.space_dimension() 00165 << " exceeds this->space_dimension() == " << this->space_dimension() 00166 << "."; 00167 throw std::invalid_argument(s.str()); 00168 } 00169 if (cs.has_strict_inequalities()) 00170 throw std::invalid_argument("PPL::MIP_Problem::add_constraints(cs):\n" 00171 "cs contains strict inequalities."); 00172 input_cs.insert(input_cs.end(), cs.begin(), cs.end()); 00173 if (status != UNSATISFIABLE) 00174 status = PARTIALLY_SATISFIABLE; 00175 PPL_ASSERT(OK()); 00176 }
| void Parma_Polyhedra_Library::MIP_Problem::add_space_dimensions_and_embed | ( | dimension_type | m | ) |
Adds m new space dimensions and embeds the old MIP problem in the new vector space.
| m | The number of dimensions to add. |
| std::length_error | Thrown if adding m new space dimensions would cause the vector space to exceed dimension max_space_dimension(). |
The new space dimensions will be those having the highest indexes in the new MIP problem; they are initially unconstrained.
Definition at line 335 of file MIP_Problem.cc.
References external_space_dim, max_space_dimension(), OK(), PARTIALLY_SATISFIABLE, space_dimension(), status, and UNSATISFIABLE.
Referenced by Parma_Polyhedra_Library::Polyhedron::simplify_using_context_assign(), and Parma_Polyhedra_Library::Polyhedron::strongly_minimize_constraints().
00335 { 00336 // The space dimension of the resulting MIP problem should not 00337 // overflow the maximum allowed space dimension. 00338 if (m > max_space_dimension() - space_dimension()) 00339 throw std::length_error("PPL::MIP_Problem::" 00340 "add_space_dimensions_and_embed(m):\n" 00341 "adding m new space dimensions exceeds " 00342 "the maximum allowed space dimension."); 00343 external_space_dim += m; 00344 if (status != UNSATISFIABLE) 00345 status = PARTIALLY_SATISFIABLE; 00346 PPL_ASSERT(OK()); 00347 }
| void Parma_Polyhedra_Library::MIP_Problem::add_to_integer_space_dimensions | ( | const Variables_Set & | i_vars | ) |
Sets the variables whose indexes are in set i_vars to be integer space dimensions.
| std::invalid_argument | Thrown if some index in i_vars does not correspond to a space dimension in *this. |
Definition at line 351 of file MIP_Problem.cc.
References external_space_dim, i_variables, Parma_Polyhedra_Library::Variables_Set::insert(), PARTIALLY_SATISFIABLE, Parma_Polyhedra_Library::Variables_Set::space_dimension(), status, and UNSATISFIABLE.
00351 { 00352 if (i_vars.space_dimension() > external_space_dim) 00353 throw std::invalid_argument("PPL::MIP_Problem::" 00354 "add_to_integer_space_dimension(i_vars):\n" 00355 "*this and i_vars are dimension" 00356 "incompatible."); 00357 const dimension_type original_size = i_variables.size(); 00358 i_variables.insert(i_vars.begin(), i_vars.end()); 00359 // If a new integral variable was inserted, set the internal status to 00360 // PARTIALLY_SATISFIABLE. 00361 if (i_variables.size() != original_size && status != UNSATISFIABLE) 00362 status = PARTIALLY_SATISFIABLE; 00363 }
| void Parma_Polyhedra_Library::MIP_Problem::ascii_dump | ( | std::ostream & | s | ) | const |
Writes to s an ASCII representation of *this.
Definition at line 2027 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Variables_Set::ascii_dump(), Parma_Polyhedra_Library::Generator::ascii_dump(), Parma_Polyhedra_Library::Row::ascii_dump(), Parma_Polyhedra_Library::Matrix::ascii_dump(), Parma_Polyhedra_Library::Linear_Expression::ascii_dump(), ascii_dump(), base, external_space_dim, first_pending_constraint, i_variables, initialized, input_cs, input_obj_function, internal_space_dim, last_generator, mapping, Parma_Polyhedra_Library::MAXIMIZATION, opt_mode, OPTIMIZED, PARTIALLY_SATISFIABLE, pricing, PRICING_STEEPEST_EDGE_EXACT, PRICING_STEEPEST_EDGE_FLOAT, PRICING_TEXTBOOK, SATISFIABLE, Parma_Polyhedra_Library::Row::size(), status, tableau, UNBOUNDED, UNSATISFIABLE, and working_cost.
02027 { 02028 using namespace IO_Operators; 02029 s << "\nexternal_space_dim: " << external_space_dim << " \n"; 02030 s << "\ninternal_space_dim: " << internal_space_dim << " \n"; 02031 02032 const dimension_type input_cs_size = input_cs.size(); 02033 02034 s << "\ninput_cs( " << input_cs_size << " )\n"; 02035 for (dimension_type i = 0; i < input_cs_size; ++i) 02036 input_cs[i].ascii_dump(s); 02037 02038 s << "\nfirst_pending_constraint: " << first_pending_constraint 02039 << std::endl; 02040 02041 s << "\ninput_obj_function\n"; 02042 input_obj_function.ascii_dump(s); 02043 s << "\nopt_mode " 02044 << (opt_mode == MAXIMIZATION ? "MAXIMIZATION" : "MINIMIZATION") << "\n"; 02045 02046 s << "\ninitialized: " << (initialized ? "YES" : "NO") << "\n"; 02047 s << "\npricing: "; 02048 switch (pricing) { 02049 case PRICING_STEEPEST_EDGE_FLOAT: 02050 s << "PRICING_STEEPEST_EDGE_FLOAT"; 02051 break; 02052 case PRICING_STEEPEST_EDGE_EXACT: 02053 s << "PRICING_STEEPEST_EDGE_EXACT"; 02054 break; 02055 case PRICING_TEXTBOOK: 02056 s << "PRICING_TEXTBOOK"; 02057 break; 02058 } 02059 s << "\n"; 02060 02061 s << "\nstatus: "; 02062 switch (status) { 02063 case UNSATISFIABLE: 02064 s << "UNSATISFIABLE"; 02065 break; 02066 case SATISFIABLE: 02067 s << "SATISFIABLE"; 02068 break; 02069 case UNBOUNDED: 02070 s << "UNBOUNDED"; 02071 break; 02072 case OPTIMIZED: 02073 s << "OPTIMIZED"; 02074 break; 02075 case PARTIALLY_SATISFIABLE: 02076 s << "PARTIALLY_SATISFIABLE"; 02077 break; 02078 } 02079 s << "\n"; 02080 02081 s << "\ntableau\n"; 02082 tableau.ascii_dump(s); 02083 s << "\nworking_cost( " << working_cost.size()<< " )\n"; 02084 working_cost.ascii_dump(s); 02085 02086 const dimension_type base_size = base.size(); 02087 s << "\nbase( " << base_size << " )\n"; 02088 for (dimension_type i = 0; i != base_size; ++i) 02089 s << base[i] << ' '; 02090 02091 s << "\nlast_generator\n"; 02092 last_generator.ascii_dump(s); 02093 02094 const dimension_type mapping_size = mapping.size(); 02095 s << "\nmapping( " << mapping_size << " )\n"; 02096 for (dimension_type i = 1; i < mapping_size; ++i) 02097 s << "\n"<< i << " -> " << mapping[i].first << " -> " << mapping[i].second 02098 << ' '; 02099 02100 s << "\n\ninteger_variables"; 02101 i_variables.ascii_dump(s); 02102 }
| void Parma_Polyhedra_Library::MIP_Problem::ascii_dump | ( | ) | const |
Writes to std::cerr an ASCII representation of *this.
Referenced by ascii_dump(), and OK().
| bool Parma_Polyhedra_Library::MIP_Problem::ascii_load | ( | std::istream & | s | ) |
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this accordingly. Returns true if successful, false otherwise.
Definition at line 2107 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Constraint::ascii_load(), Parma_Polyhedra_Library::MAXIMIZATION, Parma_Polyhedra_Library::MINIMIZATION, and Parma_Polyhedra_Library::Constraint::zero_dim_positivity().
02107 { 02108 std::string str; 02109 if (!(s >> str) || str != "external_space_dim:") 02110 return false; 02111 02112 if (!(s >> external_space_dim)) 02113 return false; 02114 02115 if (!(s >> str) || str != "internal_space_dim:") 02116 return false; 02117 02118 if (!(s >> internal_space_dim)) 02119 return false; 02120 02121 if (!(s >> str) || str != "input_cs(") 02122 return false; 02123 02124 dimension_type input_cs_size; 02125 02126 if (!(s >> input_cs_size)) 02127 return false; 02128 02129 if (!(s >> str) || str != ")") 02130 return false; 02131 02132 Constraint c(Constraint::zero_dim_positivity()); 02133 for (dimension_type i = 0; i < input_cs_size; ++i) { 02134 if (!c.ascii_load(s)) 02135 return false; 02136 input_cs.push_back(c); 02137 } 02138 02139 if (!(s >> str) || str != "first_pending_constraint:") 02140 return false; 02141 02142 if (!(s >> first_pending_constraint)) 02143 return false; 02144 02145 if (!(s >> str) || str != "input_obj_function") 02146 return false; 02147 02148 if (!input_obj_function.ascii_load(s)) 02149 return false; 02150 02151 if (!(s >> str) || str != "opt_mode") 02152 return false; 02153 02154 if (!(s >> str)) 02155 return false; 02156 02157 if (str == "MAXIMIZATION") 02158 set_optimization_mode(MAXIMIZATION); 02159 else { 02160 if (str != "MINIMIZATION") 02161 return false; 02162 set_optimization_mode(MINIMIZATION); 02163 } 02164 02165 if (!(s >> str) || str != "initialized:") 02166 return false; 02167 if (!(s >> str)) 02168 return false; 02169 if (str == "YES") 02170 initialized = true; 02171 else if (str == "NO") 02172 initialized = false; 02173 else 02174 return false; 02175 02176 if (!(s >> str) || str != "pricing:") 02177 return false; 02178 if (!(s >> str)) 02179 return false; 02180 if (str == "PRICING_STEEPEST_EDGE_FLOAT") 02181 pricing = PRICING_STEEPEST_EDGE_FLOAT; 02182 else if (str == "PRICING_STEEPEST_EDGE_EXACT") 02183 pricing = PRICING_STEEPEST_EDGE_EXACT; 02184 else if (str == "PRICING_TEXTBOOK") 02185 pricing = PRICING_TEXTBOOK; 02186 else 02187 return false; 02188 02189 if (!(s >> str) || str != "status:") 02190 return false; 02191 02192 if (!(s >> str)) 02193 return false; 02194 02195 if (str == "UNSATISFIABLE") 02196 status = UNSATISFIABLE; 02197 else if (str == "SATISFIABLE") 02198 status = SATISFIABLE; 02199 else if (str == "UNBOUNDED") 02200 status = UNBOUNDED; 02201 else if (str == "OPTIMIZED") 02202 status = OPTIMIZED; 02203 else if (str == "PARTIALLY_SATISFIABLE") 02204 status = PARTIALLY_SATISFIABLE; 02205 else 02206 return false; 02207 02208 if (!(s >> str) || str != "tableau") 02209 return false; 02210 02211 if (!tableau.ascii_load(s)) 02212 return false; 02213 02214 if (!(s >> str) || str != "working_cost(") 02215 return false; 02216 02217 dimension_type working_cost_dim; 02218 02219 if (!(s >> working_cost_dim)) 02220 return false; 02221 02222 if (!(s >> str) || str != ")") 02223 return false; 02224 02225 if (!working_cost.ascii_load(s)) 02226 return false; 02227 02228 if (!(s >> str) || str != "base(") 02229 return false; 02230 02231 dimension_type base_size; 02232 if (!(s >> base_size)) 02233 return false; 02234 02235 if (!(s >> str) || str != ")") 02236 return false; 02237 02238 dimension_type base_value; 02239 for (dimension_type i = 0; i != base_size; ++i) { 02240 if (!(s >> base_value)) 02241 return false; 02242 base.push_back(base_value); 02243 } 02244 02245 if (!(s >> str) || str != "last_generator") 02246 return false; 02247 02248 if (!last_generator.ascii_load(s)) 02249 return false; 02250 02251 if (!(s >> str) || str != "mapping(") 02252 return false; 02253 02254 dimension_type mapping_size; 02255 if (!(s >> mapping_size)) 02256 return false; 02257 02258 if (!(s >> str) || str != ")") 02259 return false; 02260 02261 dimension_type first_value; 02262 dimension_type second_value; 02263 dimension_type index; 02264 02265 // The first `mapping' index is never used, so we initialize 02266 // it pushing back a dummy value. 02267 if (tableau.num_columns() != 0) 02268 mapping.push_back(std::make_pair(0, 0)); 02269 02270 for (dimension_type i = 1; i < mapping_size; ++i) { 02271 if (!(s >> index)) 02272 return false; 02273 if (!(s >> str) || str != "->") 02274 return false; 02275 if (!(s >> first_value)) 02276 return false; 02277 if (!(s >> str) || str != "->") 02278 return false; 02279 if (!(s >> second_value)) 02280 return false; 02281 mapping.push_back(std::make_pair(first_value, second_value)); 02282 } 02283 02284 if (!(s >> str) || str != "integer_variables") 02285 return false; 02286 02287 if (!i_variables.ascii_load(s)) 02288 return false; 02289 02290 PPL_ASSERT(OK()); 02291 return true; 02292 }
| bool Parma_Polyhedra_Library::MIP_Problem::choose_branching_variable | ( | const MIP_Problem & | lp, | |
| const Variables_Set & | i_vars, | |||
| dimension_type & | branching_index | |||
| ) | [static, private] |
Returns true if and if only mip.last_generator satisfies all the integrality coditions implicitly stated using by i_vars.
| lp | The LP problem. This is assumed to have no integral space dimension. | |
| i_vars | The variables that are constrained to take an integer value. | |
| branching_index | If false is returned, this will encode the non-integral variable index on which the `branch and bound' algorithm should be applied. |
Definition at line 1722 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Generator::coefficient(), Parma_Polyhedra_Library::Generator::divisor(), Parma_Polyhedra_Library::gcd_assign(), input_cs, Parma_Polyhedra_Library::Variables_Set::insert(), is_saturated(), last_generator, PPL_DIRTY_TEMP_COEFFICIENT, and space_dimension().
Referenced by is_mip_satisfiable().
01724 { 01725 // Insert here the variables that don't satisfy the integrality condition. 01726 const Constraint_Sequence& input_cs = lp.input_cs; 01727 const Generator& last_generator = lp.last_generator; 01728 const Coefficient& last_generator_divisor = last_generator.divisor(); 01729 Variables_Set candidate_variables; 01730 01731 PPL_DIRTY_TEMP_COEFFICIENT(gcd); 01732 for (Variables_Set::const_iterator v_it = i_vars.begin(), 01733 v_end = i_vars.end(); v_it != v_end; ++v_it) { 01734 gcd_assign(gcd, 01735 last_generator.coefficient(Variable(*v_it)), 01736 last_generator_divisor); 01737 if (gcd != last_generator_divisor) 01738 candidate_variables.insert(*v_it); 01739 } 01740 // If this set is empty, we have finished. 01741 if (candidate_variables.empty()) 01742 return true; 01743 01744 // Check how many `active constraints' we have and track them. 01745 const dimension_type input_cs_num_rows = input_cs.size(); 01746 std::deque<bool> satisfiable_constraints (input_cs_num_rows, false); 01747 for (dimension_type i = input_cs_num_rows; i-- > 0; ) 01748 // An equality is an `active constraint' by definition. 01749 // If we have an inequality, check if it is an `active constraint'. 01750 if (input_cs[i].is_equality() 01751 || is_saturated(input_cs[i], last_generator)) 01752 satisfiable_constraints[i] = true; 01753 01754 dimension_type current_num_appearances = 0; 01755 dimension_type winning_num_appearances = 0; 01756 01757 // For every candidate variable, check how many times this appear in the 01758 // active constraints. 01759 for (Variables_Set::const_iterator v_it = candidate_variables.begin(), 01760 v_end = candidate_variables.end(); v_it != v_end; ++v_it) { 01761 current_num_appearances = 0; 01762 for (dimension_type i = input_cs_num_rows; i-- > 0; ) 01763 if (satisfiable_constraints[i] 01764 && *v_it < input_cs[i].space_dimension() 01765 && input_cs[i].coefficient(Variable(*v_it)) != 0) 01766 ++current_num_appearances; 01767 if (current_num_appearances >= winning_num_appearances) { 01768 winning_num_appearances = current_num_appearances; 01769 branching_index = *v_it; 01770 } 01771 } 01772 return false; 01773 }
| void Parma_Polyhedra_Library::MIP_Problem::clear | ( | ) | [inline] |
Resets *this to be equal to the trivial MIP problem.
The space dimension is reset to
.
Definition at line 148 of file MIP_Problem.inlines.hh.
References swap().
00148 { 00149 MIP_Problem tmp; 00150 swap(tmp); 00151 }
| void Parma_Polyhedra_Library::MIP_Problem::compute_generator | ( | ) | const [private] |
Computes a valid generator that satisfies all the constraints of the Linear Programming problem associated to *this.
Definition at line 1386 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::add_mul_assign(), Parma_Polyhedra_Library::exact_div_assign(), external_space_dim, is_in_base(), last_generator, Parma_Polyhedra_Library::lcm_assign(), mapping, Parma_Polyhedra_Library::neg_assign(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::sub_mul_assign(), and tableau.
Referenced by process_pending_constraints(), and second_phase().
01386 { 01387 // We will store in num[] and in den[] the numerators and 01388 // the denominators of every variable of the original problem. 01389 std::vector<Coefficient> num(external_space_dim); 01390 std::vector<Coefficient> den(external_space_dim); 01391 dimension_type row = 0; 01392 01393 PPL_DIRTY_TEMP_COEFFICIENT(lcm); 01394 // Speculatively allocate temporaries out of loop. 01395 PPL_DIRTY_TEMP_COEFFICIENT(split_num); 01396 PPL_DIRTY_TEMP_COEFFICIENT(split_den); 01397 01398 // We start to compute num[] and den[]. 01399 for (dimension_type i = external_space_dim; i-- > 0; ) { 01400 Coefficient& num_i = num[i]; 01401 Coefficient& den_i = den[i]; 01402 // Get the value of the variable from the tableau 01403 // (if it is not a basic variable, the value is 0). 01404 const dimension_type original_var = mapping[i+1].first; 01405 if (is_in_base(original_var, row)) { 01406 const Row& t_row = tableau[row]; 01407 if (t_row[original_var] > 0) { 01408 neg_assign(num_i, t_row[0]); 01409 den_i = t_row[original_var]; 01410 } 01411 else { 01412 num_i = t_row[0]; 01413 neg_assign(den_i, t_row[original_var]); 01414 } 01415 } 01416 else { 01417 num_i = 0; 01418 den_i = 1; 01419 } 01420 // Check whether the variable was split. 01421 const dimension_type split_var = mapping[i+1].second; 01422 if (split_var != 0) { 01423 // The variable was split: get the value for the negative component, 01424 // having index mapping[i+1].second . 01425 // Like before, we he have to check if the variable is in base. 01426 if (is_in_base(split_var, row)) { 01427 const Row& t_row = tableau[row]; 01428 if (t_row[split_var] > 0) { 01429 neg_assign(split_num, t_row[0]); 01430 split_den = t_row[split_var]; 01431 } 01432 else { 01433 split_num = t_row[0]; 01434 neg_assign(split_den, t_row[split_var]); 01435 } 01436 // We compute the lcm to compute subsequently the difference 01437 // between the 2 variables. 01438 lcm_assign(lcm, den_i, split_den); 01439 exact_div_assign(den_i, lcm, den_i); 01440 exact_div_assign(split_den, lcm, split_den); 01441 num_i *= den_i; 01442 sub_mul_assign(num_i, split_num, split_den); 01443 if (num_i == 0) 01444 den_i = 1; 01445 else 01446 den_i = lcm; 01447 } 01448 // Note: if the negative component was not in base, then 01449 // it has value zero and there is nothing left to do. 01450 } 01451 } 01452 01453 // Compute the lcm of all denominators. 01454 lcm = den[0]; 01455 for (dimension_type i = 1; i < external_space_dim; ++i) 01456 lcm_assign(lcm, lcm, den[i]); 01457 // Use the denominators to store the numerators' multipliers 01458 // and then compute the normalized numerators. 01459 for (dimension_type i = external_space_dim; i-- > 0; ) { 01460 exact_div_assign(den[i], lcm, den[i]); 01461 num[i] *= den[i]; 01462 } 01463 01464 // Finally, build the generator. 01465 Linear_Expression expr; 01466 for (dimension_type i = external_space_dim; i-- > 0; ) 01467 add_mul_assign(expr, num[i], Variable(i)); 01468 01469 MIP_Problem& x = const_cast<MIP_Problem&>(*this); 01470 x.last_generator = point(expr, lcm); 01471 }
| bool Parma_Polyhedra_Library::MIP_Problem::compute_simplex_using_exact_pricing | ( | ) | [private] |
Returns true if and if only the algorithm successfully computed a feasible solution.
Definition at line 1281 of file MIP_Problem.cc.
References get_control_parameter(), get_exiting_base_index(), Parma_Polyhedra_Library::maybe_abandon(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), pivot(), PRICING, PRICING_STEEPEST_EDGE_EXACT, PRICING_TEXTBOOK, Parma_Polyhedra_Library::Row::size(), steepest_edge_exact_entering_index(), tableau, textbook_entering_index(), and working_cost.
Referenced by process_pending_constraints(), and second_phase().
01281 { 01282 PPL_ASSERT(tableau.num_columns() == working_cost.size()); 01283 PPL_ASSERT(get_control_parameter(PRICING) == PRICING_STEEPEST_EDGE_EXACT 01284 || get_control_parameter(PRICING) == PRICING_TEXTBOOK); 01285 01286 const dimension_type tableau_num_rows = tableau.num_rows(); 01287 const bool textbook_pricing 01288 = (PRICING_TEXTBOOK == get_control_parameter(PRICING)); 01289 01290 while (true) { 01291 // Choose the index of the variable entering the base, if any. 01292 const dimension_type entering_var_index 01293 = textbook_pricing 01294 ? textbook_entering_index() 01295 : steepest_edge_exact_entering_index(); 01296 // If no entering index was computed, the problem is solved. 01297 if (entering_var_index == 0) 01298 return true; 01299 01300 // Choose the index of the row exiting the base. 01301 const dimension_type exiting_base_index 01302 = get_exiting_base_index(entering_var_index); 01303 // If no exiting index was computed, the problem is unbounded. 01304 if (exiting_base_index == tableau_num_rows) 01305 return false; 01306 01307 // Check if the client has requested abandoning all expensive 01308 // computations. If so, the exception specified by the client 01309 // is thrown now. 01310 maybe_abandon(); 01311 01312 // We have not reached the optimality or unbounded condition: 01313 // compute the new base and the corresponding vertex of the 01314 // feasible region. 01315 pivot(entering_var_index, exiting_base_index); 01316 #if PPL_NOISY_SIMPLEX 01317 ++num_iterations; 01318 if (num_iterations % 200 == 0) 01319 std::cout << "Primal simplex: iteration " << num_iterations 01320 << "." << std::endl; 01321 #endif // PPL_NOISY_SIMPLEX 01322 } 01323 }
| bool Parma_Polyhedra_Library::MIP_Problem::compute_simplex_using_steepest_edge_float | ( | ) | [private] |
Returns true if and if only the algorithm successfully computed a feasible solution.
Definition at line 1190 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::abs_assign(), get_exiting_base_index(), Parma_Polyhedra_Library::maybe_abandon(), Parma_Polyhedra_Library::neg_assign(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), pivot(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Row::size(), steepest_edge_float_entering_index(), tableau, textbook_entering_index(), WEIGHT_ADD, WEIGHT_BEGIN, and working_cost.
Referenced by process_pending_constraints(), and second_phase().
01190 { 01191 // We may need to temporarily switch to the textbook pricing. 01192 const unsigned long allowed_non_increasing_loops = 200; 01193 unsigned long non_increased_times = 0; 01194 bool textbook_pricing = false; 01195 01196 PPL_DIRTY_TEMP_COEFFICIENT(cost_sgn_coeff); 01197 PPL_DIRTY_TEMP_COEFFICIENT(current_num); 01198 PPL_DIRTY_TEMP_COEFFICIENT(current_den); 01199 PPL_DIRTY_TEMP_COEFFICIENT(challenger); 01200 PPL_DIRTY_TEMP_COEFFICIENT(current); 01201 01202 cost_sgn_coeff = working_cost[working_cost.size()-1]; 01203 current_num = working_cost[0]; 01204 if (cost_sgn_coeff < 0) 01205 neg_assign(current_num); 01206 abs_assign(current_den, cost_sgn_coeff); 01207 PPL_ASSERT(tableau.num_columns() == working_cost.size()); 01208 const dimension_type tableau_num_rows = tableau.num_rows(); 01209 01210 while (true) { 01211 // Choose the index of the variable entering the base, if any. 01212 const dimension_type entering_var_index 01213 = textbook_pricing 01214 ? textbook_entering_index() 01215 : steepest_edge_float_entering_index(); 01216 01217 // If no entering index was computed, the problem is solved. 01218 if (entering_var_index == 0) 01219 return true; 01220 01221 // Choose the index of the row exiting the base. 01222 const dimension_type exiting_base_index 01223 = get_exiting_base_index(entering_var_index); 01224 // If no exiting index was computed, the problem is unbounded. 01225 if (exiting_base_index == tableau_num_rows) 01226 return false; 01227 01228 // Check if the client has requested abandoning all expensive 01229 // computations. If so, the exception specified by the client 01230 // is thrown now. 01231 maybe_abandon(); 01232 01233 // We have not reached the optimality or unbounded condition: 01234 // compute the new base and the corresponding vertex of the 01235 // feasible region. 01236 pivot(entering_var_index, exiting_base_index); 01237 01238 WEIGHT_BEGIN(); 01239 // Now begins the objective function's value check to choose between 01240 // the `textbook' and the float `steepest-edge' technique. 01241 cost_sgn_coeff = working_cost[working_cost.size()-1]; 01242 01243 challenger = working_cost[0]; 01244 if (cost_sgn_coeff < 0) 01245 neg_assign(challenger); 01246 challenger *= current_den; 01247 abs_assign(current, cost_sgn_coeff); 01248 current *= current_num; 01249 #if PPL_NOISY_SIMPLEX 01250 ++num_iterations; 01251 if (num_iterations % 200 == 0) 01252 std::cout << "Primal simplex: iteration " << num_iterations 01253 << "." << std::endl; 01254 #endif // PPL_NOISY_SIMPLEX 01255 // If the following condition fails, probably there's a bug. 01256 PPL_ASSERT(challenger >= current); 01257 // If the value of the objective function does not improve, 01258 // keep track of that. 01259 if (challenger == current) { 01260 ++non_increased_times; 01261 // In the following case we will proceed using the `textbook' 01262 // technique, until the objective function is not improved. 01263 if (non_increased_times > allowed_non_increasing_loops) 01264 textbook_pricing = true; 01265 } 01266 // The objective function has an improvement: 01267 // reset `non_increased_times' and `textbook_pricing'. 01268 else { 01269 non_increased_times = 0; 01270 textbook_pricing = false; 01271 } 01272 current_num = working_cost[0]; 01273 if (cost_sgn_coeff < 0) 01274 neg_assign(current_num); 01275 abs_assign(current_den, cost_sgn_coeff); 01276 WEIGHT_ADD(566); 01277 } 01278 }
| MIP_Problem_Status Parma_Polyhedra_Library::MIP_Problem::compute_tableau | ( | std::vector< dimension_type > & | worked_out_row | ) | [private] |
Assigns to this->tableau a simplex tableau representing the MIP problem, inserting into this->mapping the information that is required to recover the original MIP problem.
UNFEASIBLE_MIP_PROBLEM if the constraint system contains any trivially unfeasible constraint (tableau was not computed); UNBOUNDED_MIP_PROBLEM if the problem is trivially unbounded (the computed tableau contains no constraints); OPTIMIZED_MIP_PROBLEM> if the problem is neither trivially unfeasible nor trivially unbounded (the tableau was computed successfully). | MIP_Problem::const_iterator Parma_Polyhedra_Library::MIP_Problem::constraints_begin | ( | ) | const [inline] |
Returns a read-only iterator to the first constraint defining the feasible region.
Definition at line 95 of file MIP_Problem.inlines.hh.
References input_cs.
Referenced by operator<<().
00095 { 00096 return input_cs.begin(); 00097 }
| MIP_Problem::const_iterator Parma_Polyhedra_Library::MIP_Problem::constraints_end | ( | ) | const [inline] |
Returns a past-the-end read-only iterator to the sequence of constraints defining the feasible region.
Definition at line 100 of file MIP_Problem.inlines.hh.
References input_cs.
Referenced by operator<<().
00100 { 00101 return input_cs.end(); 00102 }
| void Parma_Polyhedra_Library::MIP_Problem::erase_artificials | ( | dimension_type | begin_artificials, | |
| dimension_type | end_artificials | |||
| ) | [private] |
Drop unnecessary artificial variables from the tableau and get ready for the second phase of the simplex algorithm.
begin_artificials is strictly greater than 0 and smaller than end_artificials.| begin_artificials | The start of the tableau column index range for artificial variables. | |
| end_artificials | The end of the tableau column index range for artificial variables. Note that column index end_artificial is excluded from the range. |
Definition at line 1328 of file MIP_Problem.cc.
References base, Parma_Polyhedra_Library::Matrix::erase_to_end(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), pivot(), Parma_Polyhedra_Library::Matrix::remove_trailing_columns(), Parma_Polyhedra_Library::Row::shrink(), Parma_Polyhedra_Library::Row::size(), Parma_Polyhedra_Library::Row::swap(), tableau, and working_cost.
Referenced by process_pending_constraints().
01329 { 01330 PPL_ASSERT(0 < begin_artificials && begin_artificials < end_artificials); 01331 01332 const dimension_type old_last_column = tableau.num_columns() - 1; 01333 dimension_type tableau_n_rows = tableau.num_rows(); 01334 // Step 1: try to remove from the base all the remaining slack variables. 01335 for (dimension_type i = 0; i < tableau_n_rows; ++i) 01336 if (begin_artificials <= base[i] && base[i] < end_artificials) { 01337 // Search for a non-zero element to enter the base. 01338 Row& tableau_i = tableau[i]; 01339 bool redundant = true; 01340 for (dimension_type j = end_artificials; j-- > 1; ) 01341 if (!(begin_artificials <= j && j < end_artificials) 01342 && tableau_i[j] != 0) { 01343 pivot(j, i); 01344 redundant = false; 01345 break; 01346 } 01347 if (redundant) { 01348 // No original variable entered the base: 01349 // the constraint is redundant and should be deleted. 01350 --tableau_n_rows; 01351 if (i < tableau_n_rows) { 01352 // Replace the redundant row with the last one, 01353 // taking care of adjusting the iteration index. 01354 tableau_i.swap(tableau[tableau_n_rows]); 01355 base[i] = base[tableau_n_rows]; 01356 --i; 01357 } 01358 tableau.erase_to_end(tableau_n_rows); 01359 base.pop_back(); 01360 } 01361 } 01362 01363 01364 // Step 2: Adjust data structures so as to enter phase 2 of the simplex. 01365 01366 // Resize the tableau. 01367 const dimension_type num_artificials = end_artificials - begin_artificials; 01368 tableau.remove_trailing_columns(num_artificials); 01369 01370 // Zero the last column of the tableau. 01371 const dimension_type new_last_column = tableau.num_columns() - 1; 01372 for (dimension_type i = tableau_n_rows; i-- > 0; ) 01373 tableau[i][new_last_column] = 0; 01374 01375 // ... then properly set the element in the (new) last column, 01376 // encoding the kind of optimization; ... 01377 working_cost[new_last_column] = working_cost[old_last_column]; 01378 // ... and finally remove redundant columns. 01379 const dimension_type working_cost_new_size 01380 = working_cost.size() - num_artificials; 01381 working_cost.shrink(working_cost_new_size); 01382 }
| void Parma_Polyhedra_Library::MIP_Problem::evaluate_objective_function | ( | const Generator & | evaluating_point, | |
| Coefficient & | num, | |||
| Coefficient & | den | |||
| ) | const |
Sets num and den so that
is the result of evaluating the objective function on evaluating_point.
| evaluating_point | The point on which the objective function will be evaluated. | |
| num | On exit will contain the numerator of the evaluated value. | |
| den | On exit will contain the denominator of the evaluated value. |
| std::invalid_argument | Thrown if *this and evaluating_point are dimension-incompatible or if the generator evaluating_point is not a point. |
Definition at line 1532 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Linear_Expression::coefficient(), Parma_Polyhedra_Library::Generator::coefficient(), Parma_Polyhedra_Library::Generator::divisor(), Parma_Polyhedra_Library::Linear_Expression::inhomogeneous_term(), input_obj_function, Parma_Polyhedra_Library::Generator::is_point(), Parma_Polyhedra_Library::normalize2(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), space_dimension(), and Parma_Polyhedra_Library::Generator::space_dimension().
Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::Octagonal_Shape< T >::max_min(), Parma_Polyhedra_Library::BD_Shape< T >::max_min(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), optimal_value(), and solve_mip().
01534 { 01535 const dimension_type ep_space_dim = evaluating_point.space_dimension(); 01536 if (space_dimension() < ep_space_dim) 01537 throw std::invalid_argument("PPL::MIP_Problem::" 01538 "evaluate_objective_function(p, n, d):\n" 01539 "*this and p are dimension incompatible."); 01540 if (!evaluating_point.is_point()) 01541 throw std::invalid_argument("PPL::MIP_Problem::" 01542 "evaluate_objective_function(p, n, d):\n" 01543 "p is not a point."); 01544 01545 // Compute the smallest space dimension between `input_obj_function' 01546 // and `evaluating_point'. 01547 const dimension_type working_space_dim 01548 = std::min(ep_space_dim, input_obj_function.space_dimension()); 01549 // Compute the optimal value of the cost function. 01550 const Coefficient& divisor = evaluating_point.divisor(); 01551 ext_n = input_obj_function.inhomogeneous_term() * divisor; 01552 for (dimension_type i = working_space_dim; i-- > 0; ) 01553 ext_n += evaluating_point.coefficient(Variable(i)) 01554 * input_obj_function.coefficient(Variable(i)); 01555 // Numerator and denominator should be coprime. 01556 normalize2(ext_n, divisor, ext_n, ext_d); 01557 }
| memory_size_type Parma_Polyhedra_Library::MIP_Problem::external_memory_in_bytes | ( | ) | const [inline] |
Returns the size in bytes of the memory managed by *this.
Definition at line 154 of file MIP_Problem.inlines.hh.
References base, Parma_Polyhedra_Library::Generator::external_memory_in_bytes(), Parma_Polyhedra_Library::Linear_Expression::external_memory_in_bytes(), Parma_Polyhedra_Library::Row::external_memory_in_bytes(), Parma_Polyhedra_Library::Matrix::external_memory_in_bytes(), input_cs, input_obj_function, last_generator, mapping, tableau, and working_cost.
Referenced by total_memory_in_bytes().
00154 { 00155 memory_size_type n 00156 = tableau.external_memory_in_bytes() 00157 + working_cost.external_memory_in_bytes() 00158 + input_obj_function.external_memory_in_bytes() 00159 + last_generator.external_memory_in_bytes(); 00160 // Adding the external memory for `input_cs'. 00161 n += input_cs.capacity() * sizeof(Constraint); 00162 for (const_iterator i = input_cs.begin(), 00163 i_end = input_cs.end(); i != i_end; ++i) 00164 n += (i->external_memory_in_bytes()); 00165 // Adding the external memory for `base'. 00166 n += base.capacity() * sizeof(dimension_type); 00167 // Adding the external memory for `mapping'. 00168 n += mapping.capacity() * sizeof(std::pair<dimension_type, dimension_type>); 00169 return n; 00170 }
| const PPL::Generator & Parma_Polyhedra_Library::MIP_Problem::feasible_point | ( | ) | const |
Returns a feasible point for *this, if it exists.
| std::domain_error | Thrown if the MIP problem is not satisfiable. |
Definition at line 195 of file MIP_Problem.cc.
References is_satisfiable(), and last_generator.
00195 { 00196 if (is_satisfiable()) 00197 return last_generator; 00198 else 00199 throw std::domain_error("PPL::MIP_Problem::feasible_point():\n" 00200 "*this is not satisfiable."); 00201 }
| MIP_Problem::Control_Parameter_Value Parma_Polyhedra_Library::MIP_Problem::get_control_parameter | ( | Control_Parameter_Name | name | ) | const [inline] |
Returns the value of the control parameter name.
Definition at line 110 of file MIP_Problem.inlines.hh.
References pricing, and PRICING.
Referenced by compute_simplex_using_exact_pricing(), process_pending_constraints(), and second_phase().
| 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.
| entering_var_index | The column index of the variable entering the base. |
Definition at line 1135 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::abs_assign(), base, Parma_Polyhedra_Library::exact_div_assign(), Parma_Polyhedra_Library::lcm_assign(), Parma_Polyhedra_Library::Matrix::num_rows(), PPL_DIRTY_TEMP_COEFFICIENT, tableau, WEIGHT_ADD, and WEIGHT_BEGIN.
Referenced by compute_simplex_using_exact_pricing(), and compute_simplex_using_steepest_edge_float().
01135 { 01136 // The variable exiting the base should be associated to a tableau 01137 // constraint such that the ratio 01138 // tableau[i][entering_var_index] / tableau[i][base[i]] 01139 // is strictly positive and minimal. 01140 01141 // Find the first tableau constraint `c' having a positive value for 01142 // tableau[i][entering_var_index] / tableau[i][base[i]] 01143 const dimension_type tableau_num_rows = tableau.num_rows(); 01144 dimension_type exiting_base_index = tableau_num_rows; 01145 for (dimension_type i = 0; i < tableau_num_rows; ++i) { 01146 const Row& t_i = tableau[i]; 01147 const int num_sign = sgn(t_i[entering_var_index]); 01148 if (num_sign != 0 && num_sign == sgn(t_i[base[i]])) { 01149 exiting_base_index = i; 01150 break; 01151 } 01152 } 01153 // Check for unboundedness. 01154 if (exiting_base_index == tableau_num_rows) 01155 return tableau_num_rows; 01156 01157 // Reaching this point means that a variable will definitely exit the base. 01158 PPL_DIRTY_TEMP_COEFFICIENT(lcm); 01159 PPL_DIRTY_TEMP_COEFFICIENT(current_min); 01160 PPL_DIRTY_TEMP_COEFFICIENT(challenger); 01161 for (dimension_type i = exiting_base_index + 1; i < tableau_num_rows; ++i) { 01162 const Row& t_i = tableau[i]; 01163 const Coefficient& t_ie = t_i[entering_var_index]; 01164 const Coefficient& t_ib = t_i[base[i]]; 01165 const int t_ie_sign = sgn(t_ie); 01166 if (t_ie_sign != 0 && t_ie_sign == sgn(t_ib)) { 01167 WEIGHT_BEGIN(); 01168 const Row& t_e = tableau[exiting_base_index]; 01169 const Coefficient& t_ee = t_e[entering_var_index]; 01170 lcm_assign(lcm, t_ee, t_ie); 01171 exact_div_assign(current_min, lcm, t_ee); 01172 current_min *= t_e[0]; 01173 abs_assign(current_min); 01174 exact_div_assign(challenger, lcm, t_ie); 01175 challenger *= t_i[0]; 01176 abs_assign(challenger); 01177 current_min -= challenger; 01178 const int sign = sgn(current_min); 01179 if (sign > 0 01180 || (sign == 0 && base[i] < base[exiting_base_index])) 01181 exiting_base_index = i; 01182 WEIGHT_ADD(1044); 01183 } 01184 } 01185 return exiting_base_index; 01186 }
| const Variables_Set & Parma_Polyhedra_Library::MIP_Problem::integer_space_dimensions | ( | ) | const [inline] |
Returns a set containing all the variables' indexes constrained to be integral.
Definition at line 105 of file MIP_Problem.inlines.hh.
References i_variables.
Referenced by is_mip_satisfiable(), operator<<(), and solve().
00105 { 00106 return i_variables; 00107 }
| bool Parma_Polyhedra_Library::MIP_Problem::is_in_base | ( | dimension_type | var_index, | |
| dimension_type & | row_index | |||
| ) | const [private] |
Definition at line 366 of file MIP_Problem.cc.
References base.
Referenced by compute_generator(), and merge_split_variable().
| bool Parma_Polyhedra_Library::MIP_Problem::is_lp_satisfiable | ( | ) | const [private] |
Returns true if and if only the LP problem is satisfiable.
Definition at line 1560 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Matrix::add_zero_columns(), external_space_dim, first_pending_constraint, initialized, input_cs, internal_space_dim, mapping, Parma_Polyhedra_Library::Matrix::num_columns(), OK(), OPTIMIZED, PARTIALLY_SATISFIABLE, process_pending_constraints(), SATISFIABLE, status, tableau, UNBOUNDED, and UNSATISFIABLE.
Referenced by is_mip_satisfiable(), is_satisfiable(), solve(), and solve_mip().
01560 { 01561 #if PPL_NOISY_SIMPLEX 01562 num_iterations = 0; 01563 #endif // PPL_NOISY_SIMPLEX 01564 switch (status) { 01565 case UNSATISFIABLE: 01566 return false; 01567 case SATISFIABLE: 01568 // Intentionally fall through. 01569 case UNBOUNDED: 01570 // Intentionally fall through. 01571 case OPTIMIZED: 01572 // Intentionally fall through. 01573 return true; 01574 case PARTIALLY_SATISFIABLE: 01575 { 01576 MIP_Problem& x = const_cast<MIP_Problem&>(*this); 01577 // This code tries to handle the case that happens if the tableau is 01578 // empty, so it must be initialized. 01579 if (tableau.num_columns() == 0) { 01580 // Add two columns, the first that handles the inhomogeneous term and 01581 // the second that represent the `sign'. 01582 x.tableau.add_zero_columns(2); 01583 // Sync `mapping' for the inhomogeneous term. 01584 x.mapping.push_back(std::make_pair(0, 0)); 01585 // The internal data structures are ready, so prepare for more 01586 // assertion to be checked. 01587 x.initialized = true; 01588 } 01589 01590 // Apply incrementality to the pending constraint system. 01591 x.process_pending_constraints(); 01592 // Update `first_pending_constraint': no more pending. 01593 x.first_pending_constraint = input_cs.size(); 01594 // Update also `internal_space_dim'. 01595 x.internal_space_dim = x.external_space_dim; 01596 PPL_ASSERT(OK()); 01597 return status != UNSATISFIABLE; 01598 } 01599 } 01600 // We should not be here! 01601 throw std::runtime_error("PPL internal error"); 01602 }
| bool Parma_Polyhedra_Library::MIP_Problem::is_mip_satisfiable | ( | MIP_Problem & | lp, | |
| const Variables_Set & | i_vars, | |||
| Generator & | p | |||
| ) | [static, private] |
Returns true if and if only the LP problem lp is satisfiable when variables in i_vars can only take integral values.
| lp | The LP problem. This is assumed to have no integral space dimension. | |
| i_vars | The variables that are constrained to take integral values. | |
| p | If true is returned, it will encode a feasible point. |
Definition at line 1776 of file MIP_Problem.cc.
References add_constraint(), Parma_Polyhedra_Library::assign_r(), choose_branching_variable(), Parma_Polyhedra_Library::Generator::coefficient(), Parma_Polyhedra_Library::Generator::divisor(), Parma_Polyhedra_Library::gcd_assign(), integer_space_dimensions(), is_lp_satisfiable(), last_generator, PPL_DIRTY_TEMP_COEFFICIENT, and space_dimension().
Referenced by is_satisfiable().
01778 { 01779 #if PPL_NOISY_SIMPLEX 01780 ++mip_recursion_level; 01781 std::cout << "MIP_Problem::is_mip_satisfiable(): " 01782 << "entering recursion level " << mip_recursion_level 01783 << "." << std::endl; 01784 #endif // PPL_NOISY_SIMPLEX 01785 PPL_ASSERT(lp.integer_space_dimensions().empty()); 01786 01787 // Solve the LP problem. 01788 if (!lp.is_lp_satisfiable()) { 01789 #if PPL_NOISY_SIMPLEX 01790 std::cout << "MIP_Problem::is_mip_satisfiable(): " 01791 << "exiting from recursion level " << mip_recursion_level 01792 << "." << std::endl; 01793 --mip_recursion_level; 01794 #endif // PPL_NOISY_SIMPLEX 01795 return false; 01796 } 01797 01798 PPL_DIRTY_TEMP0(mpq_class, tmp_rational); 01799 PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff1); 01800 PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff2); 01801 bool found_satisfiable_generator = true; 01802 dimension_type nonint_dim; 01803 p = lp.last_generator; 01804 const Coefficient& p_divisor = p.divisor(); 01805 01806 #if PPL_SIMPLEX_USE_MIP_HEURISTIC 01807 found_satisfiable_generator 01808 = choose_branching_variable(lp, i_vars, nonint_dim); 01809 #else 01810 PPL_DIRTY_TEMP_COEFFICIENT(gcd); 01811 for (Variables_Set::const_iterator v_begin = i_vars.begin(), 01812 v_end = i_vars.end(); v_begin != v_end; ++v_begin) { 01813 gcd_assign(gcd, p.coefficient(Variable(*v_begin)), p_divisor); 01814 if (gcd != p_divisor) { 01815 nonint_dim = *v_begin; 01816 found_satisfiable_generator = false; 01817 break; 01818 } 01819 } 01820 #endif 01821 01822 if (found_satisfiable_generator) 01823 return true; 01824 01825 PPL_ASSERT(nonint_dim < lp.space_dimension()); 01826 01827 assign_r(tmp_rational.get_num(), p.coefficient(Variable(nonint_dim)), 01828 ROUND_NOT_NEEDED); 01829 assign_r(tmp_rational.get_den(), p_divisor, ROUND_NOT_NEEDED); 01830 tmp_rational.canonicalize(); 01831 assign_r(tmp_coeff1, tmp_rational, ROUND_DOWN); 01832 assign_r(tmp_coeff2, tmp_rational, ROUND_UP); 01833 { 01834 MIP_Problem lp_aux = lp; 01835 lp_aux.add_constraint(Variable(nonint_dim) <= tmp_coeff1); 01836 #if PPL_NOISY_SIMPLEX 01837 using namespace IO_Operators; 01838 std::cout << "MIP_Problem::is_mip_satisfiable(): " 01839 << "descending with: " 01840 << (Variable(nonint_dim) <= tmp_coeff1) 01841 << "." << std::endl; 01842 #endif // PPL_NOISY_SIMPLEX 01843 if (is_mip_satisfiable(lp_aux, i_vars, p)) { 01844 #if PPL_NOISY_SIMPLEX 01845 std::cout << "MIP_Problem::is_mip_satisfiable(): " 01846 << "exiting from recursion level " << mip_recursion_level 01847 << "." << std::endl; 01848 --mip_recursion_level; 01849 #endif // PPL_NOISY_SIMPLEX 01850 return true; 01851 } 01852 } 01853 lp.add_constraint(Variable(nonint_dim) >= tmp_coeff2); 01854 #if PPL_NOISY_SIMPLEX 01855 using namespace IO_Operators; 01856 std::cout << "MIP_Problem::is_mip_satisfiable(): " 01857 << "descending with: " 01858 << (Variable(nonint_dim) >= tmp_coeff2) 01859 << "." << std::endl; 01860 #endif // PPL_NOISY_SIMPLEX 01861 bool satisfiable = is_mip_satisfiable(lp, i_vars, p); 01862 #if PPL_NOISY_SIMPLEX 01863 std::cout << "MIP_Problem::is_mip_satisfiable(): " 01864 << "exiting from recursion level " << mip_recursion_level 01865 << "." << std::endl; 01866 --mip_recursion_level; 01867 #endif // PPL_NOISY_SIMPLEX 01868 return satisfiable; 01869 }
| bool Parma_Polyhedra_Library::MIP_Problem::is_satisfiable | ( | ) | const |
Checks satisfiability of *this.
true if and only if the MIP problem is satisfiable. Definition at line 213 of file MIP_Problem.cc.
References i_variables, Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::i_vars, is_lp_satisfiable(), is_mip_satisfiable(), last_generator, Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::lp, OK(), OPTIMIZED, PARTIALLY_SATISFIABLE, SATISFIABLE, status, UNBOUNDED, and UNSATISFIABLE.
Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::Box< ITV >::Box(), feasible_point(), and Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape().
00213 { 00214 // Check `status' to filter out trivial cases. 00215 switch (status) { 00216 case UNSATISFIABLE: 00217 PPL_ASSERT(OK()); 00218 return false; 00219 case SATISFIABLE: 00220 // Intentionally fall through 00221 case UNBOUNDED: 00222 // Intentionally fall through. 00223 case OPTIMIZED: 00224 PPL_ASSERT(OK()); 00225 return true; 00226 case PARTIALLY_SATISFIABLE: 00227 { 00228 MIP_Problem& x = const_cast<MIP_Problem&>(*this); 00229 // LP case. 00230 if (x.i_variables.empty()) 00231 return x.is_lp_satisfiable(); 00232 00233 // MIP case. 00234 { 00235 // Temporarily relax the MIP into an LP problem. 00236 RAII_Temporary_Real_Relaxation relaxed(x); 00237 Generator p = point(); 00238 relaxed.lp.is_lp_satisfiable(); 00239 #if PPL_NOISY_SIMPLEX 00240 mip_recursion_level = 0; 00241 #endif // PPL_NOISY_SIMPLEX 00242 if (is_mip_satisfiable(relaxed.lp, relaxed.i_vars, p)) { 00243 x.last_generator = p; 00244 x.status = SATISFIABLE; 00245 } 00246 else 00247 x.status = UNSATISFIABLE; 00248 } // `relaxed' destroyed here: relaxation automatically reset. 00249 return (x.status == SATISFIABLE); 00250 } 00251 } 00252 // We should not be here! 00253 throw std::runtime_error("PPL internal error"); 00254 }
| bool Parma_Polyhedra_Library::MIP_Problem::is_satisfied | ( | const Constraint & | c, | |
| const Generator & | g | |||
| ) | [static, private] |
Returns true if and only if c is satisfied by g.
Definition at line 432 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Constraint::is_inequality(), Parma_Polyhedra_Library::Scalar_Products::sign(), Parma_Polyhedra_Library::Constraint::space_dimension(), and Parma_Polyhedra_Library::Generator::space_dimension().
Referenced by OK(), and parse_constraints().
00432 { 00433 // Scalar_Products::sign() requires the second argument to be at least 00434 // as large as the first one. 00435 int sp_sign = g.space_dimension() <= c.space_dimension() 00436 ? Scalar_Products::sign(g, c) 00437 : Scalar_Products::sign(c, g); 00438 return c.is_inequality() ? sp_sign >= 0 : sp_sign == 0; 00439 }
| bool Parma_Polyhedra_Library::MIP_Problem::is_saturated | ( | const Constraint & | c, | |
| const Generator & | g | |||
| ) | [static, private] |
Returns true if and only if c is saturated by g.
Definition at line 442 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Scalar_Products::sign(), Parma_Polyhedra_Library::Constraint::space_dimension(), and Parma_Polyhedra_Library::Generator::space_dimension().
Referenced by choose_branching_variable().
00442 { 00443 // Scalar_Products::sign() requires the space dimension of the second 00444 // argument to be at least as large as the one of the first one. 00445 int sp_sign = g.space_dimension() <= c.space_dimension() 00446 ? Scalar_Products::sign(g, c) 00447 : Scalar_Products::sign(c, g); 00448 return sp_sign == 0; 00449 }
| void Parma_Polyhedra_Library::MIP_Problem::linear_combine | ( | Row & | x, | |
| const Row & | y, | |||
| const dimension_type | k | |||
| ) | [static, private] |
Linearly combines x with y so that *this[k] is 0.
| x | The Row that will be combined with y object. | |
| y | The Row that will be combined with x object. | |
| k | The position of *this that have to be . |
Computes a linear combination of x and y having the element of index k equal to
. Then it assigns the resulting Linear_Row to x and normalizes it.
Definition at line 1086 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Row::normalize(), Parma_Polyhedra_Library::normalize2(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Row::size(), Parma_Polyhedra_Library::sub_mul_assign(), WEIGHT_ADD_MUL, and WEIGHT_BEGIN.
Referenced by pivot(), process_pending_constraints(), and second_phase().
01088 { 01089 WEIGHT_BEGIN(); 01090 const dimension_type x_size = x.size(); 01091 PPL_ASSERT(x_size == y.size()); 01092 PPL_ASSERT(y[k] != 0 && x[k] != 0); 01093 // Let g be the GCD between `x[k]' and `y[k]'. 01094 // For each i the following computes 01095 // x[i] = x[i]*y[k]/g - y[i]*x[k]/g. 01096 PPL_DIRTY_TEMP_COEFFICIENT(normalized_x_k); 01097 PPL_DIRTY_TEMP_COEFFICIENT(normalized_y_k); 01098 normalize2(x[k], y[k], normalized_x_k, normalized_y_k); 01099 for (dimension_type i = x_size; i-- > 0; ) 01100 if (i != k) { 01101 Coefficient& x_i = x[i]; 01102 x_i *= normalized_y_k; 01103 // The test against 0 gives rise to a consistent speed up: see 01104 // http://www.cs.unipr.it/pipermail/ppl-devel/2009-February/014000.html 01105 const Coefficient& y_i = y[i]; 01106 if (y_i != 0) 01107 sub_mul_assign(x_i, y_i, normalized_x_k); 01108 } 01109 x[k] = 0; 01110 x.normalize(); 01111 WEIGHT_ADD_MUL(83, x_size); 01112 }
| dimension_type Parma_Polyhedra_Library::MIP_Problem::max_space_dimension | ( | ) | [inline, static] |
Returns the maximum space dimension an MIP_Problem can handle.
Definition at line 33 of file MIP_Problem.inlines.hh.
Referenced by add_space_dimensions_and_embed(), and MIP_Problem().
00033 { 00034 return Constraint::max_space_dimension(); 00035 }
| PPL::dimension_type Parma_Polyhedra_Library::MIP_Problem::merge_split_variable | ( | dimension_type | var_index | ) | [private] |
Merges back the positive and negative part of a (previously split) variable after detecting a corresponding nonnegativity constraint.
var_index was in base, the index of the corresponding tableau row (which has become nonfeasible); otherwise not_a_dimension().| var_index | The index of the variable that has to be merged. |
Definition at line 375 of file MIP_Problem.cc.
References base, is_in_base(), mapping, Parma_Polyhedra_Library::not_a_dimension(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::permute_columns(), Parma_Polyhedra_Library::Matrix::remove_trailing_columns(), and tableau.
Referenced by process_pending_constraints().
00375 { 00376 // Initialize the return value to a dummy index. 00377 dimension_type unfeasible_tableau_row = not_a_dimension(); 00378 00379 const dimension_type removing_column = mapping[1+var_index].second; 00380 00381 // Check if the negative part of the split variable is in base: 00382 // if so, the corresponding tableau row becomes nonfeasible. 00383 { 00384 dimension_type base_index; 00385 if (is_in_base(removing_column, base_index)) { 00386 // Set the return value. 00387 unfeasible_tableau_row = base_index; 00388 // Reset base[base_index] to zero to remember nonfeasibility. 00389 base[base_index] = 0; 00390 #ifndef NDEBUG 00391 // Since the negative part of the variable is in base, 00392 // the positive part can not be in base too. 00393 PPL_ASSERT(!is_in_base(mapping[1+var_index].first, base_index)); 00394 #endif 00395 } 00396 } 00397 00398 // Remove the column: 00399 // first, make sure it is the last one in the tableau ... 00400 const dimension_type tableau_num_cols = tableau.num_columns(); 00401 if (removing_column != tableau_num_cols - 1) { 00402 std::vector<dimension_type> cycle; 00403 for (dimension_type j = tableau_num_cols - 1; j >= removing_column; --j) 00404 cycle.push_back(j); 00405 cycle.push_back(0); 00406 tableau.permute_columns(cycle); 00407 } 00408 // ... and then actually remove it. 00409 tableau.remove_trailing_columns(1); 00410 00411 // var_index is no longer split. 00412 mapping[1+var_index].second = 0; 00413 00414 // Adjust data structured, `shifting' the proper columns to the left by 1. 00415 const dimension_type base_size = base.size(); 00416 for (dimension_type i = base_size; i-- > 0; ) { 00417 if (base[i] > removing_column) 00418 --base[i]; 00419 } 00420 const dimension_type mapping_size = mapping.size(); 00421 for (dimension_type i = mapping_size; i-- > 0; ) { 00422 if (mapping[i].first > removing_column) 00423 --mapping[i].first; 00424 if (mapping[i].second > removing_column) 00425 --mapping[i].second; 00426 } 00427 00428 return unfeasible_tableau_row; 00429 }
| const Linear_Expression & Parma_Polyhedra_Library::MIP_Problem::objective_function | ( | ) | const [inline] |
Returns the objective function.
Definition at line 79 of file MIP_Problem.inlines.hh.
References input_obj_function.
Referenced by operator<<().
00079 { 00080 return input_obj_function; 00081 }
| bool Parma_Polyhedra_Library::MIP_Problem::OK | ( | ) | const |
Checks if all the invariants are satisfied.
Definition at line 1872 of file MIP_Problem.cc.
References ascii_dump(), base, Parma_Polyhedra_Library::Generator::coefficient(), Parma_Polyhedra_Library::Generator::divisor(), external_space_dim, first_pending_constraint, Parma_Polyhedra_Library::gcd_assign(), i_variables, initialized, input_cs, input_obj_function, is_satisfied(), last_generator, mapping, Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Generator::OK(), Parma_Polyhedra_Library::Linear_Expression::OK(), Parma_Polyhedra_Library::Matrix::OK(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Row::size(), Parma_Polyhedra_Library::Generator::space_dimension(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), status, tableau, UNSATISFIABLE, and working_cost.
Referenced by add_constraint(), add_constraints(), add_space_dimensions_and_embed(), is_lp_satisfiable(), is_satisfiable(), MIP_Problem(), process_pending_constraints(), second_phase(), set_objective_function(), set_optimization_mode(), and solve().
01872 { 01873 #ifndef NDEBUG 01874 using std::endl; 01875 using std::cerr; 01876 #endif 01877 const dimension_type input_cs_num_rows = input_cs.size(); 01878 // Check that every member used is OK. 01879 01880 for (dimension_type i = input_cs_num_rows; i-- > 0; ) 01881 if (!input_cs[i].OK()) 01882 return false; 01883 01884 if (!tableau.OK() || !input_obj_function.OK() || !last_generator.OK()) 01885 return false; 01886 01887 // Constraint system should contain no strict inequalities. 01888 for (dimension_type i = input_cs_num_rows; i-- > 0; ) 01889 if (input_cs[i].is_strict_inequality()) { 01890 #ifndef NDEBUG 01891 cerr << "The feasible region of the MIP_Problem is defined by " 01892 << "a constraint system containing strict inequalities." 01893 << endl; 01894 ascii_dump(cerr); 01895 #endif 01896 return false; 01897 } 01898 01899 // Constraint system and objective function should be dimension compatible. 01900 if (external_space_dim < input_obj_function.space_dimension()) { 01901 #ifndef NDEBUG 01902 cerr << "The MIP_Problem and the objective function have " 01903 << "incompatible space dimensions (" 01904 << external_space_dim << " < " 01905 << input_obj_function.space_dimension() << ")." 01906 << endl; 01907 ascii_dump(cerr); 01908 #endif 01909 return false; 01910 } 01911 01912 if (status != UNSATISFIABLE && initialized) { 01913 // Here `last_generator' has to be meaningful. 01914 // Check for dimension compatibility and actual feasibility. 01915 if (external_space_dim != last_generator.space_dimension()) { 01916 #ifndef NDEBUG 01917 cerr << "The MIP_Problem and the cached feasible point have " 01918 << "incompatible space dimensions (" 01919 << external_space_dim << " != " 01920 << last_generator.space_dimension() << ")." 01921 << endl; 01922 ascii_dump(cerr); 01923 #endif 01924 return false; 01925 } 01926 01927 for (dimension_type i = 0; i < first_pending_constraint; ++i) 01928 if (!is_satisfied(input_cs[i], last_generator)) { 01929 #ifndef NDEBUG 01930 cerr << "The cached feasible point does not belong to " 01931 << "the feasible region of the MIP_Problem." 01932 << endl; 01933 ascii_dump(cerr); 01934 #endif 01935 return false; 01936 } 01937 01938 // Check that every integer declared variable is really integer. 01939 // in the solution found. 01940 if (!i_variables.empty()) { 01941 PPL_DIRTY_TEMP_COEFFICIENT(gcd); 01942 for (Variables_Set::const_iterator v_it = i_variables.begin(), 01943 v_end = i_variables.end(); v_it != v_end; ++v_it) { 01944 gcd_assign(gcd, last_generator.coefficient(Variable(*v_it)), 01945 last_generator.divisor()); 01946 if (gcd != last_generator.divisor()) 01947 return false; 01948 } 01949 } 01950 01951 const dimension_type tableau_nrows = tableau.num_rows(); 01952 const dimension_type tableau_ncols = tableau.num_columns(); 01953 01954 // The number of rows in the tableau and base should be equal. 01955 if (tableau_nrows != base.size()) { 01956 #ifndef NDEBUG 01957 cerr << "tableau and base have incompatible sizes" << endl; 01958 ascii_dump(cerr); 01959 #endif 01960 return false; 01961 } 01962 // The size of `mapping' should be equal to the space dimension 01963 // of `input_cs' plus one. 01964 if (mapping.size() != external_space_dim + 1) { 01965 #ifndef NDEBUG 01966 cerr << "`input_cs' and `mapping' have incompatible sizes" << endl; 01967 ascii_dump(cerr); 01968 #endif 01969 return false; 01970 } 01971 01972 // The number of columns in the tableau and working_cost should be equal. 01973 if (tableau_ncols != working_cost.size()) { 01974 #ifndef NDEBUG 01975 cerr << "tableau and working_cost have incompatible sizes" << endl; 01976 ascii_dump(cerr); 01977 #endif 01978 return false; 01979 } 01980 01981 // The vector base should contain indices of tableau's columns. 01982 for (dimension_type i = base.size(); i-- > 0; ) { 01983 if (base[i] > tableau_ncols) { 01984 #ifndef NDEBUG 01985 cerr << "base contains an invalid column index" << endl; 01986 ascii_dump(cerr); 01987 #endif 01988 return false; 01989 } 01990 // tableau[i][base[i] must be different from zero. 01991 // tableau[i][base[j], with i different from j, must not be a zero. 01992 for (dimension_type j = tableau_nrows; j-- > 0; ) 01993 if (i != j && tableau[j][base[i]] != 0) { 01994 #ifndef NDEBUG 01995 cerr << "tableau[i][base[i] must be different from zero" << endl; 01996 ascii_dump(cerr); 01997 #endif 01998 return false; 01999 } 02000 if (tableau[i][base[i]] == 0) { 02001 #ifndef NDEBUG 02002 cerr << "tableau[i][base[j], with i different from j, must not be " 02003 << "a zero" << endl; 02004 ascii_dump(cerr); 02005 #endif 02006 return false; 02007 } 02008 } 02009 02010 // The last column of the tableau must contain only zeroes. 02011 for (dimension_type i = tableau_nrows; i-- > 0; ) 02012 if (tableau[i][tableau_ncols-1] != 0) { 02013 #ifndef NDEBUG 02014 cerr << "the last column of the tableau must contain only" 02015 "zeroes"<< endl; 02016 ascii_dump(cerr); 02017 #endif 02018 return false; 02019 } 02020 } 02021 02022 // All checks passed. 02023 return true; 02024 }
| MIP_Problem & Parma_Polyhedra_Library::MIP_Problem::operator= | ( | const MIP_Problem & | y | ) | [inline] |
Assignment operator.
Definition at line 141 of file MIP_Problem.inlines.hh.
References swap().
00141 { 00142 MIP_Problem tmp(y); 00143 swap(tmp); 00144 return *this; 00145 }
| void Parma_Polyhedra_Library::MIP_Problem::optimal_value | ( | Coefficient & | num, | |
| Coefficient & | den | |||
| ) | const [inline] |
Sets num and den so that
is the solution of the optimization problem.
| std::domain_error | Thrown if *this doesn't not have an optimizing point, i.e., if the MIP problem is unbounded or not satisfiable. |
Definition at line 89 of file MIP_Problem.inlines.hh.
References evaluate_objective_function(), and optimizing_point().
Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BFT00_upper_bound_assign_if_exact(), Parma_Polyhedra_Library::Octagonal_Shape< T >::max_min(), and Parma_Polyhedra_Library::BD_Shape< T >::max_min().
00089 { 00090 const Generator& g = optimizing_point(); 00091 evaluate_objective_function(g, num, den); 00092 }
| Optimization_Mode Parma_Polyhedra_Library::MIP_Problem::optimization_mode | ( | ) | const [inline] |
Returns the optimization mode.
Definition at line 84 of file MIP_Problem.inlines.hh.
References opt_mode.
Referenced by operator<<(), and solve_mip().
00084 { 00085 return opt_mode; 00086 }
| const PPL::Generator & Parma_Polyhedra_Library::MIP_Problem::optimizing_point | ( | ) | const |
Returns an optimal point for *this, if it exists.
| std::domain_error | Thrown if *this doesn't not have an optimizing point, i.e., if the MIP problem is unbounded or not satisfiable. |
Definition at line 204 of file MIP_Problem.cc.
References last_generator, Parma_Polyhedra_Library::OPTIMIZED_MIP_PROBLEM, and solve().
Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::Octagonal_Shape< T >::max_min(), Parma_Polyhedra_Library::BD_Shape< T >::max_min(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), and optimal_value().
00204 { 00205 if (solve() == OPTIMIZED_MIP_PROBLEM) 00206 return last_generator; 00207 else 00208 throw std::domain_error("PPL::MIP_Problem::optimizing_point():\n" 00209 "*this doesn't have an optimizing point."); 00210 }
| bool Parma_Polyhedra_Library::MIP_Problem::parse_constraints | ( | dimension_type & | additional_tableau_rows, | |
| dimension_type & | additional_slack_variables, | |||
| std::deque< bool > & | is_tableau_constraint, | |||
| std::deque< bool > & | is_satisfied_inequality, | |||
| std::deque< bool > & | is_nonnegative_variable, | |||
| std::deque< bool > & | is_remergeable_variable | |||
| ) | const [private] |
Parses the pending constraints to gather information on how to resize the tableau.
true.false if a trivially false constraint is detected, true otherwise.| additional_tableau_rows | On exit, this will store the number of rows that have to be added to the original tableau. | |
| additional_slack_variables | This will store the number of slack variables that have to be added to the original tableau. | |
| is_tableau_constraint | This container of Boolean flags is initially empty. On exit, it size will be equal to the number of pending constraints in input_cs. For each pending constraint index i, the corresponding element of this container (having index i - first_pending_constraint) will be set to true if and only if the constraint has to be included in the tableau. | |
| is_satisfied_inequality | This container of Boolean flags is initially empty. On exit, its size will be equal to the number of pending constraints in input_cs. For each pending constraint index i, the corresponding element of this container (having index i - first_pending_constraint) will be set to true if and only if it is an inequality and it is already satisfied by last_generator (hence it does not require the introduction of an artificial variable). | |
| is_nonnegative_variable | This container of Boolean flags is initially empty. On exit, it size is equal to external_space_dim. For each variable (index), the corresponding element of this container is true if the variable is known to be nonnegative (and hence should not be split into a positive and a negative part). | |
| is_remergeable_variable | This container of Boolean flags is initially empty. On exit, it size is equal to internal_space_dim. For each variable (index), the corresponding element of this container is true if the variable was previously split into positive and negative parts that can now be merged back, since it is known that the variable is nonnegative. |
Definition at line 453 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Constraint::coefficient(), external_space_dim, first_pending_constraint, Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), input_cs, internal_space_dim, Parma_Polyhedra_Library::Constraint::is_equality(), Parma_Polyhedra_Library::Constraint::is_inequality(), is_satisfied(), last_generator, mapping, and Parma_Polyhedra_Library::Constraint::space_dimension().
Referenced by process_pending_constraints().
00458 { 00459 // Initially all containers are empty. 00460 PPL_ASSERT(is_tableau_constraint.empty() 00461 && is_satisfied_inequality.empty() 00462 && is_nonnegative_variable.empty() 00463 && is_remergeable_variable.empty()); 00464 00465 const dimension_type cs_space_dim = external_space_dim; 00466 const dimension_type cs_num_rows = input_cs.size(); 00467 const dimension_type cs_num_pending = cs_num_rows - first_pending_constraint; 00468 00469 // Counters determining the change in dimensions of the tableau: 00470 // initialized here, they will be updated while examining `input_cs'. 00471 additional_tableau_rows = cs_num_pending; 00472 additional_slack_variables = 0; 00473 00474 // Resize containers appropriately. 00475 00476 // On exit, `is_tableau_constraint[i]' will be true if and only if 00477 // `input_cs[first_pending_constraint + i]' is neither a tautology 00478 // (e.g., 1 >= 0) nor a non-negativity constraint (e.g., X >= 0). 00479 is_tableau_constraint.insert(is_tableau_constraint.end(), 00480 cs_num_pending, true); 00481 00482 // On exit, `is_satisfied_inequality[i]' will be true if and only if 00483 // `input_cs[first_pending_constraint + i]' is an inequality and it is 00484 // satisfied by `last_generator'. 00485 is_satisfied_inequality.insert(is_satisfied_inequality.end(), 00486 cs_num_pending, false); 00487 00488 // On exit, `is_nonnegative_variable[j]' will be true if and only if 00489 // Variable(j) is bound to be nonnegative in `input_cs'. 00490 is_nonnegative_variable.insert(is_nonnegative_variable.end(), 00491 cs_space_dim, false); 00492 00493 // On exit, `is_remergeable_variable[j]' will be true if and only if 00494 // Variable(j) was initially split and is now remergeable. 00495 is_remergeable_variable.insert(is_remergeable_variable.end(), 00496 internal_space_dim, false); 00497 00498 // Check for variables that are already known to be nonnegative 00499 // due to nonpending constraints. 00500 const dimension_type mapping_size = mapping.size(); 00501 if (mapping_size > 0) { 00502 // Note: mapping[0] is associated to the cost function. 00503 for (dimension_type i = std::min(mapping_size - 1, cs_space_dim); i-- > 0; ) 00504 if (mapping[i + 1].second == 0) 00505 is_nonnegative_variable[i] = true; 00506 } 00507 00508 // Process each pending constraint in `input_cs' and 00509 // - detect variables that are constrained to be nonnegative; 00510 // - detect (non-negativity or tautology) pending constraints that 00511 // will not be part of the tableau; 00512 // - count the number of new slack variables. 00513 for (dimension_type i = cs_num_rows; i-- > first_pending_constraint; ) { 00514 const Constraint& cs_i = input_cs[i]; 00515 bool found_a_nonzero_coeff = false; 00516 bool found_many_nonzero_coeffs = false; 00517 dimension_type nonzero_coeff_column_index = 0; 00518 for (dimension_type sd = cs_i.space_dimension(); sd-- > 0; ) { 00519 if (cs_i.coefficient(Variable(sd)) != 0) { 00520 if (found_a_nonzero_coeff) { 00521 found_many_nonzero_coeffs = true; 00522 if (cs_i.is_inequality()) 00523 ++additional_slack_variables; 00524 break; 00525 } 00526 else { 00527 nonzero_coeff_column_index = sd + 1; 00528 found_a_nonzero_coeff = true; 00529 } 00530 } 00531 } 00532 // If more than one coefficient is nonzero, 00533 // continue with next constraint. 00534 if (found_many_nonzero_coeffs) { 00535 // CHECKME: Is it true that in the first phase we can apply 00536 // `is_satisfied()' with the generator `point()'? If so, the following 00537 // code works even if we do not have a feasible point. 00538 // Check for satisfiability of the inequality. This can be done if we 00539 // have a feasible point of *this. 00540 if (cs_i.is_inequality() && is_satisfied(cs_i, last_generator)) 00541 is_satisfied_inequality[i - first_pending_constraint] = true; 00542 continue; 00543 } 00544 00545 if (!found_a_nonzero_coeff) { 00546 // All coefficients are 0. 00547 // The constraint is either trivially true or trivially false. 00548 if (cs_i.is_inequality()) { 00549 if (cs_i.inhomogeneous_term() < 0) 00550 // A constraint such as -1 >= 0 is trivially false. 00551 return false; 00552 } 00553 else 00554 // The constraint is an equality. 00555 if (cs_i.inhomogeneous_term() != 0) 00556 // A constraint such as 1 == 0 is trivially false. 00557 return false; 00558 // Here the constraint is trivially true. 00559 is_tableau_constraint[i - first_pending_constraint] = false; 00560 --additional_tableau_rows; 00561 continue; 00562 } 00563 else { 00564 // Here we have only one nonzero coefficient. 00565 /* 00566 00567 We have the following methods: 00568 A) Do split the variable and do add the constraint 00569 in the tableau. 00570 B) Do not split the variable and do add the constraint 00571 in the tableau. 00572 C) Do not split the variable and do not add the constraint 00573 in the tableau. 00574 00575 Let the constraint be (a*v + b relsym 0). 00576 These are the 12 possible combinations we can have: 00577 a | b | relsym | method 00578 ---------------------------------- 00579 1) >0 | >0 | >= | A 00580 2) >0 | >0 | == | A 00581 3) <0 | <0 | >= | A 00582 4) >0 | =0 | == | B 00583 5) >0 | <0 | == | B 00584 Note: <0 | >0 | == | impossible by strong normalization 00585 Note: <0 | =0 | == | impossible by strong normalization 00586 Note: <0 | <0 | == | impossible by strong normalization 00587 6) >0 | <0 | >= | B 00588 7) >0 | =0 | >= | C 00589 8) <0 | >0 | >= | A 00590 9) <0 | =0 | >= | A 00591 00592 The next lines will apply the correct method to each case. 00593 */ 00594 00595 // The variable index is not equal to the column index. 00596 const dimension_type nonzero_var_index = nonzero_coeff_column_index - 1; 00597 00598 const int sgn_a = sgn(cs_i.coefficient(Variable(nonzero_var_index))); 00599 const int sgn_b = sgn(cs_i.inhomogeneous_term()); 00600 00601 // Cases 1-3: apply method A. 00602 if (sgn_a == sgn_b) { 00603 if (cs_i.is_inequality()) 00604 ++additional_slack_variables; 00605 } 00606 // Cases 4-5: apply method B. 00607 else if (cs_i.is_equality()) 00608 is_nonnegative_variable[nonzero_var_index] = true; 00609 // Case 6: apply method B. 00610 else if (sgn_b < 0) { 00611 is_nonnegative_variable[nonzero_var_index] = true; 00612 ++additional_slack_variables; 00613 } 00614 // Case 7: apply method C. 00615 else if (sgn_a > 0) { 00616 if (!is_nonnegative_variable[nonzero_var_index]) { 00617 is_nonnegative_variable[nonzero_var_index] = true; 00618 if (nonzero_coeff_column_index < mapping_size) { 00619 // Remember to merge back the positive and negative parts. 00620 PPL_ASSERT(nonzero_var_index < internal_space_dim); 00621 is_remergeable_variable[nonzero_var_index] = true; 00622 } 00623 } 00624 is_tableau_constraint[i - first_pending_constraint] = false; 00625 --additional_tableau_rows; 00626 } 00627 // Cases 8-9: apply method A. 00628 else { 00629 PPL_ASSERT(cs_i.is_inequality()); 00630 ++additional_slack_variables; 00631 } 00632 } 00633 } 00634 return true; 00635 }
| void Parma_Polyhedra_Library::MIP_Problem::pivot | ( | dimension_type | entering_var_index, | |
| dimension_type | exiting_base_index | |||
| ) | [private] |
Performs the pivoting operation on the tableau.
| entering_var_index | The index of the variable entering the base. | |
| exiting_base_index | The index of the row exiting the base. |
Definition at line 1116 of file MIP_Problem.cc.
References base, linear_combine(), Parma_Polyhedra_Library::Matrix::num_rows(), tableau, and working_cost.
Referenced by compute_simplex_using_exact_pricing(), compute_simplex_using_steepest_edge_float(), and erase_artificials().
01117 { 01118 const Row& tableau_out = tableau[exiting_base_index]; 01119 // Linearly combine the constraints. 01120 for (dimension_type i = tableau.num_rows(); i-- > 0; ) { 01121 Row& tableau_i = tableau[i]; 01122 if (i != exiting_base_index && tableau_i[entering_var_index] != 0) 01123 linear_combine(tableau_i, tableau_out, entering_var_index); 01124 } 01125 // Linearly combine the cost function. 01126 if (working_cost[entering_var_index] != 0) 01127 linear_combine(working_cost, tableau_out, entering_var_index); 01128 // Adjust the base. 01129 base[exiting_base_index] = entering_var_index; 01130 }
| void Parma_Polyhedra_Library::MIP_Problem::print | ( | ) | const |
Prints *this to std::cerr using operator<<.
| bool Parma_Polyhedra_Library::MIP_Problem::process_pending_constraints | ( | ) | [private] |
Processes the pending constraints of *this.
true if and only if the MIP problem is satisfiable after processing the pending constraints, false otherwise. Definition at line 638 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Matrix::add_zero_columns(), Parma_Polyhedra_Library::Matrix::add_zero_rows(), base, Parma_Polyhedra_Library::Linear_Expression::coefficient(), Parma_Polyhedra_Library::Constraint::coefficient(), compute_generator(), compute_simplex_using_exact_pricing(), compute_simplex_using_steepest_edge_float(), erase_artificials(), external_space_dim, first_pending_constraint, get_control_parameter(), Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), input_cs, input_obj_function, internal_space_dim, Parma_Polyhedra_Library::Constraint::is_inequality(), last_generator, linear_combine(), mapping, Parma_Polyhedra_Library::MAXIMIZATION, merge_split_variable(), Parma_Polyhedra_Library::MINIMIZATION, Parma_Polyhedra_Library::neg_assign(), Parma_Polyhedra_Library::not_a_dimension(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), opt_mode, OPTIMIZED, parse_constraints(), PRICING, PRICING_STEEPEST_EDGE_FLOAT, SATISFIABLE, Parma_Polyhedra_Library::Row::size(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), space_dimension(), Parma_Polyhedra_Library::Constraint::space_dimension(), status, tableau, UNBOUNDED, UNSATISFIABLE, and working_cost.
Referenced by is_lp_satisfiable().
00638 { 00639 // Check the pending constraints to adjust the data structures. 00640 // If `false' is returned, they are trivially unfeasible. 00641 dimension_type additional_tableau_rows = 0; 00642 dimension_type additional_slack_vars = 0; 00643 std::deque<bool> is_tableau_constraint; 00644 std::deque<bool> is_satisfied_inequality; 00645 std::deque<bool> is_nonnegative_variable; 00646 std::deque<bool> is_remergeable_variable; 00647 if (!parse_constraints(additional_tableau_rows, 00648 additional_slack_vars, 00649 is_tableau_constraint, 00650 is_satisfied_inequality, 00651 is_nonnegative_variable, 00652 is_remergeable_variable)) { 00653 status = UNSATISFIABLE; 00654 return false; 00655 }; 00656 00657 // Merge back any variable that was previously split into a positive 00658 // and a negative part and is now known to be nonnegative. 00659 std::vector<dimension_type> unfeasible_tableau_rows; 00660 for (dimension_type i = internal_space_dim; i-- > 0; ) { 00661 if (!is_remergeable_variable[i]) 00662 continue; 00663 // TODO: merging all rows in a single shot may be more efficient 00664 // as it would require a single call to permute_columns(). 00665 const dimension_type unfeasible_row = merge_split_variable(i); 00666 if (unfeasible_row != not_a_dimension()) 00667 unfeasible_tableau_rows.push_back(unfeasible_row); 00668 } 00669 00670 const dimension_type old_tableau_num_rows = tableau.num_rows(); 00671 const dimension_type old_tableau_num_cols = tableau.num_columns(); 00672 const dimension_type first_free_tableau_index = old_tableau_num_cols - 1; 00673 00674 // Update mapping for the new problem variables (if any). 00675 dimension_type additional_problem_vars = 0; 00676 if (external_space_dim > internal_space_dim) { 00677 const dimension_type space_diff = external_space_dim - internal_space_dim; 00678 for (dimension_type i = 0, j = 0; i < space_diff; ++i) { 00679 // Let `mapping' associate the variable index with the corresponding 00680 // tableau column: split the variable into positive and negative 00681 // parts if it is not known to be nonnegative. 00682 const dimension_type positive = first_free_tableau_index + j; 00683 if (is_nonnegative_variable[internal_space_dim + i]) { 00684 // Do not split. 00685 mapping.push_back(std::make_pair(positive, 0)); 00686 ++j; 00687 ++additional_problem_vars; 00688 } 00689 else { 00690 // Split: negative index is positive + 1. 00691 mapping.push_back(std::make_pair(positive, positive + 1)); 00692 j += 2; 00693 additional_problem_vars += 2; 00694 } 00695 } 00696 } 00697 00698 // Resize the tableau: first add additional rows ... 00699 if (additional_tableau_rows > 0) 00700 tableau.add_zero_rows(additional_tableau_rows, Row::Flags()); 00701 00702 // ... then add additional columns. 00703 // We need columns for additional (split) problem variables, additional 00704 // slack variables and additional artificials. 00705 // The number of artificials to be added is computed as: 00706 // * number of pending constraints entering the tableau 00707 // minus 00708 // * pending constraints that are inequalities and are already satisfied 00709 // by `last_generator' 00710 // plus 00711 // * number of non-pending constraints that are no longer satisfied 00712 // due to re-merging of splitted variables. 00713 00714 dimension_type num_satisfied_ineqs 00715 = std::count(is_satisfied_inequality.begin(), 00716 is_satisfied_inequality.end(), 00717 true); 00718 const dimension_type unfeasible_tableau_rows_size 00719 = unfeasible_tableau_rows.size(); 00720 00721 const dimension_type additional_artificial_vars 00722 = (additional_tableau_rows - num_satisfied_ineqs) 00723 + unfeasible_tableau_rows_size; 00724 00725 const dimension_type additional_tableau_columns 00726 = additional_problem_vars 00727 + additional_slack_vars 00728 + additional_artificial_vars; 00729 00730 if (additional_tableau_columns > 0) 00731 tableau.add_zero_columns(additional_tableau_columns); 00732 00733 // Dimensions of the tableau after resizing. 00734 const dimension_type tableau_num_rows = tableau.num_rows(); 00735 const dimension_type tableau_num_cols = tableau.num_columns(); 00736 00737 // The following vector will be useful know if a constraint is feasible 00738 // and does not require an additional artificial variable. 00739 std::deque<bool> worked_out_row (tableau_num_rows, false); 00740 00741 // Sync the `base' vector size to the new tableau: fill with zeros 00742 // to encode that these rows are not OK and must be adjusted. 00743 base.insert(base.end(), additional_tableau_rows, 0); 00744 const dimension_type base_size = base.size(); 00745 00746 // These indexes will be used to insert slack and artificial variables 00747 // in the appropriate position. 00748 dimension_type slack_index 00749 = tableau_num_cols - additional_artificial_vars - 1; 00750 dimension_type artificial_index = slack_index; 00751 00752 // The first column of the tableau containing an artificial variable. 00753 // Encode with 0 the fact that there are no artificial variables at all. 00754 const dimension_type begin_artificials 00755 = additional_artificial_vars > 0 ? artificial_index : 0; 00756 00757 // Proceed with the insertion of the pending constraints. 00758 for (dimension_type k = tableau_num_rows, 00759 i = input_cs.size() - first_pending_constraint; i-- > 0; ) { 00760 // Skip if trivially redundant. 00761 if (!is_tableau_constraint[i]) 00762 continue; 00763 const Constraint& c = input_cs[i + first_pending_constraint]; 00764 // Copy the original constraint in the tableau. 00765 --k; 00766 Row& tableau_k = tableau[k]; 00767 for (dimension_type sd = c.space_dimension(); sd-- > 0; ) { 00768 const Coefficient& coeff_sd = c.coefficient(Variable(sd)); 00769 if (coeff_sd != 0) { 00770 tableau_k[mapping[sd+1].first] = coeff_sd; 00771 // Split if needed. 00772 if (mapping[sd+1].second != 0) 00773 neg_assign(tableau_k[mapping[sd+1].second], coeff_sd); 00774 } 00775 } 00776 const Coefficient& inhomo = c.inhomogeneous_term(); 00777 if (inhomo != 0) { 00778 tableau_k[mapping[0].first] = inhomo; 00779 // Split if needed. 00780 if (mapping[0].second != 0) 00781 neg_assign(tableau_k[mapping[0].second], inhomo); 00782 } 00783 00784 // Add the slack variable, if needed. 00785 if (c.is_inequality()) { 00786 --slack_index; 00787 tableau_k[slack_index] = -1; 00788 // If the constraint is already satisfied, we will not add an 00789 // artificial variable and put instead the slack variable in base. 00790 if (is_satisfied_inequality[i]) { 00791 base[k] = slack_index; 00792 worked_out_row[k] = true; 00793 } 00794 } 00795 for (dimension_type j = base_size; j-- > 0; ) 00796 if (k != j && tableau_k[base[j]] != 0 && base[j] != 0) 00797 linear_combine(tableau_k, tableau[j], base[j]); 00798 } 00799 00800 // Let all inhomogeneous terms in the tableau be nonpositive, 00801 // so as to simplify the insertion of artificial variables 00802 // (the coefficient of each artificial variable will be 1). 00803 for (dimension_type i = tableau_num_rows; i-- > 0 ; ) { 00804 Row& tableau_i = tableau[i]; 00805 if (tableau_i[0] > 0) 00806 for (dimension_type j = tableau_num_cols; j-- > 0; ) 00807 neg_assign(tableau_i[j]); 00808 } 00809 00810 // Reset the working cost function to have the right size. 00811 working_cost = Row(tableau_num_cols, Row::Flags()); 00812 00813 // Set up artificial variables: these will have coefficient 1 in the 00814 // constraint, will enter the base and will have coefficient -1 in 00815 // the cost function. 00816 00817 // First go through nonpending constraints that became unfeasible 00818 // due to re-merging of split variables. 00819 for (dimension_type i = 0; i < unfeasible_tableau_rows_size; ++i) { 00820 tableau[unfeasible_tableau_rows[i]][artificial_index] = 1; 00821 working_cost[artificial_index] = -1; 00822 base[unfeasible_tableau_rows[i]] = artificial_index; 00823 ++artificial_index; 00824 } 00825 // Then go through newly added tableau rows, disregarding inequalities 00826 // that are already satisfied by `last_generator' (this information 00827 // is encoded in `worked_out_row'). 00828 for (dimension_type i = old_tableau_num_rows; i < tableau_num_rows; ++i) { 00829 if (worked_out_row[i]) 00830 continue; 00831 tableau[i][artificial_index] = 1; 00832 working_cost[artificial_index] = -1; 00833 base[i] = artificial_index; 00834 ++artificial_index; 00835 } 00836 // One past the last tableau column index containing an artificial variable. 00837 const dimension_type end_artificials = artificial_index; 00838 00839 // Set the extra-coefficient of the cost functions to record its sign. 00840 // This is done to keep track of the possible sign's inversion. 00841 const dimension_type last_obj_index = working_cost.size() - 1; 00842 working_cost[last_obj_index] = 1; 00843 00844 // Express the problem in terms of the variables in base. 00845 for (dimension_type i = tableau_num_rows; i-- > 0; ) 00846 if (working_cost[base[i]] != 0) 00847 linear_combine(working_cost, tableau[i], base[i]); 00848 00849 // Deal with zero dimensional problems. 00850 if (space_dimension() == 0) { 00851 status = OPTIMIZED; 00852 last_generator = point(); 00853 return true; 00854 } 00855 // Deal with trivial cases. 00856 // If there is no constraint in the tableau, then the feasible region 00857 // is only delimited by non-negativity constraints. Therefore, 00858 // the problem is unbounded as soon as the cost function has 00859 // a variable with a positive coefficient. 00860 if (tableau_num_rows == 0) { 00861 const dimension_type input_obj_function_size 00862 = input_obj_function.space_dimension(); 00863 for (dimension_type i = input_obj_function_size; i-- > 0; ) 00864 // If a the value of a variable in the objective function is 00865 // different from zero, the final status is unbounded. 00866 // In the first part the variable is constrained to be greater or equal 00867 // than zero. 00868 if ((((input_obj_function.coefficient(Variable(i)) > 0 00869 && opt_mode == MAXIMIZATION) 00870 || (input_obj_function.coefficient(Variable(i)) < 0 00871 && opt_mode == MINIMIZATION)) && mapping[i].second == 0) 00872 // In the following case the variable is unconstrained. 00873 || (input_obj_function.coefficient(Variable(i)) != 0 00874 && mapping[i].second != 0)) { 00875 // Ensure the right space dimension is obtained. 00876 last_generator = point(0 * Variable(space_dimension()-1)); 00877 status = UNBOUNDED; 00878 return true; 00879 } 00880 00881 // The problem is neither trivially unfeasible nor trivially unbounded. 00882 // The tableau was successful computed and the caller has to figure 00883 // out which case applies. 00884 status = OPTIMIZED; 00885 // Ensure the right space dimension is obtained. 00886 last_generator = point(0*Variable(space_dimension()-1)); 00887 PPL_ASSERT(OK()); 00888 return true; 00889 } 00890 00891 // Now we are ready to solve the first phase. 00892 bool first_phase_succesful 00893 = (get_control_parameter(PRICING) == PRICING_STEEPEST_EDGE_FLOAT) 00894 ? compute_simplex_using_steepest_edge_float() 00895 : compute_simplex_using_exact_pricing(); 00896 00897 #if PPL_NOISY_SIMPLEX 00898 std::cout << "MIP_Problem::process_pending_constraints(): " 00899 << "1st phase ended at iteration " << num_iterations 00900 << "." << std::endl; 00901 #endif // PPL_NOISY_SIMPLEX 00902 00903 if (!first_phase_succesful || working_cost[0] != 0) { 00904 // The feasible region is empty. 00905 status = UNSATISFIABLE; 00906 return false; 00907 } 00908 00909 // Prepare *this for a possible second phase. 00910 if (begin_artificials != 0) 00911 erase_artificials(begin_artificials, end_artificials); 00912 compute_generator(); 00913 status = SATISFIABLE; 00914 PPL_ASSERT(OK()); 00915 return true; 00916 }
| void Parma_Polyhedra_Library::MIP_Problem::second_phase | ( | ) | [private] |
Optimizes the MIP problem using the second phase of the primal simplex algorithm.
Definition at line 1474 of file MIP_Problem.cc.
References base, Parma_Polyhedra_Library::Linear_Expression::coefficient(), compute_generator(), compute_simplex_using_exact_pricing(), compute_simplex_using_steepest_edge_float(), get_control_parameter(), Parma_Polyhedra_Library::Linear_Expression::inhomogeneous_term(), input_obj_function, linear_combine(), mapping, Parma_Polyhedra_Library::MINIMIZATION, Parma_Polyhedra_Library::neg_assign(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), opt_mode, OPTIMIZED, PRICING, PRICING_STEEPEST_EDGE_FLOAT, SATISFIABLE, Parma_Polyhedra_Library::Row::size(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), status, Parma_Polyhedra_Library::Row::swap(), tableau, UNBOUNDED, and working_cost.
Referenced by solve(), and solve_mip().
01474 { 01475 // Second_phase requires that *this is satisfiable. 01476 PPL_ASSERT(status == SATISFIABLE || status == UNBOUNDED || status == OPTIMIZED); 01477 // In the following cases the problem is already solved. 01478 if (status == UNBOUNDED || status == OPTIMIZED) 01479 return; 01480 01481 // Build the objective function for the second phase. 01482 const dimension_type input_obj_function_sd 01483 = input_obj_function.space_dimension(); 01484 Row new_cost(input_obj_function_sd + 1, Row::Flags()); 01485 for (dimension_type i = input_obj_function_sd; i-- > 0; ) 01486 new_cost[i+1] = input_obj_function.coefficient(Variable(i)); 01487 new_cost[0] = input_obj_function.inhomogeneous_term(); 01488 01489 // Negate the cost function if we are minimizing. 01490 if (opt_mode == MINIMIZATION) 01491 for (dimension_type i = new_cost.size(); i-- > 0; ) 01492 neg_assign(new_cost[i]); 01493 01494 // Substitute properly the cost function in the `costs' matrix. 01495 const dimension_type cost_zero_size = working_cost.size(); 01496 Row tmp_cost = Row(new_cost, cost_zero_size, cost_zero_size); 01497 tmp_cost.swap(working_cost); 01498 working_cost[cost_zero_size-1] = 1; 01499 01500 // Split the variables the cost function. 01501 for (dimension_type i = new_cost.size(); i-- > 1; ) { 01502 const dimension_type original_var = mapping[i].first; 01503 const dimension_type split_var = mapping[i].second; 01504 working_cost[original_var] = new_cost[i]; 01505 if (mapping[i].second != 0) 01506 neg_assign(working_cost[split_var], new_cost[i]); 01507 } 01508 // Here the first phase problem succeeded with optimum value zero. 01509 // Express the old cost function in terms of the computed base. 01510 for (dimension_type i = tableau.num_rows(); i-- > 0; ) { 01511 const dimension_type base_i = base[i]; 01512 if (working_cost[base_i] != 0) 01513 linear_combine(working_cost, tableau[i], base_i); 01514 } 01515 // Solve the second phase problem. 01516 bool second_phase_successful 01517 = (get_control_parameter(PRICING) == PRICING_STEEPEST_EDGE_FLOAT) 01518 ? compute_simplex_using_steepest_edge_float() 01519 : compute_simplex_using_exact_pricing(); 01520 compute_generator(); 01521 #if PPL_NOISY_SIMPLEX 01522 std::cout << "MIP_Problem::second_phase(): 2nd phase ended at iteration " 01523 << num_iterations 01524 << "." << std::endl; 01525 #endif // PPL_NOISY_SIMPLEX 01526 status = second_phase_successful ? OPTIMIZED : UNBOUNDED; 01527 PPL_ASSERT(OK()); 01528 }
| void Parma_Polyhedra_Library::MIP_Problem::set_control_parameter | ( | Control_Parameter_Value | value | ) | [inline] |
Sets control parameter value.
Definition at line 117 of file MIP_Problem.inlines.hh.
References pricing.
00117 { 00118 pricing = value; 00119 }
| void Parma_Polyhedra_Library::MIP_Problem::set_objective_function | ( | const Linear_Expression & | obj | ) |
Sets the objective function to obj.
| std::invalid_argument | Thrown if the space dimension of obj is strictly greater than the space dimension of *this. |
Definition at line 179 of file MIP_Problem.cc.
References input_obj_function, OK(), OPTIMIZED, SATISFIABLE, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), space_dimension(), status, and UNBOUNDED.
Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), and Parma_Polyhedra_Library::Polyhedron::strongly_minimize_constraints().
00179 { 00180 if (space_dimension() < obj.space_dimension()) { 00181 std::ostringstream s; 00182 s << "PPL::MIP_Problem::set_objective_function(obj):\n" 00183 << "obj.space_dimension() == " << obj.space_dimension() 00184 << " exceeds this->space_dimension == " << space_dimension() 00185 << "."; 00186 throw std::invalid_argument(s.str()); 00187 } 00188 input_obj_function = obj; 00189 if (status == UNBOUNDED || status == OPTIMIZED) 00190 status = SATISFIABLE; 00191 PPL_ASSERT(OK()); 00192 }
| void Parma_Polyhedra_Library::MIP_Problem::set_optimization_mode | ( | Optimization_Mode | mode | ) | [inline] |
Sets the optimization mode to mode.
Definition at line 69 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().
| PPL::MIP_Problem_Status Parma_Polyhedra_Library::MIP_Problem::solve | ( | ) | const |
Optimizes the MIP problem.
Definition at line 257 of file MIP_Problem.cc.
References i_variables, Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::i_vars, integer_space_dimensions(), is_lp_satisfiable(), last_generator, Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::lp, OK(), OPTIMIZED, Parma_Polyhedra_Library::OPTIMIZED_MIP_PROBLEM, PARTIALLY_SATISFIABLE, SATISFIABLE, second_phase(), solve_mip(), status, UNBOUNDED, Parma_Polyhedra_Library::UNBOUNDED_MIP_PROBLEM, Parma_Polyhedra_Library::UNFEASIBLE_MIP_PROBLEM, and UNSATISFIABLE.
Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::BD_Shape< T >::BFT00_upper_bound_assign_if_exact(), Parma_Polyhedra_Library::Octagonal_Shape< T >::bounds(), Parma_Polyhedra_Library::BD_Shape< T >::bounds(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::Octagonal_Shape< T >::max_min(), Parma_Polyhedra_Library::BD_Shape< T >::max_min(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), optimizing_point(), Parma_Polyhedra_Library::Polyhedron::simplify_using_context_assign(), and Parma_Polyhedra_Library::Polyhedron::strongly_minimize_constraints().
00257 { 00258 switch (status) { 00259 case UNSATISFIABLE: 00260 PPL_ASSERT(OK()); 00261 return UNFEASIBLE_MIP_PROBLEM; 00262 case UNBOUNDED: 00263 PPL_ASSERT(OK()); 00264 return UNBOUNDED_MIP_PROBLEM; 00265 case OPTIMIZED: 00266 PPL_ASSERT(OK()); 00267 return OPTIMIZED_MIP_PROBLEM; 00268 case SATISFIABLE: 00269 // Intentionally fall through 00270 case PARTIALLY_SATISFIABLE: 00271 { 00272 MIP_Problem& x = const_cast<MIP_Problem&>(*this); 00273 if (x.i_variables.empty()) { 00274 // LP case. 00275 if (x.is_lp_satisfiable()) { 00276 x.second_phase(); 00277 if (x.status == UNBOUNDED) 00278 return UNBOUNDED_MIP_PROBLEM; 00279 else { 00280 PPL_ASSERT(x.status == OPTIMIZED); 00281 return OPTIMIZED_MIP_PROBLEM; 00282 } 00283 } 00284 return UNFEASIBLE_MIP_PROBLEM; 00285 } 00286 00287 // MIP case. 00288 MIP_Problem_Status return_value; 00289 Generator g = point(); 00290 { 00291 // Temporarily relax the MIP into an LP problem. 00292 RAII_Temporary_Real_Relaxation relaxed(x); 00293 if (relaxed.lp.is_lp_satisfiable()) 00294 relaxed.lp.second_phase(); 00295 else { 00296 x.status = UNSATISFIABLE; 00297 // NOTE: `relaxed' destroyed: relaxation automatically reset. 00298 return UNFEASIBLE_MIP_PROBLEM; 00299 } 00300 PPL_DIRTY_TEMP0(mpq_class, incumbent_solution); 00301 bool have_incumbent_solution = false; 00302 00303 MIP_Problem lp_copy(relaxed.lp); 00304 PPL_ASSERT(lp_copy.integer_space_dimensions().empty()); 00305 return_value = solve_mip(have_incumbent_solution, 00306 incumbent_solution, g, 00307 lp_copy, relaxed.i_vars); 00308 } // `relaxed' destroyed here: relaxation automatically reset. 00309 00310 switch (return_value) { 00311 case UNFEASIBLE_MIP_PROBLEM: 00312 x.status = UNSATISFIABLE; 00313 break; 00314 case UNBOUNDED_MIP_PROBLEM: 00315 x.status = UNBOUNDED; 00316 // A feasible point has been set in `solve_mip()', so that 00317 // a call to `feasible_point' will be successful. 00318 x.last_generator = g; 00319 break; 00320 case OPTIMIZED_MIP_PROBLEM: 00321 x.status = OPTIMIZED; 00322 // Set the internal generator. 00323 x.last_generator = g; 00324 break; 00325 } 00326 PPL_ASSERT(OK()); 00327 return return_value; 00328 } 00329 } 00330 // We should not be here! 00331 throw std::runtime_error("PPL internal error"); 00332 }
| PPL::MIP_Problem_Status Parma_Polyhedra_Library::MIP_Problem::solve_mip | ( | bool & | have_incumbent_solution, | |
| mpq_class & | incumbent_solution_value, | |||
| Generator & | incumbent_solution_point, | |||
| MIP_Problem & | mip, | |||
| const Variables_Set & | i_vars | |||
| ) | [static, private] |
Returns a status that encodes the solution of the MIP problem.
| have_incumbent_solution | It is used to store if the solving process has found a provisional optimum point. | |
| incumbent_solution_value | Encodes the evaluated value of the provisional optimum point found. | |
| incumbent_solution_point | If the method returns `OPTIMIZED', this will contain the optimality point. | |
| mip | The problem that has to be solved. | |
| i_vars | The variables that are constrained to take an integer value. |
Definition at line 1605 of file MIP_Problem.cc.
References add_constraint(), Parma_Polyhedra_Library::assign_r(), Parma_Polyhedra_Library::Generator::coefficient(), Parma_Polyhedra_Library::Generator::divisor(), evaluate_objective_function(), Parma_Polyhedra_Library::gcd_assign(), Parma_Polyhedra_Library::is_canonical(), is_lp_satisfiable(), last_generator, Parma_Polyhedra_Library::MAXIMIZATION, Parma_Polyhedra_Library::MINIMIZATION, optimization_mode(), OPTIMIZED, Parma_Polyhedra_Library::OPTIMIZED_MIP_PROBLEM, PPL_DIRTY_TEMP_COEFFICIENT, second_phase(), space_dimension(), status, Parma_Polyhedra_Library::UNBOUNDED_MIP_PROBLEM, and Parma_Polyhedra_Library::UNFEASIBLE_MIP_PROBLEM.
Referenced by solve().
01609 { 01610 // Solve the problem as a non MIP one, it must be done internally. 01611 PPL::MIP_Problem_Status lp_status; 01612 if (lp.is_lp_satisfiable()) { 01613 lp.second_phase(); 01614 lp_status = (lp.status == OPTIMIZED) ? OPTIMIZED_MIP_PROBLEM 01615 : UNBOUNDED_MIP_PROBLEM; 01616 } 01617 else 01618 return UNFEASIBLE_MIP_PROBLEM; 01619 01620 PPL_DIRTY_TEMP0(mpq_class, tmp_rational); 01621 01622 Generator p = point(); 01623 PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff1); 01624 PPL_DIRTY_TEMP_COEFFICIENT(tmp_coeff2); 01625 01626 if (lp_status == UNBOUNDED_MIP_PROBLEM) 01627 p = lp.last_generator; 01628 else { 01629 PPL_ASSERT(lp_status == OPTIMIZED_MIP_PROBLEM); 01630 // Do not call optimizing_point(). 01631 p = lp.last_generator; 01632 lp.evaluate_objective_function(p, tmp_coeff1, tmp_coeff2); 01633 assign_r(tmp_rational.get_num(), tmp_coeff1, ROUND_NOT_NEEDED); 01634 assign_r(tmp_rational.get_den(), tmp_coeff2, ROUND_NOT_NEEDED); 01635 PPL_ASSERT(is_canonical(tmp_rational)); 01636 if (have_incumbent_solution 01637 && ((lp.optimization_mode() == MAXIMIZATION 01638 && tmp_rational <= incumbent_solution_value) 01639 || (lp.optimization_mode() == MINIMIZATION 01640 && tmp_rational >= incumbent_solution_value))) 01641 // Abandon this path. 01642 return lp_status; 01643 } 01644 01645 bool found_satisfiable_generator = true; 01646 PPL_DIRTY_TEMP_COEFFICIENT(gcd); 01647 const Coefficient& p_divisor = p.divisor(); 01648 dimension_type nonint_dim = lp.space_dimension(); 01649 for (Variables_Set::const_iterator v_begin = i_vars.begin(), 01650 v_end = i_vars.end(); v_begin != v_end; ++v_begin) { 01651 gcd_assign(gcd, p.coefficient(Variable(*v_begin)), p_divisor); 01652 if (gcd != p_divisor) { 01653 nonint_dim = *v_begin; 01654 found_satisfiable_generator = false; 01655 break; 01656 } 01657 } 01658 if (found_satisfiable_generator) { 01659 // All the coordinates of `point' are satisfiable. 01660 if (lp_status == UNBOUNDED_MIP_PROBLEM) { 01661 // This is a point that belongs to the MIP_Problem. 01662 // In this way we are sure that we will return every time 01663 // a feasible point if requested by the user. 01664 incumbent_solution_point = p; 01665 return lp_status; 01666 } 01667 if (!have_incumbent_solution 01668 || (lp.optimization_mode() == MAXIMIZATION 01669 && tmp_rational > incumbent_solution_value) 01670 || tmp_rational < incumbent_solution_value) { 01671 incumbent_solution_value = tmp_rational; 01672 incumbent_solution_point = p; 01673 have_incumbent_solution = true; 01674 #if PPL_NOISY_SIMPLEX 01675 PPL_DIRTY_TEMP_COEFFICIENT(num); 01676 PPL_DIRTY_TEMP_COEFFICIENT(den); 01677 lp.evaluate_objective_function(p, num, den); 01678 std::cout << "MIP_Problem::solve_mip(): " 01679 << "new value found: " << num << "/" << den 01680 << "." << std::endl; 01681 #endif // PPL_NOISY_SIMPLEX 01682 } 01683 return lp_status; 01684 } 01685 01686 PPL_ASSERT(nonint_dim < lp.space_dimension()); 01687 01688 assign_r(tmp_rational.get_num(), p.coefficient(Variable(nonint_dim)), 01689 ROUND_NOT_NEEDED); 01690 assign_r(tmp_rational.get_den(), p_divisor, ROUND_NOT_NEEDED); 01691 tmp_rational.canonicalize(); 01692 assign_r(tmp_coeff1, tmp_rational, ROUND_DOWN); 01693 assign_r(tmp_coeff2, tmp_rational, ROUND_UP); 01694 { 01695 MIP_Problem lp_aux = lp; 01696 lp_aux.add_constraint(Variable(nonint_dim) <= tmp_coeff1); 01697 #if PPL_NOISY_SIMPLEX 01698 using namespace IO_Operators; 01699 std::cout << "MIP_Problem::solve_mip(): " 01700 << "descending with: " 01701 << (Variable(nonint_dim) <= tmp_coeff1) 01702 << "." << std::endl; 01703 #endif // PPL_NOISY_SIMPLEX 01704 solve_mip(have_incumbent_solution, incumbent_solution_value, 01705 incumbent_solution_point, lp_aux, i_vars); 01706 } 01707 // TODO: change this when we will be able to remove constraints. 01708 lp.add_constraint(Variable(nonint_dim) >= tmp_coeff2); 01709 #if PPL_NOISY_SIMPLEX 01710 using namespace IO_Operators; 01711 std::cout << "MIP_Problem::solve_mip(): " 01712 << "descending with: " 01713 << (Variable(nonint_dim) >= tmp_coeff2) 01714 << "." << std::endl; 01715 #endif // PPL_NOISY_SIMPLEX 01716 solve_mip(have_incumbent_solution, incumbent_solution_value, 01717 incumbent_solution_point, lp, i_vars); 01718 return have_incumbent_solution ? lp_status : UNFEASIBLE_MIP_PROBLEM; 01719 }
| dimension_type Parma_Polyhedra_Library::MIP_Problem::space_dimension | ( | ) | const [inline] |
Returns the space dimension of the MIP problem.
Definition at line 38 of file MIP_Problem.inlines.hh.
References external_space_dim.
Referenced by add_constraint(), add_constraints(), add_space_dimensions_and_embed(), choose_branching_variable(), evaluate_objective_function(), is_mip_satisfiable(), process_pending_constraints(), set_objective_function(), and solve_mip().
00038 { 00039 return external_space_dim; 00040 }
| 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.
0 is returned.To compute the entering_index, the steepest edge algorithm chooses the index `j' such that
is the largest in absolute value, where
Recall that, due to the exact integer implementation of the algorithm, our tableau doesn't contain the ``real''
values, but these can be computed dividing the value of the coefficient by the value of the variable in base. Obviously the result may not be an integer, so we will proceed in another way: we compute the lcm of all the variables in base to get the good ``weight'' of each Coefficient of the tableau.
Definition at line 989 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::add_mul_assign(), base, Parma_Polyhedra_Library::exact_div_assign(), Parma_Polyhedra_Library::lcm_assign(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Row::size(), swap(), tableau, WEIGHT_ADD_MUL, WEIGHT_BEGIN, and working_cost.
Referenced by compute_simplex_using_exact_pricing().
00989 { 00990 const dimension_type tableau_num_rows = tableau.num_rows(); 00991 PPL_ASSERT(tableau_num_rows == base.size()); 00992 // The square of the lcm of all the coefficients of variables in base. 00993 PPL_DIRTY_TEMP_COEFFICIENT(squared_lcm_basis); 00994 // The normalization factor for each coefficient in the tableau. 00995 std::vector<Coefficient> norm_factor(tableau_num_rows); 00996 { 00997 WEIGHT_BEGIN(); 00998 // Compute the lcm of all the coefficients of variables in base. 00999 PPL_DIRTY_TEMP_COEFFICIENT(lcm_basis); 01000 lcm_basis = 1; 01001 for (dimension_type i = tableau_num_rows; i-- > 0; ) 01002 lcm_assign(lcm_basis, lcm_basis, tableau[i][base[i]]); 01003 // Compute normalization factors. 01004 for (dimension_type i = tableau_num_rows; i-- > 0; ) 01005 exact_div_assign(norm_factor[i], lcm_basis, tableau[i][base[i]]); 01006 // Compute the square of `lcm_basis', exploiting the fact that 01007 // `lcm_basis' will no longer be needed. 01008 lcm_basis *= lcm_basis; 01009 std::swap(squared_lcm_basis, lcm_basis); 01010 WEIGHT_ADD_MUL(444, tableau_num_rows); 01011 } 01012 01013 // Defined here to avoid repeated (de-)allocations. 01014 PPL_DIRTY_TEMP_COEFFICIENT(challenger_num); 01015 PPL_DIRTY_TEMP_COEFFICIENT(scalar_value); 01016 PPL_DIRTY_TEMP_COEFFICIENT(challenger_den); 01017 PPL_DIRTY_TEMP_COEFFICIENT(challenger_value); 01018 PPL_DIRTY_TEMP_COEFFICIENT(current_value); 01019 01020 PPL_DIRTY_TEMP_COEFFICIENT(current_num); 01021 PPL_DIRTY_TEMP_COEFFICIENT(current_den); 01022 dimension_type entering_index = 0; 01023 const int cost_sign = sgn(working_cost[working_cost.size() - 1]); 01024 for (dimension_type j = tableau.num_columns() - 1; j-- > 1; ) { 01025 const Coefficient& cost_j = working_cost[j]; 01026 if (sgn(cost_j) == cost_sign) { 01027 WEIGHT_BEGIN(); 01028 // We cannot compute the (exact) square root of abs(\Delta x_j). 01029 // The workaround is to compute the square of `cost[j]'. 01030 challenger_num = cost_j * cost_j; 01031 // Due to our integer implementation, the `1' term in the denominator 01032 // of the original formula has to be replaced by `squared_lcm_basis'. 01033 challenger_den = squared_lcm_basis; 01034 for (dimension_type i = tableau_num_rows; i-- > 0; ) { 01035 const Coefficient& tableau_ij = tableau[i][j]; 01036 // The test against 0 gives rise to a consistent speed up: see 01037 // http://www.cs.unipr.it/pipermail/ppl-devel/2009-February/014000.html 01038 if (tableau_ij != 0) { 01039 scalar_value = tableau_ij * norm_factor[i]; 01040 add_mul_assign(challenger_den, scalar_value, scalar_value); 01041 } 01042 } 01043 // Initialization during the first loop. 01044 if (entering_index == 0) { 01045 std::swap(current_num, challenger_num); 01046 std::swap(current_den, challenger_den); 01047 entering_index = j; 01048 continue; 01049 } 01050 challenger_value = challenger_num * current_den; 01051 current_value = current_num * challenger_den; 01052 // Update the values, if the challenger wins. 01053 if (challenger_value > current_value) { 01054 std::swap(current_num, challenger_num); 01055 std::swap(current_den, challenger_den); 01056 entering_index = j; 01057 } 01058 WEIGHT_ADD_MUL(47, tableau_num_rows); 01059 } 01060 } 01061 return entering_index; 01062 }
| PPL::dimension_type Parma_Polyhedra_Library::MIP_Problem::steepest_edge_float_entering_index | ( | ) | const [private] |
Same as steepest_edge_exact_entering_index, but using floating points.
Definition at line 943 of file MIP_Problem.cc.
References base, Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Row::size(), tableau, WEIGHT_ADD_MUL, WEIGHT_BEGIN, and working_cost.
Referenced by compute_simplex_using_steepest_edge_float().
00943 { 00944 const dimension_type tableau_num_rows = tableau.num_rows(); 00945 PPL_ASSERT(tableau_num_rows == base.size()); 00946 double challenger_num = 0.0; 00947 double challenger_den = 0.0; 00948 double current_value = 0.0; 00949 double float_tableau_value = 0.0; 00950 double float_tableau_denum = 0.0; 00951 dimension_type entering_index = 0; 00952 const int cost_sign = sgn(working_cost[working_cost.size() - 1]); 00953 for (dimension_type j = tableau.num_columns() - 1; j-- > 1; ) { 00954 const Coefficient& cost_j = working_cost[j]; 00955 if (sgn(cost_j) == cost_sign) { 00956 WEIGHT_BEGIN(); 00957 // We cannot compute the (exact) square root of abs(\Delta x_j). 00958 // The workaround is to compute the square of `cost[j]'. 00959 assign(challenger_num, cost_j); 00960 challenger_num = std::abs(challenger_num); 00961 // Due to our integer implementation, the `1' term in the denominator 00962 // of the original formula has to be replaced by `squared_lcm_basis'. 00963 challenger_den = 1.0; 00964 for (dimension_type i = tableau_num_rows; i-- > 0; ) { 00965 const Row& tableau_i = tableau[i]; 00966 const Coefficient& tableau_ij = tableau_i[j]; 00967 if (tableau_ij != 0) { 00968 PPL_ASSERT(tableau_i[base[i]] != 0); 00969 assign(float_tableau_value, tableau_ij); 00970 assign(float_tableau_denum, tableau_i[base[i]]); 00971 float_tableau_value /= float_tableau_denum; 00972 challenger_den += float_tableau_value * float_tableau_value; 00973 } 00974 } 00975 double challenger_value = sqrt(challenger_den); 00976 // Initialize `current_value' during the first iteration. 00977 // Otherwise update if the challenger wins. 00978 if (entering_index == 0 || challenger_value > current_value) { 00979 current_value = challenger_value; 00980 entering_index = j; 00981 } 00982 WEIGHT_ADD_MUL(338, tableau_num_rows); 00983 } 00984 } 00985 return entering_index; 00986 }
| void Parma_Polyhedra_Library::MIP_Problem::swap | ( | MIP_Problem & | y | ) | [inline] |
Swaps *this with y.
Definition at line 122 of file MIP_Problem.inlines.hh.
References base, external_space_dim, first_pending_constraint, i_variables, initialized, input_cs, input_obj_function, internal_space_dim, last_generator, mapping, opt_mode, pricing, status, tableau, and working_cost.
Referenced by clear(), operator=(), Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::RAII_Temporary_Real_Relaxation(), steepest_edge_exact_entering_index(), swap(), and Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::~RAII_Temporary_Real_Relaxation().
00122 { 00123 std::swap(external_space_dim, y.external_space_dim); 00124 std::swap(internal_space_dim, y.internal_space_dim); 00125 std::swap(tableau, y.tableau); 00126 std::swap(working_cost, y.working_cost); 00127 std::swap(mapping, y.mapping); 00128 std::swap(initialized, y.initialized); 00129 std::swap(base, y.base); 00130 std::swap(status, y.status); 00131 std::swap(pricing, y.pricing); 00132 std::swap(input_cs, y.input_cs); 00133 std::swap(first_pending_constraint, y.first_pending_constraint); 00134 std::swap(input_obj_function, y.input_obj_function); 00135 std::swap(opt_mode, y.opt_mode); 00136 std::swap(last_generator, y.last_generator); 00137 std::swap(i_variables, y.i_variables); 00138 }
| PPL::dimension_type Parma_Polyhedra_Library::MIP_Problem::textbook_entering_index | ( | ) | const [private] |
Computes the column index of the variable entering the base, using the textbook algorithm with anti-cycling rule.
0 is returned. Definition at line 1067 of file MIP_Problem.cc.
References Parma_Polyhedra_Library::Row::size(), and working_cost.
Referenced by compute_simplex_using_exact_pricing(), and compute_simplex_using_steepest_edge_float().
01067 { 01068 // The variable entering the base is the first one whose coefficient 01069 // in the cost function has the same sign the cost function itself. 01070 // If no such variable exists, then we met the optimality condition 01071 // (and return 0 to the caller). 01072 01073 // Get the "sign" of the cost function. 01074 const dimension_type cost_sign_index = working_cost.size() - 1; 01075 const int cost_sign = sgn(working_cost[cost_sign_index]); 01076 PPL_ASSERT(cost_sign != 0); 01077 for (dimension_type i = 1; i < cost_sign_index; ++i) 01078 if (sgn(working_cost[i]) == cost_sign) 01079 return i; 01080 // No variable has to enter the base: 01081 // the cost function was optimized. 01082 return 0; 01083 }
| memory_size_type Parma_Polyhedra_Library::MIP_Problem::total_memory_in_bytes | ( | ) | const [inline] |
Returns the total size in bytes of the memory occupied by *this.
Definition at line 173 of file MIP_Problem.inlines.hh.
References external_memory_in_bytes().
00173 { 00174 return sizeof(*this) + external_memory_in_bytes(); 00175 }
| std::ostream & operator<< | ( | std::ostream & | s, | |
| const MIP_Problem & | lp | |||
| ) | [related] |
Output operator.
Definition at line 2296 of file MIP_Problem.cc.
References constraints_begin(), constraints_end(), integer_space_dimensions(), Parma_Polyhedra_Library::MAXIMIZATION, objective_function(), and optimization_mode().
02296 { 02297 s << "Constraints:"; 02298 for (MIP_Problem::const_iterator i = lp.constraints_begin(), 02299 i_end = lp.constraints_end(); i != i_end; ++i) 02300 s << "\n" << *i; 02301 s << "\nObjective function: " 02302 << lp.objective_function() 02303 << "\nOptimization mode: " 02304 << (lp.optimization_mode() == MAXIMIZATION 02305 ? "MAXIMIZATION" 02306 : "MINIMIZATION"); 02307 s << "\nInteger variables: " << lp.integer_space_dimensions(); 02308 return s; 02309 }
friend class RAII_Temporary_Real_Relaxation [friend] |
Definition at line 525 of file MIP_Problem.defs.hh.
| void swap | ( | Parma_Polyhedra_Library::MIP_Problem & | x, | |
| Parma_Polyhedra_Library::MIP_Problem & | y | |||
| ) | [related] |
Specializes std::swap.
Definition at line 183 of file MIP_Problem.inlines.hh.
References swap().
00184 { 00185 x.swap(y); 00186 }
std::vector<dimension_type> Parma_Polyhedra_Library::MIP_Problem::base [private] |
The current basic solution.
Definition at line 451 of file MIP_Problem.defs.hh.
Referenced by ascii_dump(), erase_artificials(), external_memory_in_bytes(), get_exiting_base_index(), is_in_base(), merge_split_variable(), OK(), pivot(), process_pending_constraints(), second_phase(), steepest_edge_exact_entering_index(), steepest_edge_float_entering_index(), and swap().
The dimension of the vector space.
Definition at line 426 of file MIP_Problem.defs.hh.
Referenced by add_space_dimensions_and_embed(), add_to_integer_space_dimensions(), ascii_dump(), compute_generator(), is_lp_satisfiable(), MIP_Problem(), OK(), parse_constraints(), process_pending_constraints(), space_dimension(), and swap().
The first index of `input_cs' containing a pending constraint.
Definition at line 492 of file MIP_Problem.defs.hh.
Referenced by ascii_dump(), is_lp_satisfiable(), OK(), parse_constraints(), process_pending_constraints(), and swap().
A set containing all the indexes of variables that are constrained to have an integer value.
Definition at line 507 of file MIP_Problem.defs.hh.
Referenced by add_to_integer_space_dimensions(), ascii_dump(), integer_space_dimensions(), is_satisfiable(), MIP_Problem(), OK(), Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::RAII_Temporary_Real_Relaxation(), solve(), swap(), and Parma_Polyhedra_Library::MIP_Problem::RAII_Temporary_Real_Relaxation::~RAII_Temporary_Real_Relaxation().
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 486 of file MIP_Problem.defs.hh.
Referenced by ascii_dump(), is_lp_satisfiable(), OK(), and swap().
The sequence of constraints describing the feasible region.
Definition at line 489 of file MIP_Problem.defs.hh.
Referenced by add_constraint(), add_constraints(), ascii_dump(), choose_branching_variable(), constraints_begin(), constraints_end(), external_memory_in_bytes(), is_lp_satisfiable(), MIP_Problem(), OK(), parse_constraints(), process_pending_constraints(), and swap().
The objective function to be optimized.
Definition at line 495 of file MIP_Problem.defs.hh.
Referenced by ascii_dump(), evaluate_objective_function(), external_memory_in_bytes(), objective_function(), OK(), process_pending_constraints(), second_phase(), set_objective_function(), and swap().
The space dimension of the current (partial) solution of the MIP problem; it may be smaller than external_space_dim.
Definition at line 432 of file MIP_Problem.defs.hh.
Referenced by ascii_dump(), is_lp_satisfiable(), parse_constraints(), process_pending_constraints(), and swap().
The last successfully computed feasible or optimizing point.
Definition at line 501 of file MIP_Problem.defs.hh.
Referenced by ascii_dump(), choose_branching_variable(), compute_generator(), external_memory_in_bytes(), feasible_point(), is_mip_satisfiable(), is_satisfiable(), OK(), optimizing_point(), parse_constraints(), process_pending_constraints(), solve(), solve_mip(), and swap().
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; mapping[i].second not a zero, encodes the split part of the tableau of input_cs[i]. The "positive" one is represented by mapping[i].first and the "negative" one is represented by mapping[i].second.
Definition at line 448 of file MIP_Problem.defs.hh.
Referenced by ascii_dump(), compute_generator(), external_memory_in_bytes(), is_lp_satisfiable(), merge_split_variable(), OK(), parse_constraints(), process_pending_constraints(), second_phase(), and swap().
The optimization mode requested.
Definition at line 498 of file MIP_Problem.defs.hh.
Referenced by ascii_dump(), optimization_mode(), process_pending_constraints(), second_phase(), set_optimization_mode(), and swap().
The pricing method in use.
Definition at line 479 of file MIP_Problem.defs.hh.
Referenced by ascii_dump(), get_control_parameter(), set_control_parameter(), and swap().
The internal state of the MIP problem.
Definition at line 472 of file MIP_Problem.defs.hh.
Referenced by add_constraint(), add_constraints(), add_space_dimensions_and_embed(), add_to_integer_space_dimensions(), ascii_dump(), is_lp_satisfiable(), is_satisfiable(), OK(), process_pending_constraints(), second_phase(), set_objective_function(), set_optimization_mode(), solve(), solve_mip(), and swap().
The matrix encoding the current feasible region in tableau form.
Definition at line 435 of file MIP_Problem.defs.hh.
Referenced by ascii_dump(), compute_generator(), compute_simplex_using_exact_pricing(), compute_simplex_using_steepest_edge_float(), erase_artificials(), external_memory_in_bytes(), get_exiting_base_index(), is_lp_satisfiable(), merge_split_variable(), OK(), pivot(), process_pending_constraints(), second_phase(), steepest_edge_exact_entering_index(), steepest_edge_float_entering_index(), and swap().
The working cost function.
Definition at line 438 of file MIP_Problem.defs.hh.
Referenced by ascii_dump(), compute_simplex_using_exact_pricing(), compute_simplex_using_steepest_edge_float(), erase_artificials(), external_memory_in_bytes(), OK(), pivot(), process_pending_constraints(), second_phase(), steepest_edge_exact_entering_index(), steepest_edge_float_entering_index(), swap(), and textbook_entering_index().
1.6.3