A tree node representing part of the space of solutions. More...
#include <PIP_Tree.defs.hh>


Classes | |
| struct | No_Constraints |
| A tag type to select the alternative copy constructor. More... | |
| struct | Tableau |
| The type for parametric simplex tableau. More... | |
Public Member Functions | |
| PIP_Solution_Node (const PIP_Problem *owner) | |
Constructor: builds a solution node owned by *owner. | |
| virtual PIP_Tree_Node * | clone () const |
Returns a pointer to a dynamically-allocated copy of *this. | |
| virtual | ~PIP_Solution_Node () |
| Destructor. | |
| virtual bool | OK () const |
Returns true if and only if *this is well formed. | |
| virtual const PIP_Solution_Node * | as_solution () const |
Returns this. | |
| const Linear_Expression & | parametric_values (Variable var) const |
Returns a parametric expression for the values of problem variable var. | |
| void | ascii_dump (std::ostream &s) const |
Dumps to s an ASCII representation of *this. | |
| bool | ascii_load (std::istream &s) |
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this accordingly. Returns true if successful, false otherwise. | |
| virtual memory_size_type | total_memory_in_bytes () const |
Returns the total size in bytes of the memory occupied by *this. | |
| virtual memory_size_type | external_memory_in_bytes () const |
Returns the size in bytes of the memory managed by *this. | |
Protected Member Functions | |
| PIP_Solution_Node (const PIP_Solution_Node &y) | |
| Copy constructor. | |
| PIP_Solution_Node (const PIP_Solution_Node &y, No_Constraints) | |
| Alternative copy constructor. | |
| virtual void | set_owner (const PIP_Problem *owner) |
| Sets the pointer to the PIP_Problem owning object. | |
| virtual bool | check_ownership (const PIP_Problem *owner) const |
Returns true if and only if all the nodes in the subtree rooted in *this is owned by *pip. | |
| virtual void | update_tableau (const PIP_Problem &pip, dimension_type external_space_dim, dimension_type first_pending_constraint, const Constraint_Sequence &input_cs, const Variables_Set ¶meters) |
| Implements pure virtual method PIP_Tree_Node::update_tableau. | |
| void | update_solution (const std::vector< bool > &pip_dim_is_param) const |
| Update the solution values. | |
| void | update_solution () const |
| Helper method. | |
| virtual PIP_Tree_Node * | solve (const PIP_Problem &pip, bool check_feasible_context, const Matrix &context, const Variables_Set ¶ms, dimension_type space_dim, unsigned indent_level) |
| Implements pure virtual method PIP_Tree_Node::solve. | |
| void | generate_cut (dimension_type i, Variables_Set ¶meters, Matrix &context, dimension_type &space_dimension, unsigned indent_level) |
Generate a Gomory cut using non-integer tableau row i. | |
| virtual void | print_tree (std::ostream &s, unsigned indent, const std::vector< bool > &pip_dim_is_param, dimension_type first_art_dim) const |
Prints on s the tree rooted in *this. | |
Private Types | |
| enum | Row_Sign { UNKNOWN, ZERO, POSITIVE, NEGATIVE, MIXED } |
The possible values for the sign of a parametric linear expression. More... | |
Static Private Member Functions | |
| static Row_Sign | row_sign (const Row &x, dimension_type big_dimension) |
Returns the sign of row x. | |
Private Attributes | |
| Tableau | tableau |
| The parametric simplex tableau. | |
| std::vector< bool > | basis |
| A boolean vector for identifying the basic variables. | |
| std::vector< dimension_type > | mapping |
| A mapping between the tableau rows/columns and the original variables. | |
| std::vector< dimension_type > | var_row |
| The variable identifiers associated to the rows of the simplex tableau. | |
| std::vector< dimension_type > | var_column |
| The variable identifiers associated to the columns of the simplex tableau. | |
| dimension_type | special_equality_row |
| The variable number of the special inequality used for modelling equality constraints. | |
| dimension_type | big_dimension |
The column index in the parametric part of the simplex tableau corresponding to the big parameter; not_a_dimension() if not set. | |
| std::vector< Row_Sign > | sign |
| A cache for computed sign values of constraint parametric RHS. | |
| std::vector< Linear_Expression > | solution |
| Parametric values for the solution. | |
| bool | solution_valid |
| An indicator for solution validity. | |
Friends | |
| bool | PIP_Problem::ascii_load (std::istream &s) |
A tree node representing part of the space of solutions.
Definition at line 344 of file PIP_Tree.defs.hh.
enum Parma_Polyhedra_Library::PIP_Solution_Node::Row_Sign [private] |
The possible values for the sign of a parametric linear expression.
Definition at line 573 of file PIP_Tree.defs.hh.
| Parma_Polyhedra_Library::PIP_Solution_Node::PIP_Solution_Node | ( | const PIP_Problem * | owner | ) | [explicit] |
Constructor: builds a solution node owned by *owner.
Definition at line 481 of file PIP_Tree.cc.
Referenced by clone(), and solve().
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 }
| Parma_Polyhedra_Library::PIP_Solution_Node::~PIP_Solution_Node | ( | ) | [virtual] |
| Parma_Polyhedra_Library::PIP_Solution_Node::PIP_Solution_Node | ( | const PIP_Solution_Node & | y | ) | [protected] |
Copy constructor.
Definition at line 495 of file PIP_Tree.cc.
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 }
| Parma_Polyhedra_Library::PIP_Solution_Node::PIP_Solution_Node | ( | const PIP_Solution_Node & | y, | |
| No_Constraints | ||||
| ) | [protected] |
Alternative copy constructor.
This constructor differs from the default copy constructor in that it will not copy the constraint system, nor the artificial parameters.
Definition at line 509 of file PIP_Tree.cc.
00511 : PIP_Tree_Node(y.owner_), // NOTE: only copy 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 }
| const PIP_Solution_Node * Parma_Polyhedra_Library::PIP_Solution_Node::as_solution | ( | ) | const [virtual] |
Returns this.
Reimplemented from Parma_Polyhedra_Library::PIP_Tree_Node.
Definition at line 599 of file PIP_Tree.cc.
| void Parma_Polyhedra_Library::PIP_Solution_Node::ascii_dump | ( | std::ostream & | s | ) | const |
Dumps to s an ASCII representation of *this.
Reimplemented from Parma_Polyhedra_Library::PIP_Tree_Node.
Definition at line 1262 of file PIP_Tree.cc.
References big_dimension, MIXED, NEGATIVE, POSITIVE, sign, solution, solution_valid, special_equality_row, UNKNOWN, var_column, var_row, and ZERO.
Referenced by Parma_Polyhedra_Library::PIP_Decision_Node::ascii_dump(), and Parma_Polyhedra_Library::PIP_Problem::ascii_dump().
01262 { 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 }
| bool Parma_Polyhedra_Library::PIP_Solution_Node::ascii_load | ( | std::istream & | s | ) |
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this accordingly. Returns true if successful, false otherwise.
Reimplemented from Parma_Polyhedra_Library::PIP_Tree_Node.
Definition at line 1331 of file PIP_Tree.cc.
References Parma_Polyhedra_Library::Linear_Expression::ascii_load(), Parma_Polyhedra_Library::PIP_Tree_Node::ascii_load(), big_dimension, MIXED, NEGATIVE, OK(), POSITIVE, sign, solution, solution_valid, special_equality_row, UNKNOWN, var_column, var_row, and ZERO.
Referenced by Parma_Polyhedra_Library::PIP_Decision_Node::ascii_load(), and Parma_Polyhedra_Library::PIP_Problem::ascii_load().
01331 { 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 }
| bool Parma_Polyhedra_Library::PIP_Solution_Node::check_ownership | ( | const PIP_Problem * | owner | ) | const [protected, virtual] |
Returns true if and only if all the nodes in the subtree rooted in *this is owned by *pip.
Implements Parma_Polyhedra_Library::PIP_Tree_Node.
Definition at line 577 of file PIP_Tree.cc.
References Parma_Polyhedra_Library::PIP_Tree_Node::get_owner().
00577 { 00578 return get_owner() == owner; 00579 }
| PIP_Tree_Node * Parma_Polyhedra_Library::PIP_Solution_Node::clone | ( | ) | const [virtual] |
Returns a pointer to a dynamically-allocated copy of *this.
Implements Parma_Polyhedra_Library::PIP_Tree_Node.
Definition at line 1222 of file PIP_Tree.cc.
References PIP_Solution_Node().
01222 { 01223 return new PIP_Solution_Node(*this); 01224 }
| memory_size_type Parma_Polyhedra_Library::PIP_Solution_Node::external_memory_in_bytes | ( | ) | const [virtual] |
Returns the size in bytes of the memory managed by *this.
Implements Parma_Polyhedra_Library::PIP_Tree_Node.
Definition at line 2885 of file PIP_Tree.cc.
References Parma_Polyhedra_Library::Checked::bool, sign, solution, var_column, and var_row.
Referenced by total_memory_in_bytes().
02885 { 02886 memory_size_type n = PIP_Tree_Node::external_memory_in_bytes(); 02887 n += tableau.external_memory_in_bytes(); 02888 // FIXME: size of std::vector<bool> ? 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 // FIXME: Adding the external memory for `solution'. 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 }
| void Parma_Polyhedra_Library::PIP_Solution_Node::generate_cut | ( | dimension_type | i, | |
| Variables_Set & | parameters, | |||
| Matrix & | context, | |||
| dimension_type & | space_dimension, | |||
| unsigned | indent_level | |||
| ) | [protected] |
Generate a Gomory cut using non-integer tableau row i.
| i | Row index in simplex tableau from which the cut is generated | |
| parameters | A std::set of the current parameter dimensions (including artificials); to be updated if a new artificial parameter is to be created | |
| context | A set of linear inequalities on the parameters, in matrix form; to be updated if a new artificial parameter is to be created | |
| space_dimension | The current space dimension, including variables and all parameters; to be updated if an extra parameter is to be created | |
| indent_level | The indentation level (for debugging output only). |
Definition at line 2631 of file PIP_Tree.cc.
References Parma_Polyhedra_Library::add_mul_assign(), Parma_Polyhedra_Library::Matrix::add_zero_columns(), Parma_Polyhedra_Library::Matrix::add_zero_rows(), Parma_Polyhedra_Library::PIP_Tree_Node::artificial_parameters, Parma_Polyhedra_Library::Variables_Set::insert(), Parma_Polyhedra_Library::neg_assign(), NEGATIVE, Parma_Polyhedra_Library::not_a_dimension(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::PIP_Tree_Node::parent(), PPL_DIRTY_TEMP_COEFFICIENT, sign, var_row, WEIGHT_ADD, WEIGHT_ADD_MUL, and WEIGHT_BEGIN.
Referenced by solve().
02635 { 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 // Test if cut to be generated must be parametric or not. 02654 bool generate_parametric_cut = false; 02655 { 02656 // Limiting the scope of reference row_t (may be later invalidated). 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 // Column index of already existing Artificial_Parameter. 02669 dimension_type ap_column = not_a_dimension(); 02670 bool reuse_ap = false; 02671 02672 if (generate_parametric_cut) { 02673 // Fractional parameter coefficient found: generate parametric cut. 02674 Linear_Expression expr; 02675 02676 // Limiting the scope of reference row_t (may be later invalidated). 02677 { 02678 const Row& row_t = tableau.t[index]; 02679 pos_mod_assign(mod, row_t[0], den); 02680 if (mod != 0) { 02681 // Optimizing computation: expr += (den - mod); 02682 expr += den; 02683 expr -= mod; 02684 } 02685 // NOTE: iterating downwards on parameters to avoid reallocations. 02686 Variables_Set::const_reverse_iterator p_j = parameters.rbegin(); 02687 // NOTE: index j spans [1..num_params-1] downwards. 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 // Optimizing computation: expr += (den - mod) * Variable(*p_j); 02693 coeff = den - mod; 02694 add_mul_assign(expr, coeff, Variable(*p_j)); 02695 } 02696 // Mode to previous parameter. 02697 ++p_j; 02698 } 02699 WEIGHT_ADD_MUL(2, num_params); 02700 } 02701 // Generate new artificial parameter. 02702 Artificial_Parameter ap(expr, den); 02703 02704 // Search if the Artificial_Parameter has already been generated. 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 // We can re-use an existing Artificial_Parameter. 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 // Here reuse_ap == false: the Artificial_Parameter does not exist yet. 02730 // Beware: possible reallocation invalidates row references. 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 // Update current context with constraints on the new parameter. 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 // Recompute row reference after possible reallocation. 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 // ctx2[0] += den-1; 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 // Generate new cut. 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 // Recompute references after possible reallocation. 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 // If we re-use an existing Artificial_Parameter 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 }
| bool Parma_Polyhedra_Library::PIP_Solution_Node::OK | ( | ) | const [virtual] |
Returns true if and only if *this is well formed.
Reimplemented from Parma_Polyhedra_Library::PIP_Tree_Node.
Definition at line 697 of file PIP_Tree.cc.
References Parma_Polyhedra_Library::PIP_Tree_Node::OK(), var_column, and var_row.
Referenced by ascii_load(), solve(), and update_tableau().
00697 { 00698 #ifndef NDEBUG 00699 using std::cerr; 00700 #endif 00701 if (!PIP_Tree_Node::OK()) 00702 return false; 00703 00704 // Check that every member used is OK. 00705 00706 if (!tableau.OK()) 00707 return false; 00708 00709 // Check coherency of basis, mapping, var_row and var_column 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 // All checks passed. 00761 return true; 00762 }
| const Linear_Expression & Parma_Polyhedra_Library::PIP_Solution_Node::parametric_values | ( | Variable | var | ) | const |
Returns a parametric expression for the values of problem variable var.
The returned linear expression may involve problem parameters as well as artificial parameters.
| var | The problem variable which is queried about. |
| std::invalid_argument | Thrown if var is dimension-incompatible with the PIP_Problem owning this solution node, or if var is a problem parameter. |
Definition at line 3016 of file PIP_Tree.cc.
References Parma_Polyhedra_Library::PIP_Tree_Node::get_owner(), Parma_Polyhedra_Library::Variable::id(), Parma_Polyhedra_Library::PIP_Problem::parameter_space_dimensions(), solution, Parma_Polyhedra_Library::Variable::space_dimension(), Parma_Polyhedra_Library::PIP_Problem::space_dimension(), and update_solution().
03016 { 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 }
| void Parma_Polyhedra_Library::PIP_Solution_Node::print_tree | ( | std::ostream & | s, | |
| unsigned | indent, | |||
| const std::vector< bool > & | pip_dim_is_param, | |||
| dimension_type | first_art_dim | |||
| ) | const [protected, virtual] |
Prints on s the tree rooted in *this.
Reimplemented from Parma_Polyhedra_Library::PIP_Tree_Node.
Definition at line 2985 of file PIP_Tree.cc.
References Parma_Polyhedra_Library::PIP_Tree_Node::constraints_, Parma_Polyhedra_Library::Constraint_System::empty(), Parma_Polyhedra_Library::PIP_Tree_Node::indent_and_print(), solution, and update_solution().
02987 { 02988 // Print info common to decision and solution nodes. 02989 PIP_Tree_Node::print_tree(s, indent, pip_dim_is_param, first_art_dim); 02990 02991 // Print info specific of solution nodes: 02992 // first update solution if needed ... 02993 update_solution(pip_dim_is_param); 02994 // ... and then actually print it. 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 }
| PIP_Solution_Node::Row_Sign Parma_Polyhedra_Library::PIP_Solution_Node::row_sign | ( | const Row & | x, | |
| dimension_type | big_dimension | |||
| ) | [static, private] |
Returns the sign of row x.
Definition at line 1461 of file PIP_Tree.cc.
References MIXED, NEGATIVE, Parma_Polyhedra_Library::not_a_dimension(), POSITIVE, sign, Parma_Polyhedra_Library::Row::size(), and ZERO.
Referenced by solve(), and update_tableau().
01462 { 01463 if (big_dimension != not_a_dimension()) { 01464 // If a big parameter has been set and its coefficient is not zero, 01465 // then return the sign of the coefficient. 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 // Otherwise x_big == 0, then no big parameter involved. 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 }
| void Parma_Polyhedra_Library::PIP_Solution_Node::set_owner | ( | const PIP_Problem * | owner | ) | [protected, virtual] |
Sets the pointer to the PIP_Problem owning object.
Implements Parma_Polyhedra_Library::PIP_Tree_Node.
Definition at line 563 of file PIP_Tree.cc.
References Parma_Polyhedra_Library::PIP_Tree_Node::owner_.
Referenced by Parma_Polyhedra_Library::PIP_Problem::ascii_load().
00563 { 00564 owner_ = owner; 00565 }
| PIP_Tree_Node * Parma_Polyhedra_Library::PIP_Solution_Node::solve | ( | const PIP_Problem & | pip, | |
| bool | check_feasible_context, | |||
| const Matrix & | context, | |||
| const Variables_Set & | params, | |||
| dimension_type | space_dim, | |||
| unsigned | indent_level | |||
| ) | [protected, virtual] |
Implements pure virtual method PIP_Tree_Node::solve.
Implements Parma_Polyhedra_Library::PIP_Tree_Node.
Definition at line 1887 of file PIP_Tree.cc.
References Parma_Polyhedra_Library::PIP_Tree_Node::add_constraint(), Parma_Polyhedra_Library::add_mul_assign(), Parma_Polyhedra_Library::Matrix::add_row(), Parma_Polyhedra_Library::PIP_Tree_Node::artificial_parameters, Parma_Polyhedra_Library::Matrix::ascii_dump(), Parma_Polyhedra_Library::Constraint_System::begin(), big_dimension, Parma_Polyhedra_Library::PIP_Tree_Node::compatibility_check(), Parma_Polyhedra_Library::PIP_Tree_Node::constraints_, Parma_Polyhedra_Library::PIP_Problem::control_parameters, Parma_Polyhedra_Library::PIP_Problem::CUTTING_STRATEGY, Parma_Polyhedra_Library::PIP_Problem::CUTTING_STRATEGY_ALL, Parma_Polyhedra_Library::PIP_Problem::CUTTING_STRATEGY_DEEPEST, Parma_Polyhedra_Library::PIP_Problem::CUTTING_STRATEGY_FIRST, Parma_Polyhedra_Library::Constraint_System::empty(), Parma_Polyhedra_Library::Constraint_System::end(), Parma_Polyhedra_Library::exact_div_assign(), Parma_Polyhedra_Library::PIP_Decision_Node::false_child, Parma_Polyhedra_Library::gcd_assign(), generate_cut(), Parma_Polyhedra_Library::PIP_Tree_Node::get_owner(), Parma_Polyhedra_Library::PIP_Tree_Node::indent_and_print(), Parma_Polyhedra_Library::Constraint_System::insert(), Parma_Polyhedra_Library::maybe_abandon(), MIXED, NEGATIVE, Parma_Polyhedra_Library::not_a_dimension(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), Parma_Polyhedra_Library::PIP_Tree_Node::parent(), Parma_Polyhedra_Library::PIP_Tree_Node::PIP_Decision_Node, PIP_Solution_Node(), Parma_Polyhedra_Library::PIP_Problem::PIVOT_ROW_STRATEGY, Parma_Polyhedra_Library::PIP_Problem::PIVOT_ROW_STRATEGY_FIRST, POSITIVE, PPL_DIRTY_TEMP_COEFFICIENT, row_sign(), sign, solution_valid, Parma_Polyhedra_Library::PIP_Tree_Node::solve(), Parma_Polyhedra_Library::Constraint_System::swap(), Parma_Polyhedra_Library::Row::swap(), UNKNOWN, var_column, var_row, WEIGHT_ADD, WEIGHT_ADD_MUL, WEIGHT_BEGIN, and ZERO.
01892 { 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 // Reset current solution as invalid. 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 // If needed, (re-)check feasibility of context. 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 // Main loop of the simplex algorithm. 01919 while (true) { 01920 // Check if the client has requested abandoning all expensive 01921 // computations. If so, the exception specified by the client 01922 // is thrown now. 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 // (Re-) Compute parameter row signs. 01939 // While at it, keep track of the first parameter rows 01940 // having negative and mixed sign. 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 // If no negative parameter row was found, try to refine the sign of 01955 // mixed rows using compatibility checks with the current context. 01956 if (first_negative == not_a_dim && first_mixed != not_a_dim) { 01957 for (dimension_type i = first_mixed; i < num_rows; ++i) { 01958 // Consider mixed sign parameter rows only. 01959 if (sign[i] != MIXED) 01960 continue; 01961 const Row& t_i = tableau.t[i]; 01962 Row_Sign new_sign = ZERO; 01963 // Check compatibility for constraint t_i(z) >= 0. 01964 if (compatibility_check(context, t_i)) 01965 new_sign = POSITIVE; 01966 // Check compatibility for constraint t_i(z) < 0, 01967 // i.e., -t_i(z) - 1 >= 0. 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 // Update sign for parameter row i. 01973 sign[i] = new_sign; 01974 // Maybe update first_negative and first_mixed. 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 // If there still is no negative parameter row and a mixed sign 01990 // parameter row (first_mixed) such that: 01991 // - it has at least one positive variable coefficient; 01992 // - constraint t_i(z) > 0 is not compatible with the context; 01993 // then this parameter row can be considered negative. 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 // Consider mixed sign parameter rows only. 01998 if (sign[i] != MIXED) 01999 continue; 02000 // Check for a positive variable coefficient. 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 // Check compatibility of constraint t_i(z) > 0. 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 // Maybe update sign (and first_* indices). 02018 if (compatible) { 02019 // Sign is still mixed. 02020 if (first_mixed == not_a_dim) 02021 first_mixed = i; 02022 } 02023 else { 02024 // Sign becomes negative (i.e., no longer mixed). 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 // If we have found a negative parameter row, then 02042 // either the problem is unfeasible, or a pivoting step is required. 02043 if (first_negative != not_a_dim) { 02044 02045 // Search for the best pivot row. 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 // No positive s_ij was found: problem is unfeasible. 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 // Update pivot indices. 02065 pi = i; 02066 pj = j; 02067 if (pip.control_parameters[PIP_Problem::PIVOT_ROW_STRATEGY] 02068 == PIP_Problem::PIVOT_ROW_STRATEGY_FIRST) 02069 // Stop at first valid row. 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 // Normalize the tableau before pivoting. 02079 tableau.normalize(); 02080 02081 // Perform pivot operation. 02082 02083 // Update basis. 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 // Creating identity rows corresponding to basic variable pj: 02100 // 1. add them to tableau so as to have proper size and capacity; 02101 tableau.s.add_zero_rows(1, Row::Flags()); 02102 tableau.t.add_zero_rows(1, Row::Flags()); 02103 // 2. swap the rows just added with empty ones. 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 // 3. drop rows previously added at end of tableau. 02109 tableau.s.erase_to_end(num_rows); 02110 tableau.t.erase_to_end(num_rows); 02111 02112 // Save current pivot denominator. 02113 PPL_DIRTY_TEMP_COEFFICIENT(pivot_den); 02114 pivot_den = tableau.denominator(); 02115 // Let the (scaled) pivot coordinate be 1. 02116 s_pivot[pj] = pivot_den; 02117 02118 // Swap identity row with the pivot row previously found. 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 // Compute columns s[*][j] : 02127 // s[i][j] -= s[i][pj] * s_pivot[j] / s_pivot_pj; 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 // Do nothing if the j-th pivot element is zero. 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 // Must scale matrix to stay in integer case. 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 // Compute columns t[*][j] : 02155 // t[i][j] -= s[i][pj] * t_pivot[j] / s_pivot_pj; 02156 for (dimension_type j = num_params; j-- > 0; ) { 02157 const Coefficient& t_pivot_j = t_pivot[j]; 02158 // Do nothing if the j-th pivot element is zero. 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 // Must scale matrix to stay in integer case. 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 // Update row sign. 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 // Compute column s[*][pj] : s[i][pj] /= s_pivot_pj; 02202 // Update column only if pivot coordinate != 1. 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 // As above, perform matrix scaling. 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 // Pivoting process ended: jump to next iteration. 02224 continue; 02225 } // if (first_negative != not_a_dim) 02226 02227 02228 PPL_ASSERT(first_negative == not_a_dim); 02229 // If no negative parameter row was found, 02230 // but a mixed parameter row was found ... 02231 if (first_mixed != not_a_dim) { 02232 // Look for a constraint (i_neg): 02233 // - having mixed parameter sign; 02234 // - having no positive variable coefficient; 02235 // - minimizing the score (sum of parameter coefficients). 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 // Mixed parameter sign. 02241 if (sign[i] != MIXED) 02242 continue; 02243 // No positive variable coefficient. 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 // Minimize parameter coefficient score, 02254 // eliminating implicated tautologies (if any). 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 /* Simplify tautology by exploiting integrality. */ 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 // Jump to next iteration. 02291 continue; 02292 } 02293 02294 PPL_ASSERT(i_neg == not_a_dim); 02295 // Heuristically choose "best" (mixed) pivoting row. 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 /* Simplify t_test by exploiting integrality. */ 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 // Create a solution node for the "true" version of current node. 02331 PIP_Tree_Node* t_node = new PIP_Solution_Node(*this, No_Constraints()); 02332 // Protect it from exception safety issues via std::auto_ptr. 02333 std::auto_ptr<PIP_Tree_Node> wrapped_node(t_node); 02334 02335 // Add parametric constraint to context. 02336 context.add_row(t_test); 02337 // Recusively solve true node wrt updated context. 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 // Resolution may have changed t_node: in case, rewrap it. 02345 if (t_node != wrapped_node.get()) { 02346 wrapped_node.release(); 02347 wrapped_node.reset(t_node); 02348 } 02349 02350 // Modify *this in place to become the "false" version of current node. 02351 PIP_Tree_Node* f_node = this; 02352 // Swap aside constraints and artificial parameters 02353 // (these will be later restored if needed). 02354 Constraint_System cs; 02355 Artificial_Parameter_Sequence aps; 02356 cs.swap(f_node->constraints_); 02357 aps.swap(f_node->artificial_parameters); 02358 // Compute the complement of the constraint used for the "true" node. 02359 Row& f_test = context[context.num_rows()-1]; 02360 complement_assign(f_test, t_test, 1); 02361 02362 // Recusively solve false node wrt updated context. 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 // Case analysis on recursive resolution calls outcome. 02371 if (t_node == 0) { 02372 if (f_node == 0) { 02373 // Both t_node and f_node unfeasible. 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 // t_node unfeasible, f_node feasible: 02382 // restore cs and aps into f_node (i.e., this). 02383 PPL_ASSERT(f_node == this); 02384 f_node->constraints_.swap(cs); 02385 f_node->artificial_parameters.swap(aps); 02386 // Add f_test to constraints. 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 // t_node feasible, f_node unfeasible. 02397 #ifdef NOISY_PIP_TREE_STRUCTURE 02398 indent_and_print(std::cerr, indent_level, 02399 "=== EXIT: THEN BRANCH FEASIBLE\n"); 02400 #endif 02401 // NOTE: in principle, we could merge t_node into its parent. 02402 // However, if t_node is a decision node having both childs, 02403 // then we would obtain a node violating the PIP_Decision_Node 02404 // invariant saying that t_node should have a single constraint: 02405 // it will have, at least, the two splitting constraints. 02406 PIP_Decision_Node* dn = dynamic_cast<PIP_Decision_Node*>(t_node); 02407 if (dn != 0 && dn->false_child != 0) { 02408 // Do NOT merge: create a new decision node. 02409 PIP_Tree_Node* parent 02410 = new PIP_Decision_Node(t_node->get_owner(), 0, t_node); 02411 // Previously wrapped 't_node' is now safe: release it 02412 // and protect new 'parent' node from exception safety issues. 02413 wrapped_node.release(); 02414 wrapped_node.reset(parent); 02415 // Restore into parent `cs' and `aps'. 02416 parent->constraints_.swap(cs); 02417 parent->artificial_parameters.swap(aps); 02418 // Add t_test to parent's constraints. 02419 parent->add_constraint(t_test, all_params); 02420 // It is now safe to release previously wrapped parent pointer 02421 // and return it to caller. 02422 return wrapped_node.release(); 02423 } 02424 else { 02425 // Merge t_node with its parent: 02426 // a) append into `cs' the constraints of t_node; 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 // b) append into `aps' the parameters of t_node; 02432 aps.insert(aps.end(), 02433 t_node->artificial_parameters.begin(), 02434 t_node->artificial_parameters.end()); 02435 // c) swap the updated `cs' and `aps' into t_node. 02436 cs.swap(t_node->constraints_); 02437 aps.swap(t_node->artificial_parameters); 02438 // d) add t_test to t_nodes's constraints. 02439 t_node->add_constraint(t_test, all_params); 02440 // It is now safe to release previously wrapped t_node pointer 02441 // and return it to caller. 02442 return wrapped_node.release(); 02443 } 02444 } 02445 02446 // Here both t_node and f_node are feasible: 02447 // create a new decision node. 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 // Previously wrapped 't_node' is now safe: release it 02455 // and protect new 'parent' node from exception safety issues. 02456 wrapped_node.release(); 02457 wrapped_node.reset(parent); 02458 02459 // Add t_test to the constraints of the new decision node. 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 // If node to be solved had tautologies, 02470 // store them in a new decision node. 02471 parent = new PIP_Decision_Node(parent->get_owner(), 0, parent); 02472 // Previously wrapped 'parent' node is now safe: release it 02473 // and protect new 'parent' node from exception safety issues. 02474 wrapped_node.release(); 02475 wrapped_node.reset(parent); 02476 parent->constraints_.swap(cs); 02477 } 02478 parent->artificial_parameters.swap(aps); 02479 // It is now safe to release previously wrapped decision node 02480 // and return it to the caller. 02481 return wrapped_node.release(); 02482 } // if (first_mixed != not_a_dim) 02483 02484 02485 PPL_ASSERT(first_negative == not_a_dim); 02486 PPL_ASSERT(first_mixed == not_a_dim); 02487 // Here all parameters are positive: we have found a continuous 02488 // solution. If the solution happens to be integer, then it is the 02489 // solution of the integer problem. Otherwise, we may need to generate 02490 // a new cut to try and get back into the integer case. 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 // Look for any row having non integer parameter coefficients. 02498 const Coefficient& den = tableau.denominator(); 02499 for (dimension_type k = 0; k < num_vars; ++k) { 02500 if (basis[k]) 02501 // Basic variable = 0, hence integer. 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 // The goto was not taken, the solution is integer. 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 // The solution is non-integer: generate a cut. 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 // Find the first row with simplest parametric part. 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 // Count the number of non-integer parameter coefficients. 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 // Generate cut using 'best_i'. 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 // Find the row with simplest parametric part 02556 // which will generate the "deepest" cut. 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 // Compute score and pcount. 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 // Compute s_score. 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 // Combine 'score' and 's_score'. 02593 score *= s_score; 02594 /* 02595 Select row i if it is non integer AND 02596 - no row has been chosen yet; OR 02597 - it has fewer non-integer parameter coefficients; OR 02598 - it has the same number of non-integer parameter coefficients, 02599 but its score is greater. 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 } // End of processing for non-integer solutions. 02623 02624 } // Main loop of the simplex algorithm 02625 02626 // This point should be unreachable. 02627 throw std::runtime_error("PPL internal error"); 02628 }
| memory_size_type Parma_Polyhedra_Library::PIP_Solution_Node::total_memory_in_bytes | ( | ) | const [virtual] |
Returns the total size in bytes of the memory occupied by *this.
Implements Parma_Polyhedra_Library::PIP_Tree_Node.
Definition at line 2903 of file PIP_Tree.cc.
References external_memory_in_bytes().
02903 { 02904 return sizeof(*this) + external_memory_in_bytes(); 02905 }
| void Parma_Polyhedra_Library::PIP_Solution_Node::update_solution | ( | ) | const [protected] |
Helper method.
Definition at line 3051 of file PIP_Tree.cc.
References Parma_Polyhedra_Library::PIP_Tree_Node::get_owner(), Parma_Polyhedra_Library::PIP_Problem::parameter_space_dimensions(), solution_valid, and Parma_Polyhedra_Library::PIP_Problem::space_dimension().
Referenced by parametric_values(), and print_tree().
03051 { 03052 // Avoid doing useless work. 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 }
| void Parma_Polyhedra_Library::PIP_Solution_Node::update_solution | ( | const std::vector< bool > & | pip_dim_is_param | ) | const [protected] |
Update the solution values.
| pip_dim_is_param | A vector of Boolean flags telling which PIP problem dimensions are problem parameters. The size of the vector is equal to the PIP problem internal space dimension (i.e., no artificial parameters). |
Definition at line 3069 of file PIP_Tree.cc.
References Parma_Polyhedra_Library::add_mul_assign(), PPL_DIRTY_TEMP_COEFFICIENT, solution, and solution_valid.
03069 { 03070 // Avoid doing useless work. 03071 if (solution_valid) 03072 return; 03073 03074 // const_cast required so as to refresh the solution cache. 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 // Compute external "names" (i.e., indices) for all parameters. 03087 std::vector<dimension_type> all_param_names(num_all_params); 03088 03089 // External indices for problem parameters. 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 // External indices for artificial parameters. 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 // NOTE: add 1 to column index to account for inhomogenous term. 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 // Mark solution as valid. 03123 x.solution_valid = true; 03124 }
| void Parma_Polyhedra_Library::PIP_Solution_Node::update_tableau | ( | const PIP_Problem & | pip, | |
| dimension_type | external_space_dim, | |||
| dimension_type | first_pending_constraint, | |||
| const Constraint_Sequence & | input_cs, | |||
| const Variables_Set & | parameters | |||
| ) | [protected, virtual] |
Implements pure virtual method PIP_Tree_Node::update_tableau.
Implements Parma_Polyhedra_Library::PIP_Tree_Node.
Definition at line 1703 of file PIP_Tree.cc.
References Parma_Polyhedra_Library::add_mul_assign(), big_dimension, Parma_Polyhedra_Library::PIP_Problem::big_parameter_dimension, Parma_Polyhedra_Library::Constraint::coefficient(), Parma_Polyhedra_Library::PIP_Problem::external_space_dim, Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), Parma_Polyhedra_Library::PIP_Problem::internal_space_dim, Parma_Polyhedra_Library::Constraint::is_equality(), Parma_Polyhedra_Library::Constraint::is_strict_inequality(), Parma_Polyhedra_Library::not_a_dimension(), OK(), row_sign(), sign, Parma_Polyhedra_Library::Constraint::space_dimension(), special_equality_row, var_column, var_row, WEIGHT_ADD, WEIGHT_BEGIN, and ZERO.
01707 { 01708 // Make sure a parameter column exists, for the inhomogeneous term. 01709 if (tableau.t.num_columns() == 0) 01710 tableau.t.add_zero_columns(1); 01711 01712 // NOTE: here 'params' stands for problem (i.e., non artificial) parameters. 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 // Resize the two tableau matrices. 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 // Shift to the right the columns of artificial parameters. 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 // A new problem variable. 01751 if (tableau.s.num_rows() == 0) { 01752 // No rows have been added yet 01753 basis.push_back(true); 01754 mapping.push_back(new_var_column); 01755 } 01756 else { 01757 /* 01758 Need to insert the original variable id 01759 before the slack variable id's to respect variable ordering. 01760 */ 01761 basis.insert(basis.begin() + new_var_column, true); 01762 mapping.insert(mapping.begin() + new_var_column, new_var_column); 01763 // Update variable id's of slack variables. 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 // Compute the column number of big parameter in tableau.t matrix. 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 // (Tentatively) Add new rows to s and t matrices. 01792 // These will be removed at the end if they turn out to be useless. 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 // Setting the inhomogeneus term. 01800 p_row[0] = constraint.inhomogeneous_term(); 01801 if (constraint.is_strict_inequality()) 01802 // Transform (expr > 0) into (expr - 1 >= 0). 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 // Optimize computation below: only update p/v index. 01815 if (is_parameter) 01816 ++p_index; 01817 else 01818 ++v_index; 01819 // Jump to next iteration. 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 // Basic variable : add coeff_i * x_i 01832 add_mul_assign(v_row[mv], coeff_i, denom); 01833 else { 01834 // Non-basic variable : add coeff_i * row_i 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 // Parametric-only constraints have already been inserted in 01844 // initial context, so no need to insert them in the tableau. 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 // Handle equality constraints. 01856 // After having added the f_i(x,p) >= 0 constraint, 01857 // we must add -f_i(x,p) to the special equality row. 01858 if (special_equality_row == 0 || basis[special_equality_row]) { 01859 // The special constraint has not been created yet 01860 // FIXME: for now, we don't handle the case where the variable 01861 // is basic, and we just create a new row. 01862 // This might be faster however. 01863 tableau.s.add_zero_rows(1, Row::Flags()); 01864 tableau.t.add_zero_rows(1, Row::Flags()); 01865 // NOTE: addition of rows invalidates references v_row and p_row 01866 // due to possible matrix reallocations: recompute them. 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 // The special constraint already exists and is nonbasic. 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 }
| bool PIP_Problem::ascii_load | ( | std::istream & | s | ) | [friend] |
std::vector<bool> Parma_Polyhedra_Library::PIP_Solution_Node::basis [private] |
A boolean vector for identifying the basic variables.
Variable identifiers are numbered from 0 to n+m-1, where n is the number of columns in the simplex tableau corresponding to variables, and m is the number of rows.
Indices from 0 to n-1 correspond to the original variables.
Indices from n to n+m-1 correspond to the slack variables associated to the internal constraints, which do not strictly correspond to original constraints, since these may have been transformed to fit the standard form of the dual simplex.
The value for basis[i] is:
i is basic,i is nonbasic. Definition at line 523 of file PIP_Tree.defs.hh.
The column index in the parametric part of the simplex tableau corresponding to the big parameter; not_a_dimension() if not set.
Definition at line 570 of file PIP_Tree.defs.hh.
Referenced by ascii_dump(), ascii_load(), solve(), and update_tableau().
std::vector<dimension_type> Parma_Polyhedra_Library::PIP_Solution_Node::mapping [private] |
A mapping between the tableau rows/columns and the original variables.
The value of mapping[i] depends of the value of basis[i].
basis[i] is true, mapping[i] encodes the column index of variable i in the s matrix of the tableau.basis[i] is false, mapping[i] encodes the row index of variable i in the tableau. Definition at line 535 of file PIP_Tree.defs.hh.
std::vector<Row_Sign> Parma_Polyhedra_Library::PIP_Solution_Node::sign [private] |
A cache for computed sign values of constraint parametric RHS.
Definition at line 587 of file PIP_Tree.defs.hh.
Referenced by ascii_dump(), ascii_load(), external_memory_in_bytes(), generate_cut(), row_sign(), solve(), and update_tableau().
std::vector<Linear_Expression> Parma_Polyhedra_Library::PIP_Solution_Node::solution [private] |
Parametric values for the solution.
Definition at line 590 of file PIP_Tree.defs.hh.
Referenced by ascii_dump(), ascii_load(), external_memory_in_bytes(), parametric_values(), print_tree(), and update_solution().
bool Parma_Polyhedra_Library::PIP_Solution_Node::solution_valid [private] |
An indicator for solution validity.
Definition at line 593 of file PIP_Tree.defs.hh.
Referenced by ascii_dump(), ascii_load(), solve(), and update_solution().
The variable number of the special inequality used for modelling equality constraints.
The subset of equality constraints in a specific problem can be expressed as:
. As the dual simplex standard form requires constraints to be inequalities, the following constraints can be modelized the following way:


The special_equality_row value stores the variable number of the specific constraint which is used to modelize the latter sum of constraints. If no such constraint exists, the value is set to 0.
Definition at line 564 of file PIP_Tree.defs.hh.
Referenced by ascii_dump(), ascii_load(), and update_tableau().
The parametric simplex tableau.
Definition at line 503 of file PIP_Tree.defs.hh.
std::vector<dimension_type> Parma_Polyhedra_Library::PIP_Solution_Node::var_column [private] |
The variable identifiers associated to the columns of the simplex tableau.
Definition at line 545 of file PIP_Tree.defs.hh.
Referenced by ascii_dump(), ascii_load(), external_memory_in_bytes(), OK(), solve(), and update_tableau().
std::vector<dimension_type> Parma_Polyhedra_Library::PIP_Solution_Node::var_row [private] |
The variable identifiers associated to the rows of the simplex tableau.
Definition at line 540 of file PIP_Tree.defs.hh.
Referenced by ascii_dump(), ascii_load(), external_memory_in_bytes(), generate_cut(), OK(), solve(), and update_tableau().
1.6.3