PPL  1.2
BD_Shape_templates.hh
Go to the documentation of this file.
1 /* BD_Shape class implementation: non-inline template 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 #ifndef PPL_BD_Shape_templates_hh
25 #define PPL_BD_Shape_templates_hh 1
26 
27 #include "Generator_System_defs.hh"
31 #include "Interval_defs.hh"
32 #include "Linear_Form_defs.hh"
35 #include "MIP_Problem_defs.hh"
36 #include "Variables_Set_defs.hh"
37 #include "Bit_Row_defs.hh"
38 #include "Temp_defs.hh"
39 #include "assertions.hh"
40 #include <vector>
41 #include <deque>
42 #include <iostream>
43 #include <sstream>
44 #include <stdexcept>
45 #include <algorithm>
46 
47 namespace Parma_Polyhedra_Library {
48 
49 template <typename T>
51  : dbm(cgs.space_dimension() + 1),
52  status(),
53  redundancy_dbm() {
54  add_congruences(cgs);
55 }
56 
57 template <typename T>
59  : dbm(gs.space_dimension() + 1), status(), redundancy_dbm() {
60  const Generator_System::const_iterator gs_begin = gs.begin();
61  const Generator_System::const_iterator gs_end = gs.end();
62  if (gs_begin == gs_end) {
63  // An empty generator system defines the empty BD shape.
64  set_empty();
65  return;
66  }
67 
68  const dimension_type space_dim = space_dimension();
69  DB_Row<N>& dbm_0 = dbm[0];
70  PPL_DIRTY_TEMP(N, tmp);
71 
72  bool dbm_initialized = false;
73  bool point_seen = false;
74  // Going through all the points and closure points.
75  for (Generator_System::const_iterator gs_i = gs_begin;
76  gs_i != gs_end; ++gs_i) {
77  const Generator& g = *gs_i;
78  switch (g.type()) {
79  case Generator::POINT:
80  point_seen = true;
81  // Intentionally fall through.
83  if (!dbm_initialized) {
84  // When handling the first (closure) point, we initialize the DBM.
85  dbm_initialized = true;
86  const Coefficient& d = g.divisor();
87  // TODO: Check if the following loop can be optimized used
88  // Generator::expr_type::const_iterator.
89  for (dimension_type i = space_dim; i > 0; --i) {
90  const Coefficient& g_i = g.expression().get(Variable(i - 1));
91  DB_Row<N>& dbm_i = dbm[i];
92  for (dimension_type j = space_dim; j > 0; --j) {
93  if (i != j) {
94  const Coefficient& g_j = g.expression().get(Variable(j - 1));
95  div_round_up(dbm_i[j], g_j - g_i, d);
96  }
97  }
98  div_round_up(dbm_i[0], -g_i, d);
99  }
100  for (dimension_type j = space_dim; j > 0; --j) {
101  const Coefficient& g_j = g.expression().get(Variable(j - 1));
102  div_round_up(dbm_0[j], g_j, d);
103  }
104  // Note: no need to initialize the first element of the main diagonal.
105  }
106  else {
107  // This is not the first point: the DBM already contains
108  // valid values and we must compute maxima.
109  const Coefficient& d = g.divisor();
110  // TODO: Check if the following loop can be optimized used
111  // Generator::expr_type::const_iterator.
112  for (dimension_type i = space_dim; i > 0; --i) {
113  const Coefficient& g_i = g.expression().get(Variable(i - 1));
114  DB_Row<N>& dbm_i = dbm[i];
115  // The loop correctly handles the case when i == j.
116  for (dimension_type j = space_dim; j > 0; --j) {
117  const Coefficient& g_j = g.expression().get(Variable(j - 1));
118  div_round_up(tmp, g_j - g_i, d);
119  max_assign(dbm_i[j], tmp);
120  }
121  div_round_up(tmp, -g_i, d);
122  max_assign(dbm_i[0], tmp);
123  }
124  for (dimension_type j = space_dim; j > 0; --j) {
125  const Coefficient& g_j = g.expression().get(Variable(j - 1));
126  div_round_up(tmp, g_j, d);
127  max_assign(dbm_0[j], tmp);
128  }
129  }
130  break;
131  default:
132  // Lines and rays temporarily ignored.
133  break;
134  }
135  }
136 
137  if (!point_seen) {
138  // The generator system is not empty, but contains no points.
139  throw_invalid_argument("BD_Shape(gs)",
140  "the non-empty generator system gs "
141  "contains no points.");
142  }
143 
144  // Going through all the lines and rays.
145  for (Generator_System::const_iterator gs_i = gs_begin;
146  gs_i != gs_end; ++gs_i) {
147  const Generator& g = *gs_i;
148  switch (g.type()) {
149  case Generator::LINE:
150  // TODO: Check if the following loop can be optimized used
151  // Generator::expr_type::const_iterator.
152  for (dimension_type i = space_dim; i > 0; --i) {
153  const Coefficient& g_i = g.expression().get(Variable(i - 1));
154  DB_Row<N>& dbm_i = dbm[i];
155  // The loop correctly handles the case when i == j.
156  for (dimension_type j = space_dim; j > 0; --j) {
157  if (g_i != g.expression().get(Variable(j - 1))) {
159  }
160  }
161  if (g_i != 0) {
163  }
164  }
166  i_end = g.expression().end(); i != i_end; ++i) {
167  assign_r(dbm_0[i.variable().space_dimension()],
169  }
170  break;
171  case Generator::RAY:
172  // TODO: Check if the following loop can be optimized used
173  // Generator::expr_type::const_iterator.
174  for (dimension_type i = space_dim; i > 0; --i) {
175  const Coefficient& g_i = g.expression().get(Variable(i - 1));
176  DB_Row<N>& dbm_i = dbm[i];
177  // The loop correctly handles the case when i == j.
178  for (dimension_type j = space_dim; j > 0; --j) {
179  if (g_i < g.expression().get(Variable(j - 1))) {
181  }
182  }
183  if (g_i < 0) {
185  }
186  }
188  i_end = g.expression().end(); i != i_end; ++i) {
189  if (*i > 0) {
190  assign_r(dbm_0[i.variable().space_dimension()],
192  }
193  }
194  break;
195  default:
196  // Points and closure points already dealt with.
197  break;
198  }
199  }
201  PPL_ASSERT(OK());
202 }
203 
204 template <typename T>
206  : dbm(), status(), redundancy_dbm() {
207  const dimension_type num_dimensions = ph.space_dimension();
208 
209  if (ph.marked_empty()) {
210  *this = BD_Shape<T>(num_dimensions, EMPTY);
211  return;
212  }
213 
214  if (num_dimensions == 0) {
215  *this = BD_Shape<T>(num_dimensions, UNIVERSE);
216  return;
217  }
218 
219  // Build from generators when we do not care about complexity
220  // or when the process has polynomial complexity.
221  if (complexity == ANY_COMPLEXITY
223  *this = BD_Shape<T>(ph.generators());
224  return;
225  }
226 
227  // We cannot afford exponential complexity, we do not have a complete set
228  // of generators for the polyhedron, and the polyhedron is not trivially
229  // empty or zero-dimensional. Constraints, however, are up to date.
230  PPL_ASSERT(ph.constraints_are_up_to_date());
231 
233  // If the constraint system of the polyhedron is minimized,
234  // the test `is_universe()' has polynomial complexity.
235  if (ph.is_universe()) {
236  *this = BD_Shape<T>(num_dimensions, UNIVERSE);
237  return;
238  }
239  }
240 
241  // See if there is at least one inconsistent constraint in `ph.con_sys'.
243  cs_end = ph.con_sys.end(); i != cs_end; ++i) {
244  if (i->is_inconsistent()) {
245  *this = BD_Shape<T>(num_dimensions, EMPTY);
246  return;
247  }
248  }
249 
250  // If `complexity' allows it, use simplex to derive the exact (modulo
251  // the fact that our BDSs are topologically closed) variable bounds.
252  if (complexity == SIMPLEX_COMPLEXITY) {
253  MIP_Problem lp(num_dimensions);
255 
256  const Constraint_System& ph_cs = ph.constraints();
257  if (!ph_cs.has_strict_inequalities()) {
258  lp.add_constraints(ph_cs);
259  }
260  else {
261  // Adding to `lp' a topologically closed version of `ph_cs'.
262  for (Constraint_System::const_iterator i = ph_cs.begin(),
263  ph_cs_end = ph_cs.end(); i != ph_cs_end; ++i) {
264  const Constraint& c = *i;
265  if (c.is_strict_inequality()) {
266  Linear_Expression expr(c.expression());
267  lp.add_constraint(expr >= 0);
268  }
269  else {
270  lp.add_constraint(c);
271  }
272  }
273  }
274 
275  // Check for unsatisfiability.
276  if (!lp.is_satisfiable()) {
277  *this = BD_Shape<T>(num_dimensions, EMPTY);
278  return;
279  }
280 
281  // Start with a universe BDS that will be refined by the simplex.
282  *this = BD_Shape<T>(num_dimensions, UNIVERSE);
283  // Get all the upper bounds.
284  Generator g(point());
287  for (dimension_type i = 1; i <= num_dimensions; ++i) {
288  Variable x(i-1);
289  // Evaluate optimal upper bound for `x <= ub'.
291  if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
292  g = lp.optimizing_point();
293  lp.evaluate_objective_function(g, numer, denom);
294  div_round_up(dbm[0][i], numer, denom);
295  }
296  // Evaluate optimal upper bound for `x - y <= ub'.
297  for (dimension_type j = 1; j <= num_dimensions; ++j) {
298  if (i == j) {
299  continue;
300  }
301  Variable y(j-1);
302  lp.set_objective_function(x - y);
303  if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
304  g = lp.optimizing_point();
305  lp.evaluate_objective_function(g, numer, denom);
306  div_round_up(dbm[j][i], numer, denom);
307  }
308  }
309  // Evaluate optimal upper bound for `-x <= ub'.
310  lp.set_objective_function(-x);
311  if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
312  g = lp.optimizing_point();
313  lp.evaluate_objective_function(g, numer, denom);
314  div_round_up(dbm[i][0], numer, denom);
315  }
316  }
318  PPL_ASSERT(OK());
319  return;
320  }
321 
322  // Extract easy-to-find bounds from constraints.
323  PPL_ASSERT(complexity == POLYNOMIAL_COMPLEXITY);
324  *this = BD_Shape<T>(num_dimensions, UNIVERSE);
326 }
327 
328 template <typename T>
331  const dimension_type space_dim = space_dimension();
332  // A zero-space-dim shape always has affine dimension zero.
333  if (space_dim == 0) {
334  return 0;
335  }
336  // Shortest-path closure is necessary to detect emptiness
337  // and all (possibly implicit) equalities.
338  shortest_path_closure_assign();
339  if (marked_empty()) {
340  return 0;
341  }
342  // The vector `predecessor' is used to represent equivalence classes:
343  // `predecessor[i] == i' if and only if `i' is the leader of its
344  // equivalence class (i.e., the minimum index in the class).
345  std::vector<dimension_type> predecessor;
346  compute_predecessors(predecessor);
347 
348  // Due to the fictitious variable `0', the affine dimension is one
349  // less the number of equivalence classes.
350  dimension_type affine_dim = 0;
351  // Note: disregard the first equivalence class.
352  for (dimension_type i = 1; i <= space_dim; ++i) {
353  if (predecessor[i] == i) {
354  ++affine_dim;
355  }
356  }
357  return affine_dim;
358 }
359 
360 template <typename T>
363  // Shortest-path closure is necessary to detect emptiness
364  // and all (possibly implicit) equalities.
365  shortest_path_closure_assign();
366 
367  const dimension_type space_dim = space_dimension();
368  Congruence_System cgs(space_dim);
369 
370  if (space_dim == 0) {
371  if (marked_empty()) {
373  }
374  return cgs;
375  }
376 
377  if (marked_empty()) {
379  return cgs;
380  }
381 
384 
385  // Compute leader information.
386  std::vector<dimension_type> leaders;
387  compute_leaders(leaders);
388 
389  // Go through the non-leaders to generate equality constraints.
390  const DB_Row<N>& dbm_0 = dbm[0];
391  for (dimension_type i = 1; i <= space_dim; ++i) {
392  const dimension_type leader = leaders[i];
393  if (i != leader) {
394  // Generate the constraint relating `i' and its leader.
395  if (leader == 0) {
396  // A unary equality has to be generated.
397  PPL_ASSERT(!is_plus_infinity(dbm_0[i]));
398  numer_denom(dbm_0[i], numer, denom);
399  cgs.insert(denom*Variable(i-1) == numer);
400  }
401  else {
402  // A binary equality has to be generated.
403  PPL_ASSERT(!is_plus_infinity(dbm[i][leader]));
404  numer_denom(dbm[i][leader], numer, denom);
405  cgs.insert(denom*Variable(leader-1) - denom*Variable(i-1) == numer);
406  }
407  }
408  }
409  return cgs;
410 }
411 
412 template <typename T>
413 void
415  // Dimension-compatibility check.
416  if (c.space_dimension() > space_dimension()) {
417  throw_dimension_incompatible("add_constraint(c)", c);
418  }
419  // Get rid of strict inequalities.
420  if (c.is_strict_inequality()) {
421  if (c.is_inconsistent()) {
422  set_empty();
423  return;
424  }
425  if (c.is_tautological()) {
426  return;
427  }
428  // Nontrivial strict inequalities are not allowed.
429  throw_invalid_argument("add_constraint(c)",
430  "strict inequalities are not allowed");
431  }
432 
433  dimension_type num_vars = 0;
434  dimension_type i = 0;
435  dimension_type j = 0;
437  // Constraints that are not bounded differences are not allowed.
438  if (!BD_Shape_Helpers::extract_bounded_difference(c, num_vars, i, j, coeff)) {
439  throw_invalid_argument("add_constraint(c)",
440  "c is not a bounded difference constraint");
441  }
442  const Coefficient& inhomo = c.inhomogeneous_term();
443  if (num_vars == 0) {
444  // Dealing with a trivial constraint (not a strict inequality).
445  if (inhomo < 0
446  || (inhomo != 0 && c.is_equality())) {
447  set_empty();
448  }
449  return;
450  }
451 
452  // Select the cell to be modified for the "<=" part of the constraint,
453  // and set `coeff' to the absolute value of itself.
454  const bool negative = (coeff < 0);
455  if (negative) {
456  neg_assign(coeff);
457  }
458  bool changed = false;
459  N& x = negative ? dbm[i][j] : dbm[j][i];
460  // Compute the bound for `x', rounding towards plus infinity.
461  PPL_DIRTY_TEMP(N, d);
462  div_round_up(d, inhomo, coeff);
463  if (x > d) {
464  x = d;
465  changed = true;
466  }
467 
468  if (c.is_equality()) {
469  N& y = negative ? dbm[j][i] : dbm[i][j];
470  // Also compute the bound for `y', rounding towards plus infinity.
471  PPL_DIRTY_TEMP_COEFFICIENT(minus_c_term);
472  neg_assign(minus_c_term, inhomo);
473  div_round_up(d, minus_c_term, coeff);
474  if (y > d) {
475  y = d;
476  changed = true;
477  }
478  }
479 
480  // In general, adding a constraint does not preserve the shortest-path
481  // closure or reduction of the bounded difference shape.
482  if (changed && marked_shortest_path_closed()) {
483  reset_shortest_path_closed();
484  }
485  PPL_ASSERT(OK());
486 }
487 
488 template <typename T>
489 void
491  const dimension_type cg_space_dim = cg.space_dimension();
492  // Dimension-compatibility check:
493  // the dimension of `cg' can not be greater than space_dim.
494  if (space_dimension() < cg_space_dim) {
495  throw_dimension_incompatible("add_congruence(cg)", cg);
496  }
497  // Handle the case of proper congruences first.
498  if (cg.is_proper_congruence()) {
499  if (cg.is_tautological()) {
500  return;
501  }
502  if (cg.is_inconsistent()) {
503  set_empty();
504  return;
505  }
506  // Non-trivial and proper congruences are not allowed.
507  throw_invalid_argument("add_congruence(cg)",
508  "cg is a non-trivial, proper congruence");
509  }
510 
511  PPL_ASSERT(cg.is_equality());
512  Constraint c(cg);
513  add_constraint(c);
514 }
515 
516 template <typename T>
517 void
519  PPL_ASSERT(!marked_empty());
520  PPL_ASSERT(c.space_dimension() <= space_dimension());
521 
522  dimension_type num_vars = 0;
523  dimension_type i = 0;
524  dimension_type j = 0;
526  // Constraints that are not bounded differences are ignored.
527  if (!BD_Shape_Helpers::extract_bounded_difference(c, num_vars, i, j, coeff)) {
528  return;
529  }
530  const Coefficient& inhomo = c.inhomogeneous_term();
531  if (num_vars == 0) {
532  // Dealing with a trivial constraint (might be a strict inequality).
533  if (inhomo < 0
534  || (c.is_equality() && inhomo != 0)
535  || (c.is_strict_inequality() && inhomo == 0)) {
536  set_empty();
537  }
538  return;
539  }
540 
541  // Select the cell to be modified for the "<=" part of the constraint,
542  // and set `coeff' to the absolute value of itself.
543  const bool negative = (coeff < 0);
544  N& x = negative ? dbm[i][j] : dbm[j][i];
545  N& y = negative ? dbm[j][i] : dbm[i][j];
546  if (negative) {
547  neg_assign(coeff);
548  }
549  bool changed = false;
550  // Compute the bound for `x', rounding towards plus infinity.
551  PPL_DIRTY_TEMP(N, d);
552  div_round_up(d, inhomo, coeff);
553  if (x > d) {
554  x = d;
555  changed = true;
556  }
557 
558  if (c.is_equality()) {
559  // Also compute the bound for `y', rounding towards plus infinity.
560  PPL_DIRTY_TEMP_COEFFICIENT(minus_c_term);
561  neg_assign(minus_c_term, inhomo);
562  div_round_up(d, minus_c_term, coeff);
563  if (y > d) {
564  y = d;
565  changed = true;
566  }
567  }
568 
569  // In general, adding a constraint does not preserve the shortest-path
570  // closure or reduction of the bounded difference shape.
571  if (changed && marked_shortest_path_closed()) {
572  reset_shortest_path_closed();
573  }
574  PPL_ASSERT(OK());
575 }
576 
577 template <typename T>
578 void
580  BD_Shape& x = *this;
581 
582  const dimension_type x_space_dim = x.space_dimension();
583  const dimension_type y_space_dim = y.space_dimension();
584 
585  // If `y' is an empty 0-dim space bounded difference shape,
586  // let `*this' become empty.
587  if (y_space_dim == 0 && y.marked_empty()) {
588  set_empty();
589  return;
590  }
591 
592  // If `x' is an empty 0-dim space BDS, then it is sufficient to adjust
593  // the dimension of the vector space.
594  if (x_space_dim == 0 && marked_empty()) {
595  dbm.grow(y_space_dim + 1);
596  PPL_ASSERT(OK());
597  return;
598  }
599  // First we increase the space dimension of `x' by adding
600  // `y.space_dimension()' new dimensions.
601  // The matrix for the new system of constraints is obtained
602  // by leaving the old system of constraints in the upper left-hand side
603  // and placing the constraints of `y' in the lower right-hand side,
604  // except the constraints as `y(i) >= cost' or `y(i) <= cost', that are
605  // placed in the right position on the new matrix.
606  add_space_dimensions_and_embed(y_space_dim);
607  const dimension_type new_space_dim = x_space_dim + y_space_dim;
608  for (dimension_type i = x_space_dim + 1; i <= new_space_dim; ++i) {
609  DB_Row<N>& dbm_i = dbm[i];
610  dbm_i[0] = y.dbm[i - x_space_dim][0];
611  dbm[0][i] = y.dbm[0][i - x_space_dim];
612  for (dimension_type j = x_space_dim + 1; j <= new_space_dim; ++j) {
613  dbm_i[j] = y.dbm[i - x_space_dim][j - x_space_dim];
614  }
615  }
616 
617  if (marked_shortest_path_closed()) {
618  reset_shortest_path_closed();
619  }
620  PPL_ASSERT(OK());
621 }
622 
623 template <typename T>
624 bool
626  const BD_Shape<T>& x = *this;
627  const dimension_type x_space_dim = x.space_dimension();
628 
629  // Dimension-compatibility check.
630  if (x_space_dim != y.space_dimension()) {
631  throw_dimension_incompatible("contains(y)", y);
632  }
633  if (x_space_dim == 0) {
634  // The zero-dimensional empty shape only contains another
635  // zero-dimensional empty shape.
636  // The zero-dimensional universe shape contains any other
637  // zero-dimensional shape.
638  return marked_empty() ? y.marked_empty() : true;
639  }
640 
641  /*
642  The `y' bounded difference shape must be closed. As an example,
643  consider the case where in `*this' we have the constraints
644 
645  x1 - x2 <= 1,
646  x1 <= 3,
647  x2 <= 2,
648 
649  and in `y' the constraints are
650 
651  x1 - x2 <= 0,
652  x2 <= 1.
653 
654  Without closure the (erroneous) analysis of the inhomogeneous terms
655  would conclude containment does not hold. Closing `y' results into
656  the "discovery" of the implicit constraint
657 
658  x1 <= 1,
659 
660  at which point the inhomogeneous terms can be examined to determine
661  that containment does hold.
662  */
664  // An empty shape is contained in any other dimension-compatible shapes.
665  if (y.marked_empty()) {
666  return true;
667  }
668  // If `x' is empty it can not contain `y' (which is not empty).
669  if (x.is_empty()) {
670  return false;
671  }
672  // `*this' contains `y' if and only if every cell of `dbm'
673  // is greater than or equal to the correspondent one of `y.dbm'.
674  for (dimension_type i = x_space_dim + 1; i-- > 0; ) {
675  const DB_Row<N>& x_dbm_i = x.dbm[i];
676  const DB_Row<N>& y_dbm_i = y.dbm[i];
677  for (dimension_type j = x_space_dim + 1; j-- > 0; ) {
678  if (x_dbm_i[j] < y_dbm_i[j]) {
679  return false;
680  }
681  }
682  }
683  return true;
684 }
685 
686 template <typename T>
687 bool
689  const dimension_type space_dim = space_dimension();
690  // Dimension-compatibility check.
691  if (space_dim != y.space_dimension()) {
692  throw_dimension_incompatible("is_disjoint_from(y)", y);
693  }
694  // If one of the two bounded difference shape is empty,
695  // then the two bounded difference shape are disjoint.
696  shortest_path_closure_assign();
697  if (marked_empty()) {
698  return true;
699  }
701  if (y.marked_empty()) {
702  return true;
703  }
704  // Two BDSs are disjoint when their intersection is empty.
705  // That is if and only if there exists at least a bounded difference
706  // such that the upper bound of the bounded difference in the first
707  // BD_Shape is strictly less than the lower bound of
708  // the corresponding bounded difference in the second BD_Shape
709  // or vice versa.
710  // For example: let be
711  // in `*this': -a_j_i <= v_j - v_i <= a_i_j;
712  // and in `y': -b_j_i <= v_j - v_i <= b_i_j;
713  // `*this' and `y' are disjoint if
714  // 1.) a_i_j < -b_j_i or
715  // 2.) b_i_j < -a_j_i.
716  PPL_DIRTY_TEMP(N, tmp);
717  for (dimension_type i = space_dim+1; i-- > 0; ) {
718  const DB_Row<N>& x_i = dbm[i];
719  for (dimension_type j = space_dim+1; j-- > 0; ) {
720  neg_assign_r(tmp, y.dbm[j][i], ROUND_UP);
721  if (x_i[j] < tmp) {
722  return true;
723  }
724  }
725  }
726 
727  return false;
728 }
729 
730 template <typename T>
731 bool
733  if (marked_empty()) {
734  return false;
735  }
736  const dimension_type space_dim = space_dimension();
737  // If the BDS is non-empty and zero-dimensional,
738  // then it is necessarily the universe BDS.
739  if (space_dim == 0) {
740  return true;
741  }
742  // A bounded difference shape defining the universe BDS can only
743  // contain trivial constraints.
744  for (dimension_type i = space_dim + 1; i-- > 0; ) {
745  const DB_Row<N>& dbm_i = dbm[i];
746  for (dimension_type j = space_dim + 1; j-- > 0; ) {
747  if (!is_plus_infinity(dbm_i[j])) {
748  return false;
749  }
750  }
751  }
752  return true;
753 }
754 
755 template <typename T>
756 bool
758  shortest_path_closure_assign();
759  const dimension_type space_dim = space_dimension();
760  // A zero-dimensional or empty BDS is bounded.
761  if (marked_empty() || space_dim == 0) {
762  return true;
763  }
764  // A bounded difference shape defining the bounded BDS never can
765  // contain trivial constraints.
766  for (dimension_type i = space_dim + 1; i-- > 0; ) {
767  const DB_Row<N>& dbm_i = dbm[i];
768  for (dimension_type j = space_dim + 1; j-- > 0; ) {
769  if (i != j) {
770  if (is_plus_infinity(dbm_i[j])) {
771  return false;
772  }
773  }
774  }
775  }
776 
777  return true;
778 }
779 
780 template <typename T>
781 bool
783  // Force shortest-path closure.
784  if (is_empty()) {
785  return false;
786  }
787  const dimension_type space_dim = space_dimension();
788  if (space_dim == 0) {
789  return true;
790  }
791  // A non-empty BD_Shape defined by integer constraints
792  // necessarily contains an integer point.
794  return true;
795  }
796  // Build an integer BD_Shape z with bounds at least as tight as
797  // those in *this and then recheck for emptiness.
798  BD_Shape<mpz_class> bds_z(space_dim);
799  typedef BD_Shape<mpz_class>::N Z;
801  PPL_DIRTY_TEMP(N, tmp);
802  bool all_integers = true;
803  for (dimension_type i = space_dim + 1; i-- > 0; ) {
804  DB_Row<Z>& z_i = bds_z.dbm[i];
805  const DB_Row<N>& dbm_i = dbm[i];
806  for (dimension_type j = space_dim + 1; j-- > 0; ) {
807  const N& dbm_i_j = dbm_i[j];
808  if (is_plus_infinity(dbm_i_j)) {
809  continue;
810  }
811  if (is_integer(dbm_i_j)) {
812  assign_r(z_i[j], dbm_i_j, ROUND_NOT_NEEDED);
813  }
814  else {
815  all_integers = false;
816  Z& z_i_j = z_i[j];
817  // Copy dbm_i_j into z_i_j, but rounding downwards.
818  neg_assign_r(tmp, dbm_i_j, ROUND_NOT_NEEDED);
819  assign_r(z_i_j, tmp, ROUND_UP);
820  neg_assign_r(z_i_j, z_i_j, ROUND_NOT_NEEDED);
821  }
822  }
823  }
824  return all_integers || !bds_z.is_empty();
825 }
826 
827 template <typename T>
828 bool
830  Coefficient& freq_n, Coefficient& freq_d,
831  Coefficient& val_n, Coefficient& val_d) const {
832  dimension_type space_dim = space_dimension();
833  // The dimension of `expr' must be at most the dimension of *this.
834  if (space_dim < expr.space_dimension()) {
835  throw_dimension_incompatible("frequency(e, ...)", "e", expr);
836  }
837  // Check if `expr' has a constant value.
838  // If it is constant, set the frequency `freq_n' to 0
839  // and return true. Otherwise the values for \p expr
840  // are not discrete so return false.
841 
842  // Space dimension is 0: if empty, then return false;
843  // otherwise the frequency is 0 and the value is the inhomogeneous term.
844  if (space_dim == 0) {
845  if (is_empty()) {
846  return false;
847  }
848  freq_n = 0;
849  freq_d = 1;
850  val_n = expr.inhomogeneous_term();
851  val_d = 1;
852  return true;
853  }
854 
855  shortest_path_closure_assign();
856  // For an empty BD shape, we simply return false.
857  if (marked_empty()) {
858  return false;
859  }
860  // The BD shape has at least 1 dimension and is not empty.
864  PPL_DIRTY_TEMP(N, tmp);
865  Linear_Expression le = expr;
866  // Boolean to keep track of a variable `v' in expression `le'.
867  // If we can replace `v' by an expression using variables other
868  // than `v' and are already in `le', then this is set to true.
869 
870  PPL_DIRTY_TEMP_COEFFICIENT(val_denom);
871  val_denom = 1;
872 
873  // TODO: This loop can be optimized more, if needed, exploiting the
874  // (possible) sparseness of le.
875  for (dimension_type i = dbm.num_rows(); i-- > 1; ) {
876  const Variable v(i-1);
877  coeff = le.coefficient(v);
878  if (coeff == 0) {
879  continue;
880  }
881  const DB_Row<N>& dbm_i = dbm[i];
882  // Check if `v' is constant in the BD shape.
883  assign_r(tmp, dbm_i[0], ROUND_NOT_NEEDED);
884  if (is_additive_inverse(dbm[0][i], tmp)) {
885  // If `v' is constant, replace it in `le' by the value.
886  numer_denom(tmp, numer, denom);
887  sub_mul_assign(le, coeff, v);
888  le *= denom;
889  le -= numer*coeff;
890  val_denom *= denom;
891  continue;
892  }
893  // Check the bounded differences with the other dimensions that
894  // have non-zero coefficient in `le'.
895  else {
896  bool constant_v = false;
898  j_end = le.lower_bound(Variable(i - 1)); j != j_end; ++j) {
899  const Variable vj = j.variable();
900  const dimension_type j_dim = vj.space_dimension();
901  assign_r(tmp, dbm_i[j_dim], ROUND_NOT_NEEDED);
902  if (is_additive_inverse(dbm[j_dim][i], tmp)) {
903  // The coefficient for `vj' in `le' is not 0
904  // and the difference with `v' in the BD shape is constant.
905  // So apply this equality to eliminate `v' in `le'.
906  numer_denom(tmp, numer, denom);
907  // Modifying le invalidates the iterators, but it's not a problem
908  // since we are going to exit the loop.
909  sub_mul_assign(le, coeff, v);
910  add_mul_assign(le, coeff, vj);
911  le *= denom;
912  le -= numer*coeff;
913  val_denom *= denom;
914  constant_v = true;
915  break;
916  }
917  }
918  if (!constant_v) {
919  // The expression `expr' is not constant.
920  return false;
921  }
922  }
923  }
924 
925  // The expression `expr' is constant.
926  freq_n = 0;
927  freq_d = 1;
928 
929  // Reduce `val_n' and `val_d'.
930  normalize2(le.inhomogeneous_term(), val_denom, val_n, val_d);
931  return true;
932 }
933 
934 template <typename T>
935 bool
937  // `var' should be one of the dimensions of the BD shape.
938  const dimension_type var_space_dim = var.space_dimension();
939  if (space_dimension() < var_space_dim) {
940  throw_dimension_incompatible("constrains(v)", "v", var);
941  }
942  shortest_path_closure_assign();
943  // A BD shape known to be empty constrains all variables.
944  // (Note: do not force emptiness check _yet_)
945  if (marked_empty()) {
946  return true;
947  }
948  // Check whether `var' is syntactically constrained.
949  const DB_Row<N>& dbm_v = dbm[var_space_dim];
950  for (dimension_type i = dbm.num_rows(); i-- > 0; ) {
951  if (!is_plus_infinity(dbm_v[i])
952  || !is_plus_infinity(dbm[i][var_space_dim])) {
953  return true;
954  }
955  }
956 
957  // `var' is not syntactically constrained:
958  // now force an emptiness check.
959  return is_empty();
960 }
961 
962 template <typename T>
963 void
965 ::compute_predecessors(std::vector<dimension_type>& predecessor) const {
966  PPL_ASSERT(!marked_empty() && marked_shortest_path_closed());
967  PPL_ASSERT(predecessor.size() == 0);
968  // Variables are ordered according to their index.
969  // The vector `predecessor' is used to indicate which variable
970  // immediately precedes a given one in the corresponding equivalence class.
971  // The `leader' of an equivalence class is the element having minimum
972  // index: leaders are their own predecessors.
973  const dimension_type predecessor_size = dbm.num_rows();
974  // Initially, each variable is leader of its own zero-equivalence class.
975  predecessor.reserve(predecessor_size);
976  for (dimension_type i = 0; i < predecessor_size; ++i) {
977  predecessor.push_back(i);
978  }
979  // Now compute actual predecessors.
980  for (dimension_type i = predecessor_size; i-- > 1; ) {
981  if (i == predecessor[i]) {
982  const DB_Row<N>& dbm_i = dbm[i];
983  for (dimension_type j = i; j-- > 0; ) {
984  if (j == predecessor[j]
985  && is_additive_inverse(dbm[j][i], dbm_i[j])) {
986  // Choose as predecessor the variable having the smaller index.
987  predecessor[i] = j;
988  break;
989  }
990  }
991  }
992  }
993 }
994 
995 template <typename T>
996 void
997 BD_Shape<T>::compute_leaders(std::vector<dimension_type>& leaders) const {
998  PPL_ASSERT(!marked_empty() && marked_shortest_path_closed());
999  PPL_ASSERT(leaders.size() == 0);
1000  // Compute predecessor information.
1001  compute_predecessors(leaders);
1002  // Flatten the predecessor chains so as to obtain leaders.
1003  PPL_ASSERT(leaders[0] == 0);
1004  for (dimension_type i = 1, l_size = leaders.size(); i != l_size; ++i) {
1005  const dimension_type leaders_i = leaders[i];
1006  PPL_ASSERT(leaders_i <= i);
1007  if (leaders_i != i) {
1008  const dimension_type leaders_leaders_i = leaders[leaders_i];
1009  PPL_ASSERT(leaders_leaders_i == leaders[leaders_leaders_i]);
1010  leaders[i] = leaders_leaders_i;
1011  }
1012  }
1013 }
1014 
1015 template <typename T>
1016 bool
1018  // If the BDS is empty, it is also reduced.
1019  if (marked_empty()) {
1020  return true;
1021  }
1022  const dimension_type space_dim = space_dimension();
1023  // Zero-dimensional BDSs are necessarily reduced.
1024  if (space_dim == 0) {
1025  return true;
1026  }
1027  // A shortest-path reduced dbm is just a dbm with an indication of
1028  // those constraints that are redundant. If there is no indication
1029  // of the redundant constraints, then it cannot be reduced.
1030  if (!marked_shortest_path_reduced()) {
1031  return false;
1032  }
1033 
1034  const BD_Shape x_copy = *this;
1036  // If we just discovered emptiness, it cannot be reduced.
1037  if (x_copy.marked_empty()) {
1038  return false;
1039  }
1040  // The vector `leader' is used to indicate which variables are equivalent.
1041  std::vector<dimension_type> leader(space_dim + 1);
1042 
1043  // We store the leader.
1044  for (dimension_type i = space_dim + 1; i-- > 0; ) {
1045  leader[i] = i;
1046  }
1047  // Step 1: we store really the leader with the corrected value.
1048  // We search for the equivalent or zero-equivalent variables.
1049  // The variable(i-1) and variable(j-1) are equivalent if and only if
1050  // m_i_j == -(m_j_i).
1051  for (dimension_type i = 0; i < space_dim; ++i) {
1052  const DB_Row<N>& x_copy_dbm_i = x_copy.dbm[i];
1053  for (dimension_type j = i + 1; j <= space_dim; ++j) {
1054  if (is_additive_inverse(x_copy.dbm[j][i], x_copy_dbm_i[j])) {
1055  // Two equivalent variables have got the same leader
1056  // (the smaller variable).
1057  leader[j] = leader[i];
1058  }
1059  }
1060  }
1061 
1062  // Step 2: we check if there are redundant constraints in the zero_cycle
1063  // free bounded difference shape, considering only the leaders.
1064  // A constraint `c' is redundant, when there are two constraints such that
1065  // their sum is the same constraint with the inhomogeneous term
1066  // less than or equal to the `c' one.
1067  PPL_DIRTY_TEMP(N, c);
1068  for (dimension_type k = 0; k <= space_dim; ++k) {
1069  if (leader[k] == k) {
1070  const DB_Row<N>& x_k = x_copy.dbm[k];
1071  for (dimension_type i = 0; i <= space_dim; ++i) {
1072  if (leader[i] == i) {
1073  const DB_Row<N>& x_i = x_copy.dbm[i];
1074  const Bit_Row& redundancy_i = redundancy_dbm[i];
1075  const N& x_i_k = x_i[k];
1076  for (dimension_type j = 0; j <= space_dim; ++j) {
1077  if (leader[j] == j) {
1078  const N& x_i_j = x_i[j];
1079  if (!is_plus_infinity(x_i_j)) {
1080  add_assign_r(c, x_i_k, x_k[j], ROUND_UP);
1081  if (x_i_j >= c && !redundancy_i[j]) {
1082  return false;
1083  }
1084  }
1085  }
1086  }
1087  }
1088  }
1089  }
1090  }
1091 
1092  // The vector `var_conn' is used to check if there is a single cycle
1093  // that connected all zero-equivalent variables between them.
1094  // The value `space_dim + 1' is used to indicate that the equivalence
1095  // class contains a single variable.
1096  std::vector<dimension_type> var_conn(space_dim + 1);
1097  for (dimension_type i = space_dim + 1; i-- > 0; ) {
1098  var_conn[i] = space_dim + 1;
1099  }
1100  // Step 3: we store really the `var_conn' with the right value, putting
1101  // the variable with the selected variable is connected:
1102  // we check the row of each variable:
1103  // a- each leader could be connected with only zero-equivalent one,
1104  // b- each non-leader with only another zero-equivalent one.
1105  for (dimension_type i = 0; i <= space_dim; ++i) {
1106  // It count with how many variables the selected variable is
1107  // connected.
1108  dimension_type t = 0;
1109  dimension_type leader_i = leader[i];
1110  // Case a: leader.
1111  if (leader_i == i) {
1112  for (dimension_type j = 0; j <= space_dim; ++j) {
1113  dimension_type leader_j = leader[j];
1114  // Only the connectedness with equivalent variables
1115  // is considered.
1116  if (j != leader_j) {
1117  if (!redundancy_dbm[i][j]) {
1118  if (t == 1) {
1119  // Two non-leaders cannot be connected with the same leader.
1120  return false;
1121  }
1122  else {
1123  if (leader_j != i) {
1124  // The variables are not in the same equivalence class.
1125  return false;
1126  }
1127  else {
1128  ++t;
1129  var_conn[i] = j;
1130  }
1131  }
1132  }
1133  }
1134  }
1135  }
1136  // Case b: non-leader.
1137  else {
1138  for (dimension_type j = 0; j <= space_dim; ++j) {
1139  if (!redundancy_dbm[i][j]) {
1140  dimension_type leader_j = leader[j];
1141  if (leader_i != leader_j) {
1142  // The variables are not in the same equivalence class.
1143  return false;
1144  }
1145  else {
1146  if (t == 1) {
1147  // The variables cannot be connected with the same leader.
1148  return false;
1149  }
1150  else {
1151  ++t;
1152  var_conn[i] = j;
1153  }
1154  }
1155  // A non-leader must be connected with
1156  // another variable.
1157  if (t == 0) {
1158  return false;
1159  }
1160  }
1161  }
1162  }
1163  }
1164 
1165  // The vector `just_checked' is used to check if
1166  // a variable is already checked.
1167  std::vector<bool> just_checked(space_dim + 1);
1168  for (dimension_type i = space_dim + 1; i-- > 0; ) {
1169  just_checked[i] = false;
1170  }
1171  // Step 4: we check if there are single cycles that
1172  // connected all the zero-equivalent variables between them.
1173  for (dimension_type i = 0; i <= space_dim; ++i) {
1174  // We do not re-check the already considered single cycles.
1175  if (!just_checked[i]) {
1176  dimension_type v_con = var_conn[i];
1177  // We consider only the equivalence classes with
1178  // 2 or plus variables.
1179  if (v_con != space_dim + 1) {
1180  // There is a single cycle if taken a variable,
1181  // we return to this same variable.
1182  while (v_con != i) {
1183  just_checked[v_con] = true;
1184  v_con = var_conn[v_con];
1185  // If we re-pass to an already considered variable,
1186  // then we haven't a single cycle.
1187  if (just_checked[v_con]) {
1188  return false;
1189  }
1190  }
1191  }
1192  }
1193  just_checked[i] = true;
1194  }
1195 
1196  // The system bounded differences is just reduced.
1197  return true;
1198 }
1199 
1200 template <typename T>
1201 bool
1203  const bool from_above) const {
1204  // The dimension of `expr' should not be greater than the dimension
1205  // of `*this'.
1206  const dimension_type expr_space_dim = expr.space_dimension();
1207  const dimension_type space_dim = space_dimension();
1208  if (space_dim < expr_space_dim) {
1209  throw_dimension_incompatible((from_above
1210  ? "bounds_from_above(e)"
1211  : "bounds_from_below(e)"), "e", expr);
1212  }
1213  shortest_path_closure_assign();
1214  // A zero-dimensional or empty BDS bounds everything.
1215  if (space_dim == 0 || marked_empty()) {
1216  return true;
1217  }
1218  // The constraint `c' is used to check if `expr' is a difference
1219  // bounded and, in this case, to select the cell.
1220  const Constraint& c = from_above ? expr <= 0 : expr >= 0;
1221  dimension_type num_vars = 0;
1222  dimension_type i = 0;
1223  dimension_type j = 0;
1225  // Check if `c' is a BD constraint.
1226  if (BD_Shape_Helpers::extract_bounded_difference(c, num_vars, i, j, coeff)) {
1227  if (num_vars == 0) {
1228  // Dealing with a trivial constraint.
1229  return true;
1230  }
1231  // Select the cell to be checked.
1232  const N& x = (coeff < 0) ? dbm[i][j] : dbm[j][i];
1233  return !is_plus_infinity(x);
1234  }
1235  else {
1236  // Not a DB constraint: use the MIP solver.
1237  Optimization_Mode mode_bounds
1238  = from_above ? MAXIMIZATION : MINIMIZATION;
1239  MIP_Problem mip(space_dim, constraints(), expr, mode_bounds);
1240  // Problem is known to be feasible.
1241  return mip.solve() == OPTIMIZED_MIP_PROBLEM;
1242  }
1243 }
1244 
1245 template <typename T>
1246 bool
1248  const bool maximize,
1249  Coefficient& ext_n, Coefficient& ext_d,
1250  bool& included) const {
1251  // The dimension of `expr' should not be greater than the dimension
1252  // of `*this'.
1253  const dimension_type space_dim = space_dimension();
1254  const dimension_type expr_space_dim = expr.space_dimension();
1255  if (space_dim < expr_space_dim) {
1256  throw_dimension_incompatible((maximize
1257  ? "maximize(e, ...)"
1258  : "minimize(e, ...)"), "e", expr);
1259  }
1260  // Deal with zero-dim BDS first.
1261  if (space_dim == 0) {
1262  if (marked_empty()) {
1263  return false;
1264  }
1265  else {
1266  ext_n = expr.inhomogeneous_term();
1267  ext_d = 1;
1268  included = true;
1269  return true;
1270  }
1271  }
1272 
1273  shortest_path_closure_assign();
1274  // For an empty BDS we simply return false.
1275  if (marked_empty()) {
1276  return false;
1277  }
1278  // The constraint `c' is used to check if `expr' is a difference
1279  // bounded and, in this case, to select the cell.
1280  const Constraint& c = maximize ? expr <= 0 : expr >= 0;
1281  dimension_type num_vars = 0;
1282  dimension_type i = 0;
1283  dimension_type j = 0;
1285  // Check if `c' is a BD constraint.
1286  if (!BD_Shape_Helpers::extract_bounded_difference(c, num_vars, i, j, coeff)) {
1287  Optimization_Mode mode_max_min
1288  = maximize ? MAXIMIZATION : MINIMIZATION;
1289  MIP_Problem mip(space_dim, constraints(), expr, mode_max_min);
1290  if (mip.solve() == OPTIMIZED_MIP_PROBLEM) {
1291  mip.optimal_value(ext_n, ext_d);
1292  included = true;
1293  return true;
1294  }
1295  else {
1296  // Here`expr' is unbounded in `*this'.
1297  return false;
1298  }
1299  }
1300  else {
1301  // Here `expr' is a bounded difference.
1302  if (num_vars == 0) {
1303  // Dealing with a trivial expression.
1304  ext_n = expr.inhomogeneous_term();
1305  ext_d = 1;
1306  included = true;
1307  return true;
1308  }
1309 
1310  // Select the cell to be checked.
1311  const N& x = (coeff < 0) ? dbm[i][j] : dbm[j][i];
1312  if (!is_plus_infinity(x)) {
1313  // Compute the maximize/minimize of `expr'.
1314  PPL_DIRTY_TEMP(N, d);
1315  const Coefficient& b = expr.inhomogeneous_term();
1316  PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
1317  neg_assign(minus_b, b);
1318  const Coefficient& sc_b = maximize ? b : minus_b;
1319  assign_r(d, sc_b, ROUND_UP);
1320  // Set `coeff_expr' to the absolute value of coefficient of
1321  // a variable in `expr'.
1322  PPL_DIRTY_TEMP(N, coeff_expr);
1323  PPL_ASSERT(i != 0);
1324  const Coefficient& coeff_i = expr.get(Variable(i - 1));
1325  const int sign_i = sgn(coeff_i);
1326  if (sign_i > 0) {
1327  assign_r(coeff_expr, coeff_i, ROUND_UP);
1328  }
1329  else {
1330  PPL_DIRTY_TEMP_COEFFICIENT(minus_coeff_i);
1331  neg_assign(minus_coeff_i, coeff_i);
1332  assign_r(coeff_expr, minus_coeff_i, ROUND_UP);
1333  }
1334  // Approximating the maximum/minimum of `expr'.
1335  add_mul_assign_r(d, coeff_expr, x, ROUND_UP);
1336  numer_denom(d, ext_n, ext_d);
1337  if (!maximize) {
1338  neg_assign(ext_n);
1339  }
1340  included = true;
1341  return true;
1342  }
1343 
1344  // `expr' is unbounded.
1345  return false;
1346  }
1347 }
1348 
1349 template <typename T>
1350 bool
1352  const bool maximize,
1353  Coefficient& ext_n, Coefficient& ext_d,
1354  bool& included,
1355  Generator& g) const {
1356  // The dimension of `expr' should not be greater than the dimension
1357  // of `*this'.
1358  const dimension_type space_dim = space_dimension();
1359  const dimension_type expr_space_dim = expr.space_dimension();
1360  if (space_dim < expr_space_dim) {
1361  throw_dimension_incompatible((maximize
1362  ? "maximize(e, ...)"
1363  : "minimize(e, ...)"), "e", expr);
1364  }
1365  // Deal with zero-dim BDS first.
1366  if (space_dim == 0) {
1367  if (marked_empty()) {
1368  return false;
1369  }
1370  else {
1371  ext_n = expr.inhomogeneous_term();
1372  ext_d = 1;
1373  included = true;
1374  g = point();
1375  return true;
1376  }
1377  }
1378 
1379  shortest_path_closure_assign();
1380  // For an empty BDS we simply return false.
1381  if (marked_empty()) {
1382  return false;
1383  }
1384  Optimization_Mode mode_max_min
1385  = maximize ? MAXIMIZATION : MINIMIZATION;
1386  MIP_Problem mip(space_dim, constraints(), expr, mode_max_min);
1387  if (mip.solve() == OPTIMIZED_MIP_PROBLEM) {
1388  g = mip.optimizing_point();
1389  mip.evaluate_objective_function(g, ext_n, ext_d);
1390  included = true;
1391  return true;
1392  }
1393  // Here `expr' is unbounded in `*this'.
1394  return false;
1395 }
1396 
1397 template <typename T>
1400  const dimension_type space_dim = space_dimension();
1401 
1402  // Dimension-compatibility check.
1403  if (cg.space_dimension() > space_dim) {
1404  throw_dimension_incompatible("relation_with(cg)", cg);
1405  }
1406  // If the congruence is an equality, find the relation with
1407  // the equivalent equality constraint.
1408  if (cg.is_equality()) {
1409  Constraint c(cg);
1410  return relation_with(c);
1411  }
1412 
1413  shortest_path_closure_assign();
1414 
1415  if (marked_empty()) {
1419  }
1420  if (space_dim == 0) {
1421  if (cg.is_inconsistent()) {
1423  }
1424  else {
1427  }
1428  }
1429 
1430  // Find the lower bound for a hyperplane with direction
1431  // defined by the congruence.
1433  PPL_DIRTY_TEMP_COEFFICIENT(min_numer);
1434  PPL_DIRTY_TEMP_COEFFICIENT(min_denom);
1435  bool min_included;
1436  bool bounded_below = minimize(le, min_numer, min_denom, min_included);
1437 
1438  // If there is no lower bound, then some of the hyperplanes defined by
1439  // the congruence will strictly intersect the shape.
1440  if (!bounded_below) {
1442  }
1443  // TODO: Consider adding a max_and_min() method, performing both
1444  // maximization and minimization so as to possibly exploit
1445  // incrementality of the MIP solver.
1446 
1447  // Find the upper bound for a hyperplane with direction
1448  // defined by the congruence.
1449  PPL_DIRTY_TEMP_COEFFICIENT(max_numer);
1450  PPL_DIRTY_TEMP_COEFFICIENT(max_denom);
1451  bool max_included;
1452  bool bounded_above = maximize(le, max_numer, max_denom, max_included);
1453 
1454  // If there is no upper bound, then some of the hyperplanes defined by
1455  // the congruence will strictly intersect the shape.
1456  if (!bounded_above) {
1458  }
1459  PPL_DIRTY_TEMP_COEFFICIENT(signed_distance);
1460 
1461  // Find the position value for the hyperplane that satisfies the congruence
1462  // and is above the lower bound for the shape.
1463  PPL_DIRTY_TEMP_COEFFICIENT(min_value);
1464  min_value = min_numer / min_denom;
1465  const Coefficient& modulus = cg.modulus();
1466  signed_distance = min_value % modulus;
1467  min_value -= signed_distance;
1468  if (min_value * min_denom < min_numer) {
1469  min_value += modulus;
1470  }
1471  // Find the position value for the hyperplane that satisfies the congruence
1472  // and is below the upper bound for the shape.
1473  PPL_DIRTY_TEMP_COEFFICIENT(max_value);
1474  max_value = max_numer / max_denom;
1475  signed_distance = max_value % modulus;
1476  max_value += signed_distance;
1477  if (max_value * max_denom > max_numer) {
1478  max_value -= modulus;
1479  }
1480  // If the upper bound value is less than the lower bound value,
1481  // then there is an empty intersection with the congruence;
1482  // otherwise it will strictly intersect.
1483  if (max_value < min_value) {
1485  }
1486  else {
1488  }
1489 }
1490 
1491 
1492 template <typename T>
1495  const dimension_type c_space_dim = c.space_dimension();
1496  const dimension_type space_dim = space_dimension();
1497 
1498  // Dimension-compatibility check.
1499  if (c_space_dim > space_dim) {
1500  throw_dimension_incompatible("relation_with(c)", c);
1501  }
1502  shortest_path_closure_assign();
1503 
1504  if (marked_empty()) {
1508  }
1509  if (space_dim == 0) {
1510  if ((c.is_equality() && c.inhomogeneous_term() != 0)
1511  || (c.is_inequality() && c.inhomogeneous_term() < 0)) {
1513  }
1514  else if (c.is_strict_inequality() && c.inhomogeneous_term() == 0) {
1515  // The constraint 0 > 0 implicitly defines the hyperplane 0 = 0;
1516  // thus, the zero-dimensional point also saturates it.
1519  }
1520  else if (c.is_equality() || c.inhomogeneous_term() == 0) {
1523  }
1524  else {
1525  // The zero-dimensional point saturates
1526  // neither the positivity constraint 1 >= 0,
1527  // nor the strict positivity constraint 1 > 0.
1529  }
1530  }
1531 
1532  dimension_type num_vars = 0;
1533  dimension_type i = 0;
1534  dimension_type j = 0;
1536  if (!BD_Shape_Helpers::extract_bounded_difference(c, num_vars, i, j, coeff)) {
1537  // Constraints that are not bounded differences.
1538  // Use maximize() and minimize() to do much of the work.
1539 
1540  // Find the linear expression for the constraint and use that to
1541  // find if the expression is bounded from above or below and if it
1542  // is, find the maximum and minimum values.
1544  le.set_inhomogeneous_term(Coefficient_zero());
1545 
1546  PPL_DIRTY_TEMP_COEFFICIENT(max_numer);
1547  PPL_DIRTY_TEMP_COEFFICIENT(max_denom);
1548  bool max_included;
1549  PPL_DIRTY_TEMP_COEFFICIENT(min_numer);
1550  PPL_DIRTY_TEMP_COEFFICIENT(min_denom);
1551  bool min_included;
1552  bool bounded_above = maximize(le, max_numer, max_denom, max_included);
1553  bool bounded_below = minimize(le, min_numer, min_denom, min_included);
1554  if (!bounded_above) {
1555  if (!bounded_below) {
1557  }
1558  min_numer += c.inhomogeneous_term() * min_denom;
1559  switch (sgn(min_numer)) {
1560  case 1:
1561  if (c.is_equality()) {
1563  }
1565  case 0:
1566  if (c.is_strict_inequality() || c.is_equality()) {
1568  }
1570  case -1:
1572  }
1573  }
1574  if (!bounded_below) {
1575  max_numer += c.inhomogeneous_term() * max_denom;
1576  switch (sgn(max_numer)) {
1577  case 1:
1579  case 0:
1580  if (c.is_strict_inequality()) {
1582  }
1584  case -1:
1586  }
1587  }
1588  else {
1589  max_numer += c.inhomogeneous_term() * max_denom;
1590  min_numer += c.inhomogeneous_term() * min_denom;
1591  switch (sgn(max_numer)) {
1592  case 1:
1593  switch (sgn(min_numer)) {
1594  case 1:
1595  if (c.is_equality()) {
1597  }
1599  case 0:
1600  if (c.is_equality()) {
1602  }
1603  if (c.is_strict_inequality()) {
1605  }
1607  case -1:
1609  }
1610  PPL_UNREACHABLE;
1611  break;
1612  case 0:
1613  if (min_numer == 0) {
1614  if (c.is_strict_inequality()) {
1617  }
1620  }
1621  if (c.is_strict_inequality()) {
1623  }
1625  case -1:
1627  }
1628  }
1629  }
1630 
1631  // Constraints that are bounded differences.
1632  if (num_vars == 0) {
1633  // Dealing with a trivial constraint.
1634  switch (sgn(c.inhomogeneous_term())) {
1635  case -1:
1637  case 0:
1638  if (c.is_strict_inequality()) {
1641  }
1642  else {
1645  }
1646  case 1:
1647  if (c.is_equality()) {
1649  }
1650  else {
1652  }
1653  }
1654  }
1655 
1656  // Select the cell to be checked for the "<=" part of the constraint,
1657  // and set `coeff' to the absolute value of itself.
1658  const bool negative = (coeff < 0);
1659  const N& x = negative ? dbm[i][j] : dbm[j][i];
1660  const N& y = negative ? dbm[j][i] : dbm[i][j];
1661  if (negative) {
1662  neg_assign(coeff);
1663  }
1664  // Deduce the relation/s of the constraint `c' of the form
1665  // `coeff*v - coeff*u </<=/== c.inhomogeneous_term()'
1666  // with the respectively constraints in `*this'
1667  // `-y <= v - u <= x'.
1668  // Let `d == c.inhomogeneous_term()/coeff'
1669  // and `d1 == -c.inhomogeneous_term()/coeff'.
1670  // The following variables of mpq_class type are used to be precise
1671  // when the bds is defined by integer constraints.
1672  PPL_DIRTY_TEMP(mpq_class, q_x);
1673  PPL_DIRTY_TEMP(mpq_class, q_y);
1674  PPL_DIRTY_TEMP(mpq_class, d);
1675  PPL_DIRTY_TEMP(mpq_class, d1);
1676  PPL_DIRTY_TEMP(mpq_class, c_denom);
1677  PPL_DIRTY_TEMP(mpq_class, q_denom);
1678  assign_r(c_denom, coeff, ROUND_NOT_NEEDED);
1680  neg_assign_r(d1, d, ROUND_NOT_NEEDED);
1681  div_assign_r(d, d, c_denom, ROUND_NOT_NEEDED);
1682  div_assign_r(d1, d1, c_denom, ROUND_NOT_NEEDED);
1683 
1684  if (is_plus_infinity(x)) {
1685  if (!is_plus_infinity(y)) {
1686  // `*this' is in the following form:
1687  // `-y <= v - u'.
1688  // In this case `*this' is disjoint from `c' if
1689  // `-y > d' (`-y >= d' if c is a strict equality), i.e. if
1690  // `y < d1' (`y <= d1' if c is a strict equality).
1693  numer_denom(y, numer, denom);
1694  assign_r(q_denom, denom, ROUND_NOT_NEEDED);
1695  assign_r(q_y, numer, ROUND_NOT_NEEDED);
1696  div_assign_r(q_y, q_y, q_denom, ROUND_NOT_NEEDED);
1697  if (q_y < d1) {
1699  }
1700  if (q_y == d1 && c.is_strict_inequality()) {
1702  }
1703  }
1704 
1705  // In all other cases `*this' intersects `c'.
1707  }
1708 
1709  // Here `x' is not plus-infinity.
1712  numer_denom(x, numer, denom);
1713  assign_r(q_denom, denom, ROUND_NOT_NEEDED);
1714  assign_r(q_x, numer, ROUND_NOT_NEEDED);
1715  div_assign_r(q_x, q_x, q_denom, ROUND_NOT_NEEDED);
1716 
1717  if (!is_plus_infinity(y)) {
1718  numer_denom(y, numer, denom);
1719  assign_r(q_denom, denom, ROUND_NOT_NEEDED);
1720  assign_r(q_y, numer, ROUND_NOT_NEEDED);
1721  div_assign_r(q_y, q_y, q_denom, ROUND_NOT_NEEDED);
1722  if (q_x == d && q_y == d1) {
1723  if (c.is_strict_inequality()) {
1726  }
1727  else {
1730  }
1731  }
1732  // `*this' is disjoint from `c' when
1733  // `-y > d' (`-y >= d' if c is a strict equality), i.e. if
1734  // `y < d1' (`y <= d1' if c is a strict equality).
1735  if (q_y < d1) {
1737  }
1738  if (q_y == d1 && c.is_strict_inequality()) {
1740  }
1741  }
1742 
1743  // Here `y' can be also plus-infinity.
1744  // If `c' is an equality, `*this' is disjoint from `c' if
1745  // `x < d'.
1746  if (d > q_x) {
1747  if (c.is_equality()) {
1749  }
1750  else {
1752  }
1753  }
1754 
1755  if (d == q_x && c.is_nonstrict_inequality()) {
1757  }
1758  // In all other cases `*this' intersects `c'.
1760 }
1761 
1762 template <typename T>
1765  const dimension_type space_dim = space_dimension();
1766  const dimension_type g_space_dim = g.space_dimension();
1767 
1768  // Dimension-compatibility check.
1769  if (space_dim < g_space_dim) {
1770  throw_dimension_incompatible("relation_with(g)", g);
1771  }
1772  shortest_path_closure_assign();
1773  // The empty BDS cannot subsume a generator.
1774  if (marked_empty()) {
1775  return Poly_Gen_Relation::nothing();
1776  }
1777  // A universe BDS in a zero-dimensional space subsumes
1778  // all the generators of a zero-dimensional space.
1779  if (space_dim == 0) {
1780  return Poly_Gen_Relation::subsumes();
1781  }
1782  const bool is_line = g.is_line();
1783  const bool is_line_or_ray = g.is_line_or_ray();
1784 
1785  // The relation between the BDS and the given generator is obtained
1786  // checking if the generator satisfies all the constraints in the BDS.
1787  // To check if the generator satisfies all the constraints it's enough
1788  // studying the sign of the scalar product between the generator and
1789  // all the constraints in the BDS.
1790 
1791  // Allocation of temporaries done once and for all.
1794  PPL_DIRTY_TEMP_COEFFICIENT(product);
1795  // We find in `*this' all the constraints.
1796  // TODO: This loop can be optimized more, if needed.
1797  for (dimension_type i = 0; i <= space_dim; ++i) {
1798  const Coefficient& g_coeff_y = (i > g_space_dim || i == 0)
1799  ? Coefficient_zero() : g.coefficient(Variable(i-1));
1800  const DB_Row<N>& dbm_i = dbm[i];
1801  for (dimension_type j = i + 1; j <= space_dim; ++j) {
1802  const Coefficient& g_coeff_x = (j > g_space_dim)
1803  ? Coefficient_zero() : g.coefficient(Variable(j-1));
1804  const N& dbm_ij = dbm_i[j];
1805  const N& dbm_ji = dbm[j][i];
1806  if (is_additive_inverse(dbm_ji, dbm_ij)) {
1807  // We have one equality constraint: denom*x - denom*y = numer.
1808  // Compute the scalar product.
1809  numer_denom(dbm_ij, numer, denom);
1810  product = g_coeff_y;
1811  product -= g_coeff_x;
1812  product *= denom;
1813  if (!is_line_or_ray) {
1814  add_mul_assign(product, numer, g.divisor());
1815  }
1816  if (product != 0) {
1817  return Poly_Gen_Relation::nothing();
1818  }
1819  }
1820  else {
1821  // We have 0, 1 or 2 binary inequality constraint/s.
1822  if (!is_plus_infinity(dbm_ij)) {
1823  // We have the binary inequality constraint:
1824  // denom*x - denom*y <= numer.
1825  // Compute the scalar product.
1826  numer_denom(dbm_ij, numer, denom);
1827  product = g_coeff_y;
1828  product -= g_coeff_x;
1829  product *= denom;
1830  if (!is_line_or_ray) {
1831  add_mul_assign(product, numer, g.divisor());
1832  }
1833  if (is_line) {
1834  if (product != 0) {
1835  // Lines must saturate all constraints.
1836  return Poly_Gen_Relation::nothing();
1837  }
1838  }
1839  else {
1840  // `g' is either a ray, a point or a closure point.
1841  if (product < 0) {
1842  return Poly_Gen_Relation::nothing();
1843  }
1844  }
1845  }
1846 
1847  if (!is_plus_infinity(dbm_ji)) {
1848  // We have the binary inequality constraint: denom*y - denom*x <= b.
1849  // Compute the scalar product.
1850  numer_denom(dbm_ji, numer, denom);
1851  product = 0;
1852  add_mul_assign(product, denom, g_coeff_x);
1853  add_mul_assign(product, -denom, g_coeff_y);
1854  if (!is_line_or_ray) {
1855  add_mul_assign(product, numer, g.divisor());
1856  }
1857  if (is_line) {
1858  if (product != 0) {
1859  // Lines must saturate all constraints.
1860  return Poly_Gen_Relation::nothing();
1861  }
1862  }
1863  else {
1864  // `g' is either a ray, a point or a closure point.
1865  if (product < 0) {
1866  return Poly_Gen_Relation::nothing();
1867  }
1868  }
1869  }
1870  }
1871  }
1872  }
1873 
1874  // The generator satisfies all the constraints.
1875  return Poly_Gen_Relation::subsumes();
1876 }
1877 
1878 template <typename T>
1879 void
1881  // Do something only if necessary.
1882  if (marked_empty() || marked_shortest_path_closed()) {
1883  return;
1884  }
1885  const dimension_type num_dimensions = space_dimension();
1886  // Zero-dimensional BDSs are necessarily shortest-path closed.
1887  if (num_dimensions == 0) {
1888  return;
1889  }
1890  // Even though the BDS will not change, its internal representation
1891  // is going to be modified by the Floyd-Warshall algorithm.
1892  BD_Shape& x = const_cast<BD_Shape<T>&>(*this);
1893 
1894  // Fill the main diagonal with zeros.
1895  for (dimension_type h = num_dimensions + 1; h-- > 0; ) {
1896  PPL_ASSERT(is_plus_infinity(x.dbm[h][h]));
1897  assign_r(x.dbm[h][h], 0, ROUND_NOT_NEEDED);
1898  }
1899 
1900  PPL_DIRTY_TEMP(N, sum);
1901  for (dimension_type k = num_dimensions + 1; k-- > 0; ) {
1902  const DB_Row<N>& x_dbm_k = x.dbm[k];
1903  for (dimension_type i = num_dimensions + 1; i-- > 0; ) {
1904  DB_Row<N>& x_dbm_i = x.dbm[i];
1905  const N& x_dbm_i_k = x_dbm_i[k];
1906  if (!is_plus_infinity(x_dbm_i_k)) {
1907  for (dimension_type j = num_dimensions + 1; j-- > 0; ) {
1908  const N& x_dbm_k_j = x_dbm_k[j];
1909  if (!is_plus_infinity(x_dbm_k_j)) {
1910  // Rounding upward for correctness.
1911  add_assign_r(sum, x_dbm_i_k, x_dbm_k_j, ROUND_UP);
1912  min_assign(x_dbm_i[j], sum);
1913  }
1914  }
1915  }
1916  }
1917  }
1918 
1919  // Check for emptiness: the BDS is empty if and only if there is a
1920  // negative value on the main diagonal of `dbm'.
1921  for (dimension_type h = num_dimensions + 1; h-- > 0; ) {
1922  N& x_dbm_hh = x.dbm[h][h];
1923  if (sgn(x_dbm_hh) < 0) {
1924  x.set_empty();
1925  return;
1926  }
1927  else {
1928  PPL_ASSERT(sgn(x_dbm_hh) == 0);
1929  // Restore PLUS_INFINITY on the main diagonal.
1931  }
1932  }
1933 
1934  // The BDS is not empty and it is now shortest-path closed.
1936 }
1937 
1938 template <typename T>
1939 void
1941  // Do something only if necessary.
1942  if (marked_empty() || marked_shortest_path_closed()) {
1943  return;
1944  }
1945  const dimension_type num_dimensions = space_dimension();
1946  PPL_ASSERT(var.id() < num_dimensions);
1947 
1948  // Even though the BDS will not change, its internal representation
1949  // is going to be modified by the incremental Floyd-Warshall algorithm.
1950  BD_Shape& x = const_cast<BD_Shape&>(*this);
1951 
1952  // Fill the main diagonal with zeros.
1953  for (dimension_type h = num_dimensions + 1; h-- > 0; ) {
1954  PPL_ASSERT(is_plus_infinity(x.dbm[h][h]));
1955  assign_r(x.dbm[h][h], 0, ROUND_NOT_NEEDED);
1956  }
1957 
1958  // Using the incremental Floyd-Warshall algorithm.
1959  PPL_DIRTY_TEMP(N, sum);
1960  const dimension_type v = var.id() + 1;
1961  DB_Row<N>& x_v = x.dbm[v];
1962  // Step 1: Improve all constraints on variable `var'.
1963  for (dimension_type k = num_dimensions + 1; k-- > 0; ) {
1964  DB_Row<N>& x_k = x.dbm[k];
1965  const N& x_v_k = x_v[k];
1966  const N& x_k_v = x_k[v];
1967  const bool x_v_k_finite = !is_plus_infinity(x_v_k);
1968  const bool x_k_v_finite = !is_plus_infinity(x_k_v);
1969  // Specialize inner loop based on finiteness info.
1970  if (x_v_k_finite) {
1971  if (x_k_v_finite) {
1972  // Here both x_v_k and x_k_v are finite.
1973  for (dimension_type i = num_dimensions + 1; i-- > 0; ) {
1974  DB_Row<N>& x_i = x.dbm[i];
1975  const N& x_i_k = x_i[k];
1976  if (!is_plus_infinity(x_i_k)) {
1977  add_assign_r(sum, x_i_k, x_k_v, ROUND_UP);
1978  min_assign(x_i[v], sum);
1979  }
1980  const N& x_k_i = x_k[i];
1981  if (!is_plus_infinity(x_k_i)) {
1982  add_assign_r(sum, x_v_k, x_k_i, ROUND_UP);
1983  min_assign(x_v[i], sum);
1984  }
1985  }
1986  }
1987  else {
1988  // Here x_v_k is finite, but x_k_v is not.
1989  for (dimension_type i = num_dimensions + 1; i-- > 0; ) {
1990  const N& x_k_i = x_k[i];
1991  if (!is_plus_infinity(x_k_i)) {
1992  add_assign_r(sum, x_v_k, x_k_i, ROUND_UP);
1993  min_assign(x_v[i], sum);
1994  }
1995  }
1996  }
1997  }
1998  else if (x_k_v_finite) {
1999  // Here x_v_k is infinite, but x_k_v is finite.
2000  for (dimension_type i = num_dimensions + 1; i-- > 0; ) {
2001  DB_Row<N>& x_i = x.dbm[i];
2002  const N& x_i_k = x_i[k];
2003  if (!is_plus_infinity(x_i_k)) {
2004  add_assign_r(sum, x_i_k, x_k_v, ROUND_UP);
2005  min_assign(x_i[v], sum);
2006  }
2007  }
2008  }
2009  else {
2010  // Here both x_v_k and x_k_v are infinite.
2011  continue;
2012  }
2013  }
2014 
2015  // Step 2: improve the other bounds by using the precise bounds
2016  // for the constraints on `var'.
2017  for (dimension_type i = num_dimensions + 1; i-- > 0; ) {
2018  DB_Row<N>& x_i = x.dbm[i];
2019  const N& x_i_v = x_i[v];
2020  if (!is_plus_infinity(x_i_v)) {
2021  for (dimension_type j = num_dimensions + 1; j-- > 0; ) {
2022  const N& x_v_j = x_v[j];
2023  if (!is_plus_infinity(x_v_j)) {
2024  add_assign_r(sum, x_i_v, x_v_j, ROUND_UP);
2025  min_assign(x_i[j], sum);
2026  }
2027  }
2028  }
2029  }
2030 
2031  // Check for emptiness: the BDS is empty if and only if there is a
2032  // negative value on the main diagonal of `dbm'.
2033  for (dimension_type h = num_dimensions + 1; h-- > 0; ) {
2034  N& x_dbm_hh = x.dbm[h][h];
2035  if (sgn(x_dbm_hh) < 0) {
2036  x.set_empty();
2037  return;
2038  }
2039  else {
2040  PPL_ASSERT(sgn(x_dbm_hh) == 0);
2041  // Restore PLUS_INFINITY on the main diagonal.
2043  }
2044  }
2045 
2046  // The BDS is not empty and it is now shortest-path closed.
2047  x.set_shortest_path_closed();
2048 }
2049 
2050 template <typename T>
2051 void
2053  // Do something only if necessary.
2054  if (marked_shortest_path_reduced()) {
2055  return;
2056  }
2057  const dimension_type space_dim = space_dimension();
2058  // Zero-dimensional BDSs are necessarily reduced.
2059  if (space_dim == 0) {
2060  return;
2061  }
2062  // First find the tightest constraints for this BDS.
2063  shortest_path_closure_assign();
2064 
2065  // If `*this' is empty, then there is nothing to reduce.
2066  if (marked_empty()) {
2067  return;
2068  }
2069  // Step 1: compute zero-equivalence classes.
2070  // Variables corresponding to indices `i' and `j' are zero-equivalent
2071  // if they lie on a zero-weight loop; since the matrix is shortest-path
2072  // closed, this happens if and only if dbm[i][j] == -dbm[j][i].
2073  std::vector<dimension_type> predecessor;
2074  compute_predecessors(predecessor);
2075  std::vector<dimension_type> leaders;
2076  compute_leader_indices(predecessor, leaders);
2077  const dimension_type num_leaders = leaders.size();
2078 
2079  Bit_Matrix redundancy(space_dim + 1, space_dim + 1);
2080  // Init all constraints to be redundant.
2081  // TODO: provide an appropriate method to set multiple bits.
2082  Bit_Row& red_0 = redundancy[0];
2083  for (dimension_type j = space_dim + 1; j-- > 0; ) {
2084  red_0.set(j);
2085  }
2086  for (dimension_type i = space_dim + 1; i-- > 0; ) {
2087  redundancy[i] = red_0;
2088  }
2089  // Step 2: flag non-redundant constraints in the (zero-cycle-free)
2090  // subsystem of bounded differences having only leaders as variables.
2091  PPL_DIRTY_TEMP(N, c);
2092  for (dimension_type l_i = 0; l_i < num_leaders; ++l_i) {
2093  const dimension_type i = leaders[l_i];
2094  const DB_Row<N>& dbm_i = dbm[i];
2095  Bit_Row& redundancy_i = redundancy[i];
2096  for (dimension_type l_j = 0; l_j < num_leaders; ++l_j) {
2097  const dimension_type j = leaders[l_j];
2098  if (redundancy_i[j]) {
2099  const N& dbm_i_j = dbm_i[j];
2100  redundancy_i.clear(j);
2101  for (dimension_type l_k = 0; l_k < num_leaders; ++l_k) {
2102  const dimension_type k = leaders[l_k];
2103  add_assign_r(c, dbm_i[k], dbm[k][j], ROUND_UP);
2104  if (dbm_i_j >= c) {
2105  redundancy_i.set(j);
2106  break;
2107  }
2108  }
2109  }
2110  }
2111  }
2112 
2113  // Step 3: flag non-redundant constraints in zero-equivalence classes.
2114  // Each equivalence class must have a single 0-cycle connecting
2115  // all the equivalent variables in increasing order.
2116  std::deque<bool> dealt_with(space_dim + 1, false);
2117  for (dimension_type i = space_dim + 1; i-- > 0; ) {
2118  // We only need to deal with non-singleton zero-equivalence classes
2119  // that haven't already been dealt with.
2120  if (i != predecessor[i] && !dealt_with[i]) {
2121  dimension_type j = i;
2122  while (true) {
2123  const dimension_type predecessor_j = predecessor[j];
2124  if (j == predecessor_j) {
2125  // We finally found the leader of `i'.
2126  PPL_ASSERT(redundancy[i][j]);
2127  redundancy[i].clear(j);
2128  // Here we dealt with `j' (i.e., `predecessor_j'), but it is useless
2129  // to update `dealt_with' because `j' is a leader.
2130  break;
2131  }
2132  // We haven't found the leader of `i' yet.
2133  PPL_ASSERT(redundancy[predecessor_j][j]);
2134  redundancy[predecessor_j].clear(j);
2135  dealt_with[predecessor_j] = true;
2136  j = predecessor_j;
2137  }
2138  }
2139  }
2140  // Even though shortest-path reduction is not going to change the BDS,
2141  // it might change its internal representation.
2142  BD_Shape<T>& x = const_cast<BD_Shape<T>&>(*this);
2143  using std::swap;
2144  swap(x.redundancy_dbm, redundancy);
2146 
2147  PPL_ASSERT(is_shortest_path_reduced());
2148 }
2149 
2150 template <typename T>
2151 void
2153  const dimension_type space_dim = space_dimension();
2154 
2155  // Dimension-compatibility check.
2156  if (space_dim != y.space_dimension()) {
2157  throw_dimension_incompatible("upper_bound_assign(y)", y);
2158  }
2159  // The upper bound of a BD shape `bd' with an empty shape is `bd'.
2161  if (y.marked_empty()) {
2162  return;
2163  }
2164  shortest_path_closure_assign();
2165  if (marked_empty()) {
2166  *this = y;
2167  return;
2168  }
2169 
2170  // The bds-hull consists in constructing `*this' with the maximum
2171  // elements selected from `*this' and `y'.
2172  PPL_ASSERT(space_dim == 0 || marked_shortest_path_closed());
2173  for (dimension_type i = space_dim + 1; i-- > 0; ) {
2174  DB_Row<N>& dbm_i = dbm[i];
2175  const DB_Row<N>& y_dbm_i = y.dbm[i];
2176  for (dimension_type j = space_dim + 1; j-- > 0; ) {
2177  N& dbm_ij = dbm_i[j];
2178  const N& y_dbm_ij = y_dbm_i[j];
2179  if (dbm_ij < y_dbm_ij) {
2180  dbm_ij = y_dbm_ij;
2181  }
2182  }
2183  }
2184  // Shortest-path closure is maintained (if it was holding).
2185  // TODO: see whether reduction can be (efficiently!) maintained too.
2186  if (marked_shortest_path_reduced()) {
2187  reset_shortest_path_reduced();
2188  }
2189  PPL_ASSERT(OK());
2190 }
2191 
2192 template <typename T>
2193 bool
2195  // Declare a const reference to *this (to avoid accidental modifications).
2196  const BD_Shape& x = *this;
2197  const dimension_type x_space_dim = x.space_dimension();
2198 
2199  // Private method: the caller must ensure the following.
2200  PPL_ASSERT(x_space_dim == y.space_dimension());
2201 
2202  // The zero-dim case is trivial.
2203  if (x_space_dim == 0) {
2204  upper_bound_assign(y);
2205  return true;
2206  }
2207  // If `x' or `y' is (known to be) empty, the upper bound is exact.
2208  if (x.marked_empty()) {
2209  *this = y;
2210  return true;
2211  }
2212  else if (y.is_empty()) {
2213  return true;
2214  }
2215  else if (x.is_empty()) {
2216  *this = y;
2217  return true;
2218  }
2219 
2220  // Here both `x' and `y' are known to be non-empty.
2221  // Implementation based on Algorithm 4.1 (page 6) in [BemporadFT00TR],
2222  // tailored to the special case of BD shapes.
2223 
2224  Variable epsilon(x_space_dim);
2225  Linear_Expression zero_expr;
2226  zero_expr.set_space_dimension(x_space_dim + 1);
2227  Linear_Expression db_expr;
2230 
2231  // Step 1: compute the constraint system for the envelope env(x,y)
2232  // and put into x_cs_removed and y_cs_removed those non-redundant
2233  // constraints that are not in the constraint system for env(x,y).
2234  // While at it, also add the additional space dimension (epsilon).
2235  Constraint_System env_cs;
2236  Constraint_System x_cs_removed;
2237  Constraint_System y_cs_removed;
2240  for (dimension_type i = x_space_dim + 1; i-- > 0; ) {
2241  const Bit_Row& x_red_i = x.redundancy_dbm[i];
2242  const Bit_Row& y_red_i = y.redundancy_dbm[i];
2243  const DB_Row<N>& x_dbm_i = x.dbm[i];
2244  const DB_Row<N>& y_dbm_i = y.dbm[i];
2245  for (dimension_type j = x_space_dim + 1; j-- > 0; ) {
2246  if (x_red_i[j] && y_red_i[j]) {
2247  continue;
2248  }
2249  if (!x_red_i[j]) {
2250  const N& x_dbm_ij = x_dbm_i[j];
2251  PPL_ASSERT(!is_plus_infinity(x_dbm_ij));
2252  numer_denom(x_dbm_ij, numer, denom);
2253  // Build skeleton DB constraint (having the right space dimension).
2254  db_expr = zero_expr;
2255  if (i > 0) {
2256  db_expr += Variable(i-1);
2257  }
2258  if (j > 0) {
2259  db_expr -= Variable(j-1);
2260  }
2261  if (denom != 1) {
2262  db_expr *= denom;
2263  }
2264  db_expr += numer;
2265  if (x_dbm_ij >= y_dbm_i[j]) {
2266  env_cs.insert(db_expr >= 0);
2267  }
2268  else {
2269  db_expr += epsilon;
2270  x_cs_removed.insert(db_expr == 0);
2271  }
2272  }
2273  if (!y_red_i[j]) {
2274  const N& y_dbm_ij = y_dbm_i[j];
2275  const N& x_dbm_ij = x_dbm_i[j];
2276  PPL_ASSERT(!is_plus_infinity(y_dbm_ij));
2277  numer_denom(y_dbm_ij, numer, denom);
2278  // Build skeleton DB constraint (having the right space dimension).
2279  db_expr = zero_expr;
2280  if (i > 0) {
2281  db_expr += Variable(i-1);
2282  }
2283  if (j > 0) {
2284  db_expr -= Variable(j-1);
2285  }
2286  if (denom != 1) {
2287  db_expr *= denom;
2288  }
2289  db_expr += numer;
2290  if (y_dbm_ij >= x_dbm_ij) {
2291  // Check if same constraint was added when considering x_dbm_ij.
2292  if (!x_red_i[j] && x_dbm_ij == y_dbm_ij) {
2293  continue;
2294  }
2295  env_cs.insert(db_expr >= 0);
2296  }
2297  else {
2298  db_expr += epsilon;
2299  y_cs_removed.insert(db_expr == 0);
2300  }
2301  }
2302  }
2303  }
2304 
2305  if (x_cs_removed.empty()) {
2306  // No constraint of x was removed: y is included in x.
2307  return true;
2308  }
2309  if (y_cs_removed.empty()) {
2310  // No constraint of y was removed: x is included in y.
2311  *this = y;
2312  return true;
2313  }
2314 
2315  // In preparation to Step 4: build the common part of LP problems,
2316  // i.e., the constraints corresponding to env(x,y),
2317  // where the additional space dimension (epsilon) has to be maximized.
2318  MIP_Problem env_lp(x_space_dim + 1, env_cs, epsilon, MAXIMIZATION);
2319  // Pre-solve `env_lp' to later exploit incrementality.
2320  env_lp.solve();
2321  PPL_ASSERT(env_lp.solve() != UNFEASIBLE_MIP_PROBLEM);
2322 
2323  // Implementing loop in Steps 3-6.
2324  for (Constraint_System::const_iterator i = x_cs_removed.begin(),
2325  i_end = x_cs_removed.end(); i != i_end; ++i) {
2326  MIP_Problem lp_i(env_lp);
2327  lp_i.add_constraint(*i);
2328  // Pre-solve to exploit incrementality.
2329  if (lp_i.solve() == UNFEASIBLE_MIP_PROBLEM) {
2330  continue;
2331  }
2332  for (Constraint_System::const_iterator j = y_cs_removed.begin(),
2333  j_end = y_cs_removed.end(); j != j_end; ++j) {
2334  MIP_Problem lp_ij(lp_i);
2335  lp_ij.add_constraint(*j);
2336  // Solve and check for a positive optimal value.
2337  switch (lp_ij.solve()) {
2339  // CHECKME: is the following actually impossible?
2340  PPL_UNREACHABLE;
2341  return false;
2342  case UNBOUNDED_MIP_PROBLEM:
2343  return false;
2344  case OPTIMIZED_MIP_PROBLEM:
2345  lp_ij.optimal_value(numer, denom);
2346  if (numer > 0) {
2347  return false;
2348  }
2349  break;
2350  }
2351  }
2352  }
2353 
2354  // The upper bound of x and y is indeed exact.
2355  upper_bound_assign(y);
2356  PPL_ASSERT(OK());
2357  return true;
2358 }
2359 
2360 template <typename T>
2361 template <bool integer_upper_bound>
2362 bool
2364  PPL_COMPILE_TIME_CHECK(!integer_upper_bound
2366  "BD_Shape<T>::BHZ09_upper_bound_assign_if_exact(y):"
2367  " instantiating for integer upper bound,"
2368  " but T in not an integer datatype.");
2369 
2370  // FIXME, CHECKME: what about inexact computations?
2371  // Declare a const reference to *this (to avoid accidental modifications).
2372  const BD_Shape& x = *this;
2373  const dimension_type x_space_dim = x.space_dimension();
2374 
2375  // Private method: the caller must ensure the following.
2376  PPL_ASSERT(x_space_dim == y.space_dimension());
2377 
2378  // The zero-dim case is trivial.
2379  if (x_space_dim == 0) {
2380  upper_bound_assign(y);
2381  return true;
2382  }
2383  // If `x' or `y' is (known to be) empty, the upper bound is exact.
2384  if (x.marked_empty()) {
2385  *this = y;
2386  return true;
2387  }
2388  else if (y.is_empty()) {
2389  return true;
2390  }
2391  else if (x.is_empty()) {
2392  *this = y;
2393  return true;
2394  }
2395 
2396  // Here both `x' and `y' are known to be non-empty.
2399  PPL_ASSERT(x.marked_shortest_path_closed());
2400  PPL_ASSERT(y.marked_shortest_path_closed());
2401  // Pre-compute the upper bound of `x' and `y'.
2402  BD_Shape<T> ub(x);
2403  ub.upper_bound_assign(y);
2404 
2405  PPL_DIRTY_TEMP(N, lhs);
2406  PPL_DIRTY_TEMP(N, rhs);
2407  PPL_DIRTY_TEMP(N, temp_zero);
2408  assign_r(temp_zero, 0, ROUND_NOT_NEEDED);
2409  PPL_DIRTY_TEMP(N, temp_one);
2410  if (integer_upper_bound) {
2411  assign_r(temp_one, 1, ROUND_NOT_NEEDED);
2412  }
2413  for (dimension_type i = x_space_dim + 1; i-- > 0; ) {
2414  const DB_Row<N>& x_i = x.dbm[i];
2415  const Bit_Row& x_red_i = x.redundancy_dbm[i];
2416  const DB_Row<N>& y_i = y.dbm[i];
2417  const DB_Row<N>& ub_i = ub.dbm[i];
2418  for (dimension_type j = x_space_dim + 1; j-- > 0; ) {
2419  // Check redundancy of x_i_j.
2420  if (x_red_i[j]) {
2421  continue;
2422  }
2423  // By non-redundancy, we know that i != j.
2424  PPL_ASSERT(i != j);
2425  const N& x_i_j = x_i[j];
2426  if (x_i_j < y_i[j]) {
2427  for (dimension_type k = x_space_dim + 1; k-- > 0; ) {
2428  const DB_Row<N>& x_k = x.dbm[k];
2429  const DB_Row<N>& y_k = y.dbm[k];
2430  const Bit_Row& y_red_k = y.redundancy_dbm[k];
2431  const DB_Row<N>& ub_k = ub.dbm[k];
2432  const N& ub_k_j = (k == j) ? temp_zero : ub_k[j];
2433  for (dimension_type ell = x_space_dim + 1; ell-- > 0; ) {
2434  // Check redundancy of y_k_ell.
2435  if (y_red_k[ell]) {
2436  continue;
2437  }
2438  // By non-redundancy, we know that k != ell.
2439  PPL_ASSERT(k != ell);
2440  const N& y_k_ell = y_k[ell];
2441  if (y_k_ell < x_k[ell]) {
2442  // The first condition in BHZ09 theorem holds;
2443  // now check for the second condition.
2444  add_assign_r(lhs, x_i_j, y_k_ell, ROUND_UP);
2445  const N& ub_i_ell = (i == ell) ? temp_zero : ub_i[ell];
2446  add_assign_r(rhs, ub_i_ell, ub_k_j, ROUND_UP);
2447  if (integer_upper_bound) {
2448  // Note: adding 1 rather than 2 (as in Theorem 5.3)
2449  // so as to later test for < rather than <=.
2450  add_assign_r(lhs, lhs, temp_one, ROUND_NOT_NEEDED);
2451  }
2452  // Testing for < in both the rational and integer case.
2453  if (lhs < rhs) {
2454  return false;
2455  }
2456  }
2457  }
2458  }
2459  }
2460  }
2461  }
2462  // The upper bound of x and y is indeed exact.
2463  m_swap(ub);
2464  PPL_ASSERT(OK());
2465  return true;
2466 }
2467 
2468 template <typename T>
2469 void
2471  const dimension_type space_dim = space_dimension();
2472 
2473  // Dimension-compatibility check.
2474  if (space_dim != y.space_dimension()) {
2475  throw_dimension_incompatible("difference_assign(y)", y);
2476  }
2477  BD_Shape new_bd_shape(space_dim, EMPTY);
2478 
2479  BD_Shape& x = *this;
2480 
2482  // The difference of an empty bounded difference shape
2483  // and of a bounded difference shape `p' is empty.
2484  if (x.marked_empty()) {
2485  return;
2486  }
2488  // The difference of a bounded difference shape `p'
2489  // and an empty bounded difference shape is `p'.
2490  if (y.marked_empty()) {
2491  return;
2492  }
2493  // If both bounded difference shapes are zero-dimensional,
2494  // then at this point they are necessarily universe system of
2495  // bounded differences, so that their difference is empty.
2496  if (space_dim == 0) {
2497  x.set_empty();
2498  return;
2499  }
2500 
2501  // TODO: This is just an executable specification.
2502  // Have to find a more efficient method.
2503  if (y.contains(x)) {
2504  x.set_empty();
2505  return;
2506  }
2507 
2508  // We take a constraint of the system y at the time and we
2509  // consider its complementary. Then we intersect the union
2510  // of these complementary constraints with the system x.
2511  const Constraint_System& y_cs = y.constraints();
2512  for (Constraint_System::const_iterator i = y_cs.begin(),
2513  y_cs_end = y_cs.end(); i != y_cs_end; ++i) {
2514  const Constraint& c = *i;
2515  // If the bounded difference shape `x' is included
2516  // in the bounded difference shape defined by `c',
2517  // then `c' _must_ be skipped, as adding its complement to `x'
2518  // would result in the empty bounded difference shape,
2519  // and as we would obtain a result that is less precise
2520  // than the bds-difference.
2522  continue;
2523  }
2524  BD_Shape z = x;
2525  const Linear_Expression e(c.expression());
2526  z.add_constraint(e <= 0);
2527  if (!z.is_empty()) {
2528  new_bd_shape.upper_bound_assign(z);
2529  }
2530  if (c.is_equality()) {
2531  z = x;
2532  z.add_constraint(e >= 0);
2533  if (!z.is_empty()) {
2534  new_bd_shape.upper_bound_assign(z);
2535  }
2536  }
2537  }
2538  *this = new_bd_shape;
2539  PPL_ASSERT(OK());
2540 }
2541 
2542 template <typename T>
2543 bool
2545  BD_Shape& x = *this;
2546  const dimension_type dim = x.space_dimension();
2547  // Dimension-compatibility check.
2548  if (dim != y.space_dimension()) {
2549  throw_dimension_incompatible("simplify_using_context_assign(y)", y);
2550  }
2551  // Filter away the zero-dimensional case.
2552  if (dim == 0) {
2553  if (y.marked_empty()) {
2554  x.set_zero_dim_univ();
2555  return false;
2556  }
2557  else {
2558  return !x.marked_empty();
2559  }
2560  }
2561 
2562  // Filter away the case where `x' contains `y'
2563  // (this subsumes the case when `y' is empty).
2565  if (x.contains(y)) {
2566  BD_Shape<T> res(dim, UNIVERSE);
2567  x.m_swap(res);
2568  return false;
2569  }
2570 
2571  // Filter away the case where `x' is empty.
2573  if (x.marked_empty()) {
2574  // Search for a constraint of `y' that is not a tautology.
2575  dimension_type i;
2576  dimension_type j;
2577  // Prefer unary constraints.
2578  i = 0;
2579  const DB_Row<N>& y_dbm_0 = y.dbm[0];
2580  for (j = 1; j <= dim; ++j) {
2581  if (!is_plus_infinity(y_dbm_0[j])) {
2582  // FIXME: if N is a float or bounded integer type, then
2583  // we also need to check that we are actually able to construct
2584  // a constraint inconsistent with respect to this one.
2585  goto found;
2586  }
2587  }
2588  j = 0;
2589  for (i = 1; i <= dim; ++i) {
2590  if (!is_plus_infinity(y.dbm[i][0])) {
2591  // FIXME: if N is a float or bounded integer type, then
2592  // we also need to check that we are actually able to construct
2593  // a constraint inconsistent with respect to this one.
2594  goto found;
2595  }
2596  }
2597  // Then search binary constraints.
2598  for (i = 1; i <= dim; ++i) {
2599  const DB_Row<N>& y_dbm_i = y.dbm[i];
2600  for (j = 1; j <= dim; ++j) {
2601  if (!is_plus_infinity(y_dbm_i[j])) {
2602  // FIXME: if N is a float or bounded integer type, then
2603  // we also need to check that we are actually able to construct
2604  // a constraint inconsistent with respect to this one.
2605  goto found;
2606  }
2607  }
2608  }
2609  // Not found: we were not able to build a constraint contradicting
2610  // one of the constraints in `y': `x' cannot be enlarged.
2611  return false;
2612 
2613  found:
2614  // Found: build a new BDS contradicting the constraint found.
2615  PPL_ASSERT(i <= dim && j <= dim && (i > 0 || j > 0));
2616  BD_Shape<T> res(dim, UNIVERSE);
2617  PPL_DIRTY_TEMP(N, tmp);
2618  assign_r(tmp, 1, ROUND_UP);
2619  add_assign_r(tmp, tmp, y.dbm[i][j], ROUND_UP);
2620  PPL_ASSERT(!is_plus_infinity(tmp));
2621  // CHECKME: round down is really meant.
2622  neg_assign_r(res.dbm[j][i], tmp, ROUND_DOWN);
2623  x.m_swap(res);
2624  return false;
2625  }
2626 
2627  // Here `x' and `y' are not empty and shortest-path closed;
2628  // also, `x' does not contain `y'.
2629  // Let `target' be the intersection of `x' and `y'.
2630  BD_Shape<T> target = x;
2631  target.intersection_assign(y);
2632  const bool bool_result = !target.is_empty();
2633 
2634  // Compute a reduced dbm for `x' and ...
2636  // ... count the non-redundant constraints.
2637  dimension_type x_num_non_redundant = (dim+1)*(dim+1);
2638  for (dimension_type i = dim + 1; i-- > 0; ) {
2639  x_num_non_redundant -= x.redundancy_dbm[i].count_ones();
2640  }
2641  PPL_ASSERT(x_num_non_redundant > 0);
2642 
2643  // Let `yy' be a copy of `y': we will keep adding to `yy'
2644  // the non-redundant constraints of `x',
2645  // stopping as soon as `yy' becomes equal to `target'.
2646  BD_Shape<T> yy = y;
2647 
2648  // The constraints added to `yy' will be recorded in `res' ...
2649  BD_Shape<T> res(dim, UNIVERSE);
2650  // ... and we will count them too.
2651  dimension_type res_num_non_redundant = 0;
2652 
2653  // Compute leader information for `x'.
2654  std::vector<dimension_type> x_leaders;
2655  x.compute_leaders(x_leaders);
2656 
2657  // First go through the unary equality constraints.
2658  const DB_Row<N>& x_dbm_0 = x.dbm[0];
2659  DB_Row<N>& yy_dbm_0 = yy.dbm[0];
2660  DB_Row<N>& res_dbm_0 = res.dbm[0];
2661  for (dimension_type j = 1; j <= dim; ++j) {
2662  // Unary equality constraints are encoded in entries dbm_0j and dbm_j0
2663  // provided index j has special variable index 0 as its leader.
2664  if (x_leaders[j] != 0) {
2665  continue;
2666  }
2667  PPL_ASSERT(!is_plus_infinity(x_dbm_0[j]));
2668  if (x_dbm_0[j] < yy_dbm_0[j]) {
2669  res_dbm_0[j] = x_dbm_0[j];
2670  ++res_num_non_redundant;
2671  // Tighten context `yy' using the newly added constraint.
2672  yy_dbm_0[j] = x_dbm_0[j];
2674  }
2675  PPL_ASSERT(!is_plus_infinity(x.dbm[j][0]));
2676  if (x.dbm[j][0] < yy.dbm[j][0]) {
2677  res.dbm[j][0] = x.dbm[j][0];
2678  ++res_num_non_redundant;
2679  // Tighten context `yy' using the newly added constraint.
2680  yy.dbm[j][0] = x.dbm[j][0];
2682  }
2683  // Restore shortest-path closure, if it was lost.
2684  if (!yy.marked_shortest_path_closed()) {
2685  Variable var_j(j-1);
2687  if (target.contains(yy)) {
2688  // Target reached: swap `x' and `res' if needed.
2689  if (res_num_non_redundant < x_num_non_redundant) {
2691  x.m_swap(res);
2692  }
2693  return bool_result;
2694  }
2695  }
2696  }
2697 
2698  // Go through the binary equality constraints.
2699  // Note: no need to consider the case i == 1.
2700  for (dimension_type i = 2; i <= dim; ++i) {
2701  const dimension_type j = x_leaders[i];
2702  if (j == i || j == 0) {
2703  continue;
2704  }
2705  PPL_ASSERT(!is_plus_infinity(x.dbm[i][j]));
2706  if (x.dbm[i][j] < yy.dbm[i][j]) {
2707  res.dbm[i][j] = x.dbm[i][j];
2708  ++res_num_non_redundant;
2709  // Tighten context `yy' using the newly added constraint.
2710  yy.dbm[i][j] = x.dbm[i][j];
2712  }
2713  PPL_ASSERT(!is_plus_infinity(x.dbm[j][i]));
2714  if (x.dbm[j][i] < yy.dbm[j][i]) {
2715  res.dbm[j][i] = x.dbm[j][i];
2716  ++res_num_non_redundant;
2717  // Tighten context `yy' using the newly added constraint.
2718  yy.dbm[j][i] = x.dbm[j][i];
2720  }
2721  // Restore shortest-path closure, if it was lost.
2722  if (!yy.marked_shortest_path_closed()) {
2723  Variable var_j(j-1);
2725  if (target.contains(yy)) {
2726  // Target reached: swap `x' and `res' if needed.
2727  if (res_num_non_redundant < x_num_non_redundant) {
2729  x.m_swap(res);
2730  }
2731  return bool_result;
2732  }
2733  }
2734  }
2735 
2736  // Finally go through the (proper) inequality constraints:
2737  // both indices i and j should be leaders.
2738  for (dimension_type i = 0; i <= dim; ++i) {
2739  if (i != x_leaders[i]) {
2740  continue;
2741  }
2742  const DB_Row<N>& x_dbm_i = x.dbm[i];
2743  const Bit_Row& x_redundancy_dbm_i = x.redundancy_dbm[i];
2744  DB_Row<N>& yy_dbm_i = yy.dbm[i];
2745  DB_Row<N>& res_dbm_i = res.dbm[i];
2746  for (dimension_type j = 0; j <= dim; ++j) {
2747  if (j != x_leaders[j] || x_redundancy_dbm_i[j]) {
2748  continue;
2749  }
2750  N& yy_dbm_ij = yy_dbm_i[j];
2751  const N& x_dbm_ij = x_dbm_i[j];
2752  if (x_dbm_ij < yy_dbm_ij) {
2753  res_dbm_i[j] = x_dbm_ij;
2754  ++res_num_non_redundant;
2755  // Tighten context `yy' using the newly added constraint.
2756  yy_dbm_ij = x_dbm_ij;
2758  PPL_ASSERT(i > 0 || j > 0);
2759  Variable var(((i > 0) ? i : j) - 1);
2761  if (target.contains(yy)) {
2762  // Target reached: swap `x' and `res' if needed.
2763  if (res_num_non_redundant < x_num_non_redundant) {
2765  x.m_swap(res);
2766  }
2767  return bool_result;
2768  }
2769  }
2770  }
2771  }
2772  // This point should be unreachable.
2773  PPL_UNREACHABLE;
2774  return false;
2775 }
2776 
2777 template <typename T>
2778 void
2780  // Adding no dimensions is a no-op.
2781  if (m == 0) {
2782  return;
2783  }
2784  const dimension_type space_dim = space_dimension();
2785  const dimension_type new_space_dim = space_dim + m;
2786  const bool was_zero_dim_univ = (!marked_empty() && space_dim == 0);
2787 
2788  // To embed an n-dimension space BDS in a (n+m)-dimension space,
2789  // we just add `m' rows and columns in the bounded difference shape,
2790  // initialized to PLUS_INFINITY.
2791  dbm.grow(new_space_dim + 1);
2792 
2793  // Shortest-path closure is maintained (if it was holding).
2794  // TODO: see whether reduction can be (efficiently!) maintained too.
2795  if (marked_shortest_path_reduced()) {
2796  reset_shortest_path_reduced();
2797  }
2798  // If `*this' was the zero-dim space universe BDS,
2799  // the we can set the shortest-path closure flag.
2800  if (was_zero_dim_univ) {
2801  set_shortest_path_closed();
2802  }
2803  PPL_ASSERT(OK());
2804 }
2805 
2806 template <typename T>
2807 void
2809  // Adding no dimensions is a no-op.
2810  if (m == 0) {
2811  return;
2812  }
2813  const dimension_type space_dim = space_dimension();
2814 
2815  // If `*this' was zero-dimensional, then we add `m' rows and columns.
2816  // If it also was non-empty, then we zero all the added elements
2817  // and set the flag for shortest-path closure.
2818  if (space_dim == 0) {
2819  dbm.grow(m + 1);
2820  if (!marked_empty()) {
2821  for (dimension_type i = m + 1; i-- > 0; ) {
2822  DB_Row<N>& dbm_i = dbm[i];
2823  for (dimension_type j = m + 1; j-- > 0; ) {
2824  if (i != j) {
2825  assign_r(dbm_i[j], 0, ROUND_NOT_NEEDED);
2826  }
2827  }
2828  }
2829  set_shortest_path_closed();
2830  }
2831  PPL_ASSERT(OK());
2832  return;
2833  }
2834 
2835  // To project an n-dimension space bounded difference shape
2836  // in a (n+m)-dimension space, we add `m' rows and columns.
2837  // In the first row and column of the matrix we add `zero' from
2838  // the (n+1)-th position to the end.
2839  const dimension_type new_space_dim = space_dim + m;
2840  dbm.grow(new_space_dim + 1);
2841 
2842  // Bottom of the matrix and first row.
2843  DB_Row<N>& dbm_0 = dbm[0];
2844  for (dimension_type i = space_dim + 1; i <= new_space_dim; ++i) {
2845  assign_r(dbm[i][0], 0, ROUND_NOT_NEEDED);
2846  assign_r(dbm_0[i], 0, ROUND_NOT_NEEDED);
2847  }
2848 
2849  if (marked_shortest_path_closed()) {
2850  reset_shortest_path_closed();
2851  }
2852  PPL_ASSERT(OK());
2853 }
2854 
2855 template <typename T>
2856 void
2858  // The removal of no dimensions from any BDS is a no-op.
2859  // Note that this case also captures the only legal removal of
2860  // space dimensions from a BDS in a 0-dim space.
2861  if (vars.empty()) {
2862  PPL_ASSERT(OK());
2863  return;
2864  }
2865 
2866  const dimension_type old_space_dim = space_dimension();
2867 
2868  // Dimension-compatibility check.
2869  const dimension_type min_space_dim = vars.space_dimension();
2870  if (old_space_dim < min_space_dim) {
2871  throw_dimension_incompatible("remove_space_dimensions(vs)", min_space_dim);
2872  }
2873  // Shortest-path closure is necessary to keep precision.
2874  shortest_path_closure_assign();
2875 
2876  // When removing _all_ dimensions from a BDS, we obtain the
2877  // zero-dimensional BDS.
2878  const dimension_type new_space_dim = old_space_dim - vars.size();
2879  if (new_space_dim == 0) {
2880  dbm.resize_no_copy(1);
2881  if (!marked_empty()) {
2882  // We set the zero_dim_univ flag.
2883  set_zero_dim_univ();
2884  }
2885  PPL_ASSERT(OK());
2886  return;
2887  }
2888 
2889  // Handle the case of an empty BD_Shape.
2890  if (marked_empty()) {
2891  dbm.resize_no_copy(new_space_dim + 1);
2892  PPL_ASSERT(OK());
2893  return;
2894  }
2895 
2896  // Shortest-path closure is maintained.
2897  // TODO: see whether reduction can be (efficiently!) maintained too.
2898  if (marked_shortest_path_reduced()) {
2899  reset_shortest_path_reduced();
2900  }
2901  // For each variable to remove, we fill the corresponding column and
2902  // row by shifting respectively left and above those
2903  // columns and rows, that will not be removed.
2904  Variables_Set::const_iterator vsi = vars.begin();
2905  Variables_Set::const_iterator vsi_end = vars.end();
2906  dimension_type dst = *vsi + 1;
2907  dimension_type src = dst + 1;
2908  for (++vsi; vsi != vsi_end; ++vsi) {
2909  const dimension_type vsi_next = *vsi + 1;
2910  // All other columns and rows are moved respectively to the left
2911  // and above.
2912  while (src < vsi_next) {
2913  using std::swap;
2914  swap(dbm[dst], dbm[src]);
2915  for (dimension_type i = old_space_dim + 1; i-- > 0; ) {
2916  DB_Row<N>& dbm_i = dbm[i];
2917  assign_or_swap(dbm_i[dst], dbm_i[src]);
2918  }
2919  ++dst;
2920  ++src;
2921  }
2922  ++src;
2923  }
2924 
2925  // Moving the remaining rows and columns.
2926  while (src <= old_space_dim) {
2927  using std::swap;
2928  swap(dbm[dst], dbm[src]);
2929  for (dimension_type i = old_space_dim + 1; i-- > 0; ) {
2930  DB_Row<N>& dbm_i = dbm[i];
2931  assign_or_swap(dbm_i[dst], dbm_i[src]);
2932  }
2933  ++src;
2934  ++dst;
2935  }
2936 
2937  // Update the space dimension.
2938  dbm.resize_no_copy(new_space_dim + 1);
2939  PPL_ASSERT(OK());
2940 }
2941 
2942 template <typename T>
2943 template <typename Partial_Function>
2944 void
2946  const dimension_type space_dim = space_dimension();
2947  // TODO: this implementation is just an executable specification.
2948  if (space_dim == 0) {
2949  return;
2950  }
2951  if (pfunc.has_empty_codomain()) {
2952  // All dimensions vanish: the BDS becomes zero_dimensional.
2953  remove_higher_space_dimensions(0);
2954  return;
2955  }
2956 
2957  const dimension_type new_space_dim = pfunc.max_in_codomain() + 1;
2958  // If we are going to actually reduce the space dimension,
2959  // then shortest-path closure is required to keep precision.
2960  if (new_space_dim < space_dim) {
2961  shortest_path_closure_assign();
2962  }
2963  // If the BDS is empty, then it is sufficient to adjust the
2964  // space dimension of the bounded difference shape.
2965  if (marked_empty()) {
2966  remove_higher_space_dimensions(new_space_dim);
2967  return;
2968  }
2969 
2970  // Shortest-path closure is maintained (if it was holding).
2971  // TODO: see whether reduction can be (efficiently!) maintained too.
2972  if (marked_shortest_path_reduced()) {
2973  reset_shortest_path_reduced();
2974  }
2975  // We create a new matrix with the new space dimension.
2976  DB_Matrix<N> x(new_space_dim+1);
2977  // First of all we must map the unary constraints, because
2978  // there is the fictitious variable `zero', that can't be mapped
2979  // at all.
2980  DB_Row<N>& dbm_0 = dbm[0];
2981  DB_Row<N>& x_0 = x[0];
2982  for (dimension_type j = 1; j <= space_dim; ++j) {
2983  dimension_type new_j;
2984  if (pfunc.maps(j - 1, new_j)) {
2985  assign_or_swap(x_0[new_j + 1], dbm_0[j]);
2986  assign_or_swap(x[new_j + 1][0], dbm[j][0]);
2987  }
2988  }
2989  // Now we map the binary constraints, exchanging the indexes.
2990  for (dimension_type i = 1; i <= space_dim; ++i) {
2991  dimension_type new_i;
2992  if (pfunc.maps(i - 1, new_i)) {
2993  DB_Row<N>& dbm_i = dbm[i];
2994  ++new_i;
2995  DB_Row<N>& x_new_i = x[new_i];
2996  for (dimension_type j = i+1; j <= space_dim; ++j) {
2997  dimension_type new_j;
2998  if (pfunc.maps(j - 1, new_j)) {
2999  ++new_j;
3000  assign_or_swap(x_new_i[new_j], dbm_i[j]);
3001  assign_or_swap(x[new_j][new_i], dbm[j][i]);
3002  }
3003  }
3004  }
3005  }
3006 
3007  using std::swap;
3008  swap(dbm, x);
3009  PPL_ASSERT(OK());
3010 }
3011 
3012 template <typename T>
3013 void
3015  const dimension_type space_dim = space_dimension();
3016 
3017  // Dimension-compatibility check.
3018  if (space_dim != y.space_dimension()) {
3019  throw_dimension_incompatible("intersection_assign(y)", y);
3020  }
3021  // If one of the two bounded difference shapes is empty,
3022  // the intersection is empty.
3023  if (marked_empty()) {
3024  return;
3025  }
3026  if (y.marked_empty()) {
3027  set_empty();
3028  return;
3029  }
3030 
3031  // If both bounded difference shapes are zero-dimensional,
3032  // then at this point they are necessarily non-empty,
3033  // so that their intersection is non-empty too.
3034  if (space_dim == 0) {
3035  return;
3036  }
3037  // To intersect two bounded difference shapes we compare
3038  // the constraints and we choose the less values.
3039  bool changed = false;
3040  for (dimension_type i = space_dim + 1; i-- > 0; ) {
3041  DB_Row<N>& dbm_i = dbm[i];
3042  const DB_Row<N>& y_dbm_i = y.dbm[i];
3043  for (dimension_type j = space_dim + 1; j-- > 0; ) {
3044  N& dbm_ij = dbm_i[j];
3045  const N& y_dbm_ij = y_dbm_i[j];
3046  if (dbm_ij > y_dbm_ij) {
3047  dbm_ij = y_dbm_ij;
3048  changed = true;
3049  }
3050  }
3051  }
3052 
3053  if (changed && marked_shortest_path_closed()) {
3054  reset_shortest_path_closed();
3055  }
3056  PPL_ASSERT(OK());
3057 }
3058 
3059 template <typename T>
3060 template <typename Iterator>
3061 void
3063  Iterator first, Iterator last,
3064  unsigned* tp) {
3065  const dimension_type space_dim = space_dimension();
3066 
3067  // Dimension-compatibility check.
3068  if (space_dim != y.space_dimension()) {
3069  throw_dimension_incompatible("CC76_extrapolation_assign(y)", y);
3070  }
3071  // We assume that `y' is contained in or equal to `*this'.
3072  PPL_EXPECT_HEAVY(copy_contains(*this, y));
3073 
3074  // If both bounded difference shapes are zero-dimensional,
3075  // since `*this' contains `y', we simply return `*this'.
3076  if (space_dim == 0) {
3077  return;
3078  }
3079  shortest_path_closure_assign();
3080  // If `*this' is empty, since `*this' contains `y', `y' is empty too.
3081  if (marked_empty()) {
3082  return;
3083  }
3085  // If `y' is empty, we return.
3086  if (y.marked_empty()) {
3087  return;
3088  }
3089  // If there are tokens available, work on a temporary copy.
3090  if (tp != 0 && *tp > 0) {
3091  BD_Shape<T> x_tmp(*this);
3092  x_tmp.CC76_extrapolation_assign(y, first, last, 0);
3093  // If the widening was not precise, use one of the available tokens.
3094  if (!contains(x_tmp)) {
3095  --(*tp);
3096  }
3097  return;
3098  }
3099 
3100  // Compare each constraint in `y' to the corresponding one in `*this'.
3101  // The constraint in `*this' is kept as is if it is stronger than or
3102  // equal to the constraint in `y'; otherwise, the inhomogeneous term
3103  // of the constraint in `*this' is further compared with elements taken
3104  // from a sorted container (the stop-points, provided by the user), and
3105  // is replaced by the first entry, if any, which is greater than or equal
3106  // to the inhomogeneous term. If no such entry exists, the constraint
3107  // is removed altogether.
3108  for (dimension_type i = space_dim + 1; i-- > 0; ) {
3109  DB_Row<N>& dbm_i = dbm[i];
3110  const DB_Row<N>& y_dbm_i = y.dbm[i];
3111  for (dimension_type j = space_dim + 1; j-- > 0; ) {
3112  N& dbm_ij = dbm_i[j];
3113  const N& y_dbm_ij = y_dbm_i[j];
3114  if (y_dbm_ij < dbm_ij) {
3115  Iterator k = std::lower_bound(first, last, dbm_ij);
3116  if (k != last) {
3117  if (dbm_ij < *k) {
3118  assign_r(dbm_ij, *k, ROUND_UP);
3119  }
3120  }
3121  else {
3123  }
3124  }
3125  }
3126  }
3127  reset_shortest_path_closed();
3128  PPL_ASSERT(OK());
3129 }
3130 
3131 template <typename T>
3132 void
3134  BD_Shape& limiting_shape) const {
3135  // Private method: the caller has to ensure the following.
3136  PPL_ASSERT(cs.space_dimension() <= space_dimension());
3137 
3138  shortest_path_closure_assign();
3139  bool changed = false;
3141  PPL_DIRTY_TEMP_COEFFICIENT(minus_c_term);
3142  PPL_DIRTY_TEMP(N, d);
3143  PPL_DIRTY_TEMP(N, d1);
3144  for (Constraint_System::const_iterator cs_i = cs.begin(),
3145  cs_end = cs.end(); cs_i != cs_end; ++cs_i) {
3146  const Constraint& c = *cs_i;
3147  dimension_type num_vars = 0;
3148  dimension_type i = 0;
3149  dimension_type j = 0;
3150  // Constraints that are not bounded differences are ignored.
3151  if (BD_Shape_Helpers::extract_bounded_difference(c, num_vars, i, j, coeff)) {
3152  // Select the cell to be modified for the "<=" part of the constraint,
3153  // and set `coeff' to the absolute value of itself.
3154  const bool negative = (coeff < 0);
3155  const N& x = negative ? dbm[i][j] : dbm[j][i];
3156  const N& y = negative ? dbm[j][i] : dbm[i][j];
3157  DB_Matrix<N>& ls_dbm = limiting_shape.dbm;
3158  if (negative) {
3159  neg_assign(coeff);
3160  }
3161  // Compute the bound for `x', rounding towards plus infinity.
3162  div_round_up(d, c.inhomogeneous_term(), coeff);
3163  if (x <= d) {
3164  if (c.is_inequality()) {
3165  N& ls_x = negative ? ls_dbm[i][j] : ls_dbm[j][i];
3166  if (ls_x > d) {
3167  ls_x = d;
3168  changed = true;
3169  }
3170  }
3171  else {
3172  // Compute the bound for `y', rounding towards plus infinity.
3173  neg_assign(minus_c_term, c.inhomogeneous_term());
3174  div_round_up(d1, minus_c_term, coeff);
3175  if (y <= d1) {
3176  N& ls_x = negative ? ls_dbm[i][j] : ls_dbm[j][i];
3177  N& ls_y = negative ? ls_dbm[j][i] : ls_dbm[i][j];
3178  if ((ls_x >= d && ls_y > d1) || (ls_x > d && ls_y >= d1)) {
3179  ls_x = d;
3180  ls_y = d1;
3181  changed = true;
3182  }
3183  }
3184  }
3185  }
3186  }
3187  }
3188 
3189  // In general, adding a constraint does not preserve the shortest-path
3190  // closure of the bounded difference shape.
3191  if (changed && limiting_shape.marked_shortest_path_closed()) {
3192  limiting_shape.reset_shortest_path_closed();
3193  }
3194 }
3195 
3196 template <typename T>
3197 void
3199  const Constraint_System& cs,
3200  unsigned* tp) {
3201  // Dimension-compatibility check.
3202  const dimension_type space_dim = space_dimension();
3203  if (space_dim != y.space_dimension()) {
3204  throw_dimension_incompatible("limited_CC76_extrapolation_assign(y, cs)",
3205  y);
3206  }
3207  // `cs' must be dimension-compatible with the two systems
3208  // of bounded differences.
3209  const dimension_type cs_space_dim = cs.space_dimension();
3210  if (space_dim < cs_space_dim) {
3211  throw_invalid_argument("limited_CC76_extrapolation_assign(y, cs)",
3212  "cs is space_dimension incompatible");
3213  }
3214 
3215  // Strict inequalities not allowed.
3216  if (cs.has_strict_inequalities()) {
3217  throw_invalid_argument("limited_CC76_extrapolation_assign(y, cs)",
3218  "cs has strict inequalities");
3219  }
3220  // The limited CC76-extrapolation between two systems of bounded
3221  // differences in a zero-dimensional space is a system of bounded
3222  // differences in a zero-dimensional space, too.
3223  if (space_dim == 0) {
3224  return;
3225  }
3226  // We assume that `y' is contained in or equal to `*this'.
3227  PPL_EXPECT_HEAVY(copy_contains(*this, y));
3228 
3229  // If `*this' is empty, since `*this' contains `y', `y' is empty too.
3230  if (marked_empty()) {
3231  return;
3232  }
3233  // If `y' is empty, we return.
3234  if (y.marked_empty()) {
3235  return;
3236  }
3237  BD_Shape<T> limiting_shape(space_dim, UNIVERSE);
3238  get_limiting_shape(cs, limiting_shape);
3239  CC76_extrapolation_assign(y, tp);
3240  intersection_assign(limiting_shape);
3241 }
3242 
3243 template <typename T>
3244 void
3246  const dimension_type space_dim = space_dimension();
3247 
3248  // Dimension-compatibility check.
3249  if (space_dim != y.space_dimension()) {
3250  throw_dimension_incompatible("BHMZ05_widening_assign(y)", y);
3251  }
3252  // We assume that `y' is contained in or equal to `*this'.
3253  PPL_EXPECT_HEAVY(copy_contains(*this, y));
3254 
3255  // Compute the affine dimension of `y'.
3256  const dimension_type y_affine_dim = y.affine_dimension();
3257  // If the affine dimension of `y' is zero, then either `y' is
3258  // zero-dimensional, or it is empty, or it is a singleton.
3259  // In all cases, due to the inclusion hypothesis, the result is `*this'.
3260  if (y_affine_dim == 0) {
3261  return;
3262  }
3263  // If the affine dimension has changed, due to the inclusion hypothesis,
3264  // the result is `*this'.
3265  const dimension_type x_affine_dim = affine_dimension();
3266  PPL_ASSERT(x_affine_dim >= y_affine_dim);
3267  if (x_affine_dim != y_affine_dim) {
3268  return;
3269  }
3270  // If there are tokens available, work on a temporary copy.
3271  if (tp != 0 && *tp > 0) {
3272  BD_Shape<T> x_tmp(*this);
3273  x_tmp.BHMZ05_widening_assign(y, 0);
3274  // If the widening was not precise, use one of the available tokens.
3275  if (!contains(x_tmp)) {
3276  --(*tp);
3277  }
3278  return;
3279  }
3280 
3281  // Here no token is available.
3282  PPL_ASSERT(marked_shortest_path_closed() && y.marked_shortest_path_closed());
3283  // Minimize `y'.
3285 
3286  // Extrapolate unstable bounds, taking into account redundancy in `y'.
3287  for (dimension_type i = space_dim + 1; i-- > 0; ) {
3288  DB_Row<N>& dbm_i = dbm[i];
3289  const DB_Row<N>& y_dbm_i = y.dbm[i];
3290  const Bit_Row& y_redundancy_i = y.redundancy_dbm[i];
3291  for (dimension_type j = space_dim + 1; j-- > 0; ) {
3292  N& dbm_ij = dbm_i[j];
3293  // Note: in the following line the use of `!=' (as opposed to
3294  // the use of `<' that would seem -but is not- equivalent) is
3295  // intentional.
3296  if (y_redundancy_i[j] || y_dbm_i[j] != dbm_ij) {
3298  }
3299  }
3300  }
3301  // NOTE: this will also reset the shortest-path reduction flag,
3302  // even though the dbm is still in reduced form. However, the
3303  // current implementation invariant requires that any reduced dbm
3304  // is closed too.
3305  reset_shortest_path_closed();
3306  PPL_ASSERT(OK());
3307 }
3308 
3309 template <typename T>
3310 void
3312  const Constraint_System& cs,
3313  unsigned* tp) {
3314  // Dimension-compatibility check.
3315  const dimension_type space_dim = space_dimension();
3316  if (space_dim != y.space_dimension()) {
3317  throw_dimension_incompatible("limited_BHMZ05_extrapolation_assign(y, cs)",
3318  y);
3319  }
3320  // `cs' must be dimension-compatible with the two systems
3321  // of bounded differences.
3322  const dimension_type cs_space_dim = cs.space_dimension();
3323  if (space_dim < cs_space_dim) {
3324  throw_invalid_argument("limited_BHMZ05_extrapolation_assign(y, cs)",
3325  "cs is space-dimension incompatible");
3326  }
3327  // Strict inequalities are not allowed.
3328  if (cs.has_strict_inequalities()) {
3329  throw_invalid_argument("limited_BHMZ05_extrapolation_assign(y, cs)",
3330  "cs has strict inequalities");
3331  }
3332  // The limited BHMZ05-extrapolation between two systems of bounded
3333  // differences in a zero-dimensional space is a system of bounded
3334  // differences in a zero-dimensional space, too.
3335  if (space_dim == 0) {
3336  return;
3337  }
3338  // We assume that `y' is contained in or equal to `*this'.
3339  PPL_EXPECT_HEAVY(copy_contains(*this, y));
3340 
3341  // If `*this' is empty, since `*this' contains `y', `y' is empty too.
3342  if (marked_empty()) {
3343  return;
3344  }
3345  // If `y' is empty, we return.
3346  if (y.marked_empty()) {
3347  return;
3348  }
3349  BD_Shape<T> limiting_shape(space_dim, UNIVERSE);
3350  get_limiting_shape(cs, limiting_shape);
3351  BHMZ05_widening_assign(y, tp);
3352  intersection_assign(limiting_shape);
3353 }
3354 
3355 template <typename T>
3356 void
3358  const dimension_type space_dim = space_dimension();
3359 
3360  // Dimension-compatibility check.
3361  if (space_dim != y.space_dimension()) {
3362  throw_dimension_incompatible("CC76_narrowing_assign(y)", y);
3363  }
3364  // We assume that `*this' is contained in or equal to `y'.
3365  PPL_EXPECT_HEAVY(copy_contains(y, *this));
3366 
3367  // If both bounded difference shapes are zero-dimensional,
3368  // since `y' contains `*this', we simply return `*this'.
3369  if (space_dim == 0) {
3370  return;
3371  }
3373  // If `y' is empty, since `y' contains `this', `*this' is empty too.
3374  if (y.marked_empty()) {
3375  return;
3376  }
3377  shortest_path_closure_assign();
3378  // If `*this' is empty, we return.
3379  if (marked_empty()) {
3380  return;
3381  }
3382  // Replace each constraint in `*this' by the corresponding constraint
3383  // in `y' if the corresponding inhomogeneous terms are both finite.
3384  bool changed = false;
3385  for (dimension_type i = space_dim + 1; i-- > 0; ) {
3386  DB_Row<N>& dbm_i = dbm[i];
3387  const DB_Row<N>& y_dbm_i = y.dbm[i];
3388  for (dimension_type j = space_dim + 1; j-- > 0; ) {
3389  N& dbm_ij = dbm_i[j];
3390  const N& y_dbm_ij = y_dbm_i[j];
3391  if (!is_plus_infinity(dbm_ij)
3392  && !is_plus_infinity(y_dbm_ij)
3393  && dbm_ij != y_dbm_ij) {
3394  dbm_ij = y_dbm_ij;
3395  changed = true;
3396  }
3397  }
3398  }
3399  if (changed && marked_shortest_path_closed()) {
3400  reset_shortest_path_closed();
3401  }
3402  PPL_ASSERT(OK());
3403 }
3404 
3405 template <typename T>
3406 void
3409  const dimension_type last_v,
3410  const Linear_Expression& sc_expr,
3411  Coefficient_traits::const_reference sc_denom,
3412  const N& ub_v) {
3413  PPL_ASSERT(sc_denom > 0);
3414  PPL_ASSERT(!is_plus_infinity(ub_v));
3415  // Deduce constraints of the form `v - u', where `u != v'.
3416  // Note: the shortest-path closure is able to deduce the constraint
3417  // `v - u <= ub_v - lb_u'. We can be more precise if variable `u'
3418  // played an active role in the computation of the upper bound for `v',
3419  // i.e., if the corresponding coefficient `q == expr_u/denom' is
3420  // greater than zero. In particular:
3421  // if `q >= 1', then `v - u <= ub_v - ub_u';
3422  // if `0 < q < 1', then `v - u <= ub_v - (q*ub_u + (1-q)*lb_u)'.
3423  PPL_DIRTY_TEMP(mpq_class, mpq_sc_denom);
3424  assign_r(mpq_sc_denom, sc_denom, ROUND_NOT_NEEDED);
3425  const DB_Row<N>& dbm_0 = dbm[0];
3426  // Speculative allocation of temporaries to be used in the following loop.
3427  PPL_DIRTY_TEMP(mpq_class, minus_lb_u);
3428  PPL_DIRTY_TEMP(mpq_class, q);
3429  PPL_DIRTY_TEMP(mpq_class, ub_u);
3430  PPL_DIRTY_TEMP(N, up_approx);
3431  for (Linear_Expression::const_iterator u = sc_expr.begin(),
3432  u_end = sc_expr.lower_bound(Variable(last_v)); u != u_end; ++u) {
3433  const dimension_type u_dim = u.variable().space_dimension();
3434  if (u_dim == v) {
3435  continue;
3436  }
3437  const Coefficient& expr_u = *u;
3438  if (expr_u < 0) {
3439  continue;
3440  }
3441  PPL_ASSERT(expr_u > 0);
3442  if (expr_u >= sc_denom) {
3443  // Deducing `v - u <= ub_v - ub_u'.
3444  sub_assign_r(dbm[u_dim][v], ub_v, dbm_0[u_dim], ROUND_UP);
3445  }
3446  else {
3447  DB_Row<N>& dbm_u = dbm[u_dim];
3448  const N& dbm_u0 = dbm_u[0];
3449  if (!is_plus_infinity(dbm_u0)) {
3450  // Let `ub_u' and `lb_u' be the known upper and lower bound
3451  // for `u', respectively. Letting `q = expr_u/sc_denom' be the
3452  // rational coefficient of `u' in `sc_expr/sc_denom',
3453  // the upper bound for `v - u' is computed as
3454  // `ub_v - (q * ub_u + (1-q) * lb_u)', i.e.,
3455  // `ub_v + (-lb_u) - q * (ub_u + (-lb_u))'.
3456  assign_r(minus_lb_u, dbm_u0, ROUND_NOT_NEEDED);
3457  assign_r(q, expr_u, ROUND_NOT_NEEDED);
3458  div_assign_r(q, q, mpq_sc_denom, ROUND_NOT_NEEDED);
3459  assign_r(ub_u, dbm_0[u_dim], ROUND_NOT_NEEDED);
3460  // Compute `ub_u - lb_u'.
3461  add_assign_r(ub_u, ub_u, minus_lb_u, ROUND_NOT_NEEDED);
3462  // Compute `(-lb_u) - q * (ub_u - lb_u)'.
3463  sub_mul_assign_r(minus_lb_u, q, ub_u, ROUND_NOT_NEEDED);
3464  assign_r(up_approx, minus_lb_u, ROUND_UP);
3465  // Deducing `v - u <= ub_v - (q * ub_u + (1-q) * lb_u)'.
3466  add_assign_r(dbm_u[v], ub_v, up_approx, ROUND_UP);
3467  }
3468  }
3469  }
3470 }
3471 
3472 template <typename T>
3473 void
3476  const dimension_type last_v,
3477  const Linear_Expression& sc_expr,
3478  Coefficient_traits::const_reference sc_denom,
3479  const N& minus_lb_v) {
3480  PPL_ASSERT(sc_denom > 0);
3481  PPL_ASSERT(!is_plus_infinity(minus_lb_v));
3482  // Deduce constraints of the form `u - v', where `u != v'.
3483  // Note: the shortest-path closure is able to deduce the constraint
3484  // `u - v <= ub_u - lb_v'. We can be more precise if variable `u'
3485  // played an active role in the computation of the lower bound for `v',
3486  // i.e., if the corresponding coefficient `q == expr_u/denom' is
3487  // greater than zero. In particular:
3488  // if `q >= 1', then `u - v <= lb_u - lb_v';
3489  // if `0 < q < 1', then `u - v <= (q*lb_u + (1-q)*ub_u) - lb_v'.
3490  PPL_DIRTY_TEMP(mpq_class, mpq_sc_denom);
3491  assign_r(mpq_sc_denom, sc_denom, ROUND_NOT_NEEDED);
3492  DB_Row<N>& dbm_0 = dbm[0];
3493  DB_Row<N>& dbm_v = dbm[v];
3494  // Speculative allocation of temporaries to be used in the following loop.
3495  PPL_DIRTY_TEMP(mpq_class, ub_u);
3496  PPL_DIRTY_TEMP(mpq_class, q);
3497  PPL_DIRTY_TEMP(mpq_class, minus_lb_u);
3498  PPL_DIRTY_TEMP(N, up_approx);
3499  // No need to consider indices greater than `last_v'.
3500  for (Linear_Expression::const_iterator u = sc_expr.begin(),
3501  u_end = sc_expr.lower_bound(Variable(last_v)); u != u_end; ++u) {
3502  const Variable u_var = u.variable();
3503  const dimension_type u_dim = u_var.space_dimension();
3504  if (u_var.space_dimension() == v) {
3505  continue;
3506  }
3507  const Coefficient& expr_u = *u;
3508  if (expr_u < 0) {
3509  continue;
3510  }
3511  PPL_ASSERT(expr_u > 0);
3512  if (expr_u >= sc_denom) {
3513  // Deducing `u - v <= lb_u - lb_v',
3514  // i.e., `u - v <= (-lb_v) - (-lb_u)'.
3515  sub_assign_r(dbm_v[u_dim], minus_lb_v, dbm[u_dim][0], ROUND_UP);
3516  }
3517  else {
3518  const N& dbm_0u = dbm_0[u_dim];
3519  if (!is_plus_infinity(dbm_0u)) {
3520  // Let `ub_u' and `lb_u' be the known upper and lower bound
3521  // for `u', respectively. Letting `q = expr_u/sc_denom' be the
3522  // rational coefficient of `u' in `sc_expr/sc_denom',
3523  // the upper bound for `u - v' is computed as
3524  // `(q * lb_u + (1-q) * ub_u) - lb_v', i.e.,
3525  // `ub_u - q * (ub_u + (-lb_u)) + minus_lb_v'.
3526  assign_r(ub_u, dbm_0u, ROUND_NOT_NEEDED);
3527  assign_r(q, expr_u, ROUND_NOT_NEEDED);
3528  div_assign_r(q, q, mpq_sc_denom, ROUND_NOT_NEEDED);
3529  assign_r(minus_lb_u, dbm[u_dim][0], ROUND_NOT_NEEDED);
3530  // Compute `ub_u - lb_u'.
3531  add_assign_r(minus_lb_u, minus_lb_u, ub_u, ROUND_NOT_NEEDED);
3532  // Compute `ub_u - q * (ub_u - lb_u)'.
3533  sub_mul_assign_r(ub_u, q, minus_lb_u, ROUND_NOT_NEEDED);
3534  assign_r(up_approx, ub_u, ROUND_UP);
3535  // Deducing `u - v <= (q*lb_u + (1-q)*ub_u) - lb_v'.
3536  add_assign_r(dbm_v[u_dim], up_approx, minus_lb_v, ROUND_UP);
3537  }
3538  }
3539  }
3540 }
3541 
3542 template <typename T>
3543 void
3545  PPL_ASSERT(0 < v && v <= dbm.num_rows());
3546  DB_Row<N>& dbm_v = dbm[v];
3547  for (dimension_type i = dbm.num_rows(); i-- > 0; ) {
3550  }
3551 }
3552 
3553 template <typename T>
3554 void
3556  PPL_ASSERT(0 < v && v <= dbm.num_rows());
3557  DB_Row<N>& dbm_v = dbm[v];
3558  for (dimension_type i = dbm.num_rows()-1; i > 0; --i) {
3561  }
3562 }
3563 
3564 template <typename T>
3565 void
3567  // Dimension-compatibility check.
3568  const dimension_type var_space_dim = var.space_dimension();
3569  if (space_dimension() < var_space_dim) {
3570  throw_dimension_incompatible("unconstrain(var)", var_space_dim);
3571  }
3572  // Shortest-path closure is necessary to detect emptiness
3573  // and all (possibly implicit) constraints.
3574  shortest_path_closure_assign();
3575 
3576  // If the shape is empty, this is a no-op.
3577  if (marked_empty()) {
3578  return;
3579  }
3580  forget_all_dbm_constraints(var_space_dim);
3581  // Shortest-path closure is preserved, but not reduction.
3582  reset_shortest_path_reduced();
3583  PPL_ASSERT(OK());
3584 }
3585 
3586 template <typename T>
3587 void
3589  // The cylindrification with respect to no dimensions is a no-op.
3590  // This case captures the only legal cylindrification in a 0-dim space.
3591  if (vars.empty()) {
3592  return;
3593  }
3594  // Dimension-compatibility check.
3595  const dimension_type min_space_dim = vars.space_dimension();
3596  if (space_dimension() < min_space_dim) {
3597  throw_dimension_incompatible("unconstrain(vs)", min_space_dim);
3598  }
3599  // Shortest-path closure is necessary to detect emptiness
3600  // and all (possibly implicit) constraints.
3601  shortest_path_closure_assign();
3602 
3603  // If the shape is empty, this is a no-op.
3604  if (marked_empty()) {
3605  return;
3606  }
3607  for (Variables_Set::const_iterator vsi = vars.begin(),
3608  vsi_end = vars.end(); vsi != vsi_end; ++vsi) {
3609  forget_all_dbm_constraints(*vsi + 1);
3610  }
3611  // Shortest-path closure is preserved, but not reduction.
3612  reset_shortest_path_reduced();
3613  PPL_ASSERT(OK());
3614 }
3615 
3616 template <typename T>
3617 void
3619  const Relation_Symbol relsym,
3620  const Linear_Expression& expr,
3621  Coefficient_traits::const_reference denominator) {
3622  PPL_ASSERT(denominator != 0);
3623  PPL_ASSERT(space_dimension() >= expr.space_dimension());
3624  const dimension_type v = var.id() + 1;
3625  PPL_ASSERT(v <= space_dimension());
3626  PPL_ASSERT(expr.coefficient(var) == 0);
3627  PPL_ASSERT(relsym != LESS_THAN && relsym != GREATER_THAN);
3628 
3629  const Coefficient& b = expr.inhomogeneous_term();
3630  // Number of non-zero coefficients in `expr': will be set to
3631  // 0, 1, or 2, the latter value meaning any value greater than 1.
3632  dimension_type t = 0;
3633  // Index of the last non-zero coefficient in `expr', if any.
3634  dimension_type w = expr.last_nonzero();
3635 
3636  if (w != 0) {
3637  ++t;
3638  if (!expr.all_zeroes(1, w)) {
3639  ++t;
3640  }
3641  }
3642 
3643  // Since we are only able to record bounded differences, we can
3644  // precisely deal with the case of a single variable only if its
3645  // coefficient (taking into account the denominator) is 1.
3646  // If this is not the case, we fall back to the general case
3647  // so as to over-approximate the constraint.
3648  if (t == 1 && expr.get(Variable(w - 1)) != denominator) {
3649  t = 2;
3650  }
3651  // Now we know the form of `expr':
3652  // - If t == 0, then expr == b, with `b' a constant;
3653  // - If t == 1, then expr == a*w + b, where `w != v' and `a == denominator';
3654  // - If t == 2, the `expr' is of the general form.
3655  const DB_Row<N>& dbm_0 = dbm[0];
3656  PPL_DIRTY_TEMP_COEFFICIENT(minus_denom);
3657  neg_assign(minus_denom, denominator);
3658 
3659  if (t == 0) {
3660  // Case 1: expr == b.
3661  switch (relsym) {
3662  case EQUAL:
3663  // Add the constraint `var == b/denominator'.
3664  add_dbm_constraint(0, v, b, denominator);
3665  add_dbm_constraint(v, 0, b, minus_denom);
3666  break;
3667  case LESS_OR_EQUAL:
3668  // Add the constraint `var <= b/denominator'.
3669  add_dbm_constraint(0, v, b, denominator);
3670  break;
3671  case GREATER_OR_EQUAL:
3672  // Add the constraint `var >= b/denominator',
3673  // i.e., `-var <= -b/denominator',
3674  add_dbm_constraint(v, 0, b, minus_denom);
3675  break;
3676  default:
3677  // We already dealt with the other cases.
3678  PPL_UNREACHABLE;
3679  break;
3680  }
3681  return;
3682  }
3683 
3684  if (t == 1) {
3685  // Case 2: expr == a*w + b, w != v, a == denominator.
3686  PPL_ASSERT(expr.get(Variable(w - 1)) == denominator);
3687  PPL_DIRTY_TEMP(N, d);
3688  switch (relsym) {
3689  case EQUAL:
3690  // Add the new constraint `v - w <= b/denominator'.
3691  div_round_up(d, b, denominator);
3692  add_dbm_constraint(w, v, d);
3693  // Add the new constraint `v - w >= b/denominator',
3694  // i.e., `w - v <= -b/denominator'.
3695  div_round_up(d, b, minus_denom);
3696  add_dbm_constraint(v, w, d);
3697  break;
3698  case LESS_OR_EQUAL:
3699  // Add the new constraint `v - w <= b/denominator'.
3700  div_round_up(d, b, denominator);
3701  add_dbm_constraint(w, v, d);
3702  break;
3703  case GREATER_OR_EQUAL:
3704  // Add the new constraint `v - w >= b/denominator',
3705  // i.e., `w - v <= -b/denominator'.
3706  div_round_up(d, b, minus_denom);
3707  add_dbm_constraint(v, w, d);
3708  break;
3709  default:
3710  // We already dealt with the other cases.
3711  PPL_UNREACHABLE;
3712  break;
3713  }
3714  return;
3715  }
3716 
3717  // Here t == 2, so that either
3718  // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2, or
3719  // expr == a*w + b, w != v and a != denominator.
3720  const bool is_sc = (denominator > 0);
3721  PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
3722  neg_assign(minus_b, b);
3723  const Coefficient& sc_b = is_sc ? b : minus_b;
3724  const Coefficient& minus_sc_b = is_sc ? minus_b : b;
3725  const Coefficient& sc_denom = is_sc ? denominator : minus_denom;
3726  const Coefficient& minus_sc_denom = is_sc ? minus_denom : denominator;
3727  // NOTE: here, for optimization purposes, `minus_expr' is only assigned
3728  // when `denominator' is negative. Do not use it unless you are sure
3729  // it has been correctly assigned.
3730  Linear_Expression minus_expr;
3731  if (!is_sc) {
3732  minus_expr = -expr;
3733  }
3734  const Linear_Expression& sc_expr = is_sc ? expr : minus_expr;
3735 
3736  PPL_DIRTY_TEMP(N, sum);
3737  // Indices of the variables that are unbounded in `this->dbm'.
3738  PPL_UNINITIALIZED(dimension_type, pinf_index);
3739  // Number of unbounded variables found.
3740  dimension_type pinf_count = 0;
3741 
3742  // Speculative allocation of temporaries that are used in most
3743  // of the computational traces starting from this point (also loops).
3744  PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
3745  PPL_DIRTY_TEMP(N, coeff_i);
3746 
3747  switch (relsym) {
3748  case EQUAL:
3749  {
3750  PPL_DIRTY_TEMP(N, neg_sum);
3751  // Indices of the variables that are unbounded in `this->dbm'.
3752  PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
3753  // Number of unbounded variables found.
3754  dimension_type neg_pinf_count = 0;
3755 
3756  // Compute an upper approximation for `expr' into `sum',
3757  // taking into account the sign of `denominator'.
3758 
3759  // Approximate the inhomogeneous term.
3760  assign_r(sum, sc_b, ROUND_UP);
3761  assign_r(neg_sum, minus_sc_b, ROUND_UP);
3762 
3763  // Approximate the homogeneous part of `sc_expr'.
3764  // Note: indices above `w' can be disregarded, as they all have
3765  // a zero coefficient in `expr'.
3766  for (Linear_Expression::const_iterator i = sc_expr.begin(),
3767  i_end = sc_expr.lower_bound(Variable(w)); i != i_end; ++i) {
3768  const dimension_type i_dim = i.variable().space_dimension();
3769  const Coefficient& sc_i = *i;
3770  const int sign_i = sgn(sc_i);
3771  PPL_ASSERT(sign_i != 0);
3772  if (sign_i > 0) {
3773  assign_r(coeff_i, sc_i, ROUND_UP);
3774  // Approximating `sc_expr'.
3775  if (pinf_count <= 1) {
3776  const N& approx_i = dbm_0[i_dim];
3777  if (!is_plus_infinity(approx_i)) {
3778  add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
3779  }
3780  else {
3781  ++pinf_count;
3782  pinf_index = i_dim;
3783  }
3784  }
3785  // Approximating `-sc_expr'.
3786  if (neg_pinf_count <= 1) {
3787  const N& approx_minus_i = dbm[i_dim][0];
3788  if (!is_plus_infinity(approx_minus_i)) {
3789  add_mul_assign_r(neg_sum, coeff_i, approx_minus_i, ROUND_UP);
3790  }
3791  else {
3792  ++neg_pinf_count;
3793  neg_pinf_index = i_dim;
3794  }
3795  }
3796  }
3797  else {
3798  PPL_ASSERT(sign_i < 0);
3799  neg_assign(minus_sc_i, sc_i);
3800  // Note: using temporary named `coeff_i' to store -coeff_i.
3801  assign_r(coeff_i, minus_sc_i, ROUND_UP);
3802  // Approximating `sc_expr'.
3803  if (pinf_count <= 1) {
3804  const N& approx_minus_i = dbm[i_dim][0];
3805  if (!is_plus_infinity(approx_minus_i)) {
3806  add_mul_assign_r(sum, coeff_i, approx_minus_i, ROUND_UP);
3807  }
3808  else {
3809  ++pinf_count;
3810  pinf_index = i_dim;
3811  }
3812  }
3813  // Approximating `-sc_expr'.
3814  if (neg_pinf_count <= 1) {
3815  const N& approx_i = dbm_0[i_dim];
3816  if (!is_plus_infinity(approx_i)) {
3817  add_mul_assign_r(neg_sum, coeff_i, approx_i, ROUND_UP);
3818  }
3819  else {
3820  ++neg_pinf_count;
3821  neg_pinf_index = i_dim;
3822  }
3823  }
3824  }
3825  }
3826  // Return immediately if no approximation could be computed.
3827  if (pinf_count > 1 && neg_pinf_count > 1) {
3828  PPL_ASSERT(OK());
3829  return;
3830  }
3831 
3832  // In the following, shortest-path closure will be definitely lost.
3833  reset_shortest_path_closed();
3834 
3835  // Before computing quotients, the denominator should be approximated
3836  // towards zero. Since `sc_denom' is known to be positive, this amounts to
3837  // rounding downwards, which is achieved as usual by rounding upwards
3838  // `minus_sc_denom' and negating again the result.
3839  PPL_DIRTY_TEMP(N, down_sc_denom);
3840  assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
3841  neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
3842 
3843  // Exploit the upper approximation, if possible.
3844  if (pinf_count <= 1) {
3845  // Compute quotient (if needed).
3846  if (down_sc_denom != 1) {
3847  div_assign_r(sum, sum, down_sc_denom, ROUND_UP);
3848  }
3849  // Add the upper bound constraint, if meaningful.
3850  if (pinf_count == 0) {
3851  // Add the constraint `v <= sum'.
3852  dbm[0][v] = sum;
3853  // Deduce constraints of the form `v - u', where `u != v'.
3854  deduce_v_minus_u_bounds(v, w, sc_expr, sc_denom, sum);
3855  }
3856  else {
3857  // Here `pinf_count == 1'.
3858  if (pinf_index != v
3859  && sc_expr.get(Variable(pinf_index - 1)) == sc_denom) {
3860  // Add the constraint `v - pinf_index <= sum'.
3861  dbm[pinf_index][v] = sum;
3862  }
3863  }
3864  }
3865 
3866  // Exploit the lower approximation, if possible.
3867  if (neg_pinf_count <= 1) {
3868  // Compute quotient (if needed).
3869  if (down_sc_denom != 1) {
3870  div_assign_r(neg_sum, neg_sum, down_sc_denom, ROUND_UP);
3871  }
3872  // Add the lower bound constraint, if meaningful.
3873  if (neg_pinf_count == 0) {
3874  // Add the constraint `v >= -neg_sum', i.e., `-v <= neg_sum'.
3875  DB_Row<N>& dbm_v = dbm[v];
3876  dbm_v[0] = neg_sum;
3877  // Deduce constraints of the form `u - v', where `u != v'.
3878  deduce_u_minus_v_bounds(v, w, sc_expr, sc_denom, neg_sum);
3879  }
3880  // Here `neg_pinf_count == 1'.
3881  else if (neg_pinf_index != v
3882  && sc_expr.get(Variable(neg_pinf_index - 1)) == sc_denom) {
3883  // Add the constraint `v - neg_pinf_index >= -neg_sum',
3884  // i.e., `neg_pinf_index - v <= neg_sum'.
3885  dbm[v][neg_pinf_index] = neg_sum;
3886  }
3887  }
3888  }
3889  break;
3890 
3891  case LESS_OR_EQUAL:
3892  // Compute an upper approximation for `expr' into `sum',
3893  // taking into account the sign of `denominator'.
3894 
3895  // Approximate the inhomogeneous term.
3896  assign_r(sum, sc_b, ROUND_UP);
3897 
3898  // Approximate the homogeneous part of `sc_expr'.
3899  // Note: indices above `w' can be disregarded, as they all have
3900  // a zero coefficient in `expr'.
3901  for (Linear_Expression::const_iterator i = sc_expr.begin(),
3902  i_end = sc_expr.lower_bound(Variable(w)); i != i_end; ++i) {
3903  const Coefficient& sc_i = *i;
3904  const dimension_type i_dim = i.variable().space_dimension();
3905  const int sign_i = sgn(sc_i);
3906  PPL_ASSERT(sign_i != 0);
3907  // Choose carefully: we are approximating `sc_expr'.
3908  const N& approx_i = (sign_i > 0) ? dbm_0[i_dim] : dbm[i_dim][0];
3909  if (is_plus_infinity(approx_i)) {
3910  if (++pinf_count > 1) {
3911  break;
3912  }
3913  pinf_index = i_dim;
3914  continue;
3915  }
3916  if (sign_i > 0) {
3917  assign_r(coeff_i, sc_i, ROUND_UP);
3918  }
3919  else {
3920  neg_assign(minus_sc_i, sc_i);
3921  assign_r(coeff_i, minus_sc_i, ROUND_UP);
3922  }
3923  add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
3924  }
3925 
3926  // Divide by the (sign corrected) denominator (if needed).
3927  if (sc_denom != 1) {
3928  // Before computing the quotient, the denominator should be
3929  // approximated towards zero. Since `sc_denom' is known to be
3930  // positive, this amounts to rounding downwards, which is achieved
3931  // by rounding upwards `minus_sc - denom' and negating again the result.
3932  PPL_DIRTY_TEMP(N, down_sc_denom);
3933  assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
3934  neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
3935  div_assign_r(sum, sum, down_sc_denom, ROUND_UP);
3936  }
3937 
3938  if (pinf_count == 0) {
3939  // Add the constraint `v <= sum'.
3940  add_dbm_constraint(0, v, sum);
3941  // Deduce constraints of the form `v - u', where `u != v'.
3942  deduce_v_minus_u_bounds(v, w, sc_expr, sc_denom, sum);
3943  }
3944  else if (pinf_count == 1) {
3945  if (expr.get(Variable(pinf_index - 1)) == denominator) {
3946  // Add the constraint `v - pinf_index <= sum'.
3947  add_dbm_constraint(pinf_index, v, sum);
3948  }
3949  }
3950  break;
3951 
3952  case GREATER_OR_EQUAL:
3953  // Compute an upper approximation for `-sc_expr' into `sum'.
3954  // Note: approximating `-sc_expr' from above and then negating the
3955  // result is the same as approximating `sc_expr' from below.
3956 
3957  // Approximate the inhomogeneous term.
3958  assign_r(sum, minus_sc_b, ROUND_UP);
3959 
3960  // Approximate the homogeneous part of `-sc_expr'.
3961  for (Linear_Expression::const_iterator i = sc_expr.begin(),
3962  i_end = sc_expr.lower_bound(Variable(w)); i != i_end; ++i) {
3963  const Coefficient& sc_i = *i;
3964  const dimension_type i_dim = i.variable().space_dimension();
3965  const int sign_i = sgn(sc_i);
3966  PPL_ASSERT(sign_i != 0);
3967  // Choose carefully: we are approximating `-sc_expr'.
3968  const N& approx_i = (sign_i > 0) ? dbm[i_dim][0] : dbm_0[i_dim];
3969  if (is_plus_infinity(approx_i)) {
3970  if (++pinf_count > 1) {
3971  break;
3972  }
3973  pinf_index = i_dim;
3974  continue;
3975  }
3976  if (sign_i > 0) {
3977  assign_r(coeff_i, sc_i, ROUND_UP);
3978  }
3979  else {
3980  neg_assign(minus_sc_i, sc_i);
3981  assign_r(coeff_i, minus_sc_i, ROUND_UP);
3982  }
3983  add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
3984  }
3985 
3986  // Divide by the (sign corrected) denominator (if needed).
3987  if (sc_denom != 1) {
3988  // Before computing the quotient, the denominator should be
3989  // approximated towards zero. Since `sc_denom' is known to be positive,
3990  // this amounts to rounding downwards, which is achieved by rounding
3991  // upwards `minus_sc_denom' and negating again the result.
3992  PPL_DIRTY_TEMP(N, down_sc_denom);
3993  assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
3994  neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
3995  div_assign_r(sum, sum, down_sc_denom, ROUND_UP);
3996  }
3997 
3998  if (pinf_count == 0) {
3999  // Add the constraint `v >= -sum', i.e., `-v <= sum'.
4000  add_dbm_constraint(v, 0, sum);
4001  // Deduce constraints of the form `u - v', where `u != v'.
4002  deduce_u_minus_v_bounds(v, w, sc_expr, sc_denom, sum);
4003  }
4004  else if (pinf_count == 1) {
4005  if (pinf_index != v
4006  && expr.get(Variable(pinf_index - 1)) == denominator) {
4007  // Add the constraint `v - pinf_index >= -sum',
4008  // i.e., `pinf_index - v <= sum'.
4009  add_dbm_constraint(v, pinf_index, sum);
4010  }
4011  }
4012  break;
4013 
4014  default:
4015  // We already dealt with the other cases.
4016  PPL_UNREACHABLE;
4017  break;
4018  }
4019 
4020  PPL_ASSERT(OK());
4021 }
4022 
4023 template <typename T>
4024 void
4026  const Linear_Expression& expr,
4027  Coefficient_traits::const_reference denominator) {
4028  // The denominator cannot be zero.
4029  if (denominator == 0) {
4030  throw_invalid_argument("affine_image(v, e, d)", "d == 0");
4031  }
4032  // Dimension-compatibility checks.
4033  // The dimension of `expr' should not be greater than the dimension
4034  // of `*this'.
4035  const dimension_type space_dim = space_dimension();
4036  const dimension_type expr_space_dim = expr.space_dimension();
4037  if (space_dim < expr_space_dim) {
4038  throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
4039  }
4040  // `var' should be one of the dimensions of the shape.
4041  const dimension_type v = var.id() + 1;
4042  if (v > space_dim) {
4043  throw_dimension_incompatible("affine_image(v, e, d)", var.id());
4044  }
4045  // The image of an empty BDS is empty too.
4046  shortest_path_closure_assign();
4047  if (marked_empty()) {
4048  return;
4049  }
4050  const Coefficient& b = expr.inhomogeneous_term();
4051  // Number of non-zero coefficients in `expr': will be set to
4052  // 0, 1, or 2, the latter value meaning any value greater than 1.
4053  dimension_type t = 0;
4054  // Index of the last non-zero coefficient in `expr', if any.
4055  dimension_type w = expr.last_nonzero();
4056 
4057  if (w != 0) {
4058  ++t;
4059  if (!expr.all_zeroes(1, w)) {
4060  ++t;
4061  }
4062  }
4063 
4064  // Now we know the form of `expr':
4065  // - If t == 0, then expr == b, with `b' a constant;
4066  // - If t == 1, then expr == a*w + b, where `w' can be `v' or another
4067  // variable; in this second case we have to check whether `a' is
4068  // equal to `denominator' or `-denominator', since otherwise we have
4069  // to fall back on the general form;
4070  // - If t == 2, the `expr' is of the general form.
4071  PPL_DIRTY_TEMP_COEFFICIENT(minus_denom);
4072  neg_assign(minus_denom, denominator);
4073 
4074  if (t == 0) {
4075  // Case 1: expr == b.
4076  // Remove all constraints on `var'.
4077  forget_all_dbm_constraints(v);
4078  // Shortest-path closure is preserved, but not reduction.
4079  if (marked_shortest_path_reduced()) {
4080  reset_shortest_path_reduced();
4081  }
4082  // Add the constraint `var == b/denominator'.
4083  add_dbm_constraint(0, v, b, denominator);
4084  add_dbm_constraint(v, 0, b, minus_denom);
4085  PPL_ASSERT(OK());
4086  return;
4087  }
4088 
4089  if (t == 1) {
4090  // Value of the one and only non-zero coefficient in `expr'.
4091  const Coefficient& a = expr.get(Variable(w - 1));
4092  if (a == denominator || a == minus_denom) {
4093  // Case 2: expr == a*w + b, with a == +/- denominator.
4094  if (w == v) {
4095  // `expr' is of the form: a*v + b.
4096  if (a == denominator) {
4097  if (b == 0) {
4098  // The transformation is the identity function.
4099  return;
4100  }
4101  else {
4102  // Translate all the constraints on `var',
4103  // adding or subtracting the value `b/denominator'.
4104  PPL_DIRTY_TEMP(N, d);
4105  div_round_up(d, b, denominator);
4106  PPL_DIRTY_TEMP(N, c);
4107  div_round_up(c, b, minus_denom);
4108  DB_Row<N>& dbm_v = dbm[v];
4109  for (dimension_type i = space_dim + 1; i-- > 0; ) {
4110  N& dbm_vi = dbm_v[i];
4111  add_assign_r(dbm_vi, dbm_vi, c, ROUND_UP);
4112  N& dbm_iv = dbm[i][v];
4113  add_assign_r(dbm_iv, dbm_iv, d, ROUND_UP);
4114  }
4115  // Both shortest-path closure and reduction are preserved.
4116  }
4117  }
4118  else {
4119  // Here `a == -denominator'.
4120  // Remove the binary constraints on `var'.
4121  forget_binary_dbm_constraints(v);
4122  // Swap the unary constraints on `var'.
4123  using std::swap;
4124  swap(dbm[v][0], dbm[0][v]);
4125  // Shortest-path closure is not preserved.
4126  reset_shortest_path_closed();
4127  if (b != 0) {
4128  // Translate the unary constraints on `var',
4129  // adding or subtracting the value `b/denominator'.
4130  PPL_DIRTY_TEMP(N, c);
4131  div_round_up(c, b, minus_denom);
4132  N& dbm_v0 = dbm[v][0];
4133  add_assign_r(dbm_v0, dbm_v0, c, ROUND_UP);
4134  PPL_DIRTY_TEMP(N, d);
4135  div_round_up(d, b, denominator);
4136  N& dbm_0v = dbm[0][v];
4137  add_assign_r(dbm_0v, dbm_0v, d, ROUND_UP);
4138  }
4139  }
4140  }
4141  else {
4142  // Here `w != v', so that `expr' is of the form
4143  // +/-denominator * w + b.
4144  // Remove all constraints on `var'.
4145  forget_all_dbm_constraints(v);
4146  // Shortest-path closure is preserved, but not reduction.
4147  if (marked_shortest_path_reduced()) {
4148  reset_shortest_path_reduced();
4149  }
4150  if (a == denominator) {
4151  // Add the new constraint `v - w == b/denominator'.
4152  add_dbm_constraint(w, v, b, denominator);
4153  add_dbm_constraint(v, w, b, minus_denom);
4154  }
4155  else {
4156  // Here a == -denominator, so that we should be adding
4157  // the constraint `v + w == b/denominator'.
4158  // Approximate it by computing lower and upper bounds for `w'.
4159  const N& dbm_w0 = dbm[w][0];
4160  if (!is_plus_infinity(dbm_w0)) {
4161  // Add the constraint `v <= b/denominator - lower_w'.
4162  PPL_DIRTY_TEMP(N, d);
4163  div_round_up(d, b, denominator);
4164  add_assign_r(dbm[0][v], d, dbm_w0, ROUND_UP);
4165  reset_shortest_path_closed();
4166  }
4167  const N& dbm_0w = dbm[0][w];
4168  if (!is_plus_infinity(dbm_0w)) {
4169  // Add the constraint `v >= b/denominator - upper_w'.
4170  PPL_DIRTY_TEMP(N, c);
4171  div_round_up(c, b, minus_denom);
4172  add_assign_r(dbm[v][0], dbm_0w, c, ROUND_UP);
4173  reset_shortest_path_closed();
4174  }
4175  }
4176  }
4177  PPL_ASSERT(OK());
4178  return;
4179  }
4180  }
4181 
4182  // General case.
4183  // Either t == 2, so that
4184  // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2,
4185  // or t == 1, expr == a*w + b, but a <> +/- denominator.
4186  // We will remove all the constraints on `var' and add back
4187  // constraints providing upper and lower bounds for `var'.
4188 
4189  // Compute upper approximations for `expr' and `-expr'
4190  // into `pos_sum' and `neg_sum', respectively, taking into account
4191  // the sign of `denominator'.
4192  // Note: approximating `-expr' from above and then negating the
4193  // result is the same as approximating `expr' from below.
4194  const bool is_sc = (denominator > 0);
4195  PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
4196  neg_assign(minus_b, b);
4197  const Coefficient& sc_b = is_sc ? b : minus_b;
4198  const Coefficient& minus_sc_b = is_sc ? minus_b : b;
4199  const Coefficient& sc_denom = is_sc ? denominator : minus_denom;
4200  const Coefficient& minus_sc_denom = is_sc ? minus_denom : denominator;
4201  // NOTE: here, for optimization purposes, `minus_expr' is only assigned
4202  // when `denominator' is negative. Do not use it unless you are sure
4203  // it has been correctly assigned.
4204  Linear_Expression minus_expr;
4205  if (!is_sc) {
4206  minus_expr = -expr;
4207  }
4208  const Linear_Expression& sc_expr = is_sc ? expr : minus_expr;
4209 
4210  PPL_DIRTY_TEMP(N, pos_sum);
4211  PPL_DIRTY_TEMP(N, neg_sum);
4212  // Indices of the variables that are unbounded in `this->dbm'.
4213  PPL_UNINITIALIZED(dimension_type, pos_pinf_index);
4214  PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
4215  // Number of unbounded variables found.
4216  dimension_type pos_pinf_count = 0;
4217  dimension_type neg_pinf_count = 0;
4218 
4219  // Approximate the inhomogeneous term.
4220  assign_r(pos_sum, sc_b, ROUND_UP);
4221  assign_r(neg_sum, minus_sc_b, ROUND_UP);
4222 
4223  // Approximate the homogeneous part of `sc_expr'.
4224  const DB_Row<N>& dbm_0 = dbm[0];
4225  // Speculative allocation of temporaries to be used in the following loop.
4226  PPL_DIRTY_TEMP(N, coeff_i);
4227  PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
4228 
4229  // Note: indices above `w' can be disregarded, as they all have
4230  // a zero coefficient in `sc_expr'.
4231  for (Linear_Expression::const_iterator i = sc_expr.begin(),
4232  i_end = sc_expr.lower_bound(Variable(w)); i != i_end; ++i) {
4233  const Coefficient& sc_i = *i;
4234  const dimension_type i_dim = i.variable().space_dimension();
4235  const int sign_i = sgn(sc_i);
4236  if (sign_i > 0) {
4237  assign_r(coeff_i, sc_i, ROUND_UP);
4238  // Approximating `sc_expr'.
4239  if (pos_pinf_count <= 1) {
4240  const N& up_approx_i = dbm_0[i_dim];
4241  if (!is_plus_infinity(up_approx_i)) {
4242  add_mul_assign_r(pos_sum, coeff_i, up_approx_i, ROUND_UP);
4243  }
4244  else {
4245  ++pos_pinf_count;
4246  pos_pinf_index = i_dim;
4247  }
4248  }
4249  // Approximating `-sc_expr'.
4250  if (neg_pinf_count <= 1) {
4251  const N& up_approx_minus_i = dbm[i_dim][0];
4252  if (!is_plus_infinity(up_approx_minus_i)) {
4253  add_mul_assign_r(neg_sum, coeff_i, up_approx_minus_i, ROUND_UP);
4254  }
4255  else {
4256  ++neg_pinf_count;
4257  neg_pinf_index = i_dim;
4258  }
4259  }
4260  }
4261  else {
4262  PPL_ASSERT(sign_i < 0);
4263  neg_assign(minus_sc_i, sc_i);
4264  // Note: using temporary named `coeff_i' to store -coeff_i.
4265  assign_r(coeff_i, minus_sc_i, ROUND_UP);
4266  // Approximating `sc_expr'.
4267  if (pos_pinf_count <= 1) {
4268  const N& up_approx_minus_i = dbm[i_dim][0];
4269  if (!is_plus_infinity(up_approx_minus_i)) {
4270  add_mul_assign_r(pos_sum, coeff_i, up_approx_minus_i, ROUND_UP);
4271  }
4272  else {
4273  ++pos_pinf_count;
4274  pos_pinf_index = i_dim;
4275  }
4276  }
4277  // Approximating `-sc_expr'.
4278  if (neg_pinf_count <= 1) {
4279  const N& up_approx_i = dbm_0[i_dim];
4280  if (!is_plus_infinity(up_approx_i)) {
4281  add_mul_assign_r(neg_sum, coeff_i, up_approx_i, ROUND_UP);
4282  }
4283  else {
4284  ++neg_pinf_count;
4285  neg_pinf_index = i_dim;
4286  }
4287  }
4288  }
4289  }
4290 
4291  // Remove all constraints on 'v'.
4292  forget_all_dbm_constraints(v);
4293  // Shortest-path closure is maintained, but not reduction.
4294  if (marked_shortest_path_reduced()) {
4295  reset_shortest_path_reduced();
4296  }
4297  // Return immediately if no approximation could be computed.
4298  if (pos_pinf_count > 1 && neg_pinf_count > 1) {
4299  PPL_ASSERT(OK());
4300  return;
4301  }
4302 
4303  // In the following, shortest-path closure will be definitely lost.
4304  reset_shortest_path_closed();
4305 
4306  // Exploit the upper approximation, if possible.
4307  if (pos_pinf_count <= 1) {
4308  // Compute quotient (if needed).
4309  if (sc_denom != 1) {
4310  // Before computing quotients, the denominator should be approximated
4311  // towards zero. Since `sc_denom' is known to be positive, this amounts to
4312  // rounding downwards, which is achieved as usual by rounding upwards
4313  // `minus_sc_denom' and negating again the result.
4314  PPL_DIRTY_TEMP(N, down_sc_denom);
4315  assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
4316  neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
4317  div_assign_r(pos_sum, pos_sum, down_sc_denom, ROUND_UP);
4318  }
4319  // Add the upper bound constraint, if meaningful.
4320  if (pos_pinf_count == 0) {
4321  // Add the constraint `v <= pos_sum'.
4322  dbm[0][v] = pos_sum;
4323  // Deduce constraints of the form `v - u', where `u != v'.
4324  deduce_v_minus_u_bounds(v, w, sc_expr, sc_denom, pos_sum);
4325  } // Here `pos_pinf_count == 1'.
4326  else if (pos_pinf_index != v
4327  && sc_expr.get(Variable(pos_pinf_index - 1)) == sc_denom) {
4328  // Add the constraint `v - pos_pinf_index <= pos_sum'.
4329  dbm[pos_pinf_index][v] = pos_sum;
4330  }
4331  }
4332 
4333  // Exploit the lower approximation, if possible.
4334  if (neg_pinf_count <= 1) {
4335  // Compute quotient (if needed).
4336  if (sc_denom != 1) {
4337  // Before computing quotients, the denominator should be approximated
4338  // towards zero. Since `sc_denom' is known to be positive, this amounts to
4339  // rounding downwards, which is achieved as usual by rounding upwards
4340  // `minus_sc_denom' and negating again the result.
4341  PPL_DIRTY_TEMP(N, down_sc_denom);
4342  assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
4343  neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
4344  div_assign_r(neg_sum, neg_sum, down_sc_denom, ROUND_UP);
4345  }
4346  // Add the lower bound constraint, if meaningful.
4347  if (neg_pinf_count == 0) {
4348  // Add the constraint `v >= -neg_sum', i.e., `-v <= neg_sum'.
4349  DB_Row<N>& dbm_v = dbm[v];
4350  dbm_v[0] = neg_sum;
4351  // Deduce constraints of the form `u - v', where `u != v'.
4352  deduce_u_minus_v_bounds(v, w, sc_expr, sc_denom, neg_sum);
4353  }
4354  // Here `neg_pinf_count == 1'.
4355  else if (neg_pinf_index != v
4356  && sc_expr.get(Variable(neg_pinf_index - 1)) == sc_denom) {
4357  // Add the constraint `v - neg_pinf_index >= -neg_sum',
4358  // i.e., `neg_pinf_index - v <= neg_sum'.
4359  dbm[v][neg_pinf_index] = neg_sum;
4360  }
4361  }
4362 
4363  PPL_ASSERT(OK());
4364 }
4365 
4366 template <typename T>
4367 template <typename Interval_Info>
4368 void
4370  const Linear_Form< Interval<T, Interval_Info> >& lf) {
4371 
4372  // Check that T is a floating point type.
4373  PPL_COMPILE_TIME_CHECK(!std::numeric_limits<T>::is_exact,
4374  "BD_Shape<T>::affine_form_image(Variable, Linear_Form):"
4375  " T not a floating point type.");
4376 
4377  // Dimension-compatibility checks.
4378  // The dimension of `lf' should not be greater than the dimension
4379  // of `*this'.
4380  const dimension_type space_dim = space_dimension();
4381  const dimension_type lf_space_dim = lf.space_dimension();
4382  if (space_dim < lf_space_dim) {
4383  throw_dimension_incompatible("affine_form_image(var_id, l)", "l", lf);
4384  }
4385  // `var' should be one of the dimensions of the shape.
4386  const dimension_type var_id = var.id() + 1;
4387  if (space_dim < var_id) {
4388  throw_dimension_incompatible("affine_form_image(var_id, l)", var.id());
4389  }
4390  // The image of an empty BDS is empty too.
4391  shortest_path_closure_assign();
4392  if (marked_empty()) {
4393  return;
4394  }
4395  // Number of non-zero coefficients in `lf': will be set to
4396  // 0, 1, or 2, the latter value meaning any value greater than 1.
4397  dimension_type t = 0;
4398  // Index of the last non-zero coefficient in `lf', if any.
4399  dimension_type w_id = 0;
4400  // Get information about the number of non-zero coefficients in `lf'.
4401  for (dimension_type i = lf_space_dim; i-- > 0; ) {
4402  if (lf.coefficient(Variable(i)) != 0) {
4403  if (t++ == 1) {
4404  break;
4405  }
4406  else {
4407  w_id = i + 1;
4408  }
4409  }
4410  }
4411  typedef Interval<T, Interval_Info> FP_Interval_Type;
4412 
4413  const FP_Interval_Type& b = lf.inhomogeneous_term();
4414 
4415  // Now we know the form of `lf':
4416  // - If t == 0, then lf == b, with `b' a constant;
4417  // - If t == 1, then lf == a*w + b, where `w' can be `v' or another
4418  // variable;
4419  // - If t == 2, the linear form 'lf' is of the general form.
4420 
4421  if (t == 0) {
4422  inhomogeneous_affine_form_image(var_id, b);
4423  PPL_ASSERT(OK());
4424  return;
4425  }
4426  else if (t == 1) {
4427  const FP_Interval_Type& w_coeff = lf.coefficient(Variable(w_id - 1));
4428  if (w_coeff == 1 || w_coeff == -1) {
4429  one_variable_affine_form_image(var_id, b, w_coeff, w_id, space_dim);
4430  PPL_ASSERT(OK());
4431  return;
4432  }
4433  }
4434  two_variables_affine_form_image(var_id, lf, space_dim);
4435  PPL_ASSERT(OK());
4436 }
4437 
4438 // Case 1: var = b, where b = [-b_mlb, b_ub]
4439 template <typename T>
4440 template <typename Interval_Info>
4441 void
4444  const Interval<T, Interval_Info>& b) {
4445  PPL_DIRTY_TEMP(N, b_ub);
4446  assign_r(b_ub, b.upper(), ROUND_NOT_NEEDED);
4447  PPL_DIRTY_TEMP(N, b_mlb);
4448  neg_assign_r(b_mlb, b.lower(), ROUND_NOT_NEEDED);
4449 
4450  // Remove all constraints on `var'.
4451  forget_all_dbm_constraints(var_id);
4452  // Shortest-path closure is preserved, but not reduction.
4453  if (marked_shortest_path_reduced()) {
4454  reset_shortest_path_reduced();
4455  }
4456  // Add the constraint `var >= lb && var <= ub'.
4457  add_dbm_constraint(0, var_id, b_ub);
4458  add_dbm_constraint(var_id, 0, b_mlb);
4459  return;
4460 }
4461 
4462 // case 2: var = (+/-1) * w + [-b_mlb, b_ub], where `w' can be `var'
4463 // or another variable.
4464 template <typename T>
4465 template <typename Interval_Info>
4466 void BD_Shape<T>
4468  const Interval<T, Interval_Info>& b,
4469  const Interval<T, Interval_Info>& w_coeff,
4470  const dimension_type& w_id,
4471  const dimension_type& space_dim) {
4472 
4473  PPL_DIRTY_TEMP(N, b_ub);
4474  assign_r(b_ub, b.upper(), ROUND_NOT_NEEDED);
4475  PPL_DIRTY_TEMP(N, b_mlb);
4476  neg_assign_r(b_mlb, b.lower(), ROUND_NOT_NEEDED);
4477 
4478  // True if `w_coeff' is in [1, 1].
4479  bool is_w_coeff_one = (w_coeff == 1);
4480 
4481  if (w_id == var_id) {
4482  // True if `b' is in [b_mlb, b_ub] and that is [0, 0].
4483  bool is_b_zero = (b_mlb == 0 && b_ub == 0);
4484  // Here `lf' is of the form: [+/-1, +/-1] * v + b.
4485  if (is_w_coeff_one) {
4486  if (is_b_zero) {
4487  // The transformation is the identity function.
4488  return;
4489  }
4490  else {
4491  // Translate all the constraints on `var' by adding the value
4492  // `b_ub' or subtracting the value `b_mlb'.
4493  DB_Row<N>& dbm_v = dbm[var_id];
4494  for (dimension_type i = space_dim + 1; i-- > 0; ) {
4495  N& dbm_vi = dbm_v[i];
4496  add_assign_r(dbm_vi, dbm_vi, b_mlb, ROUND_UP);
4497  N& dbm_iv = dbm[i][var_id];
4498  add_assign_r(dbm_iv, dbm_iv, b_ub, ROUND_UP);
4499  }
4500  // Both shortest-path closure and reduction are preserved.
4501  }
4502  }
4503  else {
4504  // Here `w_coeff = [-1, -1].
4505  // Remove the binary constraints on `var'.
4506  forget_binary_dbm_constraints(var_id);
4507  using std::swap;
4508  swap(dbm[var_id][0], dbm[0][var_id]);
4509  // Shortest-path closure is not preserved.
4510  reset_shortest_path_closed();
4511  if (!is_b_zero) {
4512  // Translate the unary constraints on `var' by adding the value
4513  // `b_ub' or subtracting the value `b_mlb'.
4514  N& dbm_v0 = dbm[var_id][0];
4515  add_assign_r(dbm_v0, dbm_v0, b_mlb, ROUND_UP);
4516  N& dbm_0v = dbm[0][var_id];
4517  add_assign_r(dbm_0v, dbm_0v, b_ub, ROUND_UP);
4518  }
4519  }
4520  }
4521  else {
4522  // Here `w != var', so that `lf' is of the form
4523  // [+/-1, +/-1] * w + b.
4524  // Remove all constraints on `var'.
4525  forget_all_dbm_constraints(var_id);
4526  // Shortest-path closure is preserved, but not reduction.
4527  if (marked_shortest_path_reduced()) {
4528  reset_shortest_path_reduced();
4529  }
4530  if (is_w_coeff_one) {
4531  // Add the new constraints `var - w >= b_mlb'
4532  // `and var - w <= b_ub'.
4533  add_dbm_constraint(w_id, var_id, b_ub);
4534  add_dbm_constraint(var_id, w_id, b_mlb);
4535  }
4536  else {
4537  // We have to add the constraint `v + w == b', over-approximating it
4538  // by computing lower and upper bounds for `w'.
4539  const N& mlb_w = dbm[w_id][0];
4540  if (!is_plus_infinity(mlb_w)) {
4541  // Add the constraint `v <= ub - lb_w'.
4542  add_assign_r(dbm[0][var_id], b_ub, mlb_w, ROUND_UP);
4543  reset_shortest_path_closed();
4544  }
4545  const N& ub_w = dbm[0][w_id];
4546  if (!is_plus_infinity(ub_w)) {
4547  // Add the constraint `v >= lb - ub_w'.
4548  add_assign_r(dbm[var_id][0], ub_w, b_mlb, ROUND_UP);
4549  reset_shortest_path_closed();
4550  }
4551  }
4552  }
4553  return;
4554 }
4555 
4556 // General case.
4557 // Either t == 2, so that
4558 // lf == i_1*x_1 + i_2*x_2 + ... + i_n*x_n + b, where n >= 2,
4559 // or t == 1, lf == i*w + b, but i <> [+/-1, +/-1].
4560 template <typename T>
4561 template <typename Interval_Info>
4562 void BD_Shape<T>
4565  const dimension_type& space_dim) {
4566  // Shortest-path closure is maintained, but not reduction.
4567  if (marked_shortest_path_reduced()) {
4568  reset_shortest_path_reduced();
4569  }
4570  reset_shortest_path_closed();
4571 
4573  minus_lf.negate();
4574 
4575  // Declare temporaries outside the loop.
4576  PPL_DIRTY_TEMP(N, upper_bound);
4577 
4578  // Update binary constraints on var FIRST.
4579  for (dimension_type curr_var = 1; curr_var < var_id; ++curr_var) {
4580  Variable current(curr_var - 1);
4581  linear_form_upper_bound(lf - current, upper_bound);
4582  assign_r(dbm[curr_var][var_id], upper_bound, ROUND_NOT_NEEDED);
4583  linear_form_upper_bound(minus_lf + current, upper_bound);
4584  assign_r(dbm[var_id][curr_var], upper_bound, ROUND_NOT_NEEDED);
4585  }
4586  for (dimension_type curr_var = var_id + 1; curr_var <= space_dim;
4587  ++curr_var) {
4588  Variable current(curr_var - 1);
4589  linear_form_upper_bound(lf - current, upper_bound);
4590  assign_r(dbm[curr_var][var_id], upper_bound, ROUND_NOT_NEEDED);
4591  linear_form_upper_bound(minus_lf + current, upper_bound);
4592  assign_r(dbm[var_id][curr_var], upper_bound, ROUND_NOT_NEEDED);
4593  }
4594  // Finally, update unary constraints on var.
4595  PPL_DIRTY_TEMP(N, lf_ub);
4596  linear_form_upper_bound(lf, lf_ub);
4597  PPL_DIRTY_TEMP(N, minus_lf_ub);
4598  linear_form_upper_bound(minus_lf, minus_lf_ub);
4599  assign_r(dbm[0][var_id], lf_ub, ROUND_NOT_NEEDED);
4600  assign_r(dbm[var_id][0], minus_lf_ub, ROUND_NOT_NEEDED);
4601 }
4602 
4603 template <typename T>
4604 template <typename Interval_Info>
4606  const Linear_Form< Interval<T, Interval_Info> >& left,
4607  const Linear_Form< Interval<T, Interval_Info> >& right) {
4608  // Check that T is a floating point type.
4609  PPL_COMPILE_TIME_CHECK(!std::numeric_limits<T>::is_exact,
4610  "Octagonal_Shape<T>::refine_with_linear_form_inequality:"
4611  " T not a floating point type.");
4612 
4613  //We assume that the analyzer will not try to apply an unreachable filter.
4614  PPL_ASSERT(!marked_empty());
4615 
4616  // Dimension-compatibility checks.
4617  // The dimensions of `left' and `right' should not be greater than the
4618  // dimension of `*this'.
4619  const dimension_type left_space_dim = left.space_dimension();
4620  const dimension_type space_dim = space_dimension();
4621  if (space_dim < left_space_dim) {
4622  throw_dimension_incompatible(
4623  "refine_with_linear_form_inequality(left, right)", "left", left);
4624  }
4625  const dimension_type right_space_dim = right.space_dimension();
4626  if (space_dim < right_space_dim) {
4627  throw_dimension_incompatible(
4628  "refine_with_linear_form_inequality(left, right)", "right", right);
4629  }
4630  // Number of non-zero coefficients in `left': will be set to
4631  // 0, 1, or 2, the latter value meaning any value greater than 1.
4632  dimension_type left_t = 0;
4633  // Variable-index of the last non-zero coefficient in `left', if any.
4634  dimension_type left_w_id = 0;
4635  // Number of non-zero coefficients in `right': will be set to
4636  // 0, 1, or 2, the latter value meaning any value greater than 1.
4637  dimension_type right_t = 0;
4638  // Variable-index of the last non-zero coefficient in `right', if any.
4639  dimension_type right_w_id = 0;
4640 
4641  typedef Interval<T, Interval_Info> FP_Interval_Type;
4642 
4643  // Get information about the number of non-zero coefficients in `left'.
4644  for (dimension_type i = left_space_dim; i-- > 0; ) {
4645  if (left.coefficient(Variable(i)) != 0) {
4646  if (left_t++ == 1) {
4647  break;
4648  }
4649  else {
4650  left_w_id = i;
4651  }
4652  }
4653  }
4654 
4655  // Get information about the number of non-zero coefficients in `right'.
4656  for (dimension_type i = right_space_dim; i-- > 0; ) {
4657  if (right.coefficient(Variable(i)) != 0) {
4658  if (right_t++ == 1) {
4659  break;
4660  }
4661  else {
4662  right_w_id = i;
4663  }
4664  }
4665  }
4666 
4667  const FP_Interval_Type& left_w_coeff =
4668  left.coefficient(Variable(left_w_id));
4669  const FP_Interval_Type& right_w_coeff =
4670  right.coefficient(Variable(right_w_id));
4671 
4672  if (left_t == 0) {
4673  if (right_t == 0) {
4674  // The constraint involves constants only. Ignore it: it is up to
4675  // the analyzer to handle it.
4676  PPL_ASSERT(OK());
4677  return;
4678  }
4679  else if (right_w_coeff == 1 || right_w_coeff == -1) {
4680  left_inhomogeneous_refine(right_t, right_w_id, left, right);
4681  PPL_ASSERT(OK());
4682  return;
4683  }
4684  }
4685  else if (left_t == 1) {
4686  if (left_w_coeff == 1 || left_w_coeff == -1) {
4687  if (right_t == 0 || (right_w_coeff == 1 || right_w_coeff == -1)) {
4688  left_one_var_refine(left_w_id, right_t, right_w_id, left, right);
4689  PPL_ASSERT(OK());
4690  return;
4691  }
4692  }
4693  }
4694 
4695  // General case.
4696  general_refine(left_w_id, right_w_id, left, right);
4697  PPL_ASSERT(OK());
4698 } // end of refine_with_linear_form_inequality
4699 
4700 template <typename T>
4701 template <typename U>
4702 void
4705  const dimension_type space_dim = space_dimension();
4706  if (space_dim > dest.space_dimension()) {
4707  throw std::invalid_argument(
4708  "BD_Shape<T>::export_interval_constraints");
4709  }
4710 
4711  // Expose all the interval constraints.
4712  shortest_path_closure_assign();
4713 
4714  if (marked_empty()) {
4715  dest.set_empty();
4716  PPL_ASSERT(OK());
4717  return;
4718  }
4719 
4720  PPL_DIRTY_TEMP(N, tmp);
4721  const DB_Row<N>& dbm_0 = dbm[0];
4722  for (dimension_type i = space_dim; i-- > 0; ) {
4723  // Set the upper bound.
4724  const N& u = dbm_0[i+1];
4725  if (!is_plus_infinity(u)) {
4726  if (!dest.restrict_upper(i, u.raw_value())) {
4727  return;
4728  }
4729  }
4730  // Set the lower bound.
4731  const N& negated_l = dbm[i+1][0];
4732  if (!is_plus_infinity(negated_l)) {
4733  neg_assign_r(tmp, negated_l, ROUND_DOWN);
4734  if (!dest.restrict_lower(i, tmp.raw_value())) {
4735  return;
4736  }
4737  }
4738  }
4739 
4740  PPL_ASSERT(OK());
4741 }
4742 
4743 template <typename T>
4744 template <typename Interval_Info>
4745 void
4747  const dimension_type& right_w_id,
4748  const Linear_Form< Interval<T, Interval_Info> >& left,
4749  const Linear_Form< Interval<T, Interval_Info> >& right) {
4750 
4751  typedef Interval<T, Interval_Info> FP_Interval_Type;
4752 
4753  if (right_t == 1) {
4754  // The constraint has the form [a-, a+] <= [b-, b+] + [c-, c+] * x.
4755  // Reduce it to the constraint +/-x <= b+ - a- if [c-, c+] = +/-[1, 1].
4756  const FP_Interval_Type& right_w_coeff =
4757  right.coefficient(Variable(right_w_id));
4758  if (right_w_coeff == 1) {
4759  PPL_DIRTY_TEMP(N, b_plus_minus_a_minus);
4760  const FP_Interval_Type& left_a = left.inhomogeneous_term();
4761  const FP_Interval_Type& right_b = right.inhomogeneous_term();
4762  sub_assign_r(b_plus_minus_a_minus, right_b.upper(), left_a.lower(),
4763  ROUND_UP);
4764  add_dbm_constraint(right_w_id+1, 0, b_plus_minus_a_minus);
4765  return;
4766  }
4767 
4768  if (right_w_coeff == -1) {
4769  PPL_DIRTY_TEMP(N, b_plus_minus_a_minus);
4770  const FP_Interval_Type& left_a = left.inhomogeneous_term();
4771  const FP_Interval_Type& right_b = right.inhomogeneous_term();
4772  sub_assign_r(b_plus_minus_a_minus, right_b.upper(), left_a.lower(),
4773  ROUND_UP);
4774  add_dbm_constraint(0, right_w_id+1, b_plus_minus_a_minus);
4775  return;
4776  }
4777  }
4778 } // end of left_inhomogeneous_refine
4779 
4780 
4781 template <typename T>
4782 template <typename Interval_Info>
4783 void
4786  const dimension_type& right_t,
4787  const dimension_type& right_w_id,
4788  const Linear_Form< Interval<T, Interval_Info> >& left,
4789  const Linear_Form< Interval<T, Interval_Info> >& right) {
4790 
4791  typedef Interval<T, Interval_Info> FP_Interval_Type;
4792 
4793  if (right_t == 0) {
4794  // The constraint has the form [b-, b+] + [c-, c+] * x <= [a-, a+]
4795  // Reduce it to the constraint +/-x <= a+ - b- if [c-, c+] = +/-[1, 1].
4796  const FP_Interval_Type& left_w_coeff =
4797  left.coefficient(Variable(left_w_id));
4798 
4799  if (left_w_coeff == 1) {
4800  PPL_DIRTY_TEMP(N, a_plus_minus_b_minus);
4801  const FP_Interval_Type& left_b = left.inhomogeneous_term();
4802  const FP_Interval_Type& right_a = right.inhomogeneous_term();
4803  sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(),
4804  ROUND_UP);
4805  add_dbm_constraint(0, left_w_id+1, a_plus_minus_b_minus);
4806  return;
4807  }
4808 
4809  if (left_w_coeff == -1) {
4810  PPL_DIRTY_TEMP(N, a_plus_minus_b_minus);
4811  const FP_Interval_Type& left_b = left.inhomogeneous_term();
4812  const FP_Interval_Type& right_a = right.inhomogeneous_term();
4813  sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(),
4814  ROUND_UP);
4815  add_dbm_constraint(left_w_id+1, 0, a_plus_minus_b_minus);
4816  return;
4817  }
4818  }
4819  else if (right_t == 1) {
4820  // The constraint has the form
4821  // [a-, a+] + [b-, b+] * x <= [c-, c+] + [d-, d+] * y.
4822  // Reduce it to the constraint +/-x +/-y <= c+ - a-
4823  // if [b-, b+] = +/-[1, 1] and [d-, d+] = +/-[1, 1].
4824  const FP_Interval_Type& left_w_coeff =
4825  left.coefficient(Variable(left_w_id));
4826 
4827  const FP_Interval_Type& right_w_coeff =
4828  right.coefficient(Variable(right_w_id));
4829 
4830  bool is_left_coeff_one = (left_w_coeff == 1);
4831  bool is_left_coeff_minus_one = (left_w_coeff == -1);
4832  bool is_right_coeff_one = (right_w_coeff == 1);
4833  bool is_right_coeff_minus_one = (right_w_coeff == -1);
4834  if (left_w_id == right_w_id) {
4835  if ((is_left_coeff_one && is_right_coeff_one)
4836  ||
4837  (is_left_coeff_minus_one && is_right_coeff_minus_one)) {
4838  // Here we have an identity or a constants-only constraint.
4839  return;
4840  }
4841  if (is_left_coeff_one && is_right_coeff_minus_one) {
4842  // We fall back to a previous case.
4843  PPL_DIRTY_TEMP(N, a_plus_minus_b_minus);
4844  const FP_Interval_Type& left_b = left.inhomogeneous_term();
4845  const FP_Interval_Type& right_a = right.inhomogeneous_term();
4846  sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(),
4847  ROUND_UP);
4848  div_2exp_assign_r(a_plus_minus_b_minus, a_plus_minus_b_minus, 1,
4849  ROUND_UP);
4850  add_dbm_constraint(0, left_w_id + 1, a_plus_minus_b_minus);
4851  return;
4852  }
4853  if (is_left_coeff_minus_one && is_right_coeff_one) {
4854  // We fall back to a previous case.
4855  PPL_DIRTY_TEMP(N, a_plus_minus_b_minus);
4856  const FP_Interval_Type& left_b = left.inhomogeneous_term();
4857  const FP_Interval_Type& right_a = right.inhomogeneous_term();
4858  sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(),
4859  ROUND_UP);
4860  div_2exp_assign_r(a_plus_minus_b_minus, a_plus_minus_b_minus, 1,
4861  ROUND_UP);
4862  add_dbm_constraint(right_w_id + 1, 0, a_plus_minus_b_minus);
4863  return;
4864  }
4865  }
4866  else if (is_left_coeff_minus_one && is_right_coeff_one) {
4867  // over-approximate (if is it possible) the inequality
4868  // -B + [b1, b2] <= A + [a1, a2] by adding the constraints
4869  // -B <= upper_bound(A) + (a2 - b1) and
4870  // -A <= upper_bound(B) + (a2 - b1)
4871  PPL_DIRTY_TEMP(N, a_plus_minus_b_minus);
4872  const FP_Interval_Type& left_b = left.inhomogeneous_term();
4873  const FP_Interval_Type& right_a = right.inhomogeneous_term();
4874  sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(),
4875  ROUND_UP);
4876  PPL_DIRTY_TEMP(N, ub);
4877  ub = dbm[0][right_w_id + 1];
4878  if (!is_plus_infinity(ub)) {
4879  add_assign_r(ub, ub, a_plus_minus_b_minus, ROUND_UP);
4880  add_dbm_constraint(left_w_id + 1, 0, ub);
4881  }
4882  ub = dbm[0][left_w_id + 1];
4883  if (!is_plus_infinity(ub)) {
4884  add_assign_r(ub, ub, a_plus_minus_b_minus, ROUND_UP);
4885  add_dbm_constraint(right_w_id + 1, 0, ub);
4886  }
4887  return;
4888  }
4889  if (is_left_coeff_one && is_right_coeff_minus_one) {
4890  // over-approximate (if is it possible) the inequality
4891  // B + [b1, b2] <= -A + [a1, a2] by adding the constraints
4892  // B <= upper_bound(-A) + (a2 - b1) and
4893  // A <= upper_bound(-B) + (a2 - b1)
4894  PPL_DIRTY_TEMP(N, a_plus_minus_b_minus);
4895  const FP_Interval_Type& left_b = left.inhomogeneous_term();
4896  const FP_Interval_Type& right_a = right.inhomogeneous_term();
4897  sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(),
4898  ROUND_UP);
4899  PPL_DIRTY_TEMP(N, ub);
4900  ub = dbm[right_w_id + 1][0];
4901  if (!is_plus_infinity(ub)) {
4902  add_assign_r(ub, ub, a_plus_minus_b_minus, ROUND_UP);
4903  add_dbm_constraint(0, left_w_id + 1, ub);
4904  }
4905  ub = dbm[left_w_id + 1][0];
4906  if (!is_plus_infinity(ub)) {
4907  add_assign_r(ub, ub, a_plus_minus_b_minus, ROUND_UP);
4908  add_dbm_constraint(0, right_w_id + 1, ub);
4909  }
4910  return;
4911  }
4912  if (is_left_coeff_one && is_right_coeff_one) {
4913  PPL_DIRTY_TEMP(N, c_plus_minus_a_minus);
4914  const FP_Interval_Type& left_a = left.inhomogeneous_term();
4915  const FP_Interval_Type& right_c = right.inhomogeneous_term();
4916  sub_assign_r(c_plus_minus_a_minus, right_c.upper(), left_a.lower(),
4917  ROUND_UP);
4918  add_dbm_constraint(right_w_id+1, left_w_id+1, c_plus_minus_a_minus);
4919  return;
4920  }
4921  if (is_left_coeff_minus_one && is_right_coeff_minus_one) {
4922  PPL_DIRTY_TEMP(N, c_plus_minus_a_minus);
4923  const FP_Interval_Type& left_a = left.inhomogeneous_term();
4924  const FP_Interval_Type& right_c = right.inhomogeneous_term();
4925  sub_assign_r(c_plus_minus_a_minus, right_c.upper(), left_a.lower(),
4926  ROUND_UP);
4927  add_dbm_constraint(left_w_id+1, right_w_id+1, c_plus_minus_a_minus);
4928  return;
4929  }
4930  }
4931 }
4932 
4933 template <typename T>
4934 template <typename Interval_Info>
4935 void
4938  const dimension_type& right_w_id,
4939  const Linear_Form< Interval<T, Interval_Info> >& left,
4940  const Linear_Form< Interval<T, Interval_Info> >& right) {
4941 
4942  typedef Interval<T, Interval_Info> FP_Interval_Type;
4943  Linear_Form<FP_Interval_Type> right_minus_left(right);
4944  right_minus_left -= left;
4945 
4946  // Declare temporaries outside of the loop.
4947  PPL_DIRTY_TEMP(N, low_coeff);
4948  PPL_DIRTY_TEMP(N, high_coeff);
4949  PPL_DIRTY_TEMP(N, upper_bound);
4950 
4951  dimension_type max_w_id = std::max(left_w_id, right_w_id);
4952 
4953  for (dimension_type first_v = 0; first_v < max_w_id; ++first_v) {
4954  for (dimension_type second_v = first_v+1;
4955  second_v <= max_w_id; ++second_v) {
4956  const FP_Interval_Type& lfv_coefficient =
4957  left.coefficient(Variable(first_v));
4958  const FP_Interval_Type& lsv_coefficient =
4959  left.coefficient(Variable(second_v));
4960  const FP_Interval_Type& rfv_coefficient =
4961  right.coefficient(Variable(first_v));
4962  const FP_Interval_Type& rsv_coefficient =
4963  right.coefficient(Variable(second_v));
4964  // We update the constraints only when both variables appear in at
4965  // least one argument.
4966  bool do_update = false;
4967  assign_r(low_coeff, lfv_coefficient.lower(), ROUND_NOT_NEEDED);
4968  assign_r(high_coeff, lfv_coefficient.upper(), ROUND_NOT_NEEDED);
4969  if (low_coeff != 0 || high_coeff != 0) {
4970  assign_r(low_coeff, lsv_coefficient.lower(), ROUND_NOT_NEEDED);
4971  assign_r(high_coeff, lsv_coefficient.upper(), ROUND_NOT_NEEDED);
4972  if (low_coeff != 0 || high_coeff != 0) {
4973  do_update = true;
4974  }
4975  else {
4976  assign_r(low_coeff, rsv_coefficient.lower(), ROUND_NOT_NEEDED);
4977  assign_r(high_coeff, rsv_coefficient.upper(), ROUND_NOT_NEEDED);
4978  if (low_coeff != 0 || high_coeff != 0) {
4979  do_update = true;
4980  }
4981  }
4982  }
4983  else {
4984  assign_r(low_coeff, rfv_coefficient.lower(), ROUND_NOT_NEEDED);
4985  assign_r(high_coeff, rfv_coefficient.upper(), ROUND_NOT_NEEDED);
4986  if (low_coeff != 0 || high_coeff != 0) {
4987  assign_r(low_coeff, lsv_coefficient.lower(), ROUND_NOT_NEEDED);
4988  assign_r(high_coeff, lsv_coefficient.upper(), ROUND_NOT_NEEDED);
4989  if (low_coeff != 0 || high_coeff != 0) {
4990  do_update = true;
4991  }
4992  else {
4993  assign_r(low_coeff, rsv_coefficient.lower(), ROUND_NOT_NEEDED);
4994  assign_r(high_coeff, rsv_coefficient.upper(), ROUND_NOT_NEEDED);
4995  if (low_coeff != 0 || high_coeff != 0) {
4996  do_update = true;
4997  }
4998  }
4999  }
5000  }
5001 
5002  if (do_update) {
5003  Variable first(first_v);
5004  Variable second(second_v);
5005  dimension_type n_first_var = first_v +1 ;
5006  dimension_type n_second_var = second_v + 1;
5007  linear_form_upper_bound(right_minus_left - first + second,
5008  upper_bound);
5009  add_dbm_constraint(n_first_var, n_second_var, upper_bound);
5010  linear_form_upper_bound(right_minus_left + first - second,
5011  upper_bound);
5012  add_dbm_constraint(n_second_var, n_first_var, upper_bound);
5013  }
5014  }
5015  }
5016 
5017  // Finally, update the unary constraints.
5018  for (dimension_type v = 0; v < max_w_id; ++v) {
5019  const FP_Interval_Type& lv_coefficient =
5020  left.coefficient(Variable(v));
5021  const FP_Interval_Type& rv_coefficient =
5022  right.coefficient(Variable(v));
5023  // We update the constraints only if v appears in at least one of the
5024  // two arguments.
5025  bool do_update = false;
5026  assign_r(low_coeff, lv_coefficient.lower(), ROUND_NOT_NEEDED);
5027  assign_r(high_coeff, lv_coefficient.upper(), ROUND_NOT_NEEDED);
5028  if (low_coeff != 0 || high_coeff != 0) {
5029  do_update = true;
5030  }
5031  else {
5032  assign_r(low_coeff, rv_coefficient.lower(), ROUND_NOT_NEEDED);
5033  assign_r(high_coeff, rv_coefficient.upper(), ROUND_NOT_NEEDED);
5034  if (low_coeff != 0 || high_coeff != 0) {
5035  do_update = true;
5036  }
5037  }
5038 
5039  if (do_update) {
5040  Variable var(v);
5041  dimension_type n_var = v + 1;
5042  linear_form_upper_bound(right_minus_left + var, upper_bound);
5043  add_dbm_constraint(0, n_var, upper_bound);
5044  linear_form_upper_bound(right_minus_left - var, upper_bound);
5045  add_dbm_constraint(n_var, 0, upper_bound);
5046  }
5047  }
5048 
5049 }
5050 
5051 template <typename T>
5052 template <typename Interval_Info>
5053 void
5056  N& result) const {
5057 
5058  // Check that T is a floating point type.
5059  PPL_COMPILE_TIME_CHECK(!std::numeric_limits<T>::is_exact,
5060  "BD_Shape<T>::linear_form_upper_bound:"
5061  " T not a floating point type.");
5062 
5063  const dimension_type lf_space_dimension = lf.space_dimension();
5064  PPL_ASSERT(lf_space_dimension <= space_dimension());
5065 
5066  typedef Interval<T, Interval_Info> FP_Interval_Type;
5067 
5068  PPL_DIRTY_TEMP(N, curr_lb);
5069  PPL_DIRTY_TEMP(N, curr_ub);
5070  PPL_DIRTY_TEMP(N, curr_var_ub);
5071  PPL_DIRTY_TEMP(N, curr_minus_var_ub);
5072 
5073  PPL_DIRTY_TEMP(N, first_comparison_term);
5074  PPL_DIRTY_TEMP(N, second_comparison_term);
5075 
5076  PPL_DIRTY_TEMP(N, negator);
5077 
5078  assign_r(result, lf.inhomogeneous_term().upper(), ROUND_NOT_NEEDED);
5079 
5080  for (dimension_type curr_var = 0, n_var = 0; curr_var < lf_space_dimension;
5081  ++curr_var) {
5082  n_var = curr_var + 1;
5083  const FP_Interval_Type&
5084  curr_coefficient = lf.coefficient(Variable(curr_var));
5085  assign_r(curr_lb, curr_coefficient.lower(), ROUND_NOT_NEEDED);
5086  assign_r(curr_ub, curr_coefficient.upper(), ROUND_NOT_NEEDED);
5087  if (curr_lb != 0 || curr_ub != 0) {
5088  assign_r(curr_var_ub, dbm[0][n_var], ROUND_NOT_NEEDED);
5089  neg_assign_r(curr_minus_var_ub, dbm[n_var][0], ROUND_NOT_NEEDED);
5090  // Optimize the most commons cases: curr = +/-[1, 1].
5091  if (curr_lb == 1 && curr_ub == 1) {
5092  add_assign_r(result, result, std::max(curr_var_ub, curr_minus_var_ub),
5093  ROUND_UP);
5094  }
5095  else if (curr_lb == -1 && curr_ub == -1) {
5096  neg_assign_r(negator, std::min(curr_var_ub, curr_minus_var_ub),
5098  add_assign_r(result, result, negator, ROUND_UP);
5099  }
5100  else {
5101  // Next addend will be the maximum of four quantities.
5102  assign_r(first_comparison_term, 0, ROUND_NOT_NEEDED);
5103  assign_r(second_comparison_term, 0, ROUND_NOT_NEEDED);
5104  add_mul_assign_r(first_comparison_term, curr_var_ub, curr_ub,
5105  ROUND_UP);
5106  add_mul_assign_r(second_comparison_term, curr_var_ub, curr_lb,
5107  ROUND_UP);
5108  assign_r(first_comparison_term, std::max(first_comparison_term,
5109  second_comparison_term),
5111  assign_r(second_comparison_term, 0, ROUND_NOT_NEEDED);
5112  add_mul_assign_r(second_comparison_term, curr_minus_var_ub, curr_ub,
5113  ROUND_UP);
5114  assign_r(first_comparison_term, std::max(first_comparison_term,
5115  second_comparison_term),
5117  assign_r(second_comparison_term, 0, ROUND_NOT_NEEDED);
5118  add_mul_assign_r(second_comparison_term, curr_minus_var_ub, curr_lb,
5119  ROUND_UP);
5120  assign_r(first_comparison_term, std::max(first_comparison_term,
5121  second_comparison_term),
5123 
5124  add_assign_r(result, result, first_comparison_term, ROUND_UP);
5125  }
5126  }
5127  }
5128 }
5129 
5130 template <typename T>
5131 void
5133  const Linear_Expression& expr,
5134  Coefficient_traits::const_reference denominator) {
5135  // The denominator cannot be zero.
5136  if (denominator == 0) {
5137  throw_invalid_argument("affine_preimage(v, e, d)", "d == 0");
5138  }
5139  // Dimension-compatibility checks.
5140  // The dimension of `expr' should not be greater than the dimension
5141  // of `*this'.
5142  const dimension_type space_dim = space_dimension();
5143  const dimension_type expr_space_dim = expr.space_dimension();
5144  if (space_dim < expr_space_dim) {
5145  throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
5146  }
5147  // `var' should be one of the dimensions of
5148  // the bounded difference shapes.
5149  const dimension_type v = var.id() + 1;
5150  if (v > space_dim) {
5151  throw_dimension_incompatible("affine_preimage(v, e, d)", var.id());
5152  }
5153  // The image of an empty BDS is empty too.
5154  shortest_path_closure_assign();
5155  if (marked_empty()) {
5156  return;
5157  }
5158  const Coefficient& b = expr.inhomogeneous_term();
5159  // Number of non-zero coefficients in `expr': will be set to
5160  // 0, 1, or 2, the latter value meaning any value greater than 1.
5161  dimension_type t = 0;
5162  // Index of the last non-zero coefficient in `expr', if any.
5163  dimension_type j = expr.last_nonzero();
5164 
5165  if (j != 0) {
5166  ++t;
5167  if (!expr.all_zeroes(1, j)) {
5168  ++t;
5169  }
5170  }
5171 
5172  // Now we know the form of `expr':
5173  // - If t == 0, then expr = b, with `b' a constant;
5174  // - If t == 1, then expr = a*w + b, where `w' can be `v' or another
5175  // variable; in this second case we have to check whether `a' is
5176  // equal to `denominator' or `-denominator', since otherwise we have
5177  // to fall back on the general form;
5178  // - If t > 1, the `expr' is of the general form.
5179  if (t == 0) {
5180  // Case 1: expr = n; remove all constraints on `var'.
5181  forget_all_dbm_constraints(v);
5182  // Shortest-path closure is preserved, but not reduction.
5183  if (marked_shortest_path_reduced()) {
5184  reset_shortest_path_reduced();
5185  }
5186  PPL_ASSERT(OK());
5187  return;
5188  }
5189 
5190  if (t == 1) {
5191  // Value of the one and only non-zero coefficient in `expr'.
5192  const Coefficient& a = expr.get(Variable(j - 1));
5193  if (a == denominator || a == -denominator) {
5194  // Case 2: expr = a*w + b, with a = +/- denominator.
5195  if (j == var.space_dimension()) {
5196  // Apply affine_image() on the inverse of this transformation.
5197  affine_image(var, denominator*var - b, a);
5198  }
5199  else {
5200  // `expr == a*w + b', where `w != v'.
5201  // Remove all constraints on `var'.
5202  forget_all_dbm_constraints(v);
5203  // Shortest-path closure is preserved, but not reduction.
5204  if (marked_shortest_path_reduced()) {
5205  reset_shortest_path_reduced();
5206  }
5207  PPL_ASSERT(OK());
5208  }
5209  return;
5210  }
5211  }
5212 
5213  // General case.
5214  // Either t == 2, so that
5215  // expr = a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2,
5216  // or t = 1, expr = a*w + b, but a <> +/- denominator.
5217  const Coefficient& expr_v = expr.coefficient(var);
5218  if (expr_v != 0) {
5219  // The transformation is invertible.
5220  Linear_Expression inverse((expr_v + denominator)*var);
5221  inverse -= expr;
5222  affine_image(var, inverse, expr_v);
5223  }
5224  else {
5225  // Transformation not invertible: all constraints on `var' are lost.
5226  forget_all_dbm_constraints(v);
5227  // Shortest-path closure is preserved, but not reduction.
5228  if (marked_shortest_path_reduced()) {
5229  reset_shortest_path_reduced();
5230  }
5231  }
5232  PPL_ASSERT(OK());
5233 }
5234 
5235 template <typename T>
5236 void
5239  const Linear_Expression& lb_expr,
5240  const Linear_Expression& ub_expr,
5241  Coefficient_traits::const_reference denominator) {
5242  // The denominator cannot be zero.
5243  if (denominator == 0) {
5244  throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0");
5245  }
5246  // Dimension-compatibility checks.
5247  // `var' should be one of the dimensions of the BD_Shape.
5248  const dimension_type bds_space_dim = space_dimension();
5249  const dimension_type v = var.id() + 1;
5250  if (v > bds_space_dim) {
5251  throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
5252  "v", var);
5253  }
5254  // The dimension of `lb_expr' and `ub_expr' should not be
5255  // greater than the dimension of `*this'.
5256  const dimension_type lb_space_dim = lb_expr.space_dimension();
5257  if (bds_space_dim < lb_space_dim) {
5258  throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
5259  "lb", lb_expr);
5260  }
5261  const dimension_type ub_space_dim = ub_expr.space_dimension();
5262  if (bds_space_dim < ub_space_dim) {
5263  throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
5264  "ub", ub_expr);
5265  }
5266  // Any image of an empty BDS is empty.
5267  shortest_path_closure_assign();
5268  if (marked_empty()) {
5269  return;
5270  }
5271  const Coefficient& b = ub_expr.inhomogeneous_term();
5272  // Number of non-zero coefficients in `ub_expr': will be set to
5273  // 0, 1, or 2, the latter value meaning any value greater than 1.
5274  dimension_type t = 0;
5275  // Index of the last non-zero coefficient in `ub_expr', if any.
5276  dimension_type w = ub_expr.last_nonzero();
5277 
5278  if (w != 0) {
5279  ++t;
5280  if (!ub_expr.all_zeroes(1, w)) {
5281  ++t;
5282  }
5283  }
5284 
5285  // Now we know the form of `ub_expr':
5286  // - If t == 0, then ub_expr == b, with `b' a constant;
5287  // - If t == 1, then ub_expr == a*w + b, where `w' can be `v' or another
5288  // variable; in this second case we have to check whether `a' is
5289  // equal to `denominator' or `-denominator', since otherwise we have
5290  // to fall back on the general form;
5291  // - If t == 2, the `ub_expr' is of the general form.
5292  PPL_DIRTY_TEMP_COEFFICIENT(minus_denom);
5293  neg_assign(minus_denom, denominator);
5294 
5295  if (t == 0) {
5296  // Case 1: ub_expr == b.
5297  generalized_affine_image(var,
5299  lb_expr,
5300  denominator);
5301  // Add the constraint `var <= b/denominator'.
5302  add_dbm_constraint(0, v, b, denominator);
5303  PPL_ASSERT(OK());
5304  return;
5305  }
5306 
5307  if (t == 1) {
5308  // Value of the one and only non-zero coefficient in `ub_expr'.
5309  const Coefficient& a = ub_expr.get(Variable(w - 1));
5310  if (a == denominator || a == minus_denom) {
5311  // Case 2: expr == a*w + b, with a == +/- denominator.
5312  if (w == v) {
5313  // Here `var' occurs in `ub_expr'.
5314  // To ease the computation, we add an additional dimension.
5315  const Variable new_var(bds_space_dim);
5316  add_space_dimensions_and_embed(1);
5317  // Constrain the new dimension to be equal to `ub_expr'.
5318  affine_image(new_var, ub_expr, denominator);
5319  // NOTE: enforce shortest-path closure for precision.
5320  shortest_path_closure_assign();
5321  PPL_ASSERT(!marked_empty());
5322  // Apply the affine lower bound.
5323  generalized_affine_image(var,
5325  lb_expr,
5326  denominator);
5327  // Now apply the affine upper bound, as recorded in `new_var'.
5328  add_constraint(var <= new_var);
5329  // Remove the temporarily added dimension.
5330  remove_higher_space_dimensions(bds_space_dim);
5331  return;
5332  }
5333  else {
5334  // Here `w != v', so that `expr' is of the form
5335  // +/-denominator * w + b.
5336  // Apply the affine lower bound.
5337  generalized_affine_image(var,
5339  lb_expr,
5340  denominator);
5341  if (a == denominator) {
5342  // Add the new constraint `v - w == b/denominator'.
5343  add_dbm_constraint(w, v, b, denominator);
5344  }
5345  else {
5346  // Here a == -denominator, so that we should be adding
5347  // the constraint `v + w == b/denominator'.
5348  // Approximate it by computing lower and upper bounds for `w'.
5349  const N& dbm_w0 = dbm[w][0];
5350  if (!is_plus_infinity(dbm_w0)) {
5351  // Add the constraint `v <= b/denominator - lower_w'.
5352  PPL_DIRTY_TEMP(N, d);
5353  div_round_up(d, b, denominator);
5354  add_assign_r(dbm[0][v], d, dbm_w0, ROUND_UP);
5355  reset_shortest_path_closed();
5356  }
5357  }
5358  PPL_ASSERT(OK());
5359  return;
5360  }
5361  }
5362  }
5363 
5364  // General case.
5365  // Either t == 2, so that
5366  // ub_expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2,
5367  // or t == 1, ub_expr == a*w + b, but a <> +/- denominator.
5368  // We will remove all the constraints on `var' and add back
5369  // constraints providing upper and lower bounds for `var'.
5370 
5371  // Compute upper approximations for `ub_expr' into `pos_sum'
5372  // taking into account the sign of `denominator'.
5373  const bool is_sc = (denominator > 0);
5374  PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
5375  neg_assign(minus_b, b);
5376  const Coefficient& sc_b = is_sc ? b : minus_b;
5377  const Coefficient& sc_denom = is_sc ? denominator : minus_denom;
5378  const Coefficient& minus_sc_denom = is_sc ? minus_denom : denominator;
5379  // NOTE: here, for optimization purposes, `minus_expr' is only assigned
5380  // when `denominator' is negative. Do not use it unless you are sure
5381  // it has been correctly assigned.
5382  Linear_Expression minus_expr;
5383  if (!is_sc) {
5384  minus_expr = -ub_expr;
5385  }
5386  const Linear_Expression& sc_expr = is_sc ? ub_expr : minus_expr;
5387 
5388  PPL_DIRTY_TEMP(N, pos_sum);
5389  // Index of the variable that are unbounded in `this->dbm'.
5390  PPL_UNINITIALIZED(dimension_type, pos_pinf_index);
5391  // Number of unbounded variables found.
5392  dimension_type pos_pinf_count = 0;
5393 
5394  // Approximate the inhomogeneous term.
5395  assign_r(pos_sum, sc_b, ROUND_UP);
5396 
5397  // Approximate the homogeneous part of `sc_expr'.
5398  const DB_Row<N>& dbm_0 = dbm[0];
5399  // Speculative allocation of temporaries to be used in the following loop.
5400  PPL_DIRTY_TEMP(N, coeff_i);
5401  PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
5402  // Note: indices above `w' can be disregarded, as they all have
5403  // a zero coefficient in `sc_expr'.
5404  for (Linear_Expression::const_iterator i = sc_expr.begin(),
5405  i_end = sc_expr.lower_bound(Variable(w)); i != i_end; ++i) {
5406  const Coefficient& sc_i = *i;
5407  const dimension_type i_dim = i.variable().space_dimension();
5408  const int sign_i = sgn(sc_i);
5409  if (sign_i > 0) {
5410  assign_r(coeff_i, sc_i, ROUND_UP);
5411  // Approximating `sc_expr'.
5412  if (pos_pinf_count <= 1) {
5413  const N& up_approx_i = dbm_0[i_dim];
5414  if (!is_plus_infinity(up_approx_i)) {
5415  add_mul_assign_r(pos_sum, coeff_i, up_approx_i, ROUND_UP);
5416  }
5417  else {
5418  ++pos_pinf_count;
5419  pos_pinf_index = i_dim;
5420  }
5421  }
5422  }
5423  else {
5424  PPL_ASSERT(sign_i < 0);
5425  neg_assign(minus_sc_i, sc_i);
5426  // Note: using temporary named `coeff_i' to store -coeff_i.
5427  assign_r(coeff_i, minus_sc_i, ROUND_UP);
5428  // Approximating `sc_expr'.
5429  if (pos_pinf_count <= 1) {
5430  const N& up_approx_minus_i = dbm[i_dim][0];
5431  if (!is_plus_infinity(up_approx_minus_i)) {
5432  add_mul_assign_r(pos_sum, coeff_i, up_approx_minus_i, ROUND_UP);
5433  }
5434  else {
5435  ++pos_pinf_count;
5436  pos_pinf_index = i_dim;
5437  }
5438  }
5439  }
5440  }
5441  // Apply the affine lower bound.
5442  generalized_affine_image(var,
5444  lb_expr,
5445  denominator);
5446  // Return immediately if no approximation could be computed.
5447  if (pos_pinf_count > 1) {
5448  return;
5449  }
5450 
5451  // In the following, shortest-path closure will be definitely lost.
5452  reset_shortest_path_closed();
5453 
5454  // Exploit the upper approximation, if possible.
5455  if (pos_pinf_count <= 1) {
5456  // Compute quotient (if needed).
5457  if (sc_denom != 1) {
5458  // Before computing quotients, the denominator should be approximated
5459  // towards zero. Since `sc_denom' is known to be positive, this amounts to
5460  // rounding downwards, which is achieved as usual by rounding upwards
5461  // `minus_sc_denom' and negating again the result.
5462  PPL_DIRTY_TEMP(N, down_sc_denom);
5463  assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
5464  neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
5465  div_assign_r(pos_sum, pos_sum, down_sc_denom, ROUND_UP);
5466  }
5467  // Add the upper bound constraint, if meaningful.
5468  if (pos_pinf_count == 0) {
5469  // Add the constraint `v <= pos_sum'.
5470  dbm[0][v] = pos_sum;
5471  // Deduce constraints of the form `v - u', where `u != v'.
5472  deduce_v_minus_u_bounds(v, w, sc_expr, sc_denom, pos_sum);
5473  }
5474  // Here `pos_pinf_count == 1'.
5475  else if (pos_pinf_index != v
5476  && sc_expr.get(Variable(pos_pinf_index - 1)) == sc_denom) {
5477  // Add the constraint `v - pos_pinf_index <= pos_sum'.
5478  dbm[pos_pinf_index][v] = pos_sum;
5479  }
5480  }
5481  PPL_ASSERT(OK());
5482 }
5483 
5484 template <typename T>
5485 void
5488  const Linear_Expression& lb_expr,
5489  const Linear_Expression& ub_expr,
5490  Coefficient_traits::const_reference denominator) {
5491  // The denominator cannot be zero.
5492  if (denominator == 0) {
5493  throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
5494  }
5495  // Dimension-compatibility checks.
5496  // `var' should be one of the dimensions of the BD_Shape.
5497  const dimension_type space_dim = space_dimension();
5498  const dimension_type v = var.id() + 1;
5499  if (v > space_dim) {
5500  throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
5501  "v", var);
5502  }
5503  // The dimension of `lb_expr' and `ub_expr' should not be
5504  // greater than the dimension of `*this'.
5505  const dimension_type lb_space_dim = lb_expr.space_dimension();
5506  if (space_dim < lb_space_dim) {
5507  throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
5508  "lb", lb_expr);
5509  }
5510  const dimension_type ub_space_dim = ub_expr.space_dimension();
5511  if (space_dim < ub_space_dim) {
5512  throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
5513  "ub", ub_expr);
5514  }
5515  // Any preimage of an empty BDS is empty.
5516  shortest_path_closure_assign();
5517  if (marked_empty()) {
5518  return;
5519  }
5520  if (ub_expr.coefficient(var) == 0) {
5521  refine(var, LESS_OR_EQUAL, ub_expr, denominator);
5522  generalized_affine_preimage(var, GREATER_OR_EQUAL,
5523  lb_expr, denominator);
5524  return;
5525  }
5526  if (lb_expr.coefficient(var) == 0) {
5527  refine(var, GREATER_OR_EQUAL, lb_expr, denominator);
5528  generalized_affine_preimage(var, LESS_OR_EQUAL,
5529  ub_expr, denominator);
5530  return;
5531  }
5532 
5533  const Coefficient& lb_expr_v = lb_expr.coefficient(var);
5534  // Here `var' occurs in `lb_expr' and `ub_expr'.
5535  // To ease the computation, we add an additional dimension.
5536  const Variable new_var(space_dim);
5537  add_space_dimensions_and_embed(1);
5538  const Linear_Expression lb_inverse
5539  = lb_expr - (lb_expr_v + denominator)*var;
5540  PPL_DIRTY_TEMP_COEFFICIENT(lb_inverse_denom);
5541  neg_assign(lb_inverse_denom, lb_expr_v);
5542  affine_image(new_var, lb_inverse, lb_inverse_denom);
5543  shortest_path_closure_assign();
5544  PPL_ASSERT(!marked_empty());
5545  generalized_affine_preimage(var, LESS_OR_EQUAL,
5546  ub_expr, denominator);
5547  if (sgn(denominator) == sgn(lb_inverse_denom)) {
5548  add_constraint(var >= new_var);
5549  }
5550  else {
5551  add_constraint(var <= new_var);
5552  }
5553  // Remove the temporarily added dimension.
5554  remove_higher_space_dimensions(space_dim);
5555 }
5556 
5557 template <typename T>
5558 void
5560  const Relation_Symbol relsym,
5561  const Linear_Expression& expr,
5562  Coefficient_traits::const_reference
5563  denominator) {
5564  // The denominator cannot be zero.
5565  if (denominator == 0) {
5566  throw_invalid_argument("generalized_affine_image(v, r, e, d)", "d == 0");
5567  }
5568  // Dimension-compatibility checks.
5569  // The dimension of `expr' should not be greater than the dimension
5570  // of `*this'.
5571  const dimension_type space_dim = space_dimension();
5572  const dimension_type expr_space_dim = expr.space_dimension();
5573  if (space_dim < expr_space_dim) {
5574  throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
5575  "e", expr);
5576  }
5577  // `var' should be one of the dimensions of the BDS.
5578  const dimension_type v = var.id() + 1;
5579  if (v > space_dim) {
5580  throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
5581  var.id());
5582  }
5583  // The relation symbol cannot be a strict relation symbol.
5584  if (relsym == LESS_THAN || relsym == GREATER_THAN) {
5585  throw_invalid_argument("generalized_affine_image(v, r, e, d)",
5586  "r is a strict relation symbol");
5587  }
5588  // The relation symbol cannot be a disequality.
5589  if (relsym == NOT_EQUAL) {
5590  throw_invalid_argument("generalized_affine_image(v, r, e, d)",
5591  "r is the disequality relation symbol");
5592  }
5593  if (relsym == EQUAL) {
5594  // The relation symbol is "=":
5595  // this is just an affine image computation.
5596  affine_image(var, expr, denominator);
5597  return;
5598  }
5599 
5600  // The image of an empty BDS is empty too.
5601  shortest_path_closure_assign();
5602  if (marked_empty()) {
5603  return;
5604  }
5605  const Coefficient& b = expr.inhomogeneous_term();
5606  // Number of non-zero coefficients in `expr': will be set to
5607  // 0, 1, or 2, the latter value meaning any value greater than 1.
5608  dimension_type t = 0;
5609  // Index of the last non-zero coefficient in `expr', if any.
5610  dimension_type w = expr.last_nonzero();
5611 
5612  if (w != 0) {
5613  ++t;
5614  if (!expr.all_zeroes(1, w)) {
5615  ++t;
5616  }
5617  }
5618 
5619  // Now we know the form of `expr':
5620  // - If t == 0, then expr == b, with `b' a constant;
5621  // - If t == 1, then expr == a*w + b, where `w' can be `v' or another
5622  // variable; in this second case we have to check whether `a' is
5623  // equal to `denominator' or `-denominator', since otherwise we have
5624  // to fall back on the general form;
5625  // - If t == 2, the `expr' is of the general form.
5626  DB_Row<N>& dbm_0 = dbm[0];
5627  DB_Row<N>& dbm_v = dbm[v];
5628  PPL_DIRTY_TEMP_COEFFICIENT(minus_denom);
5629  neg_assign(minus_denom, denominator);
5630 
5631  if (t == 0) {
5632  // Case 1: expr == b.
5633  // Remove all constraints on `var'.
5634  forget_all_dbm_constraints(v);
5635  // Both shortest-path closure and reduction are lost.
5636  reset_shortest_path_closed();
5637  switch (relsym) {
5638  case LESS_OR_EQUAL:
5639  // Add the constraint `var <= b/denominator'.
5640  add_dbm_constraint(0, v, b, denominator);
5641  break;
5642  case GREATER_OR_EQUAL:
5643  // Add the constraint `var >= b/denominator',
5644  // i.e., `-var <= -b/denominator',
5645  add_dbm_constraint(v, 0, b, minus_denom);
5646  break;
5647  default:
5648  // We already dealt with the other cases.
5649  PPL_UNREACHABLE;
5650  break;
5651  }
5652  PPL_ASSERT(OK());
5653  return;
5654  }
5655 
5656  if (t == 1) {
5657  // Value of the one and only non-zero coefficient in `expr'.
5658  const Coefficient& a = expr.get(Variable(w - 1));
5659  if (a == denominator || a == minus_denom) {
5660  // Case 2: expr == a*w + b, with a == +/- denominator.
5661  PPL_DIRTY_TEMP(N, d);
5662  switch (relsym) {
5663  case LESS_OR_EQUAL:
5664  div_round_up(d, b, denominator);
5665  if (w == v) {
5666  // `expr' is of the form: a*v + b.
5667  // Shortest-path closure and reduction are not preserved.
5668  reset_shortest_path_closed();
5669  if (a == denominator) {
5670  // Translate each constraint `v - w <= dbm_wv'
5671  // into the constraint `v - w <= dbm_wv + b/denominator';
5672  // forget each constraint `w - v <= dbm_vw'.
5673  for (dimension_type i = space_dim + 1; i-- > 0; ) {
5674  N& dbm_iv = dbm[i][v];
5675  add_assign_r(dbm_iv, dbm_iv, d, ROUND_UP);
5677  }
5678  }
5679  else {
5680  // Here `a == -denominator'.
5681  // Translate the constraint `0 - v <= dbm_v0'
5682  // into the constraint `0 - v <= dbm_v0 + b/denominator'.
5683  N& dbm_v0 = dbm_v[0];
5684  add_assign_r(dbm_0[v], dbm_v0, d, ROUND_UP);
5685  // Forget all the other constraints on `v'.
5687  forget_binary_dbm_constraints(v);
5688  }
5689  }
5690  else {
5691  // Here `w != v', so that `expr' is of the form
5692  // +/-denominator * w + b, with `w != v'.
5693  // Remove all constraints on `v'.
5694  forget_all_dbm_constraints(v);
5695  // Shortest-path closure is preserved, but not reduction.
5696  if (marked_shortest_path_reduced()) {
5697  reset_shortest_path_reduced();
5698  }
5699  if (a == denominator) {
5700  // Add the new constraint `v - w <= b/denominator'.
5701  add_dbm_constraint(w, v, d);
5702  }
5703  else {
5704  // Here a == -denominator, so that we should be adding
5705  // the constraint `v <= b/denominator - w'.
5706  // Approximate it by computing a lower bound for `w'.
5707  const N& dbm_w0 = dbm[w][0];
5708  if (!is_plus_infinity(dbm_w0)) {
5709  // Add the constraint `v <= b/denominator - lb_w'.
5710  add_assign_r(dbm_0[v], d, dbm_w0, ROUND_UP);
5711  // Shortest-path closure is not preserved.
5712  reset_shortest_path_closed();
5713  }
5714  }
5715  }
5716  break;
5717 
5718  case GREATER_OR_EQUAL:
5719  div_round_up(d, b, minus_denom);
5720  if (w == v) {
5721  // `expr' is of the form: a*w + b.
5722  // Shortest-path closure and reduction are not preserved.
5723  reset_shortest_path_closed();
5724  if (a == denominator) {
5725  // Translate each constraint `w - v <= dbm_vw'
5726  // into the constraint `w - v <= dbm_vw - b/denominator';
5727  // forget each constraint `v - w <= dbm_wv'.
5728  for (dimension_type i = space_dim + 1; i-- > 0; ) {
5729  N& dbm_vi = dbm_v[i];
5730  add_assign_r(dbm_vi, dbm_vi, d, ROUND_UP);
5732  }
5733  }
5734  else {
5735  // Here `a == -denominator'.
5736  // Translate the constraint `0 - v <= dbm_v0'
5737  // into the constraint `0 - v <= dbm_0v - b/denominator'.
5738  N& dbm_0v = dbm_0[v];
5739  add_assign_r(dbm_v[0], dbm_0v, d, ROUND_UP);
5740  // Forget all the other constraints on `v'.
5742  forget_binary_dbm_constraints(v);
5743  }
5744  }
5745  else {
5746  // Here `w != v', so that `expr' is of the form
5747  // +/-denominator * w + b, with `w != v'.
5748  // Remove all constraints on `v'.
5749  forget_all_dbm_constraints(v);
5750  // Shortest-path closure is preserved, but not reduction.
5751  if (marked_shortest_path_reduced()) {
5752  reset_shortest_path_reduced();
5753  }
5754  if (a == denominator) {
5755  // Add the new constraint `v - w >= b/denominator',
5756  // i.e., `w - v <= -b/denominator'.
5757  add_dbm_constraint(v, w, d);
5758  }
5759  else {
5760  // Here a == -denominator, so that we should be adding
5761  // the constraint `v >= -w + b/denominator',
5762  // i.e., `-v <= w - b/denominator'.
5763  // Approximate it by computing an upper bound for `w'.
5764  const N& dbm_0w = dbm_0[w];
5765  if (!is_plus_infinity(dbm_0w)) {
5766  // Add the constraint `-v <= ub_w - b/denominator'.
5767  add_assign_r(dbm_v[0], dbm_0w, d, ROUND_UP);
5768  // Shortest-path closure is not preserved.
5769  reset_shortest_path_closed();
5770  }
5771  }
5772  }
5773  break;
5774 
5775  default:
5776  // We already dealt with the other cases.
5777  PPL_UNREACHABLE;
5778  break;
5779  }
5780  PPL_ASSERT(OK());
5781  return;
5782  }
5783  }
5784 
5785  // General case.
5786  // Either t == 2, so that
5787  // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2,
5788  // or t == 1, expr == a*w + b, but a <> +/- denominator.
5789  // We will remove all the constraints on `v' and add back
5790  // a constraint providing an upper or a lower bound for `v'
5791  // (depending on `relsym').
5792  const bool is_sc = (denominator > 0);
5793  PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
5794  neg_assign(minus_b, b);
5795  const Coefficient& sc_b = is_sc ? b : minus_b;
5796  const Coefficient& minus_sc_b = is_sc ? minus_b : b;
5797  const Coefficient& sc_denom = is_sc ? denominator : minus_denom;
5798  const Coefficient& minus_sc_denom = is_sc ? minus_denom : denominator;
5799  // NOTE: here, for optimization purposes, `minus_expr' is only assigned
5800  // when `denominator' is negative. Do not use it unless you are sure
5801  // it has been correctly assigned.
5802  Linear_Expression minus_expr;
5803  if (!is_sc) {
5804  minus_expr = -expr;
5805  }
5806  const Linear_Expression& sc_expr = is_sc ? expr : minus_expr;
5807 
5808  PPL_DIRTY_TEMP(N, sum);
5809  // Index of variable that is unbounded in `this->dbm'.
5810  PPL_UNINITIALIZED(dimension_type, pinf_index);
5811  // Number of unbounded variables found.
5812  dimension_type pinf_count = 0;
5813 
5814  // Speculative allocation of temporaries to be used in the following loops.
5815  PPL_DIRTY_TEMP(N, coeff_i);
5816  PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
5817 
5818  switch (relsym) {
5819  case LESS_OR_EQUAL:
5820  // Compute an upper approximation for `sc_expr' into `sum'.
5821 
5822  // Approximate the inhomogeneous term.
5823  assign_r(sum, sc_b, ROUND_UP);
5824  // Approximate the homogeneous part of `sc_expr'.
5825  // Note: indices above `w' can be disregarded, as they all have
5826  // a zero coefficient in `sc_expr'.
5827  PPL_ASSERT(w != 0);
5828  for (Linear_Expression::const_iterator i = sc_expr.begin(),
5829  i_end = sc_expr.lower_bound(Variable(w)); i != i_end; ++i) {
5830  const Coefficient& sc_i = *i;
5831  const dimension_type i_dim = i.variable().space_dimension();
5832  const int sign_i = sgn(sc_i);
5833  PPL_ASSERT(sign_i != 0);
5834  // Choose carefully: we are approximating `sc_expr'.
5835  const N& approx_i = (sign_i > 0) ? dbm_0[i_dim] : dbm[i_dim][0];
5836  if (is_plus_infinity(approx_i)) {
5837  if (++pinf_count > 1) {
5838  break;
5839  }
5840  pinf_index = i_dim;
5841  continue;
5842  }
5843  if (sign_i > 0) {
5844  assign_r(coeff_i, sc_i, ROUND_UP);
5845  }
5846  else {
5847  neg_assign(minus_sc_i, sc_i);
5848  assign_r(coeff_i, minus_sc_i, ROUND_UP);
5849  }
5850  add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
5851  }
5852 
5853  // Remove all constraints on `v'.
5854  forget_all_dbm_constraints(v);
5855  // Shortest-path closure is preserved, but not reduction.
5856  if (marked_shortest_path_reduced()) {
5857  reset_shortest_path_reduced();
5858  }
5859  // Return immediately if no approximation could be computed.
5860  if (pinf_count > 1) {
5861  PPL_ASSERT(OK());
5862  return;
5863  }
5864 
5865  // Divide by the (sign corrected) denominator (if needed).
5866  if (sc_denom != 1) {
5867  // Before computing the quotient, the denominator should be approximated
5868  // towards zero. Since `sc_denom' is known to be positive, this amounts to
5869  // rounding downwards, which is achieved as usual by rounding upwards
5870  // `minus_sc_denom' and negating again the result.
5871  PPL_DIRTY_TEMP(N, down_sc_denom);
5872  assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
5873  neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
5874  div_assign_r(sum, sum, down_sc_denom, ROUND_UP);
5875  }
5876 
5877  if (pinf_count == 0) {
5878  // Add the constraint `v <= sum'.
5879  add_dbm_constraint(0, v, sum);
5880  // Deduce constraints of the form `v - u', where `u != v'.
5881  deduce_v_minus_u_bounds(v, w, sc_expr, sc_denom, sum);
5882  }
5883  else if (pinf_count == 1) {
5884  if (pinf_index != v
5885  && expr.get(Variable(pinf_index - 1)) == denominator) {
5886  // Add the constraint `v - pinf_index <= sum'.
5887  add_dbm_constraint(pinf_index, v, sum);
5888  }
5889  }
5890  break;
5891 
5892  case GREATER_OR_EQUAL:
5893  // Compute an upper approximation for `-sc_expr' into `sum'.
5894  // Note: approximating `-sc_expr' from above and then negating the
5895  // result is the same as approximating `sc_expr' from below.
5896 
5897  // Approximate the inhomogeneous term.
5898  assign_r(sum, minus_sc_b, ROUND_UP);
5899  // Approximate the homogeneous part of `-sc_expr'.
5900  for (Linear_Expression::const_iterator i = sc_expr.begin(),
5901  i_end = sc_expr.lower_bound(Variable(w)); i != i_end; ++i) {
5902  const Coefficient& sc_i = *i;
5903  const int sign_i = sgn(sc_i);
5904  PPL_ASSERT(sign_i != 0);
5905  const dimension_type i_dim = i.variable().space_dimension();
5906  // Choose carefully: we are approximating `-sc_expr'.
5907  const N& approx_i = (sign_i > 0) ? dbm[i_dim][0] : dbm_0[i_dim];
5908  if (is_plus_infinity(approx_i)) {
5909  if (++pinf_count > 1) {
5910  break;
5911  }
5912  pinf_index = i_dim;
5913  continue;
5914  }
5915  if (sign_i > 0) {
5916  assign_r(coeff_i, sc_i, ROUND_UP);
5917  }
5918  else {
5919  neg_assign(minus_sc_i, sc_i);
5920  assign_r(coeff_i, minus_sc_i, ROUND_UP);
5921  }
5922  add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
5923  }
5924 
5925  // Remove all constraints on `var'.
5926  forget_all_dbm_constraints(v);
5927  // Shortest-path closure is preserved, but not reduction.
5928  if (marked_shortest_path_reduced()) {
5929  reset_shortest_path_reduced();
5930  }
5931  // Return immediately if no approximation could be computed.
5932  if (pinf_count > 1) {
5933  PPL_ASSERT(OK());
5934  return;
5935  }
5936 
5937  // Divide by the (sign corrected) denominator (if needed).
5938  if (sc_denom != 1) {
5939  // Before computing the quotient, the denominator should be approximated
5940  // towards zero. Since `sc_denom' is known to be positive, this amounts to
5941  // rounding downwards, which is achieved as usual by rounding upwards
5942  // `minus_sc_denom' and negating again the result.
5943  PPL_DIRTY_TEMP(N, down_sc_denom);
5944  assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
5945  neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
5946  div_assign_r(sum, sum, down_sc_denom, ROUND_UP);
5947  }
5948 
5949  if (pinf_count == 0) {
5950  // Add the constraint `v >= -sum', i.e., `-v <= sum'.
5951  add_dbm_constraint(v, 0, sum);
5952  // Deduce constraints of the form `u - v', where `u != v'.
5953  deduce_u_minus_v_bounds(v, w, sc_expr, sc_denom, sum);
5954  }
5955  else if (pinf_count == 1) {
5956  if (pinf_index != v
5957  && expr.get(Variable(pinf_index - 1)) == denominator) {
5958  // Add the constraint `v - pinf_index >= -sum',
5959  // i.e., `pinf_index - v <= sum'.
5960  add_dbm_constraint(v, pinf_index, sum);
5961  }
5962  }
5963  break;
5964 
5965  default:
5966  // We already dealt with the other cases.
5967  PPL_UNREACHABLE;
5968  break;
5969  }
5970  PPL_ASSERT(OK());
5971 }
5972 
5973 template <typename T>
5974 void
5976  const Relation_Symbol relsym,
5977  const Linear_Expression& rhs) {
5978  // Dimension-compatibility checks.
5979  // The dimension of `lhs' should not be greater than the dimension
5980  // of `*this'.
5981  const dimension_type space_dim = space_dimension();
5982  const dimension_type lhs_space_dim = lhs.space_dimension();
5983  if (space_dim < lhs_space_dim) {
5984  throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
5985  "e1", lhs);
5986  }
5987  // The dimension of `rhs' should not be greater than the dimension
5988  // of `*this'.
5989  const dimension_type rhs_space_dim = rhs.space_dimension();
5990  if (space_dim < rhs_space_dim) {
5991  throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
5992  "e2", rhs);
5993  }
5994  // Strict relation symbols are not admitted for BDSs.
5995  if (relsym == LESS_THAN || relsym == GREATER_THAN) {
5996  throw_invalid_argument("generalized_affine_image(e1, r, e2)",
5997  "r is a strict relation symbol");
5998  }
5999  // The relation symbol cannot be a disequality.
6000  if (relsym == NOT_EQUAL) {
6001  throw_invalid_argument("generalized_affine_image(e1, r, e2)",
6002  "r is the disequality relation symbol");
6003  }
6004  // The image of an empty BDS is empty.
6005  shortest_path_closure_assign();
6006  if (marked_empty()) {
6007  return;
6008  }
6009  // Number of non-zero coefficients in `lhs': will be set to
6010  // 0, 1, or 2, the latter value meaning any value greater than 1.
6011  dimension_type t_lhs = 0;
6012  // Index of the last non-zero coefficient in `lhs', if any.
6013  dimension_type j_lhs = lhs.last_nonzero();
6014 
6015  if (j_lhs != 0) {
6016  ++t_lhs;
6017  if (!lhs.all_zeroes(1, j_lhs)) {
6018  ++t_lhs;
6019  }
6020  --j_lhs;
6021  }
6022 
6023  const Coefficient& b_lhs = lhs.inhomogeneous_term();
6024 
6025  if (t_lhs == 0) {
6026  // `lhs' is a constant.
6027  // In principle, it is sufficient to add the constraint `lhs relsym rhs'.
6028  // Note that this constraint is a bounded difference if `t_rhs <= 1'
6029  // or `t_rhs > 1' and `rhs == a*v - a*w + b_rhs'. If `rhs' is of a
6030  // more general form, it will be simply ignored.
6031  // TODO: if it is not a bounded difference, should we compute
6032  // approximations for this constraint?
6033  switch (relsym) {
6034  case LESS_OR_EQUAL:
6035  refine_no_check(lhs <= rhs);
6036  break;
6037  case EQUAL:
6038  refine_no_check(lhs == rhs);
6039  break;
6040  case GREATER_OR_EQUAL:
6041  refine_no_check(lhs >= rhs);
6042  break;
6043  default:
6044  // We already dealt with the other cases.
6045  PPL_UNREACHABLE;
6046  break;
6047  }
6048  }
6049  else if (t_lhs == 1) {
6050  // Here `lhs == a_lhs * v + b_lhs'.
6051  // Independently from the form of `rhs', we can exploit the
6052  // method computing generalized affine images for a single variable.
6053  Variable v(j_lhs);
6054  // Compute a sign-corrected relation symbol.
6055  const Coefficient& denom = lhs.coefficient(v);
6056  Relation_Symbol new_relsym = relsym;
6057  if (denom < 0) {
6058  if (relsym == LESS_OR_EQUAL) {
6059  new_relsym = GREATER_OR_EQUAL;
6060  }
6061  else if (relsym == GREATER_OR_EQUAL) {
6062  new_relsym = LESS_OR_EQUAL;
6063  }
6064  }
6065  Linear_Expression expr = rhs - b_lhs;
6066  generalized_affine_image(v, new_relsym, expr, denom);
6067  }
6068  else {
6069  // Here `lhs' is of the general form, having at least two variables.
6070  // Compute the set of variables occurring in `lhs'.
6071  std::vector<Variable> lhs_vars;
6072  for (Linear_Expression::const_iterator i = lhs.begin(), i_end = lhs.end();
6073  i != i_end; ++i) {
6074  lhs_vars.push_back(i.variable());
6075  }
6076  const dimension_type num_common_dims = std::min(lhs_space_dim, rhs_space_dim);
6077  if (!lhs.have_a_common_variable(rhs, Variable(0), Variable(num_common_dims))) {
6078  // `lhs' and `rhs' variables are disjoint.
6079  // Existentially quantify all variables in the lhs.
6080  for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
6081  forget_all_dbm_constraints(lhs_vars[i].id() + 1);
6082  }
6083  // Constrain the left hand side expression so that it is related to
6084  // the right hand side expression as dictated by `relsym'.
6085  // TODO: if the following constraint is NOT a bounded difference,
6086  // it will be simply ignored. Should we compute approximations for it?
6087  switch (relsym) {
6088  case LESS_OR_EQUAL:
6089  refine_no_check(lhs <= rhs);
6090  break;
6091  case EQUAL:
6092  refine_no_check(lhs == rhs);
6093  break;
6094  case GREATER_OR_EQUAL:
6095  refine_no_check(lhs >= rhs);
6096  break;
6097  default:
6098  // We already dealt with the other cases.
6099  PPL_UNREACHABLE;
6100  break;
6101  }
6102  }
6103  else {
6104  // Some variables in `lhs' also occur in `rhs'.
6105 
6106 #if 1 // Simplified computation (see the TODO note below).
6107 
6108  for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
6109  forget_all_dbm_constraints(lhs_vars[i].id() + 1);
6110  }
6111 #else // Currently unnecessarily complex computation.
6112 
6113  // More accurate computation that is worth doing only if
6114  // the following TODO note is accurately dealt with.
6115 
6116  // To ease the computation, we add an additional dimension.
6117  const Variable new_var(space_dim);
6118  add_space_dimensions_and_embed(1);
6119  // Constrain the new dimension to be equal to `rhs'.
6120  // NOTE: calling affine_image() instead of refine_no_check()
6121  // ensures some approximation is tried even when the constraint
6122  // is not a bounded difference.
6123  affine_image(new_var, rhs);
6124  // Existentially quantify all variables in the lhs.
6125  // NOTE: enforce shortest-path closure for precision.
6126  shortest_path_closure_assign();
6127  PPL_ASSERT(!marked_empty());
6128  for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
6129  forget_all_dbm_constraints(lhs_vars[i].id() + 1);
6130  }
6131  // Constrain the new dimension so that it is related to
6132  // the left hand side as dictated by `relsym'.
6133  // TODO: each one of the following constraints is definitely NOT
6134  // a bounded differences (since it has 3 variables at least).
6135  // Thus, the method refine_no_check() will simply ignore it.
6136  // Should we compute approximations for this constraint?
6137  switch (relsym) {
6138  case LESS_OR_EQUAL:
6139  refine_no_check(lhs <= new_var);
6140  break;
6141  case EQUAL:
6142  refine_no_check(lhs == new_var);
6143  break;
6144  case GREATER_OR_EQUAL:
6145  refine_no_check(lhs >= new_var);
6146  break;
6147  default:
6148  // We already dealt with the other cases.
6149  PPL_UNREACHABLE;
6150  break;
6151  }
6152  // Remove the temporarily added dimension.
6153  remove_higher_space_dimensions(space_dim-1);
6154 #endif // Currently unnecessarily complex computation.
6155  }
6156  }
6157 
6158  PPL_ASSERT(OK());
6159 }
6160 
6161 template <typename T>
6162 void
6164  const Relation_Symbol relsym,
6165  const Linear_Expression& expr,
6166  Coefficient_traits::const_reference
6167  denominator) {
6168  // The denominator cannot be zero.
6169  if (denominator == 0) {
6170  throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
6171  "d == 0");
6172  }
6173  // Dimension-compatibility checks.
6174  // The dimension of `expr' should not be greater than the dimension
6175  // of `*this'.
6176  const dimension_type space_dim = space_dimension();
6177  const dimension_type expr_space_dim = expr.space_dimension();
6178  if (space_dim < expr_space_dim) {
6179  throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
6180  "e", expr);
6181  }
6182  // `var' should be one of the dimensions of the BDS.
6183  const dimension_type v = var.id() + 1;
6184  if (v > space_dim) {
6185  throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
6186  var.id());
6187  }
6188  // The relation symbol cannot be a strict relation symbol.
6189  if (relsym == LESS_THAN || relsym == GREATER_THAN) {
6190  throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
6191  "r is a strict relation symbol");
6192  }
6193  // The relation symbol cannot be a disequality.
6194  if (relsym == NOT_EQUAL) {
6195  throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
6196  "r is the disequality relation symbol");
6197  }
6198  if (relsym == EQUAL) {
6199  // The relation symbol is "=":
6200  // this is just an affine preimage computation.
6201  affine_preimage(var, expr, denominator);
6202  return;
6203  }
6204 
6205  // The preimage of an empty BDS is empty too.
6206  shortest_path_closure_assign();
6207  if (marked_empty()) {
6208  return;
6209  }
6210  // Check whether the preimage of this affine relation can be easily
6211  // computed as the image of its inverse relation.
6212  const Coefficient& expr_v = expr.coefficient(var);
6213  if (expr_v != 0) {
6214  const Relation_Symbol reversed_relsym = (relsym == LESS_OR_EQUAL)
6217  = expr - (expr_v + denominator)*var;
6218  PPL_DIRTY_TEMP_COEFFICIENT(inverse_denom);
6219  neg_assign(inverse_denom, expr_v);
6220  const Relation_Symbol inverse_relsym
6221  = (sgn(denominator) == sgn(inverse_denom)) ? relsym : reversed_relsym;
6222  generalized_affine_image(var, inverse_relsym, inverse, inverse_denom);
6223  return;
6224  }
6225 
6226  refine(var, relsym, expr, denominator);
6227  // If the shrunk BD_Shape is empty, its preimage is empty too; ...
6228  if (is_empty()) {
6229  return;
6230  }
6231  // ... otherwise, since the relation was not invertible,
6232  // we just forget all constraints on `v'.
6233  forget_all_dbm_constraints(v);
6234  // Shortest-path closure is preserved, but not reduction.
6235  if (marked_shortest_path_reduced()) {
6236  reset_shortest_path_reduced();
6237  }
6238  PPL_ASSERT(OK());
6239 }
6240 
6241 template <typename T>
6242 void
6244  const Relation_Symbol relsym,
6245  const Linear_Expression& rhs) {
6246  // Dimension-compatibility checks.
6247  // The dimension of `lhs' should not be greater than the dimension
6248  // of `*this'.
6249  const dimension_type bds_space_dim = space_dimension();
6250  const dimension_type lhs_space_dim = lhs.space_dimension();
6251  if (bds_space_dim < lhs_space_dim) {
6252  throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
6253  "e1", lhs);
6254  }
6255  // The dimension of `rhs' should not be greater than the dimension
6256  // of `*this'.
6257  const dimension_type rhs_space_dim = rhs.space_dimension();
6258  if (bds_space_dim < rhs_space_dim) {
6259  throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
6260  "e2", rhs);
6261  }
6262  // Strict relation symbols are not admitted for BDSs.
6263  if (relsym == LESS_THAN || relsym == GREATER_THAN) {
6264  throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
6265  "r is a strict relation symbol");
6266  }
6267  // The relation symbol cannot be a disequality.
6268  if (relsym == NOT_EQUAL) {
6269  throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
6270  "r is the disequality relation symbol");
6271  }
6272  // The preimage of an empty BDS is empty.
6273  shortest_path_closure_assign();
6274  if (marked_empty()) {
6275  return;
6276  }
6277  // Number of non-zero coefficients in `lhs': will be set to
6278  // 0, 1, or 2, the latter value meaning any value greater than 1.
6279  dimension_type t_lhs = 0;
6280  // Index of the last non-zero coefficient in `lhs', if any.
6281  dimension_type j_lhs = lhs.last_nonzero();
6282 
6283  if (j_lhs != 0) {
6284  ++t_lhs;
6285  if (!lhs.all_zeroes(1, j_lhs)) {
6286  ++t_lhs;
6287  }
6288  --j_lhs;
6289  }
6290 
6291  const Coefficient& b_lhs = lhs.inhomogeneous_term();
6292 
6293  if (t_lhs == 0) {
6294  // `lhs' is a constant.
6295  // In this case, preimage and image happen to be the same.
6296  generalized_affine_image(lhs, relsym, rhs);
6297  return;
6298  }
6299  else if (t_lhs == 1) {
6300  // Here `lhs == a_lhs * v + b_lhs'.
6301  // Independently from the form of `rhs', we can exploit the
6302  // method computing generalized affine preimages for a single variable.
6303  Variable v(j_lhs);
6304  // Compute a sign-corrected relation symbol.
6305  const Coefficient& denom = lhs.coefficient(v);
6306  Relation_Symbol new_relsym = relsym;
6307  if (denom < 0) {
6308  if (relsym == LESS_OR_EQUAL) {
6309  new_relsym = GREATER_OR_EQUAL;
6310  }
6311  else if (relsym == GREATER_OR_EQUAL) {
6312  new_relsym = LESS_OR_EQUAL;
6313  }
6314  }
6315  Linear_Expression expr = rhs - b_lhs;
6316  generalized_affine_preimage(v, new_relsym, expr, denom);
6317  }
6318  else {
6319  // Here `lhs' is of the general form, having at least two variables.
6320  // Compute the set of variables occurring in `lhs'.
6321  std::vector<Variable> lhs_vars;
6322  for (Linear_Expression::const_iterator i = lhs.begin(), i_end = lhs.end();
6323  i != i_end; ++i) {
6324  lhs_vars.push_back(i.variable());
6325  }
6326  const dimension_type num_common_dims = std::min(lhs_space_dim, rhs_space_dim);
6327  if (!lhs.have_a_common_variable(rhs, Variable(0), Variable(num_common_dims))) {
6328  // `lhs' and `rhs' variables are disjoint.
6329 
6330  // Constrain the left hand side expression so that it is related to
6331  // the right hand side expression as dictated by `relsym'.
6332  // TODO: if the following constraint is NOT a bounded difference,
6333  // it will be simply ignored. Should we compute approximations for it?
6334  switch (relsym) {
6335  case LESS_OR_EQUAL:
6336  refine_no_check(lhs <= rhs);
6337  break;
6338  case EQUAL:
6339  refine_no_check(lhs == rhs);
6340  break;
6341  case GREATER_OR_EQUAL:
6342  refine_no_check(lhs >= rhs);
6343  break;
6344  default:
6345  // We already dealt with the other cases.
6346  PPL_UNREACHABLE;
6347  break;
6348  }
6349 
6350  // If the shrunk BD_Shape is empty, its preimage is empty too; ...
6351  if (is_empty()) {
6352  return;
6353  }
6354  // Existentially quantify all variables in the lhs.
6355  for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
6356  forget_all_dbm_constraints(lhs_vars[i].id() + 1);
6357  }
6358  }
6359  else {
6360 
6361  // Some variables in `lhs' also occur in `rhs'.
6362  // To ease the computation, we add an additional dimension.
6363  const Variable new_var(bds_space_dim);
6364  add_space_dimensions_and_embed(1);
6365  // Constrain the new dimension to be equal to `lhs'.
6366  // NOTE: calling affine_image() instead of refine_no_check()
6367  // ensures some approximation is tried even when the constraint
6368  // is not a bounded difference.
6369  affine_image(new_var, lhs);
6370  // Existentiallly quantify all variables in the lhs.
6371  // NOTE: enforce shortest-path closure for precision.
6372  shortest_path_closure_assign();
6373  PPL_ASSERT(!marked_empty());
6374  for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
6375  forget_all_dbm_constraints(lhs_vars[i].id() + 1);
6376  }
6377  // Constrain the new dimension so that it is related to
6378  // the left hand side as dictated by `relsym'.
6379  // Note: if `rhs == a_rhs*v + b_rhs' where `a_rhs' is in {0, 1},
6380  // then one of the following constraints will be added,
6381  // since it is a bounded difference. Else the method
6382  // refine_no_check() will ignore it, because the
6383  // constraint is NOT a bounded difference.
6384  switch (relsym) {
6385  case LESS_OR_EQUAL:
6386  refine_no_check(new_var <= rhs);
6387  break;
6388  case EQUAL:
6389  refine_no_check(new_var == rhs);
6390  break;
6391  case GREATER_OR_EQUAL:
6392  refine_no_check(new_var >= rhs);
6393  break;
6394  default:
6395  // We already dealt with the other cases.
6396  PPL_UNREACHABLE;
6397  break;
6398  }
6399  // Remove the temporarily added dimension.
6400  remove_higher_space_dimensions(bds_space_dim);
6401  }
6402  }
6403 
6404  PPL_ASSERT(OK());
6405 }
6406 
6407 template <typename T>
6410  const dimension_type space_dim = space_dimension();
6411  Constraint_System cs;
6412  cs.set_space_dimension(space_dim);
6413 
6414  if (space_dim == 0) {
6415  if (marked_empty()) {
6417  }
6418  return cs;
6419  }
6420 
6421  if (marked_empty()) {
6423  return cs;
6424  }
6425 
6426  if (marked_shortest_path_reduced()) {
6427  // Disregard redundant constraints.
6428  cs = minimized_constraints();
6429  return cs;
6430  }
6431 
6434  // Go through all the unary constraints in `dbm'.
6435  const DB_Row<N>& dbm_0 = dbm[0];
6436  for (dimension_type j = 1; j <= space_dim; ++j) {
6437  const Variable x(j-1);
6438  const N& dbm_0j = dbm_0[j];
6439  const N& dbm_j0 = dbm[j][0];
6440  if (is_additive_inverse(dbm_j0, dbm_0j)) {
6441  // We have a unary equality constraint.
6442  numer_denom(dbm_0j, b, a);
6443  cs.insert(a*x == b);
6444  }
6445  else {
6446  // We have 0, 1 or 2 unary inequality constraints.
6447  if (!is_plus_infinity(dbm_0j)) {
6448  numer_denom(dbm_0j, b, a);
6449  cs.insert(a*x <= b);
6450  }
6451  if (!is_plus_infinity(dbm_j0)) {
6452  numer_denom(dbm_j0, b, a);
6453  cs.insert(-a*x <= b);
6454  }
6455  }
6456  }
6457 
6458  // Go through all the binary constraints in `dbm'.
6459  for (dimension_type i = 1; i <= space_dim; ++i) {
6460  const Variable y(i-1);
6461  const DB_Row<N>& dbm_i = dbm[i];
6462  for (dimension_type j = i + 1; j <= space_dim; ++j) {
6463  const Variable x(j-1);
6464  const N& dbm_ij = dbm_i[j];
6465  const N& dbm_ji = dbm[j][i];
6466  if (is_additive_inverse(dbm_ji, dbm_ij)) {
6467  // We have a binary equality constraint.
6468  numer_denom(dbm_ij, b, a);
6469  cs.insert(a*x - a*y == b);
6470  }
6471  else {
6472  // We have 0, 1 or 2 binary inequality constraints.
6473  if (!is_plus_infinity(dbm_ij)) {
6474  numer_denom(dbm_ij, b, a);
6475  cs.insert(a*x - a*y <= b);
6476  }
6477  if (!is_plus_infinity(dbm_ji)) {
6478  numer_denom(dbm_ji, b, a);
6479  cs.insert(a*y - a*x <= b);
6480  }
6481  }
6482  }
6483  }
6484  return cs;
6485 }
6486 
6487 template <typename T>
6490  shortest_path_reduction_assign();
6491  const dimension_type space_dim = space_dimension();
6492  Constraint_System cs;
6493  cs.set_space_dimension(space_dim);
6494 
6495  if (space_dim == 0) {
6496  if (marked_empty()) {
6498  }
6499  return cs;
6500  }
6501 
6502  if (marked_empty()) {
6504  return cs;
6505  }
6506 
6509 
6510  // Compute leader information.
6511  std::vector<dimension_type> leaders;
6512  compute_leaders(leaders);
6513  std::vector<dimension_type> leader_indices;
6514  compute_leader_indices(leaders, leader_indices);
6515  const dimension_type num_leaders = leader_indices.size();
6516 
6517  // Go through the non-leaders to generate equality constraints.
6518  const DB_Row<N>& dbm_0 = dbm[0];
6519  for (dimension_type i = 1; i <= space_dim; ++i) {
6520  const dimension_type leader = leaders[i];
6521  if (i != leader) {
6522  // Generate the constraint relating `i' and its leader.
6523  if (leader == 0) {
6524  // A unary equality has to be generated.
6525  PPL_ASSERT(!is_plus_infinity(dbm_0[i]));
6526  numer_denom(dbm_0[i], numer, denom);
6527  cs.insert(denom*Variable(i-1) == numer);
6528  }
6529  else {
6530  // A binary equality has to be generated.
6531  PPL_ASSERT(!is_plus_infinity(dbm[i][leader]));
6532  numer_denom(dbm[i][leader], numer, denom);
6533  cs.insert(denom*Variable(leader-1) - denom*Variable(i-1) == numer);
6534  }
6535  }
6536  }
6537 
6538  // Go through the leaders to generate inequality constraints.
6539  // First generate all the unary inequalities.
6540  const Bit_Row& red_0 = redundancy_dbm[0];
6541  for (dimension_type l_i = 1; l_i < num_leaders; ++l_i) {
6542  const dimension_type i = leader_indices[l_i];
6543  if (!red_0[i]) {
6544  numer_denom(dbm_0[i], numer, denom);
6545  cs.insert(denom*Variable(i-1) <= numer);
6546  }
6547  if (!redundancy_dbm[i][0]) {
6548  numer_denom(dbm[i][0], numer, denom);
6549  cs.insert(-denom*Variable(i-1) <= numer);
6550  }
6551  }
6552  // Then generate all the binary inequalities.
6553  for (dimension_type l_i = 1; l_i < num_leaders; ++l_i) {
6554  const dimension_type i = leader_indices[l_i];
6555  const DB_Row<N>& dbm_i = dbm[i];
6556  const Bit_Row& red_i = redundancy_dbm[i];
6557  for (dimension_type l_j = l_i + 1; l_j < num_leaders; ++l_j) {
6558  const dimension_type j = leader_indices[l_j];
6559  if (!red_i[j]) {
6560  numer_denom(dbm_i[j], numer, denom);
6561  cs.insert(denom*Variable(j-1) - denom*Variable(i-1) <= numer);
6562  }
6563  if (!redundancy_dbm[j][i]) {
6564  numer_denom(dbm[j][i], numer, denom);
6565  cs.insert(denom*Variable(i-1) - denom*Variable(j-1) <= numer);
6566  }
6567  }
6568  }
6569  return cs;
6570 }
6571 
6572 template <typename T>
6573 void
6575  dimension_type old_dim = space_dimension();
6576  // `var' should be one of the dimensions of the vector space.
6577  if (var.space_dimension() > old_dim) {
6578  throw_dimension_incompatible("expand_space_dimension(v, m)", "v", var);
6579  }
6580 
6581  // The space dimension of the resulting BDS should not
6582  // overflow the maximum allowed space dimension.
6583  if (m > max_space_dimension() - space_dimension()) {
6584  throw_invalid_argument("expand_dimension(v, m)",
6585  "adding m new space dimensions exceeds "
6586  "the maximum allowed space dimension");
6587  }
6588  // Nothing to do, if no dimensions must be added.
6589  if (m == 0) {
6590  return;
6591  }
6592  // Add the required new dimensions.
6593  add_space_dimensions_and_embed(m);
6594 
6595  // For each constraints involving variable `var', we add a
6596  // similar constraint with the new variable substituted for
6597  // variable `var'.
6598  const dimension_type v_id = var.id() + 1;
6599  const DB_Row<N>& dbm_v = dbm[v_id];
6600  for (dimension_type i = old_dim + 1; i-- > 0; ) {
6601  DB_Row<N>& dbm_i = dbm[i];
6602  const N& dbm_i_v = dbm[i][v_id];
6603  const N& dbm_v_i = dbm_v[i];
6604  for (dimension_type j = old_dim+1; j < old_dim+m+1; ++j) {
6605  dbm_i[j] = dbm_i_v;
6606  dbm[j][i] = dbm_v_i;
6607  }
6608  }
6609  // In general, adding a constraint does not preserve the shortest-path
6610  // closure or reduction of the bounded difference shape.
6611  if (marked_shortest_path_closed()) {
6612  reset_shortest_path_closed();
6613  }
6614  PPL_ASSERT(OK());
6615 }
6616 
6617 template <typename T>
6618 void
6620  Variable dest) {
6621  const dimension_type space_dim = space_dimension();
6622  // `dest' should be one of the dimensions of the BDS.
6623  if (dest.space_dimension() > space_dim) {
6624  throw_dimension_incompatible("fold_space_dimensions(vs, v)",
6625  "v", dest);
6626  }
6627  // The folding of no dimensions is a no-op.
6628  if (vars.empty()) {
6629  return;
6630  }
6631  // All variables in `vars' should be dimensions of the BDS.
6632  if (vars.space_dimension() > space_dim) {
6633  throw_dimension_incompatible("fold_space_dimensions(vs, v)",
6634  vars.space_dimension());
6635  }
6636  // Moreover, `dest.id()' should not occur in `vars'.
6637  if (vars.find(dest.id()) != vars.end()) {
6638  throw_invalid_argument("fold_space_dimensions(vs, v)",
6639  "v should not occur in vs");
6640  }
6641  shortest_path_closure_assign();
6642  if (!marked_empty()) {
6643  // Recompute the elements of the row and the column corresponding
6644  // to variable `dest' by taking the join of their value with the
6645  // value of the corresponding elements in the row and column of the
6646  // variable `vars'.
6647  const dimension_type v_id = dest.id() + 1;
6648  DB_Row<N>& dbm_v = dbm[v_id];
6649  for (Variables_Set::const_iterator i = vars.begin(),
6650  vs_end = vars.end(); i != vs_end; ++i) {
6651  const dimension_type to_be_folded_id = *i + 1;
6652  const DB_Row<N>& dbm_to_be_folded_id = dbm[to_be_folded_id];
6653  for (dimension_type j = space_dim + 1; j-- > 0; ) {
6654  max_assign(dbm[j][v_id], dbm[j][to_be_folded_id]);
6655  max_assign(dbm_v[j], dbm_to_be_folded_id[j]);
6656  }
6657  }
6658  }
6659  remove_space_dimensions(vars);
6660 }
6661 
6662 template <typename T>
6663 void
6666  return;
6667  }
6668  const dimension_type space_dim = space_dimension();
6669  shortest_path_closure_assign();
6670  if (space_dim == 0 || marked_empty()) {
6671  return;
6672  }
6673  for (dimension_type i = space_dim + 1; i-- > 0; ) {
6674  DB_Row<N>& dbm_i = dbm[i];
6675  for (dimension_type j = space_dim + 1; j-- > 0; ) {
6676  if (i != j) {
6677  drop_some_non_integer_points_helper(dbm_i[j]);
6678  }
6679  }
6680  }
6681  PPL_ASSERT(OK());
6682 }
6683 
6684 template <typename T>
6685 void
6687  Complexity_Class) {
6688  // Dimension-compatibility check.
6689  const dimension_type space_dim = space_dimension();
6690  const dimension_type min_space_dim = vars.space_dimension();
6691  if (space_dim < min_space_dim) {
6692  throw_dimension_incompatible("drop_some_non_integer_points(vs, cmpl)",
6693  min_space_dim);
6694  }
6695  if (std::numeric_limits<T>::is_integer || min_space_dim == 0) {
6696  return;
6697  }
6698  shortest_path_closure_assign();
6699  if (marked_empty()) {
6700  return;
6701  }
6702  const Variables_Set::const_iterator v_begin = vars.begin();
6703  const Variables_Set::const_iterator v_end = vars.end();
6704  PPL_ASSERT(v_begin != v_end);
6705  // Unary constraints on a variable occurring in `vars'.
6706  DB_Row<N>& dbm_0 = dbm[0];
6707  for (Variables_Set::const_iterator v_i = v_begin; v_i != v_end; ++v_i) {
6708  const dimension_type i = *v_i + 1;
6709  drop_some_non_integer_points_helper(dbm_0[i]);
6710  drop_some_non_integer_points_helper(dbm[i][0]);
6711  }
6712 
6713  // Binary constraints where both variables occur in `vars'.
6714  for (Variables_Set::const_iterator v_i = v_begin; v_i != v_end; ++v_i) {
6715  const dimension_type i = *v_i + 1;
6716  DB_Row<N>& dbm_i = dbm[i];
6717  for (Variables_Set::const_iterator v_j = v_begin; v_j != v_end; ++v_j) {
6718  const dimension_type j = *v_j + 1;
6719  if (i != j) {
6720  drop_some_non_integer_points_helper(dbm_i[j]);
6721  }
6722  }
6723  }
6724  PPL_ASSERT(OK());
6725 }
6726 
6728 template <typename T>
6729 std::ostream&
6730 IO_Operators::operator<<(std::ostream& s, const BD_Shape<T>& bds) {
6731  typedef typename BD_Shape<T>::coefficient_type N;
6732  if (bds.is_universe()) {
6733  s << "true";
6734  }
6735  else {
6736  // We control empty bounded difference shape.
6737  dimension_type n = bds.space_dimension();
6738  if (bds.marked_empty()) {
6739  s << "false";
6740  }
6741  else {
6742  PPL_DIRTY_TEMP(N, v);
6743  bool first = true;
6744  for (dimension_type i = 0; i <= n; ++i) {
6745  for (dimension_type j = i + 1; j <= n; ++j) {
6746  const N& c_i_j = bds.dbm[i][j];
6747  const N& c_j_i = bds.dbm[j][i];
6748  if (is_additive_inverse(c_j_i, c_i_j)) {
6749  // We will print an equality.
6750  if (first) {
6751  first = false;
6752  }
6753  else {
6754  s << ", ";
6755  }
6756  if (i == 0) {
6757  // We have got a equality constraint with one variable.
6758  s << Variable(j - 1);
6759  s << " = " << c_i_j;
6760  }
6761  else {
6762  // We have got a equality constraint with two variables.
6763  if (sgn(c_i_j) >= 0) {
6764  s << Variable(j - 1);
6765  s << " - ";
6766  s << Variable(i - 1);
6767  s << " = " << c_i_j;
6768  }
6769  else {
6770  s << Variable(i - 1);
6771  s << " - ";
6772  s << Variable(j - 1);
6773  s << " = " << c_j_i;
6774  }
6775  }
6776  }
6777  else {
6778  // We will print a non-strict inequality.
6779  if (!is_plus_infinity(c_j_i)) {
6780  if (first) {
6781  first = false;
6782  }
6783  else {
6784  s << ", ";
6785  }
6786  if (i == 0) {
6787  // We have got a constraint with only one variable.
6788  s << Variable(j - 1);
6789  neg_assign_r(v, c_j_i, ROUND_DOWN);
6790  s << " >= " << v;
6791  }
6792  else {
6793  // We have got a constraint with two variables.
6794  if (sgn(c_j_i) >= 0) {
6795  s << Variable(i - 1);
6796  s << " - ";
6797  s << Variable(j - 1);
6798  s << " <= " << c_j_i;
6799  }
6800  else {
6801  s << Variable(j - 1);
6802  s << " - ";
6803  s << Variable(i - 1);
6804  neg_assign_r(v, c_j_i, ROUND_DOWN);
6805  s << " >= " << v;
6806  }
6807  }
6808  }
6809  if (!is_plus_infinity(c_i_j)) {
6810  if (first) {
6811  first = false;
6812  }
6813  else {
6814  s << ", ";
6815  }
6816  if (i == 0) {
6817  // We have got a constraint with only one variable.
6818  s << Variable(j - 1);
6819  s << " <= " << c_i_j;
6820  }
6821  else {
6822  // We have got a constraint with two variables.
6823  if (sgn(c_i_j) >= 0) {
6824  s << Variable(j - 1);
6825  s << " - ";
6826  s << Variable(i - 1);
6827  s << " <= " << c_i_j;
6828  }
6829  else {
6830  s << Variable(i - 1);
6831  s << " - ";
6832  s << Variable(j - 1);
6833  neg_assign_r(v, c_i_j, ROUND_DOWN);
6834  s << " >= " << v;
6835  }
6836  }
6837  }
6838  }
6839  }
6840  }
6841  }
6842  }
6843  return s;
6844 }
6845 
6846 template <typename T>
6847 void
6848 BD_Shape<T>::ascii_dump(std::ostream& s) const {
6849  status.ascii_dump(s);
6850  s << "\n";
6851  dbm.ascii_dump(s);
6852  s << "\n";
6853  redundancy_dbm.ascii_dump(s);
6854 }
6855 
6857 
6858 template <typename T>
6859 bool
6860 BD_Shape<T>::ascii_load(std::istream& s) {
6861  if (!status.ascii_load(s)) {
6862  return false;
6863  }
6864  if (!dbm.ascii_load(s)) {
6865  return false;
6866  }
6867  if (!redundancy_dbm.ascii_load(s)) {
6868  return false;
6869  }
6870  return true;
6871 }
6872 
6873 template <typename T>
6876  return dbm.external_memory_in_bytes()
6877  + redundancy_dbm.external_memory_in_bytes();
6878 }
6879 
6880 template <typename T>
6881 bool
6883  // Check whether the difference-bound matrix is well-formed.
6884  if (!dbm.OK()) {
6885  return false;
6886  }
6887  // Check whether the status information is legal.
6888  if (!status.OK()) {
6889  return false;
6890  }
6891  // An empty BDS is OK.
6892  if (marked_empty()) {
6893  return true;
6894  }
6895  // MINUS_INFINITY cannot occur at all.
6896  for (dimension_type i = dbm.num_rows(); i-- > 0; ) {
6897  for (dimension_type j = dbm.num_rows(); j-- > 0; ) {
6898  if (is_minus_infinity(dbm[i][j])) {
6899 #ifndef NDEBUG
6900  using namespace Parma_Polyhedra_Library::IO_Operators;
6901  std::cerr << "BD_Shape::dbm[" << i << "][" << j << "] = "
6902  << dbm[i][j] << "!"
6903  << std::endl;
6904 #endif
6905  return false;
6906  }
6907  }
6908  }
6909  // On the main diagonal only PLUS_INFINITY can occur.
6910  for (dimension_type i = dbm.num_rows(); i-- > 0; ) {
6911  if (!is_plus_infinity(dbm[i][i])) {
6912 #ifndef NDEBUG
6913  using namespace Parma_Polyhedra_Library::IO_Operators;
6914  std::cerr << "BD_Shape::dbm[" << i << "][" << i << "] = "
6915  << dbm[i][i] << "! (+inf was expected.)"
6916  << std::endl;
6917 #endif
6918  return false;
6919  }
6920  }
6921  // Check whether the shortest-path closure information is legal.
6922  if (marked_shortest_path_closed()) {
6923  BD_Shape x = *this;
6926  if (x.dbm != dbm) {
6927 #ifndef NDEBUG
6928  std::cerr << "BD_Shape is marked as closed but it is not!"
6929  << std::endl;
6930 #endif
6931  return false;
6932  }
6933  }
6934 
6935  // The following tests might result in false alarms when using floating
6936  // point coefficients: they are only meaningful if the coefficient type
6937  // base is exact (since otherwise shortest-path closure is approximated).
6938  if (std::numeric_limits<coefficient_type_base>::is_exact) {
6939 
6940  // Check whether the shortest-path reduction information is legal.
6941  if (marked_shortest_path_reduced()) {
6942  // A non-redundant constraint cannot be equal to PLUS_INFINITY.
6943  for (dimension_type i = dbm.num_rows(); i-- > 0; ) {
6944  for (dimension_type j = dbm.num_rows(); j-- > 0; ) {
6945  if (!redundancy_dbm[i][j] && is_plus_infinity(dbm[i][j])) {
6946 #ifndef NDEBUG
6947  using namespace Parma_Polyhedra_Library::IO_Operators;
6948  std::cerr << "BD_Shape::dbm[" << i << "][" << j << "] = "
6949  << dbm[i][j] << " is marked as non-redundant!"
6950  << std::endl;
6951 #endif
6952  return false;
6953  }
6954  }
6955  }
6956  BD_Shape x = *this;
6959  if (x.redundancy_dbm != redundancy_dbm) {
6960 #ifndef NDEBUG
6961  std::cerr << "BD_Shape is marked as reduced but it is not!"
6962  << std::endl;
6963 #endif
6964  return false;
6965  }
6966  }
6967  }
6968 
6969  // All checks passed.
6970  return true;
6971 }
6972 
6973 template <typename T>
6974 void
6976  const BD_Shape& y) const {
6977  std::ostringstream s;
6978  s << "PPL::BD_Shape::" << method << ":" << std::endl
6979  << "this->space_dimension() == " << space_dimension()
6980  << ", y->space_dimension() == " << y.space_dimension() << ".";
6981  throw std::invalid_argument(s.str());
6982 }
6983 
6984 template <typename T>
6985 void
6987  dimension_type required_dim) const {
6988  std::ostringstream s;
6989  s << "PPL::BD_Shape::" << method << ":" << std::endl
6990  << "this->space_dimension() == " << space_dimension()
6991  << ", required dimension == " << required_dim << ".";
6992  throw std::invalid_argument(s.str());
6993 }
6994 
6995 template <typename T>
6996 void
6998  const Constraint& c) const {
6999  std::ostringstream s;
7000  s << "PPL::BD_Shape::" << method << ":" << std::endl
7001  << "this->space_dimension() == " << space_dimension()
7002  << ", c->space_dimension == " << c.space_dimension() << ".";
7003  throw std::invalid_argument(s.str());
7004 }
7005 
7006 template <typename T>
7007 void
7009  const Congruence& cg) const {
7010  std::ostringstream s;
7011  s << "PPL::BD_Shape::" << method << ":" << std::endl
7012  << "this->space_dimension() == " << space_dimension()
7013  << ", cg->space_dimension == " << cg.space_dimension() << ".";
7014  throw std::invalid_argument(s.str());
7015 }
7016 
7017 template <typename T>
7018 void
7020  const Generator& g) const {
7021  std::ostringstream s;
7022  s << "PPL::BD_Shape::" << method << ":" << std::endl
7023  << "this->space_dimension() == " << space_dimension()
7024  << ", g->space_dimension == " << g.space_dimension() << ".";
7025  throw std::invalid_argument(s.str());
7026 }
7027 
7028 template <typename T>
7029 void
7031  const Linear_Expression& le) {
7032  using namespace IO_Operators;
7033  std::ostringstream s;
7034  s << "PPL::BD_Shape::" << method << ":" << std::endl
7035  << le << " is too complex.";
7036  throw std::invalid_argument(s.str());
7037 }
7038 
7039 
7040 template <typename T>
7041 void
7043  const char* le_name,
7044  const Linear_Expression& le) const {
7045  std::ostringstream s;
7046  s << "PPL::BD_Shape::" << method << ":" << std::endl
7047  << "this->space_dimension() == " << space_dimension()
7048  << ", " << le_name << "->space_dimension() == "
7049  << le.space_dimension() << ".";
7050  throw std::invalid_argument(s.str());
7051 }
7052 
7053 template <typename T>
7054 template<typename Interval_Info>
7055 void
7057  const char* lf_name,
7058  const Linear_Form< Interval<T,
7059  Interval_Info> >& lf) const {
7060  std::ostringstream s;
7061  s << "PPL::BD_Shape::" << method << ":" << std::endl
7062  << "this->space_dimension() == " << space_dimension()
7063  << ", " << lf_name << "->space_dimension() == "
7064  << lf.space_dimension() << ".";
7065  throw std::invalid_argument(s.str());
7066 }
7067 
7068 template <typename T>
7069 void
7070 BD_Shape<T>::throw_invalid_argument(const char* method, const char* reason) {
7071  std::ostringstream s;
7072  s << "PPL::BD_Shape::" << method << ":" << std::endl
7073  << reason << ".";
7074  throw std::invalid_argument(s.str());
7075 }
7076 
7077 } // namespace Parma_Polyhedra_Library
7078 
7079 #endif // !defined(PPL_BD_Shape_templates_hh)
bool marked_empty() const
Returns true if the BDS is known to be empty.
Minimization is requested.
bool has_pending_constraints() const
Returns true if there are pending constraints.
bool is_satisfiable() const
Checks satisfiability of *this.
Definition: MIP_Problem.cc:247
bool constraints_are_minimized() const
Returns true if the system of constraints is minimized.
void BHMZ05_widening_assign(const BD_Shape &y, unsigned *tp=0)
Assigns to *this the result of computing the BHMZ05-widening of *this and y.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
Enable_If< Is_Native_Or_Checked< To >::value &&Is_Special< From >::value, Result >::type assign_r(To &to, const From &, Rounding_Dir dir)
bool is_tautological() const
Returns true if and only if *this is a tautology (i.e., an always true constraint).
Definition: Constraint.cc:105
dimension_type space_dimension() const
Returns the dimension of the smallest vector space enclosing all the variables whose indexes are in t...
void limited_CC76_extrapolation_assign(const BD_Shape &y, const Constraint_System &cs, unsigned *tp=0)
Improves the result of the CC76-extrapolation computation by also enforcing those constraints in cs t...
void deduce_u_minus_v_bounds(dimension_type v, dimension_type last_v, const Linear_Expression &sc_expr, Coefficient_traits::const_reference sc_denom, const N &minus_lb_v)
An helper function for the computation of affine relations.
bool marked_empty() const
Returns true if the polyhedron is known to be empty.
Enable_If< Is_Native_Or_Checked< T >::value, bool >::type is_minus_infinity(const T &x)
The empty element, i.e., the empty set.
static Poly_Con_Relation is_disjoint()
The polyhedron and the set of points satisfying the constraint are disjoint.
static Poly_Gen_Relation subsumes()
Adding the generator would not change the polyhedron.
dimension_type max_space_dimension()
Returns the maximum space dimension this library can handle.
void set_optimization_mode(Optimization_Mode mode)
Sets the optimization mode to mode.
Coefficient_traits::const_reference modulus() const
Returns a const reference to the modulus of *this.
A linear equality or inequality.
void unconstrain(Variable var)
Computes the cylindrification of *this with respect to space dimension var, assigning the result to *...
void left_inhomogeneous_refine(const dimension_type &right_t, const dimension_type &right_w_id, const Linear_Form< Interval< T, Interval_Info > > &left, const Linear_Form< Interval< T, Interval_Info > > &right)
Auxiliary function for refine with linear form that handle the general case: .
bool is_equality() const
Returns true if and only if *this is an equality constraint.
void swap(CO_Tree &x, CO_Tree &y)
Optimization_Mode
Possible optimization modes.
void set_space_dimension(dimension_type n)
Sets the dimension of the vector space enclosing *this to n .
static bool implies(flags_t x, flags_t y)
True if and only if the conjunction x implies the conjunction y.
size_t dimension_type
An unsigned integral type for representing space dimensions.
void insert(const Congruence &cg)
Inserts in *this a copy of the congruence cg, increasing the number of space dimensions if needed...
void set_space_dimension(dimension_type space_dim)
Sets the space dimension of the rows in the system to space_dim .
An std::set of variables' indexes.
Enable_If< Is_Native_Or_Checked< T >::value, void >::type numer_denom(const T &from, Coefficient &numer, Coefficient &denom)
Extract the numerator and denominator components of from.
void fold_space_dimensions(const Variables_Set &vars, Variable dest)
Folds the space dimensions in vars into dest.
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
void upper_bound_assign(const BD_Shape &y)
Assigns to *this the smallest BDS containing the union of *this and y.
bool max_min(const Linear_Expression &expr, bool maximize, Coefficient &ext_n, Coefficient &ext_d, bool &included, Generator &g) const
Maximizes or minimizes expr subject to *this.
bool is_disjoint_from(const BD_Shape &y) const
Returns true if and only if *this and y are disjoint.
Coefficient_traits::const_reference get(dimension_type i) const
Returns the i-th coefficient.
A line, ray, point or closure point.
void negate()
Negates all the coefficients of *this.
void map_space_dimensions(const Partial_Function &pfunc)
Remaps the dimensions of the vector space according to a partial function.
void add_constraints(const Constraint_System &cs)
Adds a copy of the constraints in cs to the MIP problem.
Definition: MIP_Problem.cc:184
bool is_line_or_ray() const
Returns true if and only if *this is a line or a ray.
bool is_shortest_path_reduced() const
Returns true if and only if this->dbm is shortest-path closed and this->redundancy_dbm correctly flag...
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
BD_Shape(dimension_type num_dimensions=0, Degenerate_Element kind=UNIVERSE)
Builds a universe or empty BDS of the specified space dimension.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
void bounded_affine_image(Variable var, const Linear_Expression &lb_expr, const Linear_Expression &ub_expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the image of *this with respect to the bounded affine relation . ...
void concatenate_assign(const BD_Shape &y)
Assigns to *this the concatenation of *this and y, taken in this order.
void refine_with_constraints(const Constraint_System &cs)
Uses a copy of the constraints in cs to refine the system of bounded differences defining *this...
bool is_inconsistent() const
Returns true if and only if *this is inconsistent (i.e., an always false congruence).
Definition: Congruence.cc:218
void get_limiting_shape(const Constraint_System &cs, BD_Shape &limiting_shape) const
Adds to limiting_shape the bounded differences in cs that are satisfied by *this. ...
Enable_If< Has_Assign_Or_Swap< T >::value, void >::type assign_or_swap(T &to, T &from)
void drop_some_non_integer_points(Complexity_Class complexity=ANY_COMPLEXITY)
Possibly tightens *this by dropping some points with non-integer coordinates.
void affine_image(Variable var, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the affine image of *this under the function mapping variable var into the affine ex...
void m_swap(BD_Shape &y)
Swaps *this with y (*this and y can be dimension-incompatible).
void throw_dimension_incompatible(const char *method, const BD_Shape &y) const
void add_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
Enable_If< Is_Native_Or_Checked< T >::value, bool >::type is_integer(const T &x)
static const Constraint_System & zero_dim_empty()
Returns the singleton system containing only Constraint::zero_dim_false().
static const Constraint & zero_dim_false()
The unsatisfiable (zero-dimension space) constraint .
bool BFT00_upper_bound_assign_if_exact(const BD_Shape &y)
If the upper bound of *this and y is exact it is assigned to *this and true is returned, otherwise false is returned.
void insert(const Constraint &c)
Inserts in *this a copy of the constraint c, increasing the number of space dimensions if needed...
void CC76_extrapolation_assign(const BD_Shape &y, unsigned *tp=0)
Assigns to *this the result of computing the CC76-extrapolation between *this and y...
static const Congruence_System & zero_dim_empty()
Returns the system containing only Congruence::zero_dim_false().
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
static Poly_Con_Relation is_included()
The polyhedron is included in the set of points satisfying the constraint.
void set(unsigned long k)
Sets the bit in position k.
The standard C++ namespace.
expr_type expression() const
Partial read access to the (adapted) internal expression.
expr_type expression() const
Partial read access to the (adapted) internal expression.
#define PPL_OUTPUT_TEMPLATE_DEFINITIONS(type_symbol, class_prefix)
void affine_preimage(Variable var, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the affine preimage of *this under the function mapping variable var into the affine...
void affine_form_image(Variable var, const Linear_Form< Interval< T, Interval_Info > > &lf)
Assigns to *this the affine form image of *this under the function mapping variable var into the affi...
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
const Constraint_System & constraints() const
Returns the system of constraints.
void add_constraint(const Constraint &c)
Adds a copy of constraint c to the system of bounded differences defining *this.
bool has_empty_codomain() const
Returns true if and only if the represented partial function has an empty codomain (i...
void clear(unsigned long k)
Clears the bit in position k.
static Poly_Con_Relation saturates()
The polyhedron is included in the set of points saturating the constraint.
All input/output operators are confined to this namespace.
void evaluate_objective_function(const Generator &evaluating_point, Coefficient &numer, Coefficient &denom) const
Sets num and denom so that is the result of evaluating the objective function on evaluating_point...
A row in a matrix of bits.
void generalized_affine_image(Variable var, Relation_Symbol relsym, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the image of *this with respect to the affine relation , where is the relation symb...
void add_constraint(const Constraint &c)
Adds a copy of constraint c to the MIP problem.
Definition: MIP_Problem.cc:164
void max_assign(N &x, const N &y)
Assigns to x the maximum between x and y.
const_iterator begin() const
Returns the const_iterator pointing to the first constraint, if *this is not empty; otherwise...
bool marked_shortest_path_closed() const
Returns true if the system of bounded differences is known to be shortest-path closed.
void set_zero_dim_univ()
Turns *this into an zero-dimensional universe BDS.
void inhomogeneous_affine_form_image(const dimension_type &var_id, const Interval< T, Interval_Info > &b)
Auxiliary function for affine form image that handle the general case: .
void compute_predecessors(std::vector< dimension_type > &predecessor) const
Compute the (zero-equivalence classes) predecessor relation.
Worst-case polynomial complexity.
Enable_If< Is_Native_Or_Checked< T >::value, void >::type div_round_up(T &to, Coefficient_traits::const_reference x, Coefficient_traits::const_reference y)
Divides x by y into to, rounding the result towards plus infinity.
Coefficient_traits::const_reference coefficient(Variable v) const
Returns the coefficient of v in *this.
dimension_type id() const
Returns the index of the Cartesian axis associated to the variable.
void add_space_dimensions_and_embed(dimension_type m)
Adds m new dimensions and embeds the old BDS into the new space.
const Generator & optimizing_point() const
Returns an optimal point for *this, if it exists.
Definition: MIP_Problem.cc:236
bool is_proper_congruence() const
Returns true if the modulus is greater than zero.
bool is_empty() const
Returns true if and only if *this is an empty BDS.
void refine_no_check(const Constraint &c)
Uses the constraint c to refine *this.
void left_one_var_refine(const dimension_type &left_w_id, const dimension_type &right_t, const dimension_type &right_w_id, const Linear_Form< Interval< T, Interval_Info > > &left, const Linear_Form< Interval< T, Interval_Info > > &right)
Auxiliary function for refine with linear form that handle the general case: .
static const Congruence & zero_dim_false()
Returns a reference to the false (zero-dimension space) congruence .
A dimension of the vector space.
void shortest_path_closure_assign() const
Assigns to this->dbm its shortest-path closure.
bool bounds(const Linear_Expression &expr, bool from_above) const
Checks if and how expr is bounded in *this.
bool have_a_common_variable(const Linear_Expression &x, Variable first, Variable last) const
Returns true if there is a variable from index first (included) to index last (excluded) whose coeffi...
Rounding_Dir inverse(Rounding_Dir dir)
bool is_strict_inequality() const
Returns true if and only if *this is a strict inequality constraint.
Complexity_Class
Complexity pseudo-classes.
The base class for convex polyhedra.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
Worst-case exponential complexity but typically polynomial behavior.
The base class for the single rows of matrices.
Definition: DB_Row_defs.hh:120
bool is_inequality() const
Returns true if and only if *this is an inequality constraint (either strict or non-strict).
A wrapper for numeric types implementing a given policy.
bool generators_are_up_to_date() const
Returns true if the system of generators is up-to-date.
Constraint_System con_sys
The system of constraints.
bool all_zeroes(const Variables_Set &vars) const
Returns true if the coefficient of each variable in vars[i] is .
bool is_universe() const
Returns true if and only if *this is a universe BDS.
void bounded_affine_preimage(Variable var, const Linear_Expression &lb_expr, const Linear_Expression &ub_expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the preimage of *this with respect to the bounded affine relation ...
void linear_form_upper_bound(const Linear_Form< Interval< T, Interval_Info > > &lf, N &result) const
#define PPL_COMPILE_TIME_CHECK(e, msg)
Produces a compilation error if the compile-time constant e does not evaluate to true ...
bool constrains(Variable var) const
Returns true if and only if var is constrained in *this.
void reset_shortest_path_closed()
Marks *this as possibly not shortest-path closed.
bool is_universe() const
Returns true if and only if *this is a universe polyhedron.
Relation_Symbol
Relation symbols.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
bool is_equality() const
Returns true if *this is an equality.
Type type() const
Returns the generator type of *this.
void two_variables_affine_form_image(const dimension_type &var_id, const Linear_Form< Interval< T, Interval_Info > > &lf, const dimension_type &space_dim)
Auxiliary function for affine form image that handle the general case: .
bool empty() const
Returns true if and only if *this has no constraints.
bool constraints_are_up_to_date() const
Returns true if the system of constraints is up-to-date.
void clear()
Clears the matrix deallocating all its rows.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
bool simplify_using_context_assign(const BD_Shape &y)
Assigns to *this a meet-preserving simplification of *this with respect to y. If false is returned...
A linear form with interval coefficients.
static void throw_invalid_argument(const char *method, const char *reason)
const_iterator end() const
Returns the past-the-end const_iterator.
void optimal_value(Coefficient &numer, Coefficient &denom) const
Sets numer and denom so that is the solution of the optimization problem.
void generalized_affine_preimage(Variable var, Relation_Symbol relsym, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the preimage of *this with respect to the affine relation , where is the relation s...
bool frequency(const Linear_Expression &expr, Coefficient &freq_n, Coefficient &freq_d, Coefficient &val_n, Coefficient &val_d) const
Returns true if and only if there exist a unique value val such that *this saturates the equality exp...
A Mixed Integer (linear) Programming problem.
const_iterator end() const
Iterator pointing after the last nonzero variable coefficient.
const Generator_System & generators() const
Returns the system of generators.
void export_interval_constraints(U &dest) const
Applies to dest the interval constraints embedded in *this.
bool is_bounded() const
Returns true if and only if *this is a bounded BDS.
Coefficient_traits::const_reference get(dimension_type i) const
Returns the i -th coefficient.
bool is_inconsistent() const
Returns true if and only if *this is inconsistent (i.e., an always false constraint).
Definition: Constraint.cc:148
Constraint_System constraints() const
Returns a system of constraints defining *this.
Enable_If< Is_Native_Or_Checked< T >::value, bool >::type ascii_load(std::istream &s, T &t)
void difference_assign(const BD_Shape &y)
Assigns to *this the smallest BD shape containing the set difference of *this and y...
void intersection_assign(const BD_Shape &y)
Assigns to *this the intersection of *this and y.
Congruence_System minimized_congruences() const
Returns a minimal system of (equality) congruences satisfied by *this with the same affine dimension ...
Enable_If< Is_Native_Or_Checked< T >::value, bool >::type is_plus_infinity(const T &x)
void refine(Variable var, Relation_Symbol relsym, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Adds to the BDS the constraint .
PPL_COEFFICIENT_TYPE Coefficient
An alias for easily naming the type of PPL coefficients.
Enable_If< Is_Native_Or_Checked< T >::value, bool >::type is_additive_inverse(const T &x, const T &y)
Returns true if and only if .
bool is_tautological() const
Returns true if and only if *this is a tautology (i.e., an always true congruence).
Definition: Congruence.cc:210
void deduce_v_minus_u_bounds(dimension_type v, dimension_type last_v, const Linear_Expression &sc_expr, Coefficient_traits::const_reference sc_denom, const N &ub_v)
An helper function for the computation of affine relations.
void remove_space_dimensions(const Variables_Set &vars)
Removes all the specified dimensions.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
#define PPL_DIRTY_TEMP(T, id)
The universe element, i.e., the whole vector space.
A generic, not necessarily closed, possibly restricted interval.
dimension_type max_in_codomain() const
If the codomain is not empty, returns the maximum value in it.
Constraint_System minimized_constraints() const
Returns a minimized system of constraints defining *this.
bool OK() const
Returns true if and only if *this satisfies all its invariants.
void forget_binary_dbm_constraints(dimension_type v)
Removes all binary constraints on row/column v.
void one_variable_affine_form_image(const dimension_type &var_id, const Interval< T, Interval_Info > &b, const Interval< T, Interval_Info > &w_coeff, const dimension_type &w_id, const dimension_type &space_dim)
Auxiliary function for affine formimage" that handle the general case: .
void set_shortest_path_closed()
Marks *this as shortest-path closed.
Plus_Infinity PLUS_INFINITY
Definition: checked.cc:31
void neg_assign(GMP_Integer &x)
Coefficient_traits::const_reference Coefficient_zero()
Returns a const reference to a Coefficient with value 0.
The entire library is confined to this namespace.
Definition: version.hh:61
bool contains(const BD_Shape &y) const
Returns true if and only if *this contains y.
Maximization is requested.
Poly_Con_Relation relation_with(const Constraint &c) const
Returns the relations holding between *this and the constraint c.
void incremental_shortest_path_closure_assign(Variable var) const
Incrementally computes shortest-path closure, assuming that only constraints affecting variable var n...
void general_refine(const dimension_type &left_w_id, const dimension_type &right_w_id, const Linear_Form< Interval< T, Interval_Info > > &left, const Linear_Form< Interval< T, Interval_Info > > &right)
Auxiliary function for refine with linear form that handle the general case.
const_iterator end() const
Returns the past-the-end const_iterator.
const_iterator begin() const
Returns the const_iterator pointing to the first generator, if *this is not empty; otherwise...
A bounded difference shape.
void set_objective_function(const Linear_Expression &obj)
Sets the objective function to obj.
Definition: MIP_Problem.cc:208
MIP_Problem_Status solve() const
Optimizes the MIP problem.
Definition: MIP_Problem.cc:293
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
base_type::const_iterator const_iterator
The type of const iterators on coefficients.
bool BHZ09_upper_bound_assign_if_exact(const BD_Shape &y)
If the upper bound of *this and y is exact it is assigned to *this and true is returned, otherwise false is returned.
Coefficient_traits::const_reference coefficient(Variable v) const
Returns the coefficient of v in *this.
void compute_leaders(std::vector< dimension_type > &leaders) const
Compute the leaders of zero-equivalence classes.
int sgn(Boundary_Type type, const T &x, const Info &info)
void refine_with_linear_form_inequality(const Linear_Form< Interval< T, Interval_Info > > &left, const Linear_Form< Interval< T, Interval_Info > > &right)
Refines the system of BD_Shape constraints defining *this using the constraint expressed by left rig...
void sub_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
Bit_Matrix redundancy_dbm
A matrix indicating which constraints are redundant.
void forget_all_dbm_constraints(dimension_type v)
Removes all the constraints on row/column v.
void normalize2(Coefficient_traits::const_reference x, Coefficient_traits::const_reference y, Coefficient &n_x, Coefficient &n_y)
If is the GCD of x and y, the values of x and y divided by are assigned to n_x and n_y...
bool maps(dimension_type i, dimension_type &j) const
If *this maps i to a value k, assigns k to j and returns true; otherwise, j is unchanged and false is...
bool contains_integer_point() const
Returns true if and only if *this contains at least one integer point.
static void throw_expression_too_complex(const char *method, const Linear_Expression &le)
static bool extract_bounded_difference(const Constraint &c, dimension_type &c_num_vars, dimension_type &c_first_var, dimension_type &c_second_var, Coefficient &c_coeff)
Decodes the constraint c as a bounded difference.
size_t memory_size_type
An unsigned integral type for representing memory size in bytes.
Coefficient_traits::const_reference divisor() const
If *this is either a point or a closure point, returns its divisor.
bool is_nonstrict_inequality() const
Returns true if and only if *this is a non-strict inequality constraint.
Coefficient c
Definition: PIP_Tree.cc:64
void reset_shortest_path_reduced()
Marks *this as possibly not shortest-path reduced.
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
void set_empty()
Turns *this into an empty BDS.
void CC76_narrowing_assign(const BD_Shape &y)
Assigns to *this the result of restoring in y the constraints of *this that were lost by CC76-extrapo...
expr_type expression() const
Partial read access to the (adapted) internal expression.
#define PPL_UNINITIALIZED(type, name)
Definition: compiler.hh:72
void add_congruence(const Congruence &cg)
Adds a copy of congruence cg to the system of congruences of *this.
void upper_bound_assign(std::map< dimension_type, Linear_Form< FP_Interval_Type > > &ls1, const std::map< dimension_type, Linear_Form< FP_Interval_Type > > &ls2)
void expand_space_dimension(Variable var, dimension_type m)
Creates m copies of the space dimension corresponding to var.
const_iterator begin() const
Iterator pointing to the first nonzero variable coefficient.
dimension_type affine_dimension() const
Returns , if *this is empty; otherwise, returns the affine dimension of *this.
The base class for the square matrices.
void min_assign(N &x, const N &y)
Assigns to x the minimum between x and y.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
T & raw_value()
Returns a reference to the underlying numeric value.
void shortest_path_reduction_assign() const
Assigns to this->dbm its shortest-path closure and records into this->redundancy_dbm which of the ent...
bool is_line() const
Returns true if and only if *this is a line.
void add_congruences(const Congruence_System &cgs)
Adds to *this constraints equivalent to the congruences in cgs.
static Poly_Con_Relation strictly_intersects()
The polyhedron intersects the set of points satisfying the constraint, but it is not included in it...
static Poly_Gen_Relation nothing()
The assertion that says nothing.
void add_space_dimensions_and_project(dimension_type m)
Adds m new dimensions to the BDS and does not embed it in the new vector space.
void limited_BHMZ05_extrapolation_assign(const BD_Shape &y, const Constraint_System &cs, unsigned *tp=0)
Improves the result of the BHMZ05-widening computation by also enforcing those constraints in cs that...
bool le(Boundary_Type type1, const T1 &x1, const Info1 &info1, Boundary_Type type2, const T2 &x2, const Info2 &info2)
The relation between a polyhedron and a generator.
DB_Matrix< N > dbm
The matrix representing the system of bounded differences.
The problem has an optimal solution.
void set_shortest_path_reduced()
Marks *this as shortest-path closed.
The relation between a polyhedron and a constraint.
bool has_something_pending() const
Returns true if there are either pending constraints or pending generators.
bool has_strict_inequalities() const
Returns true if and only if *this contains one or more strict inequality constraints.