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 "PIP_Problem.defs.hh"
00026 #include "PIP_Tree.defs.hh"
00027
00028 namespace PPL = Parma_Polyhedra_Library;
00029
00031 std::ostream&
00032 PPL::IO_Operators::operator<<(std::ostream& s, const PIP_Problem& pip) {
00033 s << "Space dimension: " << pip.space_dimension();
00034 s << "\nConstraints:";
00035 for (PIP_Problem::const_iterator i = pip.constraints_begin(),
00036 i_end = pip.constraints_end(); i != i_end; ++i)
00037 s << "\n" << *i;
00038 s << "\nProblem parameters: " << pip.parameter_space_dimensions();
00039 if (pip.get_big_parameter_dimension() == not_a_dimension())
00040 s << "\nNo big-parameter set.\n";
00041 else
00042 s << "\nBig-parameter: " << Variable(pip.get_big_parameter_dimension());
00043 s << "\n";
00044 return s;
00045 }
00046
00047 PPL::PIP_Problem::PIP_Problem(const dimension_type dim)
00048 : external_space_dim(dim),
00049 internal_space_dim(0),
00050 status(PARTIALLY_SATISFIABLE),
00051 current_solution(0),
00052 input_cs(),
00053 first_pending_constraint(0),
00054 parameters(),
00055 initial_context(),
00056 big_parameter_dimension(not_a_dimension()) {
00057
00058 if (dim > max_space_dimension())
00059 throw std::length_error("PPL::PIP_Problem::PIP_Problem(dim):\n"
00060 "dim exceeds the maximum allowed "
00061 "space dimension.");
00062 control_parameters_init();
00063 PPL_ASSERT(OK());
00064 }
00065
00066 PPL::PIP_Problem::PIP_Problem(const PIP_Problem &y)
00067 : external_space_dim(y.external_space_dim),
00068 internal_space_dim(y.internal_space_dim),
00069 status(y.status),
00070 current_solution(0),
00071 input_cs(y.input_cs),
00072 first_pending_constraint(y.first_pending_constraint),
00073 parameters(y.parameters),
00074 initial_context(y.initial_context),
00075 big_parameter_dimension(y.big_parameter_dimension) {
00076 if (y.current_solution != 0) {
00077 current_solution = y.current_solution->clone();
00078 current_solution->set_owner(this);
00079 }
00080 control_parameters_copy(y);
00081 PPL_ASSERT(OK());
00082 }
00083
00084 PPL::PIP_Problem::~PIP_Problem() {
00085 delete current_solution;
00086 }
00087
00088 void
00089 PPL::PIP_Problem::control_parameters_init() {
00090 control_parameters[CUTTING_STRATEGY] = CUTTING_STRATEGY_FIRST;
00091 control_parameters[PIVOT_ROW_STRATEGY] = PIVOT_ROW_STRATEGY_FIRST;
00092 }
00093
00094 void
00095 PPL::PIP_Problem::control_parameters_copy(const PIP_Problem& y) {
00096 for (dimension_type i = CONTROL_PARAMETER_NAME_SIZE; i-- > 0; )
00097 control_parameters[i] = y.control_parameters[i];
00098 }
00099
00100 PPL::PIP_Problem_Status
00101 PPL::PIP_Problem::solve() const {
00102 switch (status) {
00103
00104 case UNSATISFIABLE:
00105 PPL_ASSERT(OK());
00106 return UNFEASIBLE_PIP_PROBLEM;
00107
00108 case OPTIMIZED:
00109 PPL_ASSERT(OK());
00110 return OPTIMIZED_PIP_PROBLEM;
00111
00112 case PARTIALLY_SATISFIABLE:
00113 {
00114 PIP_Problem& x = const_cast<PIP_Problem&>(*this);
00115
00116 if (current_solution == 0)
00117 x.current_solution = new PIP_Solution_Node(this);
00118
00119
00120 const dimension_type new_num_cols = parameters.size() + 1;
00121 const dimension_type old_num_cols = initial_context.num_columns();
00122 if (old_num_cols < new_num_cols)
00123 x.initial_context.add_zero_columns(new_num_cols - old_num_cols);
00124
00125
00126 const Variables_Set::const_iterator param_begin = parameters.begin();
00127 const Variables_Set::const_iterator param_end = parameters.end();
00128
00129
00130
00131 bool check_feasible_context = false;
00132
00133
00134 for (Constraint_Sequence::const_iterator
00135 cs_i = input_cs.begin() + first_pending_constraint,
00136 cs_end = input_cs.end(); cs_i != cs_end; ++cs_i) {
00137 const Constraint& c = *cs_i;
00138 const dimension_type c_space_dim = c.space_dimension();
00139 PPL_ASSERT(external_space_dim >= c_space_dim);
00140
00141
00142 bool has_nonzero_variable_coefficient = false;
00143 for (dimension_type i = c_space_dim; i-- > 0; ) {
00144 if (c.coefficient(Variable(i)) != 0
00145 && parameters.count(i) == 0) {
00146 has_nonzero_variable_coefficient = true;
00147 break;
00148 }
00149 }
00150
00151
00152 if (has_nonzero_variable_coefficient)
00153 continue;
00154
00155 check_feasible_context = true;
00156
00157
00158 Row row(new_num_cols, Row::Flags());
00159 row[0] = c.inhomogeneous_term();
00160 {
00161 dimension_type i = 1;
00162 for (Variables_Set::const_iterator
00163 pi = param_begin; pi != param_end; ++pi, ++i) {
00164 if (*pi < c_space_dim)
00165 row[i] = c.coefficient(Variable(*pi));
00166 else
00167 break;
00168 }
00169 }
00170
00171 if (c.is_strict_inequality())
00172 --row[0];
00173
00174
00175 x.initial_context.add_row(row);
00176
00177
00178 if (c.is_equality()) {
00179 for (dimension_type i = new_num_cols; i-- > 0; )
00180 neg_assign(row[i], row[i]);
00181
00182
00183 x.initial_context.add_row(row);
00184 }
00185 }
00186
00187 if (check_feasible_context) {
00188
00189 Matrix ctx_copy(initial_context);
00190 if (!PIP_Solution_Node::compatibility_check(ctx_copy)) {
00191
00192 delete x.current_solution;
00193 x.current_solution = 0;
00194 x.status = UNSATISFIABLE;
00195 PPL_ASSERT(OK());
00196 return UNFEASIBLE_PIP_PROBLEM;
00197 }
00198 }
00199
00200
00201 x.current_solution->update_tableau(*this,
00202 external_space_dim,
00203 first_pending_constraint,
00204 input_cs,
00205 parameters);
00206 x.internal_space_dim = external_space_dim;
00207 x.first_pending_constraint = input_cs.size();
00208
00209
00210 x.current_solution = x.current_solution->solve(*this,
00211 check_feasible_context,
00212 initial_context,
00213 parameters,
00214 external_space_dim,
00215 0);
00216
00217 x.status = (x.current_solution) ? OPTIMIZED : UNSATISFIABLE;
00218
00219 PPL_ASSERT(OK());
00220 return (x.current_solution)
00221 ? OPTIMIZED_PIP_PROBLEM
00222 : UNFEASIBLE_PIP_PROBLEM;
00223 }
00224
00225 }
00226
00227
00228 throw std::runtime_error("PPL internal error");
00229 }
00230
00231 PPL::PIP_Tree
00232 PPL::PIP_Problem::solution() const {
00233 if (status == PARTIALLY_SATISFIABLE)
00234 solve();
00235 return current_solution;
00236 }
00237
00238 PPL::PIP_Tree
00239 PPL::PIP_Problem::optimizing_solution() const {
00240 if (status == PARTIALLY_SATISFIABLE)
00241 solve();
00242 return current_solution;
00243 }
00244
00245 bool
00246 PPL::PIP_Problem::OK() const {
00247 #ifndef NDEBUG
00248 using std::endl;
00249 using std::cerr;
00250 #endif
00251
00252 if (external_space_dim < internal_space_dim) {
00253 #ifndef NDEBUG
00254 cerr << "The internal space dimension of the PIP_Problem is "
00255 << "greater than its external space dimension."
00256 << endl;
00257 ascii_dump(cerr);
00258 #endif
00259 return false;
00260 }
00261
00262
00263 const dimension_type input_cs_num_rows = input_cs.size();
00264 for (dimension_type i = input_cs_num_rows; i-- > 0; )
00265 if (!input_cs[i].OK())
00266 return false;
00267
00268
00269 for (dimension_type i = input_cs_num_rows; i-- > 0; ) {
00270 if (input_cs[i].space_dimension() > external_space_dim) {
00271 #ifndef NDEBUG
00272 cerr << "The space dimension of the PIP_Problem is smaller than "
00273 << "the space dimension of one of its constraints."
00274 << endl;
00275 ascii_dump(cerr);
00276 #endif
00277 return false;
00278 }
00279 }
00280
00281
00282 Control_Parameter_Value strategy = control_parameters[CUTTING_STRATEGY];
00283 if (strategy != CUTTING_STRATEGY_FIRST
00284 && strategy != CUTTING_STRATEGY_DEEPEST
00285 && strategy != CUTTING_STRATEGY_ALL) {
00286 #ifndef NDEBUG
00287 cerr << "Invalid value for the CUTTING_STRATEGY control parameter."
00288 << endl;
00289 ascii_dump(cerr);
00290 #endif
00291 return false;
00292 }
00293
00294 strategy = control_parameters[PIVOT_ROW_STRATEGY];
00295 if (strategy < PIVOT_ROW_STRATEGY_FIRST
00296 || strategy > PIVOT_ROW_STRATEGY_MAX_COLUMN) {
00297 #ifndef NDEBUG
00298 cerr << "Invalid value for the PIVOT_ROW_STRATEGY control parameter."
00299 << endl;
00300 ascii_dump(cerr);
00301 #endif
00302 return false;
00303 }
00304
00305 if (big_parameter_dimension != not_a_dimension()
00306 && parameters.count(big_parameter_dimension) == 0) {
00307 #ifndef NDEBUG
00308 cerr << "The big parameter is set, but it is not a parameter." << endl;
00309 ascii_dump(cerr);
00310 #endif
00311 return false;
00312 }
00313
00314 if (!parameters.OK())
00315 return false;
00316 if (!initial_context.OK())
00317 return false;
00318
00319 if (current_solution) {
00320
00321 if (!current_solution->OK()) {
00322 #ifndef NDEBUG
00323 cerr << "The computed solution tree is broken.\n";
00324 ascii_dump(cerr);
00325 #endif
00326 return false;
00327 }
00328
00329 if (!current_solution->check_ownership(this)) {
00330 #ifndef NDEBUG
00331 cerr << "There are nodes in the solution tree "
00332 << "that are not owned by *this.\n";
00333 ascii_dump(cerr);
00334 #endif
00335 return false;
00336 }
00337 }
00338
00339
00340 return true;
00341 }
00342
00343 void
00344 PPL::PIP_Problem::ascii_dump(std::ostream& s) const {
00345 using namespace IO_Operators;
00346 s << "\nexternal_space_dim: " << external_space_dim << "\n";
00347 s << "\ninternal_space_dim: " << internal_space_dim << "\n";
00348
00349 const dimension_type input_cs_size = input_cs.size();
00350
00351 s << "\ninput_cs( " << input_cs_size << " )\n";
00352 for (dimension_type i = 0; i < input_cs_size; ++i)
00353 input_cs[i].ascii_dump(s);
00354
00355 s << "\nfirst_pending_constraint: " << first_pending_constraint << "\n";
00356
00357 s << "\nstatus: ";
00358 switch (status) {
00359 case UNSATISFIABLE:
00360 s << "UNSATISFIABLE";
00361 break;
00362 case OPTIMIZED:
00363 s << "OPTIMIZED";
00364 break;
00365 case PARTIALLY_SATISFIABLE:
00366 s << "PARTIALLY_SATISFIABLE";
00367 break;
00368 }
00369 s << "\n";
00370
00371 s << "\nparameters";
00372 parameters.ascii_dump(s);
00373
00374 s << "\ninitial_context\n";
00375 initial_context.ascii_dump(s);
00376
00377 s << "\ncontrol_parameters\n";
00378 for (dimension_type i = 0; i < CONTROL_PARAMETER_NAME_SIZE; ++i) {
00379 Control_Parameter_Value value = control_parameters[i];
00380 switch (value) {
00381 case CUTTING_STRATEGY_FIRST:
00382 s << "CUTTING_STRATEGY_FIRST";
00383 break;
00384 case CUTTING_STRATEGY_DEEPEST:
00385 s << "CUTTING_STRATEGY_DEEPEST";
00386 break;
00387 case CUTTING_STRATEGY_ALL:
00388 s << "CUTTING_STRATEGY_ALL";
00389 break;
00390 case PIVOT_ROW_STRATEGY_FIRST:
00391 s << "PIVOT_ROW_STRATEGY_FIRST";
00392 break;
00393 case PIVOT_ROW_STRATEGY_MAX_COLUMN:
00394 s << "PIVOT_ROW_STRATEGY_MAX_COLUMN";
00395 break;
00396 default:
00397 s << "Invalid control parameter value";
00398 }
00399 s << "\n";
00400 }
00401
00402 s << "\nbig_parameter_dimension: " << big_parameter_dimension << "\n";
00403
00404 s << "\ncurrent_solution: ";
00405 if (current_solution == 0)
00406 s << "BOTTOM\n";
00407 else if (const PIP_Decision_Node* dec = current_solution->as_decision()) {
00408 s << "DECISION\n";
00409 dec->ascii_dump(s);
00410 }
00411 else {
00412 const PIP_Solution_Node* sol = current_solution->as_solution();
00413 PPL_ASSERT(sol != 0);
00414 s << "SOLUTION\n";
00415 sol->ascii_dump(s);
00416 }
00417 }
00418
00419 PPL_OUTPUT_DEFINITIONS(PIP_Problem)
00420
00421 bool
00422 PPL::PIP_Problem::ascii_load(std::istream& s) {
00423 std::string str;
00424 if (!(s >> str) || str != "external_space_dim:")
00425 return false;
00426
00427 if (!(s >> external_space_dim))
00428 return false;
00429
00430 if (!(s >> str) || str != "internal_space_dim:")
00431 return false;
00432
00433 if (!(s >> internal_space_dim))
00434 return false;
00435
00436 if (!(s >> str) || str != "input_cs(")
00437 return false;
00438
00439 dimension_type input_cs_size;
00440
00441 if (!(s >> input_cs_size))
00442 return false;
00443
00444 if (!(s >> str) || str != ")")
00445 return false;
00446
00447 Constraint c(Constraint::zero_dim_positivity());
00448 for (dimension_type i = 0; i < input_cs_size; ++i) {
00449 if (!c.ascii_load(s))
00450 return false;
00451 input_cs.push_back(c);
00452 }
00453
00454 if (!(s >> str) || str != "first_pending_constraint:")
00455 return false;
00456
00457 if (!(s >> first_pending_constraint))
00458 return false;
00459
00460 if (!(s >> str) || str != "status:")
00461 return false;
00462
00463 if (!(s >> str))
00464 return false;
00465
00466 if (str == "UNSATISFIABLE")
00467 status = UNSATISFIABLE;
00468 else if (str == "OPTIMIZED")
00469 status = OPTIMIZED;
00470 else if (str == "PARTIALLY_SATISFIABLE")
00471 status = PARTIALLY_SATISFIABLE;
00472 else
00473 return false;
00474
00475 if (!(s >> str) || str != "parameters")
00476 return false;
00477
00478 if (!parameters.ascii_load(s))
00479 return false;
00480
00481 if (!(s >> str) || str != "initial_context")
00482 return false;
00483
00484 if (!initial_context.ascii_load(s))
00485 return false;
00486
00487 if (!(s >> str) || str != "control_parameters")
00488 return false;
00489
00490 for (dimension_type i = 0; i < CONTROL_PARAMETER_NAME_SIZE; ++i) {
00491 if (!(s >> str))
00492 return false;
00493 Control_Parameter_Value value;
00494 if (str == "CUTTING_STRATEGY_FIRST")
00495 value = CUTTING_STRATEGY_FIRST;
00496 else if (str == "CUTTING_STRATEGY_DEEPEST")
00497 value = CUTTING_STRATEGY_DEEPEST;
00498 else if (str == "CUTTING_STRATEGY_ALL")
00499 value = CUTTING_STRATEGY_ALL;
00500 else if (str == "PIVOT_ROW_STRATEGY_FIRST")
00501 value = PIVOT_ROW_STRATEGY_FIRST;
00502 else if (str == "PIVOT_ROW_STRATEGY_MAX_COLUMN")
00503 value = PIVOT_ROW_STRATEGY_MAX_COLUMN;
00504 else
00505 return false;
00506 control_parameters[i] = value;
00507 }
00508
00509 if (!(s >> str) || str != "big_parameter_dimension:")
00510 return false;
00511 if (!(s >> big_parameter_dimension))
00512 return false;
00513
00514
00515 delete current_solution;
00516 current_solution = 0;
00517
00518 if (!(s >> str) || str != "current_solution:")
00519 return false;
00520 if (!(s >> str))
00521 return false;
00522 if (str == "BOTTOM")
00523 current_solution = 0;
00524 else if (str == "DECISION") {
00525 PIP_Decision_Node* dec = new PIP_Decision_Node(0, 0, 0);
00526 current_solution = dec;
00527 if (!dec->ascii_load(s))
00528 return false;
00529 dec->set_owner(this);
00530 }
00531 else if (str == "SOLUTION") {
00532 PIP_Solution_Node* sol = new PIP_Solution_Node(0);
00533 current_solution = sol;
00534 if (!sol->ascii_load(s))
00535 return false;
00536 sol->set_owner(this);
00537 }
00538 else
00539
00540 return false;
00541
00542 PPL_ASSERT(OK());
00543 return true;
00544 }
00545
00546 void
00547 PPL::PIP_Problem::clear() {
00548 external_space_dim = 0;
00549 internal_space_dim = 0;
00550 status = PARTIALLY_SATISFIABLE;
00551 if (current_solution != 0) {
00552 delete current_solution;
00553 current_solution = 0;
00554 }
00555 input_cs.clear();
00556 first_pending_constraint = 0;
00557 parameters.clear();
00558 initial_context.clear();
00559 control_parameters_init();
00560 big_parameter_dimension = not_a_dimension();
00561 }
00562
00563 void
00564 PPL::PIP_Problem
00565 ::add_space_dimensions_and_embed(const dimension_type m_vars,
00566 const dimension_type m_params) {
00567
00568
00569 if (m_vars == 0 && m_params == 0)
00570 return;
00571
00572
00573
00574 dimension_type available = max_space_dimension() - space_dimension();
00575 bool should_throw = (m_vars > available);
00576 if (!should_throw) {
00577 available -= m_vars;
00578 should_throw = (m_params > available);
00579 }
00580 if (should_throw)
00581 throw std::length_error("PPL::PIP_Problem::"
00582 "add_space_dimensions_and_embed(m_v, m_p):\n"
00583 "adding m_v+m_p new space dimensions exceeds "
00584 "the maximum allowed space dimension.");
00585
00586 external_space_dim += m_vars;
00587
00588 for (dimension_type i = m_params; i-- > 0; ) {
00589 parameters.insert(Variable(external_space_dim));
00590 ++external_space_dim;
00591 }
00592
00593 if (status != UNSATISFIABLE)
00594 status = PARTIALLY_SATISFIABLE;
00595 PPL_ASSERT(OK());
00596 }
00597
00598 void
00599 PPL::PIP_Problem
00600 ::add_to_parameter_space_dimensions(const Variables_Set& p_vars) {
00601 if (p_vars.space_dimension() > external_space_dim)
00602 throw std::invalid_argument("PPL::PIP_Problem::"
00603 "add_to_parameter_space_dimension(p_vars):\n"
00604 "*this and p_vars are dimension "
00605 "incompatible.");
00606 const dimension_type original_size = parameters.size();
00607 parameters.insert(p_vars.begin(), p_vars.end());
00608
00609 for (Variables_Set::const_iterator p = p_vars.begin(),
00610 end = p_vars.end(); p != end; ++p) {
00611 if (*p < internal_space_dim) {
00612 throw std::invalid_argument("PPL::PIP_Problem::"
00613 "add_to_parameter_space_dimension(p_vars):"
00614 "p_vars contain variable indices.");
00615 }
00616 }
00617
00618
00619
00620 if (parameters.size() != original_size && status != UNSATISFIABLE)
00621 status = PARTIALLY_SATISFIABLE;
00622 }
00623
00624 void
00625 PPL::PIP_Problem::add_constraint(const Constraint& c) {
00626 if (c.space_dimension() > external_space_dim) {
00627 std::ostringstream s;
00628 s << "PPL::PIP_Problem::add_constraint(c):\n"
00629 << "dim == "<< external_space_dim << " and c.space_dimension() == "
00630 << c.space_dimension() << " are dimension incompatible.";
00631 throw std::invalid_argument(s.str());
00632 }
00633 input_cs.push_back(c);
00634
00635 if (status != UNSATISFIABLE)
00636 status = PARTIALLY_SATISFIABLE;
00637 }
00638
00639 void
00640 PPL::PIP_Problem::add_constraints(const Constraint_System &cs) {
00641 for (Constraint_System::const_iterator ci = cs.begin(),
00642 ci_end = cs.end(); ci != ci_end; ++ci)
00643 add_constraint(*ci);
00644 }
00645
00646 bool
00647 PPL::PIP_Problem::is_satisfiable() const {
00648 if (status == PARTIALLY_SATISFIABLE)
00649 solve();
00650 return status == OPTIMIZED;
00651 }
00652
00653 void
00654 PPL::PIP_Problem::set_control_parameter(Control_Parameter_Value value) {
00655 switch (value) {
00656 case CUTTING_STRATEGY_FIRST:
00657
00658 case CUTTING_STRATEGY_DEEPEST:
00659
00660 case CUTTING_STRATEGY_ALL:
00661 control_parameters[CUTTING_STRATEGY] = value;
00662 break;
00663 case PIVOT_ROW_STRATEGY_FIRST:
00664
00665 case PIVOT_ROW_STRATEGY_MAX_COLUMN:
00666 control_parameters[PIVOT_ROW_STRATEGY] = value;
00667 break;
00668 default:
00669 throw std::invalid_argument("PPL::PIP_Problem::set_control_parameter(v)"
00670 ":\ninvalid value.");
00671 }
00672 }
00673
00674 void
00675 PPL::PIP_Problem::set_big_parameter_dimension(dimension_type big_dim) {
00676 if (parameters.count(big_dim) == 0)
00677 throw std::invalid_argument("PPL::PIP_Problem::"
00678 "set_big_parameter_dimension(big_dim):\n"
00679 "dimension 'big_dim' is not a parameter.");
00680 if (big_dim < internal_space_dim)
00681 throw std::invalid_argument("PPL::PIP_Problem::"
00682 "set_big_parameter_dimension(big_dim):\n"
00683 "only newly-added parameters can be"
00684 "converted into the big parameter.");
00685 big_parameter_dimension = big_dim;
00686 }
00687
00688 PPL::memory_size_type
00689 PPL::PIP_Problem::external_memory_in_bytes() const {
00690 memory_size_type n = initial_context.external_memory_in_bytes();
00691
00692 if (current_solution)
00693 n += current_solution->total_memory_in_bytes();
00694
00695 n += input_cs.capacity() * sizeof(Constraint);
00696 for (const_iterator i = input_cs.begin(),
00697 i_end = input_cs.end(); i != i_end; ++i)
00698 n += (i->external_memory_in_bytes());
00699
00700 n += parameters.size() * sizeof(dimension_type);
00701
00702 return n;
00703 }
00704
00705 PPL::memory_size_type
00706 PPL::PIP_Problem::total_memory_in_bytes() const {
00707 return sizeof(*this) + external_memory_in_bytes();
00708 }
00709
00710 void
00711 PPL::PIP_Problem::print_solution(std::ostream& s, unsigned indent) const {
00712 switch (status) {
00713
00714 case UNSATISFIABLE:
00715 PPL_ASSERT(current_solution == 0);
00716 PIP_Tree_Node::indent_and_print(s, indent, "_|_\n");
00717 break;
00718
00719 case OPTIMIZED:
00720 PPL_ASSERT(current_solution != 0);
00721 current_solution->print(s, indent);
00722 break;
00723
00724 case PARTIALLY_SATISFIABLE:
00725 throw std::logic_error("PIP_Problem::print_solution():\n"
00726 "the PIP problem has not been solved.");
00727 }
00728 }
00729