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_Tree.defs.hh"
00026 #include "PIP_Problem.defs.hh"
00027
00028 #include <algorithm>
00029 #include <memory>
00030
00031
00032
00033
00034
00035 namespace Parma_Polyhedra_Library {
00036
00037 namespace {
00038
00039
00040 inline void
00041 pos_mod_assign(Coefficient& z,
00042 Coefficient_traits::const_reference x,
00043 Coefficient_traits::const_reference y) {
00044 z = x % y;
00045 if (z < 0)
00046 z += y;
00047 }
00048
00049
00050 inline void
00051 add_mul_assign_row(Row& x,
00052 Coefficient_traits::const_reference c, const Row& y) {
00053 WEIGHT_BEGIN();
00054 const dimension_type x_size = x.size();
00055 PPL_ASSERT(x_size == y.size());
00056 for (dimension_type i = x_size; i-- > 0; )
00057 add_mul_assign(x[i], c, y[i]);
00058 WEIGHT_ADD_MUL(1, x_size);
00059 }
00060
00061
00062 inline void
00063 sub_assign(Row& x, const Row& y) {
00064 WEIGHT_BEGIN();
00065 const dimension_type x_size = x.size();
00066 PPL_ASSERT(x_size == y.size());
00067 for (dimension_type i = x_size; i-- > 0; )
00068 x[i] -= y[i];
00069 WEIGHT_ADD_MUL(1, x_size);
00070 }
00071
00072
00073 void
00074 merge_assign(Matrix& x,
00075 const Constraint_System& y,
00076 const Variables_Set& parameters) {
00077 const dimension_type params_size = parameters.size();
00078 PPL_ASSERT(params_size == x.num_columns() - 1);
00079 const dimension_type new_rows = std::distance(y.begin(), y.end());
00080 if (new_rows == 0)
00081 return;
00082 const dimension_type old_num_rows = x.num_rows();
00083 x.add_zero_rows(new_rows, Row::Flags());
00084
00085
00086 const dimension_type cs_space_dim = y.space_dimension();
00087 const Variables_Set::const_iterator param_begin = parameters.begin();
00088 const Variables_Set::const_iterator param_end = parameters.end();
00089
00090 dimension_type i = old_num_rows;
00091 for (Constraint_System::const_iterator y_i = y.begin(),
00092 y_end = y.end(); y_i != y_end; ++y_i, ++i) {
00093 WEIGHT_BEGIN();
00094 PPL_ASSERT(y_i->is_nonstrict_inequality());
00095 Row& x_i = x[i];
00096 x_i[0] = y_i->inhomogeneous_term();
00097 Variables_Set::const_iterator pj;
00098 dimension_type j = 1;
00099 for (pj = param_begin; pj != param_end; ++pj, ++j) {
00100 Variable vj(*pj);
00101 if (vj.space_dimension() > cs_space_dim)
00102 break;
00103 x_i[j] = y_i->coefficient(vj);
00104 }
00105 WEIGHT_ADD_MUL(1, params_size);
00106 }
00107 }
00108
00109
00110 inline void
00111 neg_assign_row(Row& x, const Row& y) {
00112 WEIGHT_BEGIN();
00113 const dimension_type x_size = x.size();
00114 PPL_ASSERT(x_size == y.size());
00115 for (dimension_type i = x.size(); i-- > 0; )
00116 neg_assign(x[i], y[i]);
00117 WEIGHT_ADD_MUL(1, x_size);
00118 }
00119
00120
00121
00122
00123
00124 inline void
00125 complement_assign(Row& x, const Row& y,
00126 Coefficient_traits::const_reference den) {
00127 PPL_ASSERT(den > 0);
00128 neg_assign_row(x, y);
00129 if (den == 1)
00130 --x[0];
00131 else {
00132 PPL_DIRTY_TEMP_COEFFICIENT(mod);
00133 pos_mod_assign(mod, x[0], den);
00134 x[0] -= (mod == 0) ? den : mod;
00135 }
00136 }
00137
00138
00139 inline void
00140 add_artificial_parameters(Matrix& context,
00141 const dimension_type num_art_params) {
00142 if (num_art_params > 0)
00143 context.add_zero_columns(num_art_params);
00144 }
00145
00146
00147 inline void
00148 add_artificial_parameters(Variables_Set& params,
00149 const dimension_type space_dim,
00150 const dimension_type num_art_params) {
00151 for (dimension_type i = 0; i < num_art_params; ++i)
00152 params.insert(space_dim + i);
00153 }
00154
00155
00156
00157 inline void
00158 add_artificial_parameters(Matrix& context,
00159 Variables_Set& params,
00160 dimension_type& space_dim,
00161 const dimension_type num_art_params) {
00162 add_artificial_parameters(context, num_art_params);
00163 add_artificial_parameters(params, space_dim, num_art_params);
00164 space_dim += num_art_params;
00165 }
00166
00167
00168
00169
00170
00171
00172 bool
00173 column_lower(const Matrix& tableau,
00174 const std::vector<dimension_type>& mapping,
00175 const std::vector<bool>& basis,
00176 const Row& pivot_a,
00177 const dimension_type ja,
00178 const Row& pivot_b,
00179 const dimension_type jb,
00180 Coefficient_traits::const_reference cst_a = -1,
00181 Coefficient_traits::const_reference cst_b = -1) {
00182 const Coefficient& sij_a = pivot_a[ja];
00183 const Coefficient& sij_b = pivot_b[jb];
00184 PPL_ASSERT(sij_a > 0);
00185 PPL_ASSERT(sij_b > 0);
00186
00187 PPL_DIRTY_TEMP_COEFFICIENT(lhs_coeff);
00188 PPL_DIRTY_TEMP_COEFFICIENT(rhs_coeff);
00189 lhs_coeff = cst_a * sij_b;
00190 rhs_coeff = cst_b * sij_a;
00191
00192 if (ja == jb) {
00193
00194
00195
00196 return lhs_coeff > rhs_coeff;
00197 }
00198
00199 PPL_DIRTY_TEMP_COEFFICIENT(lhs);
00200 PPL_DIRTY_TEMP_COEFFICIENT(rhs);
00201 const dimension_type num_vars = mapping.size();
00202 dimension_type k = 0;
00203
00204
00205
00206 WEIGHT_BEGIN();
00207 while (true) {
00208 const dimension_type mk = mapping[k];
00209 const bool in_base = basis[k];
00210 if (++k >= num_vars)
00211 return false;
00212 if (in_base) {
00213
00214 if (mk == ja) {
00215
00216 if (lhs_coeff == 0)
00217 continue;
00218 else
00219 return lhs_coeff > 0;
00220 }
00221 if (mk == jb) {
00222
00223 if (rhs_coeff == 0)
00224 continue;
00225 else
00226 return 0 > rhs_coeff;
00227 }
00228
00229 continue;
00230 } else {
00231
00232 WEIGHT_ADD(2);
00233 const Row& t_mk = tableau[mk];
00234 lhs = lhs_coeff * t_mk[ja];
00235 rhs = rhs_coeff * t_mk[jb];
00236 if (lhs == rhs)
00237 continue;
00238 else
00239 return lhs > rhs;
00240 }
00241 }
00242
00243 throw std::runtime_error("PPL internal error");
00244 }
00245
00246
00247
00248
00249
00250 bool
00251 find_lexico_minimum_column(const Matrix& tableau,
00252 const std::vector<dimension_type>& mapping,
00253 const std::vector<bool>& basis,
00254 const Row& pivot_row,
00255 const dimension_type start_j,
00256 dimension_type& j_out) {
00257 WEIGHT_BEGIN();
00258 const dimension_type num_cols = tableau.num_columns();
00259 bool has_positive_coefficient = false;
00260
00261 j_out = num_cols;
00262 for (dimension_type j = start_j; j < num_cols; ++j) {
00263 const Coefficient& c = pivot_row[j];
00264 if (c <= 0)
00265 continue;
00266 has_positive_coefficient = true;
00267 if (j_out == num_cols
00268 || column_lower(tableau, mapping, basis,
00269 pivot_row, j, pivot_row, j_out))
00270 j_out = j;
00271 }
00272 WEIGHT_ADD_MUL(1, num_cols - start_j);
00273 return has_positive_coefficient;
00274 }
00275
00276
00277 void
00278 row_normalize(Row& x, Coefficient& den) {
00279 if (den == 1)
00280 return;
00281 WEIGHT_BEGIN();
00282 const dimension_type x_size = x.size();
00283 PPL_DIRTY_TEMP_COEFFICIENT(gcd);
00284 gcd = den;
00285 for (dimension_type i = x_size; i-- > 0; ) {
00286 const Coefficient& x_i = x[i];
00287 if (x_i != 0) {
00288 WEIGHT_ADD(1);
00289 gcd_assign(gcd, x_i, gcd);
00290 if (gcd == 1)
00291 return;
00292 }
00293 }
00294
00295 WEIGHT_BEGIN();
00296 for (dimension_type i = x_size; i-- > 0; ) {
00297 Coefficient& x_i = x[i];
00298 exact_div_assign(x_i, x_i, gcd);
00299 }
00300 WEIGHT_ADD_MUL(1, x_size);
00301
00302 exact_div_assign(den, den, gcd);
00303 }
00304
00305
00306 void
00307 integral_simplification(Row& row) {
00308 if (row[0] != 0) {
00309
00310 const dimension_type row_size = row.size();
00311 PPL_ASSERT(row_size > 1);
00312 dimension_type i = 1;
00313 for ( ; row[i] == 0; ++i)
00314 PPL_ASSERT(i < row_size);
00315
00316 PPL_DIRTY_TEMP_COEFFICIENT(gcd);
00317 gcd = row[i];
00318 for (++i; i < row_size; ++i) {
00319 Coefficient_traits::const_reference row_i = row[i];
00320 if (row_i != 0) {
00321 gcd_assign(gcd, gcd, row_i);
00322 if (gcd == 1)
00323 break;
00324 }
00325 }
00326 if (gcd != 1) {
00327 PPL_DIRTY_TEMP_COEFFICIENT(mod);
00328 pos_mod_assign(mod, row[0], gcd);
00329 row[0] -= mod;
00330 }
00331 }
00332
00333 row.normalize();
00334 }
00335
00336 }
00337
00338 namespace IO_Operators {
00339
00340 std::ostream&
00341 operator<<(std::ostream& os, const PIP_Tree_Node& x) {
00342 x.print(os);
00343 return os;
00344 }
00345
00346 std::ostream&
00347 operator<<(std::ostream& os, const PIP_Tree_Node::Artificial_Parameter& x) {
00348 const Linear_Expression& expr = static_cast<const Linear_Expression&>(x);
00349 os << "(" << expr << ") div " << x.denominator();
00350 return os;
00351 }
00352
00353 }
00354
00355 PIP_Tree_Node::PIP_Tree_Node(const PIP_Problem* owner)
00356 : owner_(owner),
00357 parent_(0),
00358 constraints_(),
00359 artificial_parameters() {
00360 }
00361
00362 PIP_Tree_Node::PIP_Tree_Node(const PIP_Tree_Node& y)
00363 : owner_(y.owner_),
00364 parent_(0),
00365 constraints_(y.constraints_),
00366 artificial_parameters(y.artificial_parameters) {
00367 }
00368
00369 PIP_Tree_Node::Artificial_Parameter
00370 ::Artificial_Parameter(const Linear_Expression& expr,
00371 Coefficient_traits::const_reference den)
00372 : Linear_Expression(expr), denom(den) {
00373 if (denom == 0)
00374 throw std::invalid_argument("PIP_Tree_Node::Artificial_Parameter(e, d): "
00375 "denominator d is zero.");
00376
00377
00378
00379 Linear_Expression& param_expr = *this;
00380 if (denom < 0) {
00381 neg_assign(denom);
00382 param_expr *= -1;
00383 }
00384
00385
00386 PPL_DIRTY_TEMP_COEFFICIENT(gcd);
00387 gcd = denom;
00388 gcd_assign(gcd, param_expr.inhomogeneous_term(), gcd);
00389 if (gcd == 1)
00390 return;
00391 const dimension_type space_dim = param_expr.space_dimension();
00392 for (dimension_type i = space_dim; i-- > 0; ) {
00393 Coefficient_traits::const_reference
00394 e_i = param_expr.coefficient(Variable(i));
00395 if (e_i != 0) {
00396 gcd_assign(gcd, e_i, gcd);
00397 if (gcd == 1)
00398 return;
00399 }
00400 }
00401
00402
00403 PPL_ASSERT(gcd > 1);
00404 Linear_Expression normalized(0 * Variable(space_dim-1));
00405 PPL_DIRTY_TEMP_COEFFICIENT(coeff);
00406 exact_div_assign(coeff, param_expr.inhomogeneous_term(), gcd);
00407 normalized += coeff;
00408 for (dimension_type i = space_dim; i-- > 0; ) {
00409 Coefficient_traits::const_reference
00410 e_i = param_expr.coefficient(Variable(i));
00411 if (e_i != 0) {
00412 exact_div_assign(coeff, e_i, gcd);
00413 add_mul_assign(normalized, coeff, Variable(i));
00414 }
00415 }
00416
00417 param_expr = normalized;
00418 exact_div_assign(denom, denom, gcd);
00419
00420 PPL_ASSERT(OK());
00421 }
00422
00423 bool
00424 PIP_Tree_Node::Artificial_Parameter
00425 ::operator==(const PIP_Tree_Node::Artificial_Parameter& y) const {
00426 const Artificial_Parameter& x = *this;
00427 if (x.space_dimension() != y.space_dimension())
00428 return false;
00429 if (x.denom != y.denom)
00430 return false;
00431 if (x.inhomogeneous_term() != y.inhomogeneous_term())
00432 return false;
00433 for (dimension_type i = x.space_dimension(); i-- > 0; )
00434 if (x.coefficient(Variable(i)) != y.coefficient(Variable(i)))
00435 return false;
00436 return true;
00437 }
00438
00439 bool
00440 PIP_Tree_Node::Artificial_Parameter
00441 ::operator!=(const PIP_Tree_Node::Artificial_Parameter& y) const {
00442 return !operator==(y);
00443 }
00444
00445 bool
00446 PIP_Tree_Node::Artificial_Parameter::OK() const {
00447 if (denom <= 0) {
00448 #ifndef NDEBUG
00449 std::cerr << "PIP_Tree_Node::Artificial_Parameter "
00450 << "has a non-positive denominator.\n";
00451 #endif
00452 return false;
00453 }
00454 return true;
00455 }
00456
00457 void
00458 PIP_Tree_Node::Artificial_Parameter::ascii_dump(std::ostream& s) const {
00459 s << "artificial_parameter ";
00460 Linear_Expression::ascii_dump(s);
00461 s << " / " << denom << "\n";
00462 }
00463
00464 bool
00465 PIP_Tree_Node::Artificial_Parameter::ascii_load(std::istream& s) {
00466 std::string str;
00467 if (!(s >> str) || str != "artificial_parameter")
00468 return false;
00469 if (!Linear_Expression::ascii_load(s))
00470 return false;
00471 if (!(s >> str) || str != "/")
00472 return false;
00473 if (!(s >> denom))
00474 return false;
00475 PPL_ASSERT(OK());
00476 return true;
00477 }
00478
00479 PPL_OUTPUT_DEFINITIONS(PIP_Tree_Node::Artificial_Parameter)
00480
00481 PIP_Solution_Node::PIP_Solution_Node(const PIP_Problem* owner)
00482 : PIP_Tree_Node(owner),
00483 tableau(),
00484 basis(),
00485 mapping(),
00486 var_row(),
00487 var_column(),
00488 special_equality_row(0),
00489 big_dimension(not_a_dimension()),
00490 sign(),
00491 solution(),
00492 solution_valid(false) {
00493 }
00494
00495 PIP_Solution_Node::PIP_Solution_Node(const PIP_Solution_Node& y)
00496 : PIP_Tree_Node(y),
00497 tableau(y.tableau),
00498 basis(y.basis),
00499 mapping(y.mapping),
00500 var_row(y.var_row),
00501 var_column(y.var_column),
00502 special_equality_row(y.special_equality_row),
00503 big_dimension(y.big_dimension),
00504 sign(y.sign),
00505 solution(y.solution),
00506 solution_valid(y.solution_valid) {
00507 }
00508
00509 PIP_Solution_Node::PIP_Solution_Node(const PIP_Solution_Node& y,
00510 No_Constraints)
00511 : PIP_Tree_Node(y.owner_),
00512 tableau(y.tableau),
00513 basis(y.basis),
00514 mapping(y.mapping),
00515 var_row(y.var_row),
00516 var_column(y.var_column),
00517 special_equality_row(y.special_equality_row),
00518 big_dimension(y.big_dimension),
00519 sign(y.sign),
00520 solution(y.solution),
00521 solution_valid(y.solution_valid) {
00522 }
00523
00524 PIP_Solution_Node::~PIP_Solution_Node() {
00525 }
00526
00527 PIP_Decision_Node::PIP_Decision_Node(const PIP_Problem* owner,
00528 PIP_Tree_Node* fcp,
00529 PIP_Tree_Node* tcp)
00530 : PIP_Tree_Node(owner),
00531 false_child(fcp),
00532 true_child(tcp) {
00533 if (false_child != 0)
00534 false_child->set_parent(this);
00535 if (true_child != 0)
00536 true_child->set_parent(this);
00537 }
00538
00539 PIP_Decision_Node::PIP_Decision_Node(const PIP_Decision_Node& y)
00540 : PIP_Tree_Node(y),
00541 false_child(0),
00542 true_child(0) {
00543 if (y.false_child != 0) {
00544 false_child = y.false_child->clone();
00545 false_child->set_parent(this);
00546 }
00547
00548 std::auto_ptr<PIP_Tree_Node> wrapped_node(false_child);
00549 if (y.true_child != 0) {
00550 true_child = y.true_child->clone();
00551 true_child->set_parent(this);
00552 }
00553
00554 wrapped_node.release();
00555 }
00556
00557 PIP_Decision_Node::~PIP_Decision_Node() {
00558 delete false_child;
00559 delete true_child;
00560 }
00561
00562 void
00563 PIP_Solution_Node::set_owner(const PIP_Problem* owner) {
00564 owner_ = owner;
00565 }
00566
00567 void
00568 PIP_Decision_Node::set_owner(const PIP_Problem* owner) {
00569 owner_ = owner;
00570 if (false_child)
00571 false_child->set_owner(owner);
00572 if (true_child)
00573 true_child->set_owner(owner);
00574 }
00575
00576 bool
00577 PIP_Solution_Node::check_ownership(const PIP_Problem* owner) const {
00578 return get_owner() == owner;
00579 }
00580
00581 bool
00582 PIP_Decision_Node::check_ownership(const PIP_Problem* owner) const {
00583 return get_owner() == owner
00584 && (!false_child || false_child->check_ownership(owner))
00585 && (!true_child || true_child->check_ownership(owner));
00586 }
00587
00588 const PIP_Solution_Node*
00589 PIP_Tree_Node::as_solution() const {
00590 return 0;
00591 }
00592
00593 const PIP_Decision_Node*
00594 PIP_Tree_Node::as_decision() const {
00595 return 0;
00596 }
00597
00598 const PIP_Solution_Node*
00599 PIP_Solution_Node::as_solution() const {
00600 return this;
00601 }
00602
00603 const PIP_Decision_Node*
00604 PIP_Decision_Node::as_decision() const {
00605 return this;
00606 }
00607
00608 bool
00609 PIP_Solution_Node::Tableau::OK() const {
00610 if (s.num_rows() != t.num_rows()) {
00611 #ifndef NDEBUG
00612 std::cerr << "PIP_Solution_Node::Tableau matrices "
00613 << "have a different number of rows.\n";
00614 #endif
00615 return false;
00616 }
00617
00618 if (!s.OK() || !t.OK()) {
00619 #ifndef NDEBUG
00620 std::cerr << "A PIP_Solution_Node::Tableau matrix is broken.\n";
00621 #endif
00622 return false;
00623 }
00624
00625 if (denom <= 0) {
00626 #ifndef NDEBUG
00627 std::cerr << "PIP_Solution_Node::Tableau with non-positive denominator.\n";
00628 #endif
00629 return false;
00630 }
00631
00632
00633 return true;
00634 }
00635
00636 bool
00637 PIP_Tree_Node::OK() const {
00638 #ifndef NDEBUG
00639 using std::endl;
00640 using std::cerr;
00641 #endif
00642
00643 const Constraint_System::const_iterator begin = constraints_.begin();
00644 const Constraint_System::const_iterator end = constraints_.end();
00645
00646
00647 for (Constraint_System::const_iterator ci = begin; ci != end; ++ci)
00648 if (ci->is_strict_inequality()) {
00649 #ifndef NDEBUG
00650 cerr << "The feasible region of the PIP_Problem parameter context"
00651 << "is defined by a constraint system containing strict "
00652 << "inequalities."
00653 << endl;
00654 ascii_dump(cerr);
00655 #endif
00656 return false;
00657 }
00658 return true;
00659 }
00660
00661 void
00662 PIP_Tree_Node
00663 ::add_constraint(const Row& row, const Variables_Set& parameters) {
00664 const dimension_type num_params = parameters.size();
00665 PPL_ASSERT(num_params + 1 == row.size());
00666
00667
00668 Linear_Expression expr = Linear_Expression(row[0]);
00669
00670 Variables_Set::const_reverse_iterator p_j = parameters.rbegin();
00671
00672 WEIGHT_BEGIN();
00673 for (dimension_type j = num_params; j > 0; --j) {
00674 add_mul_assign(expr, row[j], Variable(*p_j));
00675
00676 ++p_j;
00677 }
00678 WEIGHT_ADD_MUL(1, num_params);
00679
00680
00681 constraints_.insert(expr >= 0);
00682 }
00683
00684 void
00685 PIP_Tree_Node::parent_merge() {
00686 const PIP_Decision_Node& parent = *parent_;
00687
00688
00689 artificial_parameters.insert(artificial_parameters.begin(),
00690 parent.art_parameter_begin(),
00691 parent.art_parameter_end());
00692
00693 PPL_ASSERT(OK());
00694 }
00695
00696 bool
00697 PIP_Solution_Node::OK() const {
00698 #ifndef NDEBUG
00699 using std::cerr;
00700 #endif
00701 if (!PIP_Tree_Node::OK())
00702 return false;
00703
00704
00705
00706 if (!tableau.OK())
00707 return false;
00708
00709
00710 if (basis.size() != mapping.size()) {
00711 #ifndef NDEBUG
00712 cerr << "The PIP_Solution_Node::basis and PIP_Solution_Node::mapping "
00713 << "vectors do not have the same number of elements.\n";
00714 #endif
00715 return false;
00716 }
00717 if (basis.size() != var_row.size() + var_column.size()) {
00718 #ifndef NDEBUG
00719 cerr << "The sum of number of elements in the PIP_Solution_Node::var_row "
00720 << "and PIP_Solution_Node::var_column vectors is different from the "
00721 << "number of elements in the PIP_Solution_Node::basis vector.\n";
00722 #endif
00723 return false;
00724 }
00725 if (var_column.size() != tableau.s.num_columns()) {
00726 #ifndef NDEBUG
00727 cerr << "The number of elements in the PIP_Solution_Node::var_column "
00728 << "vector is different from the number of columns in the "
00729 << "PIP_Solution_Node::tableau.s Matrix.\n";
00730 #endif
00731 return false;
00732 }
00733 if (var_row.size() != tableau.s.num_rows()) {
00734 #ifndef NDEBUG
00735 cerr << "The number of elements in the PIP_Solution_Node::var_row "
00736 << "vector is different from the number of rows in the "
00737 << "PIP_Solution_Node::tableau.s Matrix.\n";
00738 #endif
00739 return false;
00740 }
00741 for (dimension_type i = mapping.size(); i-- > 0; ) {
00742 const dimension_type rowcol = mapping[i];
00743 if (basis[i] && var_column[rowcol] != i) {
00744 #ifndef NDEBUG
00745 cerr << "Variable " << i << " is basic and corresponds to column "
00746 << rowcol << " but PIP_Solution_Node::var_column[" << rowcol
00747 << "] does not correspond to variable " << i << ".\n";
00748 #endif
00749 return false;
00750 }
00751 if (!basis[i] && var_row[rowcol] != i) {
00752 #ifndef NDEBUG
00753 cerr << "Variable " << i << " is nonbasic and corresponds to row "
00754 << rowcol << " but PIP_Solution_Node::var_row[" << rowcol
00755 << "] does not correspond to variable " << i << ".\n";
00756 #endif
00757 return false;
00758 }
00759 }
00760
00761 return true;
00762 }
00763
00764 bool
00765 PIP_Decision_Node::OK() const {
00766
00767 if (!PIP_Tree_Node::OK())
00768 return false;
00769
00770
00771 if (false_child && !false_child->OK())
00772 return false;
00773 if (true_child && !true_child->OK())
00774 return false;
00775
00776
00777 if (!true_child) {
00778 #ifndef NDEBUG
00779 std::cerr << "PIP_Decision_Node with no 'true' child.\n";
00780 #endif
00781 return false;
00782 }
00783
00784
00785 if (false_child) {
00786 dimension_type
00787 dist = std::distance(constraints_.begin(), constraints_.end());
00788 if (dist != 1) {
00789 #ifndef NDEBUG
00790 std::cerr << "PIP_Decision_Node with a 'false' child has "
00791 << dist << " parametric constraints (should be 1).\n";
00792 #endif
00793 return false;
00794 }
00795 }
00796
00797
00798 return true;
00799 }
00800
00801 void
00802 PIP_Decision_Node::update_tableau(const PIP_Problem& pip,
00803 const dimension_type external_space_dim,
00804 const dimension_type first_pending_constraint,
00805 const Constraint_Sequence& input_cs,
00806 const Variables_Set& parameters) {
00807 true_child->update_tableau(pip,
00808 external_space_dim,
00809 first_pending_constraint,
00810 input_cs,
00811 parameters);
00812 if (false_child)
00813 false_child->update_tableau(pip,
00814 external_space_dim,
00815 first_pending_constraint,
00816 input_cs,
00817 parameters);
00818 PPL_ASSERT(OK());
00819 }
00820
00821 PIP_Tree_Node*
00822 PIP_Decision_Node::solve(const PIP_Problem& pip,
00823 const bool check_feasible_context,
00824 const Matrix& context,
00825 const Variables_Set& params,
00826 dimension_type space_dim,
00827 const unsigned indent_level) {
00828 #ifdef NOISY_PIP_TREE_STRUCTURE
00829 indent_and_print(std::cerr, indent_level, "=== SOLVING DECISION NODE\n");
00830 #else
00831 used(indent_level);
00832 #endif
00833 PPL_ASSERT(true_child != 0);
00834 Matrix context_true(context);
00835 Variables_Set all_params(params);
00836 const dimension_type num_art_params = artificial_parameters.size();
00837 add_artificial_parameters(context_true, all_params, space_dim,
00838 num_art_params);
00839 merge_assign(context_true, constraints_, all_params);
00840 bool has_false_child = (false_child != 0);
00841 bool has_true_child = (true_child != 0);
00842 #ifdef NOISY_PIP_TREE_STRUCTURE
00843 indent_and_print(std::cerr, indent_level,
00844 "=== DECISION: SOLVING THEN CHILD\n");
00845 #endif
00846 true_child = true_child->solve(pip, check_feasible_context,
00847 context_true, all_params, space_dim,
00848 indent_level + 1);
00849
00850 if (has_false_child) {
00851
00852 PPL_ASSERT(1 == std::distance(constraints_.begin(), constraints_.end()));
00853
00854 Matrix& context_false = context_true;
00855 Row& last = context_false[context_false.num_rows()-1];
00856 complement_assign(last, last, 1);
00857 #ifdef NOISY_PIP_TREE_STRUCTURE
00858 indent_and_print(std::cerr, indent_level,
00859 "=== DECISION: SOLVING ELSE CHILD\n");
00860 #endif
00861 false_child = false_child->solve(pip, check_feasible_context,
00862 context_false, all_params, space_dim,
00863 indent_level + 1);
00864 }
00865
00866 if (true_child == 0 && false_child == 0) {
00867
00868 #ifdef NOISY_PIP_TREE_STRUCTURE
00869 indent_and_print(std::cerr, indent_level,
00870 "=== DECISION: BOTH BRANCHES NOW UNFEASIBLE: _|_\n");
00871 #endif
00872 delete this;
00873 return 0;
00874 }
00875
00876 if (has_false_child && false_child == 0) {
00877
00878
00879
00880 #ifdef NOISY_PIP_TREE_STRUCTURE
00881 indent_and_print(std::cerr, indent_level,
00882 "=== DECISION: ELSE BRANCH NOW UNFEASIBLE\n");
00883 indent_and_print(std::cerr, indent_level,
00884 "==> merge then branch with parent.\n");
00885 #endif
00886 PIP_Tree_Node* node = true_child;
00887 node->parent_merge();
00888 node->set_parent(parent());
00889 true_child = 0;
00890 delete this;
00891 PPL_ASSERT(node->OK());
00892 return node;
00893 }
00894 else if (has_true_child && true_child == 0) {
00895
00896
00897 #ifdef NOISY_PIP_TREE_STRUCTURE
00898 indent_and_print(std::cerr, indent_level,
00899 "=== DECISION: THEN BRANCH NOW UNFEASIBLE\n");
00900 indent_and_print(std::cerr, indent_level,
00901 "==> merge else branch with parent.\n");
00902 #endif
00903 PIP_Tree_Node* node = false_child;
00904 node->parent_merge();
00905 node->set_parent(parent());
00906 false_child = 0;
00907 delete this;
00908 PPL_ASSERT(node->OK());
00909 return node;
00910 }
00911 else if (check_feasible_context) {
00912
00913
00914 Constraint_System cs;
00915 cs.swap(constraints_);
00916 const Constraint_System::const_iterator end = cs.end();
00917 for (Constraint_System::const_iterator ci = cs.begin(); ci != end; ++ci) {
00918 Matrix ctx_copy(context);
00919 merge_assign(ctx_copy, Constraint_System(*ci), all_params);
00920 Row& last = ctx_copy[ctx_copy.num_rows()-1];
00921 complement_assign(last, last, 1);
00922 if (compatibility_check(ctx_copy)) {
00923
00924 constraints_.insert(*ci);
00925 }
00926 }
00927
00928 if (constraints_.empty()) {
00929 #ifdef NOISY_PIP_TREE_STRUCTURE
00930 indent_and_print(std::cerr, indent_level,
00931 "=== DECISION: NO BRANCHING CONSTRAINTS LEFT\n");
00932 indent_and_print(std::cerr, indent_level,
00933 "==> merge then branch with parent.\n");
00934 #endif
00935 PIP_Tree_Node* node = true_child;
00936 node->parent_merge();
00937 node->set_parent(parent());
00938 true_child = 0;
00939 delete this;
00940 PPL_ASSERT(node->OK());
00941 return node;
00942 }
00943 }
00944 PPL_ASSERT(OK());
00945 return this;
00946 }
00947
00948 void
00949 PIP_Decision_Node::ascii_dump(std::ostream& s) const {
00950
00951 PIP_Tree_Node::ascii_dump(s);
00952
00953
00954 s << "\ntrue_child: ";
00955 if (true_child == 0) {
00956
00957
00958
00959 s << "BOTTOM\n";
00960 }
00961 else if (const PIP_Decision_Node* dec = true_child->as_decision()) {
00962 s << "DECISION\n";
00963 dec->ascii_dump(s);
00964 }
00965 else {
00966 const PIP_Solution_Node* sol = true_child->as_solution();
00967 PPL_ASSERT(sol != 0);
00968 s << "SOLUTION\n";
00969 sol->ascii_dump(s);
00970 }
00971
00972
00973 s << "\nfalse_child: ";
00974 if (false_child == 0)
00975 s << "BOTTOM\n";
00976 else if (const PIP_Decision_Node* dec = false_child->as_decision()) {
00977
00978
00979
00980
00981
00982 s << "DECISION\n";
00983 dec->ascii_dump(s);
00984 }
00985 else {
00986 const PIP_Solution_Node* sol = false_child->as_solution();
00987 PPL_ASSERT(sol != 0);
00988 s << "SOLUTION\n";
00989 sol->ascii_dump(s);
00990 }
00991 }
00992
00993 bool
00994 PIP_Decision_Node::ascii_load(std::istream& s) {
00995 std::string str;
00996
00997
00998 if (!PIP_Tree_Node::ascii_load(s))
00999 return false;
01000
01001
01002 delete true_child;
01003 true_child = 0;
01004
01005
01006 if (!(s >> str) || str != "true_child:")
01007 return false;
01008 if (!(s >> str))
01009 return false;
01010 if (str == "BOTTOM")
01011
01012 true_child = 0;
01013 else if (str == "DECISION") {
01014 PIP_Decision_Node* dec = new PIP_Decision_Node(0, 0, 0);
01015 true_child = dec;
01016 if (!dec->ascii_load(s))
01017 return false;
01018 }
01019 else if (str == "SOLUTION") {
01020 PIP_Solution_Node* sol = new PIP_Solution_Node(0);
01021 true_child = sol;
01022 if (!sol->ascii_load(s))
01023 return false;
01024 }
01025 else
01026
01027 return false;
01028
01029
01030 delete false_child;
01031 false_child = 0;
01032
01033
01034 if (!(s >> str) || str != "false_child:")
01035 return false;
01036 if (!(s >> str))
01037 return false;
01038 if (str == "BOTTOM")
01039 false_child = 0;
01040 else if (str == "DECISION") {
01041
01042 PIP_Decision_Node* dec = new PIP_Decision_Node(0, 0, 0);
01043 false_child = dec;
01044 if (!dec->ascii_load(s))
01045 return false;
01046 }
01047 else if (str == "SOLUTION") {
01048 PIP_Solution_Node* sol = new PIP_Solution_Node(0);
01049 false_child = sol;
01050 if (!sol->ascii_load(s))
01051 return false;
01052 }
01053 else
01054
01055 return false;
01056
01057
01058 PPL_ASSERT(OK());
01059 return true;
01060 }
01061
01062
01063 void
01064 PIP_Solution_Node::Tableau::normalize() {
01065 if (denom == 1)
01066 return;
01067
01068 const dimension_type num_rows = s.num_rows();
01069 const dimension_type s_cols = s.num_columns();
01070 const dimension_type t_cols = t.num_columns();
01071
01072
01073 PPL_DIRTY_TEMP_COEFFICIENT(gcd);
01074 gcd = denom;
01075 for (dimension_type i = num_rows; i-- > 0; ) {
01076 WEIGHT_BEGIN();
01077 const Row& s_i = s[i];
01078 for (dimension_type j = s_cols; j-- > 0; ) {
01079 const Coefficient& s_ij = s_i[j];
01080 if (s_ij != 0) {
01081 WEIGHT_ADD(1);
01082 gcd_assign(gcd, s_ij, gcd);
01083 if (gcd == 1)
01084 return;
01085 }
01086 }
01087 WEIGHT_BEGIN();
01088 const Row& t_i = t[i];
01089 for (dimension_type j = t_cols; j-- > 0; ) {
01090 const Coefficient& t_ij = t_i[j];
01091 if (t_ij != 0) {
01092 WEIGHT_ADD(1);
01093 gcd_assign(gcd, t_ij, gcd);
01094 if (gcd == 1)
01095 return;
01096 }
01097 }
01098 }
01099
01100 PPL_ASSERT(gcd > 1);
01101
01102 WEIGHT_BEGIN();
01103 for (dimension_type i = num_rows; i-- > 0; ) {
01104 Row& s_i = s[i];
01105 for (dimension_type j = s_cols; j-- > 0; ) {
01106 Coefficient& s_ij = s_i[j];
01107 exact_div_assign(s_ij, s_ij, gcd);
01108 }
01109 Row& t_i = t[i];
01110 for (dimension_type j = t_cols; j-- > 0; ) {
01111 Coefficient& t_ij = t_i[j];
01112 exact_div_assign(t_ij, t_ij, gcd);
01113 }
01114 }
01115 WEIGHT_ADD_MUL(s_cols + t_cols, num_rows);
01116
01117 exact_div_assign(denom, denom, gcd);
01118 }
01119
01120 void
01121 PIP_Solution_Node::Tableau::scale(Coefficient_traits::const_reference ratio) {
01122 WEIGHT_BEGIN();
01123 const dimension_type num_rows = s.num_rows();
01124 const dimension_type s_cols = s.num_columns();
01125 const dimension_type t_cols = t.num_columns();
01126 for (dimension_type i = num_rows; i-- > 0; ) {
01127 Row& s_i = s[i];
01128 for (dimension_type j = s_cols; j-- > 0; )
01129 s_i[j] *= ratio;
01130 Row& t_i = t[i];
01131 for (dimension_type j = t_cols; j-- > 0; )
01132 t_i[j] *= ratio;
01133 }
01134 WEIGHT_ADD_MUL(s_cols + t_cols, num_rows);
01135 denom *= ratio;
01136 }
01137
01138 bool
01139 PIP_Solution_Node::Tableau
01140 ::is_better_pivot(const std::vector<dimension_type>& mapping,
01141 const std::vector<bool>& basis,
01142 const dimension_type row_0,
01143 const dimension_type col_0,
01144 const dimension_type row_1,
01145 const dimension_type col_1) const {
01146 const dimension_type num_params = t.num_columns();
01147 const dimension_type num_rows = s.num_rows();
01148 const Row& s_0 = s[row_0];
01149 const Row& s_1 = s[row_1];
01150 const Coefficient& s_0_0 = s_0[col_0];
01151 const Coefficient& s_1_1 = s_1[col_1];
01152 const Row& t_0 = t[row_0];
01153 const Row& t_1 = t[row_1];
01154 PPL_DIRTY_TEMP_COEFFICIENT(coeff_0);
01155 PPL_DIRTY_TEMP_COEFFICIENT(coeff_1);
01156 PPL_DIRTY_TEMP_COEFFICIENT(product_0);
01157 PPL_DIRTY_TEMP_COEFFICIENT(product_1);
01158 WEIGHT_BEGIN();
01159
01160
01161 dimension_type j_mismatch = num_params;
01162 for (dimension_type j = 0; j < num_params; ++j) {
01163 coeff_0 = t_0[j] * s_1_1;
01164 coeff_1 = t_1[j] * s_0_0;
01165 WEIGHT_ADD(2);
01166 for (dimension_type i = 0; i < num_rows; ++i) {
01167 const Row& s_i = s[i];
01168 product_0 = coeff_0 * s_i[col_0];
01169 product_1 = coeff_1 * s_i[col_1];
01170 WEIGHT_ADD(2);
01171 if (product_0 != product_1) {
01172
01173 j_mismatch = j;
01174 goto end_loop;
01175 }
01176 }
01177 }
01178
01179 end_loop:
01180 return (j_mismatch != num_params)
01181 && column_lower(s, mapping, basis, s_0, col_0, s_1, col_1,
01182 t_0[j_mismatch], t_1[j_mismatch]);
01183 }
01184
01185 void
01186 PIP_Tree_Node::ascii_dump(std::ostream& s) const {
01187 s << "constraints_\n";
01188 constraints_.ascii_dump(s);
01189 dimension_type artificial_parameters_size = artificial_parameters.size();
01190 s << "\nartificial_parameters( " << artificial_parameters_size << " )\n";
01191 for (dimension_type i = 0; i < artificial_parameters_size; ++i)
01192 artificial_parameters[i].ascii_dump(s);
01193 }
01194
01195 bool
01196 PIP_Tree_Node::ascii_load(std::istream& s) {
01197 std::string str;
01198 if (!(s >> str) || str != "constraints_")
01199 return false;
01200 constraints_.ascii_load(s);
01201
01202 if (!(s >> str) || str != "artificial_parameters(")
01203 return false;
01204 dimension_type artificial_parameters_size;
01205 if (!(s >> artificial_parameters_size))
01206 return false;
01207 if (!(s >> str) || str != ")")
01208 return false;
01209 Artificial_Parameter ap;
01210 for (dimension_type i = 0; i < artificial_parameters_size; ++i) {
01211 if (!ap.ascii_load(s))
01212 return false;
01213 artificial_parameters.push_back(ap);
01214 }
01215
01216
01217
01218 return true;
01219 }
01220
01221 PIP_Tree_Node*
01222 PIP_Solution_Node::clone() const {
01223 return new PIP_Solution_Node(*this);
01224 }
01225
01226 PIP_Tree_Node*
01227 PIP_Decision_Node::clone() const {
01228 return new PIP_Decision_Node(*this);
01229 }
01230
01231 void
01232 PIP_Solution_Node::Tableau::ascii_dump(std::ostream& st) const {
01233 st << "denominator " << denom << "\n";
01234 st << "variables ";
01235 s.ascii_dump(st);
01236 st << "parameters ";
01237 t.ascii_dump(st);
01238 }
01239
01240 bool
01241 PIP_Solution_Node::Tableau::ascii_load(std::istream& st) {
01242 std::string str;
01243 if (!(st >> str) || str != "denominator")
01244 return false;
01245 Coefficient den;
01246 if (!(st >> den))
01247 return false;
01248 denom = den;
01249 if (!(st >> str) || str != "variables")
01250 return false;
01251 if (!s.ascii_load(st))
01252 return false;
01253 if (!(st >> str) || str != "parameters")
01254 return false;
01255 if (!t.ascii_load(st))
01256 return false;
01257 PPL_ASSERT(OK());
01258 return true;
01259 }
01260
01261 void
01262 PIP_Solution_Node::ascii_dump(std::ostream& s) const {
01263 PIP_Tree_Node::ascii_dump(s);
01264
01265 s << "\ntableau\n";
01266 tableau.ascii_dump(s);
01267
01268 s << "\nbasis ";
01269 dimension_type basis_size = basis.size();
01270 s << basis_size;
01271 for (dimension_type i = 0; i < basis_size; ++i)
01272 s << (basis[i] ? " true" : " false");
01273
01274 s << "\nmapping ";
01275 dimension_type mapping_size = mapping.size();
01276 s << mapping_size;
01277 for (dimension_type i = 0; i < mapping_size; ++i)
01278 s << " " << mapping[i];
01279
01280 s << "\nvar_row ";
01281 dimension_type var_row_size = var_row.size();
01282 s << var_row_size;
01283 for (dimension_type i = 0; i < var_row_size; ++i)
01284 s << " " << var_row[i];
01285
01286 s << "\nvar_column ";
01287 dimension_type var_column_size = var_column.size();
01288 s << var_column_size;
01289 for (dimension_type i = 0; i < var_column_size; ++i)
01290 s << " " << var_column[i];
01291 s << "\n";
01292
01293 s << "special_equality_row " << special_equality_row << "\n";
01294 s << "big_dimension " << big_dimension << "\n";
01295
01296 s << "sign ";
01297 dimension_type sign_size = sign.size();
01298 s << sign_size;
01299 for (dimension_type i = 0; i < sign_size; ++i) {
01300 s << " ";
01301 switch (sign[i]) {
01302 case UNKNOWN:
01303 s << "UNKNOWN";
01304 break;
01305 case ZERO:
01306 s << "ZERO";
01307 break;
01308 case POSITIVE:
01309 s << "POSITIVE";
01310 break;
01311 case NEGATIVE:
01312 s << "NEGATIVE";
01313 break;
01314 case MIXED:
01315 s << "MIXED";
01316 break;
01317 }
01318 }
01319 s << "\n";
01320
01321 dimension_type solution_size = solution.size();
01322 s << "solution " << solution_size << "\n";
01323 for (dimension_type i = 0; i < solution_size; ++i)
01324 solution[i].ascii_dump(s);
01325 s << "\n";
01326
01327 s << "solution_valid " << (solution_valid ? "true" : "false") << "\n";
01328 }
01329
01330 bool
01331 PIP_Solution_Node::ascii_load(std::istream& s) {
01332 if (!PIP_Tree_Node::ascii_load(s))
01333 return false;
01334
01335 std::string str;
01336 if (!(s >> str) || str != "tableau")
01337 return false;
01338 if (!tableau.ascii_load(s))
01339 return false;
01340
01341 if (!(s >> str) || str != "basis")
01342 return false;
01343 dimension_type basis_size;
01344 if (!(s >> basis_size))
01345 return false;
01346 basis.clear();
01347 for (dimension_type i = 0; i < basis_size; ++i) {
01348 if (!(s >> str))
01349 return false;
01350 bool val = false;
01351 if (str == "true")
01352 val = true;
01353 else if (str != "false")
01354 return false;
01355 basis.push_back(val);
01356 }
01357
01358 if (!(s >> str) || str != "mapping")
01359 return false;
01360 dimension_type mapping_size;
01361 if (!(s >> mapping_size))
01362 return false;
01363 mapping.clear();
01364 for (dimension_type i = 0; i < mapping_size; ++i) {
01365 dimension_type val;
01366 if (!(s >> val))
01367 return false;
01368 mapping.push_back(val);
01369 }
01370
01371 if (!(s >> str) || str != "var_row")
01372 return false;
01373 dimension_type var_row_size;
01374 if (!(s >> var_row_size))
01375 return false;
01376 var_row.clear();
01377 for (dimension_type i = 0; i < var_row_size; ++i) {
01378 dimension_type val;
01379 if (!(s >> val))
01380 return false;
01381 var_row.push_back(val);
01382 }
01383
01384 if (!(s >> str) || str != "var_column")
01385 return false;
01386 dimension_type var_column_size;
01387 if (!(s >> var_column_size))
01388 return false;
01389 var_column.clear();
01390 for (dimension_type i = 0; i < var_column_size; ++i) {
01391 dimension_type val;
01392 if (!(s >> val))
01393 return false;
01394 var_column.push_back(val);
01395 }
01396
01397 if (!(s >> str) || str != "special_equality_row")
01398 return false;
01399 if (!(s >> special_equality_row))
01400 return false;
01401
01402 if (!(s >> str) || str != "big_dimension")
01403 return false;
01404 if (!(s >> big_dimension))
01405 return false;
01406
01407 if (!(s >> str) || str != "sign")
01408 return false;
01409 dimension_type sign_size;
01410 if (!(s >> sign_size))
01411 return false;
01412 sign.clear();
01413 for (dimension_type i = 0; i < sign_size; ++i) {
01414 if (!(s >> str))
01415 return false;
01416 Row_Sign val;
01417 if (str == "UNKNOWN")
01418 val = UNKNOWN;
01419 else if (str == "ZERO")
01420 val = ZERO;
01421 else if (str == "POSITIVE")
01422 val = POSITIVE;
01423 else if (str == "NEGATIVE")
01424 val = NEGATIVE;
01425 else if (str == "MIXED")
01426 val = MIXED;
01427 else
01428 return false;
01429 sign.push_back(val);
01430 }
01431
01432 if (!(s >> str) || str != "solution")
01433 return false;
01434 dimension_type solution_size;
01435 if (!(s >> solution_size))
01436 return false;
01437 solution.clear();
01438 for (dimension_type i = 0; i < solution_size; ++i) {
01439 Linear_Expression val;
01440 if (!val.ascii_load(s))
01441 return false;
01442 solution.push_back(val);
01443 }
01444
01445 if (!(s >> str) || str != "solution_valid")
01446 return false;
01447 if (!(s >> str))
01448 return false;
01449 if (str == "true")
01450 solution_valid = true;
01451 else if (str == "false")
01452 solution_valid = false;
01453 else
01454 return false;
01455
01456 PPL_ASSERT(OK());
01457 return true;
01458 }
01459
01460 PIP_Solution_Node::Row_Sign
01461 PIP_Solution_Node::row_sign(const Row& x,
01462 const dimension_type big_dimension) {
01463 if (big_dimension != not_a_dimension()) {
01464
01465
01466 const Coefficient& x_big = x[big_dimension];
01467 if (x_big > 0)
01468 return POSITIVE;
01469 if (x_big < 0)
01470 return NEGATIVE;
01471
01472 }
01473
01474 PIP_Solution_Node::Row_Sign sign = ZERO;
01475 for (int i = x.size(); i-- > 0; ) {
01476 const Coefficient& x_i = x[i];
01477 if (x_i > 0) {
01478 if (sign == NEGATIVE)
01479 return MIXED;
01480 sign = POSITIVE;
01481 }
01482 else if (x_i < 0) {
01483 if (sign == POSITIVE)
01484 return MIXED;
01485 sign = NEGATIVE;
01486 }
01487 }
01488 return sign;
01489 }
01490
01491 bool
01492 PIP_Tree_Node::compatibility_check(const Matrix& context, const Row& row) {
01493
01494 Matrix s(context);
01495 s.add_row(row);
01496 return compatibility_check(s);
01497 }
01498
01499 bool
01500 PIP_Tree_Node::compatibility_check(Matrix& s) {
01501 PPL_ASSERT(s.OK());
01502
01503 dimension_type num_rows = s.num_rows();
01504 const dimension_type num_cols = s.num_columns();
01505 const dimension_type num_vars = num_cols - 1;
01506
01507 std::vector<Coefficient> scaling(num_rows, 1);
01508 std::vector<bool> basis;
01509 basis.reserve(num_vars + num_rows);
01510 std::vector<dimension_type> mapping;
01511 mapping.reserve(num_vars + num_rows);
01512 std::vector<dimension_type> var_row;
01513 var_row.reserve(num_rows);
01514 std::vector<dimension_type> var_column;
01515 var_column.reserve(num_cols);
01516
01517
01518 var_column.push_back(not_a_dimension());
01519 for (dimension_type j = 1; j <= num_vars; ++j) {
01520 basis.push_back(true);
01521 mapping.push_back(j);
01522 var_column.push_back(j-1);
01523 }
01524 for (dimension_type i = 0; i < num_rows; ++i) {
01525 basis.push_back(false);
01526 mapping.push_back(i);
01527 var_row.push_back(i+num_vars);
01528 }
01529
01530
01531 PPL_DIRTY_TEMP_COEFFICIENT(pivot_den);
01532
01533 PPL_DIRTY_TEMP_COEFFICIENT(product);
01534 PPL_DIRTY_TEMP_COEFFICIENT(gcd);
01535 PPL_DIRTY_TEMP_COEFFICIENT(scale_factor);
01536
01537
01538
01539 while (true) {
01540
01541
01542
01543 maybe_abandon();
01544
01545 dimension_type pi = num_rows;
01546 dimension_type pj = 0;
01547
01548
01549
01550 for (dimension_type i = 0; i < num_rows; ++i) {
01551 const Row& s_i = s[i];
01552 if (s_i[0] < 0) {
01553 dimension_type j;
01554 if (!find_lexico_minimum_column(s, mapping, basis, s_i, 1, j)) {
01555
01556 return false;
01557 }
01558
01559
01560 if (pj == 0
01561 || column_lower(s, mapping, basis,
01562 s[pi], pj, s_i, j,
01563 s[pi][0], s_i[0])) {
01564 pi = i;
01565 pj = j;
01566 }
01567 }
01568 }
01569
01570 if (pj == 0) {
01571
01572
01573
01574 bool all_integer_vars = true;
01575
01576
01577 WEIGHT_BEGIN();
01578 for (dimension_type i = 0; i < num_vars; ++i) {
01579 if (basis[i])
01580
01581 continue;
01582
01583 WEIGHT_ADD(1);
01584 const dimension_type mi = mapping[i];
01585 const Coefficient& den = scaling[mi];
01586 if (s[mi][0] % den == 0)
01587 continue;
01588
01589 all_integer_vars = false;
01590
01591 var_row.push_back(mapping.size());
01592 basis.push_back(false);
01593 mapping.push_back(num_rows);
01594 s.add_zero_rows(1, Row::Flags());
01595 Row& cut = s[num_rows];
01596 ++num_rows;
01597 const Row& s_mi = s[mi];
01598 for (dimension_type j = num_cols; j-- > 0; )
01599 pos_mod_assign(cut[j], s_mi[j], den);
01600 WEIGHT_ADD_MUL(1, num_cols);
01601 cut[0] -= den;
01602 scaling.push_back(den);
01603 }
01604
01605 if (all_integer_vars)
01606 return true;
01607 else
01608 continue;
01609 }
01610
01611
01612
01613
01614 for (dimension_type i = num_rows; i-- > 0; )
01615 row_normalize(s[i], scaling[i]);
01616
01617
01618 {
01619 const dimension_type var_pi = var_row[pi];
01620 const dimension_type var_pj = var_column[pj];
01621 var_row[pi] = var_pj;
01622 var_column[pj] = var_pi;
01623 basis[var_pi] = true;
01624 basis[var_pj] = false;
01625 mapping[var_pi] = pj;
01626 mapping[var_pj] = pi;
01627 }
01628
01629
01630 s.add_zero_rows(1, Row::Flags());
01631 Row& pivot = s[num_rows];
01632 pivot[pj] = 1;
01633
01634
01635 std::swap(pivot, s[pi]);
01636
01637
01638 pivot_den = scaling[pi];
01639 scaling[pi] = 1;
01640
01641
01642 const Coefficient& pivot_pj = pivot[pj];
01643 for (dimension_type j = num_cols; j-- > 0; ) {
01644 if (j == pj)
01645 continue;
01646 const Coefficient& pivot_j = pivot[j];
01647
01648 if (pivot_j == 0)
01649 continue;
01650 WEIGHT_BEGIN();
01651 for (dimension_type i = num_rows; i-- > 0; ) {
01652 Row& s_i = s[i];
01653 product = s_i[pj] * pivot_j;
01654 if (product % pivot_pj != 0) {
01655 WEIGHT_ADD(4);
01656
01657 gcd_assign(gcd, product, pivot_pj);
01658 exact_div_assign(scale_factor, pivot_pj, gcd);
01659 for (dimension_type k = num_cols; k-- > 0; )
01660 s_i[k] *= scale_factor;
01661 WEIGHT_ADD_MUL(1, num_cols);
01662 product *= scale_factor;
01663 scaling[i] *= scale_factor;
01664 }
01665 PPL_ASSERT(product % pivot_pj == 0);
01666 exact_div_assign(product, product, pivot_pj);
01667 s_i[j] -= product;
01668 WEIGHT_ADD(4);
01669 }
01670 }
01671
01672 if (pivot_pj != pivot_den) {
01673 WEIGHT_BEGIN();
01674 for (dimension_type i = num_rows; i-- > 0; ) {
01675 Row& s_i = s[i];
01676 Coefficient& s_i_pj = s_i[pj];
01677 product = s_i_pj * pivot_den;
01678 if (product % pivot_pj != 0) {
01679 WEIGHT_ADD(4);
01680
01681 gcd_assign(gcd, product, pivot_pj);
01682 exact_div_assign(scale_factor, pivot_pj, gcd);
01683 for (dimension_type k = num_cols; k-- > 0; )
01684 s_i[k] *= scale_factor;
01685 WEIGHT_ADD_MUL(1, num_cols);
01686 product *= scale_factor;
01687 scaling[i] *= scale_factor;
01688 }
01689 PPL_ASSERT(product % pivot_pj == 0);
01690 exact_div_assign(s_i_pj, product, pivot_pj);
01691 WEIGHT_ADD(3);
01692 }
01693 }
01694
01695 s.erase_to_end(num_rows);
01696 }
01697
01698
01699 throw std::runtime_error("PPL internal error");
01700 }
01701
01702 void
01703 PIP_Solution_Node::update_tableau(const PIP_Problem& pip,
01704 const dimension_type external_space_dim,
01705 const dimension_type first_pending_constraint,
01706 const Constraint_Sequence& input_cs,
01707 const Variables_Set& parameters) {
01708
01709 if (tableau.t.num_columns() == 0)
01710 tableau.t.add_zero_columns(1);
01711
01712
01713 const dimension_type old_num_vars = tableau.s.num_columns();
01714 const dimension_type old_num_params
01715 = pip.internal_space_dim - old_num_vars;
01716 const dimension_type num_added_dims
01717 = pip.external_space_dim - pip.internal_space_dim;
01718 const dimension_type new_num_params = parameters.size();
01719 const dimension_type num_added_params = new_num_params - old_num_params;
01720 const dimension_type num_added_vars = num_added_dims - num_added_params;
01721
01722 const dimension_type old_num_art_params
01723 = tableau.t.num_columns() - 1 - old_num_params;
01724
01725
01726 if (num_added_vars > 0)
01727 tableau.s.add_zero_columns(num_added_vars);
01728 if (num_added_params > 0)
01729 tableau.t.add_zero_columns(num_added_params);
01730
01731 if (num_added_params > 0 && old_num_art_params > 0) {
01732
01733 std::vector<dimension_type> swaps;
01734 swaps.reserve(3*old_num_art_params);
01735 const dimension_type first_ap = 1 + old_num_params;
01736 for (dimension_type i = 0; i < old_num_art_params; ++i) {
01737 dimension_type old_ap = first_ap + i;
01738 dimension_type new_ap = old_ap + num_added_params;
01739 swaps.push_back(old_ap);
01740 swaps.push_back(new_ap);
01741 swaps.push_back(0);
01742 }
01743 tableau.t.permute_columns(swaps);
01744 }
01745
01746 dimension_type new_var_column = old_num_vars;
01747 const dimension_type initial_space_dim = old_num_vars + old_num_params;
01748 for (dimension_type i = initial_space_dim; i < external_space_dim; ++i) {
01749 if (parameters.count(i) == 0) {
01750
01751 if (tableau.s.num_rows() == 0) {
01752
01753 basis.push_back(true);
01754 mapping.push_back(new_var_column);
01755 }
01756 else {
01757
01758
01759
01760
01761 basis.insert(basis.begin() + new_var_column, true);
01762 mapping.insert(mapping.begin() + new_var_column, new_var_column);
01763
01764 for (dimension_type j = var_row.size(); j-- > 0; )
01765 if (var_row[j] >= new_var_column)
01766 ++var_row[j];
01767 for (dimension_type j = var_column.size(); j-- > 0; )
01768 if (var_column[j] >= new_var_column)
01769 ++var_column[j];
01770 if (special_equality_row > 0)
01771 ++special_equality_row;
01772 }
01773 var_column.push_back(new_var_column);
01774 ++new_var_column;
01775 }
01776 }
01777
01778 if (big_dimension == not_a_dimension()
01779 && pip.big_parameter_dimension != not_a_dimension()) {
01780
01781 Variables_Set::const_iterator pos
01782 = parameters.find(pip.big_parameter_dimension);
01783 big_dimension = std::distance(parameters.begin(), pos) + 1;
01784 }
01785
01786 const Coefficient& denom = tableau.denominator();
01787 for (Constraint_Sequence::const_iterator
01788 c_iter = input_cs.begin() + first_pending_constraint,
01789 c_end = input_cs.end(); c_iter != c_end; ++c_iter) {
01790 const Constraint& constraint = *c_iter;
01791
01792
01793 const dimension_type row_id = tableau.s.num_rows();
01794 tableau.s.add_zero_rows(1, Row::Flags());
01795 tableau.t.add_zero_rows(1, Row::Flags());
01796 Row& v_row = tableau.s[row_id];
01797 Row& p_row = tableau.t[row_id];
01798
01799
01800 p_row[0] = constraint.inhomogeneous_term();
01801 if (constraint.is_strict_inequality())
01802
01803 --p_row[0];
01804 p_row[0] *= denom;
01805
01806 WEIGHT_BEGIN();
01807 dimension_type p_index = 1;
01808 dimension_type v_index = 0;
01809 for (dimension_type i = 0,
01810 i_end = constraint.space_dimension(); i != i_end; ++i) {
01811 const bool is_parameter = (1 == parameters.count(i));
01812 const Coefficient& coeff_i = constraint.coefficient(Variable(i));
01813 if (coeff_i == 0) {
01814
01815 if (is_parameter)
01816 ++p_index;
01817 else
01818 ++v_index;
01819
01820 continue;
01821 }
01822
01823 WEIGHT_ADD(1);
01824 if (is_parameter) {
01825 p_row[p_index] = coeff_i * denom;
01826 ++p_index;
01827 }
01828 else {
01829 const dimension_type mv = mapping[v_index];
01830 if (basis[v_index])
01831
01832 add_mul_assign(v_row[mv], coeff_i, denom);
01833 else {
01834
01835 add_mul_assign_row(v_row, coeff_i, tableau.s[mv]);
01836 add_mul_assign_row(p_row, coeff_i, tableau.t[mv]);
01837 }
01838 ++v_index;
01839 }
01840 }
01841
01842 if (row_sign(v_row, not_a_dimension()) == ZERO) {
01843
01844
01845 tableau.s.erase_to_end(row_id);
01846 tableau.t.erase_to_end(row_id);
01847 }
01848 else {
01849 const dimension_type var_id = mapping.size();
01850 sign.push_back(row_sign(p_row, big_dimension));
01851 basis.push_back(false);
01852 mapping.push_back(row_id);
01853 var_row.push_back(var_id);
01854 if (constraint.is_equality()) {
01855
01856
01857
01858 if (special_equality_row == 0 || basis[special_equality_row]) {
01859
01860
01861
01862
01863 tableau.s.add_zero_rows(1, Row::Flags());
01864 tableau.t.add_zero_rows(1, Row::Flags());
01865
01866
01867 neg_assign_row(tableau.s[1 + row_id], tableau.s[row_id]);
01868 neg_assign_row(tableau.t[1 + row_id], tableau.t[row_id]);
01869 sign.push_back(row_sign(tableau.t[1 + row_id], big_dimension));
01870 special_equality_row = mapping.size();
01871 basis.push_back(false);
01872 mapping.push_back(1 + row_id);
01873 var_row.push_back(1 + var_id);
01874 } else {
01875
01876 const dimension_type m_eq = mapping[special_equality_row];
01877 sub_assign(tableau.s[m_eq], v_row);
01878 sub_assign(tableau.t[m_eq], p_row);
01879 }
01880 }
01881 }
01882 }
01883 PPL_ASSERT(OK());
01884 }
01885
01886 PIP_Tree_Node*
01887 PIP_Solution_Node::solve(const PIP_Problem& pip,
01888 const bool check_feasible_context,
01889 const Matrix& ctx,
01890 const Variables_Set& params,
01891 dimension_type space_dim,
01892 const unsigned indent_level) {
01893 #ifdef NOISY_PIP_TREE_STRUCTURE
01894 indent_and_print(std::cerr, indent_level, "=== SOLVING NODE\n");
01895 #else
01896 used(indent_level);
01897 #endif
01898
01899 solution_valid = false;
01900
01901 Matrix context(ctx);
01902 Variables_Set all_params(params);
01903 const dimension_type num_art_params = artificial_parameters.size();
01904 add_artificial_parameters(context, all_params, space_dim, num_art_params);
01905 merge_assign(context, constraints_, all_params);
01906
01907
01908 if (check_feasible_context) {
01909 Matrix ctx_copy(context);
01910 if (!compatibility_check(ctx_copy)) {
01911 delete this;
01912 return 0;
01913 }
01914 }
01915
01916 const dimension_type not_a_dim = not_a_dimension();
01917
01918
01919 while (true) {
01920
01921
01922
01923 maybe_abandon();
01924
01925 PPL_ASSERT(OK());
01926
01927 const dimension_type num_rows = tableau.t.num_rows();
01928 const dimension_type num_vars = tableau.s.num_columns();
01929 const dimension_type num_params = tableau.t.num_columns();
01930 const Coefficient& tableau_den = tableau.denominator();
01931
01932 #ifdef VERY_NOISY_PIP
01933 tableau.ascii_dump(std::cerr);
01934 std::cerr << "context ";
01935 context.ascii_dump(std::cerr);
01936 #endif // #ifdef VERY_NOISY_PIP
01937
01938
01939
01940
01941 dimension_type first_negative = not_a_dim;
01942 dimension_type first_mixed = not_a_dim;
01943 for (dimension_type i = 0; i < num_rows; ++i) {
01944 Row_Sign& sign_i = sign[i];
01945 if (sign_i == UNKNOWN || sign_i == MIXED)
01946 sign_i = row_sign(tableau.t[i], big_dimension);
01947
01948 if (sign_i == NEGATIVE && first_negative == not_a_dim)
01949 first_negative = i;
01950 else if (sign_i == MIXED && first_mixed == not_a_dim)
01951 first_mixed = i;
01952 }
01953
01954
01955
01956 if (first_negative == not_a_dim && first_mixed != not_a_dim) {
01957 for (dimension_type i = first_mixed; i < num_rows; ++i) {
01958
01959 if (sign[i] != MIXED)
01960 continue;
01961 const Row& t_i = tableau.t[i];
01962 Row_Sign new_sign = ZERO;
01963
01964 if (compatibility_check(context, t_i))
01965 new_sign = POSITIVE;
01966
01967
01968 Row t_i_compl(num_params, Row::Flags());
01969 complement_assign(t_i_compl, t_i, tableau_den);
01970 if (compatibility_check(context, t_i_compl))
01971 new_sign = (new_sign == POSITIVE) ? MIXED : NEGATIVE;
01972
01973 sign[i] = new_sign;
01974
01975 if (new_sign == NEGATIVE && first_negative == not_a_dim) {
01976 first_negative = i;
01977 if (i == first_mixed)
01978 first_mixed = not_a_dim;
01979 }
01980 else if (new_sign == MIXED) {
01981 if (first_mixed == not_a_dim)
01982 first_mixed = i;
01983 }
01984 else if (i == first_mixed)
01985 first_mixed = not_a_dim;
01986 }
01987 }
01988
01989
01990
01991
01992
01993
01994 if (first_negative == not_a_dim && first_mixed != not_a_dim) {
01995 WEIGHT_BEGIN();
01996 for (dimension_type i = first_mixed; i < num_rows; ++i) {
01997
01998 if (sign[i] != MIXED)
01999 continue;
02000
02001 const Row& s_i = tableau.s[i];
02002 bool has_positive = false;
02003 for (dimension_type j = num_vars; j-- > 0; )
02004 if (s_i[j] > 0) {
02005 has_positive = true;
02006 break;
02007 }
02008 if (!has_positive)
02009 continue;
02010
02011 Row row(tableau.t[i]);
02012 PPL_DIRTY_TEMP_COEFFICIENT(mod);
02013 pos_mod_assign(mod, row[0], tableau_den);
02014 row[0] -= (mod == 0) ? tableau_den : mod;
02015 WEIGHT_ADD(2);
02016 const bool compatible = compatibility_check(context, row);
02017
02018 if (compatible) {
02019
02020 if (first_mixed == not_a_dim)
02021 first_mixed = i;
02022 }
02023 else {
02024
02025 sign[i] = NEGATIVE;
02026 if (first_negative == not_a_dim)
02027 first_negative = i;
02028 if (first_mixed == i)
02029 first_mixed = not_a_dim;
02030 }
02031 }
02032 }
02033
02034 #ifdef VERY_NOISY_PIP
02035 std::cerr << "sign =";
02036 for (dimension_type i = 0; i < sign.size(); ++i)
02037 std::cerr << " " << "?0+-*"[sign[i]];
02038 std::cerr << std::endl;
02039 #endif // #ifdef VERY_NOISY_PIP
02040
02041
02042
02043 if (first_negative != not_a_dim) {
02044
02045
02046 dimension_type pi = not_a_dim;
02047 dimension_type pj = not_a_dim;
02048 for (dimension_type i = first_negative; i < num_rows; ++i) {
02049 if (sign[i] != NEGATIVE)
02050 continue;
02051 dimension_type j;
02052 if (!find_lexico_minimum_column(tableau.s, mapping, basis,
02053 tableau.s[i], 0, j)) {
02054
02055 #ifdef NOISY_PIP_TREE_STRUCTURE
02056 indent_and_print(std::cerr, indent_level,
02057 "No positive pivot: Solution = _|_\n");
02058 #endif // #ifdef NOISY_PIP_TREE_STRUCTURE
02059 delete this;
02060 return 0;
02061 }
02062 if (pj == not_a_dim
02063 || tableau.is_better_pivot(mapping, basis, i, j, pi, pj)) {
02064
02065 pi = i;
02066 pj = j;
02067 if (pip.control_parameters[PIP_Problem::PIVOT_ROW_STRATEGY]
02068 == PIP_Problem::PIVOT_ROW_STRATEGY_FIRST)
02069
02070 break;
02071 }
02072 }
02073
02074 #ifdef VERY_NOISY_PIP
02075 std::cerr << "Pivot (pi, pj) = (" << pi << ", " << pj << ")\n";
02076 #endif // #ifdef VERY_NOISY_PIP
02077
02078
02079 tableau.normalize();
02080
02081
02082
02083
02084 {
02085 const dimension_type var_pi = var_row[pi];
02086 const dimension_type var_pj = var_column[pj];
02087 var_row[pi] = var_pj;
02088 var_column[pj] = var_pi;
02089 basis[var_pi] = true;
02090 basis[var_pj] = false;
02091 mapping[var_pi] = pj;
02092 mapping[var_pj] = pi;
02093 }
02094
02095 PPL_DIRTY_TEMP_COEFFICIENT(product);
02096 PPL_DIRTY_TEMP_COEFFICIENT(gcd);
02097 PPL_DIRTY_TEMP_COEFFICIENT(scale_factor);
02098
02099
02100
02101 tableau.s.add_zero_rows(1, Row::Flags());
02102 tableau.t.add_zero_rows(1, Row::Flags());
02103
02104 Row s_pivot(0, Row::Flags());
02105 Row t_pivot(0, Row::Flags());
02106 s_pivot.swap(tableau.s[num_rows]);
02107 t_pivot.swap(tableau.t[num_rows]);
02108
02109 tableau.s.erase_to_end(num_rows);
02110 tableau.t.erase_to_end(num_rows);
02111
02112
02113 PPL_DIRTY_TEMP_COEFFICIENT(pivot_den);
02114 pivot_den = tableau.denominator();
02115
02116 s_pivot[pj] = pivot_den;
02117
02118
02119 s_pivot.swap(tableau.s[pi]);
02120 t_pivot.swap(tableau.t[pi]);
02121 sign[pi] = ZERO;
02122
02123 PPL_DIRTY_TEMP_COEFFICIENT(s_pivot_pj);
02124 s_pivot_pj = s_pivot[pj];
02125
02126
02127
02128 for (dimension_type j = num_vars; j-- > 0; ) {
02129 if (j == pj)
02130 continue;
02131 const Coefficient& s_pivot_j = s_pivot[j];
02132
02133 if (s_pivot_j == 0)
02134 continue;
02135 WEIGHT_BEGIN();
02136 for (dimension_type i = num_rows; i-- > 0; ) {
02137 Row& s_i = tableau.s[i];
02138 product = s_pivot_j * s_i[pj];
02139 if (product % s_pivot_pj != 0) {
02140
02141 gcd_assign(gcd, product, s_pivot_pj);
02142 exact_div_assign(scale_factor, s_pivot_pj, gcd);
02143 tableau.scale(scale_factor);
02144 product *= scale_factor;
02145 WEIGHT_ADD(3);
02146 }
02147 PPL_ASSERT(product % s_pivot_pj == 0);
02148 exact_div_assign(product, product, s_pivot_pj);
02149 s_i[j] -= product;
02150 WEIGHT_ADD(4);
02151 }
02152 }
02153
02154
02155
02156 for (dimension_type j = num_params; j-- > 0; ) {
02157 const Coefficient& t_pivot_j = t_pivot[j];
02158
02159 if (t_pivot_j == 0)
02160 continue;
02161 WEIGHT_BEGIN();
02162 for (dimension_type i = num_rows; i-- > 0; ) {
02163 Row& s_i = tableau.s[i];
02164 product = t_pivot_j * s_i[pj];
02165 if (product % s_pivot_pj != 0) {
02166
02167 gcd_assign(gcd, product, s_pivot_pj);
02168 exact_div_assign(scale_factor, s_pivot_pj, gcd);
02169 tableau.scale(scale_factor);
02170 product *= scale_factor;
02171 WEIGHT_ADD(3);
02172 }
02173 PPL_ASSERT(product % s_pivot_pj == 0);
02174 exact_div_assign(product, product, s_pivot_pj);
02175 tableau.t[i][j] -= product;
02176 WEIGHT_ADD(4);
02177
02178
02179 Row_Sign& sign_i = sign[i];
02180 switch (sign_i) {
02181 case ZERO:
02182 if (product > 0)
02183 sign_i = NEGATIVE;
02184 else if (product < 0)
02185 sign_i = POSITIVE;
02186 break;
02187 case POSITIVE:
02188 if (product > 0)
02189 sign_i = MIXED;
02190 break;
02191 case NEGATIVE:
02192 if (product < 0)
02193 sign_i = MIXED;
02194 break;
02195 default:
02196 break;
02197 }
02198 }
02199 }
02200
02201
02202
02203 if (s_pivot_pj != pivot_den) {
02204 WEIGHT_BEGIN();
02205 for (dimension_type i = num_rows; i-- > 0; ) {
02206 Row& s_i = tableau.s[i];
02207 Coefficient& s_i_pj = s_i[pj];
02208 product = s_i_pj * pivot_den;
02209 if (product % s_pivot_pj != 0) {
02210
02211 gcd_assign(gcd, product, s_pivot_pj);
02212 exact_div_assign(scale_factor, s_pivot_pj, gcd);
02213 tableau.scale(scale_factor);
02214 product *= scale_factor;
02215 WEIGHT_ADD(3);
02216 }
02217 PPL_ASSERT(product % s_pivot_pj == 0);
02218 exact_div_assign(s_i_pj, product, s_pivot_pj);
02219 WEIGHT_ADD(3);
02220 }
02221 }
02222
02223
02224 continue;
02225 }
02226
02227
02228 PPL_ASSERT(first_negative == not_a_dim);
02229
02230
02231 if (first_mixed != not_a_dim) {
02232
02233
02234
02235
02236 dimension_type i_neg = not_a_dim;
02237 PPL_DIRTY_TEMP_COEFFICIENT(best_score);
02238 PPL_DIRTY_TEMP_COEFFICIENT(score);
02239 for (dimension_type i = first_mixed; i < num_rows; ++i) {
02240
02241 if (sign[i] != MIXED)
02242 continue;
02243
02244 bool has_positive = false;
02245 const Row& s_i = tableau.s[i];
02246 for (dimension_type j = 0; j < num_vars; ++j)
02247 if (s_i[j] > 0) {
02248 has_positive = true;
02249 break;
02250 }
02251 if (has_positive)
02252 continue;
02253
02254
02255 const Row& t_i = tableau.t[i];
02256 score = 0;
02257 WEIGHT_BEGIN();
02258 for (dimension_type j = num_params; j-- > 0; )
02259 score += t_i[j];
02260 WEIGHT_ADD_MUL(1, num_params);
02261 if (i_neg == not_a_dim || score < best_score) {
02262 i_neg = i;
02263 best_score = score;
02264 }
02265 }
02266
02267 if (i_neg != not_a_dim) {
02268 Row tautology = tableau.t[i_neg];
02269
02270 integral_simplification(tautology);
02271 context.add_row(tautology);
02272 add_constraint(tautology, all_params);
02273 sign[i_neg] = POSITIVE;
02274 #ifdef NOISY_PIP
02275 {
02276 Linear_Expression expr = Linear_Expression(tautology[0]);
02277 dimension_type j = 1;
02278 for (Variables_Set::const_iterator p = all_params.begin(),
02279 p_end = all_params.end(); p != p_end; ++p, ++j)
02280 add_mul_assign(expr, tautology[j], Variable(*p));
02281 using namespace IO_Operators;
02282 std::cerr << std::setw(2 * indent_level) << ""
02283 << "Row " << i_neg
02284 << ": mixed param sign, negative var coeffs\n";
02285 std::cerr << std::setw(2 * indent_level) << ""
02286 << "==> adding tautology: "
02287 << Constraint(expr >= 0) << ".\n";
02288 }
02289 #endif // #ifdef NOISY_PIP
02290
02291 continue;
02292 }
02293
02294 PPL_ASSERT(i_neg == not_a_dim);
02295
02296 dimension_type best_i = not_a_dim;
02297 for (dimension_type i = first_mixed; i < num_rows; ++i) {
02298 if (sign[i] != MIXED)
02299 continue;
02300 const Row& t_i = tableau.t[i];
02301 score = 0;
02302 WEIGHT_BEGIN();
02303 for (dimension_type j = num_params; j-- > 0; )
02304 score += t_i[j];
02305 WEIGHT_ADD_MUL(1, num_params);
02306 if (best_i == not_a_dim || score < best_score) {
02307 best_score = score;
02308 best_i = i;
02309 }
02310 }
02311
02312 Row t_test(tableau.t[best_i]);
02313
02314 integral_simplification(t_test);
02315 #ifdef NOISY_PIP
02316 {
02317 Linear_Expression expr = Linear_Expression(t_test[0]);
02318 dimension_type j = 1;
02319 for (Variables_Set::const_iterator p = all_params.begin(),
02320 p_end = all_params.end(); p != p_end; ++p, ++j)
02321 add_mul_assign(expr, t_test[j], Variable(*p));
02322 using namespace IO_Operators;
02323 std::cerr << std::setw(2 * indent_level) << ""
02324 << "Row " << best_i << ": mixed param sign\n";
02325 std::cerr << std::setw(2 * indent_level) << ""
02326 << "==> depends on sign of " << expr << ".\n";
02327 }
02328 #endif // #ifdef NOISY_PIP
02329
02330
02331 PIP_Tree_Node* t_node = new PIP_Solution_Node(*this, No_Constraints());
02332
02333 std::auto_ptr<PIP_Tree_Node> wrapped_node(t_node);
02334
02335
02336 context.add_row(t_test);
02337
02338 #ifdef NOISY_PIP_TREE_STRUCTURE
02339 indent_and_print(std::cerr, indent_level, "=== SOLVING THEN CHILD\n");
02340 #endif
02341 t_node = t_node->solve(pip, check_feasible_context,
02342 context, all_params, space_dim,
02343 indent_level + 1);
02344
02345 if (t_node != wrapped_node.get()) {
02346 wrapped_node.release();
02347 wrapped_node.reset(t_node);
02348 }
02349
02350
02351 PIP_Tree_Node* f_node = this;
02352
02353
02354 Constraint_System cs;
02355 Artificial_Parameter_Sequence aps;
02356 cs.swap(f_node->constraints_);
02357 aps.swap(f_node->artificial_parameters);
02358
02359 Row& f_test = context[context.num_rows()-1];
02360 complement_assign(f_test, t_test, 1);
02361
02362
02363 #ifdef NOISY_PIP_TREE_STRUCTURE
02364 indent_and_print(std::cerr, indent_level, "=== SOLVING ELSE CHILD\n");
02365 #endif
02366 f_node = f_node->solve(pip, check_feasible_context,
02367 context, all_params, space_dim,
02368 indent_level + 1);
02369
02370
02371 if (t_node == 0) {
02372 if (f_node == 0) {
02373
02374 #ifdef NOISY_PIP_TREE_STRUCTURE
02375 indent_and_print(std::cerr, indent_level,
02376 "=== EXIT: BOTH BRANCHES UNFEASIBLE: _|_\n");
02377 #endif
02378 return 0;
02379 }
02380 else {
02381
02382
02383 PPL_ASSERT(f_node == this);
02384 f_node->constraints_.swap(cs);
02385 f_node->artificial_parameters.swap(aps);
02386
02387 f_node->add_constraint(f_test, all_params);
02388 #ifdef NOISY_PIP_TREE_STRUCTURE
02389 indent_and_print(std::cerr, indent_level,
02390 "=== EXIT: THEN BRANCH UNFEASIBLE: SWAP BRANCHES\n");
02391 #endif
02392 return f_node;
02393 }
02394 }
02395 else if (f_node == 0) {
02396
02397 #ifdef NOISY_PIP_TREE_STRUCTURE
02398 indent_and_print(std::cerr, indent_level,
02399 "=== EXIT: THEN BRANCH FEASIBLE\n");
02400 #endif
02401
02402
02403
02404
02405
02406 PIP_Decision_Node* dn = dynamic_cast<PIP_Decision_Node*>(t_node);
02407 if (dn != 0 && dn->false_child != 0) {
02408
02409 PIP_Tree_Node* parent
02410 = new PIP_Decision_Node(t_node->get_owner(), 0, t_node);
02411
02412
02413 wrapped_node.release();
02414 wrapped_node.reset(parent);
02415
02416 parent->constraints_.swap(cs);
02417 parent->artificial_parameters.swap(aps);
02418
02419 parent->add_constraint(t_test, all_params);
02420
02421
02422 return wrapped_node.release();
02423 }
02424 else {
02425
02426
02427 for (Constraint_System::const_iterator
02428 i = t_node->constraints_.begin(),
02429 i_end = t_node->constraints_.end(); i != i_end; ++i)
02430 cs.insert(*i);
02431
02432 aps.insert(aps.end(),
02433 t_node->artificial_parameters.begin(),
02434 t_node->artificial_parameters.end());
02435
02436 cs.swap(t_node->constraints_);
02437 aps.swap(t_node->artificial_parameters);
02438
02439 t_node->add_constraint(t_test, all_params);
02440
02441
02442 return wrapped_node.release();
02443 }
02444 }
02445
02446
02447
02448 #ifdef NOISY_PIP_TREE_STRUCTURE
02449 indent_and_print(std::cerr, indent_level,
02450 "=== EXIT: BOTH BRANCHES FEASIBLE: NEW DECISION NODE\n");
02451 #endif
02452 PIP_Tree_Node* parent
02453 = new PIP_Decision_Node(f_node->get_owner(), f_node, t_node);
02454
02455
02456 wrapped_node.release();
02457 wrapped_node.reset(parent);
02458
02459
02460 parent->add_constraint(t_test, all_params);
02461
02462 if (!cs.empty()) {
02463 #ifdef NOISY_PIP_TREE_STRUCTURE
02464 indent_and_print(std::cerr, indent_level,
02465 "=== NODE HAS BOTH BRANCHES AND TAUTOLOGIES:\n");
02466 indent_and_print(std::cerr, indent_level,
02467 "=== CREATE NEW PARENT FOR TAUTOLOGIES\n");
02468 #endif
02469
02470
02471 parent = new PIP_Decision_Node(parent->get_owner(), 0, parent);
02472
02473
02474 wrapped_node.release();
02475 wrapped_node.reset(parent);
02476 parent->constraints_.swap(cs);
02477 }
02478 parent->artificial_parameters.swap(aps);
02479
02480
02481 return wrapped_node.release();
02482 }
02483
02484
02485 PPL_ASSERT(first_negative == not_a_dim);
02486 PPL_ASSERT(first_mixed == not_a_dim);
02487
02488
02489
02490
02491 #ifdef NOISY_PIP
02492 indent_and_print(std::cerr, indent_level,
02493 "All parameters are positive.\n");
02494 #endif // #ifdef NOISY_PIP
02495 tableau.normalize();
02496
02497
02498 const Coefficient& den = tableau.denominator();
02499 for (dimension_type k = 0; k < num_vars; ++k) {
02500 if (basis[k])
02501
02502 continue;
02503 const dimension_type i = mapping[k];
02504 const Row& t_i = tableau.t[i];
02505 WEIGHT_BEGIN();
02506 for (dimension_type j = num_params; j-- > 0; ) {
02507 WEIGHT_ADD(1);
02508 if (t_i[j] % den != 0)
02509 goto non_integer;
02510 }
02511 }
02512
02513 #ifdef NOISY_PIP_TREE_STRUCTURE
02514 indent_and_print(std::cerr, indent_level,
02515 "EXIT: solution found.\n");
02516 #endif // #ifdef NOISY_PIP
02517 return this;
02518
02519 non_integer:
02520
02521 PPL_DIRTY_TEMP_COEFFICIENT(mod);
02522 dimension_type best_i = not_a_dim;
02523 dimension_type best_pcount = not_a_dim;
02524
02525 const PIP_Problem::Control_Parameter_Value cutting_strategy
02526 = pip.control_parameters[PIP_Problem::CUTTING_STRATEGY];
02527
02528 if (cutting_strategy == PIP_Problem::CUTTING_STRATEGY_FIRST) {
02529
02530 for (dimension_type k = 0; k < num_vars; ++k) {
02531 if (basis[k])
02532 continue;
02533 const dimension_type i = mapping[k];
02534 const Row& t_i = tableau.t[i];
02535
02536 WEIGHT_BEGIN();
02537 dimension_type pcount = 0;
02538 for (dimension_type j = num_params; j-- > 0; ) {
02539 pos_mod_assign(mod, t_i[j], den);
02540 if (mod != 0)
02541 ++pcount;
02542 }
02543 WEIGHT_ADD_MUL(1, num_params);
02544 if (pcount > 0 && (best_i == not_a_dim || pcount < best_pcount)) {
02545 best_pcount = pcount;
02546 best_i = i;
02547 }
02548 }
02549
02550 generate_cut(best_i, all_params, context, space_dim, indent_level);
02551 }
02552 else {
02553 PPL_ASSERT(cutting_strategy == PIP_Problem::CUTTING_STRATEGY_DEEPEST
02554 || cutting_strategy == PIP_Problem::CUTTING_STRATEGY_ALL);
02555
02556
02557 PPL_DIRTY_TEMP_COEFFICIENT(best_score);
02558 best_score = 0;
02559 PPL_DIRTY_TEMP_COEFFICIENT(score);
02560 PPL_DIRTY_TEMP_COEFFICIENT(s_score);
02561 std::vector<dimension_type> all_best_is;
02562
02563 for (dimension_type k = 0; k < num_vars; ++k) {
02564 if (basis[k])
02565 continue;
02566 const dimension_type i = mapping[k];
02567
02568 WEIGHT_BEGIN();
02569 score = 0;
02570 dimension_type pcount = 0;
02571 const Row& t_i = tableau.t[i];
02572 for (dimension_type j = num_params; j-- > 0; ) {
02573 pos_mod_assign(mod, t_i[j], den);
02574 if (mod != 0) {
02575 score += den;
02576 score -= mod;
02577 ++pcount;
02578 }
02579 }
02580 WEIGHT_ADD_MUL(3, num_params);
02581
02582
02583 WEIGHT_BEGIN();
02584 s_score = 0;
02585 const Row& s_i = tableau.s[i];
02586 for (dimension_type j = num_vars; j-- > 0; ) {
02587 pos_mod_assign(mod, s_i[j], den);
02588 s_score += den;
02589 s_score -= mod;
02590 }
02591 WEIGHT_ADD_MUL(3, num_vars);
02592
02593 score *= s_score;
02594
02595
02596
02597
02598
02599
02600
02601 if (pcount != 0
02602 && (best_i == not_a_dim
02603 || pcount < best_pcount
02604 || (pcount == best_pcount && score > best_score))) {
02605 if (pcount < best_pcount)
02606 all_best_is.clear();
02607 best_i = i;
02608 best_pcount = pcount;
02609 best_score = score;
02610 }
02611 if (pcount > 0)
02612 all_best_is.push_back(i);
02613 }
02614 if (cutting_strategy == PIP_Problem::CUTTING_STRATEGY_DEEPEST)
02615 generate_cut(best_i, all_params, context, space_dim, indent_level);
02616 else {
02617 PPL_ASSERT(cutting_strategy == PIP_Problem::CUTTING_STRATEGY_ALL);
02618 for (dimension_type k = all_best_is.size(); k-- > 0; )
02619 generate_cut(all_best_is[k], all_params, context,
02620 space_dim, indent_level);
02621 }
02622 }
02623
02624 }
02625
02626
02627 throw std::runtime_error("PPL internal error");
02628 }
02629
02630 void
02631 PIP_Solution_Node::generate_cut(const dimension_type index,
02632 Variables_Set& parameters,
02633 Matrix& context,
02634 dimension_type& space_dimension,
02635 const unsigned indent_level) {
02636 #ifdef NOISY_PIP
02637 std::cerr << std::setw(2 * indent_level) << ""
02638 << "Row " << index << " requires cut generation.\n";
02639 #else
02640 used(indent_level);
02641 #endif // #ifdef NOISY_PIP
02642
02643 const dimension_type num_rows = tableau.t.num_rows();
02644 PPL_ASSERT(index < num_rows);
02645 const dimension_type num_vars = tableau.s.num_columns();
02646 const dimension_type num_params = tableau.t.num_columns();
02647 PPL_ASSERT(num_params == 1 + parameters.size());
02648 const Coefficient& den = tableau.denominator();
02649
02650 PPL_DIRTY_TEMP_COEFFICIENT(mod);
02651 PPL_DIRTY_TEMP_COEFFICIENT(coeff);
02652
02653
02654 bool generate_parametric_cut = false;
02655 {
02656
02657 const Row& row_t = tableau.t[index];
02658 WEIGHT_BEGIN();
02659 for (dimension_type j = 1; j < num_params; ++j) {
02660 WEIGHT_ADD(1);
02661 if (row_t[j] % den != 0) {
02662 generate_parametric_cut = true;
02663 break;
02664 }
02665 }
02666 }
02667
02668
02669 dimension_type ap_column = not_a_dimension();
02670 bool reuse_ap = false;
02671
02672 if (generate_parametric_cut) {
02673
02674 Linear_Expression expr;
02675
02676
02677 {
02678 const Row& row_t = tableau.t[index];
02679 pos_mod_assign(mod, row_t[0], den);
02680 if (mod != 0) {
02681
02682 expr += den;
02683 expr -= mod;
02684 }
02685
02686 Variables_Set::const_reverse_iterator p_j = parameters.rbegin();
02687
02688 WEIGHT_BEGIN();
02689 for (dimension_type j = num_params; j-- > 1; ) {
02690 pos_mod_assign(mod, row_t[j], den);
02691 if (mod != 0) {
02692
02693 coeff = den - mod;
02694 add_mul_assign(expr, coeff, Variable(*p_j));
02695 }
02696
02697 ++p_j;
02698 }
02699 WEIGHT_ADD_MUL(2, num_params);
02700 }
02701
02702 Artificial_Parameter ap(expr, den);
02703
02704
02705 ap_column = space_dimension;
02706 const PIP_Tree_Node* node = this;
02707 do {
02708 for (dimension_type j = node->artificial_parameters.size(); j-- > 0; ) {
02709 --ap_column;
02710 if (node->artificial_parameters[j] == ap) {
02711 reuse_ap = true;
02712 break;
02713 }
02714 }
02715 node = node->parent();
02716 } while (!reuse_ap && node != 0);
02717
02718 if (reuse_ap) {
02719
02720 #ifdef NOISY_PIP
02721 using namespace IO_Operators;
02722 std::cerr << std::setw(2 * indent_level) << ""
02723 << "Re-using parameter " << Variable(ap_column)
02724 << " = " << ap << std::endl;
02725 #endif // #ifdef NOISY_PIP
02726 ap_column = ap_column - num_vars + 1;
02727 }
02728 else {
02729
02730
02731 tableau.t.add_zero_columns(1);
02732 context.add_zero_columns(1);
02733 artificial_parameters.push_back(ap);
02734 parameters.insert(space_dimension);
02735 #ifdef NOISY_PIP
02736 using namespace IO_Operators;
02737 std::cerr << std::setw(2 * indent_level) << ""
02738 << "New parameter " << Variable(space_dimension)
02739 << " = " << ap << std::endl;
02740 #endif // #ifdef NOISY_PIP
02741 ++space_dimension;
02742 ap_column = num_params;
02743
02744
02745 const dimension_type ctx_num_rows = context.num_rows();
02746 context.add_zero_rows(2, Row::Flags());
02747 Row& ctx1 = context[ctx_num_rows];
02748 Row& ctx2 = context[ctx_num_rows+1];
02749
02750 WEIGHT_BEGIN();
02751 const Row& row_t = tableau.t[index];
02752 for (dimension_type j = 0; j < num_params; ++j) {
02753 pos_mod_assign(mod, row_t[j], den);
02754 if (mod != 0) {
02755 ctx1[j] = den;
02756 ctx1[j] -= mod;
02757 neg_assign(ctx2[j], ctx1[j]);
02758 WEIGHT_ADD(3);
02759 }
02760 }
02761 WEIGHT_ADD_MUL(1, num_params);
02762 neg_assign(ctx1[num_params], den);
02763 ctx2[num_params] = den;
02764
02765 ctx2[0] += den;
02766 --ctx2[0];
02767 WEIGHT_ADD(4);
02768 #ifdef NOISY_PIP
02769 {
02770 using namespace IO_Operators;
02771 Variables_Set::const_iterator p = parameters.begin();
02772 Linear_Expression expr1(ctx1[0]);
02773 Linear_Expression expr2(ctx2[0]);
02774 for (dimension_type j = 1; j <= num_params; ++j, ++p) {
02775 add_mul_assign(expr1, ctx1[j], Variable(*p));
02776 add_mul_assign(expr2, ctx2[j], Variable(*p));
02777 }
02778 std::cerr << std::setw(2 * indent_level) << ""
02779 << "Adding to context: "
02780 << Constraint(expr1 >= 0) << " ; "
02781 << Constraint(expr2 >= 0) << std::endl;
02782 }
02783 #endif // #ifdef NOISY_PIP
02784 }
02785 }
02786
02787
02788 tableau.s.add_zero_rows(1, Row::Flags());
02789 tableau.t.add_zero_rows(1, Row::Flags());
02790 Row& cut_s = tableau.s[num_rows];
02791 Row& cut_t = tableau.t[num_rows];
02792
02793 WEIGHT_BEGIN();
02794 const Row& row_s = tableau.s[index];
02795 const Row& row_t = tableau.t[index];
02796 for (dimension_type j = 0; j < num_vars; ++j) {
02797 pos_mod_assign(cut_s[j], row_s[j], den);
02798 }
02799 WEIGHT_ADD_MUL(1, num_params);
02800 for (dimension_type j = 0; j < num_params; ++j) {
02801 pos_mod_assign(mod, row_t[j], den);
02802 if (mod != 0) {
02803 cut_t[j] = mod;
02804 cut_t[j] -= den;
02805 WEIGHT_ADD(2);
02806 }
02807 }
02808 WEIGHT_ADD_MUL(1, num_params);
02809 if (ap_column != not_a_dimension())
02810
02811 cut_t[ap_column] = den;
02812
02813 #ifdef NOISY_PIP
02814 {
02815 using namespace IO_Operators;
02816 Linear_Expression expr;
02817 dimension_type ti = 1;
02818 dimension_type si = 0;
02819 for (dimension_type j = 0; j < space_dimension; ++j) {
02820 if (parameters.count(j) == 1)
02821 add_mul_assign(expr, cut_t[ti++], Variable(j));
02822 else
02823 add_mul_assign(expr, cut_s[si++], Variable(j));
02824 }
02825 std::cerr << std::setw(2 * indent_level) << ""
02826 << "Adding cut: "
02827 << Constraint(expr + cut_t[0] >= 0)
02828 << std::endl;
02829 }
02830 #endif // #ifdef NOISY_PIP
02831 var_row.push_back(num_rows + num_vars);
02832 basis.push_back(false);
02833 mapping.push_back(num_rows);
02834 sign.push_back(NEGATIVE);
02835 }
02836
02837
02838 memory_size_type
02839 PIP_Tree_Node::Artificial_Parameter::external_memory_in_bytes() const {
02840 return Linear_Expression::external_memory_in_bytes()
02841 + Parma_Polyhedra_Library::external_memory_in_bytes(denom);
02842 }
02843
02844 memory_size_type
02845 PIP_Tree_Node::Artificial_Parameter::total_memory_in_bytes() const {
02846 return sizeof(*this) + external_memory_in_bytes();
02847 }
02848
02849 memory_size_type
02850 PIP_Tree_Node::external_memory_in_bytes() const {
02851 memory_size_type n = constraints_.external_memory_in_bytes();
02852
02853 n += artificial_parameters.capacity() * sizeof(Artificial_Parameter);
02854 for (Artificial_Parameter_Sequence::const_iterator
02855 ap = art_parameter_begin(),
02856 ap_end = art_parameter_end(); ap != ap_end; ++ap)
02857 n += (ap->external_memory_in_bytes());
02858
02859 return n;
02860 }
02861
02862 memory_size_type
02863 PIP_Decision_Node::external_memory_in_bytes() const {
02864 memory_size_type n = PIP_Tree_Node::external_memory_in_bytes();
02865 PPL_ASSERT(true_child != 0);
02866 n += true_child->total_memory_in_bytes();
02867 if (false_child)
02868 n += false_child->total_memory_in_bytes();
02869 return n;
02870 }
02871
02872 memory_size_type
02873 PIP_Decision_Node::total_memory_in_bytes() const {
02874 return sizeof(*this) + external_memory_in_bytes();
02875 }
02876
02877 memory_size_type
02878 PIP_Solution_Node::Tableau::external_memory_in_bytes() const {
02879 return Parma_Polyhedra_Library::external_memory_in_bytes(denom)
02880 + s.external_memory_in_bytes()
02881 + t.external_memory_in_bytes();
02882 }
02883
02884 memory_size_type
02885 PIP_Solution_Node::external_memory_in_bytes() const {
02886 memory_size_type n = PIP_Tree_Node::external_memory_in_bytes();
02887 n += tableau.external_memory_in_bytes();
02888
02889 n += basis.capacity() * sizeof(bool);
02890 n += sizeof(dimension_type)
02891 * (mapping.capacity() + var_row.capacity() + var_column.capacity());
02892 n += sign.capacity() * sizeof(Row_Sign);
02893
02894 n += solution.capacity() * sizeof(Linear_Expression);
02895 for (std::vector<Linear_Expression>::const_iterator
02896 i = solution.begin(), i_end = solution.end(); i != i_end; ++i)
02897 n += (i->external_memory_in_bytes());
02898
02899 return n;
02900 }
02901
02902 memory_size_type
02903 PIP_Solution_Node::total_memory_in_bytes() const {
02904 return sizeof(*this) + external_memory_in_bytes();
02905 }
02906
02907 void
02908 PIP_Tree_Node::indent_and_print(std::ostream& s,
02909 const unsigned indent,
02910 const char* str) {
02911 s << std::setw(2*indent) << "" << str;
02912 }
02913
02914 void
02915 PIP_Tree_Node::print(std::ostream& s, unsigned indent) const {
02916 const dimension_type pip_space_dim = get_owner()->space_dimension();
02917 const Variables_Set& pip_params = get_owner()->parameter_space_dimensions();
02918
02919 std::vector<bool> pip_dim_is_param(pip_space_dim);
02920 for (Variables_Set::const_iterator p = pip_params.begin(),
02921 p_end = pip_params.end(); p != p_end; ++p)
02922 pip_dim_is_param[*p] = true;
02923
02924 dimension_type first_art_dim = pip_space_dim;
02925 for (const PIP_Tree_Node* node = parent(); node != 0; node = node->parent())
02926 first_art_dim += node->art_parameter_count();
02927
02928 print_tree(s, indent, pip_dim_is_param, first_art_dim);
02929 }
02930
02931 void
02932 PIP_Tree_Node::print_tree(std::ostream& s, unsigned indent,
02933 const std::vector<bool>& pip_dim_is_param,
02934 dimension_type first_art_dim) const {
02935 used(pip_dim_is_param);
02936
02937 using namespace IO_Operators;
02938
02939
02940 for (Artificial_Parameter_Sequence::const_iterator
02941 api = art_parameter_begin(),
02942 api_end = art_parameter_end(); api != api_end; ++api) {
02943 indent_and_print(s, indent, "Parameter ");
02944 s << Variable(first_art_dim) << " = " << *api << "\n";
02945 ++first_art_dim;
02946 }
02947
02948
02949 if (!constraints_.empty()) {
02950 indent_and_print(s, indent, "if ");
02951
02952 Constraint_System::const_iterator ci = constraints_.begin();
02953 Constraint_System::const_iterator ci_end = constraints_.end();
02954 PPL_ASSERT(ci != ci_end);
02955 s << *ci;
02956 for (++ci; ci != ci_end; ++ci)
02957 s << " and " << *ci;
02958
02959 s << " then\n";
02960 }
02961 }
02962
02963 void
02964 PIP_Decision_Node::print_tree(std::ostream& s, unsigned indent,
02965 const std::vector<bool>& pip_dim_is_param,
02966 const dimension_type first_art_dim) const {
02967
02968 PIP_Tree_Node::print_tree(s, indent, pip_dim_is_param, first_art_dim);
02969
02970
02971 dimension_type child_first_art_dim = first_art_dim + art_parameter_count();
02972
02973 PPL_ASSERT(true_child != 0);
02974 true_child->print_tree(s, indent+1, pip_dim_is_param, child_first_art_dim);
02975
02976 indent_and_print(s, indent, "else\n");
02977
02978 if (false_child)
02979 false_child->print_tree(s, indent+1, pip_dim_is_param, child_first_art_dim);
02980 else
02981 indent_and_print(s, indent+1, "_|_\n");
02982 }
02983
02984 void
02985 PIP_Solution_Node::print_tree(std::ostream& s, unsigned indent,
02986 const std::vector<bool>& pip_dim_is_param,
02987 const dimension_type first_art_dim) const {
02988
02989 PIP_Tree_Node::print_tree(s, indent, pip_dim_is_param, first_art_dim);
02990
02991
02992
02993 update_solution(pip_dim_is_param);
02994
02995 const bool no_constraints = constraints_.empty();
02996 indent_and_print(s, indent + (no_constraints ? 0 : 1), "{");
02997 const dimension_type pip_space_dim = pip_dim_is_param.size();
02998 for (dimension_type i = 0, num_var = 0; i < pip_space_dim; ++i) {
02999 if (pip_dim_is_param[i])
03000 continue;
03001 if (num_var > 0)
03002 s << " ; ";
03003 using namespace IO_Operators;
03004 s << solution[num_var];
03005 ++num_var;
03006 }
03007 s << "}\n";
03008
03009 if (!no_constraints) {
03010 indent_and_print(s, indent, "else\n");
03011 indent_and_print(s, indent+1, "_|_\n");
03012 }
03013 }
03014
03015 const Linear_Expression&
03016 PIP_Solution_Node::parametric_values(const Variable var) const {
03017 const PIP_Problem* pip = get_owner();
03018 PPL_ASSERT(pip);
03019
03020 const dimension_type space_dim = pip->space_dimension();
03021 if (var.space_dimension() > space_dim) {
03022 std::ostringstream s;
03023 s << "PPL::PIP_Solution_Node::parametric_values(v):\n"
03024 << "v.space_dimension() == " << var.space_dimension()
03025 << " is incompatible with the owning PIP_Problem "
03026 << " (space dim == " << space_dim << ").";
03027 throw std::invalid_argument(s.str());
03028 }
03029
03030 dimension_type solution_index = var.id();
03031 const Variables_Set& params = pip->parameter_space_dimensions();
03032 for (Variables_Set::const_iterator p = params.begin(),
03033 p_end = params.end(); p != p_end; ++p) {
03034 const dimension_type param_index = *p;
03035 if (param_index < var.id())
03036 --solution_index;
03037 else if (param_index == var.id())
03038 throw std::invalid_argument("PPL::PIP_Solution_Node"
03039 "::parametric_values(v):\n"
03040 "v is a problem parameter.");
03041 else
03042 break;
03043 }
03044
03045 update_solution();
03046 return solution[solution_index];
03047 }
03048
03049
03050 void
03051 PIP_Solution_Node::update_solution() const {
03052
03053 if (solution_valid)
03054 return;
03055
03056 const PIP_Problem* pip = get_owner();
03057 PPL_ASSERT(pip);
03058 std::vector<bool> pip_dim_is_param(pip->space_dimension());
03059 const Variables_Set& params = pip->parameter_space_dimensions();
03060 for (Variables_Set::const_iterator p = params.begin(),
03061 p_end = params.end(); p != p_end; ++p)
03062 pip_dim_is_param[*p] = true;
03063
03064 update_solution(pip_dim_is_param);
03065 }
03066
03067 void
03068 PIP_Solution_Node
03069 ::update_solution(const std::vector<bool>& pip_dim_is_param) const {
03070
03071 if (solution_valid)
03072 return;
03073
03074
03075 PIP_Solution_Node& x = const_cast<PIP_Solution_Node&>(*this);
03076
03077 const dimension_type num_pip_dims = pip_dim_is_param.size();
03078 const dimension_type num_pip_vars = tableau.s.num_columns();
03079 const dimension_type num_pip_params = num_pip_dims - num_pip_vars;
03080 const dimension_type num_all_params = tableau.t.num_columns() - 1;
03081 const dimension_type num_art_params = num_all_params - num_pip_params;
03082
03083 if (solution.size() != num_pip_vars)
03084 x.solution.resize(num_pip_vars);
03085
03086
03087 std::vector<dimension_type> all_param_names(num_all_params);
03088
03089
03090 for (dimension_type i = 0, p_index = 0; i < num_pip_dims; ++i)
03091 if (pip_dim_is_param[i]) {
03092 all_param_names[p_index] = i;
03093 ++p_index;
03094 }
03095
03096 for (dimension_type i = 0; i < num_art_params; ++i)
03097 all_param_names[num_pip_params + i] = num_pip_dims + i;
03098
03099
03100 PPL_DIRTY_TEMP_COEFFICIENT(norm_coeff);
03101 const Coefficient& den = tableau.denominator();
03102 for (dimension_type i = num_pip_vars; i-- > 0; ) {
03103 Linear_Expression& sol_i = x.solution[i];
03104 sol_i = Linear_Expression(0);
03105 if (basis[i])
03106 continue;
03107 const Row& row = tableau.t[mapping[i]];
03108
03109 for (dimension_type j = num_all_params; j-- > 0; ) {
03110
03111 const Coefficient& coeff = row[j+1];
03112 if (coeff == 0)
03113 continue;
03114 norm_coeff = coeff / den;
03115 if (norm_coeff != 0)
03116 add_mul_assign(sol_i, norm_coeff, Variable(all_param_names[j]));
03117 }
03118 norm_coeff = row[0] / den;
03119 sol_i += norm_coeff;
03120 }
03121
03122
03123 x.solution_valid = true;
03124 }
03125
03126 }