PPL  1.2
PIP_Tree.cc
Go to the documentation of this file.
1 /* PIP_Tree related class implementation: non-inline functions.
2  Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3  Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #include "ppl-config.h"
25 #include "PIP_Tree_defs.hh"
26 #include "PIP_Problem_defs.hh"
27 #include <algorithm>
28 #include <memory>
29 #include <map>
30 
31 #if 0
32 #define NOISY_PIP_TREE_STRUCTURE 1
33 #define NOISY_PIP 1
34 #define VERY_NOISY_PIP 1
35 #endif
36 
37 namespace Parma_Polyhedra_Library {
38 
39 namespace {
40 
42 inline void
43 pos_rem_assign(Coefficient& x,
44  Coefficient_traits::const_reference y,
45  Coefficient_traits::const_reference z) {
46  rem_assign(x, y, z);
47  if (x < 0) {
48  x += z;
49  }
50 }
51 
52 class Add_Mul_Assign_Row_Helper1 {
53 public:
54  Add_Mul_Assign_Row_Helper1(Coefficient_traits::const_reference coeff)
55  : c(coeff) {
56  }
57 
58  void
59  operator()(Coefficient& x, Coefficient_traits::const_reference y) const {
60  add_mul_assign(x, c, y);
61  }
62 
63 private:
65 }; // class Add_Mul_Assign_Row_Helper1
66 
67 
68 class Add_Mul_Assign_Row_Helper2 {
69 public:
70  Add_Mul_Assign_Row_Helper2(Coefficient_traits::const_reference coeff)
71  : c(coeff) {
72  }
73 
74  void
75  operator()(Coefficient& x, Coefficient_traits::const_reference y) const {
76  x = y;
77  x *= c;
78  }
79 
80 private:
81  Coefficient c;
82 }; // class Add_Mul_Assign_Row_Helper2
83 
84 // Compute x += c * y
85 inline void
86 add_mul_assign_row(PIP_Tree_Node::Row& x,
87  Coefficient_traits::const_reference c,
88  const PIP_Tree_Node::Row& y) {
89  WEIGHT_BEGIN();
90  x.combine_needs_second(y,
91  Add_Mul_Assign_Row_Helper1(c),
92  Add_Mul_Assign_Row_Helper2(c));
93  WEIGHT_ADD_MUL(108, x.size());
94 }
95 
96 
97 struct Sub_Assign_Helper1 {
98  void
99  operator()(Coefficient& x, Coefficient_traits::const_reference y) const {
100  x -= y;
101  }
102 }; // struct Sub_Assign_Helper1
103 
104 struct Sub_Assign_Helper2 {
105  void
106  operator()(Coefficient& x, Coefficient_traits::const_reference y) const {
107  x = y;
108  neg_assign(x);
109  }
110 }; // struct Sub_Assign_Helper2
111 
112 // Compute x -= y
113 inline void
115  WEIGHT_BEGIN();
116  x.combine_needs_second(y, Sub_Assign_Helper1(), Sub_Assign_Helper2());
117  WEIGHT_ADD_MUL(10, x.size());
118 }
119 
120 // Merge constraint system to a matrix-form context such as x = x U y
121 void
122 merge_assign(Matrix<PIP_Tree_Node::Row>& x, const Constraint_System& y,
123  const Variables_Set& parameters) {
124  const dimension_type params_size = parameters.size();
125  PPL_ASSERT(params_size == x.num_columns() - 1);
127  if (new_rows == 0) {
128  return;
129  }
130  const dimension_type old_num_rows = x.num_rows();
131  x.add_zero_rows(new_rows);
132 
133  // Compute once for all.
134  const dimension_type cs_space_dim = y.space_dimension();
135  const Variables_Set::const_iterator param_begin = parameters.begin();
136  const Variables_Set::const_iterator param_end = parameters.end();
137 
138  dimension_type i = old_num_rows;
139  for (Constraint_System::const_iterator y_i = y.begin(),
140  y_end = y.end(); y_i != y_end; ++y_i, ++i) {
141  WEIGHT_BEGIN();
142  PPL_ASSERT(y_i->is_nonstrict_inequality());
143  PIP_Tree_Node::Row& x_i = x[i];
144  Coefficient_traits::const_reference inhomogeneous_term
145  = y_i->inhomogeneous_term();
146  Variables_Set::const_iterator pj = param_begin;
147  PIP_Tree_Node::Row::iterator itr = x_i.end();
148  if (inhomogeneous_term != 0) {
149  itr = x_i.insert(0, inhomogeneous_term);
150  }
151  // itr may still be end() but it can still be used as a hint.
152  // TODO: This code could be optimized more (if it's expected that the
153  // size of `parameters' will be greater than the number of nonzero
154  // coefficients in y_i).
155  for (dimension_type j = 1; pj != param_end; ++pj, ++j) {
156  const Variable vj(*pj);
157  if (vj.space_dimension() > cs_space_dim) {
158  break;
159  }
160  Coefficient_traits::const_reference c = y_i->coefficient(vj);
161  if (c != 0) {
162  itr = x_i.insert(itr, j, c);
163  }
164  }
165  WEIGHT_ADD_MUL(102, params_size);
166  }
167 }
168 
169 #if PPL_USE_SPARSE_MATRIX
170 
171 // Assigns to row x the negation of row y.
172 inline void
173 neg_assign_row(PIP_Tree_Node::Row& x, const PIP_Tree_Node::Row& y) {
174  WEIGHT_BEGIN();
175  x = y;
176  for (PIP_Tree_Node::Row::iterator i = x.begin(),
177  i_end = x.end(); i != i_end; ++i) {
178  neg_assign(*i);
179  WEIGHT_ADD(1);
180  }
181 }
182 
183 #else // !PPL_USE_SPARSE_MATRIX
184 
185 inline void
186 neg_assign_row(PIP_Tree_Node::Row& x, const PIP_Tree_Node::Row& y) {
187  WEIGHT_BEGIN();
188  const dimension_type x_size = x.size();
189  for (dimension_type i = x_size; i-- > 0; )
190  neg_assign(x[i], y[i]);
191  WEIGHT_ADD_MUL(14, x_size);
192 }
193 
194 #endif // !PPL_USE_SPARSE_MATRIX
195 
196 // Given context row \p y and denominator \p denom,
197 // to be interpreted as expression expr = y / denom,
198 // assigns to context row \p x a new value such that
199 // x / denom == - expr - 1.
200 inline void
201 complement_assign(PIP_Tree_Node::Row& x,
202  const PIP_Tree_Node::Row& y,
203  Coefficient_traits::const_reference denom) {
204  PPL_ASSERT(denom > 0);
205  neg_assign_row(x, y);
206  PIP_Tree_Node::Row::iterator itr = x.insert(0);
207  Coefficient& x_0 = *itr;
208  if (denom == 1) {
209  --x_0;
210  }
211  else {
213  pos_rem_assign(mod, x_0, denom);
214  x_0 -= (mod == 0) ? denom : mod;
215  }
216  if (x_0 == 0) {
217  x.reset(itr);
218  }
219 }
220 
221 // Add to `context' the columns for new artificial parameters.
222 inline void
223 add_artificial_parameters(Matrix<PIP_Tree_Node::Row>& context,
224  const dimension_type num_art_params) {
225  if (num_art_params > 0) {
226  context.add_zero_columns(num_art_params);
227  }
228 }
229 
230 // Add to `params' the indices of new artificial parameters.
231 inline void
232 add_artificial_parameters(Variables_Set& params,
233  const dimension_type space_dim,
234  const dimension_type num_art_params) {
235  for (dimension_type i = 0; i < num_art_params; ++i) {
236  params.insert(space_dim + i);
237  }
238 }
239 
240 // Update `context', `params' and `space_dim' to account for
241 // the addition of the new artificial parameters.
242 inline void
243 add_artificial_parameters(Matrix<PIP_Tree_Node::Row>& context,
244  Variables_Set& params,
245  dimension_type& space_dim,
246  const dimension_type num_art_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;
250 }
251 
252 /* Compares two columns lexicographically in a revised simplex tableau:
253  - returns true if
254  <CODE>
255  (column ja)*(-cst_a)/pivot_a[ja] < (column jb)*(-cst_b)/pivot_b[jb];
256  </CODE>
257  - returns false otherwise.
258 */
259 bool
260 column_lower(const Matrix<PIP_Tree_Node::Row>& tableau,
261  const std::vector<dimension_type>& mapping,
262  const std::vector<bool>& basis,
263  const PIP_Tree_Node::Row& pivot_a, const dimension_type ja,
264  const PIP_Tree_Node::Row& pivot_b, const dimension_type jb,
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);
271 
272  PPL_DIRTY_TEMP_COEFFICIENT(lhs_coeff);
273  PPL_DIRTY_TEMP_COEFFICIENT(rhs_coeff);
274  lhs_coeff = cst_a * sij_b;
275  rhs_coeff = cst_b * sij_a;
276 
277  const int lhs_coeff_sign = sgn(lhs_coeff);
278  const int rhs_coeff_sign = sgn(rhs_coeff);
279 
280  if (ja == jb) {
281  // Same column: just compare the ratios.
282  // This works since all columns are lexico-positive.
283  return lhs_coeff > rhs_coeff;
284  }
285 
288  const dimension_type num_vars = mapping.size();
289  dimension_type k = 0;
290  // While loop guard is: (k < num_rows && lhs == rhs).
291  // Return value is false, if k >= num_rows; it is equivalent to
292  // lhs < rhs, otherwise.
293  // Try to optimize the computation of lhs and rhs.
294  WEIGHT_BEGIN();
295  while (true) {
296  const dimension_type mk = mapping[k];
297  const bool in_base = basis[k];
298  if (++k >= num_vars) {
299  return false;
300  }
301  if (in_base) {
302  // Reconstitute the identity submatrix part of tableau.
303  if (mk == ja) {
304  // Optimizing for: lhs == lhs_coeff && rhs == 0;
305  if (lhs_coeff == 0) {
306  continue;
307  }
308  else {
309  return lhs_coeff > 0;
310  }
311  }
312  if (mk == jb) {
313  // Optimizing for: lhs == 0 && rhs == rhs_coeff;
314  if (rhs_coeff == 0) {
315  continue;
316  }
317  else {
318  return 0 > rhs_coeff;
319  }
320  }
321  // Optimizing for: lhs == 0 && rhs == 0;
322  continue;
323  }
324  else {
325  // Not in base.
326  const PIP_Tree_Node::Row& t_mk = tableau[mk];
327  Coefficient_traits::const_reference t_mk_ja = t_mk.get(ja);
328  Coefficient_traits::const_reference t_mk_jb = t_mk.get(jb);
329  if (t_mk_ja == 0) {
330  if (t_mk_jb == 0) {
331  continue;
332  }
333  else {
334  const int rhs_sign = rhs_coeff_sign * sgn(t_mk_jb);
335  if (0 == rhs_sign) {
336  continue;
337  }
338  else {
339  return 0 > rhs_sign;
340  }
341  }
342  }
343  else {
344  if (t_mk_jb == 0) {
345  const int lhs_sign = lhs_coeff_sign * sgn(t_mk_ja);
346  if (lhs_sign == 0) {
347  continue;
348  }
349  else {
350  return lhs_sign > 0;
351  }
352  }
353  else {
354  WEIGHT_ADD(2);
355  lhs = lhs_coeff * t_mk_ja;
356  rhs = rhs_coeff * t_mk_jb;
357  if (lhs == rhs) {
358  continue;
359  }
360  else {
361  return lhs > rhs;
362  }
363  }
364  }
365  }
366  }
367  // This point should be unreachable.
368  PPL_UNREACHABLE;
369  return false;
370 }
371 
372 /* Find the column j in revised simplex tableau such that
373  - j is in candidates
374  - (column j) / pivot_row[j] is lexico-minimal
375  When this function returns, candidates contains the minimum(s) column(s)
376  index(es).
377 */
378 void
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,
383  const PIP_Tree_Node::Row& pivot_row) {
384  WEIGHT_BEGIN();
385  const dimension_type num_vars = mapping.size();
386 
387  PPL_ASSERT(!candidates.empty());
388  // This is used as a set, it is always sorted.
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);
396  dimension_type min_column = *i;
397  ++i;
398  if (i == i_end) {
399  // Only one candidate left, so it is the minimum.
400  break;
401  }
403  pivot_itr = pivot_row.find(min_column);
404  PPL_ASSERT(pivot_itr != pivot_row.end());
405  Coefficient sij_b = *pivot_itr;
406  ++pivot_itr;
407  const dimension_type row_index = mapping[var_index];
408  const bool in_base = basis[var_index];
409  if (in_base) {
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;
414  ++pivot_itr;
415  PPL_ASSERT(sij_a > 0);
416  PPL_ASSERT(sij_b > 0);
417 
418  // Reconstitute the identity submatrix part of tableau.
419  if (row_index != *i) {
420  if (row_index == min_column) {
421  // Optimizing for: lhs == 0 && rhs == rhs_coeff;
422  new_candidates.clear();
423  min_column = *i;
424  sij_b = sij_a;
425  new_candidates.push_back(min_column);
426  }
427  else {
428  // Optimizing for: lhs == 0 && rhs == 0;
429  new_candidates.push_back(*i);
430  }
431  }
432  }
433  WEIGHT_ADD_MUL(44, candidates.size());
434  }
435  else {
436  // Not in base.
437  const PIP_Tree_Node::Row& row = tableau[row_index];
438  PIP_Tree_Node::Row::const_iterator row_itr = row.lower_bound(min_column);
439  PIP_Tree_Node::Row::const_iterator row_end = row.end();
441  if (row_itr == row_end || row_itr.index() > min_column) {
442  row_jb = 0;
443  }
444  else {
445  PPL_ASSERT(row_itr.index() == min_column);
446  row_jb = *row_itr;
447  ++row_itr;
448  }
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);
455 
458  if (row_itr != row_end && row_itr.index() < *i) {
459  row_itr = row.lower_bound(row_itr, *i);
460  }
462  if (row_itr == row_end || row_itr.index() > *i) {
463  row_ja = 0;
464  }
465  else {
466  PPL_ASSERT(row_itr.index() == *i);
467  row_ja = *row_itr;
468  ++row_itr;
469  }
470 
471  // lhs is actually the left-hand side with toggled sign.
472  // rhs is actually the right-hand side with toggled sign.
473  lhs = sij_b * row_ja;
474  rhs = sij_a * row_jb;
475  if (lhs == rhs) {
476  new_candidates.push_back(*i);
477  }
478  else {
479  if (lhs < rhs) {
480  new_candidates.clear();
481  min_column = *i;
482  row_jb = row_ja;
483  sij_b = sij_a;
484  new_candidates.push_back(min_column);
485  }
486  }
487  }
488  WEIGHT_ADD_MUL(68, candidates.size());
489  }
490  using std::swap;
491  swap(candidates, new_candidates);
492  }
493 }
494 
495 /* Find the column j in revised simplex tableau such that
496  - pivot_row[j] is positive;
497  - (column j) / pivot_row[j] is lexico-minimal.
498 */
499 bool
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,
503  const PIP_Tree_Node::Row& pivot_row,
504  const dimension_type start_j,
505  dimension_type& j_out) {
506  WEIGHT_BEGIN();
507  const dimension_type num_columns = tableau.num_columns();
508 
509  PPL_ASSERT(start_j <= pivot_row.size());
510  if (start_j == pivot_row.size()) {
511  // There are no candidates, so there is no minimum.
512  return false;
513  }
514 
515  // This is used as a set, it is always sorted.
516  std::vector<dimension_type> candidates;
517  for (PIP_Tree_Node::Row::const_iterator i = pivot_row.lower_bound(start_j),
518  i_end = pivot_row.end(); i != i_end; ++i) {
519  if (*i > 0) {
520  candidates.push_back(i.index());
521  }
522  }
523  WEIGHT_ADD_MUL(201, candidates.size());
524 
525  if (candidates.empty()) {
526  j_out = num_columns;
527  return false;
528  }
529 
530  find_lexico_minimal_column_in_set(candidates, tableau,
531  mapping, basis, pivot_row);
532  PPL_ASSERT(!candidates.empty());
533  j_out = *(candidates.begin());
534 
535  return true;
536 }
537 
538 // Computes into gcd the GCD of gcd and all coefficients in [first, last).
539 template <typename Iter>
540 void
541 gcd_assign_iter(Coefficient& gcd, Iter first, Iter last) {
542  PPL_ASSERT(gcd != 0);
543  if (gcd < 0) {
544  neg_assign(gcd);
545  }
546  if (gcd == 1) {
547  return;
548  }
549  WEIGHT_BEGIN();
550  for ( ; first != last; ++first) {
551  Coefficient_traits::const_reference coeff = *first;
552  if (coeff != 0) {
553  WEIGHT_ADD(24);
554  gcd_assign(gcd, coeff, gcd);
555  if (gcd == 1) {
556  return;
557  }
558  }
559  }
560 }
561 
562 // Simplify row by exploiting variable integrality.
563 void
564 integral_simplification(PIP_Tree_Node::Row& row) {
565  if (row[0] != 0) {
566  PIP_Tree_Node::Row::const_iterator j_begin = row.begin();
567  PIP_Tree_Node::Row::const_iterator j_end = row.end();
568  PPL_ASSERT(j_begin != j_end && j_begin.index() == 0 && *j_begin != 0);
569  /* Find next column with a non-zero value (there should be one). */
570  ++j_begin;
571  PPL_ASSERT(j_begin != j_end);
572  for ( ; *j_begin == 0; ++j_begin) {
573  PPL_ASSERT(j_begin != j_end);
574  }
575  /* Use it to initialize gcd. */
577  gcd = *j_begin;
578  ++j_begin;
579  gcd_assign_iter(gcd, j_begin, j_end);
580  if (gcd != 1) {
582  pos_rem_assign(mod, row[0], gcd);
583  row[0] -= mod;
584  }
585  }
586  /* Final normalization. */
587  row.normalize();
588 }
589 
590 // Divide all coefficients in row x and denominator y by their GCD.
591 void
592 row_normalize(PIP_Tree_Node::Row& x, Coefficient& denom) {
593  if (denom == 1) {
594  return;
595  }
597  gcd = denom;
598  gcd_assign_iter(gcd, x.begin(), x.end());
599 
600  // Divide the coefficients by the GCD.
601  WEIGHT_BEGIN();
602  for (PIP_Tree_Node::Row::iterator i = x.begin(),
603  i_end = x.end(); i != i_end; ++i) {
604  Coefficient& x_i = *i;
605  exact_div_assign(x_i, x_i, gcd);
606  WEIGHT_ADD(22);
607  }
608  // Divide the denominator by the GCD.
609  exact_div_assign(denom, denom, gcd);
610 }
611 
612 // This is here because it is used as a template argument in
613 // compatibility_check_find_pivot, so it must be a global declaration.
614 struct compatibility_check_find_pivot_in_set_data {
616  // We cache cost and value to avoid calling get() multiple times.
619  bool operator==(const compatibility_check_find_pivot_in_set_data& x) const {
620  return row_index == x.row_index;
621  }
622  // Needed by std::vector to sort the values.
623  bool operator<(const compatibility_check_find_pivot_in_set_data& x) const {
624  return row_index < x.row_index;
625  }
626 };
627 
628 void
629 compatibility_check_find_pivot_in_set(
630  std::vector<std::pair<dimension_type,
631  compatibility_check_find_pivot_in_set_data> >&
632  candidates,
633  const Matrix<PIP_Tree_Node::Row>& s,
634  const std::vector<dimension_type>& mapping,
635  const std::vector<bool>& basis) {
636 
637  typedef compatibility_check_find_pivot_in_set_data data_struct;
638  typedef std::vector<std::pair<dimension_type, data_struct> > candidates_t;
639  // This is used as a set, it is always sorted.
640  candidates_t new_candidates;
641  const dimension_type num_vars = mapping.size();
642  for (dimension_type var_index = 0; var_index < num_vars; ++var_index) {
643  const dimension_type row_index = mapping[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);
648  dimension_type pj = i->first;
649  Coefficient cost = i->second.cost;
650  Coefficient value = i->second.value;
651  new_candidates.clear();
652  new_candidates.push_back(*i);
653  if (in_base) {
654  for (++i; i != i_end; ++i) {
655  bool found_better_pivot = false;
656 
657  const dimension_type challenger_j = i->first;
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);
662 
663  const int lhs_coeff_sgn = sgn(cost);
664  const int rhs_coeff_sgn = sgn(challenger_cost);
665 
666  PPL_ASSERT(pj != challenger_j);
667 
668  // Reconstitute the identity submatrix part of tableau.
669  if (row_index == pj) {
670  // Optimizing for: lhs == lhs_coeff && rhs == 0;
671  if (lhs_coeff_sgn == 0) {
672  new_candidates.push_back(*i);
673  }
674  else {
675  found_better_pivot = (lhs_coeff_sgn > 0);
676  }
677  }
678  else {
679  if (row_index == challenger_j) {
680  // Optimizing for: lhs == 0 && rhs == rhs_coeff;
681  if (rhs_coeff_sgn == 0) {
682  new_candidates.push_back(*i);
683  }
684  else {
685  found_better_pivot = (0 > rhs_coeff_sgn);
686  }
687  }
688  else {
689  // Optimizing for: lhs == 0 && rhs == 0;
690  new_candidates.push_back(*i);
691  }
692  }
693  if (found_better_pivot) {
694  pj = challenger_j;
695  cost = challenger_cost;
696  value = i->second.value;
697  new_candidates.clear();
698  new_candidates.push_back(*i);
699  }
700  }
701  }
702  else {
703  // Not in base.
704  const PIP_Tree_Node::Row& row = s[row_index];
705  PIP_Tree_Node::Row::const_iterator row_itr = row.lower_bound(pj);
707  PIP_Tree_Node::Row::const_iterator row_end = row.end();
708  PPL_DIRTY_TEMP_COEFFICIENT(row_value);
709  if (row_itr != row_end && row_itr.index() == pj) {
710  row_value = *row_itr;
711  ++row_itr;
712  }
713  else {
714  row_value = 0;
715  }
716  PPL_DIRTY_TEMP_COEFFICIENT(row_challenger_value);
717  for (++i; i != i_end; ++i) {
718  const dimension_type challenger_j = i->first;
719  Coefficient_traits::const_reference challenger_cost = i->second.cost;
720  Coefficient_traits::const_reference challenger_value
721  = i->second.value;
722  PPL_ASSERT(value > 0);
723  PPL_ASSERT(challenger_value > 0);
724  PPL_ASSERT(pj < challenger_j);
725 
726  new_row_itr = row.find(row_itr, challenger_j);
727  if (new_row_itr != row.end()) {
728  row_challenger_value = *new_row_itr;
729  // Use new_row_itr as a hint in next iterations
730  row_itr = new_row_itr;
731  }
732  else {
733  row_challenger_value = 0;
734  // Using end() as a hint is not useful, keep the current hint.
735  }
736  PPL_ASSERT(row_challenger_value == row.get(challenger_j));
737 
738  // Before computing and comparing the actual values, the signs are
739  // compared. This speeds up the code, because the values' computation
740  // is a bit expensive.
741 
742  const int lhs_sign = sgn(cost) * sgn(row_value);
743  const int rhs_sign = sgn(challenger_cost) * sgn(row_challenger_value);
744 
745  if (lhs_sign != rhs_sign) {
746  if (lhs_sign > rhs_sign) {
747 #ifndef NDEBUG
748  pj = challenger_j;
749 #endif
750  cost = challenger_cost;
751  value = challenger_value;
752  row_value = row_challenger_value;
753  new_candidates.clear();
754  new_candidates.push_back(*i);
755  }
756  }
757  else {
758 
759  // Sign comparison is not enough this time.
760  // Do the full computation.
761 
763  lhs = cost;
764  lhs *= challenger_value;
766  rhs = challenger_cost;
767  rhs *= value;
768 
769  lhs *= row_value;
770  rhs *= row_challenger_value;
771 
772  if (lhs == rhs) {
773  new_candidates.push_back(*i);
774  }
775  else {
776  if (lhs > rhs) {
777 #ifndef NDEBUG
778  pj = challenger_j;
779 #endif
780  cost = challenger_cost;
781  value = challenger_value;
782  row_value = row_challenger_value;
783  new_candidates.clear();
784  new_candidates.push_back(*i);
785  }
786  }
787  }
788  }
789  }
790  using std::swap;
791  swap(candidates, new_candidates);
792  }
793 }
794 
795 // Returns false if there is not a positive pivot candidate.
796 // Otherwise, it sets pi, pj to the coordinates of the pivot in s.
797 bool
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,
801  dimension_type& pi, dimension_type& pj) {
802  // Look for a negative RHS (i.e., constant term, stored in column 0),
803  // maximizing pivot column.
804  const dimension_type num_rows = s.num_rows();
805  typedef compatibility_check_find_pivot_in_set_data data_struct;
806  // This is used as a set, it is always sorted.
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;
810  for (dimension_type i = 0; i < num_rows; ++i) {
811  const PIP_Tree_Node::Row& s_i = s[i];
812  Coefficient_traits::const_reference s_i0 = s_i.get(0);
813  if (s_i0 < 0) {
814  dimension_type j;
815  if (!find_lexico_minimal_column(s, mapping, basis, s_i, 1, j)) {
816  // No positive pivot candidate: unfeasible problem.
817  return false;
818  }
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;
826  }
827  else {
828  data_struct& current_data = candidates_map[j];
829  PPL_ASSERT(current_data.value > 0);
830 
831  // Before computing and comparing the actual values, the signs are
832  // compared. This speeds up the code, because the values' computation
833  // is a bit expensive.
834  const int lhs_coeff_sgn = sgn(current_data.cost);
835  const int rhs_coeff_sgn = sgn(s_i0);
836 
837  if (lhs_coeff_sgn != rhs_coeff_sgn) {
838  // Same column: just compare the ratios.
839  // This works since all columns are lexico-positive:
840  // return cst_a * sij_b > cst_b * sij_a.
841  if (lhs_coeff_sgn > rhs_coeff_sgn) {
842  // Found better pivot
843  current_data.row_index = i;
844  current_data.cost = s_i0;
845  current_data.value = s_ij;
846  }
847  // Otherwise, keep current pivot for this column.
848  }
849  else {
850  // Sign comparison is not enough this time.
851  // Do the full computation.
852  Coefficient_traits::const_reference value_b = s_i.get(j);
853  PPL_ASSERT(value_b > 0);
854 
855  PPL_DIRTY_TEMP_COEFFICIENT(lhs_coeff);
856  lhs_coeff = current_data.cost;
857  lhs_coeff *= value_b;
858 
859  PPL_DIRTY_TEMP_COEFFICIENT(rhs_coeff);
860  rhs_coeff = s_i0;
861  rhs_coeff *= current_data.value;
862 
863  // Same column: just compare the ratios.
864  // This works since all columns are lexico-positive:
865  // return cst_a * sij_b > cst_b * sij_a.
866  if (lhs_coeff > rhs_coeff) {
867  // Found better pivot
868  current_data.row_index = i;
869  current_data.cost = s_i0;
870  current_data.value = s_ij;
871  }
872  // Otherwise, keep current pivot for this column.
873  }
874  }
875  }
876  }
877  candidates_t candidates;
878  for (candidates_map_t::iterator
879  i = candidates_map.begin(), i_end = candidates_map.end();
880  i != i_end; ++i) {
881  candidates.push_back(*i);
882  }
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;
888  }
889  else {
890  pi = s.num_rows();
891  pj = 0;
892  }
893 
894  return true;
895 }
896 
897 } // namespace
898 
899 namespace IO_Operators {
900 
901 std::ostream&
902 operator<<(std::ostream& os, const PIP_Tree_Node& x) {
903  x.print(os);
904  return os;
905 }
906 
907 std::ostream&
908 operator<<(std::ostream& os, const PIP_Tree_Node::Artificial_Parameter& x) {
909  const Linear_Expression& expr = static_cast<const Linear_Expression&>(x);
910  os << "(" << expr << ") div " << x.denominator();
911  return os;
912 }
913 
914 } // namespace IO_Operators
915 
917  : owner_(owner),
918  parent_(0),
919  constraints_(),
920  artificial_parameters() {
921 }
922 
924  : owner_(y.owner_),
925  parent_(0), // NOTE: parent is not copied.
926  constraints_(y.constraints_),
927  artificial_parameters(y.artificial_parameters) {
928 }
929 
931 }
932 
935  Coefficient_traits::const_reference d)
936  : Linear_Expression(expr), denom(d) {
937  if (denom == 0) {
938  throw std::invalid_argument("PIP_Tree_Node::Artificial_Parameter(e, d): "
939  "denominator d is zero.");
940  }
941 
942  // Normalize if needed.
943  // FIXME: Provide a proper normalization helper.
944  Linear_Expression& param_expr = *this;
945  if (denom < 0) {
946  neg_assign(denom);
947  neg_assign(param_expr);
948  }
949 
950  // Compute GCD of parameter expression and denominator.
951 
952  Coefficient gcd = param_expr.gcd(0, space_dimension() + 1);
953 
954  if (gcd == 1) {
955  return;
956  }
957 
958  if (gcd == 0) {
959  gcd = denom;
960  }
961  else {
962  gcd_assign(gcd, denom, gcd);
963  }
964 
965  if (gcd == 1) {
966  return;
967  }
968 
969  // Divide coefficients and denominator by their (non-trivial) GCD.
970  PPL_ASSERT(gcd > 1);
971  param_expr.exact_div_assign(gcd, 0, space_dimension() + 1);
973 
974  PPL_ASSERT(OK());
975 }
976 
977 bool
980  const Artificial_Parameter& x = *this;
981  if (x.space_dimension() != y.space_dimension()) {
982  return false;
983  }
984  if (x.denom != y.denom) {
985  return false;
986  }
987  return x.is_equal_to(y);
988 }
989 
990 bool
993  return !operator==(y);
994 }
995 
996 bool
998  if (denom <= 0) {
999 #ifndef NDEBUG
1000  std::cerr << "PIP_Tree_Node::Artificial_Parameter "
1001  << "has a non-positive denominator.\n";
1002 #endif
1003  return false;
1004  }
1005  return true;
1006 }
1007 
1008 void
1010  s << "artificial_parameter ";
1012  s << " / " << denom << "\n";
1013 }
1014 
1015 bool
1017  std::string str;
1018  if (!(s >> str) || str != "artificial_parameter") {
1019  return false;
1020  }
1022  return false;
1023  }
1024  if (!(s >> str) || str != "/") {
1025  return false;
1026  }
1027  if (!(s >> denom)) {
1028  return false;
1029  }
1030  PPL_ASSERT(OK());
1031  return true;
1032 }
1033 
1035 
1037  : PIP_Tree_Node(owner),
1038  tableau(),
1039  basis(),
1040  mapping(),
1041  var_row(),
1042  var_column(),
1043  special_equality_row(0),
1044  big_dimension(not_a_dimension()),
1045  sign(),
1046  solution(),
1047  solution_valid(false) {
1048 }
1049 
1051  : PIP_Tree_Node(y),
1052  tableau(y.tableau),
1053  basis(y.basis),
1054  mapping(y.mapping),
1055  var_row(y.var_row),
1056  var_column(y.var_column),
1057  special_equality_row(y.special_equality_row),
1058  big_dimension(y.big_dimension),
1059  sign(y.sign),
1060  solution(y.solution),
1061  solution_valid(y.solution_valid) {
1062 }
1063 
1066  : PIP_Tree_Node(y.owner_), // NOTE: only copy owner.
1067  tableau(y.tableau),
1068  basis(y.basis),
1069  mapping(y.mapping),
1070  var_row(y.var_row),
1071  var_column(y.var_column),
1072  special_equality_row(y.special_equality_row),
1073  big_dimension(y.big_dimension),
1074  sign(y.sign),
1075  solution(y.solution),
1076  solution_valid(y.solution_valid) {
1077 }
1078 
1080 }
1081 
1083  PIP_Tree_Node* fcp,
1084  PIP_Tree_Node* tcp)
1085  : PIP_Tree_Node(owner),
1086  false_child(fcp),
1087  true_child(tcp) {
1088  if (false_child != 0) {
1089  false_child->set_parent(this);
1090  }
1091  if (true_child != 0) {
1092  true_child->set_parent(this);
1093  }
1094 }
1095 
1097  : PIP_Tree_Node(y),
1098  false_child(0),
1099  true_child(0) {
1100  if (y.false_child != 0) {
1101  false_child = y.false_child->clone();
1102  false_child->set_parent(this);
1103  }
1104  // Protect false_child from exception safety issues via std::auto_ptr.
1105  std::auto_ptr<PIP_Tree_Node> wrapped_node(false_child);
1106  if (y.true_child != 0) {
1107  true_child = y.true_child->clone();
1108  true_child->set_parent(this);
1109  }
1110  // It is now safe to release false_child.
1111  wrapped_node.release();
1112 }
1113 
1115  delete false_child;
1116  delete true_child;
1117 }
1118 
1119 void
1121  owner_ = owner;
1122 }
1123 
1124 void
1126  owner_ = owner;
1127  if (false_child != 0) {
1128  false_child->set_owner(owner);
1129  }
1130  if (true_child != 0) {
1131  true_child->set_owner(owner);
1132  }
1133 }
1134 
1135 bool
1137  return get_owner() == owner;
1138 }
1139 
1140 bool
1142  return get_owner() == owner
1143  && (false_child == 0 || false_child->check_ownership(owner))
1144  && (true_child == 0 || true_child->check_ownership(owner));
1145 }
1146 
1147 const PIP_Decision_Node*
1149  return this;
1150 }
1151 
1152 const PIP_Decision_Node*
1154  return 0;
1155 }
1156 
1157 const PIP_Solution_Node*
1159  return 0;
1160 }
1161 
1162 const PIP_Solution_Node*
1164  return this;
1165 }
1166 
1167 bool
1169  if (s.num_rows() != t.num_rows()) {
1170 #ifndef NDEBUG
1171  std::cerr << "PIP_Solution_Node::Tableau matrices "
1172  << "have a different number of rows.\n";
1173 #endif
1174  return false;
1175  }
1176 
1177  if (!s.OK() || !t.OK()) {
1178 #ifndef NDEBUG
1179  std::cerr << "A PIP_Solution_Node::Tableau matrix is broken.\n";
1180 #endif
1181  return false;
1182  }
1183 
1184  if (denom <= 0) {
1185 #ifndef NDEBUG
1186  std::cerr << "PIP_Solution_Node::Tableau with non-positive "
1187  << "denominator.\n";
1188 #endif
1189  return false;
1190  }
1191 
1192  // All tests passed.
1193  return true;
1194 }
1195 
1196 bool
1198 #ifndef NDEBUG
1199  using std::endl;
1200  using std::cerr;
1201 #endif
1202 
1203  // Parameter constraint system should contain no strict inequalities.
1205  i = constraints_.begin(), i_end = constraints_.end(); i != i_end; ++i) {
1206  if (i->is_strict_inequality()) {
1207 #ifndef NDEBUG
1208  cerr << "The feasible region of the PIP_Problem parameter context"
1209  << "is defined by a constraint system containing strict "
1210  << "inequalities."
1211  << endl;
1212  ascii_dump(cerr);
1213 #endif
1214  return false;
1215  }
1216  }
1217  return true;
1218 }
1219 
1220 void
1222 ::add_constraint(const Row& row, const Variables_Set& parameters) {
1223  // Compute the expression for the parameter constraint.
1224  Linear_Expression expr = Linear_Expression(row.get(0));
1225  Variables_Set::const_iterator j = parameters.begin();
1226  if (!parameters.empty()) {
1227  // Needed to avoid reallocations in expr when iterating upward.
1228  add_mul_assign(expr, 0, Variable(*(parameters.rbegin())));
1229  // The number of increments of j plus one.
1230  dimension_type j_index = 1;
1231  Row::const_iterator i = row.begin();
1232  Row::const_iterator i_end = row.end();
1233  if (i != i_end && i.index() == 0) {
1234  ++i;
1235  }
1236  // NOTE: iterating in [1..num_params].
1237  WEIGHT_BEGIN();
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();
1242  WEIGHT_ADD(74);
1243  add_mul_assign(expr, *i, Variable(*j));
1244  }
1245  }
1246  // Add the parameter constraint.
1247  constraints_.insert(expr >= 0);
1248 }
1249 
1250 void
1252  const PIP_Decision_Node& parent = *parent_;
1253 
1254  // Merge the parent's artificial parameters.
1256  parent.art_parameter_begin(),
1257  parent.art_parameter_end());
1258 
1259  PPL_ASSERT(OK());
1260 }
1261 
1262 bool
1264 #ifndef NDEBUG
1265  using std::cerr;
1266 #endif
1267  if (!PIP_Tree_Node::OK()) {
1268  return false;
1269  }
1270 
1271  // Check that every member used is OK.
1272 
1273  if (!tableau.OK()) {
1274  return false;
1275  }
1276 
1277  // Check coherency of basis, mapping, var_row and var_column
1278  if (basis.size() != mapping.size()) {
1279 #ifndef NDEBUG
1280  cerr << "The PIP_Solution_Node::basis and PIP_Solution_Node::mapping "
1281  << "vectors do not have the same number of elements.\n";
1282 #endif
1283  return false;
1284  }
1285  if (basis.size() != var_row.size() + var_column.size()) {
1286 #ifndef NDEBUG
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";
1290 #endif
1291  return false;
1292  }
1293  if (var_column.size() != tableau.s.num_columns()) {
1294 #ifndef NDEBUG
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";
1298 #endif
1299  return false;
1300  }
1301  if (var_row.size() != tableau.s.num_rows()) {
1302 #ifndef NDEBUG
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";
1306 #endif
1307  return false;
1308  }
1309  for (dimension_type i = mapping.size(); i-- > 0; ) {
1310  const dimension_type row_column = mapping[i];
1311  if (basis[i] && var_column[row_column] != i) {
1312 #ifndef NDEBUG
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
1316  << ".\n";
1317 #endif
1318  return false;
1319  }
1320  if (!basis[i] && var_row[row_column] != i) {
1321 #ifndef NDEBUG
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
1325  << ".\n";
1326 #endif
1327  return false;
1328  }
1329  }
1330  // All checks passed.
1331  return true;
1332 }
1333 
1334 bool
1336  // Perform base class well-formedness check on this node.
1337  if (!PIP_Tree_Node::OK()) {
1338  return false;
1339  }
1340 
1341  // Recursively check if child nodes are well-formed.
1342  if (false_child != 0 && !false_child->OK()) {
1343  return false;
1344  }
1345  if (true_child != 0 && !true_child->OK()) {
1346  return false;
1347  }
1348 
1349  // Decision nodes should always have a true child.
1350  if (true_child == 0) {
1351 #ifndef NDEBUG
1352  std::cerr << "PIP_Decision_Node with no 'true' child.\n";
1353 #endif
1354  return false;
1355  }
1356 
1357  // Decision nodes with a false child must have exactly one constraint.
1358  if (false_child != 0) {
1360  if (dist != 1) {
1361 #ifndef NDEBUG
1362  std::cerr << "PIP_Decision_Node with a 'false' child has "
1363  << dist << " parametric constraints (should be 1).\n";
1364 #endif
1365  return false;
1366  }
1367  }
1368 
1369  // All checks passed.
1370  return true;
1371 }
1372 
1373 void
1375  const PIP_Problem& pip,
1376  const dimension_type external_space_dim,
1377  const dimension_type first_pending_constraint,
1378  const Constraint_Sequence& input_cs,
1379  const Variables_Set& parameters) {
1380 
1381  true_child->update_tableau(pip,
1382  external_space_dim,
1383  first_pending_constraint,
1384  input_cs,
1385  parameters);
1386  if (false_child != 0) {
1387  false_child->update_tableau(pip,
1388  external_space_dim,
1389  first_pending_constraint,
1390  input_cs,
1391  parameters);
1392  }
1393  PPL_ASSERT(OK());
1394 }
1395 
1398  const bool check_feasible_context,
1399  const Matrix<Row>& context,
1400  const Variables_Set& params,
1401  dimension_type space_dim,
1402  const int indent_level) {
1403  PPL_ASSERT(indent_level >= 0);
1404 #ifdef NOISY_PIP_TREE_STRUCTURE
1405  indent_and_print(std::cerr, indent_level, "=== SOLVING DECISION NODE\n");
1406 #else
1407  PPL_USED(indent_level);
1408 #endif
1409  PPL_ASSERT(true_child != 0);
1410  Matrix<Row> context_true(context);
1411  Variables_Set all_params(params);
1412  const dimension_type num_art_params = artificial_parameters.size();
1413  add_artificial_parameters(context_true, all_params, space_dim,
1414  num_art_params);
1415  merge_assign(context_true, constraints_, all_params);
1416  const bool has_false_child = (false_child != 0);
1417  const bool has_true_child = (true_child != 0);
1418 #ifdef NOISY_PIP_TREE_STRUCTURE
1419  indent_and_print(std::cerr, indent_level,
1420  "=== DECISION: SOLVING THEN CHILD\n");
1421 #endif
1422  true_child = true_child->solve(pip, check_feasible_context,
1423  context_true, all_params, space_dim,
1424  indent_level + 1);
1425 
1426  if (has_false_child) {
1427  // Decision nodes with false child must have exactly one constraint
1429  // NOTE: modify context_true in place, complementing its last constraint.
1430  Matrix<Row>& context_false = context_true;
1431  Row& last = context_false[context_false.num_rows() - 1];
1432  complement_assign(last, last, 1);
1433 #ifdef NOISY_PIP_TREE_STRUCTURE
1434  indent_and_print(std::cerr, indent_level,
1435  "=== DECISION: SOLVING ELSE CHILD\n");
1436 #endif
1437  false_child = false_child->solve(pip, check_feasible_context,
1438  context_false, all_params, space_dim,
1439  indent_level + 1);
1440  }
1441 
1442  if (true_child == 0 && false_child == 0) {
1443  // No children: the whole subtree is unfeasible.
1444 #ifdef NOISY_PIP_TREE_STRUCTURE
1445  indent_and_print(std::cerr, indent_level,
1446  "=== DECISION: BOTH BRANCHES NOW UNFEASIBLE: _|_\n");
1447 #endif
1448  delete this;
1449  return 0;
1450  }
1451 
1452  if (has_false_child && false_child == 0) {
1453  // False child has become unfeasible: merge this node's artificials with
1454  // the true child, while removing the local parameter constraints, which
1455  // are no longer discriminative.
1456 #ifdef NOISY_PIP_TREE_STRUCTURE
1457  indent_and_print(std::cerr, indent_level,
1458  "=== DECISION: ELSE BRANCH NOW UNFEASIBLE\n");
1459  indent_and_print(std::cerr, indent_level,
1460  "==> merge then branch with parent.\n");
1461 #endif
1462  PIP_Tree_Node* const node = true_child;
1463  node->parent_merge();
1464  node->set_parent(parent());
1465  true_child = 0;
1466  delete this;
1467  PPL_ASSERT(node->OK());
1468  return node;
1469  }
1470  else if (has_true_child && true_child == 0) {
1471  // True child has become unfeasible: merge this node's artificials
1472  // with the false child.
1473 #ifdef NOISY_PIP_TREE_STRUCTURE
1474  indent_and_print(std::cerr, indent_level,
1475  "=== DECISION: THEN BRANCH NOW UNFEASIBLE\n");
1476  indent_and_print(std::cerr, indent_level,
1477  "==> merge else branch with parent.\n");
1478 #endif
1479  PIP_Tree_Node* const node = false_child;
1480  node->parent_merge();
1481  node->set_parent(parent());
1482  false_child = 0;
1483  delete this;
1484  PPL_ASSERT(node->OK());
1485  return node;
1486  }
1487  else if (check_feasible_context) {
1488  // Test all constraints for redundancy with the context, and eliminate
1489  // them if not necessary.
1490  Constraint_System cs;
1491  swap(cs, constraints_);
1493  ci_end = cs.end(); ci != ci_end; ++ci) {
1494  Matrix<Row> ctx_copy(context);
1495  merge_assign(ctx_copy, Constraint_System(*ci), all_params);
1496  Row& last = ctx_copy[ctx_copy.num_rows()-1];
1497  complement_assign(last, last, 1);
1498  if (compatibility_check(ctx_copy)) {
1499  // The constraint is not redundant with the context: keep it.
1500  constraints_.insert(*ci);
1501  }
1502  }
1503  // If the constraints set has become empty, only keep the true child.
1504  if (constraints_.empty()) {
1505 #ifdef NOISY_PIP_TREE_STRUCTURE
1506  indent_and_print(std::cerr, indent_level,
1507  "=== DECISION: NO BRANCHING CONSTRAINTS LEFT\n");
1508  indent_and_print(std::cerr, indent_level,
1509  "==> merge then branch with parent.\n");
1510 #endif
1511  PIP_Tree_Node* const node = true_child;
1512  node->parent_merge();
1513  node->set_parent(parent());
1514  true_child = 0;
1515  delete this;
1516  PPL_ASSERT(node->OK());
1517  return node;
1518  }
1519  }
1520  PPL_ASSERT(OK());
1521  return this;
1522 }
1523 
1524 void
1525 PIP_Decision_Node::ascii_dump(std::ostream& s) const {
1526  // Dump base class info.
1528 
1529  // Dump true child (if any).
1530  s << "\ntrue_child: ";
1531  if (true_child == 0) {
1532  // Note: this branch should normally be unreachable code, since a
1533  // well-formed decision node always has a true child. We keep this code
1534  // for debugging purposes (since we want to dump broken nodes).
1535  s << "BOTTOM\n";
1536  }
1537  else if (const PIP_Decision_Node* const dec = true_child->as_decision()) {
1538  s << "DECISION\n";
1539  dec->ascii_dump(s);
1540  }
1541  else {
1542  const PIP_Solution_Node* const sol = true_child->as_solution();
1543  PPL_ASSERT(sol != 0);
1544  s << "SOLUTION\n";
1545  sol->ascii_dump(s);
1546  }
1547 
1548  // Dump false child (if any).
1549  s << "\nfalse_child: ";
1550  if (false_child == 0) {
1551  s << "BOTTOM\n";
1552  }
1553  else if (const PIP_Decision_Node* const dec = false_child->as_decision()) {
1554  // Note: this branch should normally be unreachable code.
1555  // Since a well-formed decision node having a false child should have
1556  // a single context constraint, its false child will have no context
1557  // constraints at all, so that no further branch is possible.
1558  // We keep this code for debugging purposes.
1559  s << "DECISION\n";
1560  dec->ascii_dump(s);
1561  }
1562  else {
1563  const PIP_Solution_Node* const sol = false_child->as_solution();
1564  PPL_ASSERT(sol != 0);
1565  s << "SOLUTION\n";
1566  sol->ascii_dump(s);
1567  }
1568 }
1569 
1570 bool
1572  std::string str;
1573 
1574  // Load base class info.
1575  if (!PIP_Tree_Node::ascii_load(s)) {
1576  return false;
1577  }
1578 
1579  // Release the "true" subtree (if any).
1580  delete true_child;
1581  true_child = 0;
1582 
1583  // Load true child (if any).
1584  if (!(s >> str) || str != "true_child:") {
1585  return false;
1586  }
1587  if (!(s >> str)) {
1588  return false;
1589  }
1590  if (str == "BOTTOM") {
1591  // Note: normally unreachable code (see comment on ascii_dump).
1592  true_child = 0;
1593  }
1594  else if (str == "DECISION") {
1595  PIP_Decision_Node* const dec = new PIP_Decision_Node(0, 0, 0);
1596  true_child = dec;
1597  if (!dec->ascii_load(s)) {
1598  return false;
1599  }
1600  }
1601  else if (str == "SOLUTION") {
1602  PIP_Solution_Node* const sol = new PIP_Solution_Node(0);
1603  true_child = sol;
1604  if (!sol->ascii_load(s)) {
1605  return false;
1606  }
1607  }
1608  else {
1609  // Unknown node kind.
1610  return false;
1611  }
1612 
1613  // Release the "false" subtree (if any).
1614  delete false_child;
1615  false_child = 0;
1616 
1617  // Load false child (if any).
1618  if (!(s >> str) || str != "false_child:") {
1619  return false;
1620  }
1621  if (!(s >> str)) {
1622  return false;
1623  }
1624  if (str == "BOTTOM") {
1625  false_child = 0;
1626  }
1627  else if (str == "DECISION") {
1628  // Note: normally unreachable code (see comment on ascii_dump).
1629  PIP_Decision_Node* const dec = new PIP_Decision_Node(0, 0, 0);
1630  false_child = dec;
1631  if (!dec->ascii_load(s)) {
1632  return false;
1633  }
1634  }
1635  else if (str == "SOLUTION") {
1636  PIP_Solution_Node* const sol = new PIP_Solution_Node(0);
1637  false_child = sol;
1638  if (!sol->ascii_load(s)) {
1639  return false;
1640  }
1641  }
1642  else {
1643  // Unknown node kind.
1644  return false;
1645  }
1646 
1647  // Loaded all info.
1648  PPL_ASSERT(OK());
1649  return true;
1650 }
1651 
1652 
1653 void
1655  if (denom == 1) {
1656  return;
1657  }
1658 
1659  const dimension_type num_rows = s.num_rows();
1660 
1661  // Compute global gcd.
1663  gcd = denom;
1664  for (dimension_type i = num_rows; i-- > 0; ) {
1665  WEIGHT_BEGIN();
1666  const Row& s_i = s[i];
1667  for (Row::const_iterator
1668  j = s_i.begin(), j_end = s_i.end(); j != j_end; ++j) {
1669  Coefficient_traits::const_reference s_ij = *j;
1670  if (s_ij != 0) {
1671  WEIGHT_ADD(30);
1672  gcd_assign(gcd, s_ij, gcd);
1673  if (gcd == 1) {
1674  return;
1675  }
1676  }
1677  }
1678  WEIGHT_BEGIN();
1679  const Row& t_i = t[i];
1680  for (Row::const_iterator
1681  j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
1682  Coefficient_traits::const_reference t_ij = *j;
1683  if (t_ij != 0) {
1684  WEIGHT_ADD(14);
1685  gcd_assign(gcd, t_ij, gcd);
1686  if (gcd == 1) {
1687  return;
1688  }
1689  }
1690  }
1691  }
1692  PPL_ASSERT(gcd > 1);
1693  // Normalize all coefficients.
1694  WEIGHT_BEGIN();
1695  for (dimension_type i = num_rows; i-- > 0; ) {
1696  Row& s_i = s[i];
1697  for (Row::iterator j = s_i.begin(), j_end = s_i.end(); j != j_end; ++j) {
1698  Coefficient& s_ij = *j;
1699  WEIGHT_ADD(19);
1700  exact_div_assign(s_ij, s_ij, gcd);
1701  }
1702  Row& t_i = t[i];
1703  for (Row::iterator j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
1704  Coefficient& t_ij = *j;
1705  WEIGHT_ADD(27);
1706  exact_div_assign(t_ij, t_ij, gcd);
1707  }
1708  }
1709  // Normalize denominator.
1710  exact_div_assign(denom, denom, gcd);
1711 }
1712 
1713 void
1714 PIP_Solution_Node::Tableau::scale(Coefficient_traits::const_reference ratio) {
1715  WEIGHT_BEGIN();
1716  for (dimension_type i = s.num_rows(); i-- > 0; ) {
1717  Row& s_i = s[i];
1718  for (Row::iterator j = s_i.begin(), j_end = s_i.end(); j != j_end; ++j) {
1719  WEIGHT_ADD(19);
1720  *j *= ratio;
1721  }
1722  Row& t_i = t[i];
1723  for (Row::iterator j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
1724  WEIGHT_ADD(25);
1725  *j *= ratio;
1726  }
1727  }
1728  denom *= ratio;
1729 }
1730 
1731 bool
1733 ::is_better_pivot(const std::vector<dimension_type>& mapping,
1734  const std::vector<bool>& basis,
1735  const dimension_type row_0,
1736  const dimension_type col_0,
1737  const dimension_type row_1,
1738  const dimension_type col_1) const {
1739  const dimension_type num_params = t.num_columns();
1740  const dimension_type num_rows = s.num_rows();
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];
1747  PPL_DIRTY_TEMP_COEFFICIENT(product_0);
1748  PPL_DIRTY_TEMP_COEFFICIENT(product_1);
1749  WEIGHT_BEGIN();
1750  // On exit from the loop, if j_mismatch == num_params then
1751  // no column mismatch was found.
1752  dimension_type j_mismatch = num_params;
1753  Row::const_iterator j0 = t_0.end();
1754  Row::const_iterator j0_end = t_0.end();
1755  Row::const_iterator j1 = t_1.end();
1756  Row::const_iterator j1_end = t_1.end();
1757  for (dimension_type i = 0; i < num_rows; ++i) {
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);
1761  j0 = t_0.begin();
1762  j1 = t_1.begin();
1763  while (j0 != j0_end && j1 != j1_end) {
1764  if (j0.index() == j1.index()) {
1765  WEIGHT_ADD(1361);
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) {
1769  // Mismatch found: exit from both loops.
1770  j_mismatch = j0.index();
1771  goto end_loop;
1772  }
1773  ++j0;
1774  ++j1;
1775  }
1776  else
1777  if (j0.index() < j1.index()) {
1778  if (*j0 != 0 && s_1_1 != 0 && s_i_col_0 != 0) {
1779  // Mismatch found: exit from both loops.
1780  j_mismatch = j0.index();
1781  goto end_loop;
1782  }
1783  ++j0;
1784  }
1785  else {
1786  PPL_ASSERT(j0.index() > j1.index());
1787  if (*j1 != 0 && s_0_0 != 0 && s_i_col_1 != 0) {
1788  // Mismatch found: exit from both loops.
1789  j_mismatch = j1.index();
1790  goto end_loop;
1791  }
1792  ++j1;
1793  }
1794  }
1795  while (j0 != j0_end) {
1796  if (*j0 != 0 && s_1_1 != 0 && s_i_col_0 != 0) {
1797  // Mismatch found: exit from both loops.
1798  j_mismatch = j0.index();
1799  goto end_loop;
1800  }
1801  ++j0;
1802  }
1803  while (j1 != j1_end) {
1804  if (*j1 != 0 && s_0_0 != 0 && s_i_col_1 != 0) {
1805  // Mismatch found: exit from both loops.
1806  j_mismatch = j1.index();
1807  goto end_loop;
1808  }
1809  }
1810  }
1811 
1812  end_loop:
1813  return (j_mismatch != num_params)
1814  && column_lower(s, mapping, basis, s_0, col_0, s_1, col_1, *j0, *j1);
1815 }
1816 
1817 void
1818 PIP_Tree_Node::ascii_dump(std::ostream& s) const {
1819  s << "constraints_\n";
1821  const dimension_type artificial_parameters_size
1822  = artificial_parameters.size();
1823  s << "\nartificial_parameters( " << artificial_parameters_size << " )\n";
1824  for (dimension_type i = 0; i < artificial_parameters_size; ++i) {
1825  artificial_parameters[i].ascii_dump(s);
1826  }
1827 }
1828 
1829 bool
1830 PIP_Tree_Node::ascii_load(std::istream& s) {
1831  std::string str;
1832  if (!(s >> str) || str != "constraints_") {
1833  return false;
1834  }
1836 
1837  if (!(s >> str) || str != "artificial_parameters(") {
1838  return false;
1839  }
1840 
1841  dimension_type artificial_parameters_size;
1842  if (!(s >> artificial_parameters_size)) {
1843  return false;
1844  }
1845 
1846  if (!(s >> str) || str != ")") {
1847  return false;
1848  }
1850  for (dimension_type i = 0; i < artificial_parameters_size; ++i) {
1851  if (!ap.ascii_load(s)) {
1852  return false;
1853  }
1854  artificial_parameters.push_back(ap);
1855  }
1856 
1857  // Note: do not assert OK() here.
1858  // The node invariants should be checked on derived nodes.
1859  return true;
1860 }
1861 
1864  return new PIP_Solution_Node(*this);
1865 }
1866 
1869  return new PIP_Decision_Node(*this);
1870 }
1871 
1872 void
1874  os << "denominator " << denom << "\n";
1875  os << "variables ";
1876  s.ascii_dump(os);
1877  os << "parameters ";
1878  t.ascii_dump(os);
1879 }
1880 
1881 bool
1883  std::string str;
1884  if (!(is >> str) || str != "denominator") {
1885  return false;
1886  }
1887  Coefficient d;
1888  if (!(is >> d)) {
1889  return false;
1890  }
1891  denom = d;
1892  if (!(is >> str) || str != "variables") {
1893  return false;
1894  }
1895  if (!s.ascii_load(is)) {
1896  return false;
1897  }
1898  if (!(is >> str) || str != "parameters") {
1899  return false;
1900  }
1901  if (!t.ascii_load(is)) {
1902  return false;
1903  }
1904  PPL_ASSERT(OK());
1905  return true;
1906 }
1907 
1908 void
1909 PIP_Solution_Node::ascii_dump(std::ostream& os) const {
1911 
1912  os << "\ntableau\n";
1913  tableau.ascii_dump(os);
1914 
1915  os << "\nbasis ";
1916  const dimension_type basis_size = basis.size();
1917  os << basis_size;
1918  for (dimension_type i = 0; i < basis_size; ++i) {
1919  os << (basis[i] ? " true" : " false");
1920  }
1921 
1922  os << "\nmapping ";
1923  const dimension_type mapping_size = mapping.size();
1924  os << mapping_size;
1925  for (dimension_type i = 0; i < mapping_size; ++i) {
1926  os << " " << mapping[i];
1927  }
1928 
1929  os << "\nvar_row ";
1930  const dimension_type var_row_size = var_row.size();
1931  os << var_row_size;
1932  for (dimension_type i = 0; i < var_row_size; ++i) {
1933  os << " " << var_row[i];
1934  }
1935 
1936  os << "\nvar_column ";
1937  const dimension_type var_column_size = var_column.size();
1938  os << var_column_size;
1939  for (dimension_type i = 0; i < var_column_size; ++i) {
1940  os << " " << var_column[i];
1941  }
1942 
1943  os << "\n";
1944 
1945  os << "special_equality_row " << special_equality_row << "\n";
1946  os << "big_dimension " << big_dimension << "\n";
1947 
1948  os << "sign ";
1949  const dimension_type sign_size = sign.size();
1950  os << sign_size;
1951  for (dimension_type i = 0; i < sign_size; ++i) {
1952  os << " ";
1953  switch (sign[i]) {
1954  case UNKNOWN:
1955  os << "UNKNOWN";
1956  break;
1957  case ZERO:
1958  os << "ZERO";
1959  break;
1960  case POSITIVE:
1961  os << "POSITIVE";
1962  break;
1963  case NEGATIVE:
1964  os << "NEGATIVE";
1965  break;
1966  case MIXED:
1967  os << "MIXED";
1968  break;
1969  }
1970  }
1971  os << "\n";
1972 
1973  const dimension_type solution_size = solution.size();
1974  os << "solution " << solution_size << "\n";
1975  for (dimension_type i = 0; i < solution_size; ++i) {
1976  solution[i].ascii_dump(os);
1977  }
1978  os << "\n";
1979 
1980  os << "solution_valid " << (solution_valid ? "true" : "false") << "\n";
1981 }
1982 
1983 bool
1985  if (!PIP_Tree_Node::ascii_load(is)) {
1986  return false;
1987  }
1988 
1989  std::string str;
1990  if (!(is >> str) || str != "tableau") {
1991  return false;
1992  }
1993  if (!tableau.ascii_load(is)) {
1994  return false;
1995  }
1996  if (!(is >> str) || str != "basis") {
1997  return false;
1998  }
1999  dimension_type basis_size;
2000  if (!(is >> basis_size)) {
2001  return false;
2002  }
2003  basis.clear();
2004  for (dimension_type i = 0; i < basis_size; ++i) {
2005  if (!(is >> str)) {
2006  return false;
2007  }
2008  bool val = false;
2009  if (str == "true") {
2010  val = true;
2011  }
2012  else if (str != "false") {
2013  return false;
2014  }
2015  basis.push_back(val);
2016  }
2017 
2018  if (!(is >> str) || str != "mapping") {
2019  return false;
2020  }
2021  dimension_type mapping_size;
2022  if (!(is >> mapping_size)) {
2023  return false;
2024  }
2025  mapping.clear();
2026  for (dimension_type i = 0; i < mapping_size; ++i) {
2027  dimension_type val;
2028  if (!(is >> val)) {
2029  return false;
2030  }
2031  mapping.push_back(val);
2032  }
2033 
2034  if (!(is >> str) || str != "var_row") {
2035  return false;
2036  }
2037  dimension_type var_row_size;
2038  if (!(is >> var_row_size)) {
2039  return false;
2040  }
2041  var_row.clear();
2042  for (dimension_type i = 0; i < var_row_size; ++i) {
2043  dimension_type val;
2044  if (!(is >> val)) {
2045  return false;
2046  }
2047  var_row.push_back(val);
2048  }
2049 
2050  if (!(is >> str) || str != "var_column") {
2051  return false;
2052  }
2053  dimension_type var_column_size;
2054  if (!(is >> var_column_size)) {
2055  return false;
2056  }
2057  var_column.clear();
2058  for (dimension_type i = 0; i < var_column_size; ++i) {
2059  dimension_type val;
2060  if (!(is >> val)) {
2061  return false;
2062  }
2063  var_column.push_back(val);
2064  }
2065 
2066  if (!(is >> str) || str != "special_equality_row") {
2067  return false;
2068  }
2069  if (!(is >> special_equality_row)) {
2070  return false;
2071  }
2072 
2073  if (!(is >> str) || str != "big_dimension") {
2074  return false;
2075  }
2076  if (!(is >> big_dimension)) {
2077  return false;
2078  }
2079 
2080  if (!(is >> str) || str != "sign") {
2081  return false;
2082  }
2083  dimension_type sign_size;
2084  if (!(is >> sign_size)) {
2085  return false;
2086  }
2087 
2088  sign.clear();
2089  for (dimension_type i = 0; i < sign_size; ++i) {
2090  if (!(is >> str)) {
2091  return false;
2092  }
2093  Row_Sign val;
2094  if (str == "UNKNOWN") {
2095  val = UNKNOWN;
2096  }
2097  else if (str == "ZERO") {
2098  val = ZERO;
2099  }
2100  else if (str == "POSITIVE") {
2101  val = POSITIVE;
2102  }
2103  else if (str == "NEGATIVE") {
2104  val = NEGATIVE;
2105  }
2106  else if (str == "MIXED") {
2107  val = MIXED;
2108  }
2109  else {
2110  return false;
2111  }
2112  sign.push_back(val);
2113  }
2114 
2115  if (!(is >> str) || str != "solution") {
2116  return false;
2117  }
2118  dimension_type solution_size;
2119  if (!(is >> solution_size)) {
2120  return false;
2121  }
2122  solution.clear();
2123  for (dimension_type i = 0; i < solution_size; ++i) {
2124  Linear_Expression val;
2125  if (!val.ascii_load(is)) {
2126  return false;
2127  }
2128  solution.push_back(val);
2129  }
2130 
2131  if (!(is >> str) || str != "solution_valid") {
2132  return false;
2133  }
2134  if (!(is >> str)) {
2135  return false;
2136  }
2137  if (str == "true") {
2138  solution_valid = true;
2139  }
2140  else if (str == "false") {
2141  solution_valid = false;
2142  }
2143  else {
2144  return false;
2145  }
2146 
2147  PPL_ASSERT(OK());
2148  return true;
2149 }
2150 
2153  const dimension_type big_dimension) {
2154  if (big_dimension != not_a_dimension()) {
2155  // If a big parameter has been set and its coefficient is not zero,
2156  // then return the sign of the coefficient.
2157  Coefficient_traits::const_reference x_big = x.get(big_dimension);
2158  if (x_big > 0) {
2159  return POSITIVE;
2160  }
2161  if (x_big < 0) {
2162  return NEGATIVE;
2163  }
2164  // Otherwise x_big == 0, then no big parameter involved.
2165  }
2166 
2168  for (Row::const_iterator i = x.begin(), i_end = x.end(); i != i_end; ++i) {
2169  Coefficient_traits::const_reference x_i = *i;
2170  if (x_i > 0) {
2171  if (sign == NEGATIVE) {
2172  return MIXED;
2173  }
2174  sign = POSITIVE;
2175  }
2176  else if (x_i < 0) {
2177  if (sign == POSITIVE) {
2178  return MIXED;
2179  }
2180  sign = NEGATIVE;
2181  }
2182  }
2183  return sign;
2184 }
2185 
2186 bool
2188  // CHECKME: do `context' and `row' have compatible (row) capacity?
2189  Matrix<Row> s(context);
2190  s.add_row(row);
2191  return compatibility_check(s);
2192 }
2193 
2194 bool
2196  PPL_ASSERT(s.OK());
2197  // Note: num_rows may increase.
2198  dimension_type num_rows = s.num_rows();
2199  const dimension_type num_columns = s.num_columns();
2200  const dimension_type num_vars = num_columns - 1;
2201 
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);
2209  std::vector<dimension_type> var_column;
2210  var_column.reserve(num_columns);
2211 
2212  // Column 0 is the constant term, not a variable
2213  var_column.push_back(not_a_dimension());
2214  for (dimension_type j = 1; j <= num_vars; ++j) {
2215  basis.push_back(true);
2216  mapping.push_back(j);
2217  var_column.push_back(j - 1);
2218  }
2219  for (dimension_type i = 0; i < num_rows; ++i) {
2220  basis.push_back(false);
2221  mapping.push_back(i);
2222  var_row.push_back(i + num_vars);
2223  }
2224 
2225  // Scaling factor (i.e., denominator) for pivot coefficients.
2226  PPL_DIRTY_TEMP_COEFFICIENT(pivot_denom);
2227  // Allocate once and for all: short life temporaries.
2228  PPL_DIRTY_TEMP_COEFFICIENT(product);
2230  PPL_DIRTY_TEMP_COEFFICIENT(scale_factor);
2231 
2232  // Perform simplex pivots on the context
2233  // until we find an empty solution or an optimum.
2234  while (true) {
2235  // Check if the client has requested abandoning all expensive
2236  // computations. If so, the exception specified by the client
2237  // is thrown now.
2238  maybe_abandon();
2239 
2240  // pi is the pivot's row index.
2241  dimension_type pi = num_rows;
2242  // pj is the pivot's column index.
2243  dimension_type pj = 0;
2244 
2245  const bool found_positive_pivot_candidate
2246  = compatibility_check_find_pivot(s, mapping, basis, pi, pj);
2247 
2248  if (!found_positive_pivot_candidate) {
2249  return false;
2250  }
2251 
2252  if (pj == 0) {
2253  // No negative RHS: fractional optimum found.
2254  // If it is integer, then the test is successful.
2255  // Otherwise, generate a new cut.
2256  bool all_integer_vars = true;
2257  // NOTE: iterating downwards would be correct, but it would change
2258  // the ordering of cut generation.
2259  WEIGHT_BEGIN();
2260  for (dimension_type i = 0; i < num_vars; ++i) {
2261  if (basis[i]) {
2262  // Basic variable = 0, hence integer.
2263  continue;
2264  }
2265  // Not a basic variable.
2266  WEIGHT_ADD(70);
2267  const dimension_type mi = mapping[i];
2268  Coefficient_traits::const_reference denom = scaling[mi];
2269  if (s[mi].get(0) % denom == 0) {
2270  continue;
2271  }
2272  // Here constant term is not integer.
2273  all_integer_vars = false;
2274  // Generate a new cut.
2275  var_row.push_back(mapping.size());
2276  basis.push_back(false);
2277  mapping.push_back(num_rows);
2278  s.add_zero_rows(1);
2279  Row& cut = s[num_rows];
2280  ++num_rows;
2281  const Row& s_mi = s[mi];
2282  cut = s_mi;
2283  for (Row::iterator
2284  j = cut.begin(), j_end = cut.end(); j != j_end; ++j) {
2285  WEIGHT_ADD(32);
2286  pos_rem_assign(*j, *j, denom);
2287  }
2288  cut[0] -= denom;
2289  scaling.push_back(denom);
2290  }
2291  // Check if an integer solution was found.
2292  if (all_integer_vars) {
2293  return true;
2294  }
2295  else {
2296  continue;
2297  }
2298  }
2299 
2300  // Here we have a positive s[pi][pj] pivot.
2301 
2302  // Normalize the tableau before pivoting.
2303  for (dimension_type i = num_rows; i-- > 0; ) {
2304  row_normalize(s[i], scaling[i]);
2305  }
2306 
2307  // Update basis.
2308  {
2309  const dimension_type var_pi = var_row[pi];
2310  const dimension_type var_pj = var_column[pj];
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;
2317  }
2318 
2319  // Create an identity row corresponding to basic variable pj.
2320  s.add_zero_rows(1);
2321  Row& pivot = s[num_rows];
2322  pivot[pj] = 1;
2323 
2324  // Swap identity row with the pivot row previously found.
2325  using std::swap;
2326  swap(pivot, s[pi]);
2327  // Save original pivot scaling factor in a temporary,
2328  // then reset scaling factor for identity row.
2329  pivot_denom = scaling[pi];
2330  scaling[pi] = 1;
2331 
2332  // Perform a pivot operation on the matrix.
2333  Coefficient_traits::const_reference pivot_pj = pivot.get(pj);
2334  {
2335  for (Row::const_iterator
2336  j = pivot.begin(), j_end = pivot.end(); j != j_end; ++j) {
2337  if (j.index() == pj) {
2338  continue;
2339  }
2340  Coefficient_traits::const_reference pivot_j = *j;
2341  // Do nothing if the j-th pivot element is zero.
2342  if (pivot_j == 0) {
2343  continue;
2344  }
2345 
2346  WEIGHT_BEGIN();
2347  for (dimension_type i = num_rows; i-- > 0; ) {
2348  Row& s_i = s[i];
2349  product = s_i.get(pj) * pivot_j;
2350  if (product % pivot_pj != 0) {
2351  WEIGHT_ADD(103);
2352  // Must scale row s_i to stay in integer case.
2353  gcd_assign(gcd, product, pivot_pj);
2354  exact_div_assign(scale_factor, pivot_pj, gcd);
2355  for (Row::iterator
2356  k = s_i.begin(), k_end = s_i.end(); k != k_end; ++k) {
2357  WEIGHT_ADD(30);
2358  *k *= scale_factor;
2359  }
2360  product *= scale_factor;
2361  scaling[i] *= scale_factor;
2362  }
2363  PPL_ASSERT(product % pivot_pj == 0);
2364  exact_div_assign(product, product, pivot_pj);
2365  s_i[j.index()] -= product;
2366  WEIGHT_ADD(134);
2367  }
2368  }
2369  }
2370  // Update column only if pivot coordinate != 1.
2371  if (pivot_pj != pivot_denom) {
2372  WEIGHT_BEGIN();
2373  for (dimension_type i = num_rows; i-- > 0; ) {
2374  Row& s_i = s[i];
2375  Coefficient& s_i_pj = s_i[pj];
2376  product = s_i_pj * pivot_denom;
2377  if (product % pivot_pj != 0) {
2378  WEIGHT_ADD(98);
2379  // As above, perform row scaling.
2380  gcd_assign(gcd, product, pivot_pj);
2381  exact_div_assign(scale_factor, pivot_pj, gcd);
2382  for (Row::iterator
2383  k = s_i.begin(), k_end = s_i.end(); k != k_end; ++k) {
2384  WEIGHT_ADD(26);
2385  *k *= scale_factor;
2386  }
2387  product *= scale_factor;
2388  scaling[i] *= scale_factor;
2389  }
2390  PPL_ASSERT(product % pivot_pj == 0);
2391  exact_div_assign(s_i_pj, product, pivot_pj);
2392  WEIGHT_ADD(97);
2393  }
2394  }
2395  // Drop pivot to restore proper matrix size.
2396  s.remove_trailing_rows(1);
2397  }
2398 
2399  // This point should be unreachable.
2400  PPL_UNREACHABLE;
2401  return false;
2402 }
2403 
2404 void
2407  const dimension_type external_space_dim,
2408  const dimension_type first_pending_constraint,
2409  const Constraint_Sequence& input_cs,
2410  const Variables_Set& parameters) {
2411 
2412  // Make sure a parameter column exists, for the inhomogeneous term.
2413  if (tableau.t.num_columns() == 0) {
2414  tableau.t.add_zero_columns(1);
2415  }
2416 
2417  // NOTE: here 'params' stands for problem (i.e., non artificial) parameters.
2418  const dimension_type old_num_vars = tableau.s.num_columns();
2419  const dimension_type old_num_params
2420  = pip.internal_space_dim - old_num_vars;
2421  const dimension_type num_added_dims
2423  const dimension_type new_num_params = parameters.size();
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;
2426 
2427  // Resize the two tableau matrices.
2428  if (num_added_vars > 0) {
2429  tableau.s.add_zero_columns(num_added_vars);
2430  }
2431 
2432  if (num_added_params > 0) {
2433  tableau.t.add_zero_columns(num_added_params, old_num_params + 1);
2434  }
2435 
2436  dimension_type new_var_column = old_num_vars;
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) {
2440  // A new problem variable.
2441  if (tableau.s.num_rows() == 0) {
2442  // No rows have been added yet
2443  basis.push_back(true);
2444  mapping.push_back(new_var_column);
2445  }
2446  else {
2447  /*
2448  Need to insert the original variable id
2449  before the slack variable id's to respect variable ordering.
2450  */
2451  basis.insert(nth_iter(basis, new_var_column), true);
2452  mapping.insert(nth_iter(mapping, new_var_column), new_var_column);
2453  // Update variable id's of slack variables.
2454  for (dimension_type j = var_row.size(); j-- > 0; ) {
2455  if (var_row[j] >= new_var_column) {
2456  ++var_row[j];
2457  }
2458  }
2459  for (dimension_type j = var_column.size(); j-- > 0; ) {
2460  if (var_column[j] >= new_var_column) {
2461  ++var_column[j];
2462  }
2463  }
2464  if (special_equality_row > 0) {
2466  }
2467  }
2468  var_column.push_back(new_var_column);
2469  ++new_var_column;
2470  }
2471  }
2472 
2475  // Compute the column number of big parameter in tableau.t matrix.
2476  Variables_Set::const_iterator pos
2477  = parameters.find(pip.big_parameter_dimension);
2478  big_dimension = 1U
2479  + static_cast<dimension_type>(std::distance(parameters.begin(), pos));
2480  }
2481 
2482  Coefficient_traits::const_reference denom = tableau.denominator();
2483 
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) {
2487  const Constraint& constraint = *c_iter;
2488  // (Tentatively) Add new rows to s and t matrices.
2489  // These will be removed at the end if they turn out to be useless.
2490  const dimension_type row_id = tableau.s.num_rows();
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];
2495 
2496  {
2497  dimension_type p_index = 1;
2498  dimension_type v_index = 0;
2499  // Setting the inhomogeneous term.
2500  if (constraint.inhomogeneous_term() != 0) {
2501  Coefficient& p_row0 = p_row[0];
2502  p_row0 = constraint.inhomogeneous_term();
2503  if (constraint.is_strict_inequality()) {
2504  // Transform (expr > 0) into (expr - 1 >= 0).
2505  --p_row0;
2506  }
2507  p_row0 *= denom;
2508  }
2509  else {
2510  if (constraint.is_strict_inequality()) {
2511  // Transform (expr > 0) into (expr - 1 >= 0).
2512  neg_assign(p_row[0], denom);
2513  }
2514  }
2515  WEIGHT_BEGIN();
2516  dimension_type last_dim = 0;
2517  const Constraint::expr_type e = constraint.expression();
2519  i = e.begin(), i_end = e.end(); i != i_end; ++i) {
2520  const dimension_type dim = i.variable().space_dimension();
2521  if (dim != last_dim + 1) {
2522  // We have skipped some zero coefficients.
2523  // Update p_index and v_index accordingly.
2524  const dimension_type n
2525  = std::distance(parameters.lower_bound(last_dim),
2526  parameters.lower_bound(dim - 1));
2527  const dimension_type num_skipped = dim - last_dim - 1;
2528  p_index += n;
2529  v_index += (num_skipped - n);
2530  }
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;
2534 
2535  WEIGHT_ADD(140);
2536  if (is_parameter) {
2537  p_row.insert(p_index, coeff_i * denom);
2538  ++p_index;
2539  }
2540  else {
2541  const dimension_type mv = mapping[v_index];
2542  if (basis[v_index]) {
2543  // Basic variable: add coeff_i * x_i
2544  add_mul_assign(v_row[mv], coeff_i, denom);
2545  }
2546  else {
2547  // Non-basic variable: add coeff_i * row_i
2548  add_mul_assign_row(v_row, coeff_i, tableau.s[mv]);
2549  add_mul_assign_row(p_row, coeff_i, tableau.t[mv]);
2550  }
2551  ++v_index;
2552  }
2553 
2554  last_dim = dim;
2555  }
2556  }
2557 
2558  if (row_sign(v_row, not_a_dimension()) == ZERO) {
2559  // Parametric-only constraints have already been inserted in
2560  // initial context, so no need to insert them in the tableau.
2561  tableau.s.remove_trailing_rows(1);
2562  tableau.t.remove_trailing_rows(1);
2563  }
2564  else {
2565  const dimension_type var_id = mapping.size();
2566  sign.push_back(row_sign(p_row, big_dimension));
2567  basis.push_back(false);
2568  mapping.push_back(row_id);
2569  var_row.push_back(var_id);
2570  if (constraint.is_equality()) {
2571  // Handle equality constraints.
2572  // After having added the f_i(x,p) >= 0 constraint,
2573  // we must add -f_i(x,p) to the special equality row.
2574  if (special_equality_row == 0 || basis[special_equality_row]) {
2575  // The special constraint has not been created yet
2576  // FIXME: for now, we do not handle the case where the variable
2577  // is basic, and we just create a new row.
2578  // This might be faster however.
2579  tableau.s.add_zero_rows(1);
2580  tableau.t.add_zero_rows(1);
2581  // NOTE: addition of rows invalidates references v_row and p_row
2582  // due to possible matrix reallocations: recompute them.
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]);
2585  sign.push_back(row_sign(tableau.t[1 + row_id], big_dimension));
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);
2590  }
2591  else {
2592  // The special constraint already exists and is nonbasic.
2593  const dimension_type m_eq = mapping[special_equality_row];
2594  sub_assign(tableau.s[m_eq], v_row);
2595  sub_assign(tableau.t[m_eq], p_row);
2596  sign[m_eq] = row_sign(tableau.t[m_eq], big_dimension);
2597  }
2598  }
2599  }
2600  }
2601  PPL_ASSERT(OK());
2602 }
2603 
2606  const bool check_feasible_context,
2607  const Matrix<Row>& context,
2608  const Variables_Set& params,
2609  dimension_type space_dim,
2610  const int indent_level) {
2611  PPL_ASSERT(indent_level >= 0);
2612 #ifdef NOISY_PIP_TREE_STRUCTURE
2613  indent_and_print(std::cerr, indent_level, "=== SOLVING NODE\n");
2614 #else
2615  PPL_USED(indent_level);
2616 #endif
2617  // Reset current solution as invalid.
2618  solution_valid = false;
2619 
2620  Matrix<Row> ctx(context);
2621  Variables_Set all_params(params);
2622  const dimension_type num_art_params = artificial_parameters.size();
2623  add_artificial_parameters(ctx, all_params, space_dim, num_art_params);
2624  merge_assign(ctx, constraints_, all_params);
2625 
2626  // If needed, (re-)check feasibility of context.
2627  if (check_feasible_context) {
2628  Matrix<Row> ctx_copy(ctx);
2629  if (!compatibility_check(ctx_copy)) {
2630  delete this;
2631  return 0;
2632  }
2633  }
2634 
2635  const dimension_type not_a_dim = not_a_dimension();
2636 
2637  // Main loop of the simplex algorithm.
2638  while (true) {
2639  // Check if the client has requested abandoning all expensive
2640  // computations. If so, the exception specified by the client
2641  // is thrown now.
2642  maybe_abandon();
2643 
2644  PPL_ASSERT(OK());
2645 
2646  const dimension_type num_rows = tableau.t.num_rows();
2647  const dimension_type num_vars = tableau.s.num_columns();
2648  const dimension_type num_params = tableau.t.num_columns();
2649  Coefficient_traits::const_reference tableau_denom = tableau.denominator();
2650 
2651 #ifdef VERY_NOISY_PIP
2652  tableau.ascii_dump(std::cerr);
2653  std::cerr << "context ";
2654  ctx.ascii_dump(std::cerr);
2655 #endif // #ifdef VERY_NOISY_PIP
2656 
2657  // (Re-) Compute parameter row signs.
2658  // While at it, keep track of the first parameter rows
2659  // having negative and mixed sign.
2660  dimension_type first_negative = not_a_dim;
2661  dimension_type first_mixed = not_a_dim;
2662  for (dimension_type i = 0; i < num_rows; ++i) {
2663  Row_Sign& sign_i = sign[i];
2664  if (sign_i == UNKNOWN || sign_i == MIXED) {
2665  sign_i = row_sign(tableau.t[i], big_dimension);
2666  }
2667 
2668  if (sign_i == NEGATIVE && first_negative == not_a_dim) {
2669  first_negative = i;
2670  }
2671  else if (sign_i == MIXED && first_mixed == not_a_dim) {
2672  first_mixed = i;
2673  }
2674  }
2675 
2676  // If no negative parameter row was found, try to refine the sign of
2677  // mixed rows using compatibility checks with the current context.
2678  if (first_negative == not_a_dim && first_mixed != not_a_dim) {
2679  for (dimension_type i = first_mixed; i < num_rows; ++i) {
2680  // Consider mixed sign parameter rows only.
2681  if (sign[i] != MIXED) {
2682  continue;
2683  }
2684  const Row& t_i = tableau.t[i];
2685  Row_Sign new_sign = ZERO;
2686  // Check compatibility for constraint t_i(z) >= 0.
2687  if (compatibility_check(ctx, t_i)) {
2688  new_sign = POSITIVE;
2689  }
2690  // Check compatibility for constraint t_i(z) < 0,
2691  // i.e., -t_i(z) - 1 >= 0.
2692  Row t_i_complement(num_params);
2693  complement_assign(t_i_complement, t_i, tableau_denom);
2694  if (compatibility_check(ctx, t_i_complement)) {
2695  new_sign = (new_sign == POSITIVE) ? MIXED : NEGATIVE;
2696  }
2697  // Update sign for parameter row i.
2698  sign[i] = new_sign;
2699  // Maybe update first_negative and first_mixed.
2700  if (new_sign == NEGATIVE && first_negative == not_a_dim) {
2701  first_negative = i;
2702  if (i == first_mixed) {
2703  first_mixed = not_a_dim;
2704  }
2705  }
2706  else if (new_sign == MIXED) {
2707  if (first_mixed == not_a_dim) {
2708  first_mixed = i;
2709  }
2710  }
2711  else if (i == first_mixed) {
2712  first_mixed = not_a_dim;
2713  }
2714  }
2715  }
2716 
2717  // If there still is no negative parameter row and a mixed sign
2718  // parameter row (first_mixed) such that:
2719  // - it has at least one positive variable coefficient;
2720  // - constraint t_i(z) > 0 is not compatible with the context;
2721  // then this parameter row can be considered negative.
2722  if (first_negative == not_a_dim && first_mixed != not_a_dim) {
2723  WEIGHT_BEGIN();
2724  for (dimension_type i = first_mixed; i < num_rows; ++i) {
2725  // Consider mixed sign parameter rows only.
2726  if (sign[i] != MIXED) {
2727  continue;
2728  }
2729  // Check for a positive variable coefficient.
2730  const Row& s_i = tableau.s[i];
2731  bool has_positive = false;
2732  {
2733  for (Row::const_iterator
2734  j = s_i.begin(), j_end = s_i.end(); j != j_end; ++j) {
2735  if (*j > 0) {
2736  has_positive = true;
2737  break;
2738  }
2739  }
2740  }
2741  if (!has_positive) {
2742  continue;
2743  }
2744  // Check compatibility of constraint t_i(z) > 0.
2745  Row row(tableau.t[i]);
2747  Coefficient& row0 = row[0];
2748  pos_rem_assign(mod, row0, tableau_denom);
2749  row0 -= (mod == 0) ? tableau_denom : mod;
2750  WEIGHT_ADD(210);
2751  const bool compatible = compatibility_check(ctx, row);
2752  // Maybe update sign (and first_* indices).
2753  if (compatible) {
2754  // Sign is still mixed.
2755  if (first_mixed == not_a_dim) {
2756  first_mixed = i;
2757  }
2758  }
2759  else {
2760  // Sign becomes negative (i.e., no longer mixed).
2761  sign[i] = NEGATIVE;
2762  if (first_negative == not_a_dim) {
2763  first_negative = i;
2764  }
2765  if (first_mixed == i) {
2766  first_mixed = not_a_dim;
2767  }
2768  }
2769  }
2770  }
2771 
2772 #ifdef VERY_NOISY_PIP
2773  std::cerr << "sign =";
2774  for (dimension_type i = 0; i < sign.size(); ++i)
2775  std::cerr << " " << "?0+-*"[sign[i]];
2776  std::cerr << std::endl;
2777 #endif // #ifdef VERY_NOISY_PIP
2778 
2779  // If we have found a negative parameter row, then
2780  // either the problem is unfeasible, or a pivoting step is required.
2781  if (first_negative != not_a_dim) {
2782 
2783  // Search for the best pivot row.
2784  dimension_type pi = not_a_dim;
2785  dimension_type pj = not_a_dim;
2786  for (dimension_type i = first_negative; i < num_rows; ++i) {
2787  if (sign[i] != NEGATIVE) {
2788  continue;
2789  }
2790  dimension_type j;
2791  if (!find_lexico_minimal_column(tableau.s, mapping, basis,
2792  tableau.s[i], 0, j)) {
2793  // No positive s_ij was found: problem is unfeasible.
2794 #ifdef NOISY_PIP_TREE_STRUCTURE
2795  indent_and_print(std::cerr, indent_level,
2796  "No positive pivot: Solution = _|_\n");
2797 #endif // #ifdef NOISY_PIP_TREE_STRUCTURE
2798  delete this;
2799  return 0;
2800  }
2801  if (pj == not_a_dim
2802  || tableau.is_better_pivot(mapping, basis, i, j, pi, pj)) {
2803  // Update pivot indices.
2804  pi = i;
2805  pj = j;
2808  // Stop at first valid row.
2809  break;
2810  }
2811  }
2812  }
2813 
2814 #ifdef VERY_NOISY_PIP
2815  std::cerr << "Pivot (pi, pj) = (" << pi << ", " << pj << ")\n";
2816 #endif // #ifdef VERY_NOISY_PIP
2817 
2818  // Normalize the tableau before pivoting.
2819  tableau.normalize();
2820 
2821  // Perform pivot operation.
2822 
2823  // Update basis.
2824  {
2825  const dimension_type var_pi = var_row[pi];
2826  const dimension_type var_pj = var_column[pj];
2827  var_row[pi] = var_pj;
2828  var_column[pj] = var_pi;
2829  basis[var_pi] = true;
2830  basis[var_pj] = false;
2831  mapping[var_pi] = pj;
2832  mapping[var_pj] = pi;
2833  }
2834 
2835  PPL_DIRTY_TEMP_COEFFICIENT(product);
2837  PPL_DIRTY_TEMP_COEFFICIENT(scale_factor);
2838 
2839  // Creating identity rows corresponding to basic variable pj:
2840  // 1. add them to tableau so as to have proper size and capacity;
2841  tableau.s.add_zero_rows(1);
2842  tableau.t.add_zero_rows(1);
2843  // 2. swap the rows just added with empty ones.
2844  Row s_pivot(0);
2845  Row t_pivot(0);
2846  swap(s_pivot, tableau.s[num_rows]);
2847  swap(t_pivot, tableau.t[num_rows]);
2848  // 3. drop rows previously added at end of tableau.
2849  tableau.s.remove_trailing_rows(1);
2850  tableau.t.remove_trailing_rows(1);
2851 
2852  // Save current pivot denominator.
2853  PPL_DIRTY_TEMP_COEFFICIENT(pivot_denom);
2854  pivot_denom = tableau.denominator();
2855  // Let the (scaled) pivot coordinate be 1.
2856  s_pivot[pj] = pivot_denom;
2857 
2858  // Swap identity row with the pivot row previously found.
2859  s_pivot.m_swap(tableau.s[pi]);
2860  t_pivot.m_swap(tableau.t[pi]);
2861  sign[pi] = ZERO;
2862 
2863  PPL_DIRTY_TEMP_COEFFICIENT(s_pivot_pj);
2864  s_pivot_pj = s_pivot.get(pj);
2865 
2866  // Compute columns s[*][j]:
2867  //
2868  // <CODE>
2869  // s[i][j] -= s[i][pj] * s_pivot[j] / s_pivot_pj;
2870  // </CODE>
2871  for (dimension_type i = num_rows; i-- > 0; ) {
2872  Row& s_i = tableau.s[i];
2874  s_i_pj = s_i.get(pj);
2875 
2876  if (s_i_pj == 0) {
2877  continue;
2878  }
2879 
2880  WEIGHT_BEGIN();
2881  Row::iterator itr = s_i.end();
2882  for (Row::const_iterator
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;
2886  // Do nothing if the j-th pivot element is zero.
2887  if (s_pivot_j != 0) {
2888  product = s_pivot_j * s_i_pj;
2889  if (product % s_pivot_pj != 0) {
2890  // Must scale matrix to stay in integer case.
2891  gcd_assign(gcd, product, s_pivot_pj);
2892  exact_div_assign(scale_factor, s_pivot_pj, gcd);
2893  tableau.scale(scale_factor);
2894  s_i_pj *= scale_factor;
2895  product *= scale_factor;
2896  WEIGHT_ADD(102);
2897  }
2898  PPL_ASSERT(product % s_pivot_pj == 0);
2899  exact_div_assign(product, product, s_pivot_pj);
2900  WEIGHT_ADD(130);
2901  if (product != 0) {
2902  itr = s_i.insert(itr, j.index());
2903  *itr -= product;
2904  WEIGHT_ADD(34);
2905  }
2906  }
2907  }
2908  }
2909  }
2910 
2911  // Compute columns t[*][j]:
2912  //
2913  // <CODE>
2914  // t[i][j] -= s[i][pj] * t_pivot[j] / s_pivot_pj;
2915  // </CODE>
2916  for (dimension_type i = num_rows; i-- > 0; ) {
2917  Row& s_i = tableau.s[i];
2918  Row& t_i = tableau.t[i];
2919 
2920  Row::iterator s_i_pj_itr = s_i.find(pj);
2921 
2922  if (s_i_pj_itr == s_i.end()) {
2923  continue;
2924  }
2925 
2926  // FIXME: the following comment does not make sense.
2927  // NOTE: This is a Coefficient& instead of a
2928  // Coefficient_traits::const_reference, because scale() may silently
2929  // modify it.
2930  const Coefficient& s_i_pj = *s_i_pj_itr;
2931 
2932  if (s_i_pj == 0) {
2933  continue;
2934  }
2935 
2936  WEIGHT_BEGIN();
2937  Row::iterator k = t_i.end();
2938  for (Row::const_iterator
2939  j = t_pivot.begin(), j_end = t_pivot.end(); j != j_end; ++j) {
2940  Coefficient_traits::const_reference t_pivot_j = *j;
2941  // Do nothing if the j-th pivot element is zero.
2942  if (t_pivot_j != 0) {
2943  product = t_pivot_j * s_i_pj;
2944  if (product % s_pivot_pj != 0) {
2945  // Must scale matrix to stay in integer case.
2946  gcd_assign(gcd, product, s_pivot_pj);
2947  exact_div_assign(scale_factor, s_pivot_pj, gcd);
2948  tableau.scale(scale_factor);
2949  product *= scale_factor;
2950  WEIGHT_ADD(261);
2951  }
2952  PPL_ASSERT(product % s_pivot_pj == 0);
2953  exact_div_assign(product, product, s_pivot_pj);
2954  WEIGHT_ADD(115);
2955  if (product != 0) {
2956  k = t_i.insert(k, j.index());
2957  *k -= product;
2958  WEIGHT_ADD(41);
2959  }
2960 
2961  // Update row sign.
2962  Row_Sign& sign_i = sign[i];
2963  switch (sign_i) {
2964  case ZERO:
2965  if (product > 0) {
2966  sign_i = NEGATIVE;
2967  }
2968  else if (product < 0) {
2969  sign_i = POSITIVE;
2970  }
2971  break;
2972  case POSITIVE:
2973  if (product > 0) {
2974  sign_i = MIXED;
2975  }
2976  break;
2977  case NEGATIVE:
2978  if (product < 0) {
2979  sign_i = MIXED;
2980  }
2981  break;
2982  default:
2983  break;
2984  }
2985  }
2986  }
2987  }
2988 
2989  // Compute column s[*][pj]: s[i][pj] /= s_pivot_pj;
2990  // Update column only if pivot coordinate != 1.
2991  if (s_pivot_pj != pivot_denom) {
2992  WEIGHT_BEGIN();
2993  Row::iterator itr;
2994  for (dimension_type i = num_rows; i-- > 0; ) {
2995  Row& s_i = tableau.s[i];
2996  itr = s_i.find(pj);
2997  if (itr == s_i.end()) {
2998  continue;
2999  }
3000  WEIGHT_ADD(43);
3001  product = *itr * pivot_denom;
3002  if (product % s_pivot_pj != 0) {
3003  // As above, perform matrix scaling.
3004  gcd_assign(gcd, product, s_pivot_pj);
3005  exact_div_assign(scale_factor, s_pivot_pj, gcd);
3006  tableau.scale(scale_factor);
3007  product *= scale_factor;
3008  WEIGHT_ADD(177);
3009  }
3010  PPL_ASSERT(product % s_pivot_pj == 0);
3011  if (product != 0 || *itr != 0) {
3012  WEIGHT_ADD(106);
3013  exact_div_assign(*itr, product, s_pivot_pj);
3014  }
3015  }
3016  }
3017 
3018  // Pivoting process ended: jump to next iteration.
3019  continue;
3020  } // if (first_negative != not_a_dim)
3021 
3022 
3023  PPL_ASSERT(first_negative == not_a_dim);
3024  // If no negative parameter row was found,
3025  // but a mixed parameter row was found ...
3026  if (first_mixed != not_a_dim) {
3027  // Look for a constraint (i_neg):
3028  // - having mixed parameter sign;
3029  // - having no positive variable coefficient;
3030  // - minimizing the score (sum of parameter coefficients).
3031  dimension_type i_neg = not_a_dim;
3032  PPL_DIRTY_TEMP_COEFFICIENT(best_score);
3034  for (dimension_type i = first_mixed; i < num_rows; ++i) {
3035  // Mixed parameter sign.
3036  if (sign[i] != MIXED) {
3037  continue;
3038  }
3039  // No positive variable coefficient.
3040  bool has_positive = false;
3041  {
3042  const Row& s_i = tableau.s[i];
3043  for (Row::const_iterator
3044  j = s_i.begin(), j_end = s_i.end(); j != j_end; ++j) {
3045  if (*j > 0) {
3046  has_positive = true;
3047  break;
3048  }
3049  }
3050  }
3051  if (has_positive) {
3052  continue;
3053  }
3054  // Minimize parameter coefficient score,
3055  // eliminating implicated tautologies (if any).
3056  score = 0;
3057  {
3058  WEIGHT_BEGIN();
3059  const Row& t_i = tableau.t[i];
3060  for (Row::const_iterator
3061  j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
3062  WEIGHT_ADD(55);
3063  score += *j;
3064  }
3065  }
3066  if (i_neg == not_a_dim || score < best_score) {
3067  i_neg = i;
3068  best_score = score;
3069  }
3070  }
3071 
3072  if (i_neg != not_a_dim) {
3073  Row tautology = tableau.t[i_neg];
3074  /* Simplify tautology by exploiting integrality. */
3075  integral_simplification(tautology);
3076  ctx.add_row(tautology);
3077  add_constraint(tautology, all_params);
3078  sign[i_neg] = POSITIVE;
3079 #ifdef NOISY_PIP
3080  {
3081  Linear_Expression expr = Linear_Expression(tautology.get(0));
3082  dimension_type j = 1;
3083  for (Variables_Set::const_iterator p = all_params.begin(),
3084  p_end = all_params.end(); p != p_end; ++p, ++j)
3085  add_mul_assign(expr, tautology.get(j), Variable(*p));
3086  using namespace IO_Operators;
3087  std::cerr << std::setw(2 * indent_level) << ""
3088  << "Row " << i_neg
3089  << ": mixed param sign, negative var coeffs\n";
3090  std::cerr << std::setw(2 * indent_level) << ""
3091  << "==> adding tautology: "
3092  << Constraint(expr >= 0) << ".\n";
3093  }
3094 #endif // #ifdef NOISY_PIP
3095  // Jump to next iteration.
3096  continue;
3097  }
3098 
3099  PPL_ASSERT(i_neg == not_a_dim);
3100  // Heuristically choose "best" (mixed) pivoting row.
3101  dimension_type best_i = not_a_dim;
3102  for (dimension_type i = first_mixed; i < num_rows; ++i) {
3103  if (sign[i] != MIXED) {
3104  continue;
3105  }
3106  score = 0;
3107  {
3108  WEIGHT_BEGIN();
3109  const Row& t_i = tableau.t[i];
3110  for (Row::const_iterator
3111  j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
3112  WEIGHT_ADD(51);
3113  score += *j;
3114  }
3115  }
3116  if (best_i == not_a_dim || score < best_score) {
3117  best_score = score;
3118  best_i = i;
3119  }
3120  }
3121 
3122  Row t_test(tableau.t[best_i]);
3123  /* Simplify t_test by exploiting integrality. */
3124  integral_simplification(t_test);
3125 
3126 #ifdef NOISY_PIP
3127  {
3128  Linear_Expression expr = Linear_Expression(t_test.get(0));
3129  dimension_type j = 1;
3130  for (Variables_Set::const_iterator p = all_params.begin(),
3131  p_end = all_params.end(); p != p_end; ++p, ++j)
3132  add_mul_assign(expr, t_test.get(j), Variable(*p));
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";
3138  }
3139 #endif // #ifdef NOISY_PIP
3140 
3141  // Create a solution node for the "true" version of current node.
3142  PIP_Tree_Node* t_node = new PIP_Solution_Node(*this, No_Constraints());
3143  // Protect it from exception safety issues via std::auto_ptr.
3144  std::auto_ptr<PIP_Tree_Node> wrapped_node(t_node);
3145 
3146  // Add parametric constraint to context.
3147  ctx.add_row(t_test);
3148  // Recursively solve true node with respect to updated context.
3149 #ifdef NOISY_PIP_TREE_STRUCTURE
3150  indent_and_print(std::cerr, indent_level, "=== SOLVING THEN CHILD\n");
3151 #endif
3152  t_node = t_node->solve(pip, check_feasible_context,
3153  ctx, all_params, space_dim,
3154  indent_level + 1);
3155  // Resolution may have changed t_node: in case, re-wrap it.
3156  if (t_node != wrapped_node.get()) {
3157  wrapped_node.release();
3158  wrapped_node.reset(t_node);
3159  }
3160 
3161  // Modify *this in place to become the "false" version of current node.
3162  PIP_Tree_Node* f_node = this;
3163  // Swap aside constraints and artificial parameters
3164  // (these will be later restored if needed).
3165  Constraint_System cs;
3167  swap(cs, f_node->constraints_);
3168  swap(aps, f_node->artificial_parameters);
3169  // Compute the complement of the constraint used for the "true" node.
3170  Row& f_test = ctx[ctx.num_rows() - 1];
3171  complement_assign(f_test, t_test, 1);
3172 
3173  // Recursively solve false node with respect to updated context.
3174 #ifdef NOISY_PIP_TREE_STRUCTURE
3175  indent_and_print(std::cerr, indent_level, "=== SOLVING ELSE CHILD\n");
3176 #endif
3177  f_node = f_node->solve(pip, check_feasible_context,
3178  ctx, all_params, space_dim,
3179  indent_level + 1);
3180 
3181  // Case analysis on recursive resolution calls outcome.
3182  if (t_node == 0) {
3183  if (f_node == 0) {
3184  // Both t_node and f_node unfeasible.
3185 #ifdef NOISY_PIP_TREE_STRUCTURE
3186  indent_and_print(std::cerr, indent_level,
3187  "=== EXIT: BOTH BRANCHES UNFEASIBLE: _|_\n");
3188 #endif
3189  return 0;
3190  }
3191  else {
3192  // t_node unfeasible, f_node feasible:
3193  // restore cs and aps into f_node (i.e., this).
3194  PPL_ASSERT(f_node == this);
3195  swap(f_node->constraints_, cs);
3196  swap(f_node->artificial_parameters, aps);
3197  // Add f_test to constraints.
3198  f_node->add_constraint(f_test, all_params);
3199 #ifdef NOISY_PIP_TREE_STRUCTURE
3200  indent_and_print(std::cerr, indent_level,
3201  "=== EXIT: THEN BRANCH UNFEASIBLE: SWAP BRANCHES\n");
3202 #endif
3203  return f_node;
3204  }
3205  }
3206  else if (f_node == 0) {
3207  // t_node feasible, f_node unfeasible.
3208 #ifdef NOISY_PIP_TREE_STRUCTURE
3209  indent_and_print(std::cerr, indent_level,
3210  "=== EXIT: THEN BRANCH FEASIBLE\n");
3211 #endif
3212  // NOTE: in principle, we could merge t_node into its parent.
3213  // However, if t_node is a decision node having both children,
3214  // then we would obtain a node violating the PIP_Decision_Node
3215  // invariant saying that t_node should have a single constraint:
3216  // it will have, at least, the two splitting constraints.
3217  const PIP_Decision_Node* const decision_node_p
3218  = dynamic_cast<PIP_Decision_Node*>(t_node);
3219  if (decision_node_p != 0 && decision_node_p->false_child != 0) {
3220  // Do NOT merge: create a new decision node.
3221  PIP_Tree_Node* const parent
3222  = new PIP_Decision_Node(t_node->get_owner(), 0, t_node);
3223  // Previously wrapped 't_node' is now safe: release it
3224  // and protect new 'parent' node from exception safety issues.
3225  wrapped_node.release();
3226  wrapped_node.reset(parent);
3227  // Restore into parent `cs' and `aps'.
3228  swap(parent->constraints_, cs);
3229  swap(parent->artificial_parameters, aps);
3230  // Add t_test to parent's constraints.
3231  parent->add_constraint(t_test, all_params);
3232  // It is now safe to release previously wrapped parent pointer
3233  // and return it to caller.
3234  return wrapped_node.release();
3235  }
3236  else {
3237  // Merge t_node with its parent:
3238  // a) append into `cs' the constraints of t_node;
3240  i = t_node->constraints_.begin(),
3241  i_end = t_node->constraints_.end(); i != i_end; ++i) {
3242  cs.insert(*i);
3243  }
3244  // b) append into `aps' the parameters of t_node;
3245  aps.insert(aps.end(),
3246  t_node->artificial_parameters.begin(),
3247  t_node->artificial_parameters.end());
3248  // c) swap the updated `cs' and `aps' into t_node.
3249  swap(cs, t_node->constraints_);
3250  swap(aps, t_node->artificial_parameters);
3251  // d) add t_test to t_nodes's constraints.
3252  t_node->add_constraint(t_test, all_params);
3253  // It is now safe to release previously wrapped t_node pointer
3254  // and return it to caller.
3255  return wrapped_node.release();
3256  }
3257  }
3258 
3259  // Here both t_node and f_node are feasible:
3260  // create a new decision node.
3261 #ifdef NOISY_PIP_TREE_STRUCTURE
3262  indent_and_print(std::cerr, indent_level,
3263  "=== EXIT: BOTH BRANCHES FEASIBLE: NEW DECISION NODE\n");
3264 #endif
3266  = new PIP_Decision_Node(f_node->get_owner(), f_node, t_node);
3267  // Previously wrapped 't_node' is now safe: release it
3268  // and protect new 'parent' node from exception safety issues.
3269  wrapped_node.release();
3270  wrapped_node.reset(parent);
3271 
3272  // Add t_test to the constraints of the new decision node.
3273  parent->add_constraint(t_test, all_params);
3274 
3275  if (!cs.empty()) {
3276 #ifdef NOISY_PIP_TREE_STRUCTURE
3277  indent_and_print(std::cerr, indent_level,
3278  "=== NODE HAS BOTH BRANCHES AND TAUTOLOGIES:\n");
3279  indent_and_print(std::cerr, indent_level,
3280  "=== CREATE NEW PARENT FOR TAUTOLOGIES\n");
3281 #endif
3282  // If node to be solved had tautologies,
3283  // store them in a new decision node.
3284  parent = new PIP_Decision_Node(parent->get_owner(), 0, parent);
3285  // Previously wrapped 'parent' node is now safe: release it
3286  // and protect new 'parent' node from exception safety issues.
3287  wrapped_node.release();
3288  wrapped_node.reset(parent);
3289  swap(parent->constraints_, cs);
3290  }
3291  swap(parent->artificial_parameters, aps);
3292  // It is now safe to release previously wrapped decision node
3293  // and return it to the caller.
3294  return wrapped_node.release();
3295  } // if (first_mixed != not_a_dim)
3296 
3297 
3298  PPL_ASSERT(first_negative == not_a_dim);
3299  PPL_ASSERT(first_mixed == not_a_dim);
3300  // Here all parameters are positive: we have found a continuous
3301  // solution. If the solution happens to be integer, then it is the
3302  // solution of the integer problem. Otherwise, we may need to generate
3303  // a new cut to try and get back into the integer case.
3304 #ifdef NOISY_PIP
3305  indent_and_print(std::cerr, indent_level,
3306  "All parameters are positive.\n");
3307 #endif // #ifdef NOISY_PIP
3308  tableau.normalize();
3309 
3310  // Look for any row having non integer parameter coefficients.
3311  Coefficient_traits::const_reference denom = tableau.denominator();
3312  for (dimension_type k = 0; k < num_vars; ++k) {
3313  if (basis[k]) {
3314  // Basic variable = 0, hence integer.
3315  continue;
3316  }
3317  const dimension_type i = mapping[k];
3318  const Row& t_i = tableau.t[i];
3319  WEIGHT_BEGIN();
3320  for (Row::const_iterator
3321  j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
3322  WEIGHT_ADD(27);
3323  if (*j % denom != 0) {
3324  goto non_integer;
3325  }
3326  }
3327  }
3328  // The goto was not taken, the solution is integer.
3329 #ifdef NOISY_PIP_TREE_STRUCTURE
3330  indent_and_print(std::cerr, indent_level,
3331  "EXIT: solution found.\n");
3332 #endif // #ifdef NOISY_PIP
3333  return this;
3334 
3335  non_integer:
3336  // The solution is non-integer: generate a cut.
3338  dimension_type best_i = not_a_dim;
3339  dimension_type best_pcount = not_a_dim;
3340 
3341  const PIP_Problem::Control_Parameter_Value cutting_strategy
3343 
3344  if (cutting_strategy == PIP_Problem::CUTTING_STRATEGY_FIRST) {
3345  // Find the first row with simplest parametric part.
3346  for (dimension_type k = 0; k < num_vars; ++k) {
3347  if (basis[k]) {
3348  continue;
3349  }
3350  const dimension_type i = mapping[k];
3351  // Count the number of non-integer parameter coefficients.
3352  WEIGHT_BEGIN();
3353  dimension_type pcount = 0;
3354  const Row& t_i = tableau.t[i];
3355  for (Row::const_iterator
3356  j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
3357  WEIGHT_ADD(18);
3358  pos_rem_assign(mod, *j, denom);
3359  if (mod != 0) {
3360  ++pcount;
3361  }
3362  }
3363  if (pcount > 0 && (best_i == not_a_dim || pcount < best_pcount)) {
3364  best_pcount = pcount;
3365  best_i = i;
3366  }
3367  }
3368  // Generate cut using 'best_i'.
3369  generate_cut(best_i, all_params, ctx, space_dim, indent_level);
3370  }
3371  else {
3372  PPL_ASSERT(cutting_strategy == PIP_Problem::CUTTING_STRATEGY_DEEPEST
3373  || cutting_strategy == PIP_Problem::CUTTING_STRATEGY_ALL);
3374  // Find the row with simplest parametric part
3375  // which will generate the "deepest" cut.
3376  PPL_DIRTY_TEMP_COEFFICIENT(best_score);
3377  best_score = 0;
3379  PPL_DIRTY_TEMP_COEFFICIENT(s_score);
3380  std::vector<dimension_type> all_best_is;
3381 
3382  for (dimension_type k = 0; k < num_vars; ++k) {
3383  if (basis[k]) {
3384  continue;
3385  }
3386  const dimension_type i = mapping[k];
3387  // Compute score and pcount.
3388  score = 0;
3389  dimension_type pcount = 0;
3390  {
3391  WEIGHT_BEGIN();
3392  const Row& t_i = tableau.t[i];
3393  for (Row::const_iterator
3394  j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
3395  WEIGHT_ADD(46);
3396  pos_rem_assign(mod, *j, denom);
3397  if (mod != 0) {
3398  WEIGHT_ADD(94);
3399  score += denom;
3400  score -= mod;
3401  ++pcount;
3402  }
3403  }
3404  }
3405 
3406  // Compute s_score.
3407  s_score = 0;
3408  {
3409  WEIGHT_BEGIN();
3410  const Row& s_i = tableau.s[i];
3411  for (Row::const_iterator
3412  j = s_i.begin(), j_end = s_i.end(); j != j_end; ++j) {
3413  WEIGHT_ADD(94);
3414  pos_rem_assign(mod, *j, denom);
3415  s_score += denom;
3416  s_score -= mod;
3417  }
3418  }
3419  // Combine 'score' and 's_score'.
3420  score *= s_score;
3421  /*
3422  Select row i if it is non integer AND
3423  - no row has been chosen yet; OR
3424  - it has fewer non-integer parameter coefficients; OR
3425  - it has the same number of non-integer parameter coefficients,
3426  but its score is greater.
3427  */
3428  if (pcount != 0
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();
3434  }
3435  best_i = i;
3436  best_pcount = pcount;
3437  best_score = score;
3438  }
3439  if (pcount > 0) {
3440  all_best_is.push_back(i);
3441  }
3442  }
3443  if (cutting_strategy == PIP_Problem::CUTTING_STRATEGY_DEEPEST) {
3444  generate_cut(best_i, all_params, ctx, space_dim, indent_level);
3445  }
3446  else {
3447  PPL_ASSERT(cutting_strategy == PIP_Problem::CUTTING_STRATEGY_ALL);
3448  for (dimension_type k = all_best_is.size(); k-- > 0; ) {
3449  generate_cut(all_best_is[k], all_params, ctx,
3450  space_dim, indent_level);
3451  }
3452  }
3453  } // End of processing for non-integer solutions.
3454 
3455  } // Main loop of the simplex algorithm
3456 
3457  // This point should be unreachable.
3458  PPL_UNREACHABLE;
3459  return 0;
3460 }
3461 
3462 void
3464  Variables_Set& parameters,
3465  Matrix<Row>& context,
3466  dimension_type& space_dimension,
3467  const int indent_level) {
3468  PPL_ASSERT(indent_level >= 0);
3469 #ifdef NOISY_PIP
3470  std::cerr << std::setw(2 * indent_level) << ""
3471  << "Row " << index << " requires cut generation.\n";
3472 #else
3473  PPL_USED(indent_level);
3474 #endif // #ifdef NOISY_PIP
3475 
3476  const dimension_type num_rows = tableau.t.num_rows();
3477  PPL_ASSERT(index < num_rows);
3478  const dimension_type num_vars = tableau.s.num_columns();
3479  const dimension_type num_params = tableau.t.num_columns();
3480  PPL_ASSERT(num_params == 1 + parameters.size());
3481  Coefficient_traits::const_reference denom = tableau.denominator();
3482 
3485 
3486  // Test if cut to be generated must be parametric or not.
3487  bool generate_parametric_cut = false;
3488  {
3489  // Limiting the scope of reference row_t (may be later invalidated).
3490  const Row& row_t = tableau.t[index];
3491  Row::const_iterator j = row_t.begin();
3492  Row::const_iterator j_end = row_t.end();
3493  // Skip the element with index 0.
3494  if (j != j_end && j.index() == 0) {
3495  ++j;
3496  }
3497  WEIGHT_BEGIN();
3498  for ( ; j != j_end; ++j) {
3499  WEIGHT_ADD(7);
3500  if (*j % denom != 0) {
3501  generate_parametric_cut = true;
3502  break;
3503  }
3504  }
3505  }
3506 
3507  // Column index of already existing Artificial_Parameter.
3508  dimension_type ap_column = not_a_dimension();
3509 
3510  if (generate_parametric_cut) {
3511  // Fractional parameter coefficient found: generate parametric cut.
3512  bool reuse_ap = false;
3513  Linear_Expression expr;
3514 
3515  // Limiting the scope of reference row_t (may be later invalidated).
3516  {
3517  const Row& row_t = tableau.t[index];
3518  Row::const_iterator j = row_t.begin();
3519  Row::const_iterator j_end = row_t.end();
3520  if (j != j_end && j.index() == 0) {
3521  pos_rem_assign(mod, *j, denom);
3522  ++j;
3523  if (mod != 0) {
3524  // Optimizing computation: expr += (denom - mod);
3525  expr += denom;
3526  expr -= mod;
3527  }
3528  }
3529  if (!parameters.empty()) {
3530  // To avoid reallocations of expr.
3531  add_mul_assign(expr, 0, Variable(*(parameters.rbegin())));
3532  Variables_Set::const_iterator p_j = parameters.begin();
3533  dimension_type last_index = 1;
3534  WEIGHT_BEGIN();
3535  for ( ; j != j_end; ++j) {
3536  WEIGHT_ADD(69);
3537  pos_rem_assign(mod, *j, denom);
3538  if (mod != 0) {
3539  // Optimizing computation: expr += (denom - mod) * Variable(*p_j);
3540  WEIGHT_ADD(164);
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();
3545  add_mul_assign(expr, coeff, Variable(*p_j));
3546  }
3547  }
3548  }
3549  }
3550  // Generate new artificial parameter.
3551  const Artificial_Parameter ap(expr, denom);
3552 
3553  // Search if the Artificial_Parameter has already been generated.
3554  ap_column = space_dimension;
3555  const PIP_Tree_Node* node = this;
3556  do {
3557  for (dimension_type j = node->artificial_parameters.size(); j-- > 0; ) {
3558  --ap_column;
3559  if (node->artificial_parameters[j] == ap) {
3560  reuse_ap = true;
3561  break;
3562  }
3563  }
3564  node = node->parent();
3565  } while (!reuse_ap && node != 0);
3566 
3567  if (reuse_ap) {
3568  // We can re-use an existing Artificial_Parameter.
3569 #ifdef NOISY_PIP
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;
3576  }
3577  else {
3578  // Here reuse_ap == false: the Artificial_Parameter does not exist yet.
3579  // Beware: possible reallocation invalidates row references.
3580  tableau.t.add_zero_columns(1);
3581  context.add_zero_columns(1);
3582  artificial_parameters.push_back(ap);
3583  parameters.insert(space_dimension);
3584 #ifdef NOISY_PIP
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
3590  ++space_dimension;
3591  ap_column = num_params;
3592 
3593  // Update current context with constraints on the new parameter.
3594  const dimension_type ctx_num_rows = context.num_rows();
3595  context.add_zero_rows(2);
3596  Row& ctx1 = context[ctx_num_rows];
3597  Row& ctx2 = context[ctx_num_rows+1];
3598  // Recompute row reference after possible reallocation.
3599  const Row& row_t = tableau.t[index];
3600  {
3601  Row::const_iterator j = row_t.begin();
3602  Row::const_iterator j_end = row_t.end();
3603  Row::iterator itr1 = ctx1.end();
3604  Row::iterator itr2 = ctx2.end();
3605  if (j != j_end && j.index() == 0) {
3606  pos_rem_assign(mod, *j, denom);
3607  if (mod != 0) {
3608  itr1 = ctx1.insert(0, denom);
3609  *itr1 -= mod;
3610  itr2 = ctx2.insert(0, *itr1);
3611  neg_assign(*itr2);
3612  // Compute <CODE> ctx2[0] += denom-1; </CODE>
3613  *itr2 += denom;
3614  --(*itr2);
3615  }
3616  else {
3617  // Compute <CODE> ctx2[0] += denom-1; </CODE>
3618  itr2 = ctx2.insert(0, denom);
3619  --(*itr2);
3620  }
3621  ++j;
3622  }
3623  else {
3624  // Compute <CODE> ctx2[0] += denom-1; </CODE>
3625  itr2 = ctx2.insert(0, denom);
3626  --(*itr2);
3627  }
3628  WEIGHT_BEGIN();
3629  for ( ; j != j_end; ++j) {
3630  pos_rem_assign(mod, *j, denom);
3631  if (mod != 0) {
3632  const dimension_type j_index = j.index();
3633  itr1 = ctx1.insert(itr1, j_index, denom);
3634  *itr1 -= mod;
3635  itr2 = ctx2.insert(itr2, j_index, *itr1);
3636  neg_assign(*itr2);
3637  WEIGHT_ADD(294);
3638  }
3639  }
3640  itr1 = ctx1.insert(itr1, num_params, denom);
3641  neg_assign(*itr1);
3642  itr2 = ctx2.insert(itr2, num_params, denom);
3643  WEIGHT_ADD(122);
3644  }
3645 
3646 #ifdef NOISY_PIP
3647  {
3648  using namespace IO_Operators;
3649  Variables_Set::const_iterator p = parameters.begin();
3650  Linear_Expression expr1(ctx1.get(0));
3651  Linear_Expression expr2(ctx2.get(0));
3652  for (dimension_type j = 1; j <= num_params; ++j, ++p) {
3653  add_mul_assign(expr1, ctx1.get(j), Variable(*p));
3654  add_mul_assign(expr2, ctx2.get(j), Variable(*p));
3655  }
3656  std::cerr << std::setw(2 * indent_level) << ""
3657  << "Adding to context: "
3658  << Constraint(expr1 >= 0) << " ; "
3659  << Constraint(expr2 >= 0) << std::endl;
3660  }
3661 #endif // #ifdef NOISY_PIP
3662  }
3663  }
3664 
3665  // Generate new cut.
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];
3670  // Recompute references after possible reallocation.
3671  const Row& row_s = tableau.s[index];
3672  const Row& row_t = tableau.t[index];
3673  WEIGHT_BEGIN();
3674  {
3675  Row::iterator itr = cut_s.end();
3676  for (Row::const_iterator
3677  j = row_s.begin(), j_end = row_s.end(); j != j_end; ++j) {
3678  WEIGHT_ADD(55);
3679  itr = cut_s.insert(itr, j.index(), *j);
3680  pos_rem_assign(*itr, *itr, denom);
3681  }
3682  }
3683  {
3684  Row::iterator cut_t_itr = cut_t.end();
3685  for (Row::const_iterator
3686  j = row_t.begin(), j_end = row_t.end(); j!=j_end; ++j) {
3687  WEIGHT_ADD(37);
3688  pos_rem_assign(mod, *j, denom);
3689  if (mod != 0) {
3690  WEIGHT_ADD(108);
3691  cut_t_itr = cut_t.insert(cut_t_itr, j.index(), mod);
3692  *cut_t_itr -= denom;
3693  }
3694  }
3695  }
3696  if (ap_column != not_a_dimension()) {
3697  // If we re-use an existing Artificial_Parameter
3698  cut_t[ap_column] = denom;
3699  }
3700 #ifdef NOISY_PIP
3701  {
3702  using namespace IO_Operators;
3703  Linear_Expression expr;
3704  dimension_type ti = 1;
3705  dimension_type si = 0;
3706  for (dimension_type j = 0; j < space_dimension; ++j) {
3707  if (parameters.count(j) == 1) {
3708  add_mul_assign(expr, cut_t.get(ti), Variable(j));
3709  ++ti;
3710  }
3711  else {
3712  add_mul_assign(expr, cut_s.get(si), Variable(j));
3713  ++si;
3714  }
3715  }
3716  std::cerr << std::setw(2 * indent_level) << ""
3717  << "Adding cut: "
3718  << Constraint(expr + cut_t.get(0) >= 0)
3719  << std::endl;
3720  }
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);
3725  sign.push_back(NEGATIVE);
3726 }
3727 
3728 
3733 }
3734 
3737  return sizeof(*this) + external_memory_in_bytes();
3738 }
3739 
3743  // Adding the external memory for `artificial_parameters'.
3744  n += artificial_parameters.capacity() * sizeof(Artificial_Parameter);
3745  for (Artificial_Parameter_Sequence::const_iterator
3746  ap = art_parameter_begin(),
3747  ap_end = art_parameter_end(); ap != ap_end; ++ap) {
3748  n += (ap->external_memory_in_bytes());
3749  }
3750 
3751  return n;
3752 }
3753 
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();
3761  }
3762  return n;
3763 }
3764 
3767  return sizeof(*this) + external_memory_in_bytes();
3768 }
3769 
3773  + s.external_memory_in_bytes()
3774  + t.external_memory_in_bytes();
3775 }
3776 
3780  n += tableau.external_memory_in_bytes();
3781  // FIXME: size of std::vector<bool> ?
3782  n += basis.capacity() * sizeof(bool);
3783  n += sizeof(dimension_type)
3784  * (mapping.capacity() + var_row.capacity() + var_column.capacity());
3785  n += sign.capacity() * sizeof(Row_Sign);
3786  // FIXME: Adding the external memory for `solution'.
3787  n += solution.capacity() * sizeof(Linear_Expression);
3788  for (std::vector<Linear_Expression>::const_iterator
3789  i = solution.begin(), i_end = solution.end();
3790  i != i_end; ++i) {
3791  n += (i->external_memory_in_bytes());
3792  }
3793 
3794  return n;
3795 }
3796 
3799  return sizeof(*this) + external_memory_in_bytes();
3800 }
3801 
3802 void
3804  const int indent,
3805  const char* str) {
3806  PPL_ASSERT(indent >= 0);
3807  s << std::setw(2 * indent) << "" << str;
3808 }
3809 
3810 void
3811 PIP_Tree_Node::print(std::ostream& s, const int indent) const {
3812  const dimension_type pip_space_dim = get_owner()->space_dimension();
3813  const Variables_Set& pip_params = get_owner()->parameter_space_dimensions();
3814 
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;
3819  }
3820 
3821  dimension_type first_art_dim = pip_space_dim;
3822  for (const PIP_Tree_Node* node = parent();
3823  node != 0; node = node->parent()) {
3824  first_art_dim += node->art_parameter_count();
3825  }
3826 
3827  print_tree(s, indent, pip_dim_is_param, first_art_dim);
3828 }
3829 
3830 void
3831 PIP_Tree_Node::print_tree(std::ostream& s, const int indent,
3832  const std::vector<bool>&,
3833  dimension_type first_art_dim) const {
3834  using namespace IO_Operators;
3835 
3836  // Print artificial parameters.
3837  for (Artificial_Parameter_Sequence::const_iterator
3838  api = art_parameter_begin(),
3839  api_end = art_parameter_end(); api != api_end; ++api) {
3840  indent_and_print(s, indent, "Parameter ");
3841  s << Variable(first_art_dim) << " = " << *api << "\n";
3842  ++first_art_dim;
3843  }
3844 
3845  // Print constraints, if any.
3846  if (!constraints_.empty()) {
3847  indent_and_print(s, indent, "if ");
3848 
3851  PPL_ASSERT(ci != ci_end);
3852  s << *ci;
3853  for (++ci; ci != ci_end; ++ci) {
3854  s << " and " << *ci;
3855  }
3856 
3857  s << " then\n";
3858  }
3859 }
3860 
3861 void
3862 PIP_Decision_Node::print_tree(std::ostream& s, const int indent,
3863  const std::vector<bool>& pip_dim_is_param,
3864  const dimension_type first_art_dim) const {
3865  // First print info common to decision and solution nodes.
3866  PIP_Tree_Node::print_tree(s, indent, pip_dim_is_param, first_art_dim);
3867 
3868  // Then print info specific of decision nodes.
3869  const dimension_type child_first_art_dim
3870  = first_art_dim + art_parameter_count();
3871 
3872  PPL_ASSERT(true_child != 0);
3873  true_child->print_tree(s, indent+1, pip_dim_is_param, child_first_art_dim);
3874 
3875  indent_and_print(s, indent, "else\n");
3876 
3877  if (false_child != 0) {
3878  false_child->print_tree(s, indent+1, pip_dim_is_param,
3879  child_first_art_dim);
3880  }
3881  else {
3882  indent_and_print(s, indent+1, "_|_\n");
3883  }
3884 }
3885 
3886 void
3887 PIP_Solution_Node::print_tree(std::ostream& s, const int indent,
3888  const std::vector<bool>& pip_dim_is_param,
3889  const dimension_type first_art_dim) const {
3890  // Print info common to decision and solution nodes.
3891  PIP_Tree_Node::print_tree(s, indent, pip_dim_is_param, first_art_dim);
3892 
3893  // Print info specific of solution nodes:
3894  // first update solution if needed ...
3895  update_solution(pip_dim_is_param);
3896  // ... and then actually print it.
3897  const bool no_constraints = constraints_.empty();
3898  indent_and_print(s, indent + (no_constraints ? 0 : 1), "{");
3899  const dimension_type pip_space_dim = pip_dim_is_param.size();
3900  for (dimension_type i = 0, num_var = 0; i < pip_space_dim; ++i) {
3901  if (pip_dim_is_param[i]) {
3902  continue;
3903  }
3904  if (num_var > 0) {
3905  s << " ; ";
3906  }
3907  using namespace IO_Operators;
3908  s << solution[num_var];
3909  ++num_var;
3910  }
3911  s << "}\n";
3912 
3913  if (!no_constraints) {
3914  indent_and_print(s, indent, "else\n");
3915  indent_and_print(s, indent+1, "_|_\n");
3916  }
3917 }
3918 
3919 const Linear_Expression&
3921  const PIP_Problem* const pip = get_owner();
3922  PPL_ASSERT(pip != 0);
3923 
3924  const dimension_type space_dim = pip->space_dimension();
3925  if (var.space_dimension() > space_dim) {
3926  std::ostringstream s;
3927  s << "PPL::PIP_Solution_Node::parametric_values(v):\n"
3928  << "v.space_dimension() == " << var.space_dimension()
3929  << " is incompatible with the owning PIP_Problem "
3930  << " (space dim == " << space_dim << ").";
3931  throw std::invalid_argument(s.str());
3932  }
3933 
3934  dimension_type solution_index = var.id();
3935  const Variables_Set& params = pip->parameter_space_dimensions();
3936  for (Variables_Set::const_iterator p = params.begin(),
3937  p_end = params.end(); p != p_end; ++p) {
3938  const dimension_type param_index = *p;
3939  if (param_index < var.id()) {
3940  --solution_index;
3941  }
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.");
3946  }
3947  else {
3948  break;
3949  }
3950  }
3951 
3952  update_solution();
3953  return solution[solution_index];
3954 }
3955 
3956 
3957 void
3959  // Avoid doing useless work.
3960  if (solution_valid) {
3961  return;
3962  }
3963  const PIP_Problem* const pip = get_owner();
3964  PPL_ASSERT(pip != 0);
3965  std::vector<bool> pip_dim_is_param(pip->space_dimension());
3966  const Variables_Set& params = pip->parameter_space_dimensions();
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;
3970  }
3971 
3972  update_solution(pip_dim_is_param);
3973 }
3974 
3975 void
3977 ::update_solution(const std::vector<bool>& pip_dim_is_param) const {
3978  // Avoid doing useless work.
3979  if (solution_valid) {
3980  return;
3981  }
3982 
3983  // const_cast required so as to refresh the solution cache.
3984  PIP_Solution_Node& x = const_cast<PIP_Solution_Node&>(*this);
3985 
3986  const dimension_type num_pip_dims = pip_dim_is_param.size();
3987  const dimension_type num_pip_vars = tableau.s.num_columns();
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;
3991 
3992  if (solution.size() != num_pip_vars) {
3993  x.solution.resize(num_pip_vars);
3994  }
3995 
3996  // Compute external "names" (i.e., indices) for all parameters.
3997  std::vector<dimension_type> all_param_names(num_all_params);
3998 
3999  // External indices for problem parameters.
4000  for (dimension_type i = 0, p_index = 0; i < num_pip_dims; ++i) {
4001  if (pip_dim_is_param[i]) {
4002  all_param_names[p_index] = i;
4003  ++p_index;
4004  }
4005  }
4006  // External indices for artificial parameters.
4007  for (dimension_type i = 0; i < num_art_params; ++i) {
4008  all_param_names[num_pip_params + i] = num_pip_dims + i;
4009  }
4010 
4011 
4012  PPL_DIRTY_TEMP_COEFFICIENT(norm_coeff);
4013  Coefficient_traits::const_reference denom = tableau.denominator();
4014  for (dimension_type i = num_pip_vars; i-- > 0; ) {
4015  Linear_Expression& sol_i = x.solution[i];
4016  sol_i = Linear_Expression(0);
4017  if (basis[i]) {
4018  continue;
4019  }
4020  const Row& row = tableau.t[mapping[i]];
4021 
4022  // Start from index 1 to skip the inhomogeneous term.
4023  Row::const_iterator j = row.begin();
4024  Row::const_iterator j_end = row.end();
4025  // Skip the element with index 0.
4026  if (j != j_end && j.index() == 0) {
4027  ++j;
4028  }
4029  for ( ; j != j_end; ++j) {
4030  Coefficient_traits::const_reference coeff = *j;
4031  if (coeff == 0) {
4032  continue;
4033  }
4034  norm_coeff = coeff / denom;
4035  if (norm_coeff != 0) {
4036  add_mul_assign(sol_i, norm_coeff,
4037  Variable(all_param_names[j.index() - 1]));
4038  }
4039  }
4040  norm_coeff = row.get(0) / denom;
4041  sol_i += norm_coeff;
4042  }
4043 
4044  // Mark solution as valid.
4045  x.solution_valid = true;
4046 }
4047 
4048 } // namespace Parma_Polyhedra_Library
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.
Definition: PIP_Tree.cc:3887
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.
Definition: PIP_Tree.cc:979
Coefficient denom
The normalized (i.e., positive) denominator.
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 &parameters)
Implements pure virtual method PIP_Tree_Node::update_tableau.
Definition: PIP_Tree.cc:1374
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.
Definition: PIP_Tree.cc:992
static bool compatibility_check(Matrix< Row > &s)
Checks whether a context matrix is satisfiable.
Definition: PIP_Tree.cc:2195
A linear equality or inequality.
virtual void set_owner(const PIP_Problem *owner)
Sets the pointer to the PIP_Problem owning object.
Definition: PIP_Tree.cc:1120
virtual memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
Definition: PIP_Tree.cc:3755
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 &parameters)
Implements pure virtual method PIP_Tree_Node::update_tableau.
Definition: PIP_Tree.cc:2406
virtual void set_owner(const PIP_Problem *owner)
Sets the pointer to the PIP_Problem owning object.
Definition: PIP_Tree.cc:1125
void generate_cut(dimension_type index, Variables_Set &parameters, Matrix< Row > &context, dimension_type &space_dimension, int indent_level)
Generate a Gomory cut using non-integer tableau row index.
Definition: PIP_Tree.cc:3463
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.
bool ascii_load(std::istream &s)
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this ...
Definition: PIP_Tree.cc:1830
virtual bool OK() const
Returns true if and only if *this is well formed.
Definition: PIP_Tree.cc:1263
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.
Definition: PIP_Tree.cc:3920
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.
Coefficient cost
Definition: PIP_Tree.cc:617
virtual memory_size_type total_memory_in_bytes() const
Returns the total size in bytes of the memory occupied by *this.
Definition: PIP_Tree.cc:3798
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.
Definition: PIP_Tree.cc:1873
static Row_Sign row_sign(const Row &x, dimension_type big_dimension)
Returns the sign of row x.
Definition: PIP_Tree.cc:2152
A sparse matrix of Coefficient.
Definition: Matrix_defs.hh:37
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...
Definition: PIP_Tree.cc:1984
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.
Definition: PIP_Tree.cc:916
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.
Definition: PIP_Tree.cc:3741
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)
Definition: globals_defs.hh:83
PIP_Solution_Node(const PIP_Problem *owner)
Constructor: builds a solution node owned by *owner.
Definition: PIP_Tree.cc:1036
virtual ~PIP_Decision_Node()
Destructor.
Definition: PIP_Tree.cc:1114
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...
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.
Definition: PIP_Tree.cc:1868
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.
Definition: PIP_Tree.cc:3862
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...
void ascii_dump(std::ostream &s) const
Dumps to s an ASCII representation of *this.
Definition: PIP_Tree.cc:1818
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.
Definition: PIP_Tree.cc:1082
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.
Definition: PIP_Tree.cc:1168
void parent_merge()
Merges parent's artificial parameters into *this.
Definition: PIP_Tree.cc:1251
virtual ~PIP_Tree_Node()
Destructor.
Definition: PIP_Tree.cc:930
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.
Definition: PIP_Tree.cc:3831
virtual PIP_Tree_Node * solve(const PIP_Problem &pip, bool check_feasible_context, const Matrix< Row > &context, const Variables_Set &params, dimension_type space_dim, int indent_level)
Implements pure virtual method PIP_Tree_Node::solve.
Definition: PIP_Tree.cc:2605
virtual bool OK() const =0
Returns true if and only if *this is well formed.
Definition: PIP_Tree.cc:1197
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.
Definition: PIP_Tree.cc:3736
bool OK() const
Returns true if and only if the parameter is well-formed.
Definition: PIP_Tree.cc:997
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.
Definition: PIP_Tree.cc:1909
virtual const PIP_Solution_Node * as_solution() const
Returns this.
Definition: PIP_Tree.cc:1163
void ascii_dump(std::ostream &s) const
Dumps to s an ASCII representation of *this.
Definition: PIP_Tree.cc:1525
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.
Definition: PIP_Tree.cc:1148
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.
Definition: PIP_Tree.cc:1335
#define WEIGHT_ADD_MUL(delta, factor)
Definition: globals_defs.hh:90
dimension_type row_index
Definition: PIP_Tree.cc:615
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.
Definition: PIP_Tree.cc:1714
std::vector< Linear_Expression > solution
Parametric values for the solution.
Coefficient value
Definition: PIP_Tree.cc:618
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 ...
Definition: PIP_Tree.cc:1016
#define WEIGHT_BEGIN()
Definition: globals_defs.hh:81
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...
Definition: PIP_Tree.cc:1136
virtual memory_size_type total_memory_in_bytes() const
Returns the total size in bytes of the memory occupied by *this.
Definition: PIP_Tree.cc:3766
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.
Definition: PIP_Tree.cc:1158
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.
Definition: version.hh:61
A const iterator on the tree elements, ordered by key.
void update_solution() const
Helper method.
Definition: PIP_Tree.cc:3958
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...
Definition: PIP_Tree.cc:1141
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
Definition: PIP_Tree.cc:3771
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.
Definition: PIP_Tree.cc:1079
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.
Definition: PIP_Tree.cc:1654
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 &parameters)
Inserts a new parametric constraint in internal row format.
Definition: PIP_Tree.cc:1222
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.
Definition: PIP_Tree.cc:3730
void gcd_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
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.
Definition: compiler.hh:39
virtual PIP_Tree_Node * clone() const
Returns a pointer to a dynamically-allocated copy of *this.
Definition: PIP_Tree.cc:1863
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.
Definition: PIP_Tree.cc:1153
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.
Definition: PIP_Tree.cc:1733
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 &params, dimension_type space_dim, int indent_level)
Implements pure virtual method PIP_Tree_Node::solve.
Definition: PIP_Tree.cc:1397
Coefficient c
Definition: PIP_Tree.cc:64
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 &params, 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.
Definition: PIP_Tree.cc:3778
bool ascii_load(std::istream &s)
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this ...
Definition: PIP_Tree.cc:1571
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.
Definition: PIP_Tree.cc:3803
void print(std::ostream &s, int indent=0) const
Prints on s the tree rooted in *this.
Definition: PIP_Tree.cc:3811
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...
Definition: PIP_Tree.cc:1882
Constraint_System_const_iterator const_iterator