24 #include "ppl-config.h"
32 #define NOISY_PIP_TREE_STRUCTURE 1
34 #define VERY_NOISY_PIP 1
44 Coefficient_traits::const_reference y,
45 Coefficient_traits::const_reference z) {
52 class Add_Mul_Assign_Row_Helper1 {
54 Add_Mul_Assign_Row_Helper1(Coefficient_traits::const_reference coeff)
59 operator()(
Coefficient& x, Coefficient_traits::const_reference y)
const {
68 class Add_Mul_Assign_Row_Helper2 {
70 Add_Mul_Assign_Row_Helper2(Coefficient_traits::const_reference coeff)
75 operator()(
Coefficient& x, Coefficient_traits::const_reference y)
const {
87 Coefficient_traits::const_reference
c,
90 x.combine_needs_second(y,
91 Add_Mul_Assign_Row_Helper1(c),
92 Add_Mul_Assign_Row_Helper2(c));
97 struct Sub_Assign_Helper1 {
99 operator()(
Coefficient& x, Coefficient_traits::const_reference y)
const {
104 struct Sub_Assign_Helper2 {
106 operator()(
Coefficient& x, Coefficient_traits::const_reference y)
const {
116 x.combine_needs_second(y, Sub_Assign_Helper1(), Sub_Assign_Helper2());
122 merge_assign(Matrix<PIP_Tree_Node::Row>& x,
const Constraint_System& y,
123 const Variables_Set& parameters) {
125 PPL_ASSERT(params_size == x.num_columns() - 1);
131 x.add_zero_rows(new_rows);
135 const Variables_Set::const_iterator param_begin = parameters.begin();
136 const Variables_Set::const_iterator param_end = parameters.end();
140 y_end = y.end(); y_i != y_end; ++y_i, ++i) {
142 PPL_ASSERT(y_i->is_nonstrict_inequality());
144 Coefficient_traits::const_reference inhomogeneous_term
145 = y_i->inhomogeneous_term();
146 Variables_Set::const_iterator pj = param_begin;
148 if (inhomogeneous_term != 0) {
149 itr = x_i.insert(0, inhomogeneous_term);
156 const Variable vj(*pj);
157 if (vj.space_dimension() > cs_space_dim) {
160 Coefficient_traits::const_reference c = y_i->coefficient(vj);
162 itr = x_i.insert(itr, j, c);
169 #if PPL_USE_SPARSE_MATRIX
177 i_end = x.end(); i != i_end; ++i) {
183 #else // !PPL_USE_SPARSE_MATRIX
194 #endif // !PPL_USE_SPARSE_MATRIX
203 Coefficient_traits::const_reference denom) {
204 PPL_ASSERT(denom > 0);
205 neg_assign_row(x, y);
213 pos_rem_assign(mod, x_0, denom);
214 x_0 -= (mod == 0) ? denom : mod;
223 add_artificial_parameters(Matrix<PIP_Tree_Node::Row>& context,
225 if (num_art_params > 0) {
226 context.add_zero_columns(num_art_params);
232 add_artificial_parameters(Variables_Set& params,
236 params.insert(space_dim + i);
243 add_artificial_parameters(Matrix<PIP_Tree_Node::Row>& context,
244 Variables_Set& params,
247 add_artificial_parameters(context, num_art_params);
248 add_artificial_parameters(params, space_dim, num_art_params);
249 space_dim += num_art_params;
260 column_lower(
const Matrix<PIP_Tree_Node::Row>& tableau,
261 const std::vector<dimension_type>& mapping,
262 const std::vector<bool>& basis,
265 Coefficient_traits::const_reference cst_a = -1,
266 Coefficient_traits::const_reference cst_b = -1) {
267 Coefficient_traits::const_reference sij_a = pivot_a.get(ja);
268 Coefficient_traits::const_reference sij_b = pivot_b.get(jb);
269 PPL_ASSERT(sij_a > 0);
270 PPL_ASSERT(sij_b > 0);
274 lhs_coeff = cst_a * sij_b;
275 rhs_coeff = cst_b * sij_a;
277 const int lhs_coeff_sign =
sgn(lhs_coeff);
278 const int rhs_coeff_sign =
sgn(rhs_coeff);
283 return lhs_coeff > rhs_coeff;
297 const bool in_base = basis[k];
298 if (++k >= num_vars) {
305 if (lhs_coeff == 0) {
309 return lhs_coeff > 0;
314 if (rhs_coeff == 0) {
318 return 0 > rhs_coeff;
327 Coefficient_traits::const_reference t_mk_ja = t_mk.
get(ja);
328 Coefficient_traits::const_reference t_mk_jb = t_mk.get(jb);
334 const int rhs_sign = rhs_coeff_sign *
sgn(t_mk_jb);
345 const int lhs_sign = lhs_coeff_sign *
sgn(t_mk_ja);
355 lhs = lhs_coeff * t_mk_ja;
356 rhs = rhs_coeff * t_mk_jb;
379 find_lexico_minimal_column_in_set(std::vector<dimension_type>& candidates,
380 const Matrix<PIP_Tree_Node::Row>& tableau,
381 const std::vector<dimension_type>& mapping,
382 const std::vector<bool>& basis,
387 PPL_ASSERT(!candidates.empty());
389 std::vector<dimension_type> new_candidates;
390 for (
dimension_type var_index = 0; var_index < num_vars; ++var_index) {
391 new_candidates.clear();
392 std::vector<dimension_type>::const_iterator i = candidates.begin();
393 std::vector<dimension_type>::const_iterator i_end = candidates.end();
394 PPL_ASSERT(!candidates.empty());
395 new_candidates.push_back(*i);
403 pivot_itr = pivot_row.find(min_column);
404 PPL_ASSERT(pivot_itr != pivot_row.end());
408 const bool in_base = basis[var_index];
410 for ( ; i != i_end; ++i) {
411 pivot_itr = pivot_row.find(pivot_itr, *i);
412 PPL_ASSERT(pivot_itr != pivot_row.end());
413 Coefficient_traits::const_reference sij_a = *pivot_itr;
415 PPL_ASSERT(sij_a > 0);
416 PPL_ASSERT(sij_b > 0);
419 if (row_index != *i) {
420 if (row_index == min_column) {
422 new_candidates.clear();
425 new_candidates.push_back(min_column);
429 new_candidates.push_back(*i);
441 if (row_itr == row_end || row_itr.index() > min_column) {
445 PPL_ASSERT(row_itr.index() == min_column);
449 for ( ; i != i_end; ++i) {
450 pivot_itr = pivot_row.find(pivot_itr, *i);
451 PPL_ASSERT(pivot_itr != pivot_row.end());
452 Coefficient_traits::const_reference sij_a = *pivot_itr;
453 PPL_ASSERT(sij_a > 0);
454 PPL_ASSERT(sij_b > 0);
458 if (row_itr != row_end && row_itr.index() < *i) {
459 row_itr = row.lower_bound(row_itr, *i);
462 if (row_itr == row_end || row_itr.index() > *i) {
466 PPL_ASSERT(row_itr.index() == *i);
473 lhs = sij_b * row_ja;
474 rhs = sij_a * row_jb;
476 new_candidates.push_back(*i);
480 new_candidates.clear();
484 new_candidates.push_back(min_column);
491 swap(candidates, new_candidates);
500 find_lexico_minimal_column(
const Matrix<PIP_Tree_Node::Row>& tableau,
501 const std::vector<dimension_type>& mapping,
502 const std::vector<bool>& basis,
509 PPL_ASSERT(start_j <= pivot_row.size());
510 if (start_j == pivot_row.size()) {
516 std::vector<dimension_type> candidates;
518 i_end = pivot_row.end(); i != i_end; ++i) {
520 candidates.push_back(i.index());
525 if (candidates.empty()) {
530 find_lexico_minimal_column_in_set(candidates, tableau,
531 mapping, basis, pivot_row);
532 PPL_ASSERT(!candidates.empty());
533 j_out = *(candidates.begin());
539 template <
typename Iter>
541 gcd_assign_iter(
Coefficient& gcd, Iter first, Iter last) {
542 PPL_ASSERT(gcd != 0);
550 for ( ; first != last; ++first) {
551 Coefficient_traits::const_reference coeff = *first;
568 PPL_ASSERT(j_begin != j_end && j_begin.index() == 0 && *j_begin != 0);
571 PPL_ASSERT(j_begin != j_end);
572 for ( ; *j_begin == 0; ++j_begin) {
573 PPL_ASSERT(j_begin != j_end);
579 gcd_assign_iter(gcd, j_begin, j_end);
582 pos_rem_assign(mod, row[0], gcd);
598 gcd_assign_iter(gcd, x.begin(), x.end());
603 i_end = x.end(); i != i_end; ++i) {
614 struct compatibility_check_find_pivot_in_set_data {
619 bool operator==(
const compatibility_check_find_pivot_in_set_data& x)
const {
620 return row_index == x.row_index;
623 bool operator<(
const compatibility_check_find_pivot_in_set_data& x)
const {
624 return row_index < x.row_index;
629 compatibility_check_find_pivot_in_set(
631 compatibility_check_find_pivot_in_set_data> >&
633 const Matrix<PIP_Tree_Node::Row>& s,
634 const std::vector<dimension_type>& mapping,
635 const std::vector<bool>& basis) {
637 typedef compatibility_check_find_pivot_in_set_data data_struct;
638 typedef std::vector<std::pair<dimension_type, data_struct> > candidates_t;
640 candidates_t new_candidates;
642 for (
dimension_type var_index = 0; var_index < num_vars; ++var_index) {
644 const bool in_base = basis[var_index];
645 candidates_t::const_iterator i = candidates.begin();
646 candidates_t::const_iterator i_end = candidates.end();
647 PPL_ASSERT(i != i_end);
651 new_candidates.clear();
652 new_candidates.push_back(*i);
654 for (++i; i != i_end; ++i) {
655 bool found_better_pivot =
false;
658 Coefficient_traits::const_reference challenger_cost = i->second.cost;
659 PPL_ASSERT(value > 0);
660 PPL_ASSERT(i->second.value > 0);
661 PPL_ASSERT(pj < challenger_j);
663 const int lhs_coeff_sgn =
sgn(cost);
664 const int rhs_coeff_sgn =
sgn(challenger_cost);
666 PPL_ASSERT(pj != challenger_j);
669 if (row_index == pj) {
671 if (lhs_coeff_sgn == 0) {
672 new_candidates.push_back(*i);
675 found_better_pivot = (lhs_coeff_sgn > 0);
679 if (row_index == challenger_j) {
681 if (rhs_coeff_sgn == 0) {
682 new_candidates.push_back(*i);
685 found_better_pivot = (0 > rhs_coeff_sgn);
690 new_candidates.push_back(*i);
693 if (found_better_pivot) {
695 cost = challenger_cost;
696 value = i->second.value;
697 new_candidates.clear();
698 new_candidates.push_back(*i);
709 if (row_itr != row_end && row_itr.index() == pj) {
710 row_value = *row_itr;
717 for (++i; i != i_end; ++i) {
719 Coefficient_traits::const_reference challenger_cost = i->second.cost;
720 Coefficient_traits::const_reference challenger_value
722 PPL_ASSERT(value > 0);
723 PPL_ASSERT(challenger_value > 0);
724 PPL_ASSERT(pj < challenger_j);
726 new_row_itr = row.find(row_itr, challenger_j);
727 if (new_row_itr != row.end()) {
728 row_challenger_value = *new_row_itr;
730 row_itr = new_row_itr;
733 row_challenger_value = 0;
736 PPL_ASSERT(row_challenger_value == row.get(challenger_j));
742 const int lhs_sign =
sgn(cost) *
sgn(row_value);
743 const int rhs_sign =
sgn(challenger_cost) *
sgn(row_challenger_value);
745 if (lhs_sign != rhs_sign) {
746 if (lhs_sign > rhs_sign) {
750 cost = challenger_cost;
751 value = challenger_value;
752 row_value = row_challenger_value;
753 new_candidates.clear();
754 new_candidates.push_back(*i);
764 lhs *= challenger_value;
766 rhs = challenger_cost;
770 rhs *= row_challenger_value;
773 new_candidates.push_back(*i);
780 cost = challenger_cost;
781 value = challenger_value;
782 row_value = row_challenger_value;
783 new_candidates.clear();
784 new_candidates.push_back(*i);
791 swap(candidates, new_candidates);
798 compatibility_check_find_pivot(
const Matrix<PIP_Tree_Node::Row>& s,
799 const std::vector<dimension_type>& mapping,
800 const std::vector<bool>& basis,
805 typedef compatibility_check_find_pivot_in_set_data data_struct;
807 typedef std::vector<std::pair<dimension_type, data_struct> > candidates_t;
808 typedef std::map<dimension_type,data_struct> candidates_map_t;
809 candidates_map_t candidates_map;
812 Coefficient_traits::const_reference s_i0 = s_i.
get(0);
815 if (!find_lexico_minimal_column(s, mapping, basis, s_i, 1, j)) {
819 Coefficient_traits::const_reference s_ij = s_i.get(j);
820 candidates_map_t::iterator itr = candidates_map.find(j);
821 if (itr == candidates_map.end()) {
822 data_struct& current_data = candidates_map[j];
823 current_data.row_index = i;
824 current_data.cost = s_i0;
825 current_data.value = s_ij;
828 data_struct& current_data = candidates_map[j];
829 PPL_ASSERT(current_data.value > 0);
834 const int lhs_coeff_sgn =
sgn(current_data.cost);
835 const int rhs_coeff_sgn =
sgn(s_i0);
837 if (lhs_coeff_sgn != rhs_coeff_sgn) {
841 if (lhs_coeff_sgn > rhs_coeff_sgn) {
843 current_data.row_index = i;
844 current_data.cost = s_i0;
845 current_data.value = s_ij;
852 Coefficient_traits::const_reference value_b = s_i.get(j);
853 PPL_ASSERT(value_b > 0);
856 lhs_coeff = current_data.cost;
857 lhs_coeff *= value_b;
861 rhs_coeff *= current_data.value;
866 if (lhs_coeff > rhs_coeff) {
868 current_data.row_index = i;
869 current_data.cost = s_i0;
870 current_data.value = s_ij;
877 candidates_t candidates;
878 for (candidates_map_t::iterator
879 i = candidates_map.begin(), i_end = candidates_map.end();
881 candidates.push_back(*i);
883 if (!candidates.empty()) {
884 compatibility_check_find_pivot_in_set(candidates, s, mapping, basis);
885 PPL_ASSERT(!candidates.empty());
886 pi = candidates.begin()->second.row_index;
887 pj = candidates.begin()->first;
899 namespace IO_Operators {
920 artificial_parameters() {
926 constraints_(y.constraints_),
927 artificial_parameters(y.artificial_parameters) {
935 Coefficient_traits::const_reference d)
938 throw std::invalid_argument(
"PIP_Tree_Node::Artificial_Parameter(e, d): "
939 "denominator d is zero.");
1000 std::cerr <<
"PIP_Tree_Node::Artificial_Parameter "
1001 <<
"has a non-positive denominator.\n";
1010 s <<
"artificial_parameter ";
1012 s <<
" / " << denom <<
"\n";
1018 if (!(s >> str) || str !=
"artificial_parameter") {
1024 if (!(s >> str) || str !=
"/") {
1027 if (!(s >> denom)) {
1043 special_equality_row(0),
1047 solution_valid(false) {
1056 var_column(y.var_column),
1057 special_equality_row(y.special_equality_row),
1058 big_dimension(y.big_dimension),
1060 solution(y.solution),
1061 solution_valid(y.solution_valid) {
1071 var_column(y.var_column),
1072 special_equality_row(y.special_equality_row),
1073 big_dimension(y.big_dimension),
1075 solution(y.solution),
1076 solution_valid(y.solution_valid) {
1105 std::auto_ptr<PIP_Tree_Node> wrapped_node(
false_child);
1111 wrapped_node.release();
1169 if (s.num_rows() !=
t.num_rows()) {
1171 std::cerr <<
"PIP_Solution_Node::Tableau matrices "
1172 <<
"have a different number of rows.\n";
1177 if (!s.OK() || !
t.OK()) {
1179 std::cerr <<
"A PIP_Solution_Node::Tableau matrix is broken.\n";
1186 std::cerr <<
"PIP_Solution_Node::Tableau with non-positive "
1187 <<
"denominator.\n";
1206 if (i->is_strict_inequality()) {
1208 cerr <<
"The feasible region of the PIP_Problem parameter context"
1209 <<
"is defined by a constraint system containing strict "
1225 Variables_Set::const_iterator j = parameters.begin();
1226 if (!parameters.empty()) {
1233 if (i != i_end && i.
index() == 0) {
1238 for ( ; i != i_end; ++i) {
1239 PPL_ASSERT(i.
index() <= parameters.size());
1240 std::advance(j, i.
index() - j_index);
1241 j_index = i.
index();
1273 if (!tableau.OK()) {
1278 if (basis.size() != mapping.size()) {
1280 cerr <<
"The PIP_Solution_Node::basis and PIP_Solution_Node::mapping "
1281 <<
"vectors do not have the same number of elements.\n";
1287 cerr <<
"The sum of number of elements in the PIP_Solution_Node::var_row "
1288 <<
"and PIP_Solution_Node::var_column vectors is different from the "
1289 <<
"number of elements in the PIP_Solution_Node::basis vector.\n";
1293 if (
var_column.size() != tableau.s.num_columns()) {
1295 cerr <<
"The number of elements in the PIP_Solution_Node::var_column "
1296 <<
"vector is different from the number of columns in the "
1297 <<
"PIP_Solution_Node::tableau.s matrix.\n";
1301 if (
var_row.size() != tableau.s.num_rows()) {
1303 cerr <<
"The number of elements in the PIP_Solution_Node::var_row "
1304 <<
"vector is different from the number of rows in the "
1305 <<
"PIP_Solution_Node::tableau.s matrix.\n";
1311 if (basis[i] &&
var_column[row_column] != i) {
1313 cerr <<
"Variable " << i <<
" is basic and corresponds to column "
1314 << row_column <<
" but PIP_Solution_Node::var_column["
1315 << row_column <<
"] does not correspond to variable " << i
1320 if (!basis[i] &&
var_row[row_column] != i) {
1322 cerr <<
"Variable " << i <<
" is nonbasic and corresponds to row "
1323 << row_column <<
" but PIP_Solution_Node::var_row["
1324 << row_column <<
"] does not correspond to variable " << i
1342 if (false_child != 0 && !false_child->OK()) {
1345 if (true_child != 0 && !true_child->OK()) {
1350 if (true_child == 0) {
1352 std::cerr <<
"PIP_Decision_Node with no 'true' child.\n";
1358 if (false_child != 0) {
1362 std::cerr <<
"PIP_Decision_Node with a 'false' child has "
1363 << dist <<
" parametric constraints (should be 1).\n";
1381 true_child->update_tableau(pip,
1383 first_pending_constraint,
1386 if (false_child != 0) {
1387 false_child->update_tableau(pip,
1389 first_pending_constraint,
1398 const bool check_feasible_context,
1402 const int indent_level) {
1403 PPL_ASSERT(indent_level >= 0);
1404 #ifdef NOISY_PIP_TREE_STRUCTURE
1409 PPL_ASSERT(true_child != 0);
1413 add_artificial_parameters(context_true, all_params, space_dim,
1416 const bool has_false_child = (false_child != 0);
1417 const bool has_true_child = (true_child != 0);
1418 #ifdef NOISY_PIP_TREE_STRUCTURE
1420 "=== DECISION: SOLVING THEN CHILD\n");
1422 true_child = true_child->solve(pip, check_feasible_context,
1423 context_true, all_params, space_dim,
1426 if (has_false_child) {
1431 Row& last = context_false[context_false.
num_rows() - 1];
1432 complement_assign(last, last, 1);
1433 #ifdef NOISY_PIP_TREE_STRUCTURE
1435 "=== DECISION: SOLVING ELSE CHILD\n");
1437 false_child = false_child->solve(pip, check_feasible_context,
1438 context_false, all_params, space_dim,
1442 if (true_child == 0 && false_child == 0) {
1444 #ifdef NOISY_PIP_TREE_STRUCTURE
1446 "=== DECISION: BOTH BRANCHES NOW UNFEASIBLE: _|_\n");
1452 if (has_false_child && false_child == 0) {
1456 #ifdef NOISY_PIP_TREE_STRUCTURE
1458 "=== DECISION: ELSE BRANCH NOW UNFEASIBLE\n");
1460 "==> merge then branch with parent.\n");
1467 PPL_ASSERT(node->
OK());
1470 else if (has_true_child && true_child == 0) {
1473 #ifdef NOISY_PIP_TREE_STRUCTURE
1475 "=== DECISION: THEN BRANCH NOW UNFEASIBLE\n");
1477 "==> merge else branch with parent.\n");
1484 PPL_ASSERT(node->
OK());
1487 else if (check_feasible_context) {
1493 ci_end = cs.
end(); ci != ci_end; ++ci) {
1497 complement_assign(last, last, 1);
1505 #ifdef NOISY_PIP_TREE_STRUCTURE
1507 "=== DECISION: NO BRANCHING CONSTRAINTS LEFT\n");
1509 "==> merge then branch with parent.\n");
1516 PPL_ASSERT(node->
OK());
1530 s <<
"\ntrue_child: ";
1531 if (true_child == 0) {
1543 PPL_ASSERT(sol != 0);
1549 s <<
"\nfalse_child: ";
1550 if (false_child == 0) {
1564 PPL_ASSERT(sol != 0);
1584 if (!(s >> str) || str !=
"true_child:") {
1590 if (str ==
"BOTTOM") {
1594 else if (str ==
"DECISION") {
1601 else if (str ==
"SOLUTION") {
1618 if (!(s >> str) || str !=
"false_child:") {
1624 if (str ==
"BOTTOM") {
1627 else if (str ==
"DECISION") {
1635 else if (str ==
"SOLUTION") {
1666 const Row& s_i = s[i];
1668 j = s_i.
begin(), j_end = s_i.
end(); j != j_end; ++j) {
1669 Coefficient_traits::const_reference s_ij = *j;
1679 const Row& t_i = t[i];
1681 j = t_i.
begin(), j_end = t_i.
end(); j != j_end; ++j) {
1682 Coefficient_traits::const_reference t_ij = *j;
1692 PPL_ASSERT(gcd > 1);
1734 const std::vector<bool>& basis,
1741 const Row& s_0 = s[row_0];
1742 const Row& s_1 = s[row_1];
1743 Coefficient_traits::const_reference s_0_0 = s_0.
get(col_0);
1744 Coefficient_traits::const_reference s_1_1 = s_1.
get(col_1);
1745 const Row& t_0 = t[row_0];
1746 const Row& t_1 = t[row_1];
1758 const Row& s_i = s[i];
1759 Coefficient_traits::const_reference s_i_col_0 = s_i.
get(col_0);
1760 Coefficient_traits::const_reference s_i_col_1 = s_i.
get(col_1);
1763 while (j0 != j0_end && j1 != j1_end) {
1766 product_0 = (*j0) * s_1_1 * s_i_col_0;
1767 product_1 = (*j1) * s_0_0 * s_i_col_1;
1768 if (product_0 != product_1) {
1770 j_mismatch = j0.
index();
1778 if (*j0 != 0 && s_1_1 != 0 && s_i_col_0 != 0) {
1780 j_mismatch = j0.
index();
1787 if (*j1 != 0 && s_0_0 != 0 && s_i_col_1 != 0) {
1789 j_mismatch = j1.
index();
1795 while (j0 != j0_end) {
1796 if (*j0 != 0 && s_1_1 != 0 && s_i_col_0 != 0) {
1798 j_mismatch = j0.
index();
1803 while (j1 != j1_end) {
1804 if (*j1 != 0 && s_0_0 != 0 && s_i_col_1 != 0) {
1806 j_mismatch = j1.
index();
1813 return (j_mismatch != num_params)
1814 && column_lower(s, mapping, basis, s_0, col_0, s_1, col_1, *j0, *j1);
1819 s <<
"constraints_\n";
1823 s <<
"\nartificial_parameters( " << artificial_parameters_size <<
" )\n";
1824 for (
dimension_type i = 0; i < artificial_parameters_size; ++i) {
1832 if (!(s >> str) || str !=
"constraints_") {
1837 if (!(s >> str) || str !=
"artificial_parameters(") {
1842 if (!(s >> artificial_parameters_size)) {
1846 if (!(s >> str) || str !=
")") {
1850 for (
dimension_type i = 0; i < artificial_parameters_size; ++i) {
1874 os <<
"denominator " << denom <<
"\n";
1877 os <<
"parameters ";
1884 if (!(is >> str) || str !=
"denominator") {
1892 if (!(is >> str) || str !=
"variables") {
1895 if (!s.ascii_load(is)) {
1898 if (!(is >> str) || str !=
"parameters") {
1901 if (!t.ascii_load(is)) {
1912 os <<
"\ntableau\n";
1913 tableau.ascii_dump(os);
1919 os << (basis[i] ?
" true" :
" false");
1926 os <<
" " << mapping[i];
1936 os <<
"\nvar_column ";
1938 os << var_column_size;
1974 os <<
"solution " << solution_size <<
"\n";
1980 os <<
"solution_valid " << (
solution_valid ?
"true" :
"false") <<
"\n";
1990 if (!(is >> str) || str !=
"tableau") {
1993 if (!tableau.ascii_load(is)) {
1996 if (!(is >> str) || str !=
"basis") {
2000 if (!(is >> basis_size)) {
2009 if (str ==
"true") {
2012 else if (str !=
"false") {
2015 basis.push_back(val);
2018 if (!(is >> str) || str !=
"mapping") {
2022 if (!(is >> mapping_size)) {
2031 mapping.push_back(val);
2034 if (!(is >> str) || str !=
"var_row") {
2038 if (!(is >> var_row_size)) {
2050 if (!(is >> str) || str !=
"var_column") {
2054 if (!(is >> var_column_size)) {
2066 if (!(is >> str) || str !=
"special_equality_row") {
2073 if (!(is >> str) || str !=
"big_dimension") {
2080 if (!(is >> str) || str !=
"sign") {
2084 if (!(is >> sign_size)) {
2094 if (str ==
"UNKNOWN") {
2097 else if (str ==
"ZERO") {
2100 else if (str ==
"POSITIVE") {
2103 else if (str ==
"NEGATIVE") {
2106 else if (str ==
"MIXED") {
2112 sign.push_back(val);
2115 if (!(is >> str) || str !=
"solution") {
2119 if (!(is >> solution_size)) {
2131 if (!(is >> str) || str !=
"solution_valid") {
2137 if (str ==
"true") {
2140 else if (str ==
"false") {
2157 Coefficient_traits::const_reference x_big = x.
get(big_dimension);
2169 Coefficient_traits::const_reference x_i = *i;
2202 std::vector<Coefficient> scaling(num_rows, 1);
2203 std::vector<bool>
basis;
2204 basis.reserve(num_vars + num_rows);
2205 std::vector<dimension_type>
mapping;
2206 mapping.reserve(num_vars + num_rows);
2207 std::vector<dimension_type>
var_row;
2208 var_row.reserve(num_rows);
2210 var_column.reserve(num_columns);
2215 basis.push_back(
true);
2216 mapping.push_back(j);
2217 var_column.push_back(j - 1);
2220 basis.push_back(
false);
2221 mapping.push_back(i);
2222 var_row.push_back(i + num_vars);
2245 const bool found_positive_pivot_candidate
2246 = compatibility_check_find_pivot(s, mapping, basis, pi, pj);
2248 if (!found_positive_pivot_candidate) {
2256 bool all_integer_vars =
true;
2268 Coefficient_traits::const_reference denom = scaling[mi];
2269 if (s[mi].
get(0) % denom == 0) {
2273 all_integer_vars =
false;
2275 var_row.push_back(mapping.size());
2276 basis.push_back(
false);
2277 mapping.push_back(num_rows);
2279 Row& cut = s[num_rows];
2281 const Row& s_mi = s[mi];
2284 j = cut.
begin(), j_end = cut.
end(); j != j_end; ++j) {
2286 pos_rem_assign(*j, *j, denom);
2289 scaling.push_back(denom);
2292 if (all_integer_vars) {
2304 row_normalize(s[i], scaling[i]);
2311 var_row[pi] = var_pj;
2312 var_column[pj] = var_pi;
2313 basis[var_pi] =
true;
2314 basis[var_pj] =
false;
2315 mapping[var_pi] = pj;
2316 mapping[var_pj] = pi;
2321 Row& pivot = s[num_rows];
2329 pivot_denom = scaling[pi];
2333 Coefficient_traits::const_reference pivot_pj = pivot.
get(pj);
2336 j = pivot.
begin(), j_end = pivot.
end(); j != j_end; ++j) {
2337 if (j.index() == pj) {
2340 Coefficient_traits::const_reference pivot_j = *j;
2349 product = s_i.
get(pj) * pivot_j;
2350 if (product % pivot_pj != 0) {
2356 k = s_i.
begin(), k_end = s_i.
end(); k != k_end; ++k) {
2360 product *= scale_factor;
2361 scaling[i] *= scale_factor;
2363 PPL_ASSERT(product % pivot_pj == 0);
2365 s_i[j.index()] -= product;
2371 if (pivot_pj != pivot_denom) {
2376 product = s_i_pj * pivot_denom;
2377 if (product % pivot_pj != 0) {
2383 k = s_i.
begin(), k_end = s_i.
end(); k != k_end; ++k) {
2387 product *= scale_factor;
2388 scaling[i] *= scale_factor;
2390 PPL_ASSERT(product % pivot_pj == 0);
2413 if (tableau.t.num_columns() == 0) {
2414 tableau.t.add_zero_columns(1);
2424 const dimension_type num_added_params = new_num_params - old_num_params;
2425 const dimension_type num_added_vars = num_added_dims - num_added_params;
2428 if (num_added_vars > 0) {
2429 tableau.s.add_zero_columns(num_added_vars);
2432 if (num_added_params > 0) {
2433 tableau.t.add_zero_columns(num_added_params, old_num_params + 1);
2437 const dimension_type initial_space_dim = old_num_vars + old_num_params;
2438 for (
dimension_type i = initial_space_dim; i < external_space_dim; ++i) {
2439 if (parameters.count(i) == 0) {
2441 if (tableau.s.num_rows() == 0) {
2443 basis.push_back(
true);
2444 mapping.push_back(new_var_column);
2452 mapping.insert(
nth_iter(mapping, new_var_column), new_var_column);
2455 if (
var_row[j] >= new_var_column) {
2476 Variables_Set::const_iterator pos
2479 +
static_cast<dimension_type>(std::distance(parameters.begin(), pos));
2482 Coefficient_traits::const_reference denom = tableau.denominator();
2484 for (Constraint_Sequence::const_iterator
2485 c_iter =
nth_iter(input_cs, first_pending_constraint),
2486 c_end = input_cs.end(); c_iter != c_end; ++c_iter) {
2491 tableau.s.add_zero_rows(1);
2492 tableau.t.add_zero_rows(1);
2493 Row& v_row = tableau.s[row_id];
2494 Row& p_row = tableau.t[row_id];
2519 i = e.
begin(), i_end = e.
end(); i != i_end; ++i) {
2521 if (dim != last_dim + 1) {
2525 = std::distance(parameters.lower_bound(last_dim),
2526 parameters.lower_bound(dim - 1));
2529 v_index += (num_skipped - n);
2531 PPL_ASSERT(p_index + v_index == i.variable().id() + 1);
2532 const bool is_parameter = (1 == parameters.count(dim - 1));
2533 Coefficient_traits::const_reference coeff_i = *i;
2537 p_row.
insert(p_index, coeff_i * denom);
2542 if (basis[v_index]) {
2548 add_mul_assign_row(v_row, coeff_i, tableau.s[mv]);
2549 add_mul_assign_row(p_row, coeff_i, tableau.t[mv]);
2561 tableau.s.remove_trailing_rows(1);
2562 tableau.t.remove_trailing_rows(1);
2567 basis.push_back(
false);
2568 mapping.push_back(row_id);
2579 tableau.s.add_zero_rows(1);
2580 tableau.t.add_zero_rows(1);
2583 neg_assign_row(tableau.s[1 + row_id], tableau.s[row_id]);
2584 neg_assign_row(tableau.t[1 + row_id], tableau.t[row_id]);
2586 special_equality_row = mapping.size();
2587 basis.push_back(
false);
2588 mapping.push_back(1 + row_id);
2589 var_row.push_back(1 + var_id);
2606 const bool check_feasible_context,
2610 const int indent_level) {
2611 PPL_ASSERT(indent_level >= 0);
2612 #ifdef NOISY_PIP_TREE_STRUCTURE
2623 add_artificial_parameters(ctx, all_params, space_dim, num_art_params);
2627 if (check_feasible_context) {
2649 Coefficient_traits::const_reference tableau_denom = tableau.denominator();
2651 #ifdef VERY_NOISY_PIP
2652 tableau.ascii_dump(std::cerr);
2653 std::cerr <<
"context ";
2655 #endif // #ifdef VERY_NOISY_PIP
2668 if (sign_i ==
NEGATIVE && first_negative == not_a_dim) {
2671 else if (sign_i ==
MIXED && first_mixed == not_a_dim) {
2678 if (first_negative == not_a_dim && first_mixed != not_a_dim) {
2684 const Row& t_i = tableau.t[i];
2692 Row t_i_complement(num_params);
2693 complement_assign(t_i_complement, t_i, tableau_denom);
2700 if (new_sign ==
NEGATIVE && first_negative == not_a_dim) {
2702 if (i == first_mixed) {
2703 first_mixed = not_a_dim;
2706 else if (new_sign ==
MIXED) {
2707 if (first_mixed == not_a_dim) {
2711 else if (i == first_mixed) {
2712 first_mixed = not_a_dim;
2722 if (first_negative == not_a_dim && first_mixed != not_a_dim) {
2730 const Row& s_i = tableau.s[i];
2731 bool has_positive =
false;
2734 j = s_i.
begin(), j_end = s_i.
end(); j != j_end; ++j) {
2736 has_positive =
true;
2741 if (!has_positive) {
2745 Row row(tableau.t[i]);
2748 pos_rem_assign(mod, row0, tableau_denom);
2749 row0 -= (mod == 0) ? tableau_denom : mod;
2755 if (first_mixed == not_a_dim) {
2762 if (first_negative == not_a_dim) {
2765 if (first_mixed == i) {
2766 first_mixed = not_a_dim;
2772 #ifdef VERY_NOISY_PIP
2773 std::cerr <<
"sign =";
2775 std::cerr <<
" " <<
"?0+-*"[
sign[i]];
2776 std::cerr << std::endl;
2777 #endif // #ifdef VERY_NOISY_PIP
2781 if (first_negative != not_a_dim) {
2791 if (!find_lexico_minimal_column(tableau.s, mapping, basis,
2792 tableau.s[i], 0, j)) {
2794 #ifdef NOISY_PIP_TREE_STRUCTURE
2796 "No positive pivot: Solution = _|_\n");
2797 #endif // #ifdef NOISY_PIP_TREE_STRUCTURE
2802 || tableau.is_better_pivot(mapping, basis, i, j, pi, pj)) {
2814 #ifdef VERY_NOISY_PIP
2815 std::cerr <<
"Pivot (pi, pj) = (" << pi <<
", " << pj <<
")\n";
2816 #endif // #ifdef VERY_NOISY_PIP
2819 tableau.normalize();
2829 basis[var_pi] =
true;
2830 basis[var_pj] =
false;
2831 mapping[var_pi] = pj;
2832 mapping[var_pj] = pi;
2841 tableau.s.add_zero_rows(1);
2842 tableau.t.add_zero_rows(1);
2846 swap(s_pivot, tableau.s[num_rows]);
2847 swap(t_pivot, tableau.t[num_rows]);
2849 tableau.s.remove_trailing_rows(1);
2850 tableau.t.remove_trailing_rows(1);
2854 pivot_denom = tableau.denominator();
2856 s_pivot[pj] = pivot_denom;
2859 s_pivot.
m_swap(tableau.s[pi]);
2860 t_pivot.
m_swap(tableau.t[pi]);
2864 s_pivot_pj = s_pivot.
get(pj);
2872 Row& s_i = tableau.s[i];
2874 s_i_pj = s_i.
get(pj);
2883 j = s_pivot.
begin(), j_end = s_pivot.
end(); j != j_end; ++j) {
2884 if (j.index() != pj) {
2885 Coefficient_traits::const_reference s_pivot_j = *j;
2887 if (s_pivot_j != 0) {
2888 product = s_pivot_j * s_i_pj;
2889 if (product % s_pivot_pj != 0) {
2893 tableau.scale(scale_factor);
2894 s_i_pj *= scale_factor;
2895 product *= scale_factor;
2898 PPL_ASSERT(product % s_pivot_pj == 0);
2917 Row& s_i = tableau.s[i];
2918 Row& t_i = tableau.t[i];
2922 if (s_i_pj_itr == s_i.
end()) {
2939 j = t_pivot.
begin(), j_end = t_pivot.
end(); j != j_end; ++j) {
2940 Coefficient_traits::const_reference t_pivot_j = *j;
2942 if (t_pivot_j != 0) {
2943 product = t_pivot_j * s_i_pj;
2944 if (product % s_pivot_pj != 0) {
2948 tableau.scale(scale_factor);
2949 product *= scale_factor;
2952 PPL_ASSERT(product % s_pivot_pj == 0);
2968 else if (product < 0) {
2991 if (s_pivot_pj != pivot_denom) {
2995 Row& s_i = tableau.s[i];
2997 if (itr == s_i.
end()) {
3001 product = *itr * pivot_denom;
3002 if (product % s_pivot_pj != 0) {
3006 tableau.scale(scale_factor);
3007 product *= scale_factor;
3010 PPL_ASSERT(product % s_pivot_pj == 0);
3011 if (product != 0 || *itr != 0) {
3023 PPL_ASSERT(first_negative == not_a_dim);
3026 if (first_mixed != not_a_dim) {
3040 bool has_positive =
false;
3042 const Row& s_i = tableau.s[i];
3044 j = s_i.
begin(), j_end = s_i.
end(); j != j_end; ++j) {
3046 has_positive =
true;
3059 const Row& t_i = tableau.t[i];
3061 j = t_i.
begin(), j_end = t_i.
end(); j != j_end; ++j) {
3066 if (i_neg == not_a_dim || score < best_score) {
3072 if (i_neg != not_a_dim) {
3073 Row tautology = tableau.t[i_neg];
3075 integral_simplification(tautology);
3083 for (Variables_Set::const_iterator p = all_params.begin(),
3084 p_end = all_params.end(); p != p_end; ++p, ++j)
3086 using namespace IO_Operators;
3087 std::cerr << std::setw(2 * indent_level) <<
""
3089 <<
": mixed param sign, negative var coeffs\n";
3090 std::cerr << std::setw(2 * indent_level) <<
""
3091 <<
"==> adding tautology: "
3094 #endif // #ifdef NOISY_PIP
3099 PPL_ASSERT(i_neg == not_a_dim);
3109 const Row& t_i = tableau.t[i];
3111 j = t_i.
begin(), j_end = t_i.
end(); j != j_end; ++j) {
3116 if (best_i == not_a_dim || score < best_score) {
3122 Row t_test(tableau.t[best_i]);
3124 integral_simplification(t_test);
3130 for (Variables_Set::const_iterator p = all_params.begin(),
3131 p_end = all_params.end(); p != p_end; ++p, ++j)
3133 using namespace IO_Operators;
3134 std::cerr << std::setw(2 * indent_level) <<
""
3135 <<
"Row " << best_i <<
": mixed param sign\n";
3136 std::cerr << std::setw(2 * indent_level) <<
""
3137 <<
"==> depends on sign of " << expr <<
".\n";
3139 #endif // #ifdef NOISY_PIP
3144 std::auto_ptr<PIP_Tree_Node> wrapped_node(t_node);
3149 #ifdef NOISY_PIP_TREE_STRUCTURE
3152 t_node = t_node->
solve(pip, check_feasible_context,
3153 ctx, all_params, space_dim,
3156 if (t_node != wrapped_node.get()) {
3157 wrapped_node.release();
3158 wrapped_node.reset(t_node);
3171 complement_assign(f_test, t_test, 1);
3174 #ifdef NOISY_PIP_TREE_STRUCTURE
3177 f_node = f_node->
solve(pip, check_feasible_context,
3178 ctx, all_params, space_dim,
3185 #ifdef NOISY_PIP_TREE_STRUCTURE
3187 "=== EXIT: BOTH BRANCHES UNFEASIBLE: _|_\n");
3194 PPL_ASSERT(f_node ==
this);
3199 #ifdef NOISY_PIP_TREE_STRUCTURE
3201 "=== EXIT: THEN BRANCH UNFEASIBLE: SWAP BRANCHES\n");
3206 else if (f_node == 0) {
3208 #ifdef NOISY_PIP_TREE_STRUCTURE
3210 "=== EXIT: THEN BRANCH FEASIBLE\n");
3219 if (decision_node_p != 0 && decision_node_p->
false_child != 0) {
3225 wrapped_node.release();
3226 wrapped_node.reset(parent);
3234 return wrapped_node.release();
3245 aps.insert(aps.end(),
3255 return wrapped_node.release();
3261 #ifdef NOISY_PIP_TREE_STRUCTURE
3263 "=== EXIT: BOTH BRANCHES FEASIBLE: NEW DECISION NODE\n");
3269 wrapped_node.release();
3270 wrapped_node.reset(parent);
3276 #ifdef NOISY_PIP_TREE_STRUCTURE
3278 "=== NODE HAS BOTH BRANCHES AND TAUTOLOGIES:\n");
3280 "=== CREATE NEW PARENT FOR TAUTOLOGIES\n");
3287 wrapped_node.release();
3288 wrapped_node.reset(parent);
3294 return wrapped_node.release();
3298 PPL_ASSERT(first_negative == not_a_dim);
3299 PPL_ASSERT(first_mixed == not_a_dim);
3306 "All parameters are positive.\n");
3307 #endif // #ifdef NOISY_PIP
3308 tableau.normalize();
3311 Coefficient_traits::const_reference denom = tableau.denominator();
3318 const Row& t_i = tableau.t[i];
3321 j = t_i.
begin(), j_end = t_i.
end(); j != j_end; ++j) {
3323 if (*j % denom != 0) {
3329 #ifdef NOISY_PIP_TREE_STRUCTURE
3331 "EXIT: solution found.\n");
3332 #endif // #ifdef NOISY_PIP
3354 const Row& t_i = tableau.t[i];
3356 j = t_i.
begin(), j_end = t_i.
end(); j != j_end; ++j) {
3358 pos_rem_assign(mod, *j, denom);
3363 if (pcount > 0 && (best_i == not_a_dim || pcount < best_pcount)) {
3364 best_pcount = pcount;
3369 generate_cut(best_i, all_params, ctx, space_dim, indent_level);
3380 std::vector<dimension_type> all_best_is;
3392 const Row& t_i = tableau.t[i];
3394 j = t_i.
begin(), j_end = t_i.
end(); j != j_end; ++j) {
3396 pos_rem_assign(mod, *j, denom);
3410 const Row& s_i = tableau.s[i];
3412 j = s_i.
begin(), j_end = s_i.
end(); j != j_end; ++j) {
3414 pos_rem_assign(mod, *j, denom);
3429 && (best_i == not_a_dim
3430 || pcount < best_pcount
3431 || (pcount == best_pcount && score > best_score))) {
3432 if (pcount < best_pcount) {
3433 all_best_is.clear();
3436 best_pcount = pcount;
3440 all_best_is.push_back(i);
3444 generate_cut(best_i, all_params, ctx, space_dim, indent_level);
3450 space_dim, indent_level);
3467 const int indent_level) {
3468 PPL_ASSERT(indent_level >= 0);
3470 std::cerr << std::setw(2 * indent_level) <<
""
3471 <<
"Row " << index <<
" requires cut generation.\n";
3474 #endif // #ifdef NOISY_PIP
3477 PPL_ASSERT(index < num_rows);
3480 PPL_ASSERT(num_params == 1 + parameters.size());
3481 Coefficient_traits::const_reference denom = tableau.denominator();
3487 bool generate_parametric_cut =
false;
3490 const Row& row_t = tableau.t[index];
3494 if (j != j_end && j.
index() == 0) {
3498 for ( ; j != j_end; ++j) {
3500 if (*j % denom != 0) {
3501 generate_parametric_cut =
true;
3510 if (generate_parametric_cut) {
3512 bool reuse_ap =
false;
3517 const Row& row_t = tableau.t[index];
3520 if (j != j_end && j.
index() == 0) {
3521 pos_rem_assign(mod, *j, denom);
3529 if (!parameters.empty()) {
3532 Variables_Set::const_iterator p_j = parameters.begin();
3535 for ( ; j != j_end; ++j) {
3537 pos_rem_assign(mod, *j, denom);
3541 coeff = denom - mod;
3542 PPL_ASSERT(last_index <= j.
index());
3543 std::advance(p_j, j.
index() - last_index);
3544 last_index = j.
index();
3554 ap_column = space_dimension;
3565 }
while (!reuse_ap && node != 0);
3570 using namespace IO_Operators;
3571 std::cerr << std::setw(2 * indent_level) <<
""
3572 <<
"Re-using parameter " <<
Variable(ap_column)
3573 <<
" = " << ap << std::endl;
3574 #endif // #ifdef NOISY_PIP
3575 ap_column = ap_column - num_vars + 1;
3580 tableau.t.add_zero_columns(1);
3583 parameters.
insert(space_dimension);
3585 using namespace IO_Operators;
3586 std::cerr << std::setw(2 * indent_level) <<
""
3587 <<
"New parameter " <<
Variable(space_dimension)
3588 <<
" = " << ap << std::endl;
3589 #endif // #ifdef NOISY_PIP
3591 ap_column = num_params;
3596 Row& ctx1 = context[ctx_num_rows];
3597 Row& ctx2 = context[ctx_num_rows+1];
3599 const Row& row_t = tableau.t[index];
3605 if (j != j_end && j.
index() == 0) {
3606 pos_rem_assign(mod, *j, denom);
3608 itr1 = ctx1.
insert(0, denom);
3610 itr2 = ctx2.
insert(0, *itr1);
3618 itr2 = ctx2.
insert(0, denom);
3625 itr2 = ctx2.
insert(0, denom);
3629 for ( ; j != j_end; ++j) {
3630 pos_rem_assign(mod, *j, denom);
3633 itr1 = ctx1.
insert(itr1, j_index, denom);
3635 itr2 = ctx2.
insert(itr2, j_index, *itr1);
3640 itr1 = ctx1.
insert(itr1, num_params, denom);
3642 itr2 = ctx2.
insert(itr2, num_params, denom);
3648 using namespace IO_Operators;
3649 Variables_Set::const_iterator p = parameters.begin();
3656 std::cerr << std::setw(2 * indent_level) <<
""
3657 <<
"Adding to context: "
3661 #endif // #ifdef NOISY_PIP
3666 tableau.s.add_zero_rows(1);
3667 tableau.t.add_zero_rows(1);
3668 Row& cut_s = tableau.s[num_rows];
3669 Row& cut_t = tableau.t[num_rows];
3671 const Row& row_s = tableau.s[index];
3672 const Row& row_t = tableau.t[index];
3677 j = row_s.
begin(), j_end = row_s.
end(); j != j_end; ++j) {
3680 pos_rem_assign(*itr, *itr, denom);
3686 j = row_t.
begin(), j_end = row_t.
end(); j!=j_end; ++j) {
3688 pos_rem_assign(mod, *j, denom);
3691 cut_t_itr = cut_t.
insert(cut_t_itr, j.
index(), mod);
3692 *cut_t_itr -= denom;
3698 cut_t[ap_column] = denom;
3702 using namespace IO_Operators;
3707 if (parameters.count(j) == 1) {
3716 std::cerr << std::setw(2 * indent_level) <<
""
3721 #endif // #ifdef NOISY_PIP
3722 var_row.push_back(num_rows + num_vars);
3723 basis.push_back(
false);
3724 mapping.push_back(num_rows);
3745 for (Artificial_Parameter_Sequence::const_iterator
3748 n += (ap->external_memory_in_bytes());
3757 PPL_ASSERT(true_child != 0);
3758 n += true_child->total_memory_in_bytes();
3759 if (false_child != 0) {
3760 n += false_child->total_memory_in_bytes();
3773 + s.external_memory_in_bytes()
3774 + t.external_memory_in_bytes();
3780 n += tableau.external_memory_in_bytes();
3782 n += basis.capacity() *
sizeof(
bool);
3788 for (std::vector<Linear_Expression>::const_iterator
3791 n += (i->external_memory_in_bytes());
3806 PPL_ASSERT(indent >= 0);
3807 s << std::setw(2 * indent) <<
"" << str;
3815 std::vector<bool> pip_dim_is_param(pip_space_dim);
3816 for (Variables_Set::const_iterator p = pip_params.begin(),
3817 p_end = pip_params.end(); p != p_end; ++p) {
3818 pip_dim_is_param[*p] =
true;
3823 node != 0; node = node->
parent()) {
3824 first_art_dim += node->art_parameter_count();
3827 print_tree(s, indent, pip_dim_is_param, first_art_dim);
3832 const std::vector<bool>&,
3834 using namespace IO_Operators;
3837 for (Artificial_Parameter_Sequence::const_iterator
3841 s <<
Variable(first_art_dim) <<
" = " << *api <<
"\n";
3851 PPL_ASSERT(ci != ci_end);
3853 for (++ci; ci != ci_end; ++ci) {
3854 s <<
" and " << *ci;
3863 const std::vector<bool>& pip_dim_is_param,
3872 PPL_ASSERT(true_child != 0);
3873 true_child->print_tree(s, indent+1, pip_dim_is_param, child_first_art_dim);
3877 if (false_child != 0) {
3878 false_child->print_tree(s, indent+1, pip_dim_is_param,
3879 child_first_art_dim);
3888 const std::vector<bool>& pip_dim_is_param,
3900 for (
dimension_type i = 0, num_var = 0; i < pip_space_dim; ++i) {
3901 if (pip_dim_is_param[i]) {
3907 using namespace IO_Operators;
3913 if (!no_constraints) {
3922 PPL_ASSERT(pip != 0);
3926 std::ostringstream s;
3927 s <<
"PPL::PIP_Solution_Node::parametric_values(v):\n"
3929 <<
" is incompatible with the owning PIP_Problem "
3930 <<
" (space dim == " << space_dim <<
").";
3931 throw std::invalid_argument(s.str());
3936 for (Variables_Set::const_iterator p = params.begin(),
3937 p_end = params.end(); p != p_end; ++p) {
3939 if (param_index < var.
id()) {
3942 else if (param_index == var.
id()) {
3943 throw std::invalid_argument(
"PPL::PIP_Solution_Node"
3944 "::parametric_values(v):\n"
3945 "v is a problem parameter.");
3964 PPL_ASSERT(pip != 0);
3967 for (Variables_Set::const_iterator p = params.begin(),
3968 p_end = params.end(); p != p_end; ++p) {
3969 pip_dim_is_param[*p] =
true;
3988 const dimension_type num_pip_params = num_pip_dims - num_pip_vars;
3989 const dimension_type num_all_params = tableau.t.num_columns() - 1;
3990 const dimension_type num_art_params = num_all_params - num_pip_params;
3992 if (
solution.size() != num_pip_vars) {
3997 std::vector<dimension_type> all_param_names(num_all_params);
4001 if (pip_dim_is_param[i]) {
4002 all_param_names[p_index] = i;
4008 all_param_names[num_pip_params + i] = num_pip_dims + i;
4013 Coefficient_traits::const_reference denom = tableau.denominator();
4020 const Row& row = tableau.t[mapping[i]];
4026 if (j != j_end && j.
index() == 0) {
4029 for ( ; j != j_end; ++j) {
4030 Coefficient_traits::const_reference coeff = *j;
4034 norm_coeff = coeff / denom;
4035 if (norm_coeff != 0) {
4040 norm_coeff = row.
get(0) / denom;
4041 sol_i += norm_coeff;
Artificial_Parameter_Sequence::const_iterator art_parameter_begin() const
Returns a const_iterator to the beginning of local artificial parameters.
const PIP_Problem * owner_
A pointer to the PIP_Problem object owning this node.
virtual void print_tree(std::ostream &s, int indent, const std::vector< bool > &pip_dim_is_param, dimension_type first_art_dim) const
Prints on s the tree rooted in *this.
dimension_type index() const
Returns the index of the element pointed to by *this.
bool operator==(const Artificial_Parameter &y) const
Returns true if and only if *this and y are equal.
Coefficient denom
The normalized (i.e., positive) denominator.
An iterator over a system of constraints.
std::vector< dimension_type > var_column
The variable identifiers associated to the columns of the simplex tableau.
iterator find(dimension_type i)
Looks for an element with index i.
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.
Artificial parameters in PIP solution trees.
dimension_type internal_space_dim
The space dimension of the current (partial) solution of the PIP problem; it may be smaller than exte...
bool operator!=(const Artificial_Parameter &y) const
Returns true if and only if *this and y are different.
static bool compatibility_check(Matrix< Row > &s)
Checks whether a context matrix is satisfiable.
A linear equality or inequality.
virtual void set_owner(const PIP_Problem *owner)
Sets the pointer to the PIP_Problem owning object.
virtual memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
bool is_equality() const
Returns true if and only if *this is an equality constraint.
void swap(CO_Tree &x, CO_Tree &y)
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.
virtual void set_owner(const PIP_Problem *owner)
Sets the pointer to the PIP_Problem owning object.
void generate_cut(dimension_type index, Variables_Set ¶meters, Matrix< Row > &context, dimension_type &space_dimension, int indent_level)
Generate a Gomory cut using non-integer tableau row index.
size_t dimension_type
An unsigned integral type for representing space dimensions.
PIP_Tree_Node * false_child
Pointer to the "false" child of *this.
An std::set of variables' indexes.
Always generate all possible cuts.
bool ascii_load(std::istream &s)
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this ...
virtual bool OK() const
Returns true if and only if *this is well formed.
const PIP_Decision_Node * parent() const
Returns a pointer to this node's parent.
bool ascii_load(std::istream &s)
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this ...
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
void m_swap(Sparse_Row &x)
Swaps *this and x.
const Linear_Expression & parametric_values(Variable var) const
Returns a parametric expression for the values of problem variable var.
virtual void set_owner(const PIP_Problem *owner)=0
Sets the pointer to the PIP_Problem owning object.
dimension_type not_a_dimension()
Returns a value that does not designate a valid dimension.
dimension_type external_space_dim
The dimension of the vector space.
virtual memory_size_type total_memory_in_bytes() const
Returns the total size in bytes of the memory occupied by *this.
CO_Tree::iterator iterator
An iterator on the row elements.
void add_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
std::ostream & operator<<(std::ostream &s, const Ask_Tell< D > &x)
void ascii_dump(std::ostream &os) const
Dumps to os an ASCII representation of *this.
static Row_Sign row_sign(const Row &x, dimension_type big_dimension)
Returns the sign of row x.
A sparse matrix of Coefficient.
dimension_type special_equality_row
The variable number of the special inequality used for modeling equality constraints.
void insert(const Constraint &c)
Inserts in *this a copy of the constraint c, increasing the number of space dimensions if needed...
dimension_type num_constraints(const Constraint_System &cs)
Helper returning number of constraints in system.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
bool ascii_load(std::istream &is)
Loads from is an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this...
const PIP_Problem * get_owner() const
Returns a pointer to the PIP_Problem owning object.
A finite sparse sequence of coefficients.
PIP_Tree_Node(const PIP_Problem *owner)
Constructor: builds a node owned by *owner.
dimension_type big_dimension
The column index in the parametric part of the simplex tableau corresponding to the big parameter; no...
virtual memory_size_type external_memory_in_bytes() const =0
Returns the size in bytes of the memory managed by *this.
dimension_type space_dimension() const
Returns the space dimension of the PIP problem.
Choose the first row with negative parameter sign.
An iterator on the tree elements, ordered by key.
const iterator & end()
Returns an iterator that points after the last stored element.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
#define WEIGHT_ADD(delta)
PIP_Solution_Node(const PIP_Problem *owner)
Constructor: builds a solution node owned by *owner.
virtual ~PIP_Decision_Node()
Destructor.
const_iterator begin() const
Returns the const_iterator pointing to the first constraint, if *this is not empty; otherwise...
bool solution_valid
An indicator for solution validity.
A Parametric Integer (linear) Programming problem.
void exact_div_assign(Checked_Number< T, Policy > &x, const Checked_Number< T, Policy > &y, const Checked_Number< T, Policy > &z)
virtual PIP_Tree_Node * clone() const =0
Returns a pointer to a dynamically-allocated copy of *this.
Coefficient gcd(dimension_type start, dimension_type end) const
Returns the gcd of the nonzero coefficients in [start,end). If all the coefficients in this range are...
Not computed yet (default).
bool is_equal_to(const Linear_Expression &x) const
Artificial_Parameter_Sequence::const_iterator art_parameter_end() const
Returns a const_iterator to the end of local artificial parameters.
RA_Container::iterator nth_iter(RA_Container &cont, dimension_type n)
dimension_type id() const
Returns the index of the Cartesian axis associated to the variable.
virtual PIP_Tree_Node * clone() const
Returns a pointer to a dynamically-allocated copy of *this.
void add_zero_rows(dimension_type n)
Adds to the matrix n rows of zeroes.
A tree node representing a decision in the space of solutions.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
The row contains both positive and negative coefficients.
A dimension of the vector space.
All nonzero row coefficients are negative.
bool is_strict_inequality() const
Returns true if and only if *this is a strict inequality constraint.
virtual void print_tree(std::ostream &s, int indent, const std::vector< bool > &pip_dim_is_param, dimension_type first_art_dim) const
Prints on s the tree rooted in *this.
std::vector< Artificial_Parameter > Artificial_Parameter_Sequence
A type alias for a sequence of Artificial_Parameter's.
std::vector< dimension_type > var_row
The variable identifiers associated to the rows of the simplex tableau.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
virtual bool check_ownership(const PIP_Problem *owner) const =0
Returns true if and only if all the nodes in the subtree rooted in *this are owned by *owner...
friend class PIP_Decision_Node
void ascii_dump(std::ostream &s) const
Dumps to s an ASCII representation of *this.
PIP_Decision_Node(const PIP_Problem *owner, PIP_Tree_Node *fcp, PIP_Tree_Node *tcp)
Builds a decision node having fcp and tcp as child.
dimension_type art_parameter_count() const
Returns the number of local artificial parameters.
bool OK() const
Returns true if and only if *this is well formed.
void parent_merge()
Merges parent's artificial parameters into *this.
virtual ~PIP_Tree_Node()
Destructor.
Control_Parameter_Value control_parameters[CONTROL_PARAMETER_NAME_SIZE]
The control parameters for the problem object.
Control_Parameter_Value
Possible values for PIP_Problem control parameters.
const Variables_Set & parameter_space_dimensions() const
Returns a set containing all the variables' indexes representing the parameters of the PIP problem...
virtual void print_tree(std::ostream &s, int indent, const std::vector< bool > &pip_dim_is_param, dimension_type first_art_dim) const =0
Prints on s the tree rooted in *this.
Choose row which generates the deepest cut.
virtual PIP_Tree_Node * solve(const PIP_Problem &pip, bool check_feasible_context, const Matrix< Row > &context, const Variables_Set ¶ms, dimension_type space_dim, int indent_level)
Implements pure virtual method PIP_Tree_Node::solve.
virtual bool OK() const =0
Returns true if and only if *this is well formed.
void add_row(const Row &x)
Adds a copy of the row x at the end of the matrix.
bool ascii_load(std::istream &s)
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this ...
memory_size_type total_memory_in_bytes() const
Returns the total size in bytes of the memory occupied by *this.
bool OK() const
Returns true if and only if the parameter is well-formed.
bool empty() const
Returns true if and only if *this has no constraints.
dimension_type num_columns() const
Returns the number of columns in the matrix.
bool operator<(const Ptr_Iterator< P > &x, const Ptr_Iterator< Q > &y)
std::vector< dimension_type > mapping
A mapping between the tableau rows/columns and the original variables.
void ascii_dump(std::ostream &os) const
Dumps to os an ASCII representation of *this.
virtual const PIP_Solution_Node * as_solution() const
Returns this.
void ascii_dump(std::ostream &s) const
Dumps to s an ASCII representation of *this.
Enable_If< Is_Native< T >::value, memory_size_type >::type external_memory_in_bytes(const T &)
For native types, returns the size in bytes of the memory managed by the type of the (unused) paramet...
const_iterator end() const
Returns the past-the-end const_iterator.
virtual const PIP_Decision_Node * as_decision() const
Returns this.
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
const_iterator end() const
Iterator pointing after the last nonzero variable coefficient.
void rem_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
virtual bool OK() const
Returns true if and only if *this is well formed.
#define WEIGHT_ADD_MUL(delta, factor)
void set_parent(const PIP_Decision_Node *p)
Set this node's parent to *p.
Coefficient_traits::const_reference denominator() const
Returns the normalized (i.e., positive) denominator.
All nonzero row coefficients are positive.
Result sub_assign(Boundary_Type to_type, To &to, To_Info &to_info, Boundary_Type type1, const T1 &x1, const Info1 &info1, Boundary_Type type2, const T2 &x2, const Info2 &info2)
void scale(Coefficient_traits::const_reference ratio)
Multiplies all coefficients and denominator with ratio.
std::vector< Linear_Expression > solution
Parametric values for the solution.
PPL_COEFFICIENT_TYPE Coefficient
An alias for easily naming the type of PPL coefficients.
PIP_Tree_Node * true_child
Pointer to the "true" child of *this.
void remove_trailing_rows(dimension_type n)
Removes from the matrix the last n rows.
friend void neg_assign(Linear_Expression &e)
bool ascii_load(std::istream &s)
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this ...
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
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 memory_size_type total_memory_in_bytes() const
Returns the total size in bytes of the memory occupied by *this.
iterator insert(dimension_type i, Coefficient_traits::const_reference x)
Equivalent to (*this)[i] = x; find(i), but faster.
const PIP_Decision_Node * parent_
A pointer to the parent of *this, null if *this is the root.
virtual const PIP_Solution_Node * as_solution() const
Returns 0, since this is not a solution node.
Artificial_Parameter()
Default constructor: builds a zero artificial parameter.
void neg_assign(GMP_Integer &x)
#define PPL_OUTPUT_DEFINITIONS(class_name)
The entire library is confined to this namespace.
All row coefficients are zero.
A const iterator on the tree elements, ordered by key.
void update_solution() const
Helper method.
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...
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
dimension_type big_parameter_dimension
The dimension for the big parameter, or not_a_dimension() if not set.
void insert(Variable v)
Inserts the index of variable v into the set.
virtual ~PIP_Solution_Node()
Destructor.
Artificial_Parameter_Sequence artificial_parameters
The local sequence of expressions for local artificial parameters.
void normalize()
Normalizes the modulo of coefficients so that they are mutually prime.
std::vector< bool > basis
A boolean vector for identifying the basic variables.
Row_Sign
The possible values for the sign of a parametric linear expression.
std::vector< Constraint > Constraint_Sequence
A type alias for a sequence of constraints.
void add_constraint(const Row &row, const Variables_Set ¶meters)
Inserts a new parametric constraint in internal row format.
iterator begin()
Returns an iterator that points at the first stored element.
Matrix< Row > t
The matrix of parameter coefficients.
base_type::const_iterator const_iterator
The type of const iterators on coefficients.
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
void gcd_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
Choose the first non-integer row.
int sgn(Boundary_Type type, const T &x, const Info &info)
#define PPL_USED(v)
No-op macro that allows to avoid unused variable warnings from the compiler.
virtual PIP_Tree_Node * clone() const
Returns a pointer to a dynamically-allocated copy of *this.
A tree node representing part of the space of solutions.
virtual const PIP_Decision_Node * as_decision() const
Returns 0, since this is not a decision node.
bool operator==(const Box< ITV > &x, const Box< ITV > &y)
void exact_div_assign(Coefficient_traits::const_reference c, dimension_type start, dimension_type end)
bool is_better_pivot(const std::vector< dimension_type > &mapping, const std::vector< bool > &basis, const dimension_type row_0, const dimension_type col_0, const dimension_type row_1, const dimension_type col_1) const
Compares two pivot row and column pairs before pivoting.
size_t memory_size_type
An unsigned integral type for representing memory size in bytes.
virtual PIP_Tree_Node * solve(const PIP_Problem &pip, bool check_feasible_context, const Matrix< Row > &context, const Variables_Set ¶ms, dimension_type space_dim, int indent_level)
Implements pure virtual method PIP_Tree_Node::solve.
bool OK() const
Checks if all the invariants are satisfied.
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
expr_type expression() const
Partial read access to the (adapted) internal expression.
dimension_type index() const
Returns the index of the element pointed to by *this.
void add_zero_columns(dimension_type n)
Adds n columns of zeroes to the matrix.
Constraint_System constraints_
The local system of parameter constraints.
virtual PIP_Tree_Node * solve(const PIP_Problem &pip, bool check_feasible_context, const Matrix< Row > &context, const Variables_Set ¶ms, dimension_type space_dim, int indent_level)=0
Executes a parametric simplex on the tableau, under specified context.
const_iterator begin() const
Iterator pointing to the first nonzero variable coefficient.
A node of the PIP solution tree.
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
A tag type to select the alternative copy constructor.
dimension_type num_rows() const
Returns the number of rows in the matrix.
virtual memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
bool ascii_load(std::istream &s)
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this ...
CO_Tree::const_iterator const_iterator
A const iterator on the row elements.
Coefficient_traits::const_reference get(dimension_type i) const
Gets the i-th element in the sequence.
An adapter for Linear_Expression that maybe hides the last coefficient.
static void indent_and_print(std::ostream &s, int indent, const char *str)
A helper function used when printing PIP trees.
void print(std::ostream &s, int indent=0) const
Prints on s the tree rooted in *this.
std::vector< Row_Sign > sign
A cache for computed sign values of constraint parametric RHS.
bool ascii_load(std::istream &is)
Loads from is an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this...
Constraint_System_const_iterator const_iterator