00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <ppl-config.h>
00025 #include "MIP_Problem.defs.hh"
00026 #include "globals.defs.hh"
00027 #include "Checked_Number.defs.hh"
00028 #include "Row.defs.hh"
00029 #include "Linear_Expression.defs.hh"
00030 #include "Constraint.defs.hh"
00031 #include "Constraint_System.defs.hh"
00032 #include "Constraint_System.inlines.hh"
00033 #include "Generator.defs.hh"
00034 #include "Scalar_Products.defs.hh"
00035 #include <stdexcept>
00036 #include <deque>
00037 #include <algorithm>
00038 #include <cmath>
00039
00040 #ifndef PPL_NOISY_SIMPLEX
00041 #define PPL_NOISY_SIMPLEX 0
00042 #endif
00043
00044 #ifndef PPL_SIMPLEX_USE_MIP_HEURISTIC
00045 #define PPL_SIMPLEX_USE_MIP_HEURISTIC 1
00046 #endif
00047
00048 #if PPL_NOISY_SIMPLEX
00049 #include <iostream>
00050 #endif
00051
00052
00053 namespace PPL = Parma_Polyhedra_Library;
00054
00055 #if PPL_NOISY_SIMPLEX
00056 namespace {
00057
00058 unsigned long num_iterations = 0;
00059
00060 unsigned mip_recursion_level = 0;
00061
00062 }
00063 #endif // PPL_NOISY_SIMPLEX
00064
00065 PPL::MIP_Problem::MIP_Problem(const dimension_type dim)
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
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 }
00089
00090 PPL::MIP_Problem::MIP_Problem(const dimension_type dim,
00091 const Constraint_System& cs,
00092 const Linear_Expression& obj,
00093 const Optimization_Mode mode)
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
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
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
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
00137 input_cs.insert(input_cs.end(), cs.begin(), cs.end());
00138 PPL_ASSERT(OK());
00139 }
00140
00141 void
00142 PPL::MIP_Problem::add_constraint(const Constraint& c) {
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 }
00158
00159 void
00160 PPL::MIP_Problem::add_constraints(const Constraint_System& cs) {
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 }
00177
00178 void
00179 PPL::MIP_Problem::set_objective_function(const Linear_Expression& obj) {
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 }
00193
00194 const PPL::Generator&
00195 PPL::MIP_Problem::feasible_point() const {
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 }
00202
00203 const PPL::Generator&
00204 PPL::MIP_Problem::optimizing_point() const {
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 }
00211
00212 bool
00213 PPL::MIP_Problem::is_satisfiable() const {
00214
00215 switch (status) {
00216 case UNSATISFIABLE:
00217 PPL_ASSERT(OK());
00218 return false;
00219 case SATISFIABLE:
00220
00221 case UNBOUNDED:
00222
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
00230 if (x.i_variables.empty())
00231 return x.is_lp_satisfiable();
00232
00233
00234 {
00235
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 }
00249 return (x.status == SATISFIABLE);
00250 }
00251 }
00252
00253 throw std::runtime_error("PPL internal error");
00254 }
00255
00256 PPL::MIP_Problem_Status
00257 PPL::MIP_Problem::solve() const{
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
00270 case PARTIALLY_SATISFIABLE:
00271 {
00272 MIP_Problem& x = const_cast<MIP_Problem&>(*this);
00273 if (x.i_variables.empty()) {
00274
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
00288 MIP_Problem_Status return_value;
00289 Generator g = point();
00290 {
00291
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
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 }
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
00317
00318 x.last_generator = g;
00319 break;
00320 case OPTIMIZED_MIP_PROBLEM:
00321 x.status = OPTIMIZED;
00322
00323 x.last_generator = g;
00324 break;
00325 }
00326 PPL_ASSERT(OK());
00327 return return_value;
00328 }
00329 }
00330
00331 throw std::runtime_error("PPL internal error");
00332 }
00333
00334 void
00335 PPL::MIP_Problem::add_space_dimensions_and_embed(const dimension_type m) {
00336
00337
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 }
00348
00349 void
00350 PPL::MIP_Problem
00351 ::add_to_integer_space_dimensions(const Variables_Set& i_vars) {
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
00360
00361 if (i_variables.size() != original_size && status != UNSATISFIABLE)
00362 status = PARTIALLY_SATISFIABLE;
00363 }
00364
00365 bool
00366 PPL::MIP_Problem::is_in_base(const dimension_type var_index,
00367 dimension_type& row_index) const {
00368 for (row_index = base.size(); row_index-- > 0; )
00369 if (base[row_index] == var_index)
00370 return true;
00371 return false;
00372 }
00373
00374 PPL::dimension_type
00375 PPL::MIP_Problem::merge_split_variable(dimension_type var_index) {
00376
00377 dimension_type unfeasible_tableau_row = not_a_dimension();
00378
00379 const dimension_type removing_column = mapping[1+var_index].second;
00380
00381
00382
00383 {
00384 dimension_type base_index;
00385 if (is_in_base(removing_column, base_index)) {
00386
00387 unfeasible_tableau_row = base_index;
00388
00389 base[base_index] = 0;
00390 #ifndef NDEBUG
00391
00392
00393 PPL_ASSERT(!is_in_base(mapping[1+var_index].first, base_index));
00394 #endif
00395 }
00396 }
00397
00398
00399
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
00409 tableau.remove_trailing_columns(1);
00410
00411
00412 mapping[1+var_index].second = 0;
00413
00414
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 }
00430
00431 bool
00432 PPL::MIP_Problem::is_satisfied(const Constraint& c, const Generator& g) {
00433
00434
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 }
00440
00441 bool
00442 PPL::MIP_Problem::is_saturated(const Constraint& c, const Generator& g) {
00443
00444
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 }
00450
00451 bool
00452 PPL::MIP_Problem
00453 ::parse_constraints(dimension_type& additional_tableau_rows,
00454 dimension_type& additional_slack_variables,
00455 std::deque<bool>& is_tableau_constraint,
00456 std::deque<bool>& is_satisfied_inequality,
00457 std::deque<bool>& is_nonnegative_variable,
00458 std::deque<bool>& is_remergeable_variable) const {
00459
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
00470
00471 additional_tableau_rows = cs_num_pending;
00472 additional_slack_variables = 0;
00473
00474
00475
00476
00477
00478
00479 is_tableau_constraint.insert(is_tableau_constraint.end(),
00480 cs_num_pending, true);
00481
00482
00483
00484
00485 is_satisfied_inequality.insert(is_satisfied_inequality.end(),
00486 cs_num_pending, false);
00487
00488
00489
00490 is_nonnegative_variable.insert(is_nonnegative_variable.end(),
00491 cs_space_dim, false);
00492
00493
00494
00495 is_remergeable_variable.insert(is_remergeable_variable.end(),
00496 internal_space_dim, false);
00497
00498
00499
00500 const dimension_type mapping_size = mapping.size();
00501 if (mapping_size > 0) {
00502
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
00509
00510
00511
00512
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
00533
00534 if (found_many_nonzero_coeffs) {
00535
00536
00537
00538
00539
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
00547
00548 if (cs_i.is_inequality()) {
00549 if (cs_i.inhomogeneous_term() < 0)
00550
00551 return false;
00552 }
00553 else
00554
00555 if (cs_i.inhomogeneous_term() != 0)
00556
00557 return false;
00558
00559 is_tableau_constraint[i - first_pending_constraint] = false;
00560 --additional_tableau_rows;
00561 continue;
00562 }
00563 else {
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
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
00602 if (sgn_a == sgn_b) {
00603 if (cs_i.is_inequality())
00604 ++additional_slack_variables;
00605 }
00606
00607 else if (cs_i.is_equality())
00608 is_nonnegative_variable[nonzero_var_index] = true;
00609
00610 else if (sgn_b < 0) {
00611 is_nonnegative_variable[nonzero_var_index] = true;
00612 ++additional_slack_variables;
00613 }
00614
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
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
00628 else {
00629 PPL_ASSERT(cs_i.is_inequality());
00630 ++additional_slack_variables;
00631 }
00632 }
00633 }
00634 return true;
00635 }
00636
00637 bool
00638 PPL::MIP_Problem::process_pending_constraints() {
00639
00640
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
00658
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
00664
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
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
00680
00681
00682 const dimension_type positive = first_free_tableau_index + j;
00683 if (is_nonnegative_variable[internal_space_dim + i]) {
00684
00685 mapping.push_back(std::make_pair(positive, 0));
00686 ++j;
00687 ++additional_problem_vars;
00688 }
00689 else {
00690
00691 mapping.push_back(std::make_pair(positive, positive + 1));
00692 j += 2;
00693 additional_problem_vars += 2;
00694 }
00695 }
00696 }
00697
00698
00699 if (additional_tableau_rows > 0)
00700 tableau.add_zero_rows(additional_tableau_rows, Row::Flags());
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
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
00734 const dimension_type tableau_num_rows = tableau.num_rows();
00735 const dimension_type tableau_num_cols = tableau.num_columns();
00736
00737
00738
00739 std::deque<bool> worked_out_row (tableau_num_rows, false);
00740
00741
00742
00743 base.insert(base.end(), additional_tableau_rows, 0);
00744 const dimension_type base_size = base.size();
00745
00746
00747
00748 dimension_type slack_index
00749 = tableau_num_cols - additional_artificial_vars - 1;
00750 dimension_type artificial_index = slack_index;
00751
00752
00753
00754 const dimension_type begin_artificials
00755 = additional_artificial_vars > 0 ? artificial_index : 0;
00756
00757
00758 for (dimension_type k = tableau_num_rows,
00759 i = input_cs.size() - first_pending_constraint; i-- > 0; ) {
00760
00761 if (!is_tableau_constraint[i])
00762 continue;
00763 const Constraint& c = input_cs[i + first_pending_constraint];
00764
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
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
00780 if (mapping[0].second != 0)
00781 neg_assign(tableau_k[mapping[0].second], inhomo);
00782 }
00783
00784
00785 if (c.is_inequality()) {
00786 --slack_index;
00787 tableau_k[slack_index] = -1;
00788
00789
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
00801
00802
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
00811 working_cost = Row(tableau_num_cols, Row::Flags());
00812
00813
00814
00815
00816
00817
00818
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
00826
00827
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
00837 const dimension_type end_artificials = artificial_index;
00838
00839
00840
00841 const dimension_type last_obj_index = working_cost.size() - 1;
00842 working_cost[last_obj_index] = 1;
00843
00844
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
00850 if (space_dimension() == 0) {
00851 status = OPTIMIZED;
00852 last_generator = point();
00853 return true;
00854 }
00855
00856
00857
00858
00859
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
00865
00866
00867
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
00873 || (input_obj_function.coefficient(Variable(i)) != 0
00874 && mapping[i].second != 0)) {
00875
00876 last_generator = point(0 * Variable(space_dimension()-1));
00877 status = UNBOUNDED;
00878 return true;
00879 }
00880
00881
00882
00883
00884 status = OPTIMIZED;
00885
00886 last_generator = point(0*Variable(space_dimension()-1));
00887 PPL_ASSERT(OK());
00888 return true;
00889 }
00890
00891
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
00905 status = UNSATISFIABLE;
00906 return false;
00907 }
00908
00909
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 }
00917
00918 namespace {
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928 inline void
00929 assign(double& d, const mpz_class& c) {
00930 d = c.get_d();
00931 }
00932
00933 template <typename T, typename Policy>
00934 inline void
00935 assign(double& d,
00936 const Parma_Polyhedra_Library::Checked_Number<T, Policy>& c) {
00937 d = raw_value(c);
00938 }
00939
00940 }
00941
00942 PPL::dimension_type
00943 PPL::MIP_Problem::steepest_edge_float_entering_index() const {
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
00958
00959 assign(challenger_num, cost_j);
00960 challenger_num = std::abs(challenger_num);
00961
00962
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
00977
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 }
00987
00988 PPL::dimension_type
00989 PPL::MIP_Problem::steepest_edge_exact_entering_index() const {
00990 const dimension_type tableau_num_rows = tableau.num_rows();
00991 PPL_ASSERT(tableau_num_rows == base.size());
00992
00993 PPL_DIRTY_TEMP_COEFFICIENT(squared_lcm_basis);
00994
00995 std::vector<Coefficient> norm_factor(tableau_num_rows);
00996 {
00997 WEIGHT_BEGIN();
00998
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
01004 for (dimension_type i = tableau_num_rows; i-- > 0; )
01005 exact_div_assign(norm_factor[i], lcm_basis, tableau[i][base[i]]);
01006
01007
01008 lcm_basis *= lcm_basis;
01009 std::swap(squared_lcm_basis, lcm_basis);
01010 WEIGHT_ADD_MUL(444, tableau_num_rows);
01011 }
01012
01013
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
01029
01030 challenger_num = cost_j * cost_j;
01031
01032
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
01037
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
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
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 }
01063
01064
01065
01066 PPL::dimension_type
01067 PPL::MIP_Problem::textbook_entering_index() const {
01068
01069
01070
01071
01072
01073
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
01081
01082 return 0;
01083 }
01084
01085 void
01086 PPL::MIP_Problem::linear_combine(Row& x,
01087 const Row& y,
01088 const dimension_type k) {
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
01094
01095
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
01104
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 }
01113
01114
01115 void
01116 PPL::MIP_Problem::pivot(const dimension_type entering_var_index,
01117 const dimension_type exiting_base_index) {
01118 const Row& tableau_out = tableau[exiting_base_index];
01119
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
01126 if (working_cost[entering_var_index] != 0)
01127 linear_combine(working_cost, tableau_out, entering_var_index);
01128
01129 base[exiting_base_index] = entering_var_index;
01130 }
01131
01132
01133 PPL::dimension_type
01134 PPL::MIP_Problem
01135 ::get_exiting_base_index(const dimension_type entering_var_index) const {
01136
01137
01138
01139
01140
01141
01142
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
01154 if (exiting_base_index == tableau_num_rows)
01155 return tableau_num_rows;
01156
01157
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 }
01187
01188
01189 bool
01190 PPL::MIP_Problem::compute_simplex_using_steepest_edge_float() {
01191
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
01212 const dimension_type entering_var_index
01213 = textbook_pricing
01214 ? textbook_entering_index()
01215 : steepest_edge_float_entering_index();
01216
01217
01218 if (entering_var_index == 0)
01219 return true;
01220
01221
01222 const dimension_type exiting_base_index
01223 = get_exiting_base_index(entering_var_index);
01224
01225 if (exiting_base_index == tableau_num_rows)
01226 return false;
01227
01228
01229
01230
01231 maybe_abandon();
01232
01233
01234
01235
01236 pivot(entering_var_index, exiting_base_index);
01237
01238 WEIGHT_BEGIN();
01239
01240
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
01256 PPL_ASSERT(challenger >= current);
01257
01258
01259 if (challenger == current) {
01260 ++non_increased_times;
01261
01262
01263 if (non_increased_times > allowed_non_increasing_loops)
01264 textbook_pricing = true;
01265 }
01266
01267
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 }
01279
01280 bool
01281 PPL::MIP_Problem::compute_simplex_using_exact_pricing() {
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
01292 const dimension_type entering_var_index
01293 = textbook_pricing
01294 ? textbook_entering_index()
01295 : steepest_edge_exact_entering_index();
01296
01297 if (entering_var_index == 0)
01298 return true;
01299
01300
01301 const dimension_type exiting_base_index
01302 = get_exiting_base_index(entering_var_index);
01303
01304 if (exiting_base_index == tableau_num_rows)
01305 return false;
01306
01307
01308
01309
01310 maybe_abandon();
01311
01312
01313
01314
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 }
01324
01325
01326
01327 void
01328 PPL::MIP_Problem::erase_artificials(const dimension_type begin_artificials,
01329 const dimension_type end_artificials) {
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
01335 for (dimension_type i = 0; i < tableau_n_rows; ++i)
01336 if (begin_artificials <= base[i] && base[i] < end_artificials) {
01337
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
01349
01350 --tableau_n_rows;
01351 if (i < tableau_n_rows) {
01352
01353
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
01365
01366
01367 const dimension_type num_artificials = end_artificials - begin_artificials;
01368 tableau.remove_trailing_columns(num_artificials);
01369
01370
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
01376
01377 working_cost[new_last_column] = working_cost[old_last_column];
01378
01379 const dimension_type working_cost_new_size
01380 = working_cost.size() - num_artificials;
01381 working_cost.shrink(working_cost_new_size);
01382 }
01383
01384
01385 void
01386 PPL::MIP_Problem::compute_generator() const {
01387
01388
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
01395 PPL_DIRTY_TEMP_COEFFICIENT(split_num);
01396 PPL_DIRTY_TEMP_COEFFICIENT(split_den);
01397
01398
01399 for (dimension_type i = external_space_dim; i-- > 0; ) {
01400 Coefficient& num_i = num[i];
01401 Coefficient& den_i = den[i];
01402
01403
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
01421 const dimension_type split_var = mapping[i+1].second;
01422 if (split_var != 0) {
01423
01424
01425
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
01437
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
01449
01450 }
01451 }
01452
01453
01454 lcm = den[0];
01455 for (dimension_type i = 1; i < external_space_dim; ++i)
01456 lcm_assign(lcm, lcm, den[i]);
01457
01458
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
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 }
01472
01473 void
01474 PPL::MIP_Problem::second_phase() {
01475
01476 PPL_ASSERT(status == SATISFIABLE || status == UNBOUNDED || status == OPTIMIZED);
01477
01478 if (status == UNBOUNDED || status == OPTIMIZED)
01479 return;
01480
01481
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
01490 if (opt_mode == MINIMIZATION)
01491 for (dimension_type i = new_cost.size(); i-- > 0; )
01492 neg_assign(new_cost[i]);
01493
01494
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
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
01509
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
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 }
01529
01530 void
01531 PPL::MIP_Problem
01532 ::evaluate_objective_function(const Generator& evaluating_point,
01533 Coefficient& ext_n,
01534 Coefficient& ext_d) const {
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
01546
01547 const dimension_type working_space_dim
01548 = std::min(ep_space_dim, input_obj_function.space_dimension());
01549
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
01556 normalize2(ext_n, divisor, ext_n, ext_d);
01557 }
01558
01559 bool
01560 PPL::MIP_Problem::is_lp_satisfiable() const {
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
01569 case UNBOUNDED:
01570
01571 case OPTIMIZED:
01572
01573 return true;
01574 case PARTIALLY_SATISFIABLE:
01575 {
01576 MIP_Problem& x = const_cast<MIP_Problem&>(*this);
01577
01578
01579 if (tableau.num_columns() == 0) {
01580
01581
01582 x.tableau.add_zero_columns(2);
01583
01584 x.mapping.push_back(std::make_pair(0, 0));
01585
01586
01587 x.initialized = true;
01588 }
01589
01590
01591 x.process_pending_constraints();
01592
01593 x.first_pending_constraint = input_cs.size();
01594
01595 x.internal_space_dim = x.external_space_dim;
01596 PPL_ASSERT(OK());
01597 return status != UNSATISFIABLE;
01598 }
01599 }
01600
01601 throw std::runtime_error("PPL internal error");
01602 }
01603
01604 PPL::MIP_Problem_Status
01605 PPL::MIP_Problem::solve_mip(bool& have_incumbent_solution,
01606 mpq_class& incumbent_solution_value,
01607 Generator& incumbent_solution_point,
01608 MIP_Problem& lp,
01609 const Variables_Set& i_vars) {
01610
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
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
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
01660 if (lp_status == UNBOUNDED_MIP_PROBLEM) {
01661
01662
01663
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
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 }
01720
01721 bool
01722 PPL::MIP_Problem::choose_branching_variable(const MIP_Problem& lp,
01723 const Variables_Set& i_vars,
01724 dimension_type& branching_index) {
01725
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
01741 if (candidate_variables.empty())
01742 return true;
01743
01744
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
01749
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
01758
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 }
01774
01775 bool
01776 PPL::MIP_Problem::is_mip_satisfiable(MIP_Problem& lp,
01777 const Variables_Set& i_vars,
01778 Generator& p) {
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
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 }
01870
01871 bool
01872 PPL::MIP_Problem::OK() const {
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
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
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
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
01914
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
01939
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
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
01963
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
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
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
01991
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
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
02023 return true;
02024 }
02025
02026 void
02027 PPL::MIP_Problem::ascii_dump(std::ostream& s) const {
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 }
02103
02104 PPL_OUTPUT_DEFINITIONS(MIP_Problem)
02105
02106 bool
02107 PPL::MIP_Problem::ascii_load(std::istream& s) {
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
02266
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 }
02293
02295 std::ostream&
02296 PPL::IO_Operators::operator<<(std::ostream& s, const MIP_Problem& lp) {
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 }