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