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"
28 #include "Generator_System_inlines.hh"
29 #include "Congruence_System_inlines.hh"
30 #include "Congruence_System_defs.hh"
31 #include "Interval_defs.hh"
32 #include "Linear_Form_defs.hh"
33 #include "Poly_Con_Relation_defs.hh"
34 #include "Poly_Gen_Relation_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>
BD_Shape(const Congruence_System & cgs)50 BD_Shape<T>::BD_Shape(const Congruence_System& cgs)
51   : dbm(cgs.space_dimension() + 1),
52     status(),
53     redundancy_dbm() {
54   add_congruences(cgs);
55 }
56 
57 template <typename T>
BD_Shape(const Generator_System & gs)58 BD_Shape<T>::BD_Shape(const Generator_System& gs)
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.
82     case Generator::CLOSURE_POINT:
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))) {
158             assign_r(dbm_i[j], PLUS_INFINITY, ROUND_NOT_NEEDED);
159           }
160         }
161         if (g_i != 0) {
162           assign_r(dbm_i[0], PLUS_INFINITY, ROUND_NOT_NEEDED);
163         }
164       }
165       for (Generator::expr_type::const_iterator i = g.expression().begin(),
166             i_end = g.expression().end(); i != i_end; ++i) {
167         assign_r(dbm_0[i.variable().space_dimension()],
168                  PLUS_INFINITY, ROUND_NOT_NEEDED);
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))) {
180             assign_r(dbm_i[j], PLUS_INFINITY, ROUND_NOT_NEEDED);
181           }
182         }
183         if (g_i < 0) {
184           assign_r(dbm_i[0], PLUS_INFINITY, ROUND_NOT_NEEDED);
185         }
186       }
187       for (Generator::expr_type::const_iterator i = g.expression().begin(),
188             i_end = g.expression().end(); i != i_end; ++i) {
189         if (*i > 0) {
190           assign_r(dbm_0[i.variable().space_dimension()],
191                    PLUS_INFINITY, ROUND_NOT_NEEDED);
192         }
193       }
194       break;
195     default:
196       // Points and closure points already dealt with.
197       break;
198     }
199   }
200   set_shortest_path_closed();
201   PPL_ASSERT(OK());
202 }
203 
204 template <typename T>
BD_Shape(const Polyhedron & ph,const Complexity_Class complexity)205 BD_Shape<T>::BD_Shape(const Polyhedron& ph, const Complexity_Class complexity)
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
222       || (!ph.has_pending_constraints() && ph.generators_are_up_to_date())) {
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 
232   if (!ph.has_something_pending() && ph.constraints_are_minimized()) {
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'.
242   for (Constraint_System::const_iterator i = ph.con_sys.begin(),
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);
254     lp.set_optimization_mode(MAXIMIZATION);
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());
285     PPL_DIRTY_TEMP_COEFFICIENT(numer);
286     PPL_DIRTY_TEMP_COEFFICIENT(denom);
287     for (dimension_type i = 1; i <= num_dimensions; ++i) {
288       Variable x(i-1);
289       // Evaluate optimal upper bound for `x <= ub'.
290       lp.set_objective_function(x);
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     }
317     set_shortest_path_closed();
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);
325   refine_with_constraints(ph.constraints());
326 }
327 
328 template <typename T>
329 dimension_type
affine_dimension() const330 BD_Shape<T>::affine_dimension() const {
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>
361 Congruence_System
minimized_congruences() const362 BD_Shape<T>::minimized_congruences() const {
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()) {
372       cgs = Congruence_System::zero_dim_empty();
373     }
374     return cgs;
375   }
376 
377   if (marked_empty()) {
378     cgs.insert(Congruence::zero_dim_false());
379     return cgs;
380   }
381 
382   PPL_DIRTY_TEMP_COEFFICIENT(numer);
383   PPL_DIRTY_TEMP_COEFFICIENT(denom);
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
add_constraint(const Constraint & c)414 BD_Shape<T>::add_constraint(const Constraint& c) {
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;
436   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
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
add_congruence(const Congruence & cg)490 BD_Shape<T>::add_congruence(const Congruence& cg) {
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
refine_no_check(const Constraint & c)518 BD_Shape<T>::refine_no_check(const Constraint& c) {
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;
525   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
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
concatenate_assign(const BD_Shape & y)579 BD_Shape<T>::concatenate_assign(const BD_Shape& y) {
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
contains(const BD_Shape & y) const625 BD_Shape<T>::contains(const BD_Shape& y) const {
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   */
663   y.shortest_path_closure_assign();
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
is_disjoint_from(const BD_Shape & y) const688 BD_Shape<T>::is_disjoint_from(const BD_Shape& y) const {
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   }
700   y.shortest_path_closure_assign();
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
is_universe() const732 BD_Shape<T>::is_universe() const {
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
is_bounded() const757 BD_Shape<T>::is_bounded() const {
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
contains_integer_point() const782 BD_Shape<T>::contains_integer_point() const {
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.
793   if (std::numeric_limits<T>::is_integer) {
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;
800   bds_z.reset_shortest_path_closed();
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
frequency(const Linear_Expression & expr,Coefficient & freq_n,Coefficient & freq_d,Coefficient & val_n,Coefficient & val_d) const829 BD_Shape<T>::frequency(const Linear_Expression& expr,
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.
861   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
862   PPL_DIRTY_TEMP_COEFFICIENT(numer);
863   PPL_DIRTY_TEMP_COEFFICIENT(denom);
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;
897       for (Linear_Expression::const_iterator j = le.begin(),
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
constrains(const Variable var) const936 BD_Shape<T>::constrains(const Variable var) const {
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
964 BD_Shape<T>
compute_predecessors(std::vector<dimension_type> & predecessor) const965 ::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
compute_leaders(std::vector<dimension_type> & leaders) const997 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
is_shortest_path_reduced() const1017 BD_Shape<T>::is_shortest_path_reduced() const {
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;
1035   x_copy.shortest_path_closure_assign();
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
bounds(const Linear_Expression & expr,const bool from_above) const1202 BD_Shape<T>::bounds(const Linear_Expression& expr,
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;
1224   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
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
max_min(const Linear_Expression & expr,const bool maximize,Coefficient & ext_n,Coefficient & ext_d,bool & included) const1247 BD_Shape<T>::max_min(const Linear_Expression& expr,
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;
1284   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
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
max_min(const Linear_Expression & expr,const bool maximize,Coefficient & ext_n,Coefficient & ext_d,bool & included,Generator & g) const1351 BD_Shape<T>::max_min(const Linear_Expression& expr,
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>
1398 Poly_Con_Relation
relation_with(const Congruence & cg) const1399 BD_Shape<T>::relation_with(const Congruence& cg) const {
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()) {
1416     return Poly_Con_Relation::saturates()
1417       && Poly_Con_Relation::is_included()
1418       && Poly_Con_Relation::is_disjoint();
1419   }
1420   if (space_dim == 0) {
1421     if (cg.is_inconsistent()) {
1422       return Poly_Con_Relation::is_disjoint();
1423     }
1424     else {
1425       return Poly_Con_Relation::saturates()
1426         && Poly_Con_Relation::is_included();
1427     }
1428   }
1429 
1430   // Find the lower bound for a hyperplane with direction
1431   // defined by the congruence.
1432   Linear_Expression le = Linear_Expression(cg.expression());
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) {
1441     return Poly_Con_Relation::strictly_intersects();
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) {
1457     return Poly_Con_Relation::strictly_intersects();
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) {
1484     return Poly_Con_Relation::is_disjoint();
1485   }
1486   else {
1487     return Poly_Con_Relation::strictly_intersects();
1488   }
1489 }
1490 
1491 
1492 template <typename T>
1493 Poly_Con_Relation
relation_with(const Constraint & c) const1494 BD_Shape<T>::relation_with(const Constraint& c) const {
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()) {
1505     return Poly_Con_Relation::saturates()
1506       && Poly_Con_Relation::is_included()
1507       && Poly_Con_Relation::is_disjoint();
1508   }
1509   if (space_dim == 0) {
1510     if ((c.is_equality() && c.inhomogeneous_term() != 0)
1511         || (c.is_inequality() && c.inhomogeneous_term() < 0)) {
1512       return Poly_Con_Relation::is_disjoint();
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.
1517       return Poly_Con_Relation::saturates()
1518         && Poly_Con_Relation::is_disjoint();
1519     }
1520     else if (c.is_equality() || c.inhomogeneous_term() == 0) {
1521       return Poly_Con_Relation::saturates()
1522         && Poly_Con_Relation::is_included();
1523     }
1524     else {
1525       // The zero-dimensional point saturates
1526       // neither the positivity constraint 1 >= 0,
1527       // nor the strict positivity constraint 1 > 0.
1528       return Poly_Con_Relation::is_included();
1529     }
1530   }
1531 
1532   dimension_type num_vars = 0;
1533   dimension_type i = 0;
1534   dimension_type j = 0;
1535   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
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.
1543     Linear_Expression le(c.expression());
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) {
1556         return Poly_Con_Relation::strictly_intersects();
1557       }
1558       min_numer += c.inhomogeneous_term() * min_denom;
1559       switch (sgn(min_numer)) {
1560       case 1:
1561         if (c.is_equality()) {
1562           return Poly_Con_Relation::is_disjoint();
1563         }
1564         return Poly_Con_Relation::is_included();
1565       case 0:
1566         if (c.is_strict_inequality() || c.is_equality()) {
1567           return Poly_Con_Relation::strictly_intersects();
1568         }
1569         return Poly_Con_Relation::is_included();
1570       case -1:
1571         return Poly_Con_Relation::strictly_intersects();
1572       }
1573     }
1574     if (!bounded_below) {
1575       max_numer += c.inhomogeneous_term() * max_denom;
1576       switch (sgn(max_numer)) {
1577       case 1:
1578         return Poly_Con_Relation::strictly_intersects();
1579       case 0:
1580         if (c.is_strict_inequality()) {
1581           return Poly_Con_Relation::is_disjoint();
1582         }
1583         return Poly_Con_Relation::strictly_intersects();
1584       case -1:
1585         return Poly_Con_Relation::is_disjoint();
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()) {
1596             return Poly_Con_Relation::is_disjoint();
1597           }
1598           return Poly_Con_Relation::is_included();
1599         case 0:
1600           if (c.is_equality()) {
1601             return Poly_Con_Relation::strictly_intersects();
1602           }
1603           if (c.is_strict_inequality()) {
1604             return Poly_Con_Relation::strictly_intersects();
1605           }
1606           return Poly_Con_Relation::is_included();
1607         case -1:
1608           return Poly_Con_Relation::strictly_intersects();
1609         }
1610         PPL_UNREACHABLE;
1611         break;
1612       case 0:
1613         if (min_numer == 0) {
1614           if (c.is_strict_inequality()) {
1615             return Poly_Con_Relation::is_disjoint()
1616               && Poly_Con_Relation::saturates();
1617           }
1618           return Poly_Con_Relation::is_included()
1619             && Poly_Con_Relation::saturates();
1620         }
1621         if (c.is_strict_inequality()) {
1622           return Poly_Con_Relation::is_disjoint();
1623         }
1624         return Poly_Con_Relation::strictly_intersects();
1625       case -1:
1626         return Poly_Con_Relation::is_disjoint();
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:
1636       return Poly_Con_Relation::is_disjoint();
1637     case 0:
1638       if (c.is_strict_inequality()) {
1639         return Poly_Con_Relation::saturates()
1640           && Poly_Con_Relation::is_disjoint();
1641       }
1642       else {
1643         return Poly_Con_Relation::saturates()
1644           && Poly_Con_Relation::is_included();
1645       }
1646     case 1:
1647       if (c.is_equality()) {
1648         return Poly_Con_Relation::is_disjoint();
1649       }
1650       else {
1651         return Poly_Con_Relation::is_included();
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);
1679   assign_r(d, c.inhomogeneous_term(), 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).
1691       PPL_DIRTY_TEMP_COEFFICIENT(numer);
1692       PPL_DIRTY_TEMP_COEFFICIENT(denom);
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) {
1698         return Poly_Con_Relation::is_disjoint();
1699       }
1700       if (q_y == d1 && c.is_strict_inequality()) {
1701         return Poly_Con_Relation::is_disjoint();
1702       }
1703     }
1704 
1705     // In all other cases `*this' intersects `c'.
1706     return Poly_Con_Relation::strictly_intersects();
1707   }
1708 
1709   // Here `x' is not plus-infinity.
1710   PPL_DIRTY_TEMP_COEFFICIENT(numer);
1711   PPL_DIRTY_TEMP_COEFFICIENT(denom);
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()) {
1724         return Poly_Con_Relation::saturates()
1725           && Poly_Con_Relation::is_disjoint();
1726       }
1727       else {
1728         return Poly_Con_Relation::saturates()
1729           && Poly_Con_Relation::is_included();
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) {
1736       return Poly_Con_Relation::is_disjoint();
1737     }
1738     if (q_y == d1 && c.is_strict_inequality()) {
1739       return Poly_Con_Relation::is_disjoint();
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()) {
1748       return Poly_Con_Relation::is_disjoint();
1749     }
1750     else {
1751       return Poly_Con_Relation::is_included();
1752     }
1753   }
1754 
1755   if (d == q_x && c.is_nonstrict_inequality()) {
1756     return Poly_Con_Relation::is_included();
1757   }
1758   // In all other cases `*this' intersects `c'.
1759   return Poly_Con_Relation::strictly_intersects();
1760 }
1761 
1762 template <typename T>
1763 Poly_Gen_Relation
relation_with(const Generator & g) const1764 BD_Shape<T>::relation_with(const Generator& g) const {
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.
1792   PPL_DIRTY_TEMP_COEFFICIENT(numer);
1793   PPL_DIRTY_TEMP_COEFFICIENT(denom);
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
shortest_path_closure_assign() const1880 BD_Shape<T>::shortest_path_closure_assign() const {
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.
1930       assign_r(x_dbm_hh, PLUS_INFINITY, ROUND_NOT_NEEDED);
1931     }
1932   }
1933 
1934   // The BDS is not empty and it is now shortest-path closed.
1935   x.set_shortest_path_closed();
1936 }
1937 
1938 template <typename T>
1939 void
incremental_shortest_path_closure_assign(Variable var) const1940 BD_Shape<T>::incremental_shortest_path_closure_assign(Variable var) const {
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.
2042       assign_r(x_dbm_hh, PLUS_INFINITY, ROUND_NOT_NEEDED);
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
shortest_path_reduction_assign() const2052 BD_Shape<T>::shortest_path_reduction_assign() const {
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);
2145   x.set_shortest_path_reduced();
2146 
2147   PPL_ASSERT(is_shortest_path_reduced());
2148 }
2149 
2150 template <typename T>
2151 void
upper_bound_assign(const BD_Shape & y)2152 BD_Shape<T>::upper_bound_assign(const BD_Shape& y) {
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'.
2160   y.shortest_path_closure_assign();
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
BFT00_upper_bound_assign_if_exact(const BD_Shape & y)2194 BD_Shape<T>::BFT00_upper_bound_assign_if_exact(const BD_Shape& y) {
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;
2228   PPL_DIRTY_TEMP_COEFFICIENT(numer);
2229   PPL_DIRTY_TEMP_COEFFICIENT(denom);
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;
2238   x.shortest_path_reduction_assign();
2239   y.shortest_path_reduction_assign();
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()) {
2338       case UNFEASIBLE_MIP_PROBLEM:
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
BHZ09_upper_bound_assign_if_exact(const BD_Shape & y)2363 BD_Shape<T>::BHZ09_upper_bound_assign_if_exact(const BD_Shape& y) {
2364   PPL_COMPILE_TIME_CHECK(!integer_upper_bound
2365                          || std::numeric_limits<T>::is_integer,
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.
2397   x.shortest_path_reduction_assign();
2398   y.shortest_path_reduction_assign();
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
difference_assign(const BD_Shape & y)2470 BD_Shape<T>::difference_assign(const BD_Shape& y) {
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 
2481   x.shortest_path_closure_assign();
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   }
2487   y.shortest_path_closure_assign();
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.
2521     if (x.relation_with(c).implies(Poly_Con_Relation::is_included())) {
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
simplify_using_context_assign(const BD_Shape & y)2544 BD_Shape<T>::simplify_using_context_assign(const BD_Shape& y) {
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).
2564   y.shortest_path_closure_assign();
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.
2572   x.shortest_path_closure_assign();
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 ...
2635   x.shortest_path_reduction_assign();
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];
2673       yy.reset_shortest_path_closed();
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];
2681       yy.reset_shortest_path_closed();
2682     }
2683     // Restore shortest-path closure, if it was lost.
2684     if (!yy.marked_shortest_path_closed()) {
2685       Variable var_j(j-1);
2686       yy.incremental_shortest_path_closure_assign(var_j);
2687       if (target.contains(yy)) {
2688         // Target reached: swap `x' and `res' if needed.
2689         if (res_num_non_redundant < x_num_non_redundant) {
2690           res.reset_shortest_path_closed();
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];
2711       yy.reset_shortest_path_closed();
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];
2719       yy.reset_shortest_path_closed();
2720     }
2721     // Restore shortest-path closure, if it was lost.
2722     if (!yy.marked_shortest_path_closed()) {
2723       Variable var_j(j-1);
2724       yy.incremental_shortest_path_closure_assign(var_j);
2725       if (target.contains(yy)) {
2726         // Target reached: swap `x' and `res' if needed.
2727         if (res_num_non_redundant < x_num_non_redundant) {
2728           res.reset_shortest_path_closed();
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;
2757         yy.reset_shortest_path_closed();
2758         PPL_ASSERT(i > 0 || j > 0);
2759         Variable var(((i > 0) ? i : j) - 1);
2760         yy.incremental_shortest_path_closure_assign(var);
2761         if (target.contains(yy)) {
2762           // Target reached: swap `x' and `res' if needed.
2763           if (res_num_non_redundant < x_num_non_redundant) {
2764             res.reset_shortest_path_closed();
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
add_space_dimensions_and_embed(const dimension_type m)2779 BD_Shape<T>::add_space_dimensions_and_embed(const dimension_type m) {
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
add_space_dimensions_and_project(const dimension_type m)2808 BD_Shape<T>::add_space_dimensions_and_project(const dimension_type m) {
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
remove_space_dimensions(const Variables_Set & vars)2857 BD_Shape<T>::remove_space_dimensions(const Variables_Set& vars) {
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
map_space_dimensions(const Partial_Function & pfunc)2945 BD_Shape<T>::map_space_dimensions(const Partial_Function& pfunc) {
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
intersection_assign(const BD_Shape & y)3014 BD_Shape<T>::intersection_assign(const BD_Shape& y) {
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
CC76_extrapolation_assign(const BD_Shape & y,Iterator first,Iterator last,unsigned * tp)3062 BD_Shape<T>::CC76_extrapolation_assign(const BD_Shape& y,
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   }
3084   y.shortest_path_closure_assign();
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 {
3122           assign_r(dbm_ij, PLUS_INFINITY, ROUND_NOT_NEEDED);
3123         }
3124       }
3125     }
3126   }
3127   reset_shortest_path_closed();
3128   PPL_ASSERT(OK());
3129 }
3130 
3131 template <typename T>
3132 void
get_limiting_shape(const Constraint_System & cs,BD_Shape & limiting_shape) const3133 BD_Shape<T>::get_limiting_shape(const Constraint_System& cs,
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;
3140   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
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
limited_CC76_extrapolation_assign(const BD_Shape & y,const Constraint_System & cs,unsigned * tp)3198 BD_Shape<T>::limited_CC76_extrapolation_assign(const BD_Shape& y,
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
BHMZ05_widening_assign(const BD_Shape & y,unsigned * tp)3245 BD_Shape<T>::BHMZ05_widening_assign(const BD_Shape& y, unsigned* tp) {
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'.
3284   y.shortest_path_reduction_assign();
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) {
3297         assign_r(dbm_ij, PLUS_INFINITY, ROUND_NOT_NEEDED);
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
limited_BHMZ05_extrapolation_assign(const BD_Shape & y,const Constraint_System & cs,unsigned * tp)3311 BD_Shape<T>::limited_BHMZ05_extrapolation_assign(const BD_Shape& y,
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
CC76_narrowing_assign(const BD_Shape & y)3357 BD_Shape<T>::CC76_narrowing_assign(const BD_Shape& y) {
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   }
3372   y.shortest_path_closure_assign();
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
3407 BD_Shape<T>
deduce_v_minus_u_bounds(const dimension_type v,const dimension_type last_v,const Linear_Expression & sc_expr,Coefficient_traits::const_reference sc_denom,const N & ub_v)3408 ::deduce_v_minus_u_bounds(const dimension_type v,
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
3474 BD_Shape<T>
deduce_u_minus_v_bounds(const dimension_type v,const dimension_type last_v,const Linear_Expression & sc_expr,Coefficient_traits::const_reference sc_denom,const N & minus_lb_v)3475 ::deduce_u_minus_v_bounds(const dimension_type v,
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
forget_all_dbm_constraints(const dimension_type v)3544 BD_Shape<T>::forget_all_dbm_constraints(const dimension_type v) {
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; ) {
3548     assign_r(dbm_v[i], PLUS_INFINITY, ROUND_NOT_NEEDED);
3549     assign_r(dbm[i][v], PLUS_INFINITY, ROUND_NOT_NEEDED);
3550   }
3551 }
3552 
3553 template <typename T>
3554 void
forget_binary_dbm_constraints(const dimension_type v)3555 BD_Shape<T>::forget_binary_dbm_constraints(const dimension_type v) {
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) {
3559     assign_r(dbm_v[i], PLUS_INFINITY, ROUND_NOT_NEEDED);
3560     assign_r(dbm[i][v], PLUS_INFINITY, ROUND_NOT_NEEDED);
3561   }
3562 }
3563 
3564 template <typename T>
3565 void
unconstrain(const Variable var)3566 BD_Shape<T>::unconstrain(const Variable var) {
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
unconstrain(const Variables_Set & vars)3588 BD_Shape<T>::unconstrain(const Variables_Set& vars) {
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
refine(const Variable var,const Relation_Symbol relsym,const Linear_Expression & expr,Coefficient_traits::const_reference denominator)3618 BD_Shape<T>::refine(const Variable var,
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
affine_image(const Variable var,const Linear_Expression & expr,Coefficient_traits::const_reference denominator)4025 BD_Shape<T>::affine_image(const Variable var,
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
affine_form_image(const Variable var,const Linear_Form<Interval<T,Interval_Info>> & lf)4369 BD_Shape<T>::affine_form_image(const Variable var,
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
4442 BD_Shape<T>
inhomogeneous_affine_form_image(const dimension_type & var_id,const Interval<T,Interval_Info> & b)4443 ::inhomogeneous_affine_form_image(const dimension_type& var_id,
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>
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)4467 ::one_variable_affine_form_image(const dimension_type& var_id,
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>
two_variables_affine_form_image(const dimension_type & var_id,const Linear_Form<Interval<T,Interval_Info>> & lf,const dimension_type & space_dim)4563 ::two_variables_affine_form_image(const dimension_type& var_id,
4564            const Linear_Form< Interval<T, Interval_Info> >& lf,
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 
4572   Linear_Form< Interval<T, Interval_Info> > minus_lf(lf);
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>
refine_with_linear_form_inequality(const Linear_Form<Interval<T,Interval_Info>> & left,const Linear_Form<Interval<T,Interval_Info>> & right)4605 void BD_Shape<T>::refine_with_linear_form_inequality(
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
4703 BD_Shape<T>
export_interval_constraints(U & dest) const4704 ::export_interval_constraints(U& dest) const {
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
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)4746 BD_Shape<T>::left_inhomogeneous_refine(const dimension_type& right_t,
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
4784 BD_Shape<T>
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)4785 ::left_one_var_refine(const dimension_type& left_w_id,
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
4936 BD_Shape<T>
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)4937 ::general_refine(const dimension_type& left_w_id,
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
5054 BD_Shape<T>::
linear_form_upper_bound(const Linear_Form<Interval<T,Interval_Info>> & lf,N & result) const5055 linear_form_upper_bound(const Linear_Form< Interval<T, Interval_Info> >& lf,
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),
5097                      ROUND_NOT_NEEDED);
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),
5110                  ROUND_NOT_NEEDED);
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),
5116                  ROUND_NOT_NEEDED);
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),
5122                  ROUND_NOT_NEEDED);
5123 
5124         add_assign_r(result, result, first_comparison_term, ROUND_UP);
5125       }
5126     }
5127   }
5128 }
5129 
5130 template <typename T>
5131 void
affine_preimage(const Variable var,const Linear_Expression & expr,Coefficient_traits::const_reference denominator)5132 BD_Shape<T>::affine_preimage(const Variable var,
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
5237 BD_Shape<T>
bounded_affine_image(const Variable var,const Linear_Expression & lb_expr,const Linear_Expression & ub_expr,Coefficient_traits::const_reference denominator)5238 ::bounded_affine_image(const Variable var,
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,
5298                              GREATER_OR_EQUAL,
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,
5324                                  GREATER_OR_EQUAL,
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,
5338                                  GREATER_OR_EQUAL,
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,
5443                            GREATER_OR_EQUAL,
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
5486 BD_Shape<T>
bounded_affine_preimage(const Variable var,const Linear_Expression & lb_expr,const Linear_Expression & ub_expr,Coefficient_traits::const_reference denominator)5487 ::bounded_affine_preimage(const Variable var,
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
generalized_affine_image(const Variable var,const Relation_Symbol relsym,const Linear_Expression & expr,Coefficient_traits::const_reference denominator)5559 BD_Shape<T>::generalized_affine_image(const Variable var,
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);
5676               assign_r(dbm_v[i], PLUS_INFINITY, ROUND_NOT_NEEDED);
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'.
5686             assign_r(dbm_v0, PLUS_INFINITY, ROUND_NOT_NEEDED);
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);
5731               assign_r(dbm[i][v], PLUS_INFINITY, ROUND_NOT_NEEDED);
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'.
5741             assign_r(dbm_0v, PLUS_INFINITY, ROUND_NOT_NEEDED);
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
generalized_affine_image(const Linear_Expression & lhs,const Relation_Symbol relsym,const Linear_Expression & rhs)5975 BD_Shape<T>::generalized_affine_image(const Linear_Expression& lhs,
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
generalized_affine_preimage(const Variable var,const Relation_Symbol relsym,const Linear_Expression & expr,Coefficient_traits::const_reference denominator)6163 BD_Shape<T>::generalized_affine_preimage(const Variable var,
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)
6215       ? GREATER_OR_EQUAL : LESS_OR_EQUAL;
6216     const Linear_Expression inverse
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
generalized_affine_preimage(const Linear_Expression & lhs,const Relation_Symbol relsym,const Linear_Expression & rhs)6243 BD_Shape<T>::generalized_affine_preimage(const Linear_Expression& lhs,
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>
6408 Constraint_System
constraints() const6409 BD_Shape<T>::constraints() const {
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()) {
6416       cs = Constraint_System::zero_dim_empty();
6417     }
6418     return cs;
6419   }
6420 
6421   if (marked_empty()) {
6422     cs.insert(Constraint::zero_dim_false());
6423     return cs;
6424   }
6425 
6426   if (marked_shortest_path_reduced()) {
6427     // Disregard redundant constraints.
6428     cs = minimized_constraints();
6429     return cs;
6430   }
6431 
6432   PPL_DIRTY_TEMP_COEFFICIENT(a);
6433   PPL_DIRTY_TEMP_COEFFICIENT(b);
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>
6488 Constraint_System
minimized_constraints() const6489 BD_Shape<T>::minimized_constraints() const {
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()) {
6497       cs = Constraint_System::zero_dim_empty();
6498     }
6499     return cs;
6500   }
6501 
6502   if (marked_empty()) {
6503     cs.insert(Constraint::zero_dim_false());
6504     return cs;
6505   }
6506 
6507   PPL_DIRTY_TEMP_COEFFICIENT(numer);
6508   PPL_DIRTY_TEMP_COEFFICIENT(denom);
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
expand_space_dimension(Variable var,dimension_type m)6574 BD_Shape<T>::expand_space_dimension(Variable var, dimension_type m) {
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
fold_space_dimensions(const Variables_Set & vars,Variable dest)6619 BD_Shape<T>::fold_space_dimensions(const Variables_Set& vars,
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
drop_some_non_integer_points(Complexity_Class)6664 BD_Shape<T>::drop_some_non_integer_points(Complexity_Class) {
6665   if (std::numeric_limits<T>::is_integer) {
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
drop_some_non_integer_points(const Variables_Set & vars,Complexity_Class)6686 BD_Shape<T>::drop_some_non_integer_points(const Variables_Set& vars,
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 
6727 /*! \relates Parma_Polyhedra_Library::BD_Shape */
6728 template <typename T>
6729 std::ostream&
operator <<(std::ostream & s,const BD_Shape<T> & bds)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
ascii_dump(std::ostream & s) const6848 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 
PPL_OUTPUT_TEMPLATE_DEFINITIONS(T,BD_Shape<T>)6856 PPL_OUTPUT_TEMPLATE_DEFINITIONS(T, BD_Shape<T>)
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>
6874 memory_size_type
external_memory_in_bytes() const6875 BD_Shape<T>::external_memory_in_bytes() const {
6876   return dbm.external_memory_in_bytes()
6877     + redundancy_dbm.external_memory_in_bytes();
6878 }
6879 
6880 template <typename T>
6881 bool
OK() const6882 BD_Shape<T>::OK() const {
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;
6924     x.reset_shortest_path_closed();
6925     x.shortest_path_closure_assign();
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;
6957       x.reset_shortest_path_reduced();
6958       x.shortest_path_reduction_assign();
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
throw_dimension_incompatible(const char * method,const BD_Shape & y) const6975 BD_Shape<T>::throw_dimension_incompatible(const char* method,
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
throw_dimension_incompatible(const char * method,dimension_type required_dim) const6986 BD_Shape<T>::throw_dimension_incompatible(const char* method,
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
throw_dimension_incompatible(const char * method,const Constraint & c) const6997 BD_Shape<T>::throw_dimension_incompatible(const char* method,
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
throw_dimension_incompatible(const char * method,const Congruence & cg) const7008 BD_Shape<T>::throw_dimension_incompatible(const char* method,
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
throw_dimension_incompatible(const char * method,const Generator & g) const7019 BD_Shape<T>::throw_dimension_incompatible(const char* method,
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
throw_expression_too_complex(const char * method,const Linear_Expression & le)7030 BD_Shape<T>::throw_expression_too_complex(const char* method,
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
throw_dimension_incompatible(const char * method,const char * le_name,const Linear_Expression & le) const7042 BD_Shape<T>::throw_dimension_incompatible(const char* method,
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
throw_dimension_incompatible(const char * method,const char * lf_name,const Linear_Form<Interval<T,Interval_Info>> & lf) const7056 BD_Shape<T>::throw_dimension_incompatible(const char* method,
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
throw_invalid_argument(const char * method,const char * reason)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)
7080