1 /* Octagonal_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_Octagonal_Shape_templates_hh
25 #define PPL_Octagonal_Shape_templates_hh 1
26 
27 #include "Generator_System_defs.hh"
28 #include "Generator_System_inlines.hh"
29 #include "Congruence_System_defs.hh"
30 #include "Congruence_System_inlines.hh"
31 #include "Interval_defs.hh"
32 #include "Linear_Form_defs.hh"
33 #include "meta_programming.hh"
34 #include "assertions.hh"
35 #include <vector>
36 #include <deque>
37 #include <string>
38 #include <iostream>
39 #include <sstream>
40 #include <stdexcept>
41 #include <algorithm>
42 
43 namespace Parma_Polyhedra_Library {
44 
45 template <typename T>
Octagonal_Shape(const Polyhedron & ph,const Complexity_Class complexity)46 Octagonal_Shape<T>::Octagonal_Shape(const Polyhedron& ph,
47                                     const Complexity_Class complexity)
48   : matrix(0), space_dim(0), status() {
49   const dimension_type num_dimensions = ph.space_dimension();
50 
51   if (ph.marked_empty()) {
52     *this = Octagonal_Shape(num_dimensions, EMPTY);
53     return;
54   }
55 
56   if (num_dimensions == 0) {
57     *this = Octagonal_Shape(num_dimensions, UNIVERSE);
58     return;
59   }
60 
61   // Build from generators when we do not care about complexity
62   // or when the process has polynomial complexity.
63   if (complexity == ANY_COMPLEXITY
64       || (!ph.has_pending_constraints() && ph.generators_are_up_to_date())) {
65     *this = Octagonal_Shape(ph.generators());
66     return;
67   }
68 
69   // We cannot afford exponential complexity, we do not have a complete set
70   // of generators for the polyhedron, and the polyhedron is not trivially
71   // empty or zero-dimensional.  Constraints, however, are up to date.
72   PPL_ASSERT(ph.constraints_are_up_to_date());
73 
74   if (!ph.has_something_pending() && ph.constraints_are_minimized()) {
75     // If the constraint system of the polyhedron is minimized,
76     // the test `is_universe()' has polynomial complexity.
77     if (ph.is_universe()) {
78       *this = Octagonal_Shape(num_dimensions, UNIVERSE);
79       return;
80     }
81   }
82 
83   // See if there is at least one inconsistent constraint in `ph.con_sys'.
84   for (Constraint_System::const_iterator i = ph.con_sys.begin(),
85          cs_end = ph.con_sys.end(); i != cs_end; ++i) {
86     if (i->is_inconsistent()) {
87       *this = Octagonal_Shape(num_dimensions, EMPTY);
88       return;
89     }
90   }
91 
92   // If `complexity' allows it, use simplex to derive the exact (modulo
93   // the fact that our OSs are topologically closed) variable bounds.
94   if (complexity == SIMPLEX_COMPLEXITY) {
95     MIP_Problem lp(num_dimensions);
96     lp.set_optimization_mode(MAXIMIZATION);
97 
98     const Constraint_System& ph_cs = ph.constraints();
99     if (!ph_cs.has_strict_inequalities()) {
100       lp.add_constraints(ph_cs);
101     }
102     else {
103       // Adding to `lp' a topologically closed version of `ph_cs'.
104       for (Constraint_System::const_iterator i = ph_cs.begin(),
105              ph_cs_end = ph_cs.end(); i != ph_cs_end; ++i) {
106         const Constraint& c = *i;
107         if (c.is_strict_inequality()) {
108           Linear_Expression expr(c.expression());
109           lp.add_constraint(expr >= 0);
110         }
111         else {
112           lp.add_constraint(c);
113         }
114       }
115     }
116 
117     // Check for unsatisfiability.
118     if (!lp.is_satisfiable()) {
119       *this = Octagonal_Shape<T>(num_dimensions, EMPTY);
120       return;
121     }
122 
123     // Start with a universe OS that will be refined by the simplex.
124     *this = Octagonal_Shape<T>(num_dimensions, UNIVERSE);
125     // Get all the upper bounds.
126     Generator g(point());
127     PPL_DIRTY_TEMP_COEFFICIENT(numer);
128     PPL_DIRTY_TEMP_COEFFICIENT(denom);
129     for (dimension_type i = 0; i < num_dimensions; ++i) {
130       Variable x(i);
131       // Evaluate optimal upper bound for `x <= ub'.
132       lp.set_objective_function(x);
133       if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
134         g = lp.optimizing_point();
135         lp.evaluate_objective_function(g, numer, denom);
136         numer *= 2;
137         div_round_up(matrix[2*i + 1][2*i], numer, denom);
138       }
139       // Evaluate optimal upper bounds for `x + y <= ub'.
140       for (dimension_type j = 0; j < i; ++j) {
141         Variable y(j);
142         lp.set_objective_function(x + y);
143         if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
144           g = lp.optimizing_point();
145           lp.evaluate_objective_function(g, numer, denom);
146           div_round_up(matrix[2*i + 1][2*j], numer, denom);
147         }
148       }
149       // Evaluate optimal upper bound for `x - y <= ub'.
150       for (dimension_type j = 0; j < num_dimensions; ++j) {
151         if (i == j) {
152           continue;
153         }
154         Variable y(j);
155         lp.set_objective_function(x - y);
156         if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
157           g = lp.optimizing_point();
158           lp.evaluate_objective_function(g, numer, denom);
159           div_round_up(((i < j) ?
160                         matrix[2*j][2*i]
161                         : matrix[2*i + 1][2*j + 1]),
162                        numer, denom);
163         }
164       }
165       // Evaluate optimal upper bound for `y - x <= ub'.
166       for (dimension_type j = 0; j < num_dimensions; ++j) {
167         if (i == j) {
168           continue;
169         }
170         Variable y(j);
171         lp.set_objective_function(x - y);
172         if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
173           g = lp.optimizing_point();
174           lp.evaluate_objective_function(g, numer, denom);
175           div_round_up(((i < j)
176                         ? matrix[2*j][2*i]
177                         : matrix[2*i + 1][2*j + 1]),
178                        numer, denom);
179         }
180       }
181       // Evaluate optimal upper bound for `-x - y <= ub'.
182       for (dimension_type j = 0; j < i; ++j) {
183         Variable y(j);
184         lp.set_objective_function(-x - y);
185         if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
186           g = lp.optimizing_point();
187           lp.evaluate_objective_function(g, numer, denom);
188           div_round_up(matrix[2*i][2*j + 1], numer, denom);
189         }
190       }
191       // Evaluate optimal upper bound for `-x <= ub'.
192       lp.set_objective_function(-x);
193       if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
194         g = lp.optimizing_point();
195         lp.evaluate_objective_function(g, numer, denom);
196         numer *= 2;
197         div_round_up(matrix[2*i][2*i + 1], numer, denom);
198       }
199     }
200     set_strongly_closed();
201     PPL_ASSERT(OK());
202     return;
203   }
204 
205   // Extract easy-to-find bounds from constraints.
206   PPL_ASSERT(complexity == POLYNOMIAL_COMPLEXITY);
207   *this = Octagonal_Shape(num_dimensions, UNIVERSE);
208   refine_with_constraints(ph.constraints());
209 }
210 
211 template <typename T>
Octagonal_Shape(const Generator_System & gs)212 Octagonal_Shape<T>::Octagonal_Shape(const Generator_System& gs)
213   : matrix(gs.space_dimension()),
214     space_dim(gs.space_dimension()),
215     status() {
216   const Generator_System::const_iterator gs_begin = gs.begin();
217   const Generator_System::const_iterator gs_end = gs.end();
218   if (gs_begin == gs_end) {
219     // An empty generator system defines the empty polyhedron.
220     set_empty();
221     return;
222   }
223 
224   typedef typename OR_Matrix<N>::row_reference_type row_reference;
225   typename OR_Matrix<N>::row_iterator mat_begin = matrix.row_begin();
226 
227   PPL_DIRTY_TEMP(N, tmp);
228   bool mat_initialized = false;
229   bool point_seen = false;
230   // Going through all the points and closure points.
231   for (Generator_System::const_iterator k = gs_begin; k != gs_end; ++k) {
232     const Generator& g = *k;
233     switch (g.type()) {
234     case Generator::POINT:
235       point_seen = true;
236       // Intentionally fall through.
237     case Generator::CLOSURE_POINT:
238       if (!mat_initialized) {
239         // When handling the first (closure) point, we initialize the matrix.
240         mat_initialized = true;
241         const Coefficient& d = g.divisor();
242         // TODO: This can be optimized more, if needed, exploiting the
243         // (possible) sparseness of g. Also consider if OR_Matrix should be
244         // sparse, too.
245         for (dimension_type i = 0; i < space_dim; ++i) {
246           const Coefficient& g_i = g.coefficient(Variable(i));
247           const dimension_type di = 2*i;
248           row_reference x_i = *(mat_begin + di);
249           row_reference x_ii = *(mat_begin + (di + 1));
250           for (dimension_type j = 0; j < i; ++j) {
251             const Coefficient& g_j = g.coefficient(Variable(j));
252             const dimension_type dj = 2*j;
253             // Set for any point the hyperplanes passing in the point
254             // and having the octagonal gradient.
255             // Let be P = [P_1, P_2, ..., P_n] point.
256             // Hyperplanes: X_i - X_j = P_i - P_j.
257             div_round_up(x_i[dj], g_j - g_i, d);
258             div_round_up(x_ii[dj + 1], g_i - g_j, d);
259             // Hyperplanes: X_i + X_j = P_i + P_j.
260             div_round_up(x_i[dj + 1], -g_j - g_i, d);
261             div_round_up(x_ii[dj], g_i + g_j, d);
262           }
263           // Hyperplanes: X_i = P_i.
264           div_round_up(x_i[di + 1], -g_i - g_i, d);
265           div_round_up(x_ii[di], g_i + g_i, d);
266         }
267       }
268       else {
269         // This is not the first point: the matrix already contains
270         // valid values and we must compute maxima.
271         const Coefficient& d = g.divisor();
272         // TODO: This can be optimized more, if needed, exploiting the
273         // (possible) sparseness of g. Also consider if OR_Matrix should be
274         // sparse, too.
275         for (dimension_type i = 0; i < space_dim; ++i) {
276           const Coefficient& g_i = g.coefficient(Variable(i));
277           const dimension_type di = 2*i;
278           row_reference x_i = *(mat_begin + di);
279           row_reference x_ii = *(mat_begin + (di + 1));
280           for (dimension_type j = 0; j < i; ++j) {
281             const Coefficient& g_j = g.coefficient(Variable(j));
282             const dimension_type dj = 2*j;
283             // Set for any point the straight lines passing in the point
284             // and having the octagonal gradient; compute maxima values.
285             // Let be P = [P_1, P_2, ..., P_n] point.
286             // Hyperplane: X_i - X_j = max (P_i - P_j, const).
287             div_round_up(tmp, g_j - g_i, d);
288             max_assign(x_i[dj], tmp);
289             div_round_up(tmp, g_i - g_j, d);
290             max_assign(x_ii[dj + 1], tmp);
291             // Hyperplane: X_i + X_j = max (P_i + P_j, const).
292             div_round_up(tmp, -g_j - g_i, d);
293             max_assign(x_i[dj + 1], tmp);
294             div_round_up(tmp, g_i + g_j, d);
295             max_assign(x_ii[dj], tmp);
296           }
297           // Hyperplane: X_i = max (P_i, const).
298           div_round_up(tmp, -g_i - g_i, d);
299           max_assign(x_i[di + 1], tmp);
300           div_round_up(tmp, g_i + g_i, d);
301           max_assign(x_ii[di], tmp);
302         }
303       }
304       break;
305     default:
306       // Lines and rays temporarily ignored.
307       break;
308     }
309   }
310 
311   if (!point_seen) {
312     // The generator system is not empty, but contains no points.
313     throw_invalid_argument("Octagonal_Shape(gs)",
314                            "the non-empty generator system gs "
315                            "contains no points.");
316   }
317 
318   // Going through all the lines and rays.
319   for (Generator_System::const_iterator k = gs_begin; k != gs_end; ++k) {
320     const Generator& g = *k;
321     switch (g.type()) {
322     case Generator::LINE:
323         // TODO: This can be optimized more, if needed, exploiting the
324         // (possible) sparseness of g. Also consider if OR_Matrix should be
325         // sparse, too.
326         for (dimension_type i = 0; i < space_dim; ++i) {
327           const Coefficient& g_i = g.coefficient(Variable(i));
328           const dimension_type di = 2*i;
329           row_reference x_i = *(mat_begin + di);
330           row_reference x_ii = *(mat_begin + (di + 1));
331           for (dimension_type j = 0; j < i; ++j) {
332             const Coefficient& g_j = g.coefficient(Variable(j));
333             const dimension_type dj = 2*j;
334             // Set for any line the right limit.
335             if (g_i != g_j) {
336               // Hyperplane: X_i - X_j <=/>= +Inf.
337               assign_r(x_i[dj], PLUS_INFINITY, ROUND_NOT_NEEDED);
338               assign_r(x_ii[dj + 1], PLUS_INFINITY, ROUND_NOT_NEEDED);
339             }
340             if (g_i != -g_j) {
341               // Hyperplane: X_i + X_j <=/>= +Inf.
342               assign_r(x_i[dj + 1], PLUS_INFINITY, ROUND_NOT_NEEDED);
343               assign_r(x_ii[dj], PLUS_INFINITY, ROUND_NOT_NEEDED);
344             }
345           }
346           if (g_i != 0) {
347             // Hyperplane: X_i <=/>= +Inf.
348             assign_r(x_i[di + 1], PLUS_INFINITY, ROUND_NOT_NEEDED);
349             assign_r(x_ii[di], PLUS_INFINITY, ROUND_NOT_NEEDED);
350           }
351         }
352       break;
353     case Generator::RAY:
354         // TODO: This can be optimized more, if needed, exploiting the
355         // (possible) sparseness of g. Also consider if OR_Matrix should be
356         // sparse, too.
357         for (dimension_type i = 0; i < space_dim; ++i) {
358           const Coefficient& g_i = g.coefficient(Variable(i));
359           const dimension_type di = 2*i;
360           row_reference x_i = *(mat_begin + di);
361           row_reference x_ii = *(mat_begin + (di + 1));
362           for (dimension_type j = 0; j < i; ++j) {
363             const Coefficient& g_j = g.coefficient(Variable(j));
364             const dimension_type dj = 2*j;
365             // Set for any ray the right limit in the case
366             // of the binary constraints.
367             if (g_i < g_j) {
368               // Hyperplane: X_i - X_j >= +Inf.
369               assign_r(x_i[dj], PLUS_INFINITY, ROUND_NOT_NEEDED);
370             }
371             if (g_i > g_j) {
372               // Hyperplane: X_i - X_j <= +Inf.
373               assign_r(x_ii[dj + 1], PLUS_INFINITY, ROUND_NOT_NEEDED);
374             }
375             if (g_i < -g_j) {
376               // Hyperplane: X_i + X_j >= +Inf.
377               assign_r(x_i[dj + 1], PLUS_INFINITY, ROUND_NOT_NEEDED);
378             }
379             if (g_i > -g_j) {
380               // Hyperplane: X_i + X_j <= +Inf.
381               assign_r(x_ii[dj], PLUS_INFINITY, ROUND_NOT_NEEDED);
382             }
383           }
384           // Case: unary constraints.
385           if (g_i < 0) {
386             // Hyperplane: X_i  = +Inf.
387             assign_r(x_i[di + 1], PLUS_INFINITY, ROUND_NOT_NEEDED);
388           }
389           if (g_i > 0) {
390             // Hyperplane: X_i  = +Inf.
391             assign_r(x_ii[di], PLUS_INFINITY, ROUND_NOT_NEEDED);
392           }
393         }
394       break;
395     default:
396       // Points and closure points already dealt with.
397       break;
398     }
399   }
400   set_strongly_closed();
401   PPL_ASSERT(OK());
402 }
403 
404 template <typename T>
405 void
add_constraint(const Constraint & c)406 Octagonal_Shape<T>::add_constraint(const Constraint& c) {
407   const dimension_type c_space_dim = c.space_dimension();
408   // Dimension-compatibility check.
409   if (c_space_dim > space_dim) {
410     throw_dimension_incompatible("add_constraint(c)", c);
411   }
412   // Get rid of strict inequalities.
413   if (c.is_strict_inequality()) {
414     if (c.is_inconsistent()) {
415       set_empty();
416       return;
417     }
418     if (c.is_tautological()) {
419       return;
420     }
421     // Nontrivial strict inequalities are not allowed.
422     throw_invalid_argument("add_constraint(c)",
423                            "strict inequalities are not allowed");
424   }
425 
426   dimension_type num_vars = 0;
427   dimension_type i = 0;
428   dimension_type j = 0;
429   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
430   PPL_DIRTY_TEMP_COEFFICIENT(term);
431   // Constraints that are not octagonal differences are not allowed.
432   if (!Octagonal_Shape_Helper
433     ::extract_octagonal_difference(c, c_space_dim, num_vars,
434                                    i, j, coeff, term)) {
435     throw_invalid_argument("add_constraint(c)",
436                            "c is not an octagonal constraint");
437   }
438 
439   if (num_vars == 0) {
440     // Dealing with a trivial constraint (not a strict inequality).
441     if (c.inhomogeneous_term() < 0
442         || (c.is_equality() && c.inhomogeneous_term() != 0)) {
443       set_empty();
444     }
445     return;
446   }
447 
448   // Select the cell to be modified for the "<=" part of constraint.
449   typename OR_Matrix<N>::row_iterator i_iter = matrix.row_begin() + i;
450   typename OR_Matrix<N>::row_reference_type m_i = *i_iter;
451   N& m_i_j = m_i[j];
452   // Set `coeff' to the absolute value of itself.
453   if (coeff < 0) {
454     neg_assign(coeff);
455   }
456 
457   bool is_oct_changed = false;
458   // Compute the bound for `m_i_j', rounding towards plus infinity.
459   PPL_DIRTY_TEMP(N, d);
460   div_round_up(d, term, coeff);
461   if (m_i_j > d) {
462     m_i_j = d;
463     is_oct_changed = true;
464   }
465 
466   if (c.is_equality()) {
467     // Select the cell to be modified for the ">=" part of constraint.
468     if (i % 2 == 0) {
469       ++i_iter;
470     }
471     else {
472       --i_iter;
473     }
474 
475     typename OR_Matrix<N>::row_reference_type m_ci = *i_iter;
476     using namespace Implementation::Octagonal_Shapes;
477     dimension_type cj = coherent_index(j);
478     N& m_ci_cj = m_ci[cj];
479     // Also compute the bound for `m_ci_cj', rounding towards plus infinity.
480     neg_assign(term);
481     div_round_up(d, term, coeff);
482     if (m_ci_cj > d) {
483       m_ci_cj = d;
484       is_oct_changed = true;
485     }
486   }
487 
488   // This method does not preserve closure.
489   if (is_oct_changed && marked_strongly_closed()) {
490     reset_strongly_closed();
491   }
492   PPL_ASSERT(OK());
493 }
494 
495 template <typename T>
496 void
add_congruence(const Congruence & cg)497 Octagonal_Shape<T>::add_congruence(const Congruence& cg) {
498   const dimension_type cg_space_dim = cg.space_dimension();
499   // Dimension-compatibility check:
500   // the dimension of `cg' can not be greater than space_dim.
501   if (space_dimension() < cg_space_dim) {
502     throw_dimension_incompatible("add_congruence(cg)", cg);
503   }
504 
505   // Handle the case of proper congruences first.
506   if (cg.is_proper_congruence()) {
507     if (cg.is_tautological()) {
508       return;
509     }
510     if (cg.is_inconsistent()) {
511       set_empty();
512       return;
513     }
514     // Non-trivial and proper congruences are not allowed.
515     throw_invalid_argument("add_congruence(cg)",
516                            "cg is a non-trivial, proper congruence");
517   }
518 
519   PPL_ASSERT(cg.is_equality());
520   Constraint c(cg);
521   add_constraint(c);
522 }
523 
524 template <typename T>
525 template <typename Interval_Info>
526 void
refine_with_linear_form_inequality(const Linear_Form<Interval<T,Interval_Info>> & left,const Linear_Form<Interval<T,Interval_Info>> & right)527 Octagonal_Shape<T>::refine_with_linear_form_inequality(
528                     const Linear_Form< Interval<T, Interval_Info> >& left,
529                     const Linear_Form< Interval<T, Interval_Info> >& right) {
530 
531   // Check that T is a floating point type.
532   PPL_COMPILE_TIME_CHECK(!std::numeric_limits<T>::is_exact,
533                      "Octagonal_Shape<T>::refine_with_linear_form_inequality:"
534                      " T not a floating point type.");
535 
536   // We assume that the analyzer will not try to apply an unreachable filter.
537   PPL_ASSERT(!marked_empty());
538 
539   // Dimension-compatibility checks.
540   // The dimensions of `left' and `right' should not be greater than the
541   // dimension of `*this'.
542   const dimension_type left_space_dim = left.space_dimension();
543   if (space_dim < left_space_dim) {
544     throw_dimension_incompatible(
545           "refine_with_linear_form_inequality(left, right)", "left", left);
546   }
547 
548   const dimension_type right_space_dim = right.space_dimension();
549   if (space_dim < right_space_dim) {
550     throw_dimension_incompatible(
551           "refine_with_linear_form_inequality(left, right)", "right", right);
552   }
553   // Number of non-zero coefficients in `left': will be set to
554   // 0, 1, or 2, the latter value meaning any value greater than 1.
555   dimension_type left_t = 0;
556   // Variable-index of the last non-zero coefficient in `left', if any.
557   dimension_type left_w_id = 0;
558   // Number of non-zero coefficients in `right': will be set to
559   // 0, 1, or 2, the latter value meaning any value greater than 1.
560   dimension_type right_t = 0;
561   // Variable-index of the last non-zero coefficient in `right', if any.
562   dimension_type right_w_id = 0;
563 
564   // Get information about the number of non-zero coefficients in `left'.
565   for (dimension_type i = left_space_dim; i-- > 0; ) {
566     if (left.coefficient(Variable(i)) != 0) {
567       if (left_t++ == 1) {
568         break;
569       }
570       else {
571         left_w_id = i;
572       }
573     }
574   }
575 
576   // Get information about the number of non-zero coefficients in `right'.
577   for (dimension_type i = right_space_dim; i-- > 0; ) {
578     if (right.coefficient(Variable(i)) != 0) {
579       if (right_t++ == 1) {
580         break;
581       }
582       else {
583         right_w_id = i;
584       }
585     }
586   }
587 
588   typedef typename OR_Matrix<N>::row_iterator row_iterator;
589   typedef typename OR_Matrix<N>::row_reference_type row_reference;
590   typedef Interval<T, Interval_Info> FP_Interval_Type;
591 
592   // FIXME: there is plenty of duplicate code in the following lines. We could
593   // shorten it at the expense of a bit of efficiency.
594 
595   if (left_t == 0) {
596     if (right_t == 0) {
597       // The constraint involves constants only. Ignore it: it is up to
598       // the analyzer to handle it.
599       PPL_ASSERT(OK());
600       return;
601     }
602 
603     if (right_t == 1) {
604       // The constraint has the form [a-, a+] <= [b-, b+] + [c-, c+] * x.
605       // Reduce it to the constraint +/-x <= b+ - a- if [c-, c+] = +/-[1, 1].
606       const FP_Interval_Type& right_w_coeff =
607                               right.coefficient(Variable(right_w_id));
608       if (right_w_coeff == 1) {
609         const dimension_type n_right = right_w_id * 2;
610         PPL_DIRTY_TEMP(N, b_plus_minus_a_minus);
611         const FP_Interval_Type& left_a = left.inhomogeneous_term();
612         const FP_Interval_Type& right_b = right.inhomogeneous_term();
613         sub_assign_r(b_plus_minus_a_minus, right_b.upper(), left_a.lower(),
614                      ROUND_UP);
615         mul_2exp_assign_r(b_plus_minus_a_minus, b_plus_minus_a_minus, 1,
616                           ROUND_UP);
617         add_octagonal_constraint(n_right, n_right + 1, b_plus_minus_a_minus);
618         PPL_ASSERT(OK());
619         return;
620       }
621 
622       if (right_w_coeff == -1) {
623         const dimension_type n_right = right_w_id * 2;
624         PPL_DIRTY_TEMP(N, b_plus_minus_a_minus);
625         const FP_Interval_Type& left_a = left.inhomogeneous_term();
626         const FP_Interval_Type& right_b = right.inhomogeneous_term();
627         sub_assign_r(b_plus_minus_a_minus, right_b.upper(), left_a.lower(),
628                      ROUND_UP);
629         mul_2exp_assign_r(b_plus_minus_a_minus, b_plus_minus_a_minus, 1,
630                           ROUND_UP);
631         add_octagonal_constraint(n_right + 1, n_right, b_plus_minus_a_minus);
632         PPL_ASSERT(OK());
633         return;
634       }
635     }
636   }
637   else if (left_t == 1) {
638     if (right_t == 0) {
639       // The constraint has the form [b-, b+] + [c-, c+] * x <= [a-, a+]
640       // Reduce it to the constraint +/-x <= a+ - b- if [c-, c+] = +/-[1, 1].
641       const FP_Interval_Type& left_w_coeff =
642                               left.coefficient(Variable(left_w_id));
643       if (left_w_coeff == 1) {
644         const dimension_type n_left = left_w_id * 2;
645         PPL_DIRTY_TEMP(N, a_plus_minus_b_minus);
646         const FP_Interval_Type& left_b = left.inhomogeneous_term();
647         const FP_Interval_Type& right_a = right.inhomogeneous_term();
648         sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(),
649                      ROUND_UP);
650         mul_2exp_assign_r(a_plus_minus_b_minus, a_plus_minus_b_minus, 1,
651                           ROUND_UP);
652         add_octagonal_constraint(n_left + 1, n_left, a_plus_minus_b_minus);
653         PPL_ASSERT(OK());
654         return;
655       }
656 
657       if (left_w_coeff == -1) {
658         const dimension_type n_left = left_w_id * 2;
659         PPL_DIRTY_TEMP(N, a_plus_minus_b_minus);
660         const FP_Interval_Type& left_b = left.inhomogeneous_term();
661         const FP_Interval_Type& right_a = right.inhomogeneous_term();
662         sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(),
663                      ROUND_UP);
664         mul_2exp_assign_r(a_plus_minus_b_minus, a_plus_minus_b_minus, 1,
665                           ROUND_UP);
666         add_octagonal_constraint(n_left, n_left + 1, a_plus_minus_b_minus);
667         PPL_ASSERT(OK());
668         return;
669       }
670     }
671 
672     if (right_t == 1) {
673       // The constraint has the form
674       // [a-, a+] + [b-, b+] * x <= [c-, c+] + [d-, d+] * y.
675       // Reduce it to the constraint +/-x +/-y <= c+ - a-
676       // if [b-, b+] = +/-[1, 1] and [d-, d+] = +/-[1, 1].
677       const FP_Interval_Type& left_w_coeff =
678                               left.coefficient(Variable(left_w_id));
679       const FP_Interval_Type& right_w_coeff =
680                               right.coefficient(Variable(right_w_id));
681       bool is_left_coeff_one = (left_w_coeff == 1);
682       bool is_left_coeff_minus_one = (left_w_coeff == -1);
683       bool is_right_coeff_one = (right_w_coeff == 1);
684       bool is_right_coeff_minus_one = (right_w_coeff == -1);
685       if (left_w_id == right_w_id) {
686         if ((is_left_coeff_one && is_right_coeff_one)
687             || (is_left_coeff_minus_one && is_right_coeff_minus_one)) {
688           // Here we have an identity or a constants-only constraint.
689           PPL_ASSERT(OK());
690           return;
691         }
692         if (is_left_coeff_one && is_right_coeff_minus_one) {
693           // We fall back to a previous case
694           // (but we do not need to multiply the result by two).
695           const dimension_type n_left = left_w_id * 2;
696           PPL_DIRTY_TEMP(N, a_plus_minus_b_minus);
697           const FP_Interval_Type& left_b = left.inhomogeneous_term();
698           const FP_Interval_Type& right_a = right.inhomogeneous_term();
699           sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(),
700                        ROUND_UP);
701           add_octagonal_constraint(n_left + 1, n_left, a_plus_minus_b_minus);
702           PPL_ASSERT(OK());
703           return;
704         }
705         if (is_left_coeff_minus_one && is_right_coeff_one) {
706           // We fall back to a previous case
707           // (but we do not need to multiply the result by two).
708           const dimension_type n_left = left_w_id * 2;
709           PPL_DIRTY_TEMP(N, a_plus_minus_b_minus);
710           const FP_Interval_Type& left_b = left.inhomogeneous_term();
711           const FP_Interval_Type& right_a = right.inhomogeneous_term();
712           sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(),
713                        ROUND_UP);
714           add_octagonal_constraint(n_left, n_left + 1, a_plus_minus_b_minus);
715           PPL_ASSERT(OK());
716           return;
717         }
718       }
719       else if (is_left_coeff_one && is_right_coeff_one) {
720         const dimension_type n_left = left_w_id * 2;
721         const dimension_type n_right = right_w_id * 2;
722         PPL_DIRTY_TEMP(N, c_plus_minus_a_minus);
723         const FP_Interval_Type& left_a = left.inhomogeneous_term();
724         const FP_Interval_Type& right_c = right.inhomogeneous_term();
725         sub_assign_r(c_plus_minus_a_minus, right_c.upper(), left_a.lower(),
726                      ROUND_UP);
727         if (left_w_id < right_w_id) {
728           add_octagonal_constraint(n_right, n_left, c_plus_minus_a_minus);
729         }
730         else {
731           add_octagonal_constraint(n_left + 1, n_right + 1,
732                                    c_plus_minus_a_minus);
733         }
734         PPL_ASSERT(OK());
735         return;
736       }
737       if (is_left_coeff_one && is_right_coeff_minus_one) {
738         const dimension_type n_left = left_w_id * 2;
739         const dimension_type n_right = right_w_id * 2;
740         PPL_DIRTY_TEMP(N, c_plus_minus_a_minus);
741         const FP_Interval_Type& left_a = left.inhomogeneous_term();
742         const FP_Interval_Type& right_c = right.inhomogeneous_term();
743         sub_assign_r(c_plus_minus_a_minus, right_c.upper(), left_a.lower(),
744                      ROUND_UP);
745         if (left_w_id < right_w_id) {
746           add_octagonal_constraint(n_right + 1, n_left, c_plus_minus_a_minus);
747         }
748         else {
749           add_octagonal_constraint(n_left + 1, n_right, c_plus_minus_a_minus);
750         }
751         PPL_ASSERT(OK());
752         return;
753       }
754       if (is_left_coeff_minus_one && is_right_coeff_one) {
755         const dimension_type n_left = left_w_id * 2;
756         const dimension_type n_right = right_w_id * 2;
757         PPL_DIRTY_TEMP(N, c_plus_minus_a_minus);
758         const FP_Interval_Type& left_a = left.inhomogeneous_term();
759         const FP_Interval_Type& right_c = right.inhomogeneous_term();
760         sub_assign_r(c_plus_minus_a_minus, right_c.upper(), left_a.lower(),
761                      ROUND_UP);
762         if (left_w_id < right_w_id) {
763           add_octagonal_constraint(n_right, n_left + 1, c_plus_minus_a_minus);
764         }
765         else {
766           add_octagonal_constraint(n_left, n_right + 1, c_plus_minus_a_minus);
767         }
768         PPL_ASSERT(OK());
769         return;
770       }
771       if (is_left_coeff_minus_one && is_right_coeff_minus_one) {
772         const dimension_type n_left = left_w_id * 2;
773         const dimension_type n_right = right_w_id * 2;
774         PPL_DIRTY_TEMP(N, c_plus_minus_a_minus);
775         const FP_Interval_Type& left_a = left.inhomogeneous_term();
776         const FP_Interval_Type& right_c = right.inhomogeneous_term();
777         sub_assign_r(c_plus_minus_a_minus, right_c.upper(), left_a.lower(),
778                      ROUND_UP);
779         if (left_w_id < right_w_id) {
780           add_octagonal_constraint(n_right + 1, n_left + 1,
781                                    c_plus_minus_a_minus);
782         }
783         else {
784           add_octagonal_constraint(n_left, n_right, c_plus_minus_a_minus);
785         }
786         PPL_ASSERT(OK());
787         return;
788       }
789     }
790   }
791 
792   // General case.
793 
794   // FIRST, update the binary constraints for each pair of DIFFERENT variables
795   // in `left' and `right'.
796 
797   // Declare temporaries outside of the loop.
798   PPL_DIRTY_TEMP(N, low_coeff);
799   PPL_DIRTY_TEMP(N, high_coeff);
800   PPL_DIRTY_TEMP(N, upper_bound);
801 
802   Linear_Form<FP_Interval_Type> right_minus_left(right);
803   right_minus_left -= left;
804 
805   dimension_type max_w_id = std::max(left_w_id, right_w_id);
806   for (dimension_type first_v = 0; first_v < max_w_id; ++first_v) {
807     for (dimension_type second_v = first_v + 1;
808          second_v <= max_w_id; ++second_v) {
809       const FP_Interval_Type& lfv_coefficient =
810                         left.coefficient(Variable(first_v));
811       const FP_Interval_Type& lsv_coefficient =
812                         left.coefficient(Variable(second_v));
813       const FP_Interval_Type& rfv_coefficient =
814                         right.coefficient(Variable(first_v));
815       const FP_Interval_Type& rsv_coefficient =
816                         right.coefficient(Variable(second_v));
817       // We update the constraints only when both variables appear in at
818       // least one argument.
819       bool do_update = false;
820       assign_r(low_coeff, lfv_coefficient.lower(), ROUND_NOT_NEEDED);
821       assign_r(high_coeff, lfv_coefficient.upper(), ROUND_NOT_NEEDED);
822       if (low_coeff != 0 || high_coeff != 0) {
823         assign_r(low_coeff, lsv_coefficient.lower(), ROUND_NOT_NEEDED);
824         assign_r(high_coeff, lsv_coefficient.upper(), ROUND_NOT_NEEDED);
825         if (low_coeff != 0 || high_coeff != 0) {
826           do_update = true;
827         }
828         else {
829           assign_r(low_coeff, rsv_coefficient.lower(), ROUND_NOT_NEEDED);
830           assign_r(high_coeff, rsv_coefficient.upper(), ROUND_NOT_NEEDED);
831           if (low_coeff != 0 || high_coeff != 0) {
832             do_update = true;
833           }
834         }
835       }
836       else {
837         assign_r(low_coeff, rfv_coefficient.lower(), ROUND_NOT_NEEDED);
838         assign_r(high_coeff, rfv_coefficient.upper(), ROUND_NOT_NEEDED);
839         if (low_coeff != 0 || high_coeff != 0) {
840           assign_r(low_coeff, lsv_coefficient.lower(), ROUND_NOT_NEEDED);
841           assign_r(high_coeff, lsv_coefficient.upper(), ROUND_NOT_NEEDED);
842           if (low_coeff != 0 || high_coeff != 0) {
843             do_update = true;
844           }
845           else {
846             assign_r(low_coeff, rsv_coefficient.lower(), ROUND_NOT_NEEDED);
847             assign_r(high_coeff, rsv_coefficient.upper(), ROUND_NOT_NEEDED);
848             if (low_coeff != 0 || high_coeff != 0) {
849               do_update = true;
850             }
851           }
852         }
853       }
854 
855       if (do_update) {
856         Variable first(first_v);
857         Variable second(second_v);
858         dimension_type n_first_var = first_v * 2;
859         dimension_type n_second_var = second_v * 2;
860         linear_form_upper_bound(right_minus_left - first + second,
861                                 upper_bound);
862         add_octagonal_constraint(n_second_var + 1, n_first_var + 1,
863                                  upper_bound);
864         linear_form_upper_bound(right_minus_left + first + second,
865                                 upper_bound);
866         add_octagonal_constraint(n_second_var + 1, n_first_var, upper_bound);
867         linear_form_upper_bound(right_minus_left - first - second,
868                                 upper_bound);
869         add_octagonal_constraint(n_second_var, n_first_var + 1, upper_bound);
870         linear_form_upper_bound(right_minus_left + first - second,
871                                 upper_bound);
872         add_octagonal_constraint(n_second_var, n_first_var, upper_bound);
873       }
874     }
875   }
876 
877   // Finally, update the unary constraints.
878   for (dimension_type v = 0; v <= max_w_id; ++v) {
879     const FP_Interval_Type& lv_coefficient =
880                         left.coefficient(Variable(v));
881     const FP_Interval_Type& rv_coefficient =
882                         right.coefficient(Variable(v));
883     // We update the constraints only if v appears in at least one of the
884     // two arguments.
885     bool do_update = false;
886     assign_r(low_coeff, lv_coefficient.lower(), ROUND_NOT_NEEDED);
887     assign_r(high_coeff, lv_coefficient.upper(), ROUND_NOT_NEEDED);
888     if (low_coeff != 0 || high_coeff != 0) {
889       do_update = true;
890     }
891     else {
892       assign_r(low_coeff, rv_coefficient.lower(), ROUND_NOT_NEEDED);
893       assign_r(high_coeff, rv_coefficient.upper(), ROUND_NOT_NEEDED);
894       if (low_coeff != 0 || high_coeff != 0) {
895         do_update = true;
896       }
897     }
898 
899     if (do_update) {
900       Variable var(v);
901       dimension_type n_var = 2 * v;
902       /*
903         VERY DIRTY trick: since we need to keep the old unary constraints
904         while computing the new ones, we momentarily keep the new coefficients
905         in the main diagonal of the matrix. They will be moved later.
906       */
907       linear_form_upper_bound(right_minus_left + var, upper_bound);
908       mul_2exp_assign_r(matrix[n_var + 1][n_var + 1], upper_bound, 1,
909                         ROUND_UP);
910       linear_form_upper_bound(right_minus_left - var, upper_bound);
911       mul_2exp_assign_r(matrix[n_var][n_var], upper_bound, 1,
912                         ROUND_UP);
913     }
914   }
915 
916   /*
917     Now move the newly computed coefficients from the main diagonal to
918     their proper place, and restore +infinity on the diagonal.
919   */
920   row_iterator m_ite = matrix.row_begin();
921   row_iterator m_end = matrix.row_end();
922   for (dimension_type i = 0; m_ite != m_end; i += 2) {
923     row_reference upper = *m_ite;
924     N& ul = upper[i];
925     add_octagonal_constraint(i, i + 1, ul);
926     assign_r(ul, PLUS_INFINITY, ROUND_NOT_NEEDED);
927     ++m_ite;
928     row_reference lower = *m_ite;
929     N& lr = lower[i + 1];
930     add_octagonal_constraint(i + 1, i, lr);
931     assign_r(lr, PLUS_INFINITY, ROUND_NOT_NEEDED);
932     ++m_ite;
933   }
934   PPL_ASSERT(OK());
935 }
936 
937 template <typename T>
938 void
refine_no_check(const Constraint & c)939 Octagonal_Shape<T>::refine_no_check(const Constraint& c) {
940   PPL_ASSERT(!marked_empty());
941   const dimension_type c_space_dim = c.space_dimension();
942   PPL_ASSERT(c_space_dim <= space_dim);
943 
944   dimension_type num_vars = 0;
945   dimension_type i = 0;
946   dimension_type j = 0;
947   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
948   PPL_DIRTY_TEMP_COEFFICIENT(term);
949   // Constraints that are not octagonal differences are ignored.
950   if (!Octagonal_Shape_Helper
951     ::extract_octagonal_difference(c, c_space_dim, num_vars,
952                                    i, j, coeff, term)) {
953     return;
954   }
955 
956   if (num_vars == 0) {
957     const Coefficient& c_inhomo = c.inhomogeneous_term();
958     // Dealing with a trivial constraint (maybe a strict inequality).
959     if (c_inhomo < 0
960         || (c_inhomo != 0 && c.is_equality())
961         || (c_inhomo == 0 && c.is_strict_inequality())) {
962       set_empty();
963     }
964     return;
965   }
966 
967   // Select the cell to be modified for the "<=" part of constraint.
968   typename OR_Matrix<N>::row_iterator i_iter = matrix.row_begin() + i;
969   typename OR_Matrix<N>::row_reference_type m_i = *i_iter;
970   N& m_i_j = m_i[j];
971   // Set `coeff' to the absolute value of itself.
972   if (coeff < 0) {
973     neg_assign(coeff);
974   }
975 
976   bool is_oct_changed = false;
977   // Compute the bound for `m_i_j', rounding towards plus infinity.
978   PPL_DIRTY_TEMP(N, d);
979   div_round_up(d, term, coeff);
980   if (m_i_j > d) {
981     m_i_j = d;
982     is_oct_changed = true;
983   }
984 
985   if (c.is_equality()) {
986     // Select the cell to be modified for the ">=" part of constraint.
987     if (i % 2 == 0) {
988       ++i_iter;
989     }
990     else {
991       --i_iter;
992     }
993 
994     typename OR_Matrix<N>::row_reference_type m_ci = *i_iter;
995     using namespace Implementation::Octagonal_Shapes;
996     dimension_type cj = coherent_index(j);
997     N& m_ci_cj = m_ci[cj];
998     // Also compute the bound for `m_ci_cj', rounding towards plus infinity.
999     neg_assign(term);
1000     div_round_up(d, term, coeff);
1001     if (m_ci_cj > d) {
1002       m_ci_cj = d;
1003       is_oct_changed = true;
1004     }
1005   }
1006 
1007   // This method does not preserve closure.
1008   if (is_oct_changed && marked_strongly_closed()) {
1009     reset_strongly_closed();
1010   }
1011   PPL_ASSERT(OK());
1012 }
1013 
1014 template <typename T>
1015 dimension_type
affine_dimension() const1016 Octagonal_Shape<T>::affine_dimension() const {
1017   const dimension_type n_rows = matrix.num_rows();
1018   // A zero-space-dim shape always has affine dimension zero.
1019   if (n_rows == 0) {
1020     return 0;
1021   }
1022 
1023   // Strong closure is necessary to detect emptiness
1024   // and all (possibly implicit) equalities.
1025   strong_closure_assign();
1026   if (marked_empty()) {
1027     return 0;
1028   }
1029 
1030   // The vector `leaders' is used to represent non-singular
1031   // equivalence classes:
1032   // `leaders[i] == i' if and only if `i' is the leader of its
1033   // equivalence class (i.e., the minimum index in the class).
1034   std::vector<dimension_type> leaders;
1035   compute_leaders(leaders);
1036 
1037   // Due to the splitting of variables, the affine dimension is the
1038   // number of non-singular positive zero-equivalence classes.
1039   dimension_type affine_dim = 0;
1040   for (dimension_type i = 0; i < n_rows; i += 2) {
1041     // Note: disregard the singular equivalence class.
1042     if (leaders[i] == i && leaders[i + 1] == i + 1) {
1043       ++affine_dim;
1044     }
1045   }
1046 
1047   return affine_dim;
1048 }
1049 
1050 template <typename T>
1051 Congruence_System
minimized_congruences() const1052 Octagonal_Shape<T>::minimized_congruences() const {
1053   // Strong closure is necessary to detect emptiness
1054   // and all (possibly implicit) equalities.
1055   strong_closure_assign();
1056   Congruence_System cgs(space_dim);
1057 
1058   if (space_dim == 0) {
1059     if (marked_empty()) {
1060       cgs = Congruence_System::zero_dim_empty();
1061     }
1062     return cgs;
1063   }
1064 
1065   if (marked_empty()) {
1066     cgs.insert(Congruence::zero_dim_false());
1067     return cgs;
1068   }
1069 
1070   // The vector `leaders' is used to represent equivalence classes:
1071   // `leaders[i] == i' if and only if `i' is the leader of its
1072   // equivalence class (i.e., the minimum index in the class).
1073   std::vector<dimension_type> leaders;
1074   compute_leaders(leaders);
1075 
1076   PPL_DIRTY_TEMP_COEFFICIENT(numer);
1077   PPL_DIRTY_TEMP_COEFFICIENT(denom);
1078   for (dimension_type i = 0, i_end = 2*space_dim; i != i_end; i += 2) {
1079     const dimension_type lead_i = leaders[i];
1080     if (i == lead_i) {
1081       if (leaders[i + 1] == i) {
1082         // `i' is the leader of the singular equivalence class.
1083         goto singular;
1084       }
1085       else {
1086         // `i' is the leader of a non-singular equivalence class.
1087         continue;
1088       }
1089     }
1090     else {
1091       // `i' is not a leader.
1092       if (leaders[i + 1] == lead_i) {
1093         // `i' belongs to the singular equivalence class.
1094         goto singular;
1095       }
1096       else {
1097         // `i' does not belong to the singular equivalence class.
1098         goto non_singular;
1099       }
1100     }
1101 
1102   singular:
1103     // `i' belongs to the singular equivalence class:
1104     // we have a unary equality constraint.
1105     {
1106       const Variable x(i/2);
1107       const N& c_ii_i = matrix[i + 1][i];
1108 #ifndef NDEBUG
1109       const N& c_i_ii = matrix[i][i + 1];
1110       PPL_ASSERT(is_additive_inverse(c_i_ii, c_ii_i));
1111 #endif
1112       numer_denom(c_ii_i, numer, denom);
1113       denom *= 2;
1114       cgs.insert(denom*x == numer);
1115     }
1116     continue;
1117 
1118   non_singular:
1119     // `i' does not belong to the singular equivalence class.
1120     // we have a binary equality constraint.
1121     {
1122       const N& c_i_li = matrix[i][lead_i];
1123 #ifndef NDEBUG
1124       using namespace Implementation::Octagonal_Shapes;
1125       const N& c_ii_lii = matrix[i + 1][coherent_index(lead_i)];
1126       PPL_ASSERT(is_additive_inverse(c_ii_lii, c_i_li));
1127 #endif
1128       const Variable x(lead_i/2);
1129       const Variable y(i/2);
1130       numer_denom(c_i_li, numer, denom);
1131       if (lead_i % 2 == 0) {
1132         cgs.insert(denom*x - denom*y == numer);
1133       }
1134       else {
1135         cgs.insert(denom*x + denom*y + numer == 0);
1136       }
1137     }
1138     continue;
1139   }
1140   return cgs;
1141 }
1142 
1143 template <typename T>
1144 void
concatenate_assign(const Octagonal_Shape & y)1145 Octagonal_Shape<T>::concatenate_assign(const Octagonal_Shape& y) {
1146   // If `y' is an empty 0-dim space octagon, let `*this' become empty.
1147   // If `y' is an universal 0-dim space octagon, we simply return.
1148   if (y.space_dim == 0) {
1149     if (y.marked_empty()) {
1150       set_empty();
1151     }
1152     return;
1153   }
1154 
1155   // If `*this' is an empty 0-dim space octagon, then it is sufficient
1156   // to adjust the dimension of the vector space.
1157   if (space_dim == 0 && marked_empty()) {
1158     add_space_dimensions_and_embed(y.space_dim);
1159     return;
1160   }
1161 
1162   // This is the old number of rows in the matrix. It is equal to
1163   // the first index of columns to change.
1164   dimension_type old_num_rows = matrix.num_rows();
1165   // First we increase the space dimension of `*this' by adding
1166   // `y.space_dimension()' new dimensions.
1167   // The matrix for the new octagon is obtained
1168   // by leaving the old system of constraints in the upper left-hand side
1169   // (where they are at the present) and placing the constraints of `y' in the
1170   // lower right-hand side.
1171   add_space_dimensions_and_embed(y.space_dim);
1172   typename OR_Matrix<N>::const_element_iterator
1173     y_it = y.matrix.element_begin();
1174   for (typename OR_Matrix<N>::row_iterator
1175          i = matrix.row_begin() + old_num_rows,
1176          matrix_row_end = matrix.row_end(); i != matrix_row_end; ++i) {
1177     typename OR_Matrix<N>::row_reference_type r = *i;
1178     dimension_type rs_i = i.row_size();
1179     for (dimension_type j = old_num_rows; j < rs_i; ++j, ++y_it) {
1180       r[j] = *y_it;
1181     }
1182   }
1183 
1184   // The concatenation does not preserve the closure.
1185   if (marked_strongly_closed()) {
1186     reset_strongly_closed();
1187   }
1188   PPL_ASSERT(OK());
1189 }
1190 
1191 template <typename T>
1192 bool
contains(const Octagonal_Shape & y) const1193 Octagonal_Shape<T>::contains(const Octagonal_Shape& y) const {
1194   // Dimension-compatibility check.
1195   if (space_dim != y.space_dim) {
1196     throw_dimension_incompatible("contains(y)", y);
1197   }
1198 
1199   if (space_dim == 0) {
1200     // The zero-dimensional empty octagon only contains another
1201     // zero-dimensional empty octagon.
1202     // The zero-dimensional universe octagon contains any other
1203     // zero-dimensional octagon.
1204     return marked_empty() ? y.marked_empty() : true;
1205   }
1206 
1207   // `y' needs to be transitively closed.
1208   y.strong_closure_assign();
1209   // An empty octagon is in any other dimension-compatible octagons.
1210   if (y.marked_empty()) {
1211     return true;
1212   }
1213 
1214   // If `*this' is empty it can not contain `y' (which is not empty).
1215   if (is_empty()) {
1216     return false;
1217   }
1218 
1219   // `*this' contains `y' if and only if every element of `*this'
1220   // is greater than or equal to the correspondent one of `y'.
1221   for (typename OR_Matrix<N>::const_element_iterator
1222          i = matrix.element_begin(), j = y.matrix.element_begin(),
1223          matrix_element_end = matrix.element_end();
1224        i != matrix_element_end; ++i, ++j) {
1225     if (*i < *j) {
1226       return false;
1227     }
1228   }
1229   return true;
1230 }
1231 
1232 template <typename T>
1233 bool
is_disjoint_from(const Octagonal_Shape & y) const1234 Octagonal_Shape<T>::is_disjoint_from(const Octagonal_Shape& y) const {
1235   // Dimension-compatibility check.
1236   if (space_dim != y.space_dim) {
1237     throw_dimension_incompatible("is_disjoint_from(y)", y);
1238   }
1239 
1240   // If one Octagonal_Shape is empty, the Octagonal_Shapes are disjoint.
1241   strong_closure_assign();
1242   if (marked_empty()) {
1243     return true;
1244   }
1245   y.strong_closure_assign();
1246   if (y.marked_empty()) {
1247     return true;
1248   }
1249 
1250   // Two Octagonal_Shapes are disjoint if and only if their
1251   // intersection is empty, i.e., if and only if there exists a
1252   // variable such that the upper bound of the constraint on that
1253   // variable in the first Octagonal_Shape is strictly less than the
1254   // lower bound of the corresponding constraint in the second
1255   // Octagonal_Shape or vice versa.
1256 
1257   const dimension_type n_rows = matrix.num_rows();
1258 
1259   typedef typename OR_Matrix<N>::const_row_iterator row_iterator;
1260   typedef typename OR_Matrix<N>::const_row_reference_type row_reference;
1261 
1262   const row_iterator m_begin = matrix.row_begin();
1263   const row_iterator m_end = matrix.row_end();
1264 
1265   const row_iterator y_begin = y.matrix.row_begin();
1266 
1267   PPL_DIRTY_TEMP(N, neg_y_ci_cj);
1268   for (row_iterator i_iter = m_begin; i_iter != m_end; ++i_iter) {
1269     using namespace Implementation::Octagonal_Shapes;
1270     const dimension_type i = i_iter.index();
1271     const dimension_type ci = coherent_index(i);
1272     const dimension_type rs_i = i_iter.row_size();
1273     row_reference m_i = *i_iter;
1274     for (dimension_type j = 0; j < n_rows; ++j) {
1275       const dimension_type cj = coherent_index(j);
1276       row_reference m_cj = *(m_begin + cj);
1277       const N& m_i_j = (j < rs_i) ? m_i[j] : m_cj[ci];
1278       row_reference y_ci = *(y_begin + ci);
1279       row_reference y_j = *(y_begin + j);
1280       const N& y_ci_cj = (j < rs_i) ? y_ci[cj] : y_j[i];
1281       neg_assign_r(neg_y_ci_cj, y_ci_cj, ROUND_UP);
1282       if (m_i_j < neg_y_ci_cj) {
1283         return true;
1284       }
1285     }
1286   }
1287   return false;
1288 }
1289 
1290 template <typename T>
1291 bool
is_universe() const1292 Octagonal_Shape<T>::is_universe() const {
1293   // An empty octagon is not universe.
1294   if (marked_empty()) {
1295     return false;
1296   }
1297 
1298   // If the octagon is non-empty and zero-dimensional,
1299   // then it is necessarily the universe octagon.
1300   if (space_dim == 0) {
1301     return true;
1302   }
1303 
1304   // An universe octagon can only contains trivial  constraints.
1305   for (typename OR_Matrix<N>::const_element_iterator
1306          i = matrix.element_begin(), matrix_element_end = matrix.element_end();
1307        i != matrix_element_end;
1308        ++i) {
1309     if (!is_plus_infinity(*i)) {
1310       return false;
1311     }
1312   }
1313 
1314   return true;
1315 }
1316 
1317 template <typename T>
1318 bool
is_bounded() const1319 Octagonal_Shape<T>::is_bounded() const {
1320   strong_closure_assign();
1321   // A zero-dimensional or empty octagon is bounded.
1322   if (marked_empty() || space_dim == 0) {
1323     return true;
1324   }
1325 
1326   // A bounded octagon never can contains trivial constraints.
1327   for (typename OR_Matrix<N>::const_row_iterator i = matrix.row_begin(),
1328          matrix_row_end = matrix.row_end(); i != matrix_row_end; ++i) {
1329     typename OR_Matrix<N>::const_row_reference_type x_i = *i;
1330     const dimension_type i_index = i.index();
1331     for (dimension_type j = i.row_size(); j-- > 0; ) {
1332       if (i_index != j) {
1333         if (is_plus_infinity(x_i[j])) {
1334           return false;
1335         }
1336       }
1337     }
1338   }
1339 
1340   return true;
1341 }
1342 
1343 template <typename T>
1344 bool
contains_integer_point() const1345 Octagonal_Shape<T>::contains_integer_point() const {
1346   // Force strong closure.
1347   if (is_empty()) {
1348     return false;
1349   }
1350   if (space_dim == 0) {
1351     return true;
1352   }
1353   // A strongly closed and consistent Octagonal_Shape defined by
1354   // integer constraints can only be empty due to tight coherence.
1355   if (std::numeric_limits<T>::is_integer) {
1356     return !tight_coherence_would_make_empty();
1357   }
1358 
1359   // Build an integer Octagonal_Shape oct_z with bounds at least as
1360   // tight as those in *this and then recheck for emptiness, also
1361   // exploiting tight-coherence.
1362   Octagonal_Shape<mpz_class> oct_z(space_dim);
1363   oct_z.reset_strongly_closed();
1364 
1365   typedef Octagonal_Shape<mpz_class>::N Z;
1366   bool all_integers = true;
1367   typename OR_Matrix<N>::const_element_iterator x_i = matrix.element_begin();
1368   for (typename OR_Matrix<Z>::element_iterator
1369          z_i = oct_z.matrix.element_begin(),
1370          z_end = oct_z.matrix.element_end(); z_i != z_end; ++z_i, ++x_i) {
1371     const N& d = *x_i;
1372     if (is_plus_infinity(d)) {
1373       continue;
1374     }
1375     if (is_integer(d)) {
1376       assign_r(*z_i, d, ROUND_NOT_NEEDED);
1377     }
1378     else {
1379       all_integers = false;
1380       assign_r(*z_i, d, ROUND_DOWN);
1381     }
1382   }
1383   // Restore strong closure.
1384   if (all_integers) {
1385     // oct_z unchanged, so it is still strongly closed.
1386     oct_z.set_strongly_closed();
1387   }
1388   else {
1389     // oct_z changed: recompute strong closure.
1390     oct_z.strong_closure_assign();
1391     if (oct_z.marked_empty()) {
1392       return false;
1393     }
1394   }
1395   return !oct_z.tight_coherence_would_make_empty();
1396 }
1397 
1398 template <typename T>
1399 bool
frequency(const Linear_Expression & expr,Coefficient & freq_n,Coefficient & freq_d,Coefficient & val_n,Coefficient & val_d) const1400 Octagonal_Shape<T>::frequency(const Linear_Expression& expr,
1401                               Coefficient& freq_n, Coefficient& freq_d,
1402                               Coefficient& val_n, Coefficient& val_d) const {
1403   // The dimension of `expr' must be at most the dimension of *this.
1404   if (space_dim < expr.space_dimension()) {
1405     throw_dimension_incompatible("frequency(e, ...)", "e", expr);
1406   }
1407 
1408   // Check if `expr' has a constant value.
1409   // If it is constant, set the frequency `freq_n' to 0
1410   // and return true. Otherwise the values for \p expr
1411   // are not discrete so return false.
1412 
1413   // Space dimension is 0: if empty, then return false;
1414   // otherwise the frequency is 0 and the value is the inhomogeneous term.
1415   if (space_dim == 0) {
1416     if (is_empty()) {
1417       return false;
1418     }
1419     freq_n = 0;
1420     freq_d = 1;
1421     val_n = expr.inhomogeneous_term();
1422     val_d = 1;
1423     return true;
1424   }
1425 
1426   strong_closure_assign();
1427   // For an empty Octagonal shape, we simply return false.
1428   if (marked_empty()) {
1429     return false;
1430   }
1431 
1432   // The Octagonal shape has at least 1 dimension and is not empty.
1433   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
1434   PPL_DIRTY_TEMP_COEFFICIENT(coeff_j);
1435   PPL_DIRTY_TEMP_COEFFICIENT(numer);
1436   PPL_DIRTY_TEMP_COEFFICIENT(denom);
1437   Linear_Expression le = expr;
1438   // Boolean to keep track of a variable `v' in expression `le'.
1439   // If we can replace `v' by an expression using variables other
1440   // than `v' and are already in `le', then this is set to true.
1441   bool constant_v = false;
1442 
1443   typedef typename OR_Matrix<N>::const_row_iterator row_iterator;
1444   typedef typename OR_Matrix<N>::const_row_reference_type row_reference;
1445 
1446   const row_iterator m_begin = matrix.row_begin();
1447   const row_iterator m_end = matrix.row_end();
1448 
1449   PPL_DIRTY_TEMP_COEFFICIENT(val_denom);
1450   val_denom = 1;
1451 
1452   for (row_iterator i_iter = m_begin; i_iter != m_end; i_iter += 2) {
1453     constant_v = false;
1454     dimension_type i = i_iter.index();
1455     const Variable v(i/2);
1456     coeff = le.coefficient(v);
1457     if (coeff == 0) {
1458       constant_v = true;
1459       continue;
1460     }
1461     // We check the unary constraints.
1462     row_reference m_i = *i_iter;
1463     row_reference m_ii = *(i_iter + 1);
1464     const N& m_i_ii = m_i[i + 1];
1465     const N& m_ii_i = m_ii[i];
1466     if ((!is_plus_infinity(m_i_ii) && !is_plus_infinity(m_ii_i))
1467         && (is_additive_inverse(m_i_ii, m_ii_i))) {
1468       // If `v' is constant, replace it in `le' by the value.
1469       numer_denom(m_i_ii, numer, denom);
1470       denom *= 2;
1471       le -= coeff*v;
1472       le *= denom;
1473       le -= numer*coeff;
1474       val_denom *= denom;
1475       constant_v = true;
1476       continue;
1477     }
1478     // Check the octagonal constraints between `v' and the other dimensions
1479     // that have non-zero coefficient in `le'.
1480     else {
1481       PPL_ASSERT(!constant_v);
1482       using namespace Implementation::Octagonal_Shapes;
1483       const dimension_type ci = coherent_index(i);
1484       for (row_iterator j_iter = i_iter; j_iter != m_end; j_iter += 2) {
1485         dimension_type j = j_iter.index();
1486         const Variable vj(j/2);
1487         coeff_j = le.coefficient(vj);
1488         if (coeff_j == 0) {
1489           // The coefficient in `le' is 0, so do nothing.
1490           continue;
1491         }
1492         const dimension_type cj = coherent_index(j);
1493         const dimension_type cjj = coherent_index(j + 1);
1494 
1495         row_reference m_j = *(m_begin + j);
1496         row_reference m_cj = *(m_begin + cj);
1497         const N& m_j_i = m_j[i];
1498         const N& m_i_j = m_cj[ci];
1499         if ((!is_plus_infinity(m_i_j) && !is_plus_infinity(m_j_i))
1500             && (is_additive_inverse(m_i_j, m_j_i))) {
1501           // The coefficient for `vj' in `le' is not 0
1502           // and the constraint with `v' is an equality.
1503           // So apply this equality to eliminate `v' in `le'.
1504           numer_denom(m_i_j, numer, denom);
1505           le -= coeff*v;
1506           le += coeff*vj;
1507           le *= denom;
1508           le -= numer*coeff;
1509           val_denom *= denom;
1510           constant_v = true;
1511           break;
1512         }
1513 
1514         m_j = *(m_begin + (j + 1));
1515         m_cj = *(m_begin + cjj);
1516         const N& m_j_i1 = m_j[i];
1517         const N& m_i_j1 = m_cj[ci];
1518         if ((!is_plus_infinity(m_i_j1) && !is_plus_infinity(m_j_i1))
1519             && (is_additive_inverse(m_i_j1, m_j_i1))) {
1520           // The coefficient for `vj' in `le' is not 0
1521           // and the constraint with `v' is an equality.
1522           // So apply this equality to eliminate `v' in `le'.
1523           numer_denom(m_i_j1, numer, denom);
1524           le -= coeff*v;
1525           le -= coeff*vj;
1526           le *= denom;
1527           le -= numer*coeff;
1528           val_denom *= denom;
1529           constant_v = true;
1530           break;
1531         }
1532       }
1533       if (!constant_v) {
1534         // The expression `expr' is not constant.
1535         return false;
1536       }
1537     }
1538   }
1539   if (!constant_v) {
1540     // The expression `expr' is not constant.
1541     return false;
1542   }
1543 
1544   // The expression 'expr' is constant.
1545   freq_n = 0;
1546   freq_d = 1;
1547 
1548   // Reduce `val_n' and `val_d'.
1549   normalize2(le.inhomogeneous_term(), val_denom, val_n, val_d);
1550   return true;
1551 }
1552 
1553 template <typename T>
1554 bool
constrains(const Variable var) const1555 Octagonal_Shape<T>::constrains(const Variable var) const {
1556   // `var' should be one of the dimensions of the octagonal shape.
1557   const dimension_type var_space_dim = var.space_dimension();
1558   if (space_dimension() < var_space_dim) {
1559     throw_dimension_incompatible("constrains(v)", "v", var);
1560   }
1561 
1562   // An octagon known to be empty constrains all variables.
1563   // (Note: do not force emptiness check _yet_)
1564   if (marked_empty()) {
1565     return true;
1566   }
1567 
1568   // Check whether `var' is syntactically constrained.
1569   const dimension_type n_v = 2*(var_space_dim - 1);
1570   typename OR_Matrix<N>::const_row_iterator m_iter = matrix.row_begin() + n_v;
1571   typename OR_Matrix<N>::const_row_reference_type r_v = *m_iter;
1572   typename OR_Matrix<N>::const_row_reference_type r_cv = *(++m_iter);
1573   for (dimension_type h = m_iter.row_size(); h-- > 0; ) {
1574     if (!is_plus_infinity(r_v[h]) || !is_plus_infinity(r_cv[h])) {
1575       return true;
1576     }
1577   }
1578   ++m_iter;
1579   for (typename OR_Matrix<N>::const_row_iterator m_end = matrix.row_end();
1580        m_iter != m_end; ++m_iter) {
1581     typename OR_Matrix<N>::const_row_reference_type r = *m_iter;
1582     if (!is_plus_infinity(r[n_v]) || !is_plus_infinity(r[n_v + 1])) {
1583       return true;
1584     }
1585   }
1586 
1587   // `var' is not syntactically constrained:
1588   // now force an emptiness check.
1589   return is_empty();
1590 }
1591 
1592 template <typename T>
1593 bool
is_strong_coherent() const1594 Octagonal_Shape<T>::is_strong_coherent() const {
1595   // This method is only used by method OK() so as to check if a
1596   // strongly closed matrix is also strong-coherent, as it must be.
1597   const dimension_type num_rows = matrix.num_rows();
1598 
1599   // Allocated here once and for all.
1600   PPL_DIRTY_TEMP(N, semi_sum);
1601   // The strong-coherence is: for every indexes i and j (and i != j)
1602   // matrix[i][j] <= (matrix[i][ci] + matrix[cj][j])/2
1603   // where ci = i + 1, if i is even number or
1604   //       ci = i - 1, if i is odd.
1605   // Ditto for cj.
1606   for (dimension_type i = num_rows; i-- > 0; ) {
1607     typename OR_Matrix<N>::const_row_iterator iter = matrix.row_begin() + i;
1608     typename OR_Matrix<N>::const_row_reference_type m_i = *iter;
1609     using namespace Implementation::Octagonal_Shapes;
1610     const N& m_i_ci = m_i[coherent_index(i)];
1611     for (dimension_type j = matrix.row_size(i); j-- > 0; ) {
1612       // Note: on the main diagonal only PLUS_INFINITY can occur.
1613       if (i != j) {
1614         const N& m_cj_j = matrix[coherent_index(j)][j];
1615         if (!is_plus_infinity(m_i_ci)
1616             && !is_plus_infinity(m_cj_j)) {
1617           // Compute (m_i_ci + m_cj_j)/2 into `semi_sum',
1618           // rounding the result towards plus infinity.
1619           add_assign_r(semi_sum, m_i_ci, m_cj_j, ROUND_UP);
1620           div_2exp_assign_r(semi_sum, semi_sum, 1, ROUND_UP);
1621           if (m_i[j] > semi_sum) {
1622             return false;
1623           }
1624         }
1625       }
1626     }
1627   }
1628   return true;
1629 }
1630 
1631 template <typename T>
1632 bool
is_strongly_reduced() const1633 Octagonal_Shape<T>::is_strongly_reduced() const {
1634   // This method is only used in assertions: efficiency is not a must.
1635 
1636   // An empty octagon is already transitively reduced.
1637   if (marked_empty()) {
1638     return true;
1639   }
1640 
1641   Octagonal_Shape x = *this;
1642   // The matrix representing an OS is strongly reduced if, by removing
1643   // any constraint, the resulting matrix describes a different OS.
1644   for (typename OR_Matrix<N>::const_row_iterator iter = matrix.row_begin(),
1645          matrix_row_end = matrix.row_end(); iter != matrix_row_end; ++iter) {
1646     typename OR_Matrix<N>::const_row_reference_type m_i = *iter;
1647     const dimension_type i = iter.index();
1648     for (dimension_type j = iter.row_size(); j-- > 0; ) {
1649       if (!is_plus_infinity(m_i[j])) {
1650         Octagonal_Shape x_copy = *this;
1651         assign_r(x_copy.matrix[i][j], PLUS_INFINITY, ROUND_NOT_NEEDED);
1652         if (x == x_copy) {
1653           return false;
1654         }
1655       }
1656     }
1657   }
1658   // The octagon is just reduced.
1659   return true;
1660 }
1661 
1662 template <typename T>
1663 bool
bounds(const Linear_Expression & expr,const bool from_above) const1664 Octagonal_Shape<T>::bounds(const Linear_Expression& expr,
1665                            const bool from_above) const {
1666   // The dimension of `expr' should not be greater than the dimension
1667   // of `*this'.
1668   const dimension_type expr_space_dim = expr.space_dimension();
1669   if (space_dim < expr_space_dim) {
1670     throw_dimension_incompatible((from_above
1671                                   ? "bounds_from_above(e)"
1672                                   : "bounds_from_below(e)"), "e", expr);
1673   }
1674   strong_closure_assign();
1675 
1676   // A zero-dimensional or empty octagon bounds everything.
1677   if (space_dim == 0 || marked_empty()) {
1678     return true;
1679   }
1680 
1681   // The constraint `c' is used to check if `expr' is an octagonal difference
1682   // and, in this case, to select the cell.
1683   const Constraint& c = (from_above) ? expr <= 0 : expr >= 0;
1684   dimension_type num_vars = 0;
1685   dimension_type i = 0;
1686   dimension_type j = 0;
1687   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
1688   PPL_DIRTY_TEMP_COEFFICIENT(term);
1689   if (Octagonal_Shape_Helper
1690     ::extract_octagonal_difference(c, c.space_dimension(), num_vars,
1691                                    i, j, coeff, term)) {
1692     if (num_vars == 0) {
1693       return true;
1694     }
1695     // Select the cell to be checked.
1696     typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin() + i;
1697     typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
1698     return !is_plus_infinity(m_i[j]);
1699   }
1700   else {
1701     // `c' is not an octagonal constraint: use the MIP solver.
1702     Optimization_Mode mode_bounds =
1703       from_above ? MAXIMIZATION : MINIMIZATION;
1704     MIP_Problem mip(space_dim, constraints(), expr, mode_bounds);
1705     return mip.solve() == OPTIMIZED_MIP_PROBLEM;
1706   }
1707 }
1708 
1709 template <typename T>
1710 bool
max_min(const Linear_Expression & expr,const bool maximize,Coefficient & ext_n,Coefficient & ext_d,bool & included) const1711 Octagonal_Shape<T>::max_min(const Linear_Expression& expr,
1712                             const bool maximize,
1713                             Coefficient& ext_n, Coefficient& ext_d,
1714                             bool& included) const {
1715   // The dimension of `expr' should not be greater than the dimension
1716   // of `*this'.
1717   const dimension_type expr_space_dim = expr.space_dimension();
1718   if (space_dim < expr_space_dim) {
1719     throw_dimension_incompatible((maximize
1720                                   ? "maximize(e, ...)"
1721                                   : "minimize(e, ...)"), "e", expr);
1722   }
1723   // Deal with zero-dim octagons first.
1724   if (space_dim == 0) {
1725     if (marked_empty()) {
1726       return false;
1727     }
1728     else {
1729       ext_n = expr.inhomogeneous_term();
1730       ext_d = 1;
1731       included = true;
1732       return true;
1733     }
1734   }
1735 
1736   strong_closure_assign();
1737   // For an empty OS we simply return false.
1738   if (marked_empty()) {
1739     return false;
1740   }
1741 
1742   // The constraint `c' is used to check if `expr' is an octagonal difference
1743   // and, in this case, to select the cell.
1744   const Constraint& c = (maximize) ? expr <= 0 : expr >= 0;
1745   dimension_type num_vars = 0;
1746   dimension_type i = 0;
1747   dimension_type j = 0;
1748   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
1749   PPL_DIRTY_TEMP_COEFFICIENT(term);
1750   if (!Octagonal_Shape_Helper
1751     ::extract_octagonal_difference(c, c.space_dimension(), num_vars,
1752                                    i, j, coeff, term)) {
1753     // `c' is not an octagonal constraint: use the MIP solver.
1754     Optimization_Mode max_min = (maximize) ? MAXIMIZATION : MINIMIZATION;
1755     MIP_Problem mip(space_dim, constraints(), expr, max_min);
1756     if (mip.solve() == OPTIMIZED_MIP_PROBLEM) {
1757       mip.optimal_value(ext_n, ext_d);
1758       included = true;
1759       return true;
1760     }
1761     else {
1762       // Here`expr' is unbounded in `*this'.
1763       return false;
1764     }
1765   }
1766   else {
1767     // `c' is an octagonal constraint.
1768     if (num_vars == 0) {
1769       ext_n = expr.inhomogeneous_term();
1770       ext_d = 1;
1771       included = true;
1772       return true;
1773     }
1774 
1775     // Select the cell to be checked.
1776     typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin() + i;
1777     typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
1778     PPL_DIRTY_TEMP(N, d);
1779     if (!is_plus_infinity(m_i[j])) {
1780       const Coefficient& b = expr.inhomogeneous_term();
1781       PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
1782       neg_assign(minus_b, b);
1783       const Coefficient& sc_b = maximize ? b : minus_b;
1784       assign_r(d, sc_b, ROUND_UP);
1785       // Set `coeff_expr' to the absolute value of coefficient of a variable
1786       // of `expr'.
1787       PPL_DIRTY_TEMP(N, coeff_expr);
1788       const Coefficient& coeff_i = expr.coefficient(Variable(i/2));
1789       const int sign_i = sgn(coeff_i);
1790       if (sign_i > 0) {
1791         assign_r(coeff_expr, coeff_i, ROUND_UP);
1792       }
1793       else {
1794         PPL_DIRTY_TEMP_COEFFICIENT(minus_coeff_i);
1795         neg_assign(minus_coeff_i, coeff_i);
1796         assign_r(coeff_expr, minus_coeff_i, ROUND_UP);
1797       }
1798       // Approximating the maximum/minimum of `expr'.
1799       if (num_vars == 1) {
1800         PPL_DIRTY_TEMP(N, m_i_j);
1801         div_2exp_assign_r(m_i_j, m_i[j], 1, ROUND_UP);
1802         add_mul_assign_r(d, coeff_expr, m_i_j, ROUND_UP);
1803       }
1804       else {
1805         add_mul_assign_r(d, coeff_expr, m_i[j], ROUND_UP);
1806       }
1807       numer_denom(d, ext_n, ext_d);
1808       if (!maximize) {
1809         neg_assign(ext_n);
1810       }
1811       included = true;
1812       return true;
1813     }
1814 
1815     // The `expr' is unbounded.
1816     return false;
1817   }
1818 }
1819 
1820 template <typename T>
1821 bool
max_min(const Linear_Expression & expr,const bool maximize,Coefficient & ext_n,Coefficient & ext_d,bool & included,Generator & g) const1822 Octagonal_Shape<T>::max_min(const Linear_Expression& expr,
1823                             const bool maximize,
1824                             Coefficient& ext_n, Coefficient& ext_d,
1825                             bool& included, Generator& g) const {
1826   // The dimension of `expr' should not be greater than the dimension
1827   // of `*this'.
1828   const dimension_type expr_space_dim = expr.space_dimension();
1829   if (space_dim < expr_space_dim) {
1830     throw_dimension_incompatible((maximize
1831                                   ? "maximize(e, ...)"
1832                                   : "minimize(e, ...)"), "e", expr);
1833   }
1834   // Deal with zero-dim octagons first.
1835   if (space_dim == 0) {
1836     if (marked_empty()) {
1837       return false;
1838     }
1839     else {
1840       ext_n = expr.inhomogeneous_term();
1841       ext_d = 1;
1842       included = true;
1843       g = point();
1844       return true;
1845     }
1846   }
1847 
1848   strong_closure_assign();
1849   // For an empty OS we simply return false.
1850   if (marked_empty()) {
1851     return false;
1852   }
1853   if (!is_universe()) {
1854     // We use MIP_Problems to handle constraints that are not
1855     // octagonal difference.
1856     Optimization_Mode max_min = (maximize) ? MAXIMIZATION : MINIMIZATION;
1857     MIP_Problem mip(space_dim, constraints(), expr, max_min);
1858     if (mip.solve() == OPTIMIZED_MIP_PROBLEM) {
1859       g = mip.optimizing_point();
1860       mip.evaluate_objective_function(g, ext_n, ext_d);
1861       included = true;
1862       return true;
1863     }
1864   }
1865   // The `expr' is unbounded.
1866   return false;
1867 }
1868 
1869 template <typename T>
1870 Poly_Con_Relation
relation_with(const Congruence & cg) const1871 Octagonal_Shape<T>::relation_with(const Congruence& cg) const {
1872   dimension_type cg_space_dim = cg.space_dimension();
1873 
1874   // Dimension-compatibility check.
1875   if (cg_space_dim > space_dim) {
1876     throw_dimension_incompatible("relation_with(cg)", cg);
1877   }
1878 
1879   // If the congruence is an equality,
1880   // find the relation with the equivalent equality constraint.
1881   if (cg.is_equality()) {
1882     Constraint c(cg);
1883     return relation_with(c);
1884   }
1885 
1886   strong_closure_assign();
1887 
1888   if (marked_empty()) {
1889     return Poly_Con_Relation::saturates()
1890       && Poly_Con_Relation::is_included()
1891       && Poly_Con_Relation::is_disjoint();
1892   }
1893 
1894   if (space_dim == 0) {
1895     if (cg.is_inconsistent()) {
1896       return Poly_Con_Relation::is_disjoint();
1897     }
1898     else {
1899       return Poly_Con_Relation::saturates()
1900         && Poly_Con_Relation::is_included();
1901     }
1902   }
1903 
1904   // Find the lower bound for a hyperplane with direction
1905   // defined by the congruence.
1906   Linear_Expression le(cg.expression());
1907   PPL_DIRTY_TEMP_COEFFICIENT(min_numer);
1908   PPL_DIRTY_TEMP_COEFFICIENT(min_denom);
1909   bool min_included;
1910   bool bounded_below = minimize(le, min_numer, min_denom, min_included);
1911 
1912   // If there is no lower bound, then some of the hyperplanes defined by
1913   // the congruence will strictly intersect the shape.
1914   if (!bounded_below) {
1915     return Poly_Con_Relation::strictly_intersects();
1916   }
1917 
1918   // TODO: Consider adding a max_and_min() method, performing both
1919   // maximization and minimization so as to possibly exploit
1920   // incrementality of the MIP solver.
1921 
1922   // Find the upper bound for a hyperplane with direction
1923   // defined by the congruence.
1924   PPL_DIRTY_TEMP_COEFFICIENT(max_numer);
1925   PPL_DIRTY_TEMP_COEFFICIENT(max_denom);
1926   bool max_included;
1927   bool bounded_above = maximize(le, max_numer, max_denom, max_included);
1928 
1929   // If there is no upper bound, then some of the hyperplanes defined by
1930   // the congruence will strictly intersect the shape.
1931   if (!bounded_above) {
1932     return Poly_Con_Relation::strictly_intersects();
1933   }
1934 
1935   PPL_DIRTY_TEMP_COEFFICIENT(signed_distance);
1936 
1937   // Find the position value for the hyperplane that satisfies the congruence
1938   // and is above the lower bound for the shape.
1939   PPL_DIRTY_TEMP_COEFFICIENT(min_value);
1940   min_value = min_numer / min_denom;
1941   const Coefficient& modulus = cg.modulus();
1942   signed_distance = min_value % modulus;
1943   min_value -= signed_distance;
1944   if (min_value * min_denom < min_numer) {
1945     min_value += modulus;
1946   }
1947 
1948   // Find the position value for the hyperplane that satisfies the congruence
1949   // and is below the upper bound for the shape.
1950   PPL_DIRTY_TEMP_COEFFICIENT(max_value);
1951   max_value = max_numer / max_denom;
1952   signed_distance = max_value % modulus;
1953   max_value += signed_distance;
1954   if (max_value * max_denom > max_numer) {
1955     max_value -= modulus;
1956   }
1957 
1958   // If the upper bound value is less than the lower bound value,
1959   // then there is an empty intersection with the congruence;
1960   // otherwise it will strictly intersect.
1961   if (max_value < min_value) {
1962     return Poly_Con_Relation::is_disjoint();
1963   }
1964   else {
1965     return Poly_Con_Relation::strictly_intersects();
1966   }
1967 }
1968 
1969 template <typename T>
1970 Poly_Con_Relation
relation_with(const Constraint & c) const1971 Octagonal_Shape<T>::relation_with(const Constraint& c) const {
1972   dimension_type c_space_dim = c.space_dimension();
1973 
1974   // Dimension-compatibility check.
1975   if (c_space_dim > space_dim) {
1976     throw_dimension_incompatible("relation_with(c)", c);
1977   }
1978 
1979   // The closure needs to make explicit the implicit constraints.
1980   strong_closure_assign();
1981 
1982   if (marked_empty()) {
1983     return Poly_Con_Relation::saturates()
1984       && Poly_Con_Relation::is_included()
1985       && Poly_Con_Relation::is_disjoint();
1986   }
1987 
1988   if (space_dim == 0) {
1989     // Trivially false zero-dimensional constraint.
1990     if ((c.is_equality() && c.inhomogeneous_term() != 0)
1991         || (c.is_inequality() && c.inhomogeneous_term() < 0)) {
1992       return Poly_Con_Relation::is_disjoint();
1993     }
1994     else if (c.is_strict_inequality() && c.inhomogeneous_term() == 0) {
1995       // The constraint 0 > 0 implicitly defines the hyperplane 0 = 0;
1996       // thus, the zero-dimensional point also saturates it.
1997       return Poly_Con_Relation::saturates()
1998         && Poly_Con_Relation::is_disjoint();
1999     }
2000 
2001     // Trivially true zero-dimensional constraint.
2002     else if (c.is_equality() || c.inhomogeneous_term() == 0) {
2003       return Poly_Con_Relation::saturates()
2004         && Poly_Con_Relation::is_included();
2005     }
2006     else {
2007       // The zero-dimensional point saturates
2008       // neither the positivity constraint 1 >= 0,
2009       // nor the strict positivity constraint 1 > 0.
2010       return Poly_Con_Relation::is_included();
2011     }
2012   }
2013 
2014   dimension_type num_vars = 0;
2015   dimension_type i = 0;
2016   dimension_type j = 0;
2017   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
2018   PPL_DIRTY_TEMP_COEFFICIENT(c_term);
2019   if (!Octagonal_Shape_Helper
2020     ::extract_octagonal_difference(c, c_space_dim, num_vars,
2021                                    i, j, coeff, c_term)) {
2022     // Constraints that are not octagonal differences.
2023     // Use maximize() and minimize() to do much of the work.
2024 
2025     // Find the linear expression for the constraint and use that to
2026     // find if the expression is bounded from above or below and if it
2027     // is, find the maximum and minimum values.
2028     Linear_Expression le;
2029     le.set_space_dimension(c.space_dimension());
2030     le.linear_combine(c.expr, Coefficient_one(), Coefficient_one(),
2031                       1, c_space_dim + 1);
2032 
2033     PPL_DIRTY_TEMP_COEFFICIENT(max_numer);
2034     PPL_DIRTY_TEMP_COEFFICIENT(max_denom);
2035     bool max_included;
2036     PPL_DIRTY_TEMP_COEFFICIENT(min_numer);
2037     PPL_DIRTY_TEMP_COEFFICIENT(min_denom);
2038     bool min_included;
2039     bool bounded_above = maximize(le, max_numer, max_denom, max_included);
2040     bool bounded_below = minimize(le, min_numer, min_denom, min_included);
2041     if (!bounded_above) {
2042       if (!bounded_below) {
2043         return Poly_Con_Relation::strictly_intersects();
2044       }
2045       min_numer += c.inhomogeneous_term() * min_denom;
2046       switch (sgn(min_numer)) {
2047       case 1:
2048         if (c.is_equality()) {
2049           return Poly_Con_Relation::is_disjoint();
2050         }
2051         return Poly_Con_Relation::is_included();
2052       case 0:
2053         if (c.is_strict_inequality() || c.is_equality()) {
2054           return Poly_Con_Relation::strictly_intersects();
2055         }
2056         return Poly_Con_Relation::is_included();
2057       case -1:
2058         return Poly_Con_Relation::strictly_intersects();
2059       }
2060     }
2061     if (!bounded_below) {
2062       max_numer += c.inhomogeneous_term() * max_denom;
2063       switch (sgn(max_numer)) {
2064       case 1:
2065         return Poly_Con_Relation::strictly_intersects();
2066       case 0:
2067         if (c.is_strict_inequality()) {
2068           return Poly_Con_Relation::is_disjoint();
2069         }
2070         return Poly_Con_Relation::strictly_intersects();
2071       case -1:
2072         return Poly_Con_Relation::is_disjoint();
2073       }
2074     }
2075     else {
2076       max_numer += c.inhomogeneous_term() * max_denom;
2077       min_numer += c.inhomogeneous_term() * min_denom;
2078       switch (sgn(max_numer)) {
2079       case 1:
2080         switch (sgn(min_numer)) {
2081         case 1:
2082           if (c.is_equality()) {
2083             return Poly_Con_Relation::is_disjoint();
2084           }
2085           return Poly_Con_Relation::is_included();
2086         case 0:
2087           if (c.is_equality()) {
2088             return Poly_Con_Relation::strictly_intersects();
2089           }
2090           if (c.is_strict_inequality()) {
2091             return Poly_Con_Relation::strictly_intersects();
2092           }
2093           return Poly_Con_Relation::is_included();
2094         case -1:
2095           return Poly_Con_Relation::strictly_intersects();
2096         }
2097         PPL_UNREACHABLE;
2098         break;
2099       case 0:
2100         if (min_numer == 0) {
2101           if (c.is_strict_inequality()) {
2102             return Poly_Con_Relation::is_disjoint()
2103               && Poly_Con_Relation::saturates();
2104           }
2105           return Poly_Con_Relation::is_included()
2106             && Poly_Con_Relation::saturates();
2107         }
2108         if (c.is_strict_inequality()) {
2109           return Poly_Con_Relation::is_disjoint();
2110         }
2111         return Poly_Con_Relation::strictly_intersects();
2112       case -1:
2113         return Poly_Con_Relation::is_disjoint();
2114       }
2115     }
2116   }
2117 
2118   if (num_vars == 0) {
2119     // Dealing with a trivial constraint.
2120     switch (sgn(c.inhomogeneous_term())) {
2121     case -1:
2122       return Poly_Con_Relation::is_disjoint();
2123     case 0:
2124       if (c.is_strict_inequality()) {
2125         return Poly_Con_Relation::saturates()
2126           && Poly_Con_Relation::is_disjoint();
2127       }
2128       else {
2129         return Poly_Con_Relation::saturates()
2130           && Poly_Con_Relation::is_included();
2131       }
2132     case 1:
2133       if (c.is_equality()) {
2134         return Poly_Con_Relation::is_disjoint();
2135       }
2136       else {
2137         return Poly_Con_Relation::is_included();
2138       }
2139     }
2140   }
2141 
2142   // Select the cell to be checked for the "<=" part of constraint.
2143   typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin() + i;
2144   typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
2145   const N& m_i_j = m_i[j];
2146   // Set `coeff' to the absolute value of itself.
2147   if (coeff < 0) {
2148     neg_assign(coeff);
2149   }
2150 
2151   // Select the cell to be checked for the ">=" part of constraint.
2152   // Select the right row of the cell.
2153   if (i % 2 == 0) {
2154     ++i_iter;
2155   }
2156   else {
2157     --i_iter;
2158   }
2159   typename OR_Matrix<N>::const_row_reference_type m_ci = *i_iter;
2160   using namespace Implementation::Octagonal_Shapes;
2161   const N& m_ci_cj = m_ci[coherent_index(j)];
2162   PPL_DIRTY_TEMP_COEFFICIENT(numer);
2163   PPL_DIRTY_TEMP_COEFFICIENT(denom);
2164   // The following variables of mpq_class type are used to be precise
2165   // when the octagon is defined by integer constraints.
2166   PPL_DIRTY_TEMP(mpq_class, q_x);
2167   PPL_DIRTY_TEMP(mpq_class, q_y);
2168   PPL_DIRTY_TEMP(mpq_class, d);
2169   PPL_DIRTY_TEMP(mpq_class, d1);
2170   PPL_DIRTY_TEMP(mpq_class, c_denom);
2171   PPL_DIRTY_TEMP(mpq_class, q_denom);
2172   assign_r(c_denom, coeff, ROUND_NOT_NEEDED);
2173   assign_r(d, c_term, ROUND_NOT_NEEDED);
2174   neg_assign_r(d1, d, ROUND_NOT_NEEDED);
2175   div_assign_r(d, d, c_denom, ROUND_NOT_NEEDED);
2176   div_assign_r(d1, d1, c_denom, ROUND_NOT_NEEDED);
2177 
2178   if (is_plus_infinity(m_i_j)) {
2179     if (!is_plus_infinity(m_ci_cj)) {
2180       // `*this' is in the following form:
2181       // `-m_ci_cj <= v - u'.
2182       // In this case `*this' is disjoint from `c' if
2183       // `-m_ci_cj > d' (`-m_ci_cj >= d' if c is a strict inequality),
2184       // i.e., if `m_ci_cj < d1' (`m_ci_cj <= d1'
2185       // if c is a strict inequality).
2186       numer_denom(m_ci_cj, numer, denom);
2187       assign_r(q_denom, denom, ROUND_NOT_NEEDED);
2188       assign_r(q_y, numer, ROUND_NOT_NEEDED);
2189       div_assign_r(q_y, q_y, q_denom, ROUND_NOT_NEEDED);
2190       if (q_y < d1) {
2191         return Poly_Con_Relation::is_disjoint();
2192       }
2193       if (q_y == d1 && c.is_strict_inequality()) {
2194         return Poly_Con_Relation::is_disjoint();
2195       }
2196     }
2197 
2198     // In all other cases `*this' intersects `c'.
2199     return Poly_Con_Relation::strictly_intersects();
2200   }
2201 
2202   // Here `m_i_j' is not plus-infinity.
2203   numer_denom(m_i_j, numer, denom);
2204   assign_r(q_denom, denom, ROUND_NOT_NEEDED);
2205   assign_r(q_x, numer, ROUND_NOT_NEEDED);
2206   div_assign_r(q_x, q_x, q_denom, ROUND_NOT_NEEDED);
2207 
2208   if (!is_plus_infinity(m_ci_cj)) {
2209     numer_denom(m_ci_cj, numer, denom);
2210     assign_r(q_denom, denom, ROUND_NOT_NEEDED);
2211     assign_r(q_y, numer, ROUND_NOT_NEEDED);
2212     div_assign_r(q_y, q_y, q_denom, ROUND_NOT_NEEDED);
2213     if (q_x == d && q_y == d1) {
2214       if (c.is_strict_inequality()) {
2215         return Poly_Con_Relation::saturates()
2216           && Poly_Con_Relation::is_disjoint();
2217       }
2218       else {
2219         return Poly_Con_Relation::saturates()
2220           && Poly_Con_Relation::is_included();
2221       }
2222     }
2223     // `*this' is disjoint from `c' when
2224     // `m_ci_cj < d1' (`m_ci_cj <= d1' if `c' is a strict inequality).
2225     if (q_y < d1) {
2226       return Poly_Con_Relation::is_disjoint();
2227     }
2228     if (q_y == d1 && c.is_strict_inequality()) {
2229       return Poly_Con_Relation::is_disjoint();
2230     }
2231   }
2232 
2233   // Here `m_ci_cj' can be also plus-infinity.
2234   // If `c' is an equality, `*this' is disjoint from `c' if
2235   // `m_i_j < d'.
2236   if (d > q_x) {
2237     if (c.is_equality()) {
2238       return Poly_Con_Relation::is_disjoint();
2239     }
2240     else {
2241       return Poly_Con_Relation::is_included();
2242     }
2243   }
2244 
2245   if (d == q_x && c.is_nonstrict_inequality()) {
2246     return Poly_Con_Relation::is_included();
2247   }
2248   // In all other cases `*this' intersects `c'.
2249   return Poly_Con_Relation::strictly_intersects();
2250 }
2251 
2252 template <typename T>
2253 Poly_Gen_Relation
relation_with(const Generator & g) const2254 Octagonal_Shape<T>::relation_with(const Generator& g) const {
2255   const dimension_type g_space_dim = g.space_dimension();
2256 
2257   // Dimension-compatibility check.
2258   if (space_dim < g_space_dim) {
2259     throw_dimension_incompatible("relation_with(g)", g);
2260   }
2261 
2262   // The closure needs to make explicit the implicit constraints and if the
2263   // octagon is empty.
2264   strong_closure_assign();
2265 
2266   // The empty octagon cannot subsume a generator.
2267   if (marked_empty()) {
2268     return Poly_Gen_Relation::nothing();
2269   }
2270 
2271   // A universe octagon in a zero-dimensional space subsumes
2272   // all the generators of a zero-dimensional space.
2273   if (space_dim == 0) {
2274     return Poly_Gen_Relation::subsumes();
2275   }
2276 
2277   const bool is_line = g.is_line();
2278   const bool is_line_or_ray = g.is_line_or_ray();
2279 
2280   // The relation between the octagon and the given generator is obtained
2281   // checking if the generator satisfies all the constraints in the octagon.
2282   // To check if the generator satisfies all the constraints it's enough
2283   // studying the sign of the scalar product between the generator and
2284   // all the constraints in the octagon.
2285 
2286   typedef typename OR_Matrix<N>::const_row_iterator row_iterator;
2287   typedef typename OR_Matrix<N>::const_row_reference_type row_reference;
2288 
2289   const row_iterator m_begin = matrix.row_begin();
2290   const row_iterator m_end = matrix.row_end();
2291 
2292   PPL_DIRTY_TEMP_COEFFICIENT(numer);
2293   PPL_DIRTY_TEMP_COEFFICIENT(denom);
2294   PPL_DIRTY_TEMP_COEFFICIENT(product);
2295 
2296   // We find in `*this' all the constraints.
2297   for (row_iterator i_iter = m_begin; i_iter != m_end; i_iter += 2) {
2298     dimension_type i = i_iter.index();
2299     row_reference m_i = *i_iter;
2300     row_reference m_ii = *(i_iter + 1);
2301     const N& m_i_ii = m_i[i + 1];
2302     const N& m_ii_i = m_ii[i];
2303     // We have the unary constraints.
2304     const Variable x(i/2);
2305     const Coefficient& g_coeff_x
2306       = (x.space_dimension() > g_space_dim)
2307       ? Coefficient_zero()
2308       : g.coefficient(x);
2309     if (is_additive_inverse(m_i_ii, m_ii_i)) {
2310       // The constraint has form ax = b.
2311       // To satisfy the constraint it is necessary that the scalar product
2312       // is not zero. The scalar product has the form
2313       // 'denom * g_coeff_x - numer * g.divisor()'.
2314       numer_denom(m_ii_i, numer, denom);
2315       denom *= 2;
2316       product = denom * g_coeff_x;
2317       // Note that if the generator `g' is a line or a ray,
2318       // its divisor is zero.
2319       if (!is_line_or_ray) {
2320         neg_assign(numer);
2321         add_mul_assign(product, numer, g.divisor());
2322       }
2323       if (product != 0) {
2324         return Poly_Gen_Relation::nothing();
2325       }
2326     }
2327     // We have 0, 1 or 2 inequality constraints.
2328     else {
2329       if (!is_plus_infinity(m_i_ii)) {
2330         // The constraint has form -ax <= b.
2331         // If the generator is a line it's necessary to check if
2332         // the scalar product is not zero, if it is positive otherwise.
2333         numer_denom(m_i_ii, numer, denom);
2334         denom *= -2;
2335         product = denom * g_coeff_x;
2336         // Note that if the generator `g' is a line or a ray,
2337         // its divisor is zero.
2338         if (!is_line_or_ray) {
2339           neg_assign(numer);
2340           add_mul_assign(product, numer, g.divisor());
2341         }
2342         if (is_line && product != 0) {
2343           return Poly_Gen_Relation::nothing();
2344         }
2345         else
2346           // If the generator is not a line it's necessary to check
2347           // that the scalar product sign is not positive and the scalar
2348           // product has the form
2349           // '-denom * g.coeff_x - numer * g.divisor()'.
2350           if (product > 0) {
2351             return Poly_Gen_Relation::nothing();
2352           }
2353       }
2354       if (!is_plus_infinity(m_ii_i)) {
2355         // The constraint has form ax <= b.
2356         numer_denom(m_ii_i, numer, denom);
2357         denom *= 2;
2358         product = denom * g_coeff_x;
2359          // Note that if the generator `g' is a line or a ray,
2360         // its divisor is zero.
2361         if (!is_line_or_ray) {
2362           neg_assign(numer);
2363           add_mul_assign(product, numer , g.divisor());
2364         }
2365         if (is_line && product != 0) {
2366           return Poly_Gen_Relation::nothing();
2367         }
2368         else {
2369           // If the generator is not a line it's necessary to check
2370           // that the scalar product sign is not positive and the scalar
2371           // product has the form
2372           // 'denom * g_coeff_x - numer * g.divisor()'.
2373           if (product > 0) {
2374             return Poly_Gen_Relation::nothing();
2375           }
2376         }
2377       }
2378     }
2379   }
2380 
2381   // We have the binary constraints.
2382   for (row_iterator i_iter = m_begin ; i_iter != m_end; i_iter += 2) {
2383     dimension_type i = i_iter.index();
2384     row_reference m_i = *i_iter;
2385     row_reference m_ii = *(i_iter + 1);
2386     for (dimension_type j = 0; j < i; j += 2) {
2387       const N& m_i_j = m_i[j];
2388       const N& m_ii_jj = m_ii[j + 1];
2389       const N& m_ii_j = m_ii[j];
2390       const N& m_i_jj = m_i[j + 1];
2391       const Variable x(j/2);
2392       const Variable y(i/2);
2393       const Coefficient& g_coeff_x
2394         = (x.space_dimension() > g_space_dim)
2395         ? Coefficient_zero()
2396         : g.coefficient(x);
2397       const Coefficient& g_coeff_y
2398         = (y.space_dimension() > g_space_dim)
2399         ? Coefficient_zero()
2400         : g.coefficient(y);
2401 
2402       const bool difference_is_equality = is_additive_inverse(m_ii_jj, m_i_j);
2403       if (difference_is_equality) {
2404         // The constraint has form a*x - a*y = b.
2405         // The scalar product has the form
2406         // 'denom * coeff_x - denom * coeff_y - numer * g.divisor()'.
2407         // To satisfy the constraint it's necessary that the scalar product
2408         // is not zero.
2409         numer_denom(m_i_j, numer, denom);
2410         product = denom * g_coeff_x;
2411         neg_assign(denom);
2412         add_mul_assign(product, denom, g_coeff_y);
2413         // Note that if the generator `g' is a line or a ray,
2414         // its divisor is zero.
2415         if (!is_line_or_ray) {
2416           neg_assign(numer);
2417           add_mul_assign(product, numer, g.divisor());
2418         }
2419         if (product != 0) {
2420           return Poly_Gen_Relation::nothing();
2421         }
2422       }
2423       else {
2424         if (!is_plus_infinity(m_i_j)) {
2425           // The constraint has form a*x - a*y <= b.
2426           // The scalar product has the form
2427           // 'denom * coeff_x - denom * coeff_y - numer * g.divisor()'.
2428           // If the generator is not a line it's necessary to check
2429           // that the scalar product sign is not positive.
2430           numer_denom(m_i_j, numer, denom);
2431           product = denom * g_coeff_x;
2432           neg_assign(denom);
2433           add_mul_assign(product, denom, g_coeff_y);
2434           // Note that if the generator `g' is a line or a ray,
2435           // its divisor is zero.
2436           if (!is_line_or_ray) {
2437             neg_assign(numer);
2438             add_mul_assign(product, numer, g.divisor());
2439           }
2440           if (is_line && product != 0) {
2441             return Poly_Gen_Relation::nothing();
2442           }
2443           else if (product > 0) {
2444             return Poly_Gen_Relation::nothing();
2445           }
2446         }
2447         if (!is_plus_infinity(m_ii_jj)) {
2448           // The constraint has form -a*x + a*y <= b.
2449           // The scalar product has the form
2450           // '-denom * coeff_x + denom * coeff_y - numer * g.divisor()'.
2451           // If the generator is not a line it's necessary to check
2452           // that the scalar product sign is not positive.
2453           numer_denom(m_ii_jj, numer, denom);
2454           product = denom * g_coeff_y;
2455           neg_assign(denom);
2456           add_mul_assign(product, denom, g_coeff_x);
2457           // Note that if the generator `g' is a line or a ray,
2458           // its divisor is zero.
2459           if (!is_line_or_ray) {
2460             neg_assign(numer);
2461             add_mul_assign(product, numer, g.divisor());
2462           }
2463           if (is_line && product != 0) {
2464             return Poly_Gen_Relation::nothing();
2465           }
2466           else if (product > 0) {
2467             return Poly_Gen_Relation::nothing();
2468           }
2469         }
2470       }
2471 
2472       const bool sum_is_equality = is_additive_inverse(m_i_jj, m_ii_j);
2473       if (sum_is_equality) {
2474         // The constraint has form a*x + a*y = b.
2475         // The scalar product has the form
2476         // 'denom * coeff_x + denom * coeff_y - numer * g.divisor()'.
2477         // To satisfy the constraint it's necessary that the scalar product
2478         // is not zero.
2479         numer_denom(m_ii_j, numer, denom);
2480         product = denom * g_coeff_x;
2481         add_mul_assign(product, denom, g_coeff_y);
2482         // Note that if the generator `g' is a line or a ray,
2483         // its divisor is zero.
2484         if (!is_line_or_ray) {
2485           neg_assign(numer);
2486           add_mul_assign(product, numer, g.divisor());
2487         }
2488         if (product != 0) {
2489           return Poly_Gen_Relation::nothing();
2490         }
2491       }
2492       else {
2493         if (!is_plus_infinity(m_i_jj)) {
2494           // The constraint has form -a*x - a*y <= b.
2495           // The scalar product has the form
2496           // '-denom * coeff_x - denom * coeff_y - numer * g.divisor()'.
2497           // If the generator is not a line it's necessary to check
2498           // that the scalar product sign is not positive.
2499           numer_denom(m_i_jj, numer, denom);
2500           neg_assign(denom);
2501           product = denom * g_coeff_x;
2502           add_mul_assign(product, denom, g_coeff_y);
2503           // Note that if the generator `g' is a line or a ray,
2504           // its divisor is zero.
2505           if (!is_line_or_ray) {
2506             neg_assign(numer);
2507             add_mul_assign(product, numer, g.divisor());
2508           }
2509           if (is_line && product != 0) {
2510             return Poly_Gen_Relation::nothing();
2511           }
2512           else if (product > 0) {
2513             return Poly_Gen_Relation::nothing();
2514           }
2515         }
2516         if (!is_plus_infinity(m_ii_j)) {
2517           // The constraint has form a*x + a*y <= b.
2518           // The scalar product has the form
2519           // 'denom * coeff_x + denom * coeff_y - numer * g.divisor()'.
2520           // If the generator is not a line it's necessary to check
2521           // that the scalar product sign is not positive.
2522           numer_denom(m_ii_j, numer, denom);
2523           product = denom * g_coeff_x;
2524           add_mul_assign(product, denom, g_coeff_y);
2525           // Note that if the generator `g' is a line or a ray,
2526           // its divisor is zero.
2527           if (!is_line_or_ray) {
2528             neg_assign(numer);
2529             add_mul_assign(product, numer, g.divisor());
2530           }
2531           if (is_line && product != 0) {
2532             return Poly_Gen_Relation::nothing();
2533           }
2534           else if (product > 0) {
2535             return Poly_Gen_Relation::nothing();
2536           }
2537         }
2538       }
2539     }
2540   }
2541   // If this point is reached the constraint 'g' satisfies
2542   // all the constraints in the octagon.
2543   return Poly_Gen_Relation::subsumes();
2544 }
2545 
2546 template <typename T>
2547 void
strong_closure_assign() const2548 Octagonal_Shape<T>::strong_closure_assign() const {
2549   // Do something only if necessary (zero-dim implies strong closure).
2550   if (marked_empty() || marked_strongly_closed() || space_dim == 0) {
2551     return;
2552   }
2553   // Even though the octagon will not change, its internal representation
2554   // is going to be modified by the closure algorithm.
2555   Octagonal_Shape& x = const_cast<Octagonal_Shape<T>&>(*this);
2556 
2557   typedef typename OR_Matrix<N>::row_iterator row_iterator;
2558   typedef typename OR_Matrix<N>::row_reference_type row_reference;
2559 
2560   const dimension_type n_rows = x.matrix.num_rows();
2561   const row_iterator m_begin = x.matrix.row_begin();
2562   const row_iterator m_end = x.matrix.row_end();
2563 
2564   // Fill the main diagonal with zeros.
2565   for (row_iterator i = m_begin; i != m_end; ++i) {
2566     PPL_ASSERT(is_plus_infinity((*i)[i.index()]));
2567     assign_r((*i)[i.index()], 0, ROUND_NOT_NEEDED);
2568   }
2569 
2570   // This algorithm is given by two steps: the first one is a simple
2571   // adaptation of the `shortest-path closure' using the Floyd-Warshall
2572   // algorithm; the second one is the `strong-coherence' algorithm.
2573   // It is important to note that after the strong-coherence,
2574   // the octagon is still shortest-path closed and hence, strongly closed.
2575 
2576   // Recall that, given an index `h', we indicate with `ch' the coherent
2577   // index, i.e., the index such that:
2578   //   ch = h + 1, if h is an even number;
2579   //   ch = h - 1, if h is an odd number.
2580 
2581   typename OR_Matrix<N>::element_iterator iter_ij;
2582   std::vector<N> vec_k(n_rows);
2583   std::vector<N> vec_ck(n_rows);
2584   PPL_DIRTY_TEMP(N, sum1);
2585   PPL_DIRTY_TEMP(N, sum2);
2586   row_reference x_k;
2587   row_reference x_ck;
2588   row_reference x_i;
2589   row_reference x_ci;
2590 
2591   // Since the index `j' of the inner loop will go from 0 up to `i',
2592   // the three nested loops have to be executed twice.
2593   for (int twice = 0; twice < 2; ++twice) {
2594 
2595     row_iterator x_k_iter = m_begin;
2596     row_iterator x_i_iter = m_begin;
2597     for (dimension_type k = 0; k < n_rows; k += 2) {
2598       const dimension_type ck = k + 1;
2599       // Re-initialize the element iterator.
2600       iter_ij = x.matrix.element_begin();
2601       // Compute the row references `x_k' and `x_ck'.
2602       x_k  = *x_k_iter;
2603       ++x_k_iter;
2604       x_ck = *x_k_iter;
2605       ++x_k_iter;
2606 
2607       for (dimension_type i = 0; i <= k; i += 2) {
2608         const dimension_type ci = i + 1;
2609         // Storing x_k_i == x_ci_ck.
2610         vec_k[i] = x_k[i];
2611         // Storing x_k_ci == x_i_ck.
2612         vec_k[ci] = x_k[ci];
2613         // Storing x_ck_i == x_ci_k.
2614         vec_ck[i] = x_ck[i];
2615         // Storing x_ck_ci == x_i_k.
2616         vec_ck[ci] = x_ck[ci];
2617       }
2618       x_i_iter = x_k_iter;
2619       for (dimension_type i = k + 2; i < n_rows; i += 2) {
2620         const dimension_type ci = i + 1;
2621         x_i = *x_i_iter;
2622         ++x_i_iter;
2623         x_ci = *x_i_iter;
2624         ++x_i_iter;
2625         // Storing x_k_i == x_ci_ck.
2626         vec_k[i] = x_ci[ck];
2627         // Storing x_k_ci == x_i_ck.
2628         vec_k[ci] = x_i[ck];
2629         // Storing x_ck_i == x_ci_k.
2630         vec_ck[i] = x_ci[k];
2631         // Storing x_ck_ci == x_i_k.
2632         vec_ck[ci] = x_i[k];
2633       }
2634 
2635       for (dimension_type i = 0; i < n_rows; ++i) {
2636         using namespace Implementation::Octagonal_Shapes;
2637         const dimension_type ci = coherent_index(i);
2638         const N& vec_k_ci = vec_k[ci];
2639         const N& vec_ck_ci = vec_ck[ci];
2640         // Unfolding two iterations on `j': this ensures that
2641         // the loop exit condition `j <= i' is OK.
2642         for (dimension_type j = 0; j <= i; ) {
2643           // First iteration: compute
2644           //
2645           // <CODE>
2646           //   sum1 = x_i_k + x_k_j == x_ck_ci + x_k_j;
2647           //   sum2 = x_i_ck + x_ck_j == x_k_ci + x_ck_j;
2648           // </CODE>
2649           add_assign_r(sum1, vec_ck_ci, vec_k[j], ROUND_UP);
2650           add_assign_r(sum2, vec_k_ci, vec_ck[j], ROUND_UP);
2651           min_assign(sum1, sum2);
2652           min_assign(*iter_ij, sum1);
2653           // Exiting the first iteration: loop index control.
2654           ++j;
2655           ++iter_ij;
2656           // Second iteration: ditto.
2657           add_assign_r(sum1, vec_ck_ci, vec_k[j], ROUND_UP);
2658           add_assign_r(sum2, vec_k_ci, vec_ck[j], ROUND_UP);
2659           min_assign(sum1, sum2);
2660           min_assign(*iter_ij, sum1);
2661           // Exiting the second iteration: loop index control.
2662           ++j;
2663           ++iter_ij;
2664         }
2665       }
2666     }
2667   }
2668 
2669   // Check for emptiness: the octagon is empty if and only if there is a
2670   // negative value in the main diagonal.
2671   for (row_iterator i = m_begin; i != m_end; ++i) {
2672     N& x_i_i = (*i)[i.index()];
2673     if (sgn(x_i_i) < 0) {
2674       x.set_empty();
2675       return;
2676     }
2677     else {
2678       PPL_ASSERT(sgn(x_i_i) == 0);
2679       // Restore PLUS_INFINITY on the main diagonal.
2680       assign_r(x_i_i, PLUS_INFINITY, ROUND_NOT_NEEDED);
2681     }
2682   }
2683 
2684   // Step 2: we enforce the strong coherence.
2685   x.strong_coherence_assign();
2686   // The octagon is not empty and it is now strongly closed.
2687   x.set_strongly_closed();
2688 }
2689 
2690 template <typename T>
2691 void
strong_coherence_assign()2692 Octagonal_Shape<T>::strong_coherence_assign() {
2693   // The strong-coherence is: for every indexes i and j
2694   // m_i_j <= (m_i_ci + m_cj_j)/2
2695   // where ci = i + 1, if i is even number or
2696   //       ci = i - 1, if i is odd.
2697   // Ditto for cj.
2698   PPL_DIRTY_TEMP(N, semi_sum);
2699   for (typename OR_Matrix<N>::row_iterator i_iter = matrix.row_begin(),
2700          i_end = matrix.row_end(); i_iter != i_end; ++i_iter) {
2701     typename OR_Matrix<N>::row_reference_type x_i = *i_iter;
2702     const dimension_type i = i_iter.index();
2703     using namespace Implementation::Octagonal_Shapes;
2704     const N& x_i_ci = x_i[coherent_index(i)];
2705     // Avoid to do unnecessary sums.
2706     if (!is_plus_infinity(x_i_ci)) {
2707       for (dimension_type j = 0, rs_i = i_iter.row_size();
2708            j < rs_i; ++j) {
2709         if (i != j) {
2710           const N& x_cj_j = matrix[coherent_index(j)][j];
2711           if (!is_plus_infinity(x_cj_j)) {
2712             add_assign_r(semi_sum, x_i_ci, x_cj_j, ROUND_UP);
2713             div_2exp_assign_r(semi_sum, semi_sum, 1, ROUND_UP);
2714             min_assign(x_i[j], semi_sum);
2715           }
2716         }
2717       }
2718     }
2719   }
2720 }
2721 
2722 template <typename T>
2723 bool
tight_coherence_would_make_empty() const2724 Octagonal_Shape<T>::tight_coherence_would_make_empty() const {
2725   PPL_ASSERT(std::numeric_limits<N>::is_integer);
2726   PPL_ASSERT(marked_strongly_closed());
2727   for (dimension_type i = 0; i < 2*space_dim; i += 2) {
2728     const dimension_type ci = i + 1;
2729     const N& mat_i_ci = matrix[i][ci];
2730     if (!is_plus_infinity(mat_i_ci)
2731         // Check for oddness of `mat_i_ci'.
2732         && !is_even(mat_i_ci)
2733         // Check for zero-equivalence of `i' and `ci'.
2734         && is_additive_inverse(mat_i_ci, matrix[ci][i])) {
2735       return true;
2736     }
2737   }
2738   return false;
2739 }
2740 
2741 template <typename T>
2742 void
tight_closure_assign()2743 Octagonal_Shape<T>::tight_closure_assign() {
2744   PPL_COMPILE_TIME_CHECK(std::numeric_limits<T>::is_integer,
2745                          "Octagonal_Shape<T>::tight_closure_assign():"
2746                          " T in not an integer datatype.");
2747   // FIXME: this is just an executable specification.
2748   // (The following call could be replaced by shortest-path closure.)
2749   strong_closure_assign();
2750   if (marked_empty()) {
2751     return;
2752   }
2753   if (tight_coherence_would_make_empty()) {
2754     set_empty();
2755   }
2756   else {
2757     // Tighten the unary constraints.
2758     PPL_DIRTY_TEMP(N, temp_one);
2759     assign_r(temp_one, 1, ROUND_NOT_NEEDED);
2760     for (dimension_type i = 0; i < 2*space_dim; i += 2) {
2761       const dimension_type ci = i + 1;
2762       N& mat_i_ci = matrix[i][ci];
2763       if (!is_plus_infinity(mat_i_ci) && !is_even(mat_i_ci)) {
2764         sub_assign_r(mat_i_ci, mat_i_ci, temp_one, ROUND_UP);
2765       }
2766       N& mat_ci_i = matrix[ci][i];
2767       if (!is_plus_infinity(mat_ci_i) && !is_even(mat_ci_i)) {
2768         sub_assign_r(mat_ci_i, mat_ci_i, temp_one, ROUND_UP);
2769       }
2770     }
2771     // Propagate tightened unary constraints.
2772     strong_coherence_assign();
2773   }
2774   PPL_ASSERT(OK());
2775 }
2776 
2777 template <typename T>
2778 void
2779 Octagonal_Shape<T>
incremental_strong_closure_assign(const Variable var) const2780 ::incremental_strong_closure_assign(const Variable var) const {
2781   // `var' should be one of the dimensions of the octagon.
2782   if (var.id() >= space_dim) {
2783     throw_dimension_incompatible("incremental_strong_closure_assign(v)",
2784                                  var.id());
2785   }
2786 
2787   // Do something only if necessary.
2788   if (marked_empty() || marked_strongly_closed()) {
2789     return;
2790   }
2791 
2792   Octagonal_Shape& x = const_cast<Octagonal_Shape<T>&>(*this);
2793 
2794   typedef typename OR_Matrix<N>::row_iterator row_iterator;
2795   typedef typename OR_Matrix<N>::row_reference_type row_reference;
2796 
2797   const row_iterator m_begin = x.matrix.row_begin();
2798   const row_iterator m_end = x.matrix.row_end();
2799 
2800   // Fill the main diagonal with zeros.
2801   for (row_iterator i = m_begin; i != m_end; ++i) {
2802     PPL_ASSERT(is_plus_infinity((*i)[i.index()]));
2803     assign_r((*i)[i.index()], 0, ROUND_NOT_NEEDED);
2804   }
2805 
2806   // Using the incremental Floyd-Warshall algorithm.
2807   // Step 1: Improve all constraints on variable `var'.
2808   const dimension_type v = 2*var.id();
2809   const dimension_type cv = v + 1;
2810   row_iterator v_iter = m_begin + v;
2811   row_iterator cv_iter = v_iter + 1;
2812   row_reference x_v = *v_iter;
2813   row_reference x_cv = *cv_iter;
2814   const dimension_type rs_v = v_iter.row_size();
2815   const dimension_type n_rows = x.matrix.num_rows();
2816   PPL_DIRTY_TEMP(N, sum);
2817   using namespace Implementation::Octagonal_Shapes;
2818   for (row_iterator k_iter = m_begin; k_iter != m_end; ++k_iter) {
2819     const dimension_type k = k_iter.index();
2820     const dimension_type ck = coherent_index(k);
2821     const dimension_type rs_k = k_iter.row_size();
2822     row_reference x_k = *k_iter;
2823     row_reference x_ck = (k % 2 != 0) ? *(k_iter-1) : *(k_iter + 1);
2824 
2825     for (row_iterator i_iter = m_begin; i_iter != m_end; ++i_iter) {
2826       const dimension_type i = i_iter.index();
2827       const dimension_type ci = coherent_index(i);
2828       const dimension_type rs_i = i_iter.row_size();
2829       row_reference x_i = *i_iter;
2830       row_reference x_ci = (i % 2 != 0) ? *(i_iter-1) : *(i_iter + 1);
2831 
2832       const N& x_i_k = (k < rs_i) ? x_i[k] : x_ck[ci];
2833       if (!is_plus_infinity(x_i_k)) {
2834         const N& x_k_v = (v < rs_k) ? x_k[v] : x_cv[ck];
2835         if (!is_plus_infinity(x_k_v)) {
2836           add_assign_r(sum, x_i_k, x_k_v, ROUND_UP);
2837           N& x_i_v = (v < rs_i) ? x_i[v] : x_cv[ci];
2838           min_assign(x_i_v, sum);
2839         }
2840         const N& x_k_cv = (cv < rs_k) ? x_k[cv] : x_v[ck];
2841         if (!is_plus_infinity(x_k_cv)) {
2842           add_assign_r(sum, x_i_k, x_k_cv, ROUND_UP);
2843           N& x_i_cv = (cv < rs_i) ? x_i[cv] : x_v[ci];
2844           min_assign(x_i_cv, sum);
2845         }
2846       }
2847       const N& x_k_i = (i < rs_k) ? x_k[i] : x_ci[ck];
2848       if (!is_plus_infinity(x_k_i)) {
2849         const N& x_v_k = (k < rs_v) ? x_v[k] : x_ck[cv];
2850         if (!is_plus_infinity(x_v_k)) {
2851           N& x_v_i = (i < rs_v) ? x_v[i] : x_ci[cv];
2852           add_assign_r(sum, x_v_k, x_k_i, ROUND_UP);
2853           min_assign(x_v_i, sum);
2854         }
2855         const N& x_cv_k = (k < rs_v) ? x_cv[k] : x_ck[v];
2856         if (!is_plus_infinity(x_cv_k)) {
2857           N& x_cv_i = (i < rs_v) ? x_cv[i] : x_ci[v];
2858           add_assign_r(sum, x_cv_k, x_k_i, ROUND_UP);
2859           min_assign(x_cv_i, sum);
2860         }
2861       }
2862 
2863     }
2864   }
2865 
2866   // Step 2: improve the other bounds by using the precise bounds
2867   // for the constraints on `var'.
2868   for (row_iterator i_iter = m_begin; i_iter != m_end; ++i_iter) {
2869     const dimension_type i = i_iter.index();
2870     const dimension_type ci = coherent_index(i);
2871     const dimension_type rs_i = i_iter.row_size();
2872     row_reference x_i = *i_iter;
2873     const N& x_i_v = (v < rs_i) ? x_i[v] : x_cv[ci];
2874     // TODO: see if it is possible to optimize this inner loop
2875     // by splitting it into several parts, so as to avoid
2876     // conditional expressions.
2877     for (dimension_type j = 0; j < n_rows; ++j) {
2878       const dimension_type cj = coherent_index(j);
2879       row_reference x_cj = *(m_begin + cj);
2880       N& x_i_j = (j < rs_i) ? x_i[j] : x_cj[ci];
2881       if (!is_plus_infinity(x_i_v)) {
2882         const N& x_v_j = (j < rs_v) ? x_v[j] : x_cj[cv];
2883         if (!is_plus_infinity(x_v_j)) {
2884           add_assign_r(sum, x_i_v, x_v_j, ROUND_UP);
2885           min_assign(x_i_j, sum);
2886         }
2887       }
2888       const N& x_i_cv = (cv < rs_i) ? x_i[cv] : x_v[ci];
2889       if (!is_plus_infinity(x_i_cv)) {
2890         const N& x_cv_j = (j < rs_v) ? x_cv[j] : x_cj[v];
2891         if (!is_plus_infinity(x_cv_j)) {
2892           add_assign_r(sum, x_i_cv, x_cv_j, ROUND_UP);
2893           min_assign(x_i_j, sum);
2894         }
2895       }
2896     }
2897   }
2898 
2899   // Check for emptiness: the octagon is empty if and only if there is a
2900   // negative value on the main diagonal.
2901   for (row_iterator i = m_begin; i != m_end; ++i) {
2902     N& x_i_i = (*i)[i.index()];
2903     if (sgn(x_i_i) < 0) {
2904       x.set_empty();
2905       return;
2906     }
2907     else {
2908       // Restore PLUS_INFINITY on the main diagonal.
2909       PPL_ASSERT(sgn(x_i_i) == 0);
2910       assign_r(x_i_i, PLUS_INFINITY, ROUND_NOT_NEEDED);
2911     }
2912   }
2913 
2914   // Step 3: we enforce the strong coherence.
2915   x.strong_coherence_assign();
2916   // The octagon is not empty and it is now strongly closed.
2917   x.set_strongly_closed();
2918 }
2919 
2920 template <typename T>
2921 void
2922 Octagonal_Shape<T>
compute_successors(std::vector<dimension_type> & successor) const2923 ::compute_successors(std::vector<dimension_type>& successor) const {
2924   PPL_ASSERT(!marked_empty() && marked_strongly_closed());
2925   PPL_ASSERT(successor.size() == 0);
2926   // Variables are ordered according to their index.
2927   // The vector `successor' is used to indicate which variable
2928   // immediately follows a given one in the corresponding equivalence class.
2929   const dimension_type successor_size = matrix.num_rows();
2930   // Initially, each variable is successor of its own zero-equivalence class.
2931   successor.reserve(successor_size);
2932   for (dimension_type i = 0; i < successor_size; ++i) {
2933     successor.push_back(i);
2934   }
2935   // Now compute actual successors.
2936   for (dimension_type i = successor_size; i-- > 0; )  {
2937     typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin() + i;
2938     typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
2939     typename OR_Matrix<N>::const_row_reference_type m_ci
2940       = (i % 2 != 0) ? *(i_iter-1) : *(i_iter + 1);
2941     for (dimension_type j = 0; j < i; ++j) {
2942       // FIXME: what is the following, commented-out for?
2943     //for (dimension_type j = i; j-- > 0; ) {
2944       using namespace Implementation::Octagonal_Shapes;
2945       dimension_type cj = coherent_index(j);
2946       if (is_additive_inverse(m_ci[cj], m_i[j])) {
2947         // Choose as successor the variable having the greatest index.
2948         successor[j] = i;
2949       }
2950     }
2951   }
2952 }
2953 
2954 template <typename T>
2955 void
2956 Octagonal_Shape<T>
compute_leaders(std::vector<dimension_type> & leaders) const2957 ::compute_leaders(std::vector<dimension_type>& leaders) const {
2958   PPL_ASSERT(!marked_empty() && marked_strongly_closed());
2959   PPL_ASSERT(leaders.size() == 0);
2960   // Variables are ordered according to their index.
2961   // The vector `leaders' is used to indicate the smallest variable
2962   // that belongs to the corresponding equivalence class.
2963   const dimension_type leader_size = matrix.num_rows();
2964   // Initially, each variable is leader of its own zero-equivalence class.
2965   leaders.reserve(leader_size);
2966   for (dimension_type i = 0; i < leader_size; ++i) {
2967     leaders.push_back(i);
2968   }
2969   // Now compute actual leaders.
2970   for (typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin(),
2971          matrix_row_end = matrix.row_end();
2972        i_iter != matrix_row_end; ++i_iter) {
2973     typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
2974     dimension_type i = i_iter.index();
2975     typename OR_Matrix<N>::const_row_reference_type m_ci
2976       = (i % 2 != 0) ? *(i_iter-1) : *(i_iter + 1);
2977     for (dimension_type j = 0; j < i; ++j) {
2978       using namespace Implementation::Octagonal_Shapes;
2979       dimension_type cj = coherent_index(j);
2980       if (is_additive_inverse(m_ci[cj], m_i[j])) {
2981         // Choose as leader the variable having the smaller index.
2982         leaders[i] = leaders[j];
2983       }
2984     }
2985   }
2986 }
2987 
2988 template <typename T>
2989 void
2990 Octagonal_Shape<T>
compute_leaders(std::vector<dimension_type> & successor,std::vector<dimension_type> & no_sing_leaders,bool & exist_sing_class,dimension_type & sing_leader) const2991 ::compute_leaders(std::vector<dimension_type>& successor,
2992                   std::vector<dimension_type>& no_sing_leaders,
2993                   bool& exist_sing_class,
2994                   dimension_type& sing_leader) const {
2995   PPL_ASSERT(!marked_empty() && marked_strongly_closed());
2996   PPL_ASSERT(no_sing_leaders.size() == 0);
2997   dimension_type successor_size = successor.size();
2998   std::deque<bool> dealt_with(successor_size, false);
2999   for (dimension_type i = 0; i < successor_size; ++i) {
3000     dimension_type next_i = successor[i];
3001     if (!dealt_with[i]) {
3002       // The index is a leader.
3003       // Now check if it is a leader of a singular class or not.
3004       using namespace Implementation::Octagonal_Shapes;
3005       if (next_i == coherent_index(i)) {
3006         exist_sing_class = true;
3007         sing_leader = i;
3008       }
3009       else {
3010         no_sing_leaders.push_back(i);
3011       }
3012     }
3013     // The following index is not a leader.
3014     dealt_with[next_i] = true;
3015   }
3016 }
3017 
3018 template <typename T>
3019 void
strong_reduction_assign() const3020 Octagonal_Shape<T>::strong_reduction_assign() const {
3021   // Zero-dimensional octagonal shapes are necessarily reduced.
3022   if (space_dim == 0) {
3023     return;
3024   }
3025   strong_closure_assign();
3026   // If `*this' is empty, then there is nothing to reduce.
3027   if (marked_empty()) {
3028     return;
3029   }
3030   // Detect non-redundant constraints.
3031   std::vector<Bit_Row> non_red;
3032   non_redundant_matrix_entries(non_red);
3033 
3034   // Throw away redundant constraints.
3035   Octagonal_Shape<T>& x = const_cast<Octagonal_Shape<T>&>(*this);
3036 #ifndef NDEBUG
3037   const Octagonal_Shape x_copy_before(x);
3038 #endif
3039   typename OR_Matrix<N>::element_iterator x_i = x.matrix.element_begin();
3040   for (dimension_type i = 0; i < 2 * space_dim; ++i) {
3041     const Bit_Row& non_red_i = non_red[i];
3042     for (dimension_type j = 0,
3043            j_end = OR_Matrix<N>::row_size(i); j < j_end; ++j, ++x_i) {
3044       if (!non_red_i[j]) {
3045         assign_r(*x_i, PLUS_INFINITY, ROUND_NOT_NEEDED);
3046       }
3047     }
3048   }
3049   x.reset_strongly_closed();
3050 #ifndef NDEBUG
3051   const Octagonal_Shape x_copy_after(x);
3052   PPL_ASSERT(x_copy_before == x_copy_after);
3053   PPL_ASSERT(x.is_strongly_reduced());
3054   PPL_ASSERT(x.OK());
3055 #endif
3056 }
3057 
3058 template <typename T>
3059 void
3060 Octagonal_Shape<T>
non_redundant_matrix_entries(std::vector<Bit_Row> & non_redundant) const3061 ::non_redundant_matrix_entries(std::vector<Bit_Row>& non_redundant) const {
3062   // Private method: the caller has to ensure the following.
3063   PPL_ASSERT(space_dim > 0 && !marked_empty() && marked_strongly_closed());
3064   PPL_ASSERT(non_redundant.empty());
3065 
3066   // Initialize `non_redundant' as if it was an OR_Matrix of booleans
3067   // (initially set to false).
3068   non_redundant.resize(2*space_dim);
3069 
3070   // Step 1: compute zero-equivalence classes.
3071   // Variables corresponding to indices `i' and `j' are zero-equivalent
3072   // if they lie on a zero-weight loop; since the matrix is strongly
3073   // closed, this happens if and only if matrix[i][j] == -matrix[ci][cj].
3074   std::vector<dimension_type> no_sing_leaders;
3075   dimension_type sing_leader = 0;
3076   bool exist_sing_class = false;
3077   std::vector<dimension_type> successor;
3078   compute_successors(successor);
3079   compute_leaders(successor, no_sing_leaders, exist_sing_class, sing_leader);
3080   const dimension_type num_no_sing_leaders = no_sing_leaders.size();
3081 
3082 
3083   // Step 2: flag redundant constraints in `redundancy'.
3084   // Go through non-singular leaders first.
3085   for (dimension_type li = 0; li < num_no_sing_leaders; ++li) {
3086     const dimension_type i = no_sing_leaders[li];
3087     using namespace Implementation::Octagonal_Shapes;
3088     const dimension_type ci = coherent_index(i);
3089     typename OR_Matrix<N>::const_row_reference_type
3090       m_i = *(matrix.row_begin() + i);
3091     if (i % 2 == 0) {
3092       // Each positive equivalence class must have a single 0-cycle
3093       // connecting all equivalent variables in increasing order.
3094       // Note: by coherence assumption, the variables in the
3095       // corresponding negative equivalence class are
3096       // automatically connected.
3097       if (i != successor[i]) {
3098         dimension_type j = i;
3099         dimension_type next_j = successor[j];
3100         while (j != next_j) {
3101           non_redundant[next_j].set(j);
3102           j = next_j;
3103           next_j = successor[j];
3104         }
3105         const dimension_type cj = coherent_index(j);
3106         non_redundant[cj].set(ci);
3107       }
3108     }
3109 
3110     dimension_type rs_li = (li % 2 != 0) ? li : (li + 1);
3111     // Check if the constraint is redundant.
3112     PPL_DIRTY_TEMP(N, tmp);
3113     for (dimension_type lj = 0 ; lj <= rs_li; ++lj) {
3114       const dimension_type j = no_sing_leaders[lj];
3115       const dimension_type cj = coherent_index(j);
3116       const N& m_i_j = m_i[j];
3117       const N& m_i_ci = m_i[ci];
3118       bool to_add = true;
3119       // Control if the constraint is redundant by strong-coherence,
3120       // that is:
3121       // m_i_j >= (m_i_ci + m_cj_j)/2,   where j != ci.
3122       if (j != ci) {
3123         add_assign_r(tmp, m_i_ci, matrix[cj][j], ROUND_UP);
3124         div_2exp_assign_r(tmp, tmp, 1, ROUND_UP);
3125         if (m_i_j >= tmp) {
3126           // The constraint is redundant.
3127           continue;
3128         }
3129       }
3130       // Control if the constraint is redundant by strong closure, that is
3131       // if there is a path from i to j (i = i_0, ... , i_n = j), such that
3132       // m_i_j = sum_{k=0}^{n-1} m_{i_k}_{i_(k + 1)}.
3133       // Since the octagon is already strongly closed, the above relation
3134       // is reduced to three case, in accordance with k, i, j inter-depend:
3135       // exit k such that
3136       // 1.) m_i_j >= m_i_k   + m_cj_ck,   if k < j < i; or
3137       // 2.) m_i_j >= m_i_k   + m_k,_j,    if j < k < i; or
3138       // 3.) m_i_j >= m_ck_ci + m_k_j,     if j < i < k.
3139       // Note: `i > j'.
3140       for (dimension_type lk = 0; lk < num_no_sing_leaders; ++lk) {
3141         const dimension_type k = no_sing_leaders[lk];
3142         if (k != i && k != j) {
3143           dimension_type ck = coherent_index(k);
3144           if (k < j) {
3145             // Case 1.
3146             add_assign_r(tmp, m_i[k], matrix[cj][ck], ROUND_UP);
3147           }
3148           else if (k < i) {
3149             // Case 2.
3150             add_assign_r(tmp, m_i[k], matrix[k][j], ROUND_UP);
3151           }
3152           else {
3153             // Case 3.
3154             add_assign_r(tmp, matrix[ck][ci], matrix[k][j], ROUND_UP);
3155           }
3156           // Checks if the constraint is redundant.
3157           if (m_i_j >= tmp) {
3158             to_add = false;
3159             break;
3160           }
3161         }
3162       }
3163 
3164       if (to_add) {
3165         // The constraint is not redundant.
3166         non_redundant[i].set(j);
3167       }
3168     }
3169   }
3170 
3171   // If there exist a singular equivalence class, then it must have a
3172   // single 0-cycle connecting all the positive and negative equivalent
3173   // variables.
3174   // Note: the singular class is not connected with the other classes.
3175   if (exist_sing_class) {
3176     non_redundant[sing_leader].set(sing_leader + 1);
3177     if (successor[sing_leader + 1] != sing_leader + 1) {
3178       dimension_type j = sing_leader;
3179       dimension_type next_j = successor[j + 1];
3180       while (next_j != j + 1) {
3181         non_redundant[next_j].set(j);
3182         j = next_j;
3183         next_j = successor[j + 1];
3184       }
3185       non_redundant[j + 1].set(j);
3186     }
3187     else {
3188       non_redundant[sing_leader + 1].set(sing_leader);
3189     }
3190   }
3191 }
3192 
3193 template <typename T>
3194 void
upper_bound_assign(const Octagonal_Shape & y)3195 Octagonal_Shape<T>::upper_bound_assign(const Octagonal_Shape& y) {
3196   // Dimension-compatibility check.
3197   if (space_dim != y.space_dim) {
3198     throw_dimension_incompatible("upper_bound_assign(y)", y);
3199   }
3200 
3201   // The hull of an octagon `x' with an empty octagon is `x'.
3202   y.strong_closure_assign();
3203   if (y.marked_empty()) {
3204     return;
3205   }
3206   strong_closure_assign();
3207   if (marked_empty()) {
3208     *this = y;
3209     return;
3210   }
3211 
3212   // The oct-hull is obtained by computing maxima.
3213   typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
3214   for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
3215          matrix_element_end = matrix.element_end();
3216        i != matrix_element_end; ++i, ++j) {
3217     max_assign(*i, *j);
3218   }
3219 
3220   // The result is still closed.
3221   PPL_ASSERT(OK());
3222 }
3223 
3224 template <typename T>
3225 void
difference_assign(const Octagonal_Shape & y)3226 Octagonal_Shape<T>::difference_assign(const Octagonal_Shape& y) {
3227   // Dimension-compatibility check.
3228   if (space_dim != y.space_dim) {
3229     throw_dimension_incompatible("difference_assign(y)", y);
3230   }
3231 
3232   Octagonal_Shape& x = *this;
3233 
3234   // Being lazy here is only harmful.
3235   // We close.
3236   x.strong_closure_assign();
3237   // The difference of an empty octagon and of an octagon `p' is empty.
3238   if (x.marked_empty()) {
3239     return;
3240   }
3241   // The difference of a octagon `p' and an empty octagon is `p'.
3242   if (y.marked_empty()) {
3243     return;
3244   }
3245   // If both octagons are zero-dimensional,
3246   // then at this point they are necessarily universe octagons,
3247   // so that their difference is empty.
3248   if (x.space_dim == 0) {
3249     x.set_empty();
3250     return;
3251   }
3252 
3253   // TODO: This is just an executable specification.
3254   //       Have to find a more efficient method.
3255   if (y.contains(x)) {
3256     x.set_empty();
3257     return;
3258   }
3259 
3260   Octagonal_Shape new_oct(space_dim, EMPTY);
3261   // We take a constraint of the octagon y at the time and we
3262   // consider its complementary. Then we intersect the union
3263   // of these complementary constraints with the octagon x.
3264   const Constraint_System& y_cs = y.constraints();
3265   for (Constraint_System::const_iterator i = y_cs.begin(),
3266          y_cs_end = y_cs.end(); i != y_cs_end; ++i) {
3267     const Constraint& c = *i;
3268     // If the octagon `x' is included the octagon defined by `c',
3269     // then `c' _must_ be skipped, as adding its complement to `x'
3270     // would result in the empty octagon, and as we would obtain
3271     // a result that is less precise than the difference.
3272     if (x.relation_with(c).implies(Poly_Con_Relation::is_included())) {
3273       continue;
3274     }
3275     Octagonal_Shape z = x;
3276     const Linear_Expression e(c.expression());
3277     z.add_constraint(e <= 0);
3278     if (!z.is_empty()) {
3279       new_oct.upper_bound_assign(z);
3280     }
3281     if (c.is_equality()) {
3282       z = x;
3283       z.add_constraint(e >= 0);
3284       if (!z.is_empty()) {
3285         new_oct.upper_bound_assign(z);
3286       }
3287     }
3288   }
3289   *this = new_oct;
3290   PPL_ASSERT(OK());
3291 }
3292 
3293 template <typename T>
3294 bool
simplify_using_context_assign(const Octagonal_Shape & y)3295 Octagonal_Shape<T>::simplify_using_context_assign(const Octagonal_Shape& y) {
3296   Octagonal_Shape& x = *this;
3297   const dimension_type dim = x.space_dimension();
3298   // Dimension-compatibility check.
3299   if (dim != y.space_dimension()) {
3300     throw_dimension_incompatible("simplify_using_context_assign(y)", y);
3301   }
3302 
3303   // Filter away the zero-dimensional case.
3304   if (dim == 0) {
3305     if (y.marked_empty()) {
3306       x.set_zero_dim_univ();
3307       return false;
3308     }
3309     else {
3310       return !x.marked_empty();
3311     }
3312   }
3313 
3314   // Filter away the case where `x' contains `y'
3315   // (this subsumes the case when `y' is empty).
3316   if (x.contains(y)) {
3317     Octagonal_Shape<T> res(dim, UNIVERSE);
3318     x.m_swap(res);
3319     return false;
3320   }
3321 
3322   // Filter away the case where `x' is empty.
3323   x.strong_closure_assign();
3324   if (x.marked_empty()) {
3325     // Search for a constraint of `y' that is not a tautology.
3326     dimension_type i;
3327     dimension_type j;
3328     // Prefer unary constraints.
3329     for (i = 0; i < 2*dim; i += 2) {
3330       // FIXME: if N is a float or bounded integer type, then
3331       // we also need to check that we are actually able to construct
3332       // a constraint inconsistent with respect to this one.
3333       // Use something like !is_maximal()?
3334       if (!is_plus_infinity(y.matrix_at(i, i + 1))) {
3335         j = i + 1;
3336         goto found;
3337       }
3338       // Use something like !is_maximal()?
3339       if (!is_plus_infinity(y.matrix_at(i + 1, i))) {
3340         j = i;
3341         ++i;
3342         goto found;
3343       }
3344     }
3345     // Then search binary constraints.
3346     // TODO: use better iteration scheme.
3347     for (i = 2; i < 2*dim; ++i) {
3348       for (j = 0; j < i; ++j) {
3349         // Use something like !is_maximal()?
3350         if (!is_plus_infinity(y.matrix_at(i, j))) {
3351           goto found;
3352         }
3353       }
3354     }
3355 
3356     // Not found: we were not able to build a constraint contradicting
3357     // one of the constraints in `y': `x' cannot be enlarged.
3358     return false;
3359 
3360   found:
3361     // Found: build a new OS contradicting the constraint found.
3362     PPL_ASSERT(i < dim && j < dim && i != j);
3363     Octagonal_Shape<T> res(dim, UNIVERSE);
3364     // FIXME: compute a proper contradicting constraint.
3365     PPL_DIRTY_TEMP(N, tmp);
3366     assign_r(tmp, 1, ROUND_UP);
3367     add_assign_r(tmp, tmp, y.matrix_at(i, j), ROUND_UP);
3368     // CHECKME: round down is really meant.
3369     neg_assign_r(res.matrix_at(j, i), tmp, ROUND_DOWN);
3370     PPL_ASSERT(!is_plus_infinity(res.matrix_at(j, i)));
3371     x.m_swap(res);
3372     return false;
3373   }
3374 
3375   // Here `x' and `y' are not empty and strongly closed;
3376   // also, `x' does not contain `y'.
3377   // Let `target' be the intersection of `x' and `y'.
3378   Octagonal_Shape<T> target = x;
3379   target.intersection_assign(y);
3380   const bool bool_result = !target.is_empty();
3381 
3382   // Compute redundancy information for x and ...
3383   // TODO: provide a nicer data structure for redundancy.
3384   std::vector<Bit_Row> x_non_redundant;
3385   x.non_redundant_matrix_entries(x_non_redundant);
3386   // ... count the non-redundant constraints.
3387   dimension_type x_num_non_redundant = 0;
3388   for (size_t i = x_non_redundant.size(); i-- > 0 ; ) {
3389     x_num_non_redundant += x_non_redundant[i].count_ones();
3390   }
3391   PPL_ASSERT(x_num_non_redundant > 0);
3392 
3393   // Let `yy' be a copy of `y': we will keep adding to `yy'
3394   // the non-redundant constraints of `x',
3395   // stopping as soon as `yy' becomes equal to `target'.
3396   Octagonal_Shape<T> yy = y;
3397 
3398   // The constraints added to `yy' will be recorded in `res' ...
3399   Octagonal_Shape<T> res(dim, UNIVERSE);
3400   // ... and we will count them too.
3401   dimension_type res_num_non_redundant = 0;
3402 
3403   // Compute leader information for `x'.
3404   std::vector<dimension_type> x_leaders;
3405   x.compute_leaders(x_leaders);
3406 
3407   // First go through the unary equality constraints.
3408   // Find the leader of the singular equivalence class (it is even!).
3409   dimension_type sing_leader;
3410   for (sing_leader = 0; sing_leader < 2*dim; sing_leader += 2) {
3411     if (sing_leader == x_leaders[sing_leader]) {
3412       const N& x_s_ss = x.matrix_at(sing_leader, sing_leader + 1);
3413       const N& x_ss_s = x.matrix_at(sing_leader + 1, sing_leader);
3414       if (is_additive_inverse(x_s_ss, x_ss_s)) {
3415         // Singular leader found.
3416         break;
3417       }
3418     }
3419   }
3420 
3421   // Unary equalities have `sing_leader' as a leader.
3422   for (dimension_type i = sing_leader; i < 2*dim; i += 2) {
3423     if (x_leaders[i] != sing_leader) {
3424       continue;
3425     }
3426     // Found a unary equality constraint:
3427     // see if any of the two inequalities have to be added.
3428     const N& x_i_ii = x.matrix_at(i, i + 1);
3429     N& yy_i_ii = yy.matrix_at(i, i + 1);
3430     if (x_i_ii < yy_i_ii) {
3431       // The \leq inequality is not implied by context.
3432       res.matrix_at(i, i + 1) = x_i_ii;
3433       ++res_num_non_redundant;
3434       // Tighten context `yy' using the newly added constraint.
3435       yy_i_ii = x_i_ii;
3436       yy.reset_strongly_closed();
3437     }
3438     const N& x_ii_i = x.matrix_at(i + 1, i);
3439     N& yy_ii_i = yy.matrix_at(i + 1, i);
3440     if (x_ii_i < yy_ii_i) {
3441       // The \geq inequality is not implied by context.
3442       res.matrix_at(i + 1, i) = x_ii_i;
3443       ++res_num_non_redundant;
3444       // Tighten context `yy' using the newly added constraint.
3445       yy_ii_i = x_ii_i;
3446       yy.reset_strongly_closed();
3447     }
3448     // Restore strong closure, if it was lost.
3449     if (!yy.marked_strongly_closed()) {
3450       Variable var_i(i/2);
3451       yy.incremental_strong_closure_assign(var_i);
3452       if (target.contains(yy)) {
3453         // Target reached: swap `x' and `res' if needed.
3454         if (res_num_non_redundant < x_num_non_redundant) {
3455           res.reset_strongly_closed();
3456           x.m_swap(res);
3457         }
3458         return bool_result;
3459       }
3460     }
3461   }
3462 
3463   // Go through the binary equality constraints.
3464   for (dimension_type i = 0; i < 2*dim; ++i) {
3465     const dimension_type j = x_leaders[i];
3466     if (j == i || j == sing_leader) {
3467       continue;
3468     }
3469     const N& x_i_j = x.matrix_at(i, j);
3470     PPL_ASSERT(!is_plus_infinity(x_i_j));
3471     N& yy_i_j = yy.matrix_at(i, j);
3472     if (x_i_j < yy_i_j) {
3473       res.matrix_at(i, j) = x_i_j;
3474       ++res_num_non_redundant;
3475       // Tighten context `yy' using the newly added constraint.
3476       yy_i_j = x_i_j;
3477       yy.reset_strongly_closed();
3478     }
3479     const N& x_j_i = x.matrix_at(j, i);
3480     N& yy_j_i = yy.matrix_at(j, i);
3481     PPL_ASSERT(!is_plus_infinity(x_j_i));
3482     if (x_j_i < yy_j_i) {
3483       res.matrix_at(j, i) = x_j_i;
3484       ++res_num_non_redundant;
3485       // Tighten context `yy' using the newly added constraint.
3486       yy_j_i = x_j_i;
3487       yy.reset_strongly_closed();
3488     }
3489     // Restore strong closure, if it was lost.
3490     if (!yy.marked_strongly_closed()) {
3491       Variable var_j(j/2);
3492       yy.incremental_strong_closure_assign(var_j);
3493       if (target.contains(yy)) {
3494         // Target reached: swap `x' and `res' if needed.
3495         if (res_num_non_redundant < x_num_non_redundant) {
3496           res.reset_strongly_closed();
3497           x.m_swap(res);
3498         }
3499         return bool_result;
3500       }
3501     }
3502   }
3503 
3504   // Finally go through the (proper) inequality constraints:
3505   // both indices i and j should be leaders.
3506   // FIXME: improve iteration scheme (are we doing twice the work?)
3507   for (dimension_type i = 0; i < 2*dim; ++i) {
3508     if (i != x_leaders[i]) {
3509       continue;
3510     }
3511     const Bit_Row& x_non_redundant_i = x_non_redundant[i];
3512     for (dimension_type j = 0; j < 2*dim; ++j) {
3513       if (j != x_leaders[j]) {
3514         continue;
3515       }
3516       if (i >= j) {
3517         if (!x_non_redundant_i[j]) {
3518           continue;
3519         }
3520       }
3521       else if (!x_non_redundant[j][i]) {
3522         continue;
3523       }
3524       N& yy_i_j = yy.matrix_at(i, j);
3525       const N& x_i_j = x.matrix_at(i, j);
3526       if (x_i_j < yy_i_j) {
3527         res.matrix_at(i, j) = x_i_j;
3528         ++res_num_non_redundant;
3529         // Tighten context `yy' using the newly added constraint.
3530         yy_i_j = x_i_j;
3531         yy.reset_strongly_closed();
3532         Variable var(i/2);
3533         yy.incremental_strong_closure_assign(var);
3534         if (target.contains(yy)) {
3535           // Target reached: swap `x' and `res' if needed.
3536           if (res_num_non_redundant < x_num_non_redundant) {
3537             res.reset_strongly_closed();
3538             x.m_swap(res);
3539           }
3540           return bool_result;
3541         }
3542       }
3543     }
3544   }
3545   // This point should be unreachable.
3546   PPL_UNREACHABLE;
3547   return false;
3548 }
3549 
3550 template <typename T>
3551 void
add_space_dimensions_and_embed(dimension_type m)3552 Octagonal_Shape<T>::add_space_dimensions_and_embed(dimension_type m) {
3553   // Adding no dimensions is a no-op.
3554   if (m == 0) {
3555     return;
3556   }
3557 
3558   const dimension_type new_dim = space_dim + m;
3559   const bool was_zero_dim_univ = !marked_empty() && space_dim == 0;
3560 
3561   // To embed an n-dimension space octagon in a (n + m)-dimension space,
3562   // we just add `m' variables in the matrix of constraints.
3563   matrix.grow(new_dim);
3564   space_dim = new_dim;
3565   // If `*this' was the zero-dim space universe octagon,
3566   // then we can set the strongly closure flag.
3567   if (was_zero_dim_univ) {
3568     set_strongly_closed();
3569   }
3570 
3571   PPL_ASSERT(OK());
3572 }
3573 
3574 template <typename T>
3575 void
add_space_dimensions_and_project(dimension_type m)3576 Octagonal_Shape<T>::add_space_dimensions_and_project(dimension_type m) {
3577   // Adding no dimensions is a no-op.
3578   if (m == 0) {
3579     return;
3580   }
3581 
3582   const dimension_type n = matrix.num_rows();
3583 
3584   // To project an n-dimension space OS in a (space_dim + m)-dimension space,
3585   // we just add `m' columns and rows in the matrix of constraints.
3586   add_space_dimensions_and_embed(m);
3587   // We insert 0 where it needs.
3588   // Attention: now num_rows of matrix is update!
3589   for (typename OR_Matrix<N>::row_iterator i = matrix.row_begin() + n,
3590          matrix_row_end =  matrix.row_end(); i != matrix_row_end; i += 2) {
3591     typename OR_Matrix<N>::row_reference_type x_i = *i;
3592     typename OR_Matrix<N>::row_reference_type x_ci = *(i + 1);
3593     const dimension_type ind = i.index();
3594     assign_r(x_i[ind + 1], 0, ROUND_NOT_NEEDED);
3595     assign_r(x_ci[ind], 0, ROUND_NOT_NEEDED);
3596   }
3597 
3598   if (marked_strongly_closed()) {
3599     reset_strongly_closed();
3600   }
3601   PPL_ASSERT(OK());
3602 }
3603 
3604 template <typename T>
3605 void
remove_space_dimensions(const Variables_Set & vars)3606 Octagonal_Shape<T>::remove_space_dimensions(const Variables_Set& vars) {
3607   // The removal of no dimensions from any octagon is a no-op.
3608   // Note that this case also captures the only legal removal of
3609   // dimensions from a octagon in a 0-dim space.
3610   if (vars.empty()) {
3611     PPL_ASSERT(OK());
3612     return;
3613   }
3614 
3615   // Dimension-compatibility check.
3616   const dimension_type min_space_dim = vars.space_dimension();
3617   if (space_dim < min_space_dim) {
3618     throw_dimension_incompatible("remove_space_dimensions(vs)", min_space_dim);
3619   }
3620 
3621   const dimension_type new_space_dim = space_dim - vars.size();
3622 
3623   strong_closure_assign();
3624   // When removing _all_ dimensions from an octagon,
3625   // we obtain the zero-dimensional octagon.
3626   if (new_space_dim == 0) {
3627     matrix.shrink(0);
3628     if (!marked_empty()) {
3629       // We set the zero_dim_univ flag.
3630       set_zero_dim_univ();
3631     }
3632     space_dim = 0;
3633     PPL_ASSERT(OK());
3634     return;
3635   }
3636 
3637   // We consider each variable and we check if it has to be removed.
3638   // If it has to be removed, we pass to the next one, then we will
3639   // overwrite its representation in the matrix.
3640   typedef typename OR_Matrix<N>::element_iterator Elem_Iter;
3641   typedef typename std::iterator_traits<Elem_Iter>::difference_type diff_t;
3642 
3643   dimension_type first = *vars.begin();
3644   const dimension_type first_size = 2 * first * (first + 1);
3645   Elem_Iter iter = matrix.element_begin() + static_cast<diff_t>(first_size);
3646 
3647   for (dimension_type i = first + 1; i < space_dim; ++i) {
3648     if (vars.count(i) == 0) {
3649       typename OR_Matrix<N>::row_iterator row_iter = matrix.row_begin() + 2*i;
3650       typename OR_Matrix<N>::row_reference_type row_ref = *row_iter;
3651       typename OR_Matrix<N>::row_reference_type row_ref1 = *(++row_iter);
3652       // Beware: first we shift the cells corresponding to the first
3653       // row of variable(j), then we shift the cells corresponding to the
3654       // second row. We recall that every variable is represented
3655       // in the `matrix' by two rows and two columns.
3656       for (dimension_type j = 0; j <= i; ++j) {
3657         if (vars.count(j) == 0) {
3658           assign_or_swap(*(iter++), row_ref[2*j]);
3659           assign_or_swap(*(iter++), row_ref[2*j + 1]);
3660         }
3661       }
3662       for (dimension_type j = 0; j <= i; ++j) {
3663         if (vars.count(j) == 0) {
3664           assign_or_swap(*(iter++), row_ref1[2*j]);
3665           assign_or_swap(*(iter++), row_ref1[2*j + 1]);
3666         }
3667       }
3668     }
3669   }
3670   // Update the space dimension.
3671   matrix.shrink(new_space_dim);
3672   space_dim = new_space_dim;
3673   PPL_ASSERT(OK());
3674 }
3675 
3676 template <typename T>
3677 template <typename Partial_Function>
3678 void
map_space_dimensions(const Partial_Function & pfunc)3679 Octagonal_Shape<T>::map_space_dimensions(const Partial_Function& pfunc) {
3680   if (space_dim == 0) {
3681     return;
3682   }
3683 
3684   if (pfunc.has_empty_codomain()) {
3685     // All dimensions vanish: the octagon becomes zero_dimensional.
3686     remove_higher_space_dimensions(0);
3687     return;
3688   }
3689 
3690   const dimension_type new_space_dim = pfunc.max_in_codomain() + 1;
3691   // If we are going to actually reduce the space dimension,
3692   // then shortest-path closure is required to keep precision.
3693   if (new_space_dim < space_dim) {
3694     strong_closure_assign();
3695   }
3696   // If the octagon is empty, then it is sufficient to adjust
3697   // the space dimension of the octagon.
3698   if (marked_empty()) {
3699     remove_higher_space_dimensions(new_space_dim);
3700     return;
3701   }
3702 
3703   // We create a new matrix with the new space dimension.
3704   OR_Matrix<N> x(new_space_dim);
3705 
3706   typedef typename OR_Matrix<N>::row_iterator row_iterator;
3707   typedef typename OR_Matrix<N>::row_reference_type row_reference;
3708 
3709   row_iterator m_begin = x.row_begin();
3710 
3711   for (row_iterator i_iter = matrix.row_begin(), i_end = matrix.row_end();
3712        i_iter != i_end; i_iter += 2) {
3713     dimension_type new_i;
3714     dimension_type i = i_iter.index()/2;
3715     // We copy and place in the position into `x' the only cells of
3716     // the `matrix' that refer to both mapped variables,
3717     // the variable `i' and `j'.
3718     if (pfunc.maps(i, new_i)) {
3719       row_reference r_i = *i_iter;
3720       row_reference r_ii = *(i_iter + 1);
3721       dimension_type double_new_i = 2*new_i;
3722       row_iterator x_iter = m_begin + double_new_i;
3723       row_reference x_i = *x_iter;
3724       row_reference x_ii = *(x_iter + 1);
3725       for (dimension_type j = 0; j <= i; ++j) {
3726         dimension_type new_j;
3727         // If also the second variable is mapped, we work.
3728         if (pfunc.maps(j, new_j)) {
3729           dimension_type dj = 2*j;
3730           dimension_type double_new_j = 2*new_j;
3731           // Mapped the constraints, exchanging the indexes.
3732           // Attention: our matrix is pseudo-triangular.
3733           // If new_j > new_i, we must consider, as rows, the rows of
3734           // the variable new_j, and not of new_i ones.
3735           if (new_i >= new_j) {
3736             assign_or_swap(x_i[double_new_j], r_i[dj]);
3737             assign_or_swap(x_ii[double_new_j], r_ii[dj]);
3738             assign_or_swap(x_ii[double_new_j + 1], r_ii[dj + 1]);
3739             assign_or_swap(x_i[double_new_j + 1], r_i[dj + 1]);
3740           }
3741           else {
3742             row_iterator x_j_iter = m_begin + double_new_j;
3743             row_reference x_j = *x_j_iter;
3744             row_reference x_jj = *(x_j_iter + 1);
3745             assign_or_swap(x_jj[double_new_i + 1], r_i[dj]);
3746             assign_or_swap(x_jj[double_new_i], r_ii[dj]);
3747             assign_or_swap(x_j[double_new_i + 1], r_i[dj + 1]);
3748             assign_or_swap(x_j[double_new_i], r_ii[dj + 1]);
3749           }
3750 
3751         }
3752       }
3753     }
3754   }
3755 
3756   using std::swap;
3757   swap(matrix, x);
3758   space_dim = new_space_dim;
3759   PPL_ASSERT(OK());
3760 }
3761 
3762 template <typename T>
3763 void
intersection_assign(const Octagonal_Shape & y)3764 Octagonal_Shape<T>::intersection_assign(const Octagonal_Shape& y) {
3765   // Dimension-compatibility check.
3766   if (space_dim != y.space_dim) {
3767     throw_dimension_incompatible("intersection_assign(y)", y);
3768   }
3769 
3770   // If one of the two octagons is empty, the intersection is empty.
3771   if (marked_empty()) {
3772     return;
3773   }
3774   if (y.marked_empty()) {
3775     set_empty();
3776     return;
3777   }
3778   // If both octagons are zero-dimensional,then at this point
3779   // they are necessarily non-empty,
3780   // so that their intersection is non-empty too.
3781   if (space_dim == 0) {
3782     return;
3783   }
3784   // To intersect two octagons we compare the constraints
3785   // and we choose the less values.
3786   bool changed = false;
3787 
3788   typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
3789   for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
3790          matrix_element_end = matrix.element_end();
3791        i != matrix_element_end;
3792        ++i, ++j) {
3793     N& elem = *i;
3794     const N& y_elem = *j;
3795     if (y_elem < elem) {
3796       elem = y_elem;
3797       changed = true;
3798     }
3799   }
3800 
3801   // This method not preserve the closure.
3802   if (changed && marked_strongly_closed()) {
3803     reset_strongly_closed();
3804   }
3805   PPL_ASSERT(OK());
3806 }
3807 
3808 template <typename T>
3809 template <typename Iterator>
3810 void
CC76_extrapolation_assign(const Octagonal_Shape & y,Iterator first,Iterator last,unsigned * tp)3811 Octagonal_Shape<T>::CC76_extrapolation_assign(const Octagonal_Shape& y,
3812                                               Iterator first, Iterator last,
3813                                               unsigned* tp) {
3814   // Dimension-compatibility check.
3815   if (space_dim != y.space_dim) {
3816     throw_dimension_incompatible("CC76_extrapolation_assign(y)", y);
3817   }
3818 
3819   // Assume `y' is contained in or equal to `*this'.
3820   PPL_EXPECT_HEAVY(copy_contains(*this, y));
3821 
3822   // If both octagons are zero-dimensional,
3823   // since `*this' contains `y', we simply return `*this'.
3824   if (space_dim == 0) {
3825     return;
3826   }
3827 
3828   strong_closure_assign();
3829   // If `*this' is empty, since `*this' contains `y', `y' is empty too.
3830   if (marked_empty()) {
3831     return;
3832   }
3833   y.strong_closure_assign();
3834   // If `y' is empty, we return.
3835   if (y.marked_empty()) {
3836     return;
3837   }
3838 
3839   // If there are tokens available, work on a temporary copy.
3840   if (tp != 0 && *tp > 0) {
3841     Octagonal_Shape x_tmp(*this);
3842     x_tmp.CC76_extrapolation_assign(y, first, last, 0);
3843     // If the widening was not precise, use one of the available tokens.
3844     if (!contains(x_tmp)) {
3845       --(*tp);
3846     }
3847     return;
3848   }
3849 
3850   // Compare each constraint in `y' to the corresponding one in `*this'.
3851   // The constraint in `*this' is kept as is if it is stronger than or
3852   // equal to the constraint in `y'; otherwise, the inhomogeneous term
3853   // of the constraint in `*this' is further compared with elements taken
3854   // from a sorted container (the stop-points, provided by the user), and
3855   // is replaced by the first entry, if any, which is greater than or equal
3856   // to the inhomogeneous term. If no such entry exists, the constraint
3857   // is removed altogether.
3858   typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
3859   for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
3860          matrix_element_end = matrix.element_end();
3861        i != matrix_element_end;
3862        ++i, ++j) {
3863     const N& y_elem = *j;
3864     N& elem = *i;
3865     if (y_elem < elem) {
3866       Iterator k = std::lower_bound(first, last, elem);
3867       if (k != last) {
3868         if (elem < *k) {
3869           assign_r(elem, *k, ROUND_UP);
3870         }
3871       }
3872       else {
3873         assign_r(elem, PLUS_INFINITY, ROUND_NOT_NEEDED);
3874       }
3875     }
3876   }
3877 
3878   reset_strongly_closed();
3879   PPL_ASSERT(OK());
3880 }
3881 
3882 template <typename T>
3883 void
3884 Octagonal_Shape<T>
get_limiting_octagon(const Constraint_System & cs,Octagonal_Shape & limiting_octagon) const3885 ::get_limiting_octagon(const Constraint_System& cs,
3886                        Octagonal_Shape& limiting_octagon) const {
3887   const dimension_type cs_space_dim = cs.space_dimension();
3888   // Private method: the caller has to ensure the following.
3889   PPL_ASSERT(cs_space_dim <= space_dim);
3890 
3891   strong_closure_assign();
3892   bool is_oct_changed = false;
3893 
3894   // Allocate temporaries outside of the loop.
3895   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
3896   PPL_DIRTY_TEMP_COEFFICIENT(term);
3897   PPL_DIRTY_TEMP(N, d);
3898 
3899   for (Constraint_System::const_iterator cs_i = cs.begin(),
3900          cs_end = cs.end(); cs_i != cs_end; ++cs_i) {
3901     const Constraint& c = *cs_i;
3902     dimension_type num_vars = 0;
3903     dimension_type i = 0;
3904     dimension_type j = 0;
3905     // Constraints that are not octagonal differences are ignored.
3906     if (!Octagonal_Shape_Helper
3907       ::extract_octagonal_difference(c, cs_space_dim, num_vars, i, j,
3908                                      coeff, term)) {
3909       continue;
3910     }
3911 
3912     typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
3913     typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
3914     typedef typename OR_Matrix<N>::row_iterator row_iterator;
3915     typedef typename OR_Matrix<N>::row_reference_type row_reference;
3916     Row_iterator m_begin = matrix.row_begin();
3917     // Select the cell to be modified for the "<=" part of the constraint.
3918     Row_iterator i_iter = m_begin + i;
3919     Row_reference m_i = *i_iter;
3920     OR_Matrix<N>& lo_mat = limiting_octagon.matrix;
3921     row_iterator lo_iter = lo_mat.row_begin() + i;
3922     row_reference lo_m_i = *lo_iter;
3923     N& lo_m_i_j = lo_m_i[j];
3924     if (coeff < 0) {
3925       neg_assign(coeff);
3926     }
3927     // Compute the bound for `m_i_j', rounding towards plus infinity.
3928     div_round_up(d, term, coeff);
3929     if (m_i[j] <= d) {
3930       if (c.is_inequality()) {
3931         if (lo_m_i_j > d) {
3932           lo_m_i_j = d;
3933           is_oct_changed = true;
3934         }
3935         else {
3936           // Select the right row of the cell.
3937           if (i % 2 == 0) {
3938             ++i_iter;
3939             ++lo_iter;
3940           }
3941           else {
3942             --i_iter;
3943             --lo_iter;
3944           }
3945           Row_reference m_ci = *i_iter;
3946           row_reference lo_m_ci = *lo_iter;
3947           // Select the right column of the cell.
3948           using namespace Implementation::Octagonal_Shapes;
3949           dimension_type cj = coherent_index(j);
3950           N& lo_m_ci_cj = lo_m_ci[cj];
3951           neg_assign(term);
3952           div_round_up(d, term, coeff);
3953           if (m_ci[cj] <= d && lo_m_ci_cj > d) {
3954             lo_m_ci_cj = d;
3955             is_oct_changed = true;
3956           }
3957         }
3958       }
3959     }
3960   }
3961   // In general, adding a constraint does not preserve the strongly
3962   // closure of the octagon.
3963   if (is_oct_changed && limiting_octagon.marked_strongly_closed()) {
3964     limiting_octagon.reset_strongly_closed();
3965   }
3966 }
3967 
3968 template <typename T>
3969 void
3970 Octagonal_Shape<T>
limited_CC76_extrapolation_assign(const Octagonal_Shape & y,const Constraint_System & cs,unsigned * tp)3971 ::limited_CC76_extrapolation_assign(const Octagonal_Shape& y,
3972                                     const Constraint_System& cs,
3973                                     unsigned* tp) {
3974 
3975   // Dimension-compatibility check.
3976   if (space_dim != y.space_dim) {
3977     throw_dimension_incompatible("limited_CC76_extrapolation_assign(y, cs)",
3978                                  y);
3979   }
3980   // `cs' must be dimension-compatible with the two octagons.
3981   const dimension_type cs_space_dim = cs.space_dimension();
3982   if (space_dim < cs_space_dim) {
3983     throw_constraint_incompatible("limited_CC76_extrapolation_assign(y, cs)");
3984   }
3985 
3986   // Strict inequalities not allowed.
3987   if (cs.has_strict_inequalities()) {
3988     throw_constraint_incompatible("limited_CC76_extrapolation_assign(y, cs)");
3989   }
3990 
3991   // The limited CC76-extrapolation between two octagons in a
3992   // zero-dimensional space is a octagon in a zero-dimensional
3993   // space, too.
3994   if (space_dim == 0) {
3995     return;
3996   }
3997 
3998   // Assume `y' is contained in or equal to `*this'.
3999   PPL_EXPECT_HEAVY(copy_contains(*this, y));
4000 
4001   // If `*this' is empty, since `*this' contains `y', `y' is empty too.
4002   if (marked_empty()) {
4003     return;
4004   }
4005 
4006   // If `y' is empty, we return.
4007   if (y.marked_empty()) {
4008     return;
4009   }
4010 
4011   Octagonal_Shape limiting_octagon(space_dim, UNIVERSE);
4012   get_limiting_octagon(cs, limiting_octagon);
4013   CC76_extrapolation_assign(y, tp);
4014   intersection_assign(limiting_octagon);
4015 }
4016 
4017 template <typename T>
4018 void
BHMZ05_widening_assign(const Octagonal_Shape & y,unsigned * tp)4019 Octagonal_Shape<T>::BHMZ05_widening_assign(const Octagonal_Shape& y,
4020                                            unsigned* tp) {
4021   // Dimension-compatibility check.
4022   if (space_dim != y.space_dim) {
4023     throw_dimension_incompatible("BHMZ05_widening_assign(y)", y);
4024   }
4025 
4026   // Assume `y' is contained in or equal to `*this'.
4027   PPL_EXPECT_HEAVY(copy_contains(*this, y));
4028 
4029   // Compute the affine dimension of `y'.
4030   const dimension_type y_affine_dim = y.affine_dimension();
4031   // If the affine dimension of `y' is zero, then either `y' is
4032   // zero-dimensional, or it is empty, or it is a singleton.
4033   // In all cases, due to the inclusion hypothesis, the result is `*this'.
4034   if (y_affine_dim == 0) {
4035     return;
4036   }
4037 
4038   // If the affine dimension has changed, due to the inclusion hypothesis,
4039   // the result is `*this'.
4040   const dimension_type x_affine_dim = affine_dimension();
4041   PPL_ASSERT(x_affine_dim >= y_affine_dim);
4042   if (x_affine_dim != y_affine_dim) {
4043     return;
4044   }
4045   // If there are tokens available, work on a temporary copy.
4046   if (tp != 0 && *tp > 0) {
4047     Octagonal_Shape x_tmp(*this);
4048     x_tmp.BHMZ05_widening_assign(y, 0);
4049     // If the widening was not precise, use one of the available tokens.
4050     if (!contains(x_tmp)) {
4051       --(*tp);
4052     }
4053     return;
4054   }
4055 
4056   // Here no token is available.
4057   PPL_ASSERT(marked_strongly_closed() && y.marked_strongly_closed());
4058   // Minimize `y'.
4059   y.strong_reduction_assign();
4060 
4061   // Extrapolate unstable bounds.
4062   typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
4063   for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
4064        matrix_element_end = matrix.element_end();
4065        i != matrix_element_end;
4066        ++i, ++j) {
4067     N& elem = *i;
4068       // Note: in the following line the use of `!=' (as opposed to
4069       // the use of `<' that would seem -but is not- equivalent) is
4070       // intentional.
4071     if (*j != elem) {
4072       assign_r(elem, PLUS_INFINITY, ROUND_NOT_NEEDED);
4073     }
4074   }
4075   reset_strongly_closed();
4076   PPL_ASSERT(OK());
4077 }
4078 
4079 template <typename T>
4080 void
4081 Octagonal_Shape<T>
limited_BHMZ05_extrapolation_assign(const Octagonal_Shape & y,const Constraint_System & cs,unsigned * tp)4082 ::limited_BHMZ05_extrapolation_assign(const Octagonal_Shape& y,
4083                                       const Constraint_System& cs,
4084                                       unsigned* tp) {
4085 
4086   // Dimension-compatibility check.
4087   if (space_dim != y.space_dim) {
4088     throw_dimension_incompatible("limited_BHMZ05_extrapolation_assign(y, cs)",
4089                                  y);
4090   }
4091 
4092   // `cs' must be dimension-compatible with the two octagons.
4093   const dimension_type cs_space_dim = cs.space_dimension();
4094   if (space_dim < cs_space_dim) {
4095     throw_constraint_incompatible("limited_CH78_extrapolation_assign(y, cs)");
4096   }
4097 
4098   // Strict inequalities not allowed.
4099   if (cs.has_strict_inequalities()) {
4100     throw_constraint_incompatible("limited_CH78_extrapolation_assign(y, cs)");
4101   }
4102 
4103   // The limited BHMZ05-extrapolation between two octagons in a
4104   // zero-dimensional space is a octagon in a zero-dimensional
4105   // space, too.
4106   if (space_dim == 0) {
4107     return;
4108   }
4109 
4110   // Assume `y' is contained in or equal to `*this'.
4111   PPL_EXPECT_HEAVY(copy_contains(*this, y));
4112 
4113   // If `*this' is empty, since `*this' contains `y', `y' is empty too.
4114   if (marked_empty()) {
4115     return;
4116   }
4117   // If `y' is empty, we return.
4118   if (y.marked_empty()) {
4119     return;
4120   }
4121 
4122   Octagonal_Shape limiting_octagon(space_dim, UNIVERSE);
4123   get_limiting_octagon(cs, limiting_octagon);
4124   BHMZ05_widening_assign(y, tp);
4125   intersection_assign(limiting_octagon);
4126 }
4127 
4128 template <typename T>
4129 void
CC76_narrowing_assign(const Octagonal_Shape & y)4130 Octagonal_Shape<T>::CC76_narrowing_assign(const Octagonal_Shape& y) {
4131   // Dimension-compatibility check.
4132   if (space_dim != y.space_dim) {
4133     throw_dimension_incompatible("CC76_narrowing_assign(y)", y);
4134   }
4135 
4136   // Assume `*this' is contained in or equal to `y'.
4137   PPL_EXPECT_HEAVY(copy_contains(y, *this));
4138 
4139   // If both octagons are zero-dimensional, since `*this' contains `y',
4140   // we simply return '*this'.
4141   if (space_dim == 0) {
4142     return;
4143   }
4144 
4145   y.strong_closure_assign();
4146   // If `y' is empty, since `y' contains `*this', `*this' is empty too.
4147   if (y.marked_empty()) {
4148     return;
4149   }
4150 
4151   strong_closure_assign();
4152   // If `*this' is empty, we return.
4153   if (marked_empty()) {
4154     return;
4155   }
4156 
4157   // We consider a constraint of `*this', if its value is `plus_infinity',
4158   // we take the value of the corresponding constraint of `y'.
4159   bool is_oct_changed = false;
4160   typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
4161   for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
4162          matrix_element_end = matrix.element_end();
4163        i != matrix_element_end;
4164        ++i, ++j) {
4165     if (!is_plus_infinity(*i)
4166         && !is_plus_infinity(*j)
4167         && *i != *j) {
4168       *i = *j;
4169       is_oct_changed = true;
4170     }
4171   }
4172 
4173   if (is_oct_changed && marked_strongly_closed()) {
4174     reset_strongly_closed();
4175   }
4176   PPL_ASSERT(OK());
4177 }
4178 
4179 template <typename T>
4180 void
4181 Octagonal_Shape<T>
deduce_v_pm_u_bounds(const dimension_type v_id,const dimension_type last_id,const Linear_Expression & sc_expr,Coefficient_traits::const_reference sc_denom,const N & ub_v)4182 ::deduce_v_pm_u_bounds(const dimension_type v_id,
4183                        const dimension_type last_id,
4184                        const Linear_Expression& sc_expr,
4185                        Coefficient_traits::const_reference sc_denom,
4186                        const N& ub_v) {
4187   // Private method: the caller has to ensure the following.
4188   PPL_ASSERT(sc_denom > 0);
4189   PPL_ASSERT(!is_plus_infinity(ub_v));
4190 
4191   PPL_DIRTY_TEMP(mpq_class, mpq_sc_denom);
4192   assign_r(mpq_sc_denom, sc_denom, ROUND_NOT_NEEDED);
4193 
4194   // No need to consider indices greater than `last_id'.
4195   const dimension_type n_v = 2*v_id;
4196   typename OR_Matrix<N>::row_reference_type m_cv = matrix[n_v + 1];
4197 
4198   // Speculatively allocate temporaries out of the loop.
4199   PPL_DIRTY_TEMP(N, half);
4200   PPL_DIRTY_TEMP(mpq_class, minus_lb_u);
4201   PPL_DIRTY_TEMP(mpq_class, q);
4202   PPL_DIRTY_TEMP(mpq_class, minus_q);
4203   PPL_DIRTY_TEMP(mpq_class, ub_u);
4204   PPL_DIRTY_TEMP(mpq_class, lb_u);
4205   PPL_DIRTY_TEMP(N, up_approx);
4206   PPL_DIRTY_TEMP_COEFFICIENT(minus_expr_u);
4207 
4208   for (Linear_Expression::const_iterator u = sc_expr.begin(),
4209       u_end = sc_expr.lower_bound(Variable(last_id + 1)); u != u_end; ++u) {
4210     const dimension_type u_id = u.variable().id();
4211     // Skip the case when `u_id == v_id'.
4212     if (u_id == v_id) {
4213       continue;
4214     }
4215     const Coefficient& expr_u = *u;
4216 
4217     const dimension_type n_u = u_id*2;
4218     // If `expr_u' is positive, we can improve `v - u'.
4219     if (expr_u > 0) {
4220       if (expr_u >= sc_denom) {
4221         // Here q >= 1: deducing `v - u <= ub_v - ub_u'.
4222         // We avoid to check if `ub_u' is plus infinity, because
4223         // it is used for the computation of `ub_v'.
4224         // Let half = m_cu_u / 2.
4225         div_2exp_assign_r(half, matrix[n_u + 1][n_u], 1, ROUND_UP);
4226         N& m_v_minus_u = (n_v < n_u) ? matrix[n_u][n_v] : m_cv[n_u + 1];
4227         sub_assign_r(m_v_minus_u, ub_v, half, ROUND_UP);
4228       }
4229       else {
4230         // Here 0 < q < 1.
4231         typename OR_Matrix<N>::row_reference_type m_u = matrix[n_u];
4232         const N& m_u_cu = m_u[n_u + 1];
4233         if (!is_plus_infinity(m_u_cu)) {
4234           // Let `ub_u' and `lb_u' be the known upper and lower bound
4235           // for `u', respectively. The upper bound for `v - u' is
4236           // computed as `ub_v - (q * ub_u + (1-q) * lb_u)',
4237           // i.e., `ub_v + (-lb_u) - q * (ub_u + (-lb_u))'.
4238           assign_r(minus_lb_u, m_u_cu, ROUND_NOT_NEEDED);
4239           div_2exp_assign_r(minus_lb_u, minus_lb_u, 1, ROUND_NOT_NEEDED);
4240           assign_r(q, expr_u, ROUND_NOT_NEEDED);
4241           div_assign_r(q, q, mpq_sc_denom, ROUND_NOT_NEEDED);
4242           assign_r(ub_u, matrix[n_u + 1][n_u], ROUND_NOT_NEEDED);
4243           div_2exp_assign_r(ub_u, ub_u, 1, ROUND_NOT_NEEDED);
4244           // Compute `ub_u - lb_u'.
4245           add_assign_r(ub_u, ub_u, minus_lb_u, ROUND_NOT_NEEDED);
4246           // Compute `(-lb_u) - q * (ub_u - lb_u)'.
4247           sub_mul_assign_r(minus_lb_u, q, ub_u, ROUND_NOT_NEEDED);
4248           assign_r(up_approx, minus_lb_u, ROUND_UP);
4249           // Deducing `v - u <= ub_v - (q * ub_u + (1-q) * lb_u)'.
4250           N& m_v_minus_u = (n_v < n_u) ? m_u[n_v] : m_cv[n_u + 1];
4251           add_assign_r(m_v_minus_u, ub_v, up_approx, ROUND_UP);
4252         }
4253       }
4254     }
4255     else {
4256       PPL_ASSERT(expr_u < 0);
4257       // If `expr_u' is negative, we can improve `v + u'.
4258       neg_assign(minus_expr_u, expr_u);
4259       if (minus_expr_u >= sc_denom) {
4260         // Here q <= -1: Deducing `v + u <= ub_v + lb_u'.
4261         // We avoid to check if `lb_u' is plus infinity, because
4262         // it is used for the computation of `ub_v'.
4263         // Let half = m_u_cu / 2.
4264         div_2exp_assign_r(half, matrix[n_u][n_u + 1], 1, ROUND_UP);
4265         N& m_v_plus_u = (n_v < n_u) ? matrix[n_u + 1][n_v] : m_cv[n_u];
4266         sub_assign_r(m_v_plus_u, ub_v, half, ROUND_UP);
4267       }
4268       else {
4269         // Here -1 < q < 0.
4270         typename OR_Matrix<N>::row_reference_type m_cu = matrix[n_u + 1];
4271         const N& m_cu_u = m_cu[n_u];
4272         if (!is_plus_infinity(m_cu_u)) {
4273           // Let `ub_u' and `lb_u' be the known upper and lower bound
4274           // for `u', respectively. The upper bound for `v + u' is
4275           // computed as `ub_v + ((-q) * lb_u + (1 + q) * ub_u)',
4276           // i.e., `ub_v + ub_u + (-q) * (lb_u - ub_u)'.
4277           assign_r(ub_u, m_cu[n_u], ROUND_NOT_NEEDED);
4278           div_2exp_assign_r(ub_u, ub_u, 1, ROUND_NOT_NEEDED);
4279           assign_r(minus_q, minus_expr_u, ROUND_NOT_NEEDED);
4280           div_assign_r(minus_q, minus_q, mpq_sc_denom, ROUND_NOT_NEEDED);
4281           assign_r(lb_u, matrix[n_u][n_u + 1], ROUND_NOT_NEEDED);
4282           div_2exp_assign_r(lb_u, lb_u, 1, ROUND_NOT_NEEDED);
4283           neg_assign_r(lb_u, lb_u, ROUND_NOT_NEEDED);
4284           // Compute `lb_u - ub_u'.
4285           sub_assign_r(lb_u, lb_u, ub_u, ROUND_NOT_NEEDED);
4286           // Compute `ub_u + (-q) * (lb_u - ub_u)'.
4287           add_mul_assign_r(ub_u, minus_q, lb_u, ROUND_NOT_NEEDED);
4288           assign_r(up_approx, ub_u, ROUND_UP);
4289           // Deducing `v + u <= ub_v + ((-q) * lb_u + (1 + q) * ub_u)'.
4290           N& m_v_plus_u = (n_v < n_u) ? m_cu[n_v] : m_cv[n_u];
4291           add_assign_r(m_v_plus_u, ub_v, up_approx, ROUND_UP);
4292         }
4293       }
4294     }
4295   }
4296 }
4297 
4298 template <typename T>
4299 void
4300 Octagonal_Shape<T>
deduce_minus_v_pm_u_bounds(const dimension_type v_id,const dimension_type last_id,const Linear_Expression & sc_expr,Coefficient_traits::const_reference sc_denom,const N & minus_lb_v)4301 ::deduce_minus_v_pm_u_bounds(const dimension_type v_id,
4302                              const dimension_type last_id,
4303                              const Linear_Expression& sc_expr,
4304                              Coefficient_traits::const_reference sc_denom,
4305                              const N& minus_lb_v) {
4306   // Private method: the caller has to ensure the following.
4307   PPL_ASSERT(sc_denom > 0);
4308   PPL_ASSERT(!is_plus_infinity(minus_lb_v));
4309 
4310   PPL_DIRTY_TEMP(mpq_class, mpq_sc_denom);
4311   assign_r(mpq_sc_denom, sc_denom, ROUND_NOT_NEEDED);
4312 
4313   // No need to consider indices greater than `last_id'.
4314   const dimension_type n_v = 2*v_id;
4315   typename OR_Matrix<N>::row_reference_type m_v = matrix[n_v];
4316 
4317   // Speculatively allocate temporaries out of the loop.
4318   PPL_DIRTY_TEMP(N, half);
4319   PPL_DIRTY_TEMP(mpq_class, ub_u);
4320   PPL_DIRTY_TEMP(mpq_class, q);
4321   PPL_DIRTY_TEMP(mpq_class, minus_lb_u);
4322   PPL_DIRTY_TEMP(N, up_approx);
4323   PPL_DIRTY_TEMP_COEFFICIENT(minus_expr_u);
4324 
4325   for (Linear_Expression::const_iterator u = sc_expr.begin(),
4326       u_end = sc_expr.lower_bound(Variable(last_id + 1)); u != u_end; ++u) {
4327     const dimension_type u_id = u.variable().id();
4328     // Skip the case when `u_id == v_id'.
4329     if (u_id == v_id) {
4330       continue;
4331     }
4332     const Coefficient& expr_u = *u;
4333 
4334     const dimension_type n_u = u_id*2;
4335     // If `expr_u' is positive, we can improve `-v + u'.
4336     if (expr_u > 0) {
4337       if (expr_u >= sc_denom) {
4338         // Here q >= 1: deducing `-v + u <= lb_u - lb_v',
4339         // i.e., `u - v <= (-lb_v) - (-lb_u)'.
4340         // We avoid to check if `lb_u' is plus infinity, because
4341         // it is used for the computation of `lb_v'.
4342         // Let half = m_u_cu / 2.
4343         div_2exp_assign_r(half, matrix[n_u][n_u + 1], 1, ROUND_UP);
4344         N& m_u_minus_v = (n_v < n_u) ? matrix[n_u + 1][n_v + 1] : m_v[n_u];
4345         sub_assign_r(m_u_minus_v, minus_lb_v, half, ROUND_UP);
4346       }
4347       else {
4348         // Here 0 < q < 1.
4349         typename OR_Matrix<N>::row_reference_type m_cu = matrix[n_u + 1];
4350         const N& m_cu_u = m_cu[n_u];
4351         if (!is_plus_infinity(m_cu_u)) {
4352           // Let `ub_u' and `lb_u' be the known upper and lower bound
4353           // for `u', respectively. The upper bound for `u - v' is
4354           // computed as `(q * lb_u + (1-q) * ub_u) - lb_v',
4355           // i.e., `ub_u - q * (ub_u + (-lb_u)) + minus_lb_v'.
4356           assign_r(ub_u, m_cu[n_u], ROUND_NOT_NEEDED);
4357           div_2exp_assign_r(ub_u, ub_u, 1, ROUND_NOT_NEEDED);
4358           assign_r(q, expr_u, ROUND_NOT_NEEDED);
4359           div_assign_r(q, q, mpq_sc_denom, ROUND_NOT_NEEDED);
4360           assign_r(minus_lb_u, matrix[n_u][n_u + 1], ROUND_NOT_NEEDED);
4361           div_2exp_assign_r(minus_lb_u, minus_lb_u, 1, ROUND_NOT_NEEDED);
4362           // Compute `ub_u - lb_u'.
4363           add_assign_r(minus_lb_u, ub_u, minus_lb_u, ROUND_NOT_NEEDED);
4364           // Compute `ub_u - q * (ub_u - lb_u)'.
4365           sub_mul_assign_r(ub_u, q, minus_lb_u, ROUND_NOT_NEEDED);
4366           assign_r(up_approx, ub_u, ROUND_UP);
4367           // Deducing `u - v <= -lb_v - (q * lb_u + (1-q) * ub_u)'.
4368           N& m_u_minus_v = (n_v < n_u) ? m_cu[n_v + 1] : m_v[n_u];
4369           add_assign_r(m_u_minus_v, minus_lb_v, up_approx, ROUND_UP);
4370         }
4371       }
4372     }
4373     else {
4374       PPL_ASSERT(expr_u < 0);
4375       // If `expr_u' is negative, we can improve `-v - u'.
4376       neg_assign(minus_expr_u, expr_u);
4377       if (minus_expr_u >= sc_denom) {
4378         // Here q <= -1: Deducing `-v - u <= -lb_v - ub_u'.
4379         // We avoid to check if `ub_u' is plus infinity, because
4380         // it is used for the computation of `lb_v'.
4381         // Let half = m_cu_u / 2.
4382         div_2exp_assign_r(half, matrix[n_u + 1][n_u], 1, ROUND_UP);
4383         N& m_minus_v_minus_u = (n_v < n_u)
4384           ? matrix[n_u][n_v + 1]
4385           : m_v[n_u + 1];
4386         sub_assign_r(m_minus_v_minus_u, minus_lb_v, half, ROUND_UP);
4387       }
4388       else {
4389         // Here -1 < q < 0.
4390         typename OR_Matrix<N>::row_reference_type m_u = matrix[n_u];
4391         const N& m_u_cu = m_u[n_u + 1];
4392         if (!is_plus_infinity(m_u_cu)) {
4393           // Let `ub_u' and `lb_u' be the known upper and lower bound
4394           // for `u', respectively. The upper bound for `-v - u' is
4395           // computed as `-lb_v - ((-q)*ub_u + (1 + q)*lb_u)',
4396           // i.e., `minus_lb_v - lb_u + q*(ub_u - lb_u)'.
4397           assign_r(ub_u, matrix[n_u + 1][n_u], ROUND_NOT_NEEDED);
4398           div_2exp_assign_r(ub_u, ub_u, 1, ROUND_NOT_NEEDED);
4399           assign_r(q, expr_u, ROUND_NOT_NEEDED);
4400           div_assign_r(q, q, mpq_sc_denom, ROUND_NOT_NEEDED);
4401           assign_r(minus_lb_u, m_u[n_u + 1], ROUND_NOT_NEEDED);
4402           div_2exp_assign_r(minus_lb_u, minus_lb_u, 1, ROUND_NOT_NEEDED);
4403           // Compute `ub_u - lb_u'.
4404           add_assign_r(ub_u, ub_u, minus_lb_u, ROUND_NOT_NEEDED);
4405           // Compute `-lb_u + q*(ub_u - lb_u)'.
4406           add_mul_assign_r(minus_lb_u, q, ub_u, ROUND_NOT_NEEDED);
4407           assign_r(up_approx, minus_lb_u, ROUND_UP);
4408           // Deducing `-v - u <= -lb_v - ((-q) * ub_u + (1 + q) * lb_u)'.
4409           N& m_minus_v_minus_u = (n_v < n_u) ? m_u[n_v + 1] : m_v[n_u + 1];
4410           add_assign_r(m_minus_v_minus_u, minus_lb_v, up_approx, ROUND_UP);
4411         }
4412       }
4413     }
4414   }
4415 }
4416 
4417 template <typename T>
4418 void
4419 Octagonal_Shape<T>
forget_all_octagonal_constraints(const dimension_type v_id)4420 ::forget_all_octagonal_constraints(const dimension_type v_id) {
4421   PPL_ASSERT(v_id < space_dim);
4422   const dimension_type n_v = 2*v_id;
4423   typename OR_Matrix<N>::row_iterator m_iter = matrix.row_begin() + n_v;
4424   typename OR_Matrix<N>::row_reference_type r_v = *m_iter;
4425   typename OR_Matrix<N>::row_reference_type r_cv = *(++m_iter);
4426   for (dimension_type h = m_iter.row_size(); h-- > 0; ) {
4427     assign_r(r_v[h], PLUS_INFINITY, ROUND_NOT_NEEDED);
4428     assign_r(r_cv[h], PLUS_INFINITY, ROUND_NOT_NEEDED);
4429   }
4430   ++m_iter;
4431   for (typename OR_Matrix<N>::row_iterator m_end = matrix.row_end();
4432        m_iter != m_end; ++m_iter) {
4433     typename OR_Matrix<N>::row_reference_type r = *m_iter;
4434     assign_r(r[n_v], PLUS_INFINITY, ROUND_NOT_NEEDED);
4435     assign_r(r[n_v + 1], PLUS_INFINITY, ROUND_NOT_NEEDED);
4436   }
4437 }
4438 
4439 template <typename T>
4440 void
4441 Octagonal_Shape<T>
forget_binary_octagonal_constraints(const dimension_type v_id)4442 ::forget_binary_octagonal_constraints(const dimension_type v_id) {
4443   PPL_ASSERT(v_id < space_dim);
4444   const dimension_type n_v = 2*v_id;
4445   typename OR_Matrix<N>::row_iterator m_iter = matrix.row_begin() + n_v;
4446   typename OR_Matrix<N>::row_reference_type r_v = *m_iter;
4447   typename OR_Matrix<N>::row_reference_type r_cv = *(++m_iter);
4448   for (dimension_type k = n_v; k-- > 0; ) {
4449     assign_r(r_v[k], PLUS_INFINITY, ROUND_NOT_NEEDED);
4450     assign_r(r_cv[k], PLUS_INFINITY, ROUND_NOT_NEEDED);
4451   }
4452   ++m_iter;
4453   for (typename OR_Matrix<N>::row_iterator m_end = matrix.row_end();
4454        m_iter != m_end; ++m_iter) {
4455     typename OR_Matrix<N>::row_reference_type r = *m_iter;
4456     assign_r(r[n_v], PLUS_INFINITY, ROUND_NOT_NEEDED);
4457     assign_r(r[n_v + 1], PLUS_INFINITY, ROUND_NOT_NEEDED);
4458   }
4459 }
4460 
4461 template <typename T>
4462 void
unconstrain(const Variable var)4463 Octagonal_Shape<T>::unconstrain(const Variable var) {
4464   // Dimension-compatibility check.
4465   const dimension_type var_id = var.id();
4466   if (space_dimension() < var_id + 1) {
4467     throw_dimension_incompatible("unconstrain(var)", var_id + 1);
4468   }
4469 
4470   // Enforce strong closure for precision.
4471   strong_closure_assign();
4472 
4473   // If the shape is empty, this is a no-op.
4474   if (marked_empty()) {
4475     return;
4476   }
4477 
4478   forget_all_octagonal_constraints(var_id);
4479   // Strong closure is preserved.
4480   PPL_ASSERT(OK());
4481 }
4482 
4483 template <typename T>
4484 void
unconstrain(const Variables_Set & vars)4485 Octagonal_Shape<T>::unconstrain(const Variables_Set& vars) {
4486   // The cylindrification with respect to no dimensions is a no-op.
4487   // This case captures the only legal cylindrification in a 0-dim space.
4488   if (vars.empty()) {
4489     return;
4490   }
4491 
4492   // Dimension-compatibility check.
4493   const dimension_type min_space_dim = vars.space_dimension();
4494   if (space_dimension() < min_space_dim) {
4495     throw_dimension_incompatible("unconstrain(vs)", min_space_dim);
4496   }
4497 
4498   // Enforce strong closure for precision.
4499   strong_closure_assign();
4500 
4501   // If the shape is empty, this is a no-op.
4502   if (marked_empty()) {
4503     return;
4504   }
4505 
4506   for (Variables_Set::const_iterator vsi = vars.begin(),
4507          vsi_end = vars.end(); vsi != vsi_end; ++vsi) {
4508     forget_all_octagonal_constraints(*vsi);
4509   }
4510   // Strong closure is preserved.
4511   PPL_ASSERT(OK());
4512 }
4513 
4514 template <typename T>
4515 void
refine(const Variable var,const Relation_Symbol relsym,const Linear_Expression & expr,Coefficient_traits::const_reference denominator)4516 Octagonal_Shape<T>::refine(const Variable var,
4517                            const Relation_Symbol relsym,
4518                            const Linear_Expression& expr,
4519                            Coefficient_traits::const_reference denominator) {
4520   PPL_ASSERT(denominator != 0);
4521   PPL_ASSERT(space_dim >= expr.space_dimension());
4522   const dimension_type var_id = var.id();
4523   PPL_ASSERT(var_id <= space_dim);
4524   PPL_ASSERT(expr.coefficient(var) == 0);
4525   PPL_ASSERT(relsym != LESS_THAN && relsym != GREATER_THAN);
4526 
4527   const Coefficient& b = expr.inhomogeneous_term();
4528   // Number of non-zero coefficients in `expr': will be set to
4529   // 0, 1, or 2, the latter value meaning any value greater than 1.
4530   dimension_type t = 0;
4531 
4532   // Variable index of the last non-zero coefficient in `expr', if any.
4533   dimension_type w_id = expr.last_nonzero();
4534 
4535   if (w_id != 0) {
4536     ++t;
4537     if (!expr.all_zeroes(1, w_id)) {
4538       ++t;
4539     }
4540     --w_id;
4541   }
4542 
4543   // Now we know the form of `expr':
4544   // - If t == 0, then expr == b, with `b' a constant;
4545   // - If t == 1, then expr == a*j + b, where `j != v';
4546   // - If t == 2, then `expr' is of the general form.
4547   typedef typename OR_Matrix<N>::row_iterator row_iterator;
4548   typedef typename OR_Matrix<N>::row_reference_type row_reference;
4549   typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
4550   typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
4551 
4552   const row_iterator m_begin = matrix.row_begin();
4553   const dimension_type n_var = 2*var_id;
4554   PPL_DIRTY_TEMP_COEFFICIENT(minus_denom);
4555   neg_assign(minus_denom, denominator);
4556 
4557   // Since we are only able to record octagonal differences, we can
4558   // precisely deal with the case of a single variable only if its
4559   // coefficient (taking into account the denominator) is 1.
4560   // If this is not the case, we fall back to the general case
4561   // so as to over-approximate the constraint.
4562   if (t == 1 && expr.coefficient(Variable(w_id)) != denominator
4563       && expr.coefficient(Variable(w_id)) != minus_denom) {
4564     t = 2;
4565   }
4566   if (t == 0) {
4567     // Case 1: expr == b.
4568     PPL_DIRTY_TEMP_COEFFICIENT(two_b);
4569     two_b = 2*b;
4570     switch (relsym) {
4571     case EQUAL:
4572       // Add the constraint `var == b/denominator'.
4573       add_octagonal_constraint(n_var + 1, n_var, two_b, denominator);
4574       add_octagonal_constraint(n_var, n_var + 1, two_b, minus_denom);
4575       break;
4576     case LESS_OR_EQUAL:
4577       // Add the constraint `var <= b/denominator'.
4578       add_octagonal_constraint(n_var + 1, n_var, two_b, denominator);
4579       break;
4580     case GREATER_OR_EQUAL:
4581       // Add the constraint `var >= b/denominator',
4582       // i.e., `-var <= -b/denominator',
4583       add_octagonal_constraint(n_var, n_var + 1, two_b, minus_denom);
4584       break;
4585     default:
4586       // We already dealt with the other cases.
4587       PPL_UNREACHABLE;
4588       break;
4589     }
4590   }
4591   else if (t == 1) {
4592     // Value of the one and only non-zero coefficient in `expr'.
4593     const Coefficient& w_coeff = expr.coefficient(Variable(w_id));
4594     const dimension_type n_w = 2*w_id;
4595     switch (relsym) {
4596     case EQUAL:
4597       if (w_coeff == denominator) {
4598         // Add the new constraint `var - w = b/denominator'.
4599         if (var_id < w_id) {
4600           add_octagonal_constraint(n_w, n_var, b, denominator);
4601           add_octagonal_constraint(n_w + 1, n_var + 1, b, minus_denom);
4602         }
4603         else {
4604           add_octagonal_constraint(n_var + 1, n_w + 1, b, denominator);
4605           add_octagonal_constraint(n_var, n_w, b, minus_denom);
4606         }
4607       }
4608       else {
4609         // Add the new constraint `var + w = b/denominator'.
4610         if (var_id < w_id) {
4611           add_octagonal_constraint(n_w + 1, n_var, b, denominator);
4612           add_octagonal_constraint(n_w, n_var + 1, b, minus_denom);
4613         }
4614         else {
4615           add_octagonal_constraint(n_var + 1, n_w, b, denominator);
4616           add_octagonal_constraint(n_var, n_w + 1, b, minus_denom);
4617         }
4618       }
4619       break;
4620     case LESS_OR_EQUAL:
4621       {
4622         PPL_DIRTY_TEMP(N, d);
4623         div_round_up(d, b, denominator);
4624         // Note that: `w_id != v', so that `expr' is of the form
4625         // w_coeff * w + b, with `w_id != v'.
4626         if (w_coeff == denominator) {
4627           // Add the new constraints `v - w <= b/denominator'.
4628           if (var_id < w_id) {
4629             add_octagonal_constraint(n_w, n_var, d);
4630           }
4631           else {
4632             add_octagonal_constraint(n_var + 1, n_w + 1, d);
4633           }
4634         }
4635         else if (w_coeff == minus_denom) {
4636           // Add the new constraints `v + w <= b/denominator'.
4637           if (var_id < w_id) {
4638             add_octagonal_constraint(n_w + 1, n_var, d);
4639           }
4640           else {
4641             add_octagonal_constraint(n_var + 1, n_w, d);
4642           }
4643         }
4644         break;
4645       }
4646 
4647     case GREATER_OR_EQUAL:
4648       {
4649         PPL_DIRTY_TEMP(N, d);
4650         div_round_up(d, b, minus_denom);
4651         // Note that: `w_id != v', so that `expr' is of the form
4652         // w_coeff * w + b, with `w_id != v'.
4653         if (w_coeff == denominator) {
4654           // Add the new constraint `v - w >= b/denominator',
4655           // i.e.,  `-v + w <= -b/denominator'.
4656           if (var_id < w_id) {
4657             add_octagonal_constraint(n_w + 1, n_var + 1, d);
4658           }
4659           else {
4660             add_octagonal_constraint(n_var, n_w, d);
4661           }
4662         }
4663         else if (w_coeff == minus_denom) {
4664           // Add the new constraints `v + w >= b/denominator',
4665           // i.e.,  `-v - w <= -b/denominator'.
4666           if (var_id < w_id) {
4667             add_octagonal_constraint(n_w, n_var + 1, d);
4668           }
4669           else {
4670             add_octagonal_constraint(n_var, n_w + 1, d);
4671           }
4672         }
4673         break;
4674       }
4675 
4676     default:
4677       // We already dealt with the other cases.
4678       PPL_UNREACHABLE;
4679       break;
4680     }
4681   }
4682   else {
4683     // Here t == 2, so that
4684     // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2.
4685     const bool is_sc = (denominator > 0);
4686     PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
4687     neg_assign(minus_b, b);
4688     const Coefficient& sc_b = is_sc ? b : minus_b;
4689     const Coefficient& minus_sc_b = is_sc ? minus_b : b;
4690     const Coefficient& sc_denom = is_sc ? denominator : minus_denom;
4691     const Coefficient& minus_sc_denom = is_sc ? minus_denom : denominator;
4692     // NOTE: here, for optimization purposes, `minus_expr' is only assigned
4693     // when `denominator' is negative. Do not use it unless you are sure
4694     // it has been correctly assigned.
4695     Linear_Expression minus_expr;
4696     if (!is_sc) {
4697       minus_expr = -expr;
4698     }
4699     const Linear_Expression& sc_expr = is_sc ? expr : minus_expr;
4700 
4701     PPL_DIRTY_TEMP(N, sum);
4702     // Index of variable that is unbounded in `this'.
4703     PPL_UNINITIALIZED(dimension_type, pinf_index);
4704     // Number of unbounded variables found.
4705     dimension_type pinf_count = 0;
4706 
4707     switch (relsym) {
4708     case EQUAL:
4709       {
4710         PPL_DIRTY_TEMP(N, neg_sum);
4711         // Index of variable that is unbounded in `this'.
4712         PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
4713         // Number of unbounded variables found.
4714         dimension_type neg_pinf_count = 0;
4715 
4716         // Approximate the inhomogeneous term.
4717         assign_r(sum, sc_b, ROUND_UP);
4718         assign_r(neg_sum, minus_sc_b, ROUND_UP);
4719 
4720         // Approximate the homogeneous part of `sc_expr'.
4721         PPL_DIRTY_TEMP(N, coeff_i);
4722         PPL_DIRTY_TEMP(N, half);
4723         PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
4724         PPL_DIRTY_TEMP(N, minus_coeff_i);
4725         // Note: indices above `w' can be disregarded, as they all have
4726         // a zero coefficient in `sc_expr'.
4727         for (Row_iterator m_iter = m_begin,
4728                m_iter_end = m_begin + (2 * w_id + 2);
4729              m_iter != m_iter_end; ) {
4730           const dimension_type n_i = m_iter.index();
4731           const dimension_type id = n_i/2;
4732           Row_reference m_i = *m_iter;
4733           ++m_iter;
4734           Row_reference m_ci = *m_iter;
4735           ++m_iter;
4736           const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
4737           const int sign_i = sgn(sc_i);
4738           if (sign_i > 0) {
4739             assign_r(coeff_i, sc_i, ROUND_UP);
4740             // Approximating `sc_expr'.
4741             if (pinf_count <= 1) {
4742               const N& double_approx_i = m_ci[n_i];
4743               if (!is_plus_infinity(double_approx_i)) {
4744                 // Let half = double_approx_i / 2.
4745                 div_2exp_assign_r(half, double_approx_i, 1, ROUND_UP);
4746                 add_mul_assign_r(sum, coeff_i, half, ROUND_UP);
4747               }
4748               else {
4749                 ++pinf_count;
4750                 pinf_index = id;
4751               }
4752             }
4753             // Approximating `-sc_expr'.
4754             if (neg_pinf_count <= 1) {
4755               const N& double_approx_minus_i = m_i[n_i + 1];
4756               if (!is_plus_infinity(double_approx_minus_i)) {
4757                 // Let half = double_approx_minus_i / 2.
4758                 div_2exp_assign_r(half, double_approx_minus_i, 1, ROUND_UP);
4759                 add_mul_assign_r(neg_sum, coeff_i, half, ROUND_UP);
4760               }
4761               else {
4762                 ++neg_pinf_count;
4763                 neg_pinf_index = id;
4764               }
4765             }
4766           }
4767           else if (sign_i < 0) {
4768             neg_assign_r(minus_sc_i, sc_i, ROUND_NOT_NEEDED);
4769             assign_r(minus_coeff_i, minus_sc_i, ROUND_UP);
4770             // Approximating `sc_expr'.
4771             if (pinf_count <= 1) {
4772               const N& double_approx_minus_i = m_i[n_i + 1];
4773               if (!is_plus_infinity(double_approx_minus_i)) {
4774                 // Let half = double_approx_minus_i / 2.
4775                 div_2exp_assign_r(half, double_approx_minus_i, 1, ROUND_UP);
4776                 add_mul_assign_r(sum, minus_coeff_i, half, ROUND_UP);
4777               }
4778               else {
4779                 ++pinf_count;
4780                 pinf_index = id;
4781               }
4782             }
4783             // Approximating `-sc_expr'.
4784             if (neg_pinf_count <= 1) {
4785               const N& double_approx_i = m_ci[n_i];
4786               if (!is_plus_infinity(double_approx_i)) {
4787                 // Let half = double_approx_i / 2.
4788                 div_2exp_assign_r(half, double_approx_i, 1, ROUND_UP);
4789                 add_mul_assign_r(neg_sum, minus_coeff_i, half, ROUND_UP);
4790               }
4791               else {
4792                 ++neg_pinf_count;
4793                 neg_pinf_index = id;
4794               }
4795             }
4796           }
4797         }
4798         // Return immediately if no approximation could be computed.
4799         if (pinf_count > 1 && neg_pinf_count > 1) {
4800           PPL_ASSERT(OK());
4801           return;
4802         }
4803 
4804         // In the following, strong closure will be definitely lost.
4805         reset_strongly_closed();
4806 
4807         // Exploit the upper approximation, if possible.
4808         if (pinf_count <= 1) {
4809           // Compute quotient (if needed).
4810           if (sc_denom != 1) {
4811             // Before computing quotients, the denominator should be
4812             // approximated towards zero. Since `sc_denom' is known to be
4813             // positive, this amounts to rounding downwards, which is
4814             // achieved as usual by rounding upwards `minus_sc_denom'
4815             // and negating again the result.
4816             PPL_DIRTY_TEMP(N, down_sc_denom);
4817             assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
4818             neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
4819             div_assign_r(sum, sum, down_sc_denom, ROUND_UP);
4820           }
4821           // Add the upper bound constraint, if meaningful.
4822           if (pinf_count == 0) {
4823             // Add the constraint `v <= sum'.
4824             PPL_DIRTY_TEMP(N, double_sum);
4825             mul_2exp_assign_r(double_sum, sum, 1, ROUND_UP);
4826             matrix[n_var + 1][n_var] = double_sum;
4827             // Deduce constraints of the form `v +/- u', where `u != v'.
4828             deduce_v_pm_u_bounds(var_id, w_id, sc_expr, sc_denom, sum);
4829           }
4830           else {
4831             // Here `pinf_count == 1'.
4832             if (pinf_index != var_id) {
4833               const Coefficient& ppi
4834                 = sc_expr.coefficient(Variable(pinf_index));
4835               if (ppi == sc_denom) {
4836                 // Add the constraint `v - pinf_index <= sum'.
4837                 if (var_id < pinf_index) {
4838                   matrix[2*pinf_index][n_var] = sum;
4839                 }
4840                 else {
4841                   matrix[n_var + 1][2*pinf_index + 1] = sum;
4842                 }
4843               }
4844               else {
4845                 if (ppi == minus_sc_denom) {
4846                   // Add the constraint `v + pinf_index <= sum'.
4847                   if (var_id < pinf_index) {
4848                     matrix[2*pinf_index + 1][n_var] = sum;
4849                   }
4850                   else {
4851                     matrix[n_var + 1][2*pinf_index] = sum;
4852                   }
4853                 }
4854               }
4855             }
4856           }
4857         }
4858 
4859         // Exploit the lower approximation, if possible.
4860         if (neg_pinf_count <= 1) {
4861           // Compute quotient (if needed).
4862           if (sc_denom != 1) {
4863             // Before computing quotients, the denominator should be
4864             // approximated towards zero. Since `sc_denom' is known to be
4865             // positive, this amounts to rounding downwards, which is
4866             // achieved as usual by rounding upwards `minus_sc_denom'
4867             // and negating again the result.
4868             PPL_DIRTY_TEMP(N, down_sc_denom);
4869             assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
4870             neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
4871             div_assign_r(neg_sum, neg_sum, down_sc_denom, ROUND_UP);
4872           }
4873           // Add the lower bound constraint, if meaningful.
4874           if (neg_pinf_count == 0) {
4875             // Add the constraint `v >= -neg_sum', i.e., `-v <= neg_sum'.
4876             PPL_DIRTY_TEMP(N, double_neg_sum);
4877             mul_2exp_assign_r(double_neg_sum, neg_sum, 1, ROUND_UP);
4878             matrix[n_var][n_var + 1] = double_neg_sum;
4879             // Deduce constraints of the form `-v +/- u', where `u != v'.
4880             deduce_minus_v_pm_u_bounds(var_id, w_id, sc_expr, sc_denom,
4881                                        neg_sum);
4882           }
4883           else {
4884             // Here `neg_pinf_count == 1'.
4885             if (neg_pinf_index != var_id) {
4886               const Coefficient& npi
4887                 = sc_expr.coefficient(Variable(neg_pinf_index));
4888               if (npi == sc_denom) {
4889                 // Add the constraint `v - neg_pinf_index >= -neg_sum',
4890                 // i.e., `neg_pinf_index - v <= neg_sum'.
4891                 if (neg_pinf_index < var_id) {
4892                   matrix[n_var][2*neg_pinf_index] = neg_sum;
4893                 }
4894                 else {
4895                   matrix[2*neg_pinf_index + 1][n_var + 1] = neg_sum;
4896                 }
4897               }
4898               else {
4899                 if (npi == minus_sc_denom) {
4900                   // Add the constraint `v + neg_pinf_index >= -neg_sum',
4901                   // i.e., `-neg_pinf_index - v <= neg_sum'.
4902                   if (neg_pinf_index < var_id) {
4903                     matrix[n_var][2*neg_pinf_index + 1] = neg_sum;
4904                   }
4905                   else {
4906                     matrix[2*neg_pinf_index][n_var + 1] = neg_sum;
4907                   }
4908                 }
4909               }
4910             }
4911           }
4912         }
4913         break;
4914       }
4915 
4916     case LESS_OR_EQUAL:
4917       {
4918         // Compute an upper approximation for `expr' into `sum',
4919         // taking into account the sign of `denominator'.
4920 
4921         // Approximate the inhomogeneous term.
4922         assign_r(sum, sc_b, ROUND_UP);
4923 
4924         // Approximate the homogeneous part of `sc_expr'.
4925         PPL_DIRTY_TEMP(N, coeff_i);
4926         PPL_DIRTY_TEMP(N, approx_i);
4927         PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
4928         // Note: indices above `w_id' can be disregarded, as they all have
4929         // a zero coefficient in `expr'.
4930         for (row_iterator m_iter = m_begin,
4931                m_iter_end = m_begin + (2 * w_id + 2);
4932              m_iter != m_iter_end; ) {
4933           const dimension_type n_i = m_iter.index();
4934           const dimension_type id = n_i/2;
4935           row_reference m_i = *m_iter;
4936           ++m_iter;
4937           row_reference m_ci = *m_iter;
4938           ++m_iter;
4939           const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
4940           const int sign_i = sgn(sc_i);
4941           if (sign_i == 0) {
4942             continue;
4943           }
4944           // Choose carefully: we are approximating `sc_expr'.
4945           const N& double_approx_i = (sign_i > 0) ? m_ci[n_i] : m_i[n_i + 1];
4946           if (is_plus_infinity(double_approx_i)) {
4947             if (++pinf_count > 1) {
4948               break;
4949             }
4950             pinf_index = id;
4951             continue;
4952           }
4953           if (sign_i > 0) {
4954             assign_r(coeff_i, sc_i, ROUND_UP);
4955           }
4956           else {
4957             neg_assign(minus_sc_i, sc_i);
4958             assign_r(coeff_i, minus_sc_i, ROUND_UP);
4959           }
4960           div_2exp_assign_r(approx_i, double_approx_i, 1, ROUND_UP);
4961           add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
4962         }
4963         // Divide by the (sign corrected) denominator (if needed).
4964         if (sc_denom != 1) {
4965           // Before computing the quotient, the denominator should be
4966           // approximated towards zero. Since `sc_denom' is known to be
4967           // positive, this amounts to rounding downwards, which is achieved
4968           // by rounding upwards `minus_sc-denom' and negating again the result.
4969           PPL_DIRTY_TEMP(N, down_sc_denom);
4970           assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
4971           neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
4972           div_assign_r(sum, sum, down_sc_denom, ROUND_UP);
4973         }
4974 
4975         if (pinf_count == 0) {
4976           // Add the constraint `v <= sum'.
4977           PPL_DIRTY_TEMP(N, double_sum);
4978           mul_2exp_assign_r(double_sum, sum, 1, ROUND_UP);
4979           add_octagonal_constraint(n_var + 1, n_var, double_sum);
4980           // Deduce constraints of the form `v +/- u', where `u != v'.
4981           deduce_v_pm_u_bounds(var_id, w_id, sc_expr, sc_denom, sum);
4982         }
4983         else if (pinf_count == 1) {
4984           dimension_type pinf_ind = 2*pinf_index;
4985           if (expr.coefficient(Variable(pinf_index)) == denominator ) {
4986             // Add the constraint `v - pinf_index <= sum'.
4987             if (var_id < pinf_index) {
4988               add_octagonal_constraint(pinf_ind, n_var, sum);
4989             }
4990             else {
4991               add_octagonal_constraint(n_var + 1, pinf_ind + 1, sum);
4992             }
4993           }
4994           else {
4995             if (expr.coefficient(Variable(pinf_index)) == minus_denom) {
4996               // Add the constraint `v + pinf_index <= sum'.
4997               if (var_id < pinf_index) {
4998                 add_octagonal_constraint(pinf_ind + 1, n_var, sum);
4999               }
5000               else {
5001                 add_octagonal_constraint(n_var + 1, pinf_ind, sum);
5002               }
5003             }
5004           }
5005         }
5006         break;
5007       }
5008 
5009     case GREATER_OR_EQUAL:
5010       {
5011         // Compute an upper approximation for `-sc_expr' into `sum'.
5012         // Note: approximating `-sc_expr' from above and then negating the
5013         // result is the same as approximating `sc_expr' from below.
5014 
5015         // Approximate the inhomogeneous term.
5016         assign_r(sum, minus_sc_b, ROUND_UP);
5017 
5018         // Approximate the homogeneous part of `-sc_expr'.
5019         PPL_DIRTY_TEMP(N, coeff_i);
5020         PPL_DIRTY_TEMP(N, approx_i);
5021         PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
5022         for (row_iterator m_iter = m_begin,
5023                m_iter_end = m_begin + (2 * w_id + 2);
5024              m_iter != m_iter_end; ) {
5025           const dimension_type n_i = m_iter.index();
5026           const dimension_type id = n_i/2;
5027           row_reference m_i = *m_iter;
5028           ++m_iter;
5029           row_reference m_ci = *m_iter;
5030           ++m_iter;
5031           const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
5032           const int sign_i = sgn(sc_i);
5033           if (sign_i == 0) {
5034             continue;
5035           }
5036           // Choose carefully: we are approximating `-sc_expr'.
5037           const N& double_approx_i = (sign_i > 0) ? m_i[n_i + 1] : m_ci[n_i];
5038           if (is_plus_infinity(double_approx_i)) {
5039             if (++pinf_count > 1) {
5040               break;
5041             }
5042             pinf_index = id;
5043             continue;
5044           }
5045           if (sign_i > 0) {
5046             assign_r(coeff_i, sc_i, ROUND_UP);
5047           }
5048           else {
5049             neg_assign(minus_sc_i, sc_i);
5050             assign_r(coeff_i, minus_sc_i, ROUND_UP);
5051           }
5052           div_2exp_assign_r(approx_i, double_approx_i, 1, ROUND_UP);
5053           add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
5054         }
5055 
5056         // Divide by the (sign corrected) denominator (if needed).
5057         if (sc_denom != 1) {
5058           // Before computing the quotient, the denominator should be
5059           // approximated towards zero. Since `sc_denom' is known to be
5060           // positive, this amounts to rounding downwards, which is
5061           // achieved by rounding upwards `minus_sc_denom' and
5062           // negating again the result.
5063           PPL_DIRTY_TEMP(N, down_sc_denom);
5064           assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
5065           neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
5066           div_assign_r(sum, sum, down_sc_denom, ROUND_UP);
5067         }
5068 
5069         if (pinf_count == 0) {
5070           // Add the constraint `v >= -neg_sum', i.e., `-v <= neg_sum'.
5071           PPL_DIRTY_TEMP(N, double_sum);
5072           mul_2exp_assign_r(double_sum, sum, 1, ROUND_UP);
5073           add_octagonal_constraint(n_var, n_var + 1, double_sum);
5074           // Deduce constraints of the form `-v +/- u', where `u != v'.
5075           deduce_minus_v_pm_u_bounds(var_id, pinf_index, sc_expr, sc_denom,
5076                                      sum);
5077         }
5078         else if (pinf_count == 1) {
5079           dimension_type pinf_ind = 2*pinf_index;
5080           if (expr.coefficient(Variable(pinf_index)) == denominator) {
5081             // Add the constraint `v - pinf_index >= -sum',
5082             // i.e., `pinf_index - v <= sum'.
5083             if (pinf_index < var_id) {
5084               add_octagonal_constraint(n_var, pinf_ind, sum);
5085             }
5086             else {
5087               add_octagonal_constraint(pinf_ind + 1, n_var, sum);
5088             }
5089           }
5090           else {
5091             if (expr.coefficient(Variable(pinf_index)) == minus_denom) {
5092               // Add the constraint `v + pinf_index >= -sum',
5093               // i.e., `-pinf_index - v <= sum'.
5094               if (pinf_index < var_id) {
5095                 add_octagonal_constraint(n_var, pinf_ind + 1, sum);
5096               }
5097               else {
5098                 add_octagonal_constraint(pinf_ind, n_var + 1, sum);
5099               }
5100             }
5101           }
5102         }
5103         break;
5104       }
5105 
5106     default:
5107       // We already dealt with the other cases.
5108       PPL_UNREACHABLE;
5109       break;
5110     }
5111   }
5112 }
5113 
5114 template <typename T>
5115 void
affine_image(const Variable var,const Linear_Expression & expr,Coefficient_traits::const_reference denominator)5116 Octagonal_Shape<T>::affine_image(const Variable var,
5117                                  const Linear_Expression& expr,
5118                                  Coefficient_traits::const_reference
5119                                  denominator) {
5120   // The denominator cannot be zero.
5121   if (denominator == 0) {
5122     throw_invalid_argument("affine_image(v, e, d)", "d == 0");
5123   }
5124 
5125   // Dimension-compatibility checks.
5126   // The dimension of `expr' should not be greater than the dimension
5127   // of `*this'.
5128   const dimension_type expr_space_dim = expr.space_dimension();
5129   if (space_dim < expr_space_dim) {
5130     throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
5131   }
5132 
5133   // `var' should be one of the dimensions of the octagon.
5134   const dimension_type var_id = var.id();
5135   if (space_dim < var_id + 1) {
5136     throw_dimension_incompatible("affine_image(v, e, d)", var_id + 1);
5137   }
5138 
5139   strong_closure_assign();
5140   // The image of an empty octagon is empty too.
5141   if (marked_empty()) {
5142     return;
5143   }
5144 
5145   // Number of non-zero coefficients in `expr': will be set to
5146   // 0, 1, or 2, the latter value meaning any value greater than 1.
5147   dimension_type t = 0;
5148   // Variable-index of the last non-zero coefficient in `expr', if any.
5149   dimension_type w_id = expr.last_nonzero();
5150 
5151   if (w_id != 0) {
5152     ++t;
5153     if (!expr.all_zeroes(1, w_id)) {
5154       ++t;
5155     }
5156     --w_id;
5157   }
5158 
5159   typedef typename OR_Matrix<N>::row_iterator row_iterator;
5160   typedef typename OR_Matrix<N>::row_reference_type row_reference;
5161   typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
5162   typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
5163   using std::swap;
5164 
5165   const dimension_type n_var = 2*var_id;
5166   const Coefficient& b = expr.inhomogeneous_term();
5167   PPL_DIRTY_TEMP_COEFFICIENT(minus_denom);
5168   neg_assign_r(minus_denom, denominator, ROUND_NOT_NEEDED);
5169 
5170   // `w' is the variable with index `w_id'.
5171   // Now we know the form of `expr':
5172   // - If t == 0, then expr == b, with `b' a constant;
5173   // - If t == 1, then expr == a*w + b, where `w' can be `v' or another
5174   //   variable; in this second case we have to check whether `a' is
5175   //   equal to `denominator' or `-denominator', since otherwise we have
5176   //   to fall back on the general form;
5177   // - If t == 2, the `expr' is of the general form.
5178 
5179   if (t == 0) {
5180     // Case 1: expr == b.
5181     // Remove all constraints on `var'.
5182     forget_all_octagonal_constraints(var_id);
5183     PPL_DIRTY_TEMP_COEFFICIENT(two_b);
5184     two_b = 2*b;
5185     // Add the constraint `var == b/denominator'.
5186     add_octagonal_constraint(n_var + 1, n_var, two_b, denominator);
5187     add_octagonal_constraint(n_var, n_var + 1, two_b, minus_denom);
5188     PPL_ASSERT(OK());
5189     return;
5190   }
5191 
5192   if (t == 1) {
5193     // The one and only non-zero homogeneous coefficient in `expr'.
5194     const Coefficient& w_coeff = expr.coefficient(Variable(w_id));
5195     if (w_coeff == denominator || w_coeff == minus_denom) {
5196       // Case 2: expr = w_coeff*w + b, with w_coeff = +/- denominator.
5197       if (w_id == var_id) {
5198         // Here `expr' is of the form: +/- denominator * v + b.
5199         const bool sign_symmetry = (w_coeff != denominator);
5200         if (!sign_symmetry && b == 0) {
5201           // The transformation is the identity function.
5202           return;
5203         }
5204         // Translate all the constraints on `var' adding or
5205         // subtracting the value `b/denominator'.
5206         PPL_DIRTY_TEMP(N, d);
5207         div_round_up(d, b, denominator);
5208         PPL_DIRTY_TEMP(N, minus_d);
5209         div_round_up(minus_d, b, minus_denom);
5210         if (sign_symmetry) {
5211           swap(d, minus_d);
5212         }
5213         const row_iterator m_begin = matrix.row_begin();
5214         const row_iterator m_end = matrix.row_end();
5215         row_iterator m_iter = m_begin + n_var;
5216         row_reference m_v = *m_iter;
5217         ++m_iter;
5218         row_reference m_cv = *m_iter;
5219         ++m_iter;
5220         // NOTE: delay update of unary constraints on `var'.
5221         for (dimension_type j = n_var; j-- > 0; ) {
5222           N& m_v_j = m_v[j];
5223           add_assign_r(m_v_j, m_v_j, minus_d, ROUND_UP);
5224           N& m_cv_j = m_cv[j];
5225           add_assign_r(m_cv_j, m_cv_j, d, ROUND_UP);
5226           if (sign_symmetry) {
5227             swap(m_v_j, m_cv_j);
5228           }
5229         }
5230         for ( ; m_iter != m_end; ++m_iter) {
5231           row_reference m_i = *m_iter;
5232           N& m_i_v = m_i[n_var];
5233           add_assign_r(m_i_v, m_i_v, d, ROUND_UP);
5234           N& m_i_cv = m_i[n_var + 1];
5235           add_assign_r(m_i_cv, m_i_cv, minus_d, ROUND_UP);
5236           if (sign_symmetry) {
5237             swap(m_i_v, m_i_cv);
5238           }
5239         }
5240         // Now update unary constraints on var.
5241         mul_2exp_assign_r(d, d, 1, ROUND_UP);
5242         N& m_cv_v = m_cv[n_var];
5243         add_assign_r(m_cv_v, m_cv_v, d, ROUND_UP);
5244         mul_2exp_assign_r(minus_d, minus_d, 1, ROUND_UP);
5245         N& m_v_cv = m_v[n_var + 1];
5246         add_assign_r(m_v_cv, m_v_cv, minus_d, ROUND_UP);
5247         if (sign_symmetry) {
5248           swap(m_cv_v, m_v_cv);
5249         }
5250         // Note: strong closure is preserved.
5251       }
5252       else {
5253         // Here `w != var', so that `expr' is of the form
5254         // +/-denominator * w + b.
5255         // Remove all constraints on `var'.
5256         forget_all_octagonal_constraints(var_id);
5257         const dimension_type n_w = 2*w_id;
5258         // Add the new constraint `var - w = b/denominator'.
5259         if (w_coeff == denominator) {
5260           if (var_id < w_id) {
5261             add_octagonal_constraint(n_w, n_var, b, denominator);
5262             add_octagonal_constraint(n_w + 1, n_var + 1, b, minus_denom);
5263           }
5264           else {
5265             add_octagonal_constraint(n_var + 1, n_w + 1, b, denominator);
5266             add_octagonal_constraint(n_var, n_w, b, minus_denom);
5267           }
5268         }
5269         else {
5270           // Add the new constraint `var + w = b/denominator'.
5271           if (var_id < w_id) {
5272             add_octagonal_constraint(n_w + 1, n_var, b, denominator);
5273             add_octagonal_constraint(n_w, n_var + 1, b, minus_denom);
5274           }
5275           else {
5276             add_octagonal_constraint(n_var + 1, n_w, b, denominator);
5277             add_octagonal_constraint(n_var, n_w + 1, b, minus_denom);
5278           }
5279         }
5280         incremental_strong_closure_assign(var);
5281       }
5282       PPL_ASSERT(OK());
5283       return;
5284     }
5285   }
5286 
5287   // General case.
5288   // Either t == 2, so that
5289   // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2,
5290   // or t == 1, expr == a*w + b, but a <> +/- denominator.
5291   // We will remove all the constraints on `var' and add back
5292   // constraints providing upper and lower bounds for `var'.
5293 
5294   // Compute upper approximations for `expr' and `-expr'
5295   // into `pos_sum' and `neg_sum', respectively, taking into account
5296   // the sign of `denominator'.
5297   // Note: approximating `-expr' from above and then negating the
5298   // result is the same as approximating `expr' from below.
5299   const bool is_sc = (denominator > 0);
5300   PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
5301   neg_assign_r(minus_b, b, ROUND_NOT_NEEDED);
5302 
5303   const Coefficient& sc_b = is_sc ? b : minus_b;
5304   const Coefficient& minus_sc_b = is_sc ? minus_b : b;
5305   const Coefficient& sc_denom = is_sc ? denominator : minus_denom;
5306   const Coefficient& minus_sc_denom = is_sc ? minus_denom : denominator;
5307   // NOTE: here, for optimization purposes, `minus_expr' is only assigned
5308   // when `denominator' is negative. Do not use it unless you are sure
5309   // it has been correctly assigned.
5310   Linear_Expression minus_expr;
5311   if (!is_sc) {
5312     minus_expr = -expr;
5313   }
5314   const Linear_Expression& sc_expr = is_sc ? expr : minus_expr;
5315 
5316   PPL_DIRTY_TEMP(N, pos_sum);
5317   PPL_DIRTY_TEMP(N, neg_sum);
5318   // Indices of the variables that are unbounded in `this->matrix'.
5319   PPL_UNINITIALIZED(dimension_type, pos_pinf_index);
5320   PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
5321   // Number of unbounded variables found.
5322   dimension_type pos_pinf_count = 0;
5323   dimension_type neg_pinf_count = 0;
5324 
5325   // Approximate the inhomogeneous term.
5326   assign_r(pos_sum, sc_b, ROUND_UP);
5327   assign_r(neg_sum, minus_sc_b, ROUND_UP);
5328 
5329   // Approximate the homogeneous part of `sc_expr'.
5330   PPL_DIRTY_TEMP(N, coeff_i);
5331   PPL_DIRTY_TEMP(N, minus_coeff_i);
5332   PPL_DIRTY_TEMP(N, half);
5333   PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
5334   // Note: indices above `w' can be disregarded, as they all have
5335   // a zero coefficient in `sc_expr'.
5336   const row_iterator m_begin = matrix.row_begin();
5337   for (Row_iterator m_iter = m_begin, m_iter_end = m_begin + (2 * w_id + 2);
5338        m_iter != m_iter_end; ) {
5339     const dimension_type n_i = m_iter.index();
5340     const dimension_type id = n_i/2;
5341     Row_reference m_i = *m_iter;
5342     ++m_iter;
5343     Row_reference m_ci = *m_iter;
5344     ++m_iter;
5345     const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
5346     const int sign_i = sgn(sc_i);
5347     if (sign_i > 0) {
5348       assign_r(coeff_i, sc_i, ROUND_UP);
5349       // Approximating `sc_expr'.
5350       if (pos_pinf_count <= 1) {
5351         const N& double_up_approx_i = m_ci[n_i];
5352         if (!is_plus_infinity(double_up_approx_i)) {
5353           // Let half = double_up_approx_i / 2.
5354           div_2exp_assign_r(half, double_up_approx_i, 1, ROUND_UP);
5355           add_mul_assign_r(pos_sum, coeff_i, half, ROUND_UP);
5356         }
5357         else {
5358           ++pos_pinf_count;
5359           pos_pinf_index = id;
5360         }
5361       }
5362       // Approximating `-sc_expr'.
5363       if (neg_pinf_count <= 1) {
5364         const N& double_up_approx_minus_i = m_i[n_i + 1];
5365         if (!is_plus_infinity(double_up_approx_minus_i)) {
5366           // Let half = double_up_approx_minus_i / 2.
5367           div_2exp_assign_r(half, double_up_approx_minus_i, 1, ROUND_UP);
5368           add_mul_assign_r(neg_sum, coeff_i, half, ROUND_UP);
5369         }
5370         else {
5371           ++neg_pinf_count;
5372           neg_pinf_index = id;
5373         }
5374       }
5375     }
5376     else if (sign_i < 0) {
5377       neg_assign_r(minus_sc_i, sc_i, ROUND_NOT_NEEDED);
5378       assign_r(minus_coeff_i, minus_sc_i, ROUND_UP);
5379       // Approximating `sc_expr'.
5380       if (pos_pinf_count <= 1) {
5381         const N& double_up_approx_minus_i = m_i[n_i + 1];
5382         if (!is_plus_infinity(double_up_approx_minus_i)) {
5383           // Let half = double_up_approx_minus_i / 2.
5384           div_2exp_assign_r(half, double_up_approx_minus_i, 1, ROUND_UP);
5385           add_mul_assign_r(pos_sum, minus_coeff_i, half, ROUND_UP);
5386         }
5387         else {
5388           ++pos_pinf_count;
5389           pos_pinf_index = id;
5390         }
5391       }
5392       // Approximating `-sc_expr'.
5393       if (neg_pinf_count <= 1) {
5394         const N& double_up_approx_i = m_ci[n_i];
5395         if (!is_plus_infinity(double_up_approx_i)) {
5396           // Let half = double_up_approx_i / 2.
5397           div_2exp_assign_r(half, double_up_approx_i, 1, ROUND_UP);
5398           add_mul_assign_r(neg_sum, minus_coeff_i, half, ROUND_UP);
5399         }
5400         else {
5401           ++neg_pinf_count;
5402           neg_pinf_index = id;
5403         }
5404       }
5405     }
5406   }
5407 
5408   // Remove all constraints on `var'.
5409   forget_all_octagonal_constraints(var_id);
5410   // Return immediately if no approximation could be computed.
5411   if (pos_pinf_count > 1 && neg_pinf_count > 1) {
5412     PPL_ASSERT(OK());
5413     return;
5414   }
5415 
5416   // In the following, strong closure will be definitely lost.
5417   reset_strongly_closed();
5418 
5419   // Exploit the upper approximation, if possible.
5420   if (pos_pinf_count <= 1) {
5421     // Compute quotient (if needed).
5422     if (sc_denom != 1) {
5423       // Before computing quotients, the denominator should be approximated
5424       // towards zero. Since `sc_denom' is known to be positive, this amounts to
5425       // rounding downwards, which is achieved as usual by rounding upwards
5426       // `minus_sc_denom' and negating again the result.
5427       PPL_DIRTY_TEMP(N, down_sc_denom);
5428       assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
5429       neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
5430       div_assign_r(pos_sum, pos_sum, down_sc_denom, ROUND_UP);
5431     }
5432     // Add the upper bound constraint, if meaningful.
5433     if (pos_pinf_count == 0) {
5434       // Add the constraint `v <= pos_sum'.
5435       PPL_DIRTY_TEMP(N, double_pos_sum);
5436       mul_2exp_assign_r(double_pos_sum, pos_sum, 1, ROUND_UP);
5437       matrix[n_var + 1][n_var] = double_pos_sum;
5438       // Deduce constraints of the form `v +/- u', where `u != v'.
5439       deduce_v_pm_u_bounds(var_id, w_id, sc_expr, sc_denom, pos_sum);
5440     }
5441     else {
5442       // Here `pos_pinf_count == 1'.
5443       if (pos_pinf_index != var_id) {
5444         const Coefficient& ppi = sc_expr.coefficient(Variable(pos_pinf_index));
5445         if (ppi == sc_denom) {
5446           // Add the constraint `v - pos_pinf_index <= pos_sum'.
5447           if (var_id < pos_pinf_index) {
5448             matrix[2*pos_pinf_index][n_var] = pos_sum;
5449           }
5450           else {
5451             matrix[n_var + 1][2*pos_pinf_index + 1] = pos_sum;
5452           }
5453         }
5454         else {
5455           if (ppi == minus_sc_denom) {
5456             // Add the constraint `v + pos_pinf_index <= pos_sum'.
5457             if (var_id < pos_pinf_index) {
5458               matrix[2*pos_pinf_index + 1][n_var] = pos_sum;
5459             }
5460             else {
5461               matrix[n_var + 1][2*pos_pinf_index] = pos_sum;
5462             }
5463           }
5464         }
5465       }
5466     }
5467   }
5468 
5469   // Exploit the lower approximation, if possible.
5470   if (neg_pinf_count <= 1) {
5471     // Compute quotient (if needed).
5472     if (sc_denom != 1) {
5473       // Before computing quotients, the denominator should be approximated
5474       // towards zero. Since `sc_denom' is known to be positive, this amounts to
5475       // rounding downwards, which is achieved as usual by rounding upwards
5476       // `minus_sc_denom' and negating again the result.
5477       PPL_DIRTY_TEMP(N, down_sc_denom);
5478       assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
5479       neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
5480       div_assign_r(neg_sum, neg_sum, down_sc_denom, ROUND_UP);
5481     }
5482     // Add the lower bound constraint, if meaningful.
5483     if (neg_pinf_count == 0) {
5484       // Add the constraint `v >= -neg_sum', i.e., `-v <= neg_sum'.
5485       PPL_DIRTY_TEMP(N, double_neg_sum);
5486       mul_2exp_assign_r(double_neg_sum, neg_sum, 1, ROUND_UP);
5487       matrix[n_var][n_var + 1] = double_neg_sum;
5488       // Deduce constraints of the form `-v +/- u', where `u != v'.
5489       deduce_minus_v_pm_u_bounds(var_id, w_id, sc_expr, sc_denom, neg_sum);
5490     }
5491     else {
5492       // Here `neg_pinf_count == 1'.
5493       if (neg_pinf_index != var_id) {
5494         const Coefficient& npi = sc_expr.coefficient(Variable(neg_pinf_index));
5495         if (npi == sc_denom) {
5496           // Add the constraint `v - neg_pinf_index >= -neg_sum',
5497           // i.e., `neg_pinf_index - v <= neg_sum'.
5498           if (neg_pinf_index < var_id) {
5499             matrix[n_var][2*neg_pinf_index] = neg_sum;
5500           }
5501           else {
5502             matrix[2*neg_pinf_index + 1][n_var + 1] = neg_sum;
5503           }
5504         }
5505         else {
5506           if (npi == minus_sc_denom) {
5507             // Add the constraint `v + neg_pinf_index >= -neg_sum',
5508             // i.e., `-neg_pinf_index - v <= neg_sum'.
5509             if (neg_pinf_index < var_id) {
5510               matrix[n_var][2*neg_pinf_index + 1] = neg_sum;
5511             }
5512             else {
5513               matrix[2*neg_pinf_index][n_var + 1] = neg_sum;
5514             }
5515           }
5516         }
5517       }
5518     }
5519   }
5520 
5521   incremental_strong_closure_assign(var);
5522   PPL_ASSERT(OK());
5523 }
5524 
5525 template <typename T>
5526 template <typename Interval_Info>
5527 void
affine_form_image(const Variable var,const Linear_Form<Interval<T,Interval_Info>> & lf)5528 Octagonal_Shape<T>::affine_form_image(const Variable var,
5529                     const Linear_Form< Interval<T, Interval_Info> >& lf) {
5530   // Check that T is a floating point type.
5531   PPL_COMPILE_TIME_CHECK(!std::numeric_limits<T>::is_exact,
5532     "Octagonal_Shape<T>::affine_form_image(Variable, Linear_Form):"
5533     " T is not a floating point type.");
5534 
5535   // Dimension-compatibility checks.
5536   // The dimension of `lf' should not be greater than the dimension
5537   // of `*this'.
5538   const dimension_type lf_space_dim = lf.space_dimension();
5539   if (space_dim < lf_space_dim) {
5540     throw_dimension_incompatible("affine_form_image(v, l)", "l", lf);
5541   }
5542 
5543   // `var' should be one of the dimensions of the octagon.
5544   const dimension_type var_id = var.id();
5545   if (space_dim < var_id + 1) {
5546     throw_dimension_incompatible("affine_form_image(v, l)", var.id() + 1);
5547   }
5548 
5549   strong_closure_assign();
5550   // The image of an empty octagon is empty too.
5551   if (marked_empty()) {
5552     return;
5553   }
5554 
5555   // Number of non-zero coefficients in `lf': will be set to
5556   // 0, 1, or 2, the latter value meaning any value greater than 1.
5557   dimension_type t = 0;
5558   // Variable-index of the last non-zero coefficient in `lf', if any.
5559   dimension_type w_id = 0;
5560 
5561   // Get information about the number of non-zero coefficients in `lf'.
5562   for (dimension_type i = lf_space_dim; i-- > 0; ) {
5563     if (lf.coefficient(Variable(i)) != 0) {
5564       if (t++ == 1) {
5565         break;
5566       }
5567       else {
5568         w_id = i;
5569       }
5570     }
5571   }
5572 
5573   typedef typename OR_Matrix<N>::row_iterator row_iterator;
5574   typedef typename OR_Matrix<N>::row_reference_type row_reference;
5575   typedef Interval<T, Interval_Info> FP_Interval_Type;
5576   using std::swap;
5577 
5578   const dimension_type n_var = 2*var_id;
5579   const FP_Interval_Type& b = lf.inhomogeneous_term();
5580 
5581   // `w' is the variable with index `w_id'.
5582   // Now we know the form of `lf':
5583   // - If t == 0, then lf == [lb, ub];
5584   // - If t == 1, then lf == a*w + [lb, ub], where `w' can be `v' or another
5585   //   variable;
5586   // - If t == 2, the `lf' is of the general form.
5587 
5588   PPL_DIRTY_TEMP(N, b_ub);
5589   assign_r(b_ub, b.upper(), ROUND_NOT_NEEDED);
5590   PPL_DIRTY_TEMP(N, b_mlb);
5591   neg_assign_r(b_mlb, b.lower(), ROUND_NOT_NEEDED);
5592 
5593   if (t == 0) {
5594     // Case 1: lf = [lb, ub].
5595     forget_all_octagonal_constraints(var_id);
5596     mul_2exp_assign_r(b_mlb, b_mlb, 1, ROUND_UP);
5597     mul_2exp_assign_r(b_ub, b_ub, 1, ROUND_UP);
5598     // Add the constraint `var >= lb && var <= ub'.
5599     add_octagonal_constraint(n_var + 1, n_var, b_ub);
5600     add_octagonal_constraint(n_var, n_var + 1, b_mlb);
5601     PPL_ASSERT(OK());
5602     return;
5603   }
5604 
5605   // True if `b' is in [0, 0].
5606   bool is_b_zero = (b_mlb == 0 && b_ub == 0);
5607 
5608   if (t == 1) {
5609     // The one and only non-zero homogeneous coefficient in `lf'.
5610     const FP_Interval_Type& w_coeff = lf.coefficient(Variable(w_id));
5611     // True if `w_coeff' is in [1, 1].
5612     bool is_w_coeff_one = (w_coeff == 1);
5613     // True if `w_coeff' is in [-1, -1].
5614     bool is_w_coeff_minus_one = (w_coeff == -1);
5615     if (is_w_coeff_one || is_w_coeff_minus_one) {
5616       // Case 2: lf = w_coeff*w + b, with w_coeff = [+/-1, +/-1].
5617       if (w_id == var_id) {
5618         // Here lf = w_coeff*v + b, with w_coeff = [+/-1, +/-1].
5619         if (is_w_coeff_one && is_b_zero) {
5620           // The transformation is the identity function.
5621           return;
5622         }
5623         // Translate all the constraints on `var' by adding the value
5624         // `b_ub' or subtracting the value `b_lb'.
5625         if (is_w_coeff_minus_one) {
5626           swap(b_ub, b_mlb);
5627         }
5628         const row_iterator m_begin = matrix.row_begin();
5629         const row_iterator m_end = matrix.row_end();
5630         row_iterator m_iter = m_begin + n_var;
5631         row_reference m_v = *m_iter;
5632         ++m_iter;
5633         row_reference m_cv = *m_iter;
5634         ++m_iter;
5635         // NOTE: delay update of unary constraints on `var'.
5636         for (dimension_type j = n_var; j-- > 0; ) {
5637           N& m_v_j = m_v[j];
5638           add_assign_r(m_v_j, m_v_j, b_mlb, ROUND_UP);
5639           N& m_cv_j = m_cv[j];
5640           add_assign_r(m_cv_j, m_cv_j, b_ub, ROUND_UP);
5641           if (is_w_coeff_minus_one) {
5642             swap(m_v_j, m_cv_j);
5643           }
5644         }
5645         for ( ; m_iter != m_end; ++m_iter) {
5646           row_reference m_i = *m_iter;
5647           N& m_i_v = m_i[n_var];
5648           add_assign_r(m_i_v, m_i_v, b_ub, ROUND_UP);
5649           N& m_i_cv = m_i[n_var + 1];
5650           add_assign_r(m_i_cv, m_i_cv, b_mlb, ROUND_UP);
5651           if (is_w_coeff_minus_one) {
5652             swap(m_i_v, m_i_cv);
5653           }
5654         }
5655         // Now update unary constraints on var.
5656         mul_2exp_assign_r(b_ub, b_ub, 1, ROUND_UP);
5657         N& m_cv_v = m_cv[n_var];
5658         add_assign_r(m_cv_v, m_cv_v, b_ub, ROUND_UP);
5659         mul_2exp_assign_r(b_mlb, b_mlb, 1, ROUND_UP);
5660         N& m_v_cv = m_v[n_var + 1];
5661         add_assign_r(m_v_cv, m_v_cv, b_mlb, ROUND_UP);
5662         if (is_w_coeff_minus_one) {
5663           swap(m_cv_v, m_v_cv);
5664         }
5665         // Note: strong closure is preserved.
5666       }
5667       else {
5668         // Here `w != var', so that `lf' is of the form
5669         // [+/-1, +/-1] * w + b.
5670         // Remove all constraints on `var'.
5671         forget_all_octagonal_constraints(var_id);
5672         const dimension_type n_w = 2*w_id;
5673         if (is_w_coeff_one) {
5674           // Add the new constraints `var - w >= b_lb'
5675           // `and var - w <= b_ub'.
5676           if (var_id < w_id) {
5677             add_octagonal_constraint(n_w, n_var, b_ub);
5678             add_octagonal_constraint(n_w + 1, n_var + 1, b_mlb);
5679           }
5680           else {
5681             add_octagonal_constraint(n_var + 1, n_w + 1, b_ub);
5682             add_octagonal_constraint(n_var, n_w, b_mlb);
5683           }
5684         }
5685         else {
5686           // Add the new constraints `var + w >= b_lb'
5687           // `and var + w <= b_ub'.
5688           if (var_id < w_id) {
5689             add_octagonal_constraint(n_w + 1, n_var, b_ub);
5690             add_octagonal_constraint(n_w, n_var + 1, b_mlb);
5691           }
5692           else {
5693             add_octagonal_constraint(n_var + 1, n_w, b_ub);
5694             add_octagonal_constraint(n_var, n_w + 1, b_mlb);
5695           }
5696         }
5697         incremental_strong_closure_assign(var);
5698       }
5699       PPL_ASSERT(OK());
5700       return;
5701     }
5702   }
5703 
5704   // General case.
5705   // Either t == 2, so that
5706   // expr == i_1*x_1 + i_2*x_2 + ... + i_n*x_n + b, where n >= 2,
5707   // or t == 1, expr == i*w + b, but i <> [+/-1, +/-1].
5708 
5709   // In the following, strong closure will be definitely lost.
5710   reset_strongly_closed();
5711 
5712   Linear_Form<FP_Interval_Type> minus_lf(lf);
5713   minus_lf.negate();
5714 
5715   // Declare temporaries outside the loop.
5716   PPL_DIRTY_TEMP(N, upper_bound);
5717 
5718   row_iterator m_iter = matrix.row_begin();
5719   m_iter += n_var;
5720   row_reference var_ite = *m_iter;
5721   ++m_iter;
5722   row_reference var_cv_ite = *m_iter;
5723   ++m_iter;
5724   row_iterator m_end = matrix.row_end();
5725 
5726   // Update binary constraints on var FIRST.
5727   for (dimension_type curr_var = var_id,
5728          n_curr_var = n_var - 2; curr_var-- > 0; ) {
5729     Variable current(curr_var);
5730     linear_form_upper_bound(lf + current, upper_bound);
5731     assign_r(var_cv_ite[n_curr_var], upper_bound, ROUND_NOT_NEEDED);
5732     linear_form_upper_bound(lf - current, upper_bound);
5733     assign_r(var_cv_ite[n_curr_var + 1], upper_bound, ROUND_NOT_NEEDED);
5734     linear_form_upper_bound(minus_lf + current, upper_bound);
5735     assign_r(var_ite[n_curr_var], upper_bound, ROUND_NOT_NEEDED);
5736     linear_form_upper_bound(minus_lf - current, upper_bound);
5737     assign_r(var_ite[n_curr_var + 1], upper_bound, ROUND_NOT_NEEDED);
5738     n_curr_var -= 2;
5739   }
5740   for (dimension_type curr_var = var_id + 1; m_iter != m_end; ++m_iter) {
5741     row_reference m_v_ite = *m_iter;
5742     ++m_iter;
5743     row_reference m_cv_ite = *m_iter;
5744     Variable current(curr_var);
5745     linear_form_upper_bound(lf + current, upper_bound);
5746     assign_r(m_cv_ite[n_var], upper_bound, ROUND_NOT_NEEDED);
5747     linear_form_upper_bound(lf - current, upper_bound);
5748     assign_r(m_v_ite[n_var], upper_bound, ROUND_NOT_NEEDED);
5749     linear_form_upper_bound(minus_lf + current, upper_bound);
5750     assign_r(m_cv_ite[n_var + 1], upper_bound, ROUND_NOT_NEEDED);
5751     linear_form_upper_bound(minus_lf - current, upper_bound);
5752     assign_r(m_v_ite[n_var + 1], upper_bound, ROUND_NOT_NEEDED);
5753     ++curr_var;
5754   }
5755 
5756   // Finally, update unary constraints on var.
5757   PPL_DIRTY_TEMP(N, lf_ub);
5758   linear_form_upper_bound(lf, lf_ub);
5759   PPL_DIRTY_TEMP(N, minus_lf_ub);
5760   linear_form_upper_bound(minus_lf, minus_lf_ub);
5761   mul_2exp_assign_r(lf_ub, lf_ub, 1, ROUND_UP);
5762   assign_r(matrix[n_var + 1][n_var], lf_ub, ROUND_NOT_NEEDED);
5763   mul_2exp_assign_r(minus_lf_ub, minus_lf_ub, 1, ROUND_UP);
5764   assign_r(matrix[n_var][n_var + 1], minus_lf_ub, ROUND_NOT_NEEDED);
5765 
5766   PPL_ASSERT(OK());
5767 }
5768 
5769 template <typename T>
5770 template <typename Interval_Info>
5771 void
5772 Octagonal_Shape<T>::
linear_form_upper_bound(const Linear_Form<Interval<T,Interval_Info>> & lf,N & result) const5773 linear_form_upper_bound(const Linear_Form< Interval<T, Interval_Info> >& lf,
5774                         N& result) const {
5775 
5776   // Check that T is a floating point type.
5777   PPL_COMPILE_TIME_CHECK(!std::numeric_limits<T>::is_exact,
5778                      "Octagonal_Shape<T>::linear_form_upper_bound:"
5779                      " T not a floating point type.");
5780 
5781   const dimension_type lf_space_dimension = lf.space_dimension();
5782   PPL_ASSERT(lf_space_dimension <= space_dim);
5783 
5784   typedef Interval<T, Interval_Info> FP_Interval_Type;
5785 
5786   PPL_DIRTY_TEMP(N, curr_lb);
5787   PPL_DIRTY_TEMP(N, curr_ub);
5788   PPL_DIRTY_TEMP(N, curr_var_ub);
5789   PPL_DIRTY_TEMP(N, curr_minus_var_ub);
5790 
5791   PPL_DIRTY_TEMP(N, first_comparison_term);
5792   PPL_DIRTY_TEMP(N, second_comparison_term);
5793 
5794   PPL_DIRTY_TEMP(N, negator);
5795 
5796   assign_r(result, lf.inhomogeneous_term().upper(), ROUND_NOT_NEEDED);
5797 
5798   for (dimension_type curr_var = 0, n_var = 0; curr_var < lf_space_dimension;
5799        ++curr_var) {
5800     const FP_Interval_Type& curr_coefficient =
5801                             lf.coefficient(Variable(curr_var));
5802     assign_r(curr_lb, curr_coefficient.lower(), ROUND_NOT_NEEDED);
5803     assign_r(curr_ub, curr_coefficient.upper(), ROUND_NOT_NEEDED);
5804     if (curr_lb != 0 || curr_ub != 0) {
5805       assign_r(curr_var_ub, matrix[n_var + 1][n_var], ROUND_NOT_NEEDED);
5806       div_2exp_assign_r(curr_var_ub, curr_var_ub, 1, ROUND_UP);
5807       neg_assign_r(curr_minus_var_ub, matrix[n_var][n_var + 1],
5808                    ROUND_NOT_NEEDED);
5809       div_2exp_assign_r(curr_minus_var_ub, curr_minus_var_ub, 1, ROUND_DOWN);
5810       // Optimize the most common case: curr = +/-[1, 1].
5811       if (curr_lb == 1 && curr_ub == 1) {
5812         add_assign_r(result, result, std::max(curr_var_ub, curr_minus_var_ub),
5813                      ROUND_UP);
5814       }
5815       else if (curr_lb == -1 && curr_ub == -1) {
5816         neg_assign_r(negator, std::min(curr_var_ub, curr_minus_var_ub),
5817                      ROUND_NOT_NEEDED);
5818         add_assign_r(result, result, negator, ROUND_UP);
5819       }
5820       else {
5821         // Next addend will be the maximum of four quantities.
5822         assign_r(first_comparison_term, 0, ROUND_NOT_NEEDED);
5823         assign_r(second_comparison_term, 0, ROUND_NOT_NEEDED);
5824         add_mul_assign_r(first_comparison_term, curr_var_ub, curr_ub,
5825                          ROUND_UP);
5826         add_mul_assign_r(second_comparison_term, curr_var_ub, curr_lb,
5827                          ROUND_UP);
5828         assign_r(first_comparison_term, std::max(first_comparison_term,
5829                                                  second_comparison_term),
5830                  ROUND_NOT_NEEDED);
5831         assign_r(second_comparison_term, 0, ROUND_NOT_NEEDED);
5832         add_mul_assign_r(second_comparison_term, curr_minus_var_ub, curr_ub,
5833                          ROUND_UP);
5834         assign_r(first_comparison_term, std::max(first_comparison_term,
5835                                                  second_comparison_term),
5836                  ROUND_NOT_NEEDED);
5837         assign_r(second_comparison_term, 0, ROUND_NOT_NEEDED);
5838         add_mul_assign_r(second_comparison_term, curr_minus_var_ub, curr_lb,
5839                          ROUND_UP);
5840         assign_r(first_comparison_term, std::max(first_comparison_term,
5841                                                  second_comparison_term),
5842                  ROUND_NOT_NEEDED);
5843 
5844         add_assign_r(result, result, first_comparison_term, ROUND_UP);
5845       }
5846     }
5847 
5848     n_var += 2;
5849   }
5850 }
5851 
5852 template <typename T>
5853 void
5854 Octagonal_Shape<T>::
interval_coefficient_upper_bound(const N & var_ub,const N & minus_var_ub,const N & int_ub,const N & int_lb,N & result)5855 interval_coefficient_upper_bound(const N& var_ub, const N& minus_var_ub,
5856                                  const N& int_ub, const N& int_lb,
5857                                  N& result) {
5858 
5859   // Check that T is a floating point type.
5860   PPL_COMPILE_TIME_CHECK(!std::numeric_limits<T>::is_exact,
5861                      "Octagonal_Shape<T>::interval_coefficient_upper_bound:"
5862                      " T not a floating point type.");
5863 
5864   // NOTE: we store the first comparison term directly into result.
5865   PPL_DIRTY_TEMP(N, second_comparison_term);
5866   PPL_DIRTY_TEMP(N, third_comparison_term);
5867   PPL_DIRTY_TEMP(N, fourth_comparison_term);
5868 
5869   assign_r(result, 0, ROUND_NOT_NEEDED);
5870   assign_r(second_comparison_term, 0, ROUND_NOT_NEEDED);
5871   assign_r(third_comparison_term, 0, ROUND_NOT_NEEDED);
5872   assign_r(fourth_comparison_term, 0, ROUND_NOT_NEEDED);
5873 
5874   add_mul_assign_r(result, var_ub, int_ub, ROUND_UP);
5875   add_mul_assign_r(second_comparison_term, minus_var_ub, int_ub, ROUND_UP);
5876   add_mul_assign_r(third_comparison_term, var_ub, int_lb, ROUND_UP);
5877   add_mul_assign_r(fourth_comparison_term, minus_var_ub, int_lb, ROUND_UP);
5878 
5879   assign_r(result, std::max(result, second_comparison_term), ROUND_NOT_NEEDED);
5880   assign_r(result, std::max(result, third_comparison_term), ROUND_NOT_NEEDED);
5881   assign_r(result, std::max(result, fourth_comparison_term), ROUND_NOT_NEEDED);
5882 }
5883 
5884 template <typename T>
5885 void
affine_preimage(const Variable var,const Linear_Expression & expr,Coefficient_traits::const_reference denominator)5886 Octagonal_Shape<T>::affine_preimage(const Variable var,
5887                                     const Linear_Expression& expr,
5888                                     Coefficient_traits::const_reference
5889                                     denominator) {
5890 
5891   // The denominator cannot be zero.
5892   if (denominator == 0) {
5893     throw_invalid_argument("affine_preimage(v, e, d)", "d == 0");
5894   }
5895 
5896   // Dimension-compatibility checks.
5897   // The dimension of `expr' should not be greater than the dimension
5898   // of `*this'.
5899   const dimension_type expr_space_dim = expr.space_dimension();
5900   if (space_dim < expr_space_dim) {
5901     throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
5902   }
5903 
5904   // `var' should be one of the dimensions of the octagon.
5905   dimension_type var_id = var.id();
5906   if (space_dim < var_id + 1) {
5907     throw_dimension_incompatible("affine_preimage(v, e, d)", var_id + 1);
5908   }
5909 
5910   strong_closure_assign();
5911   // The image of an empty octagon is empty too.
5912   if (marked_empty()) {
5913     return;
5914   }
5915 
5916   const Coefficient& b = expr.inhomogeneous_term();
5917 
5918   // Number of non-zero coefficients in `expr': will be set to
5919   // 0, 1, or 2, the latter value meaning any value greater than 1.
5920   dimension_type t = 0;
5921 
5922   // Variable-index of the last non-zero coefficient in `expr', if any.
5923   dimension_type w_id = expr.last_nonzero();
5924 
5925   if (w_id != 0) {
5926     ++t;
5927     if (!expr.all_zeroes(1, w_id)) {
5928       ++t;
5929     }
5930     --w_id;
5931   }
5932 
5933   // `w' is the variable with index `w_id'.
5934   // Now we know the form of `expr':
5935   // - If t == 0, then expr == b, with `b' a constant;
5936   // - If t == 1, then expr == a*w + b, where `w' can be `v' or another
5937   //   variable; in this second case we have to check whether `a' is
5938   //   equal to `denominator' or `-denominator', since otherwise we have
5939   //   to fall back on the general form;
5940   // - If t == 2, the `expr' is of the general form.
5941 
5942   if (t == 0) {
5943     // Case 1: expr = n; remove all constraints on `var'.
5944     forget_all_octagonal_constraints(var_id);
5945     PPL_ASSERT(OK());
5946     return;
5947   }
5948 
5949   if (t == 1) {
5950     // Value of the one and only non-zero coefficient in `expr'.
5951     const Coefficient& w_coeff = expr.coefficient(Variable(w_id));
5952     if (w_coeff == denominator || w_coeff == -denominator) {
5953       // Case 2: expr = w_coeff*w + b, with w_coeff = +/- denominator.
5954       if (w_id == var_id) {
5955         // Apply affine_image() on the inverse of this transformation.
5956         affine_image(var, denominator*var - b, w_coeff);
5957       }
5958       else {
5959         // `expr == w_coeff*w + b', where `w != var'.
5960         // Remove all constraints on `var'.
5961         forget_all_octagonal_constraints(var_id);
5962         PPL_ASSERT(OK());
5963       }
5964       return;
5965     }
5966   }
5967   // General case.
5968   // Either t == 2, so that
5969   // expr = a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2,
5970   // or t = 1, expr = a*w + b, but a <> +/- denominator.
5971   const Coefficient& coeff_v = expr.coefficient(var);
5972   if (coeff_v != 0) {
5973     if (coeff_v > 0) {
5974       // The transformation is invertible.
5975       Linear_Expression inverse = ((coeff_v + denominator)*var);
5976       inverse -= expr;
5977       affine_image(var, inverse, coeff_v);
5978     }
5979     else {
5980       // The transformation is invertible.
5981       PPL_DIRTY_TEMP_COEFFICIENT(minus_coeff_v);
5982       neg_assign(minus_coeff_v, coeff_v);
5983       Linear_Expression inverse = ((minus_coeff_v - denominator)*var);
5984       inverse += expr;
5985       affine_image(var, inverse, minus_coeff_v);
5986     }
5987   }
5988   else {
5989     // The transformation is not invertible: all constraints on `var' are lost.
5990     forget_all_octagonal_constraints(var_id);
5991     PPL_ASSERT(OK());
5992   }
5993 }
5994 
5995 template <typename T>
5996 void
5997 Octagonal_Shape<T>
generalized_affine_image(const Variable var,const Relation_Symbol relsym,const Linear_Expression & expr,Coefficient_traits::const_reference denominator)5998 ::generalized_affine_image(const Variable var,
5999                            const Relation_Symbol relsym,
6000                            const Linear_Expression&  expr ,
6001                            Coefficient_traits::const_reference denominator) {
6002   // The denominator cannot be zero.
6003   if (denominator == 0) {
6004     throw_invalid_argument("generalized_affine_image(v, r, e, d)", "d == 0");
6005   }
6006 
6007   // Dimension-compatibility checks.
6008   // The dimension of `expr' should not be greater than the dimension
6009   // of `*this'.
6010   const dimension_type expr_space_dim = expr.space_dimension();
6011   if (space_dim < expr_space_dim) {
6012     throw_dimension_incompatible("generalized_affine_image(v, r, e, d)", "e",
6013                                  expr);
6014   }
6015 
6016   // `var' should be one of the dimensions of the octagon.
6017   dimension_type var_id = var.id();
6018   if (space_dim < var_id + 1) {
6019     throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
6020                                  var_id + 1);
6021   }
6022 
6023   // The relation symbol cannot be a strict relation symbol.
6024   if (relsym == LESS_THAN || relsym == GREATER_THAN) {
6025     throw_invalid_argument("generalized_affine_image(v, r, e, d)",
6026                            "r is a strict relation symbol");
6027   }
6028   // The relation symbol cannot be a disequality.
6029   if (relsym == NOT_EQUAL) {
6030     throw_invalid_argument("generalized_affine_image(v, r, e, d)",
6031                            "r is the disequality relation symbol");
6032   }
6033 
6034   if (relsym == EQUAL) {
6035     // The relation symbol is "=":
6036     // this is just an affine image computation.
6037     affine_image(var, expr, denominator);
6038     return;
6039   }
6040 
6041   strong_closure_assign();
6042   // The image of an empty octagon is empty too.
6043   if (marked_empty()) {
6044     return;
6045   }
6046 
6047   // Number of non-zero coefficients in `expr': will be set to
6048   // 0, 1, or 2, the latter value meaning any value greater than 1.
6049   dimension_type t = 0;
6050   // Variable-index of the last non-zero coefficient in `expr', if any.
6051   dimension_type w_id = expr.last_nonzero();
6052 
6053   if (w_id != 0) {
6054     ++t;
6055     if (!expr.all_zeroes(1, w_id)) {
6056       ++t;
6057     }
6058     --w_id;
6059   }
6060 
6061   typedef typename OR_Matrix<N>::row_iterator row_iterator;
6062   typedef typename OR_Matrix<N>::row_reference_type row_reference;
6063   typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
6064   typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
6065 
6066   const row_iterator m_begin = matrix.row_begin();
6067   const row_iterator m_end = matrix.row_end();
6068   const dimension_type n_var = 2*var_id;
6069   const Coefficient& b = expr.inhomogeneous_term();
6070   PPL_DIRTY_TEMP_COEFFICIENT(minus_denom);
6071   neg_assign_r(minus_denom, denominator, ROUND_NOT_NEEDED);
6072 
6073   // `w' is the variable with index `w_id'.
6074   // Now we know the form of `expr':
6075   // - If t == 0, then expr == b, with `b' a constant;
6076   // - If t == 1, then expr == a*w + b, where `w' can be `v' or another
6077   //   variable; in this second case we have to check whether `a' is
6078   //   equal to `denominator' or `-denominator', since otherwise we have
6079   //   to fall back on the general form;
6080   // - If t == 2, the `expr' is of the general form.
6081 
6082   if (t == 0) {
6083     // Case 1: expr = b.
6084     PPL_DIRTY_TEMP_COEFFICIENT(two_b);
6085     two_b = 2*b;
6086     // Remove all constraints on `var'.
6087     forget_all_octagonal_constraints(var_id);
6088     // Strong closure is lost.
6089     reset_strongly_closed();
6090     switch (relsym) {
6091     case LESS_OR_EQUAL:
6092       // Add the constraint `var <= b/denominator'.
6093       add_octagonal_constraint(n_var + 1, n_var, two_b, denominator);
6094       break;
6095     case GREATER_OR_EQUAL:
6096       // Add the constraint `var >= n/denominator',
6097       // i.e., `-var <= -b/denominator'.
6098       add_octagonal_constraint(n_var, n_var + 1, two_b, minus_denom);
6099       break;
6100     default:
6101       // We already dealt with the other cases.
6102       PPL_UNREACHABLE;
6103       break;
6104     }
6105     PPL_ASSERT(OK());
6106     return;
6107   }
6108 
6109   if (t == 1) {
6110     // The one and only non-zero homogeneous coefficient in `expr'.
6111     const Coefficient& w_coeff = expr.coefficient(Variable(w_id));
6112     if (w_coeff == denominator || w_coeff == minus_denom) {
6113       // Case 2: expr == w_coeff*w + b, with w_coeff == +/- denominator.
6114       switch (relsym) {
6115       case LESS_OR_EQUAL:
6116         {
6117           PPL_DIRTY_TEMP(N, d);
6118           div_round_up(d, b, denominator);
6119           if (w_id == var_id) {
6120             // Here `expr' is of the form: +/- denominator * v + b.
6121             // Strong closure is not preserved.
6122             reset_strongly_closed();
6123             if (w_coeff == denominator) {
6124               // Translate all the constraints of the form `v - w <= cost'
6125               // into the constraint `v - w <= cost + b/denominator';
6126               // forget each constraint `w - v <= cost1'.
6127               row_iterator m_iter = m_begin + n_var;
6128               row_reference m_v = *m_iter;
6129               N& m_v_cv = m_v[n_var + 1];
6130               ++m_iter;
6131               row_reference m_cv = *m_iter;
6132               N& m_cv_v = m_cv[n_var];
6133               ++m_iter;
6134               // NOTE: delay update of m_v_cv and m_cv_v.
6135               for ( ; m_iter != m_end; ++m_iter) {
6136                 row_reference m_i = *m_iter;
6137                 N& m_i_v = m_i[n_var];
6138                 add_assign_r(m_i_v, m_i_v, d, ROUND_UP);
6139                 assign_r(m_i[n_var + 1], PLUS_INFINITY, ROUND_NOT_NEEDED);
6140               }
6141               for (dimension_type k = n_var; k-- > 0; ) {
6142                 assign_r(m_v[k], PLUS_INFINITY, ROUND_NOT_NEEDED);
6143                 add_assign_r(m_cv[k], m_cv[k], d, ROUND_UP);
6144               }
6145               mul_2exp_assign_r(d, d, 1, ROUND_UP);
6146               add_assign_r(m_cv_v, m_cv_v, d, ROUND_UP);
6147               assign_r(m_v_cv, PLUS_INFINITY, ROUND_NOT_NEEDED);
6148             }
6149             else {
6150               // Here `w_coeff == -denominator'.
6151               // `expr' is of the form: -a*var + b.
6152               N& m_v_cv = matrix[n_var][n_var + 1];
6153               mul_2exp_assign_r(d, d, 1, ROUND_UP);
6154               add_assign_r(matrix[n_var + 1][n_var], m_v_cv, d, ROUND_UP);
6155               assign_r(m_v_cv, PLUS_INFINITY, ROUND_NOT_NEEDED);
6156               forget_binary_octagonal_constraints(var_id);
6157             }
6158           }
6159           else {
6160             // Here `w != v', so that `expr' is the form
6161             // +/- denominator*w + b.
6162             // Remove all constraints on `v'.
6163             forget_all_octagonal_constraints(var_id);
6164             const dimension_type n_w = 2*w_id;
6165             if (w_coeff == denominator) {
6166               // Add the new constraint `v - w <= b/denominator'.
6167               if (var_id < w_id) {
6168                 add_octagonal_constraint(n_w, n_var, b, denominator);
6169               }
6170               else {
6171                 add_octagonal_constraint(n_var + 1, n_w + 1, b, denominator);
6172               }
6173             }
6174             else {
6175               // Add the new constraint `v + w <= b/denominator'.
6176               if (var_id < w_id) {
6177                 add_octagonal_constraint(n_w + 1, n_var, b, denominator);
6178               }
6179               else {
6180                 add_octagonal_constraint(n_var + 1, n_w, b, denominator);
6181               }
6182             }
6183           }
6184           break;
6185         }
6186 
6187       case GREATER_OR_EQUAL:
6188         {
6189           PPL_DIRTY_TEMP(N, d);
6190           div_round_up(d, b, minus_denom);
6191           if (w_id == var_id) {
6192             // Here `expr' is of the form: +/- denominator * v + b.
6193             // Strong closure is not preserved.
6194             reset_strongly_closed();
6195             if (w_coeff == denominator) {
6196               // Translate each constraint `w - v <= cost'
6197               // into the constraint `w - v <= cost - b/denominator';
6198               // forget each constraint `v - w <= cost1'.
6199               row_iterator m_iter = m_begin + n_var;
6200               row_reference m_v = *m_iter;
6201               N& m_v_cv = m_v[n_var + 1];
6202               ++m_iter;
6203               row_reference m_cv = *m_iter;
6204               N& m_cv_v = m_cv[n_var];
6205               ++m_iter;
6206               // NOTE: delay update of m_v_cv and m_cv_v.
6207               for ( ; m_iter != m_end; ++m_iter) {
6208                 row_reference m_i = *m_iter;
6209                 assign_r(m_i[n_var], PLUS_INFINITY, ROUND_NOT_NEEDED);
6210                 add_assign_r(m_i[n_var + 1], m_i[n_var + 1], d, ROUND_UP);
6211               }
6212               for (dimension_type k = n_var; k-- > 0; ) {
6213                 add_assign_r(m_v[k], m_v[k], d, ROUND_UP);
6214                 assign_r(m_cv[k], PLUS_INFINITY, ROUND_NOT_NEEDED);
6215               }
6216               mul_2exp_assign_r(d, d, 1, ROUND_UP);
6217               add_assign_r(m_v_cv, m_v_cv, d, ROUND_UP);
6218               assign_r(m_cv_v, PLUS_INFINITY, ROUND_NOT_NEEDED);
6219             }
6220             else {
6221               // Here `w_coeff == -denominator'.
6222               // `expr' is of the form: -a*var + b.
6223               N& m_cv_v = matrix[n_var + 1][n_var];
6224               mul_2exp_assign_r(d, d, 1, ROUND_UP);
6225               add_assign_r(matrix[n_var][n_var + 1], m_cv_v, d, ROUND_UP);
6226               assign_r(m_cv_v, PLUS_INFINITY, ROUND_NOT_NEEDED);
6227               forget_binary_octagonal_constraints(var_id);
6228             }
6229           }
6230           else {
6231             // Here `w != v', so that `expr' is of the form
6232             // +/-denominator * w + b, with `w != v'.
6233             // Remove all constraints on `v'.
6234             forget_all_octagonal_constraints(var_id);
6235             const dimension_type n_w = 2*w_id;
6236             // We have got an expression of the following form:
6237             // var1 + n, with `var1' != `var'.
6238             // We remove all constraints of the form `var (+/- var1) >= const'
6239             // and we add the new constraint `var +/- var1 >= n/denominator'.
6240             if (w_coeff == denominator) {
6241               // Add the new constraint `var - w >= b/denominator',
6242               // i.e., `w - var <= -b/denominator'.
6243               if (var_id < w_id) {
6244                 add_octagonal_constraint(n_w + 1, n_var + 1, b, minus_denom);
6245               }
6246               else {
6247                 add_octagonal_constraint(n_var, n_w, b, minus_denom);
6248               }
6249             }
6250             else {
6251               // Add the new constraint `var + w >= b/denominator',
6252               // i.e., `-w - var <= -b/denominator'.
6253               if (var_id < w_id) {
6254                 add_octagonal_constraint(n_w, n_var + 1, b, minus_denom);
6255               }
6256               else {
6257                 add_octagonal_constraint(n_var, n_w + 1, b, minus_denom);
6258               }
6259             }
6260           }
6261           break;
6262         }
6263 
6264       default:
6265         // We already dealt with the other cases.
6266         PPL_UNREACHABLE;
6267         break;
6268       }
6269       PPL_ASSERT(OK());
6270       return;
6271     }
6272   }
6273 
6274   // General case.
6275   // Either t == 2, so that
6276   // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2,
6277   // or t == 1, expr == a*w + b, but a <> +/- denominator.
6278   // We will remove all the constraints on `v' and add back
6279   // a constraint providing an upper or a lower bound for `v'
6280   // (depending on `relsym').
6281   const bool is_sc = (denominator > 0);
6282   PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
6283   neg_assign(minus_b, b);
6284   const Coefficient& sc_b = is_sc ? b : minus_b;
6285   const Coefficient& minus_sc_b = is_sc ? minus_b : b;
6286   const Coefficient& sc_denom = is_sc ? denominator : minus_denom;
6287   const Coefficient& minus_sc_denom = is_sc ? minus_denom : denominator;
6288   // NOTE: here, for optimization purposes, `minus_expr' is only assigned
6289   // when `denominator' is negative. Do not use it unless you are sure
6290   // it has been correctly assigned.
6291   Linear_Expression minus_expr;
6292   if (!is_sc) {
6293     minus_expr = -expr;
6294   }
6295   const Linear_Expression& sc_expr = is_sc ? expr : minus_expr;
6296 
6297   PPL_DIRTY_TEMP(N, sum);
6298   // Index of variable that is unbounded in `this->matrix'.
6299   PPL_UNINITIALIZED(dimension_type, pinf_index);
6300   // Number of unbounded variables found.
6301   dimension_type pinf_count = 0;
6302 
6303   switch (relsym) {
6304   case LESS_OR_EQUAL:
6305     {
6306       // Compute an upper approximation for `sc_expr' into `sum'.
6307 
6308       // Approximate the inhomogeneous term.
6309       assign_r(sum, sc_b, ROUND_UP);
6310       // Approximate the homogeneous part of `sc_expr'.
6311       PPL_DIRTY_TEMP(N, coeff_i);
6312       PPL_DIRTY_TEMP(N, approx_i);
6313       PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
6314       // Note: indices above `w' can be disregarded, as they all have
6315       // a zero coefficient in `sc_expr'.
6316       for (Row_iterator m_iter = m_begin, m_iter_end = m_begin + (2 * w_id + 2);
6317            m_iter != m_iter_end; ) {
6318         const dimension_type n_i = m_iter.index();
6319         const dimension_type id = n_i/2;
6320         Row_reference m_i = *m_iter;
6321         ++m_iter;
6322         Row_reference m_ci = *m_iter;
6323         ++m_iter;
6324         const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
6325         const int sign_i = sgn(sc_i);
6326         if (sign_i == 0) {
6327           continue;
6328         }
6329         // Choose carefully: we are approximating `sc_expr'.
6330         const N& double_approx_i = (sign_i > 0) ? m_ci[n_i] : m_i[n_i + 1];
6331         if (is_plus_infinity(double_approx_i)) {
6332           if (++pinf_count > 1) {
6333             break;
6334           }
6335           pinf_index = id;
6336           continue;
6337         }
6338         if (sign_i > 0) {
6339           assign_r(coeff_i, sc_i, ROUND_UP);
6340         }
6341         else {
6342           neg_assign(minus_sc_i, sc_i);
6343           assign_r(coeff_i, minus_sc_i, ROUND_UP);
6344         }
6345         div_2exp_assign_r(approx_i, double_approx_i, 1, ROUND_UP);
6346         add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
6347       }
6348       // Remove all constraints on `v'.
6349       forget_all_octagonal_constraints(var_id);
6350       reset_strongly_closed();
6351       // Return immediately if no approximation could be computed.
6352       if (pinf_count > 1) {
6353         PPL_ASSERT(OK());
6354         return;
6355       }
6356 
6357       // Divide by the (sign corrected) denominator (if needed).
6358       if (sc_denom != 1) {
6359         // Before computing the quotient, the denominator should be
6360         // approximated towards zero. Since `sc_denom' is known to be
6361         // positive, this amounts to rounding downwards, which is
6362         // achieved as usual by rounding upwards
6363         // `minus_sc_denom' and negating again the result.
6364         PPL_DIRTY_TEMP(N, down_sc_denom);
6365         assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
6366         neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
6367         div_assign_r(sum, sum, down_sc_denom, ROUND_UP);
6368       }
6369 
6370       if (pinf_count == 0) {
6371         // Add the constraint `v <= pos_sum'.
6372         PPL_DIRTY_TEMP(N, double_sum);
6373         mul_2exp_assign_r(double_sum, sum, 1, ROUND_UP);
6374         matrix[n_var + 1][n_var] = double_sum;
6375         // Deduce constraints of the form `v +/- u', where `u != v'.
6376         deduce_v_pm_u_bounds(var_id, w_id, sc_expr, sc_denom, sum);
6377       }
6378       else if (pinf_count == 1) {
6379         if (pinf_index != var_id) {
6380           const Coefficient& pi = expr.coefficient(Variable(pinf_index));
6381           if (pi == denominator ) {
6382             // Add the constraint `v - pinf_index <= sum'.
6383             if (var_id < pinf_index) {
6384               matrix[2*pinf_index][n_var] = sum;
6385             }
6386             else {
6387               matrix[n_var + 1][2*pinf_index + 1] = sum;
6388             }
6389           }
6390           else {
6391             if (pi == minus_denom) {
6392               // Add the constraint `v + pinf_index <= sum'.
6393               if (var_id < pinf_index) {
6394                 matrix[2*pinf_index + 1][n_var] = sum;
6395               }
6396               else {
6397                 matrix[n_var + 1][2*pinf_index] = sum;
6398               }
6399             }
6400           }
6401         }
6402       }
6403       break;
6404     }
6405 
6406   case GREATER_OR_EQUAL:
6407     {
6408       // Compute an upper approximation for `-sc_expr' into `sum'.
6409       // Note: approximating `-sc_expr' from above and then negating the
6410       // result is the same as approximating `sc_expr' from below.
6411 
6412       // Approximate the inhomogeneous term.
6413       assign_r(sum, minus_sc_b, ROUND_UP);
6414       PPL_DIRTY_TEMP(N, coeff_i);
6415       PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
6416       PPL_DIRTY_TEMP(N, approx_i);
6417       // Approximate the homogeneous part of `-sc_expr'.
6418       for (Row_iterator m_iter = m_begin, m_iter_end = m_begin + (2 * w_id + 2);
6419            m_iter != m_iter_end; ) {
6420         const dimension_type n_i = m_iter.index();
6421         const dimension_type id = n_i/2;
6422         Row_reference m_i = *m_iter;
6423         ++m_iter;
6424         Row_reference m_ci = *m_iter;
6425         ++m_iter;
6426         const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
6427         const int sign_i = sgn(sc_i);
6428         if (sign_i == 0) {
6429           continue;
6430         }
6431         // Choose carefully: we are approximating `-sc_expr'.
6432         const N& double_approx_i = (sign_i > 0) ? m_i[n_i + 1] : m_ci[n_i];
6433         if (is_plus_infinity(double_approx_i)) {
6434           if (++pinf_count > 1) {
6435             break;
6436           }
6437           pinf_index = id;
6438           continue;
6439         }
6440         if (sign_i > 0) {
6441           assign_r(coeff_i, sc_i, ROUND_UP);
6442         }
6443         else {
6444           neg_assign(minus_sc_i, sc_i);
6445           assign_r(coeff_i, minus_sc_i, ROUND_UP);
6446         }
6447         div_2exp_assign_r(approx_i, double_approx_i, 1, ROUND_UP);
6448         add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
6449       }
6450 
6451       // Remove all constraints on `var'.
6452       forget_all_octagonal_constraints(var_id);
6453       reset_strongly_closed();
6454       // Return immediately if no approximation could be computed.
6455       if (pinf_count > 1) {
6456         PPL_ASSERT(OK());
6457         return;
6458       }
6459 
6460       // Divide by the (sign corrected) denominator (if needed).
6461       if (sc_denom != 1) {
6462         // Before computing the quotient, the denominator should be
6463         // approximated towards zero. Since `sc_denom' is known to be
6464         // positive, this amounts to rounding downwards, which is
6465         // achieved as usual by rounding upwards
6466         // `minus_sc_denom' and negating again the result.
6467         PPL_DIRTY_TEMP(N, down_sc_denom);
6468         assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
6469         neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
6470         div_assign_r(sum, sum, down_sc_denom, ROUND_UP);
6471       }
6472 
6473       if (pinf_count == 0) {
6474         // Add the constraint `v >= -neg_sum', i.e., `-v <= neg_sum'.
6475         PPL_DIRTY_TEMP(N, double_sum);
6476         mul_2exp_assign_r(double_sum, sum, 1, ROUND_UP);
6477         matrix[n_var][n_var + 1] = double_sum;
6478         // Deduce constraints of the form `-v +/- u', where `u != v'.
6479         deduce_minus_v_pm_u_bounds(var_id, pinf_index, sc_expr, sc_denom, sum);
6480       }
6481       else if (pinf_count == 1) {
6482         if (pinf_index != var_id) {
6483           const Coefficient& pi = expr.coefficient(Variable(pinf_index));
6484           if (pi == denominator) {
6485             // Add the constraint `v - pinf_index >= -sum',
6486             // i.e., `pinf_index - v <= sum'.
6487             if (pinf_index < var_id) {
6488               matrix[n_var][2*pinf_index] = sum;
6489             }
6490             else {
6491               matrix[2*pinf_index + 1][n_var + 1] = sum;
6492             }
6493           }
6494           else {
6495             if (pi == minus_denom) {
6496               // Add the constraint `v + pinf_index >= -sum',
6497               // i.e., `-pinf_index - v <= sum'.
6498               if (pinf_index < var_id) {
6499                 matrix[n_var][2*pinf_index + 1] = sum;
6500               }
6501               else {
6502                 matrix[2*pinf_index][n_var + 1] = sum;
6503               }
6504             }
6505           }
6506         }
6507       }
6508       break;
6509     }
6510 
6511   default:
6512     // We already dealt with the other cases.
6513     PPL_UNREACHABLE;
6514     break;
6515   }
6516   incremental_strong_closure_assign(var);
6517   PPL_ASSERT(OK());
6518 }
6519 
6520 template <typename T>
6521 void
generalized_affine_image(const Linear_Expression & lhs,const Relation_Symbol relsym,const Linear_Expression & rhs)6522 Octagonal_Shape<T>::generalized_affine_image(const Linear_Expression& lhs,
6523                                              const Relation_Symbol relsym,
6524                                              const Linear_Expression& rhs) {
6525   // Dimension-compatibility checks.
6526   // The dimension of `lhs' should not be greater than the dimension
6527   // of `*this'.
6528   dimension_type lhs_space_dim = lhs.space_dimension();
6529   if (space_dim < lhs_space_dim) {
6530     throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
6531                                  "e1", lhs);
6532   }
6533   // The dimension of `rhs' should not be greater than the dimension
6534   // of `*this'.
6535   const dimension_type rhs_space_dim = rhs.space_dimension();
6536   if (space_dim < rhs_space_dim) {
6537     throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
6538                                  "e2", rhs);
6539   }
6540 
6541   // Strict relation symbols are not admitted for octagons.
6542   if (relsym == LESS_THAN || relsym == GREATER_THAN) {
6543     throw_invalid_argument("generalized_affine_image(e1, r, e2)",
6544                            "r is a strict relation symbol");
6545   }
6546   // The relation symbol cannot be a disequality.
6547   if (relsym == NOT_EQUAL) {
6548     throw_invalid_argument("generalized_affine_image(e1, r, e2)",
6549                            "r is the disequality relation symbol");
6550   }
6551 
6552   strong_closure_assign();
6553   // The image of an empty octagon is empty.
6554   if (marked_empty()) {
6555     return;
6556   }
6557 
6558   // Number of non-zero coefficients in `lhs': will be set to
6559   // 0, 1, or 2, the latter value meaning any value greater than 1.
6560   dimension_type t_lhs = 0;
6561   // Index of the last non-zero coefficient in `lhs', if any.
6562   dimension_type j_lhs = lhs.last_nonzero();
6563 
6564   if (j_lhs != 0) {
6565     ++t_lhs;
6566     if (!lhs.all_zeroes(1, j_lhs)) {
6567       ++t_lhs;
6568     }
6569     --j_lhs;
6570   }
6571 
6572   const Coefficient& b_lhs = lhs.inhomogeneous_term();
6573 
6574   if (t_lhs == 0) {
6575     // `lhs' is a constant.
6576     // In principle, it is sufficient to add the constraint `lhs relsym rhs'.
6577     // Note that this constraint is an octagonal difference if `t_rhs <= 1'
6578     // or `t_rhs > 1' and `rhs == a*v - a*w + b_rhs' or
6579     // `rhs == a*v + a*w + b_rhs'. If `rhs' is of a
6580     // more general form, it will be simply ignored.
6581     // TODO: if it is not an octagonal difference, should we compute
6582     // approximations for this constraint?
6583     switch (relsym) {
6584     case LESS_OR_EQUAL:
6585       refine_no_check(lhs <= rhs);
6586       break;
6587     case EQUAL:
6588       refine_no_check(lhs == rhs);
6589       break;
6590     case GREATER_OR_EQUAL:
6591       refine_no_check(lhs >= rhs);
6592       break;
6593     default:
6594       // We already dealt with the other cases.
6595       PPL_UNREACHABLE;
6596       break;
6597     }
6598   }
6599 
6600   else if (t_lhs == 1) {
6601     // Here `lhs == a_lhs * v + b_lhs'.
6602     // Independently from the form of `rhs', we can exploit the
6603     // method computing generalized affine images for a single variable.
6604     Variable v(j_lhs);
6605     // Compute a sign-corrected relation symbol.
6606     const Coefficient& denom = lhs.coefficient(v);
6607     Relation_Symbol new_relsym = relsym;
6608     if (denom < 0) {
6609       if (relsym == LESS_OR_EQUAL) {
6610         new_relsym = GREATER_OR_EQUAL;
6611       }
6612       else if (relsym == GREATER_OR_EQUAL) {
6613         new_relsym = LESS_OR_EQUAL;
6614       }
6615     }
6616     Linear_Expression expr = rhs - b_lhs;
6617     generalized_affine_image(v, new_relsym, expr, denom);
6618   }
6619   else {
6620     // Here `lhs' is of the general form, having at least two variables.
6621     // Compute the set of variables occurring in `lhs'.
6622     std::vector<Variable> lhs_vars;
6623     for (Linear_Expression::const_iterator i = lhs.begin(), i_end = lhs.end();
6624           i != i_end; ++i) {
6625       lhs_vars.push_back(i.variable());
6626     }
6627 
6628     const dimension_type num_common_dims = std::min(lhs_space_dim, rhs_space_dim);
6629     if (!lhs.have_a_common_variable(rhs, Variable(0), Variable(num_common_dims))) {
6630       // `lhs' and `rhs' variables are disjoint.
6631       // Existentially quantify all variables in the lhs.
6632       for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
6633         dimension_type lhs_vars_i = lhs_vars[i].id();
6634         forget_all_octagonal_constraints(lhs_vars_i);
6635       }
6636       // Constrain the left hand side expression so that it is related to
6637       // the right hand side expression as dictated by `relsym'.
6638       // TODO: if the following constraint is NOT an octagonal difference,
6639       // it will be simply ignored. Should we compute approximations for it?
6640       switch (relsym) {
6641       case LESS_OR_EQUAL:
6642         refine_no_check(lhs <= rhs);
6643         break;
6644       case EQUAL:
6645         refine_no_check(lhs == rhs);
6646         break;
6647       case GREATER_OR_EQUAL:
6648         refine_no_check(lhs >= rhs);
6649         break;
6650       default:
6651         // We already dealt with the other cases.
6652         PPL_UNREACHABLE;
6653         break;
6654       }
6655     }
6656     else {
6657       // Some variables in `lhs' also occur in `rhs'.
6658 
6659 #if 1 // Simplified computation (see the TODO note below).
6660 
6661       for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
6662         dimension_type lhs_vars_i = lhs_vars[i].id();
6663         forget_all_octagonal_constraints(lhs_vars_i);
6664       }
6665 
6666 #else // Currently unnecessarily complex computation.
6667 
6668       // More accurate computation that is worth doing only if
6669       // the following TODO note is accurately dealt with.
6670 
6671       // To ease the computation, we add an additional dimension.
6672       const Variable new_var(space_dim);
6673       add_space_dimensions_and_embed(1);
6674       // Constrain the new dimension to be equal to `rhs'.
6675       // NOTE: calling affine_image() instead of refine_no_check()
6676       // ensures some approximation is tried even when the constraint
6677       // is not an octagonal constraint.
6678       affine_image(new_var, rhs);
6679       // Existentially quantify all variables in the lhs.
6680       // NOTE: enforce strong closure for precision.
6681       strong_closure_assign();
6682       PPL_ASSERT(!marked_empty());
6683       for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
6684         dimension_type lhs_vars_i = lhs_vars[i].id();
6685         forget_all_octagonal_constraints(lhs_vars_i);
6686       }
6687       // Constrain the new dimension so that it is related to
6688       // the left hand side as dictated by `relsym'.
6689       // TODO: each one of the following constraints is definitely NOT
6690       // an octagonal difference (since it has 3 variables at least).
6691       // Thus, the method refine_no_check() will simply ignore it.
6692       // Should we compute approximations for this constraint?
6693       switch (relsym) {
6694       case LESS_OR_EQUAL:
6695         refine_no_check(lhs <= new_var);
6696         break;
6697       case EQUAL:
6698         refine_no_check(lhs == new_var);
6699         break;
6700       case GREATER_OR_EQUAL:
6701         refine_no_check(lhs >= new_var);
6702         break;
6703       default:
6704         // We already dealt with the other cases.
6705         PPL_UNREACHABLE;
6706         break;
6707       }
6708       // Remove the temporarily added dimension.
6709       remove_higher_space_dimensions(space_dim-1);
6710 #endif // Currently unnecessarily complex computation.
6711     }
6712   }
6713 
6714   PPL_ASSERT(OK());
6715 }
6716 
6717 template <typename T>
6718 void
bounded_affine_image(const Variable var,const Linear_Expression & lb_expr,const Linear_Expression & ub_expr,Coefficient_traits::const_reference denominator)6719 Octagonal_Shape<T>::bounded_affine_image(const Variable var,
6720                                          const Linear_Expression& lb_expr,
6721                                          const Linear_Expression& ub_expr,
6722                                          Coefficient_traits::const_reference
6723                                          denominator) {
6724   // The denominator cannot be zero.
6725   if (denominator == 0) {
6726     throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0");
6727   }
6728 
6729   // `var' should be one of the dimensions of the octagon.
6730   const dimension_type var_id = var.id();
6731   if (space_dim < var_id + 1) {
6732     throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
6733                                  var_id + 1);
6734   }
6735 
6736   // The dimension of `lb_expr' and `ub_expr' should not be
6737   // greater than the dimension of `*this'.
6738   const dimension_type lb_space_dim = lb_expr.space_dimension();
6739   if (space_dim < lb_space_dim) {
6740     throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
6741                                  "lb", lb_expr);
6742   }
6743   const dimension_type ub_space_dim = ub_expr.space_dimension();
6744   if (space_dim < ub_space_dim) {
6745     throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
6746                                  "ub", ub_expr);
6747   }
6748 
6749   strong_closure_assign();
6750   // The image of an empty octagon is empty too.
6751   if (marked_empty()) {
6752     return;
6753   }
6754 
6755   // Number of non-zero coefficients in `lb_expr': will be set to
6756   // 0, 1, or 2, the latter value meaning any value greater than 1.
6757   dimension_type t = 0;
6758   // Variable-index of the last non-zero coefficient in `lb_expr', if any.
6759   dimension_type w_id = lb_expr.last_nonzero();
6760 
6761   if (w_id != 0) {
6762     ++t;
6763     if (!lb_expr.all_zeroes(1, w_id)) {
6764       ++t;
6765     }
6766     --w_id;
6767   }
6768 
6769   typedef typename OR_Matrix<N>::row_iterator row_iterator;
6770   typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
6771   typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
6772 
6773   const row_iterator m_begin = matrix.row_begin();
6774   const dimension_type n_var = 2*var_id;
6775   const Coefficient& b = lb_expr.inhomogeneous_term();
6776   PPL_DIRTY_TEMP_COEFFICIENT(minus_denom);
6777   neg_assign_r(minus_denom, denominator, ROUND_NOT_NEEDED);
6778 
6779   // `w' is the variable with index `w_id'.
6780   // Now we know the form of `lb_expr':
6781   // - If t == 0, then lb_expr == b, with `b' a constant;
6782   // - If t == 1, then lb_expr == a*w + b, where `w' can be `v' or another
6783   //   variable; in this second case we have to check whether `a' is
6784   //   equal to `denominator' or `-denominator', since otherwise we have
6785   //   to fall back on the general form;
6786   // - If t == 2, the `lb_expr' is of the general form.
6787 
6788   if (t == 0) {
6789     // Case 1: lb_expr == b.
6790     generalized_affine_image(var,
6791                              LESS_OR_EQUAL,
6792                              ub_expr,
6793                              denominator);
6794     PPL_DIRTY_TEMP_COEFFICIENT(two_b);
6795     two_b = 2*b;
6796     // Add the constraint `var >= b/denominator'.
6797     add_octagonal_constraint(n_var, n_var + 1, two_b, minus_denom);
6798     PPL_ASSERT(OK());
6799     return;
6800   }
6801 
6802   if (t == 1) {
6803     // The one and only non-zero homogeneous coefficient in `lb_expr'.
6804     const Coefficient& w_coeff = lb_expr.coefficient(Variable(w_id));
6805     if (w_coeff == denominator || w_coeff == minus_denom) {
6806       // Case 2: lb_expr = w_coeff*w + b, with w_coeff = +/- denominator.
6807       if (w_id == var_id) {
6808         // Here `var' occurs in `lb_expr'.
6809         // To ease the computation, we add an additional dimension.
6810         const Variable new_var(space_dim);
6811         add_space_dimensions_and_embed(1);
6812         // Constrain the new dimension to be equal to `lb_expr'.
6813         // Here `lb_expr' is of the form: +/- denominator * v + b.
6814         affine_image(new_var, lb_expr, denominator);
6815         // Enforce the strong closure for precision.
6816         strong_closure_assign();
6817         PPL_ASSERT(!marked_empty());
6818         // Apply the affine upper bound.
6819         generalized_affine_image(var,
6820                                  LESS_OR_EQUAL,
6821                                  ub_expr,
6822                                  denominator);
6823         // Now apply the affine lower bound, as recorded in `new_var'
6824         refine_no_check(var >= new_var);
6825         // Remove the temporarily added dimension.
6826         remove_higher_space_dimensions(space_dim-1);
6827         return;
6828       }
6829       else {
6830         // Apply the affine upper bound.
6831         generalized_affine_image(var,
6832                                  LESS_OR_EQUAL,
6833                                  ub_expr,
6834                                  denominator);
6835         // Here `w != var', so that `lb_expr' is of the form
6836         // +/-denominator * w + b.
6837         const dimension_type n_w = 2*w_id;
6838         // Add the new constraint `var - w >= b/denominator'.
6839         if (w_coeff == denominator) {
6840           if (var_id < w_id) {
6841             add_octagonal_constraint(n_w + 1, n_var + 1, b, minus_denom);
6842           }
6843           else {
6844             add_octagonal_constraint(n_var, n_w, b, minus_denom);
6845           }
6846         }
6847         else {
6848           // Add the new constraint `var + w >= b/denominator'.
6849           if (var_id < w_id) {
6850             add_octagonal_constraint(n_w, n_var + 1, b, minus_denom);
6851           }
6852           else {
6853             add_octagonal_constraint(n_var, n_w + 1, b, minus_denom);
6854           }
6855         }
6856         PPL_ASSERT(OK());
6857         return;
6858       }
6859     }
6860   }
6861 
6862   // General case.
6863   // Either t == 2, so that
6864   // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2,
6865   // or t == 1, expr == a*w + b, but a <> +/- denominator.
6866   // We will remove all the constraints on `var' and add back
6867   // constraints providing upper and lower bounds for `var'.
6868 
6869   // Compute upper approximations for `expr' and `-expr'
6870   // into `pos_sum' and `neg_sum', respectively, taking into account
6871   // the sign of `denominator'.
6872   // Note: approximating `-expr' from above and then negating the
6873   // result is the same as approximating `expr' from below.
6874   const bool is_sc = (denominator > 0);
6875   PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
6876   neg_assign_r(minus_b, b, ROUND_NOT_NEEDED);
6877 
6878   const Coefficient& minus_sc_b = is_sc ? minus_b : b;
6879   const Coefficient& sc_denom = is_sc ? denominator : minus_denom;
6880   const Coefficient& minus_sc_denom = is_sc ? minus_denom : denominator;
6881   // NOTE: here, for optimization purposes, `minus_expr' is only assigned
6882   // when `denominator' is negative. Do not use it unless you are sure
6883   // it has been correctly assigned.
6884   Linear_Expression minus_expr;
6885   if (!is_sc) {
6886     minus_expr = -lb_expr;
6887   }
6888   const Linear_Expression& sc_expr = is_sc ? lb_expr : minus_expr;
6889 
6890   PPL_DIRTY_TEMP(N, neg_sum);
6891   // Indices of the variables that are unbounded in `this->matrix'.
6892   PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
6893   // Number of unbounded variables found.
6894   dimension_type neg_pinf_count = 0;
6895 
6896   // Approximate the inhomogeneous term.
6897   assign_r(neg_sum, minus_sc_b, ROUND_UP);
6898 
6899   // Approximate the homogeneous part of `sc_expr'.
6900   PPL_DIRTY_TEMP(N, coeff_i);
6901   PPL_DIRTY_TEMP(N, minus_coeff_i);
6902   PPL_DIRTY_TEMP(N, half);
6903   PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
6904   // Note: indices above `w' can be disregarded, as they all have
6905   // a zero coefficient in `sc_expr'.
6906   for (Row_iterator m_iter = m_begin, m_iter_end = m_begin + (2 * w_id + 2);
6907        m_iter != m_iter_end; ) {
6908     const dimension_type n_i = m_iter.index();
6909     const dimension_type id = n_i/2;
6910     Row_reference m_i = *m_iter;
6911     ++m_iter;
6912     Row_reference m_ci = *m_iter;
6913     ++m_iter;
6914     const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
6915     const int sign_i = sgn(sc_i);
6916     if (sign_i > 0) {
6917       assign_r(coeff_i, sc_i, ROUND_UP);
6918       // Approximating `-sc_expr'.
6919       if (neg_pinf_count <= 1) {
6920         const N& double_up_approx_minus_i = m_i[n_i + 1];
6921         if (!is_plus_infinity(double_up_approx_minus_i)) {
6922           // Let half = double_up_approx_minus_i / 2.
6923           div_2exp_assign_r(half, double_up_approx_minus_i, 1, ROUND_UP);
6924           add_mul_assign_r(neg_sum, coeff_i, half, ROUND_UP);
6925         }
6926         else {
6927           ++neg_pinf_count;
6928           neg_pinf_index = id;
6929         }
6930       }
6931     }
6932     else if (sign_i < 0) {
6933       neg_assign_r(minus_sc_i, sc_i, ROUND_NOT_NEEDED);
6934       assign_r(minus_coeff_i, minus_sc_i, ROUND_UP);
6935       // Approximating `-sc_expr'.
6936       if (neg_pinf_count <= 1) {
6937         const N& double_up_approx_i = m_ci[n_i];
6938         if (!is_plus_infinity(double_up_approx_i)) {
6939           // Let half = double_up_approx_i / 2.
6940           div_2exp_assign_r(half, double_up_approx_i, 1, ROUND_UP);
6941           add_mul_assign_r(neg_sum, minus_coeff_i, half, ROUND_UP);
6942         }
6943         else {
6944           ++neg_pinf_count;
6945           neg_pinf_index = id;
6946         }
6947       }
6948     }
6949   }
6950 
6951   // Apply the affine upper bound.
6952   generalized_affine_image(var,
6953                            LESS_OR_EQUAL,
6954                            ub_expr,
6955                            denominator);
6956 
6957   // Return immediately if no approximation could be computed.
6958   if (neg_pinf_count > 1) {
6959     return;
6960   }
6961 
6962   // In the following, strong closure will be definitely lost.
6963   reset_strongly_closed();
6964 
6965   // Exploit the lower approximation, if possible.
6966   if (neg_pinf_count <= 1) {
6967     // Compute quotient (if needed).
6968     if (sc_denom != 1) {
6969       // Before computing quotients, the denominator should be approximated
6970       // towards zero. Since `sc_denom' is known to be positive, this amounts to
6971       // rounding downwards, which is achieved as usual by rounding upwards
6972       // `minus_sc_denom' and negating again the result.
6973       PPL_DIRTY_TEMP(N, down_sc_denom);
6974       assign_r(down_sc_denom, minus_sc_denom, ROUND_UP);
6975       neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP);
6976       div_assign_r(neg_sum, neg_sum, down_sc_denom, ROUND_UP);
6977     }
6978     // Add the lower bound constraint, if meaningful.
6979     if (neg_pinf_count == 0) {
6980       // Add the constraint `v >= -neg_sum', i.e., `-v <= neg_sum'.
6981       PPL_DIRTY_TEMP(N, double_neg_sum);
6982       mul_2exp_assign_r(double_neg_sum, neg_sum, 1, ROUND_UP);
6983       matrix[n_var][n_var + 1] = double_neg_sum;
6984       // Deduce constraints of the form `-v +/- u', where `u != v'.
6985       deduce_minus_v_pm_u_bounds(var_id, w_id, sc_expr, sc_denom, neg_sum);
6986     }
6987     else
6988       // Here `neg_pinf_count == 1'.
6989       if (neg_pinf_index != var_id) {
6990         const Coefficient& npi = sc_expr.coefficient(Variable(neg_pinf_index));
6991         if (npi == sc_denom) {
6992           // Add the constraint `v - neg_pinf_index >= -neg_sum',
6993           // i.e., `neg_pinf_index - v <= neg_sum'.
6994           if (neg_pinf_index < var_id) {
6995             matrix[n_var][2*neg_pinf_index] = neg_sum;
6996           }
6997           else {
6998             matrix[2*neg_pinf_index + 1][n_var + 1] = neg_sum;
6999           }
7000         }
7001         else {
7002           if (npi == minus_sc_denom) {
7003             // Add the constraint `v + neg_pinf_index >= -neg_sum',
7004             // i.e., `-neg_pinf_index - v <= neg_sum'.
7005             if (neg_pinf_index < var_id) {
7006               matrix[n_var][2*neg_pinf_index + 1] = neg_sum;
7007             }
7008             else {
7009               matrix[2*neg_pinf_index][n_var + 1] = neg_sum;
7010             }
7011           }
7012         }
7013       }
7014   }
7015 
7016   PPL_ASSERT(OK());
7017 }
7018 
7019 
7020 template <typename T>
7021 void
7022 Octagonal_Shape<T>
generalized_affine_preimage(const Variable var,const Relation_Symbol relsym,const Linear_Expression & expr,Coefficient_traits::const_reference denominator)7023 ::generalized_affine_preimage(const Variable var,
7024                               const Relation_Symbol relsym,
7025                               const Linear_Expression& expr,
7026                               Coefficient_traits::const_reference
7027                               denominator) {
7028   // The denominator cannot be zero.
7029   if (denominator == 0) {
7030     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)", "d == 0");
7031   }
7032 
7033   // Dimension-compatibility checks.
7034   // The dimension of `expr' should not be greater than the dimension
7035   // of `*this'.
7036   const dimension_type expr_space_dim = expr.space_dimension();
7037   if (space_dim < expr_space_dim) {
7038     throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
7039                                  "e", expr);
7040   }
7041 
7042   // `var' should be one of the dimensions of the octagon.
7043   const dimension_type var_id = var.id();
7044   if (space_dim < var_id + 1) {
7045     throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
7046                                  var_id + 1);
7047   }
7048 
7049   // The relation symbol cannot be a strict relation symbol.
7050   if (relsym == LESS_THAN || relsym == GREATER_THAN) {
7051     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
7052                            "r is a strict relation symbol");
7053   }
7054   // The relation symbol cannot be a disequality.
7055   if (relsym == NOT_EQUAL) {
7056     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
7057                            "r is the disequality relation symbol");
7058   }
7059 
7060   if (relsym == EQUAL) {
7061     // The relation symbol is "=":
7062     // this is just an affine preimage computation.
7063     affine_preimage(var, expr, denominator);
7064     return;
7065   }
7066 
7067   // The image of an empty octagon is empty too.
7068   strong_closure_assign();
7069   if (marked_empty()) {
7070     return;
7071   }
7072 
7073   // Check whether the preimage of this affine relation can be easily
7074   // computed as the image of its inverse relation.
7075   const Coefficient& expr_v = expr.coefficient(var);
7076   if (expr_v != 0) {
7077     const Relation_Symbol reversed_relsym = (relsym == LESS_OR_EQUAL)
7078       ? GREATER_OR_EQUAL : LESS_OR_EQUAL;
7079     const Linear_Expression inverse
7080       = expr - (expr_v + denominator)*var;
7081     PPL_DIRTY_TEMP_COEFFICIENT(inverse_denom);
7082     neg_assign(inverse_denom, expr_v);
7083     const Relation_Symbol inverse_relsym
7084       = (sgn(denominator) == sgn(inverse_denom)) ? relsym : reversed_relsym;
7085     generalized_affine_image(var, inverse_relsym, inverse, inverse_denom);
7086     return;
7087   }
7088 
7089   // Here `var_coefficient == 0', so that the preimage cannot
7090   // be easily computed by inverting the affine relation.
7091   // Shrink the Octagonal_Shape by adding the constraint induced
7092   // by the affine relation.
7093   refine(var, relsym, expr, denominator);
7094 
7095   // If the shrunk OS is empty, its preimage is empty too; ...
7096   if (is_empty()) {
7097     return;
7098   }
7099   // ...  otherwise, since the relation was not invertible,
7100   // we just forget all constraints on `var'.
7101   forget_all_octagonal_constraints(var_id);
7102   PPL_ASSERT(OK());
7103 }
7104 
7105 template <typename T>
7106 void
7107 Octagonal_Shape<T>
generalized_affine_preimage(const Linear_Expression & lhs,const Relation_Symbol relsym,const Linear_Expression & rhs)7108 ::generalized_affine_preimage(const Linear_Expression& lhs,
7109                               const Relation_Symbol relsym,
7110                               const Linear_Expression& rhs) {
7111   // Dimension-compatibility checks.
7112   // The dimension of `lhs' should not be greater than the dimension
7113   // of `*this'.
7114   dimension_type lhs_space_dim = lhs.space_dimension();
7115   if (space_dim < lhs_space_dim) {
7116     throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
7117                                  "e1", lhs);
7118   }
7119 
7120   // The dimension of `rhs' should not be greater than the dimension
7121   // of `*this'.
7122   const dimension_type rhs_space_dim = rhs.space_dimension();
7123   if (space_dim < rhs_space_dim) {
7124     throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
7125                                  "e2", rhs);
7126   }
7127 
7128   // Strict relation symbols are not admitted for octagons.
7129   if (relsym == LESS_THAN || relsym == GREATER_THAN) {
7130     throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
7131                            "r is a strict relation symbol");
7132   }
7133   // The relation symbol cannot be a disequality.
7134   if (relsym == NOT_EQUAL) {
7135     throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
7136                            "r is the disequality relation symbol");
7137   }
7138   strong_closure_assign();
7139   // The image of an empty octagon is empty.
7140   if (marked_empty()) {
7141     return;
7142   }
7143   // Number of non-zero coefficients in `lhs': will be set to
7144   // 0, 1, or 2, the latter value meaning any value greater than 1.
7145   dimension_type t_lhs = 0;
7146   // Index of the last non-zero coefficient in `lhs', if any.
7147   dimension_type j_lhs = lhs.last_nonzero();
7148 
7149   if (j_lhs != 0) {
7150     ++t_lhs;
7151     if (!lhs.all_zeroes(1, j_lhs)) {
7152       ++t_lhs;
7153     }
7154     --j_lhs;
7155   }
7156 
7157   const Coefficient& b_lhs = lhs.inhomogeneous_term();
7158 
7159   // If all variables have a zero coefficient, then `lhs' is a constant:
7160   // in this case, preimage and image happen to be the same.
7161   if (t_lhs == 0) {
7162     generalized_affine_image(lhs, relsym, rhs);
7163     return;
7164   }
7165 
7166   else if (t_lhs == 1) {
7167     // Here `lhs == a_lhs * v + b_lhs'.
7168     // Independently from the form of `rhs', we can exploit the
7169     // method computing generalized affine preimages for a single variable.
7170     Variable v(j_lhs);
7171     // Compute a sign-corrected relation symbol.
7172     const Coefficient& denom = lhs.coefficient(v);
7173     Relation_Symbol new_relsym = relsym;
7174     if (denom < 0) {
7175       if (relsym == LESS_OR_EQUAL) {
7176         new_relsym = GREATER_OR_EQUAL;
7177       }
7178       else if (relsym == GREATER_OR_EQUAL) {
7179         new_relsym = LESS_OR_EQUAL;
7180       }
7181     }
7182     Linear_Expression expr = rhs - b_lhs;
7183     generalized_affine_preimage(v, new_relsym, expr, denom);
7184   }
7185 
7186   else {
7187     // Here `lhs' is of the general form, having at least two variables.
7188     // Compute the set of variables occurring in `lhs'.
7189     std::vector<Variable> lhs_vars;
7190     for (Linear_Expression::const_iterator i = lhs.begin(), i_end = lhs.end();
7191           i != i_end; ++i) {
7192       lhs_vars.push_back(i.variable());
7193     }
7194 
7195     const dimension_type num_common_dims = std::min(lhs_space_dim, rhs_space_dim);
7196     if (!lhs.have_a_common_variable(rhs, Variable(0), Variable(num_common_dims))) {
7197       // `lhs' and `rhs' variables are disjoint.
7198       // Constrain the left hand side expression so that it is related to
7199       // the right hand side expression as dictated by `relsym'.
7200       // TODO: if the following constraint is NOT an octagonal difference,
7201       // it will be simply ignored. Should we compute approximations for it?
7202       switch (relsym) {
7203       case LESS_OR_EQUAL:
7204         refine_no_check(lhs <= rhs);
7205         break;
7206       case EQUAL:
7207         refine_no_check(lhs == rhs);
7208         break;
7209       case GREATER_OR_EQUAL:
7210         refine_no_check(lhs >= rhs);
7211         break;
7212       default:
7213         // We already dealt with the other cases.
7214         PPL_UNREACHABLE;
7215         break;
7216       }
7217 
7218       // Any image of an empty octagon is empty.
7219       if (is_empty()) {
7220         return;
7221       }
7222       // Existentially quantify all variables in the lhs.
7223       for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
7224         dimension_type lhs_vars_i = lhs_vars[i].id();
7225         forget_all_octagonal_constraints(lhs_vars_i);
7226       }
7227     }
7228     else {
7229       // Some variables in `lhs' also occur in `rhs'.
7230 
7231       // More accurate computation that is worth doing only if
7232       // the following TODO note is accurately dealt with.
7233 
7234       // To ease the computation, we add an additional dimension.
7235       const Variable new_var(space_dim);
7236       add_space_dimensions_and_embed(1);
7237       // Constrain the new dimension to be equal to `rhs'.
7238       // NOTE: calling affine_image() instead of refine_no_check()
7239       // ensures some approximation is tried even when the constraint
7240       // is not an octagonal difference.
7241       affine_image(new_var, lhs);
7242       // Existentially quantify all variables in the lhs.
7243       // NOTE: enforce strong closure for precision.
7244       strong_closure_assign();
7245       PPL_ASSERT(!marked_empty());
7246       for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
7247         dimension_type lhs_vars_i = lhs_vars[i].id();
7248         forget_all_octagonal_constraints(lhs_vars_i);
7249       }
7250       // Constrain the new dimension so that it is related to
7251       // the left hand side as dictated by `relsym'.
7252       // Note: if `rhs == v + b_rhs' or `rhs == -v + b_rhs' or `rhs == b_rhs',
7253       // one of the following constraints will be added, because they
7254       // are octagonal differences.
7255       // Else the following constraints are NOT octagonal differences,
7256       // so the method refine_no_check() will ignore them.
7257       switch (relsym) {
7258       case LESS_OR_EQUAL:
7259         refine_no_check(new_var <= rhs);
7260         break;
7261       case EQUAL:
7262         refine_no_check(new_var == rhs);
7263         break;
7264       case GREATER_OR_EQUAL:
7265         refine_no_check(new_var >= rhs);
7266         break;
7267       default:
7268         // We already dealt with the other cases.
7269         PPL_UNREACHABLE;
7270         break;
7271       }
7272       // Remove the temporarily added dimension.
7273       remove_higher_space_dimensions(space_dim-1);
7274     }
7275   }
7276   PPL_ASSERT(OK());
7277 }
7278 
7279 template <typename T>
7280 void
bounded_affine_preimage(const Variable var,const Linear_Expression & lb_expr,const Linear_Expression & ub_expr,Coefficient_traits::const_reference denominator)7281 Octagonal_Shape<T>::bounded_affine_preimage(const Variable var,
7282                                             const Linear_Expression& lb_expr,
7283                                             const Linear_Expression& ub_expr,
7284                                             Coefficient_traits::const_reference
7285                                             denominator) {
7286   // The denominator cannot be zero.
7287   if (denominator == 0) {
7288     throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
7289   }
7290 
7291   // `var' should be one of the dimensions of the octagon.
7292   const dimension_type var_id = var.id();
7293   if (space_dim < var_id + 1) {
7294     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
7295                                  var_id + 1);
7296   }
7297 
7298   // The dimension of `lb_expr' and `ub_expr' should not be
7299   // greater than the dimension of `*this'.
7300   const dimension_type lb_space_dim = lb_expr.space_dimension();
7301   if (space_dim < lb_space_dim) {
7302     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
7303                                  "lb", lb_expr);
7304   }
7305   const dimension_type ub_space_dim = ub_expr.space_dimension();
7306   if (space_dim < ub_space_dim) {
7307     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
7308                                  "ub", ub_expr);
7309   }
7310 
7311   strong_closure_assign();
7312   // The image of an empty octagon is empty too.
7313   if (marked_empty()) {
7314     return;
7315   }
7316 
7317   if (ub_expr.coefficient(var) == 0) {
7318     refine(var, LESS_OR_EQUAL, ub_expr, denominator);
7319     generalized_affine_preimage(var, GREATER_OR_EQUAL,
7320                                 lb_expr, denominator);
7321     return;
7322   }
7323   if (lb_expr.coefficient(var) == 0) {
7324     refine(var, GREATER_OR_EQUAL, lb_expr, denominator);
7325     generalized_affine_preimage(var, LESS_OR_EQUAL,
7326                                 ub_expr, denominator);
7327     return;
7328   }
7329 
7330   const Coefficient& expr_v = lb_expr.coefficient(var);
7331   // Here `var' occurs in `lb_expr' and `ub_expr'.
7332   // To ease the computation, we add an additional dimension.
7333   const Variable new_var(space_dim);
7334   add_space_dimensions_and_embed(1);
7335   const Linear_Expression lb_inverse
7336     = lb_expr - (expr_v + denominator)*var;
7337   PPL_DIRTY_TEMP_COEFFICIENT(inverse_denom);
7338   neg_assign(inverse_denom, expr_v);
7339   affine_image(new_var, lb_inverse, inverse_denom);
7340   strong_closure_assign();
7341   PPL_ASSERT(!marked_empty());
7342   generalized_affine_preimage(var, LESS_OR_EQUAL,
7343                               ub_expr, denominator);
7344   if (sgn(denominator) == sgn(inverse_denom)) {
7345     refine_no_check(var >= new_var) ;
7346   }
7347   else {
7348     refine_no_check(var <= new_var);
7349   }
7350   // Remove the temporarily added dimension.
7351   remove_higher_space_dimensions(space_dim-1);
7352 }
7353 
7354 template <typename T>
7355 Constraint_System
constraints() const7356 Octagonal_Shape<T>::constraints() const {
7357   Constraint_System cs;
7358   cs.set_space_dimension(space_dim);
7359 
7360   if (space_dim == 0) {
7361     if (marked_empty()) {
7362       cs = Constraint_System::zero_dim_empty();
7363     }
7364     return cs;
7365   }
7366 
7367   if (marked_empty()) {
7368     cs.insert(Constraint::zero_dim_false());
7369     return cs;
7370   }
7371 
7372   typedef typename OR_Matrix<N>::const_row_iterator row_iterator;
7373   typedef typename OR_Matrix<N>::const_row_reference_type row_reference;
7374 
7375   row_iterator m_begin = matrix.row_begin();
7376   row_iterator m_end = matrix.row_end();
7377 
7378   PPL_DIRTY_TEMP_COEFFICIENT(a);
7379   PPL_DIRTY_TEMP_COEFFICIENT(b);
7380 
7381   // Go through all the unary constraints in `matrix'.
7382   for (row_iterator i_iter = m_begin; i_iter != m_end; ) {
7383     const dimension_type i = i_iter.index();
7384     const Variable x(i/2);
7385     const N& c_i_ii = (*i_iter)[i + 1];
7386     ++i_iter;
7387     const N& c_ii_i = (*i_iter)[i];
7388     ++i_iter;
7389     // Go through unary constraints.
7390     if (is_additive_inverse(c_i_ii, c_ii_i)) {
7391       // We have a unary equality constraint.
7392       numer_denom(c_ii_i, b, a);
7393       a *= 2;
7394       cs.insert(a*x == b);
7395     }
7396     else {
7397       // We have 0, 1 or 2 inequality constraints.
7398       if (!is_plus_infinity(c_i_ii)) {
7399         numer_denom(c_i_ii, b, a);
7400         a *= 2;
7401         cs.insert(-a*x <= b);
7402       }
7403       if (!is_plus_infinity(c_ii_i)) {
7404         numer_denom(c_ii_i, b, a);
7405         a *= 2;
7406         cs.insert(a*x <= b);
7407       }
7408     }
7409   }
7410   //  Go through all the binary constraints in `matrix'.
7411   for (row_iterator i_iter = m_begin; i_iter != m_end; ) {
7412     const dimension_type i = i_iter.index();
7413     row_reference r_i = *i_iter;
7414     ++i_iter;
7415     row_reference r_ii = *i_iter;
7416     ++i_iter;
7417     const Variable y(i/2);
7418     for (dimension_type j = 0; j < i; j += 2) {
7419       const N& c_i_j = r_i[j];
7420       const N& c_ii_jj = r_ii[j + 1];
7421       const Variable x(j/2);
7422       if (is_additive_inverse(c_ii_jj, c_i_j)) {
7423         // We have an equality constraint of the form a*x - a*y = b.
7424         numer_denom(c_i_j, b, a);
7425         cs.insert(a*x - a*y == b);
7426       }
7427       else {
7428         // We have 0, 1 or 2 inequality constraints.
7429         if (!is_plus_infinity(c_i_j)) {
7430           numer_denom(c_i_j, b, a);
7431           cs.insert(a*x - a*y <= b);
7432         }
7433         if (!is_plus_infinity(c_ii_jj)) {
7434           numer_denom(c_ii_jj, b, a);
7435           cs.insert(a*y - a*x <= b);
7436         }
7437       }
7438 
7439       const N& c_ii_j = r_ii[j];
7440       const N& c_i_jj = r_i[j + 1];
7441       if (is_additive_inverse(c_i_jj, c_ii_j)) {
7442         // We have an equality constraint of the form a*x + a*y = b.
7443         numer_denom(c_ii_j, b, a);
7444         cs.insert(a*x + a*y == b);
7445       }
7446       else {
7447         // We have 0, 1 or 2 inequality constraints.
7448         if (!is_plus_infinity(c_i_jj)) {
7449           numer_denom(c_i_jj, b, a);
7450           cs.insert(-a*x - a*y <= b);
7451         }
7452         if (!is_plus_infinity(c_ii_j)) {
7453           numer_denom(c_ii_j, b, a);
7454           cs.insert(a*x + a*y <= b);
7455         }
7456       }
7457     }
7458   }
7459   return cs;
7460 }
7461 
7462 template <typename T>
7463 void
expand_space_dimension(Variable var,dimension_type m)7464 Octagonal_Shape<T>::expand_space_dimension(Variable var, dimension_type m) {
7465   // `var' should be one of the dimensions of the vector space.
7466   const dimension_type var_id = var.id();
7467   if (var_id + 1 > space_dim) {
7468     throw_dimension_incompatible("expand_space_dimension(v, m)", var_id + 1);
7469   }
7470 
7471   // The space dimension of the resulting octagon should not
7472   // overflow the maximum allowed space dimension.
7473   if (m > max_space_dimension() - space_dim) {
7474     throw_invalid_argument("expand_dimension(v, m)",
7475                            "adding m new space dimensions exceeds "
7476                            "the maximum allowed space dimension");
7477   }
7478   // Nothing to do, if no dimensions must be added.
7479   if (m == 0) {
7480     return;
7481   }
7482   // Keep track of the dimension before adding the new ones.
7483   const dimension_type old_num_rows = matrix.num_rows();
7484 
7485   // Add the required new dimensions.
7486   add_space_dimensions_and_embed(m);
7487 
7488   // For each constraints involving variable `var', we add a
7489   // similar constraint with the new variable substituted for
7490   // variable `var'.
7491   typedef typename OR_Matrix<N>::row_iterator row_iterator;
7492   typedef typename OR_Matrix<N>::row_reference_type row_reference;
7493   typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
7494   typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
7495 
7496   const row_iterator m_begin = matrix.row_begin();
7497   const row_iterator m_end = matrix.row_end();
7498   const dimension_type n_var = 2*var_id;
7499   Row_iterator v_iter = m_begin + n_var;
7500   Row_reference m_v = *v_iter;
7501   Row_reference m_cv = *(v_iter + 1);
7502 
7503   for (row_iterator i_iter = m_begin + old_num_rows; i_iter != m_end;
7504        i_iter += 2) {
7505     row_reference m_i = *i_iter;
7506     row_reference m_ci = *(i_iter + 1);
7507     const dimension_type i = i_iter.index();
7508     const dimension_type ci = i + 1;
7509     m_i[ci] = m_v[n_var + 1];
7510     m_ci[i] = m_cv[n_var];
7511     for (dimension_type j = 0; j < n_var; ++j) {
7512       m_i[j] = m_v[j];
7513       m_ci[j] = m_cv[j];
7514     }
7515     for (dimension_type j = n_var + 2; j < old_num_rows; ++j) {
7516       row_iterator j_iter = m_begin + j;
7517       row_reference m_cj = (j % 2 != 0) ? *(j_iter-1) : *(j_iter + 1);
7518       m_i[j] = m_cj[n_var + 1];
7519       m_ci[j] = m_cj[n_var];
7520     }
7521   }
7522   // In general, adding a constraint does not preserve the strong closure
7523   // of the octagon.
7524   if (marked_strongly_closed()) {
7525     reset_strongly_closed();
7526   }
7527   PPL_ASSERT(OK());
7528 }
7529 
7530 template <typename T>
7531 void
fold_space_dimensions(const Variables_Set & vars,Variable dest)7532 Octagonal_Shape<T>::fold_space_dimensions(const Variables_Set& vars,
7533                                           Variable dest) {
7534   // `dest' should be one of the dimensions of the octagon.
7535   if (dest.space_dimension() > space_dim) {
7536     throw_dimension_incompatible("fold_space_dimensions(vs, v)", "v", dest);
7537   }
7538   // The folding of no dimensions is a no-op.
7539   if (vars.empty()) {
7540     return;
7541   }
7542   // All variables in `vars' should be dimensions of the octagon.
7543   if (vars.space_dimension() > space_dim) {
7544     throw_dimension_incompatible("fold_space_dimensions(vs, v)",
7545                                  vars.space_dimension());
7546   }
7547 
7548   // Moreover, `dest.id()' should not occur in `vars'.
7549   if (vars.find(dest.id()) != vars.end()) {
7550     throw_invalid_argument("fold_space_dimensions(vs, v)",
7551                            "v should not occur in vs");
7552   }
7553 
7554   // Recompute the elements of the row and the column corresponding
7555   // to variable `dest' by taking the join of their value with the
7556   // value of the corresponding elements in the row and column of the
7557   // variable `vars'.
7558   typedef typename OR_Matrix<N>::row_iterator row_iterator;
7559   typedef typename OR_Matrix<N>::row_reference_type row_reference;
7560 
7561   const row_iterator m_begin = matrix.row_begin();
7562 
7563   strong_closure_assign();
7564   const dimension_type n_rows = matrix.num_rows();
7565   const dimension_type n_dest = 2*dest.id();
7566   row_iterator v_iter = m_begin + n_dest;
7567   row_reference m_v = *v_iter;
7568   row_reference m_cv = *(v_iter + 1);
7569   for (Variables_Set::const_iterator i = vars.begin(),
7570          vs_end = vars.end(); i != vs_end; ++i) {
7571     const dimension_type tbf_id = *i;
7572     const dimension_type tbf_var = 2*tbf_id;
7573     row_iterator tbf_iter = m_begin + tbf_var;
7574     row_reference m_tbf = *tbf_iter;
7575     row_reference m_ctbf = *(tbf_iter + 1);
7576     max_assign(m_v[n_dest + 1], m_tbf[tbf_var + 1]);
7577     max_assign(m_cv[n_dest], m_ctbf[tbf_var]);
7578 
7579     const dimension_type min_id = std::min(n_dest, tbf_var);
7580     const dimension_type max_id = std::max(n_dest, tbf_var);
7581 
7582     using namespace Implementation::Octagonal_Shapes;
7583     for (dimension_type j = 0; j < min_id; ++j) {
7584       const dimension_type cj = coherent_index(j);
7585       max_assign(m_v[j], m_tbf[j]);
7586       max_assign(m_cv[j], m_ctbf[j]);
7587       max_assign(m_cv[cj], m_ctbf[cj]);
7588       max_assign(m_v[cj], m_tbf[cj]);
7589     }
7590     for (dimension_type j = min_id + 2; j < max_id; ++j) {
7591       const dimension_type cj = coherent_index(j);
7592       row_iterator j_iter = m_begin + j;
7593       row_reference m_j = *j_iter;
7594       row_reference m_cj = (j % 2 != 0) ? *(j_iter-1) : *(j_iter + 1);
7595       if (n_dest == min_id) {
7596         max_assign(m_cj[n_dest + 1], m_tbf[j]);
7597         max_assign(m_cj[n_dest], m_ctbf[j]);
7598         max_assign(m_j[n_dest], m_ctbf[cj]);
7599         max_assign(m_j[n_dest + 1], m_tbf[cj]);
7600       }
7601       else {
7602         max_assign(m_v[j], m_cj[tbf_var + 1]);
7603         max_assign(m_cv[j], m_cj[tbf_var]);
7604         max_assign(m_cv[cj], m_j[tbf_var]);
7605         max_assign(m_v[cj], m_j[tbf_var + 1]);
7606       }
7607     }
7608     for (dimension_type j = max_id + 2; j < n_rows; ++j) {
7609       row_iterator j_iter = m_begin + j;
7610       row_reference m_j = *j_iter;
7611       row_reference m_cj = (j % 2 != 0) ? *(j_iter-1) : *(j_iter + 1);
7612       max_assign(m_cj[n_dest + 1], m_cj[tbf_var + 1]);
7613       max_assign(m_cj[n_dest], m_cj[tbf_var]);
7614       max_assign(m_j[n_dest], m_j[tbf_var]);
7615       max_assign(m_j[n_dest + 1], m_j[tbf_var + 1]);
7616     }
7617   }
7618   remove_space_dimensions(vars);
7619 }
7620 
7621 template <typename T>
7622 bool
upper_bound_assign_if_exact(const Octagonal_Shape & y)7623 Octagonal_Shape<T>::upper_bound_assign_if_exact(const Octagonal_Shape& y) {
7624   // FIXME, CHECKME: what about inexact computations?
7625 
7626   // Declare a const reference to *this (to avoid accidental modifications).
7627   const Octagonal_Shape& x = *this;
7628   const dimension_type x_space_dim = x.space_dimension();
7629 
7630   if (x_space_dim != y.space_dimension()) {
7631     throw_dimension_incompatible("upper_bound_assign_if_exact(y)", y);
7632   }
7633 
7634   // The zero-dim case is trivial.
7635   if (x_space_dim == 0) {
7636     upper_bound_assign(y);
7637     return true;
7638   }
7639   // If `x' or `y' is (known to be) empty, the upper bound is exact.
7640   if (x.marked_empty()) {
7641     *this = y;
7642     return true;
7643   }
7644   else if (y.is_empty()) {
7645     return true;
7646   }
7647   else if (x.is_empty()) {
7648     *this = y;
7649     return true;
7650   }
7651 
7652   // Here both `x' and `y' are known to be non-empty.
7653   PPL_ASSERT(x.marked_strongly_closed());
7654   PPL_ASSERT(y.marked_strongly_closed());
7655   // Pre-compute the upper bound of `x' and `y'.
7656   Octagonal_Shape<T> ub(x);
7657   ub.upper_bound_assign(y);
7658 
7659   // Compute redundancy information for x and y.
7660   // TODO: provide a nicer data structure for redundancy.
7661   std::vector<Bit_Row> x_non_red;
7662   x.non_redundant_matrix_entries(x_non_red);
7663   std::vector<Bit_Row> y_non_red;
7664   y.non_redundant_matrix_entries(y_non_red);
7665 
7666   PPL_DIRTY_TEMP(N, lhs);
7667   PPL_DIRTY_TEMP(N, lhs_copy);
7668   PPL_DIRTY_TEMP(N, rhs);
7669   PPL_DIRTY_TEMP(N, temp_zero);
7670   assign_r(temp_zero, 0, ROUND_NOT_NEEDED);
7671 
7672   typedef typename OR_Matrix<N>::const_row_iterator row_iterator;
7673   typedef typename OR_Matrix<N>::const_row_reference_type row_reference;
7674   const dimension_type n_rows = x.matrix.num_rows();
7675   const row_iterator x_m_begin = x.matrix.row_begin();
7676   const row_iterator y_m_begin = y.matrix.row_begin();
7677   const row_iterator ub_m_begin = ub.matrix.row_begin();
7678 
7679   for (dimension_type i = n_rows; i-- > 0; ) {
7680     const Bit_Row& x_non_red_i = x_non_red[i];
7681     using namespace Implementation::Octagonal_Shapes;
7682     const dimension_type ci = coherent_index(i);
7683     const dimension_type row_size_i = OR_Matrix<N>::row_size(i);
7684     row_reference x_i = *(x_m_begin + i);
7685     row_reference y_i = *(y_m_begin + i);
7686     row_reference ub_i = *(ub_m_begin + i);
7687     const N& ub_i_ci = ub_i[ci];
7688     for (dimension_type j = row_size_i; j-- > 0; ) {
7689       // Check redundancy of x_i_j.
7690       if (!x_non_red_i[j]) {
7691         continue;
7692       }
7693       const N& x_i_j = x_i[j];
7694       // Check 1st condition in BHZ09 theorem.
7695       if (x_i_j >= y_i[j]) {
7696         continue;
7697       }
7698 
7699       const dimension_type cj = coherent_index(j);
7700       const dimension_type row_size_cj = OR_Matrix<N>::row_size(cj);
7701       row_reference ub_cj = *(ub_m_begin + cj);
7702       const N& ub_cj_j = ub_cj[j];
7703       for (dimension_type k = 0; k < n_rows; ++k) {
7704         const Bit_Row& y_non_red_k = y_non_red[k];
7705         const dimension_type ck = coherent_index(k);
7706         const dimension_type row_size_k = OR_Matrix<N>::row_size(k);
7707         row_reference x_k = *(x_m_begin + k);
7708         row_reference y_k = *(y_m_begin + k);
7709         row_reference ub_k = *(ub_m_begin + k);
7710         const N& ub_k_ck = ub_k[ck];
7711         // Be careful: for each index h, the diagonal element m[h][h]
7712         // is (by convention) +infty in our implementation; however,
7713         // BHZ09 theorem assumes that it is equal to 0.
7714         const N& ub_k_j
7715           = (k == j)
7716           ? temp_zero
7717           : ((j < row_size_k) ? ub_k[j] : ub_cj[ck]);
7718         const N& ub_i_ck
7719           = (i == ck)
7720           ? temp_zero
7721           : ((ck < row_size_i) ? ub_i[ck] : ub_k[ci]);
7722 
7723         for (dimension_type ell = row_size_k; ell-- > 0; ) {
7724           // Check redundancy of y_k_ell.
7725           if (!y_non_red_k[ell]) {
7726             continue;
7727           }
7728           const N& y_k_ell = y_k[ell];
7729           // Check 2nd condition in BHZ09 theorem.
7730           if (y_k_ell >= x_k[ell]) {
7731             continue;
7732           }
7733           const dimension_type cell = coherent_index(ell);
7734           row_reference ub_cell = *(ub_m_begin + cell);
7735           const N& ub_i_ell
7736             = (i == ell)
7737             ? temp_zero
7738             : ((ell < row_size_i) ? ub_i[ell] : ub_cell[ci]);
7739           const N& ub_cj_ell
7740             = (cj == ell)
7741             ? temp_zero
7742             : ((ell < row_size_cj) ? ub_cj[ell] : ub_cell[j]);
7743           // Check 3rd condition in BHZ09 theorem.
7744           add_assign_r(lhs, x_i_j, y_k_ell, ROUND_UP);
7745           add_assign_r(rhs, ub_i_ell, ub_k_j, ROUND_UP);
7746           if (lhs >= rhs) {
7747             continue;
7748           }
7749           // Check 4th condition in BHZ09 theorem.
7750           add_assign_r(rhs, ub_i_ck, ub_cj_ell, ROUND_UP);
7751           if (lhs >= rhs) {
7752             continue;
7753           }
7754           // Check 5th condition in BHZ09 theorem.
7755           assign_r(lhs_copy, lhs, ROUND_NOT_NEEDED);
7756           add_assign_r(lhs, lhs_copy, x_i_j, ROUND_UP);
7757           add_assign_r(rhs, ub_i_ell, ub_i_ck, ROUND_UP);
7758           add_assign_r(rhs, rhs, ub_cj_j, ROUND_UP);
7759           if (lhs >= rhs) {
7760             continue;
7761           }
7762           // Check 6th condition in BHZ09 theorem.
7763           add_assign_r(rhs, ub_k_j, ub_cj_ell, ROUND_UP);
7764           add_assign_r(rhs, rhs, ub_i_ci, ROUND_UP);
7765           if (lhs >= rhs) {
7766             continue;
7767           }
7768           // Check 7th condition of BHZ09 theorem.
7769           add_assign_r(lhs, lhs_copy, y_k_ell, ROUND_UP);
7770           add_assign_r(rhs, ub_i_ell, ub_cj_ell, ROUND_UP);
7771           add_assign_r(rhs, rhs, ub_k_ck, ROUND_UP);
7772           if (lhs >= rhs) {
7773             continue;
7774           }
7775           // Check 8th (last) condition in BHZ09 theorem.
7776           add_assign_r(rhs, ub_k_j, ub_i_ck, ROUND_UP);
7777           add_assign_r(rhs, rhs, ub_cell[ell], ROUND_UP);
7778           if (lhs < rhs) {
7779             // All 8 conditions are satisfied:
7780             // upper bound is not exact.
7781             return false;
7782           }
7783         }
7784       }
7785     }
7786   }
7787 
7788   // The upper bound of x and y is indeed exact.
7789   m_swap(ub);
7790   PPL_ASSERT(OK());
7791   return true;
7792 }
7793 
7794 template <typename T>
7795 bool
7796 Octagonal_Shape<T>
integer_upper_bound_assign_if_exact(const Octagonal_Shape & y)7797 ::integer_upper_bound_assign_if_exact(const Octagonal_Shape& y) {
7798   PPL_COMPILE_TIME_CHECK(std::numeric_limits<T>::is_integer,
7799                          "Octagonal_Shape<T>::"
7800                          "integer_upper_bound_assign_if_exact(y):"
7801                          " T in not an integer datatype.");
7802   // Declare a const reference to *this (to avoid accidental modifications).
7803   const Octagonal_Shape& x = *this;
7804   const dimension_type x_space_dim = x.space_dimension();
7805 
7806   if (x_space_dim != y.space_dimension()) {
7807     throw_dimension_incompatible("integer_upper_bound_assign_if_exact(y)", y);
7808   }
7809   // The zero-dim case is trivial.
7810   if (x_space_dim == 0) {
7811     upper_bound_assign(y);
7812     return true;
7813   }
7814 
7815   // If `x' or `y' is (known to) contain no integral point,
7816   // then the integer upper bound can be computed exactly by tight closure.
7817   if (x.marked_empty()) {
7818     *this = y;
7819     tight_closure_assign();
7820     return true;
7821   }
7822   else if (y.marked_empty()) {
7823     tight_closure_assign();
7824     return true;
7825   }
7826   else if (x.is_empty() || x.tight_coherence_would_make_empty()) {
7827     *this = y;
7828     tight_closure_assign();
7829     return true;
7830   }
7831   else if (y.is_empty() || y.tight_coherence_would_make_empty()) {
7832     tight_closure_assign();
7833     return true;
7834   }
7835 
7836   // Here both `x' and `y' are known to be non-empty (and Z-consistent).
7837   PPL_ASSERT(x.marked_strongly_closed());
7838   PPL_ASSERT(y.marked_strongly_closed());
7839   // Pre-compute the integer upper bound of `x' and `y':
7840   // have to take copies, since tight closure might modify the rational shape.
7841   Octagonal_Shape<T> tx(x);
7842   tx.tight_closure_assign();
7843   Octagonal_Shape<T> ty(y);
7844   ty.tight_closure_assign();
7845   Octagonal_Shape<T> ub(tx);
7846   ub.upper_bound_assign(ty);
7847 
7848   // Compute redundancy information for tx and ty.
7849   // TODO: provide a nicer data structure for redundancy.
7850   // NOTE: there is no need to identify all redundancies, since this is
7851   // an optimization; hence we reuse the strong-reduction helper methods.
7852   std::vector<Bit_Row> tx_non_red;
7853   tx.non_redundant_matrix_entries(tx_non_red);
7854   std::vector<Bit_Row> ty_non_red;
7855   ty.non_redundant_matrix_entries(ty_non_red);
7856 
7857   PPL_DIRTY_TEMP(N, lhs_i_j);
7858   PPL_DIRTY_TEMP(N, lhs_k_ell);
7859   PPL_DIRTY_TEMP(N, lhs);
7860   PPL_DIRTY_TEMP(N, lhs_copy);
7861   PPL_DIRTY_TEMP(N, rhs);
7862   PPL_DIRTY_TEMP(N, temp_zero);
7863   assign_r(temp_zero, 0, ROUND_NOT_NEEDED);
7864   PPL_DIRTY_TEMP(N, temp_one);
7865   assign_r(temp_one, 1, ROUND_NOT_NEEDED);
7866   PPL_DIRTY_TEMP(N, temp_two);
7867   assign_r(temp_two, 2, ROUND_NOT_NEEDED);
7868 
7869   typedef typename OR_Matrix<N>::const_row_iterator row_iterator;
7870   typedef typename OR_Matrix<N>::const_row_reference_type row_reference;
7871   const dimension_type n_rows = tx.matrix.num_rows();
7872   const row_iterator tx_m_begin = tx.matrix.row_begin();
7873   const row_iterator ty_m_begin = ty.matrix.row_begin();
7874   const row_iterator ub_m_begin = ub.matrix.row_begin();
7875 
7876   for (dimension_type i = n_rows; i-- > 0; ) {
7877     const Bit_Row& tx_non_red_i = tx_non_red[i];
7878     using namespace Implementation::Octagonal_Shapes;
7879     const dimension_type ci = coherent_index(i);
7880     const dimension_type row_size_i = OR_Matrix<N>::row_size(i);
7881     row_reference tx_i = *(tx_m_begin + i);
7882     row_reference ty_i = *(ty_m_begin + i);
7883     row_reference ub_i = *(ub_m_begin + i);
7884     const N& ub_i_ci = ub_i[ci];
7885     for (dimension_type j = row_size_i; j-- > 0; ) {
7886       // Check redundancy of tx_i_j.
7887       if (!tx_non_red_i[j]) {
7888         continue;
7889       }
7890       const N& tx_i_j = tx_i[j];
7891       const dimension_type cj = coherent_index(j);
7892       const N& eps_i_j = (i == cj) ? temp_two : temp_one;
7893       // Check condition 1a in BHZ09 Theorem 6.8.
7894       add_assign_r(lhs_i_j, tx_i_j, eps_i_j, ROUND_NOT_NEEDED);
7895       if (lhs_i_j > ty_i[j]) {
7896         continue;
7897       }
7898       const dimension_type row_size_cj = OR_Matrix<N>::row_size(cj);
7899       row_reference ub_cj = *(ub_m_begin + cj);
7900       const N& ub_cj_j = ub_cj[j];
7901       for (dimension_type k = 0; k < n_rows; ++k) {
7902         const Bit_Row& ty_non_red_k = ty_non_red[k];
7903         const dimension_type ck = coherent_index(k);
7904         const dimension_type row_size_k = OR_Matrix<N>::row_size(k);
7905         row_reference tx_k = *(tx_m_begin + k);
7906         row_reference ty_k = *(ty_m_begin + k);
7907         row_reference ub_k = *(ub_m_begin + k);
7908         const N& ub_k_ck = ub_k[ck];
7909         // Be careful: for each index h, the diagonal element m[h][h]
7910         // is (by convention) +infty in our implementation; however,
7911         // BHZ09 theorem assumes that it is equal to 0.
7912         const N& ub_k_j
7913           = (k == j)
7914           ? temp_zero
7915           : ((j < row_size_k) ? ub_k[j] : ub_cj[ck]);
7916         const N& ub_i_ck
7917           = (i == ck)
7918           ? temp_zero
7919           : ((ck < row_size_i) ? ub_i[ck] : ub_k[ci]);
7920 
7921         for (dimension_type ell = row_size_k; ell-- > 0; ) {
7922           // Check redundancy of y_k_ell.
7923           if (!ty_non_red_k[ell]) {
7924             continue;
7925           }
7926           const N& ty_k_ell = ty_k[ell];
7927           const dimension_type cell = coherent_index(ell);
7928           const N& eps_k_ell = (k == cell) ? temp_two : temp_one;
7929           // Check condition 1b in BHZ09 Theorem 6.8.
7930           add_assign_r(lhs_k_ell, ty_k_ell, eps_k_ell, ROUND_NOT_NEEDED);
7931           if (lhs_k_ell > tx_k[ell]) {
7932             continue;
7933           }
7934           row_reference ub_cell = *(ub_m_begin + cell);
7935           const N& ub_i_ell
7936             = (i == ell)
7937             ? temp_zero
7938             : ((ell < row_size_i) ? ub_i[ell] : ub_cell[ci]);
7939           const N& ub_cj_ell
7940             = (cj == ell)
7941             ? temp_zero
7942             : ((ell < row_size_cj) ? ub_cj[ell] : ub_cell[j]);
7943           // Check condition 2a in BHZ09 Theorem 6.8.
7944           add_assign_r(lhs, lhs_i_j, lhs_k_ell, ROUND_NOT_NEEDED);
7945           add_assign_r(rhs, ub_i_ell, ub_k_j, ROUND_NOT_NEEDED);
7946           if (lhs > rhs) {
7947             continue;
7948           }
7949           // Check condition 2b in BHZ09 Theorem 6.8.
7950           add_assign_r(rhs, ub_i_ck, ub_cj_ell, ROUND_NOT_NEEDED);
7951           if (lhs > rhs) {
7952             continue;
7953           }
7954           // Check condition 3a in BHZ09 Theorem 6.8.
7955           assign_r(lhs_copy, lhs, ROUND_NOT_NEEDED);
7956           add_assign_r(lhs, lhs, lhs_i_j, ROUND_NOT_NEEDED);
7957           add_assign_r(rhs, ub_i_ell, ub_i_ck, ROUND_NOT_NEEDED);
7958           add_assign_r(rhs, rhs, ub_cj_j, ROUND_NOT_NEEDED);
7959           if (lhs > rhs) {
7960             continue;
7961           }
7962           // Check condition 3b in BHZ09 Theorem 6.8.
7963           add_assign_r(rhs, ub_k_j, ub_cj_ell, ROUND_NOT_NEEDED);
7964           add_assign_r(rhs, rhs, ub_i_ci, ROUND_NOT_NEEDED);
7965           if (lhs > rhs) {
7966             continue;
7967           }
7968           // Check condition 4a in BHZ09 Theorem 6.8.
7969           add_assign_r(lhs, lhs_copy, lhs_k_ell, ROUND_NOT_NEEDED);
7970           add_assign_r(rhs, ub_i_ell, ub_cj_ell, ROUND_NOT_NEEDED);
7971           add_assign_r(rhs, rhs, ub_k_ck, ROUND_NOT_NEEDED);
7972           if (lhs > rhs) {
7973             continue;
7974           }
7975           // Check condition 4b in BHZ09 Theorem 6.8.
7976           add_assign_r(rhs, ub_k_j, ub_i_ck, ROUND_NOT_NEEDED);
7977           add_assign_r(rhs, rhs, ub_cell[ell], ROUND_NOT_NEEDED);
7978           if (lhs <= rhs) {
7979             // All 8 conditions are satisfied:
7980             // integer upper bound is not exact.
7981             return false;
7982           }
7983         }
7984       }
7985     }
7986   }
7987 
7988   // The upper bound of x and y is indeed exact.
7989   m_swap(ub);
7990   PPL_ASSERT(OK());
7991   return true;
7992 }
7993 
7994 template <typename T>
7995 void
drop_some_non_integer_points(Complexity_Class)7996 Octagonal_Shape<T>::drop_some_non_integer_points(Complexity_Class) {
7997   if (std::numeric_limits<T>::is_integer) {
7998     return;
7999   }
8000 
8001   strong_closure_assign();
8002   if (space_dim == 0 || marked_empty()) {
8003     return;
8004   }
8005 
8006   for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
8007          i_end = matrix.element_end(); i != i_end; ++i) {
8008     drop_some_non_integer_points_helper(*i);
8009   }
8010 
8011   // Unary constraints should have an even integer boundary.
8012   PPL_DIRTY_TEMP(N, temp_one);
8013   assign_r(temp_one, 1, ROUND_NOT_NEEDED);
8014   for (dimension_type i = 0; i < 2*space_dim; i += 2) {
8015     const dimension_type ci = i + 1;
8016     N& mat_i_ci = matrix[i][ci];
8017     if (!is_plus_infinity(mat_i_ci) && !is_even(mat_i_ci)) {
8018       sub_assign_r(mat_i_ci, mat_i_ci, temp_one, ROUND_UP);
8019       reset_strongly_closed();
8020     }
8021     N& mat_ci_i = matrix[ci][i];
8022     if (!is_plus_infinity(mat_ci_i) && !is_even(mat_ci_i)) {
8023       sub_assign_r(mat_ci_i, mat_ci_i, temp_one, ROUND_UP);
8024       reset_strongly_closed();
8025     }
8026   }
8027 
8028   PPL_ASSERT(OK());
8029 }
8030 
8031 template <typename T>
8032 void
8033 Octagonal_Shape<T>
drop_some_non_integer_points(const Variables_Set & vars,Complexity_Class)8034 ::drop_some_non_integer_points(const Variables_Set& vars,
8035                                Complexity_Class) {
8036   // Dimension-compatibility check.
8037   const dimension_type min_space_dim = vars.space_dimension();
8038   if (space_dimension() < min_space_dim) {
8039     throw_dimension_incompatible("drop_some_non_integer_points(vs, cmpl)",
8040                                  min_space_dim);
8041   }
8042 
8043   if (std::numeric_limits<T>::is_integer || min_space_dim == 0) {
8044     return;
8045   }
8046 
8047   strong_closure_assign();
8048   if (marked_empty()) {
8049     return;
8050   }
8051 
8052   PPL_DIRTY_TEMP(N, temp_one);
8053   assign_r(temp_one, 1, ROUND_NOT_NEEDED);
8054 
8055   const Variables_Set::const_iterator v_begin = vars.begin();
8056   const Variables_Set::const_iterator v_end = vars.end();
8057   PPL_ASSERT(v_begin != v_end);
8058   typedef typename OR_Matrix<N>::row_reference_type row_reference;
8059   for (Variables_Set::const_iterator v_i = v_begin; v_i != v_end; ++v_i) {
8060     const dimension_type i = 2 * (*v_i);
8061     const dimension_type ci = i + 1;
8062     row_reference m_i = matrix[i];
8063     row_reference m_ci = matrix[ci];
8064 
8065     // Unary constraints: should be even integers.
8066     N& m_i_ci = m_i[ci];
8067     if (!is_plus_infinity(m_i_ci)) {
8068       drop_some_non_integer_points_helper(m_i_ci);
8069       if (!is_even(m_i_ci)) {
8070         sub_assign_r(m_i_ci, m_i_ci, temp_one, ROUND_UP);
8071         reset_strongly_closed();
8072       }
8073     }
8074     N& m_ci_i = m_ci[i];
8075     if (!is_plus_infinity(m_ci_i)) {
8076       drop_some_non_integer_points_helper(m_ci_i);
8077       if (!is_even(m_ci_i)) {
8078         sub_assign_r(m_ci_i, m_ci_i, temp_one, ROUND_UP);
8079         reset_strongly_closed();
8080       }
8081     }
8082 
8083     // Binary constraints (note: only consider j < i).
8084     for (Variables_Set::const_iterator v_j = v_begin; v_j != v_i; ++v_j) {
8085       const dimension_type j = 2 * (*v_j);
8086       const dimension_type cj = j + 1;
8087       drop_some_non_integer_points_helper(m_i[j]);
8088       drop_some_non_integer_points_helper(m_i[cj]);
8089       drop_some_non_integer_points_helper(m_ci[j]);
8090       drop_some_non_integer_points_helper(m_ci[cj]);
8091     }
8092   }
8093   PPL_ASSERT(OK());
8094 }
8095 
8096 template <typename T>
8097 template <typename U>
8098 void
8099 Octagonal_Shape<T>
export_interval_constraints(U & dest) const8100 ::export_interval_constraints(U& dest) const {
8101   if (space_dim > dest.space_dimension()) {
8102     throw std::invalid_argument(
8103                "Octagonal_Shape<T>::export_interval_constraints");
8104   }
8105 
8106   strong_closure_assign();
8107 
8108   if (marked_empty()) {
8109     dest.set_empty();
8110     return;
8111   }
8112 
8113   PPL_DIRTY_TEMP(N, lb);
8114   PPL_DIRTY_TEMP(N, ub);
8115   for (dimension_type i = space_dim; i-- > 0; ) {
8116     const dimension_type ii = 2*i;
8117     const dimension_type cii = ii + 1;
8118 
8119     // Set the upper bound.
8120     const N& twice_ub = matrix[cii][ii];
8121     if (!is_plus_infinity(twice_ub)) {
8122       assign_r(ub, twice_ub, ROUND_NOT_NEEDED);
8123       div_2exp_assign_r(ub, ub, 1, ROUND_UP);
8124       // FIXME: passing a raw value may not be general enough.
8125       if (!dest.restrict_upper(i, ub.raw_value())) {
8126         return;
8127       }
8128     }
8129 
8130     // Set the lower bound.
8131     const N& twice_lb = matrix[ii][cii];
8132     if (!is_plus_infinity(twice_lb)) {
8133       assign_r(lb, twice_lb, ROUND_NOT_NEEDED);
8134       neg_assign_r(lb, lb, ROUND_NOT_NEEDED);
8135       div_2exp_assign_r(lb, lb, 1, ROUND_DOWN);
8136       // FIXME: passing a raw value may not be general enough.
8137       if (!dest.restrict_lower(i, lb.raw_value())) {
8138         return;
8139       }
8140     }
8141   }
8142 
8143 }
8144 
8145 /*! \relates Parma_Polyhedra_Library::Octagonal_Shape */
8146 template <typename T>
8147 std::ostream&
operator <<(std::ostream & s,const Octagonal_Shape<T> & oct)8148 IO_Operators::operator<<(std::ostream& s, const Octagonal_Shape<T>& oct) {
8149   // Handle special cases first.
8150   if (oct.marked_empty()) {
8151     s << "false";
8152     return s;
8153   }
8154   if (oct.is_universe()) {
8155     s << "true";
8156     return s;
8157   }
8158 
8159   typedef typename Octagonal_Shape<T>::coefficient_type N;
8160   typedef typename OR_Matrix<N>::const_row_iterator row_iterator;
8161   typedef typename OR_Matrix<N>::const_row_reference_type row_reference;
8162 
8163   // Records whether or not we still have to print the first constraint.
8164   bool first = true;
8165 
8166   row_iterator m_begin = oct.matrix.row_begin();
8167   row_iterator m_end = oct.matrix.row_end();
8168 
8169   // Temporaries.
8170   PPL_DIRTY_TEMP(N, negation);
8171   PPL_DIRTY_TEMP(N, half);
8172   // Go through all the unary constraints.
8173   // (Note: loop iterator is incremented in the loop body.)
8174   for (row_iterator i_iter = m_begin; i_iter != m_end; ) {
8175     const dimension_type i = i_iter.index();
8176     const Variable v_i(i/2);
8177     const N& c_i_ii = (*i_iter)[i + 1];
8178     ++i_iter;
8179     const N& c_ii_i = (*i_iter)[i];
8180     ++i_iter;
8181     // Check whether or not it is an equality constraint.
8182     if (is_additive_inverse(c_i_ii, c_ii_i)) {
8183       // It is an equality.
8184       PPL_ASSERT(!is_plus_infinity(c_i_ii) && !is_plus_infinity(c_ii_i));
8185       if (first) {
8186         first = false;
8187       }
8188       else {
8189         s << ", ";
8190       }
8191       // If the value bound can NOT be divided by 2 exactly,
8192       // then we output the constraint `2*v_i = bound'.
8193       if (div_2exp_assign_r(half, c_ii_i, 1,
8194                             ROUND_UP | ROUND_STRICT_RELATION)
8195           == V_EQ) {
8196         s << v_i << " = " << half;
8197       }
8198       else {
8199         s << "2*" << v_i << " = " << c_ii_i;
8200       }
8201     }
8202     else {
8203       // We will print unary non-strict inequalities, if any.
8204       if (!is_plus_infinity(c_i_ii)) {
8205         if (first) {
8206           first = false;
8207         }
8208         else {
8209           s << ", ";
8210         }
8211         neg_assign_r(negation, c_i_ii, ROUND_NOT_NEEDED);
8212         // If the value bound can NOT be divided by 2 exactly,
8213         // then we output the constraint `2*v_i >= negation'.
8214         if (div_2exp_assign_r(half, negation, 1,
8215                               ROUND_UP | ROUND_STRICT_RELATION)
8216             == V_EQ) {
8217           s << v_i << " >= " << half;
8218         }
8219         else {
8220           s << "2*" << v_i << " >= " << negation;
8221         }
8222       }
8223       if (!is_plus_infinity(c_ii_i)) {
8224         if (first) {
8225           first = false;
8226         }
8227         else {
8228           s << ", ";
8229         }
8230         // If the value bound can NOT be divided by 2 exactly,
8231         // then we output the constraint `2*v_i <= bound'.
8232         if (div_2exp_assign_r(half, c_ii_i, 1,
8233                               ROUND_UP | ROUND_STRICT_RELATION)
8234             == V_EQ) {
8235           s << v_i << " <= " << half;
8236         }
8237         else {
8238           s << "2*" << v_i << " <= " << c_ii_i;
8239         }
8240       }
8241     }
8242   }
8243 
8244   // Go through all the binary constraints.
8245   // (Note: loop iterator is incremented in the loop body.)
8246   for (row_iterator i_iter = m_begin; i_iter != m_end; ) {
8247     const dimension_type i = i_iter.index();
8248     const Variable v_i(i/2);
8249     row_reference r_i = *i_iter;
8250     ++i_iter;
8251     row_reference r_ii = *i_iter;
8252     ++i_iter;
8253 
8254     for (dimension_type j = 0; j < i; j += 2) {
8255       const Variable v_j(j/2);
8256       // Print binary differences.
8257       const N& c_ii_jj = r_ii[j + 1];
8258       const N& c_i_j = r_i[j];
8259       // Check whether or not it is an equality constraint.
8260       if (is_additive_inverse(c_ii_jj, c_i_j)) {
8261         // It is an equality.
8262         PPL_ASSERT(!is_plus_infinity(c_i_j) && !is_plus_infinity(c_ii_jj));
8263         if (first) {
8264           first = false;
8265         }
8266         else {
8267           s << ", ";
8268         }
8269         if (sgn(c_i_j) >= 0) {
8270           s << v_j << " - " << v_i << " = " << c_i_j;
8271         }
8272         else {
8273           s << v_i << " - " << v_j << " = " << c_ii_jj;
8274         }
8275       }
8276       else {
8277         // We will print non-strict inequalities, if any.
8278         if (!is_plus_infinity(c_i_j)) {
8279           if (first) {
8280             first = false;
8281           }
8282           else {
8283             s << ", ";
8284           }
8285           if (sgn(c_i_j) >= 0) {
8286             s << v_j << " - " << v_i << " <= " << c_i_j;
8287           }
8288           else {
8289             neg_assign_r(negation, c_i_j, ROUND_DOWN);
8290             s << v_i << " - " << v_j << " >= " << negation;
8291           }
8292         }
8293         if (!is_plus_infinity(c_ii_jj)) {
8294           if (first) {
8295             first = false;
8296           }
8297           else {
8298             s << ", ";
8299           }
8300           if (sgn(c_ii_jj) >= 0) {
8301             s << v_i << " - " << v_j << " <= " << c_ii_jj;
8302           }
8303           else {
8304             neg_assign_r(negation, c_ii_jj, ROUND_DOWN);
8305             s << v_j << " - " << v_i << " >= " << negation;
8306           }
8307         }
8308       }
8309       // Print binary sums.
8310       const N& c_i_jj = r_i[j + 1];
8311       const N& c_ii_j = r_ii[j];
8312       // Check whether or not it is an equality constraint.
8313       if (is_additive_inverse(c_i_jj, c_ii_j)) {
8314         // It is an equality.
8315         PPL_ASSERT(!is_plus_infinity(c_i_jj) && !is_plus_infinity(c_ii_j));
8316         if (first) {
8317           first = false;
8318         }
8319         else {
8320           s << ", ";
8321         }
8322         s << v_j << " + " << v_i << " = " << c_ii_j;
8323       }
8324       else {
8325         // We will print non-strict inequalities, if any.
8326         if (!is_plus_infinity(c_i_jj)) {
8327           if (first) {
8328             first = false;
8329           }
8330           else {
8331             s << ", ";
8332           }
8333           neg_assign_r(negation, c_i_jj, ROUND_DOWN);
8334           s << v_j << " + " << v_i << " >= " << negation;
8335         }
8336         if (!is_plus_infinity(c_ii_j)) {
8337           if (first) {
8338             first = false;
8339           }
8340           else {
8341             s << ", ";
8342           }
8343           s << v_j << " + " << v_i << " <= " << c_ii_j;
8344         }
8345       }
8346     }
8347   }
8348   return s;
8349 }
8350 
8351 template <typename T>
8352 void
ascii_dump(std::ostream & s) const8353 Octagonal_Shape<T>::ascii_dump(std::ostream& s) const {
8354   s << "space_dim "
8355     << space_dim
8356     << "\n";
8357   status.ascii_dump(s);
8358   s << "\n";
8359   matrix.ascii_dump(s);
8360 }
8361 
PPL_OUTPUT_TEMPLATE_DEFINITIONS(T,Octagonal_Shape<T>)8362 PPL_OUTPUT_TEMPLATE_DEFINITIONS(T, Octagonal_Shape<T>)
8363 
8364 template <typename T>
8365 bool
8366 Octagonal_Shape<T>::ascii_load(std::istream& s) {
8367   std::string str;
8368 
8369   if (!(s >> str) || str != "space_dim") {
8370     return false;
8371   }
8372 
8373   if (!(s >> space_dim)) {
8374     return false;
8375   }
8376 
8377   if (!status.ascii_load(s)) {
8378     return false;
8379   }
8380 
8381   if (!matrix.ascii_load(s)) {
8382     return false;
8383   }
8384 
8385   PPL_ASSERT(OK());
8386   return true;
8387 }
8388 
8389 template <typename T>
8390 memory_size_type
external_memory_in_bytes() const8391 Octagonal_Shape<T>::external_memory_in_bytes() const {
8392   return matrix.external_memory_in_bytes();
8393 }
8394 
8395 template <typename T>
8396 bool
OK() const8397 Octagonal_Shape<T>::OK() const {
8398   // Check whether the matrix is well-formed.
8399   if (!matrix.OK()) {
8400     return false;
8401   }
8402 
8403   // Check whether the status information is legal.
8404   if (!status.OK()) {
8405     return false;
8406   }
8407 
8408   // All empty octagons are OK.
8409   if (marked_empty()) {
8410     return true;
8411   }
8412 
8413   // 0-dim universe octagon is OK.
8414   if (space_dim == 0) {
8415     return true;
8416   }
8417 
8418   // MINUS_INFINITY cannot occur at all.
8419   for (typename OR_Matrix<N>::const_row_iterator i = matrix.row_begin(),
8420          matrix_row_end = matrix.row_end(); i != matrix_row_end; ++i) {
8421     typename OR_Matrix<N>::const_row_reference_type x_i = *i;
8422     for (dimension_type j = i.row_size(); j-- > 0; ) {
8423       if (is_minus_infinity(x_i[j])) {
8424 #ifndef NDEBUG
8425         using namespace Parma_Polyhedra_Library::IO_Operators;
8426         std::cerr << "Octagonal_Shape::"
8427                   << "matrix[" << i.index() << "][" << j << "] = "
8428                   << x_i[j] << "!"
8429                   << std::endl;
8430 #endif
8431         return false;
8432       }
8433     }
8434   }
8435 
8436   // On the main diagonal only PLUS_INFINITY can occur.
8437   for (typename OR_Matrix<N>::const_row_iterator i = matrix.row_begin(),
8438          m_end = matrix.row_end(); i != m_end; ++i) {
8439     typename OR_Matrix<N>::const_row_reference_type r = *i;
8440     const N& m_i_i = r[i.index()];
8441     if (!is_plus_infinity(m_i_i)) {
8442 #ifndef NDEBUG
8443       const dimension_type j = i.index();
8444       using namespace Parma_Polyhedra_Library::IO_Operators;
8445       std::cerr << "Octagonal_Shape::matrix[" << j << "][" << j << "] = "
8446                 << m_i_i << "!  (+inf was expected.)\n";
8447 #endif
8448       return false;
8449     }
8450   }
8451 
8452   // The following tests might result in false alarms when using floating
8453   // point coefficients: they are only meaningful if the coefficient type
8454   // base is exact (since otherwise strong closure is approximated).
8455   if (std::numeric_limits<coefficient_type_base>::is_exact) {
8456 
8457     // Check whether the closure information is legal.
8458     if (marked_strongly_closed()) {
8459       Octagonal_Shape x = *this;
8460       x.reset_strongly_closed();
8461       x.strong_closure_assign();
8462       if (x.matrix != matrix) {
8463 #ifndef NDEBUG
8464         std::cerr << "Octagonal_Shape is marked as strongly closed "
8465                   << "but it is not!\n";
8466 #endif
8467         return false;
8468       }
8469     }
8470 
8471     // A closed octagon must be strong-coherent.
8472     if (marked_strongly_closed()) {
8473       if (!is_strong_coherent()) {
8474 #ifndef NDEBUG
8475         std::cerr << "Octagonal_Shape is not strong-coherent!\n";
8476 #endif
8477         return false;
8478       }
8479     }
8480   }
8481 
8482   // All checks passed.
8483   return true;
8484 }
8485 
8486 
8487 template <typename T>
8488 void
8489 Octagonal_Shape<T>
throw_dimension_incompatible(const char * method,const Octagonal_Shape & y) const8490 ::throw_dimension_incompatible(const char* method,
8491                                const Octagonal_Shape& y) const {
8492   std::ostringstream s;
8493   s << "PPL::Octagonal_Shape::" << method << ":\n"
8494     << "this->space_dimension() == " << space_dimension()
8495     << ", y->space_dimension() == " << y.space_dimension() << ".";
8496   throw std::invalid_argument(s.str());
8497 }
8498 
8499 template <typename T>
8500 void
8501 Octagonal_Shape<T>
throw_dimension_incompatible(const char * method,dimension_type required_dim) const8502 ::throw_dimension_incompatible(const char* method,
8503                                dimension_type required_dim) const {
8504   std::ostringstream s;
8505   s << "PPL::Octagonal_Shape::" << method << ":\n"
8506     << "this->space_dimension() == " << space_dimension()
8507     << ", required dimension == " << required_dim << ".";
8508   throw std::invalid_argument(s.str());
8509 }
8510 
8511 template <typename T>
8512 void
throw_dimension_incompatible(const char * method,const Constraint & c) const8513 Octagonal_Shape<T>::throw_dimension_incompatible(const char* method,
8514                                                  const Constraint& c) const {
8515   std::ostringstream s;
8516   s << "PPL::Octagonal_Shape::" << method << ":\n"
8517     << "this->space_dimension() == " << space_dimension()
8518     << ", c->space_dimension == " << c.space_dimension() << ".";
8519   throw std::invalid_argument(s.str());
8520 }
8521 
8522 template <typename T>
8523 void
throw_dimension_incompatible(const char * method,const Congruence & cg) const8524 Octagonal_Shape<T>::throw_dimension_incompatible(const char* method,
8525                                                  const Congruence& cg) const {
8526   std::ostringstream s;
8527   s << "PPL::Octagonal_Shape::" << method << ":\n"
8528     << "this->space_dimension() == " << space_dimension()
8529     << ", cg->space_dimension == " << cg.space_dimension() << ".";
8530   throw std::invalid_argument(s.str());
8531 }
8532 
8533 template <typename T>
8534 void
throw_dimension_incompatible(const char * method,const Generator & g) const8535 Octagonal_Shape<T>::throw_dimension_incompatible(const char* method,
8536                                                  const Generator& g) const {
8537   std::ostringstream s;
8538   s << "PPL::Octagonal_Shape::" << method << ":\n"
8539     << "this->space_dimension() == " << space_dimension()
8540     << ", g->space_dimension == " << g.space_dimension() << ".";
8541   throw std::invalid_argument(s.str());
8542 }
8543 
8544 template <typename T>
8545 void
throw_constraint_incompatible(const char * method)8546 Octagonal_Shape<T>::throw_constraint_incompatible(const char* method) {
8547   std::ostringstream s;
8548   s << "PPL::Octagonal_Shape::" << method << ":\n"
8549     << "the constraint is incompatible.";
8550   throw std::invalid_argument(s.str());
8551 }
8552 
8553 template <typename T>
8554 void
throw_expression_too_complex(const char * method,const Linear_Expression & le)8555 Octagonal_Shape<T>::throw_expression_too_complex(const char* method,
8556                                                  const Linear_Expression& le) {
8557   using namespace IO_Operators;
8558   std::ostringstream s;
8559   s << "PPL::Octagonal_Shape::" << method << ":\n"
8560     << le << " is too complex.";
8561   throw std::invalid_argument(s.str());
8562 }
8563 
8564 template <typename T>
8565 void
8566 Octagonal_Shape<T>
throw_dimension_incompatible(const char * method,const char * le_name,const Linear_Expression & le) const8567 ::throw_dimension_incompatible(const char* method,
8568                                const char* le_name,
8569                                const Linear_Expression& le) const {
8570   std::ostringstream s;
8571   s << "PPL::Octagonal_Shape::" << method << ":\n"
8572     << "this->space_dimension() == " << space_dimension()
8573     << ", " << le_name << "->space_dimension() == "
8574     << le.space_dimension() << ".";
8575   throw std::invalid_argument(s.str());
8576 }
8577 
8578 template <typename T>
8579 template <typename C>
8580 void
8581 Octagonal_Shape<T>
throw_dimension_incompatible(const char * method,const char * lf_name,const Linear_Form<C> & lf) const8582 ::throw_dimension_incompatible(const char* method,
8583                                const char* lf_name,
8584                                const Linear_Form<C>& lf) const {
8585   std::ostringstream s;
8586   s << "PPL::Octagonal_Shape::" << method << ":\n"
8587     << "this->space_dimension() == " << space_dimension()
8588     << ", " << lf_name << "->space_dimension() == "
8589     << lf.space_dimension() << ".";
8590   throw std::invalid_argument(s.str());
8591 }
8592 
8593 template <typename T>
8594 void
throw_invalid_argument(const char * method,const char * reason)8595 Octagonal_Shape<T>::throw_invalid_argument(const char* method,
8596                                            const char* reason) {
8597   std::ostringstream s;
8598   s << "PPL::Octagonal_Shape::" << method << ":\n"
8599     << reason << ".";
8600   throw std::invalid_argument(s.str());
8601 }
8602 
8603 } // namespace Parma_Polyhedra_Library
8604 
8605 #endif // !defined(PPL_Octagonal_Shape_templates_hh)
8606