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