1 /* BD_Shape class implementation: inline 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_inlines_hh
25 #define PPL_BD_Shape_inlines_hh 1
26
27 #include "Constraint_System_defs.hh"
28 #include "Constraint_System_inlines.hh"
29 #include "C_Polyhedron_defs.hh"
30 #include "Grid_defs.hh"
31 #include "Octagonal_Shape_defs.hh"
32 #include "Poly_Con_Relation_defs.hh"
33 #include "Poly_Gen_Relation_defs.hh"
34 #include "Temp_defs.hh"
35 #include "meta_programming.hh"
36 #include "wrap_assign.hh"
37 #include "assertions.hh"
38 #include <vector>
39 #include <iostream>
40 #include <algorithm>
41
42 namespace Parma_Polyhedra_Library {
43
44 template <typename T>
45 inline dimension_type
max_space_dimension()46 BD_Shape<T>::max_space_dimension() {
47 // One dimension is reserved to have a value of type dimension_type
48 // that does not represent a legal dimension.
49 return std::min(DB_Matrix<N>::max_num_rows() - 1,
50 DB_Matrix<N>::max_num_columns() - 1);
51 }
52
53 template <typename T>
54 inline bool
marked_zero_dim_univ() const55 BD_Shape<T>::marked_zero_dim_univ() const {
56 return status.test_zero_dim_univ();
57 }
58
59 template <typename T>
60 inline bool
marked_empty() const61 BD_Shape<T>::marked_empty() const {
62 return status.test_empty();
63 }
64
65 template <typename T>
66 inline bool
marked_shortest_path_closed() const67 BD_Shape<T>::marked_shortest_path_closed() const {
68 return status.test_shortest_path_closed();
69 }
70
71 template <typename T>
72 inline bool
marked_shortest_path_reduced() const73 BD_Shape<T>::marked_shortest_path_reduced() const {
74 return status.test_shortest_path_reduced();
75 }
76
77 template <typename T>
78 inline void
set_zero_dim_univ()79 BD_Shape<T>::set_zero_dim_univ() {
80 status.set_zero_dim_univ();
81 }
82
83 template <typename T>
84 inline void
set_empty()85 BD_Shape<T>::set_empty() {
86 status.set_empty();
87 }
88
89 template <typename T>
90 inline void
set_shortest_path_closed()91 BD_Shape<T>::set_shortest_path_closed() {
92 status.set_shortest_path_closed();
93 }
94
95 template <typename T>
96 inline void
set_shortest_path_reduced()97 BD_Shape<T>::set_shortest_path_reduced() {
98 status.set_shortest_path_reduced();
99 }
100
101 template <typename T>
102 inline void
reset_shortest_path_closed()103 BD_Shape<T>::reset_shortest_path_closed() {
104 status.reset_shortest_path_closed();
105 }
106
107 template <typename T>
108 inline void
reset_shortest_path_reduced()109 BD_Shape<T>::reset_shortest_path_reduced() {
110 status.reset_shortest_path_reduced();
111 }
112
113 template <typename T>
114 inline
BD_Shape(const dimension_type num_dimensions,const Degenerate_Element kind)115 BD_Shape<T>::BD_Shape(const dimension_type num_dimensions,
116 const Degenerate_Element kind)
117 : dbm(num_dimensions + 1), status(), redundancy_dbm() {
118 if (kind == EMPTY) {
119 set_empty();
120 }
121 else {
122 if (num_dimensions > 0) {
123 // A (non zero-dim) universe BDS is closed.
124 set_shortest_path_closed();
125 }
126 }
127 PPL_ASSERT(OK());
128 }
129
130 template <typename T>
131 inline
BD_Shape(const BD_Shape & y,Complexity_Class)132 BD_Shape<T>::BD_Shape(const BD_Shape& y, Complexity_Class)
133 : dbm(y.dbm), status(y.status), redundancy_dbm() {
134 if (y.marked_shortest_path_reduced()) {
135 redundancy_dbm = y.redundancy_dbm;
136 }
137 }
138
139 template <typename T>
140 template <typename U>
141 inline
BD_Shape(const BD_Shape<U> & y,Complexity_Class)142 BD_Shape<T>::BD_Shape(const BD_Shape<U>& y, Complexity_Class)
143 // For maximum precision, enforce shortest-path closure
144 // before copying the DB matrix.
145 : dbm((y.shortest_path_closure_assign(), y.dbm)),
146 status(),
147 redundancy_dbm() {
148 // TODO: handle flags properly, possibly taking special cases into account.
149 if (y.marked_empty()) {
150 set_empty();
151 }
152 else if (y.marked_zero_dim_univ()) {
153 set_zero_dim_univ();
154 }
155 }
156
157 template <typename T>
158 inline Congruence_System
congruences() const159 BD_Shape<T>::congruences() const {
160 return minimized_congruences();
161 }
162
163 template <typename T>
164 inline void
add_constraints(const Constraint_System & cs)165 BD_Shape<T>::add_constraints(const Constraint_System& cs) {
166 for (Constraint_System::const_iterator i = cs.begin(),
167 cs_end = cs.end(); i != cs_end; ++i) {
168 add_constraint(*i);
169 }
170 }
171
172 template <typename T>
173 inline void
add_recycled_constraints(Constraint_System & cs)174 BD_Shape<T>::add_recycled_constraints(Constraint_System& cs) {
175 add_constraints(cs);
176 }
177
178 template <typename T>
179 inline void
add_congruences(const Congruence_System & cgs)180 BD_Shape<T>::add_congruences(const Congruence_System& cgs) {
181 for (Congruence_System::const_iterator i = cgs.begin(),
182 cgs_end = cgs.end(); i != cgs_end; ++i) {
183 add_congruence(*i);
184 }
185 }
186
187 template <typename T>
188 inline void
add_recycled_congruences(Congruence_System & cgs)189 BD_Shape<T>::add_recycled_congruences(Congruence_System& cgs) {
190 add_congruences(cgs);
191 }
192
193 template <typename T>
194 inline void
refine_with_constraint(const Constraint & c)195 BD_Shape<T>::refine_with_constraint(const Constraint& c) {
196 const dimension_type c_space_dim = c.space_dimension();
197 // Dimension-compatibility check.
198 if (c_space_dim > space_dimension()) {
199 throw_dimension_incompatible("refine_with_constraint(c)", c);
200 }
201
202 if (!marked_empty()) {
203 refine_no_check(c);
204 }
205 }
206
207 template <typename T>
208 inline void
refine_with_constraints(const Constraint_System & cs)209 BD_Shape<T>::refine_with_constraints(const Constraint_System& cs) {
210 // Dimension-compatibility check.
211 if (cs.space_dimension() > space_dimension()) {
212 throw_invalid_argument("refine_with_constraints(cs)",
213 "cs and *this are space-dimension incompatible");
214 }
215
216 for (Constraint_System::const_iterator i = cs.begin(),
217 cs_end = cs.end(); !marked_empty() && i != cs_end; ++i) {
218 refine_no_check(*i);
219 }
220 }
221
222 template <typename T>
223 inline void
refine_with_congruence(const Congruence & cg)224 BD_Shape<T>::refine_with_congruence(const Congruence& cg) {
225 const dimension_type cg_space_dim = cg.space_dimension();
226 // Dimension-compatibility check.
227 if (cg_space_dim > space_dimension()) {
228 throw_dimension_incompatible("refine_with_congruence(cg)", cg);
229 }
230
231 if (!marked_empty()) {
232 refine_no_check(cg);
233 }
234 }
235
236 template <typename T>
237 void
refine_with_congruences(const Congruence_System & cgs)238 BD_Shape<T>::refine_with_congruences(const Congruence_System& cgs) {
239 // Dimension-compatibility check.
240 if (cgs.space_dimension() > space_dimension()) {
241 throw_invalid_argument("refine_with_congruences(cgs)",
242 "cgs and *this are space-dimension incompatible");
243 }
244
245 for (Congruence_System::const_iterator i = cgs.begin(),
246 cgs_end = cgs.end(); !marked_empty() && i != cgs_end; ++i) {
247 refine_no_check(*i);
248 }
249 }
250
251 template <typename T>
252 inline void
refine_no_check(const Congruence & cg)253 BD_Shape<T>::refine_no_check(const Congruence& cg) {
254 PPL_ASSERT(!marked_empty());
255 PPL_ASSERT(cg.space_dimension() <= space_dimension());
256
257 if (cg.is_proper_congruence()) {
258 if (cg.is_inconsistent()) {
259 set_empty();
260 }
261 // Other proper congruences are just ignored.
262 return;
263 }
264
265 PPL_ASSERT(cg.is_equality());
266 Constraint c(cg);
267 refine_no_check(c);
268 }
269
270 template <typename T>
271 inline bool
can_recycle_constraint_systems()272 BD_Shape<T>::can_recycle_constraint_systems() {
273 return false;
274 }
275
276
277 template <typename T>
278 inline bool
can_recycle_congruence_systems()279 BD_Shape<T>::can_recycle_congruence_systems() {
280 return false;
281 }
282
283 template <typename T>
284 inline
BD_Shape(const Constraint_System & cs)285 BD_Shape<T>::BD_Shape(const Constraint_System& cs)
286 : dbm(cs.space_dimension() + 1), status(), redundancy_dbm() {
287 if (cs.space_dimension() > 0) {
288 // A (non zero-dim) universe BDS is shortest-path closed.
289 set_shortest_path_closed();
290 }
291 add_constraints(cs);
292 }
293
294 template <typename T>
295 template <typename Interval>
296 inline
BD_Shape(const Box<Interval> & box,Complexity_Class)297 BD_Shape<T>::BD_Shape(const Box<Interval>& box,
298 Complexity_Class)
299 : dbm(box.space_dimension() + 1), status(), redundancy_dbm() {
300 // Check emptiness for maximum precision.
301 if (box.is_empty()) {
302 set_empty();
303 }
304 else if (box.space_dimension() > 0) {
305 // A (non zero-dim) universe BDS is shortest-path closed.
306 set_shortest_path_closed();
307 refine_with_constraints(box.constraints());
308 }
309 }
310
311 template <typename T>
312 inline
BD_Shape(const Grid & grid,Complexity_Class)313 BD_Shape<T>::BD_Shape(const Grid& grid,
314 Complexity_Class)
315 : dbm(grid.space_dimension() + 1), status(), redundancy_dbm() {
316 if (grid.space_dimension() > 0) {
317 // A (non zero-dim) universe BDS is shortest-path closed.
318 set_shortest_path_closed();
319 }
320 // Taking minimized congruences ensures maximum precision.
321 refine_with_congruences(grid.minimized_congruences());
322 }
323
324 template <typename T>
325 template <typename U>
326 inline
BD_Shape(const Octagonal_Shape<U> & os,Complexity_Class)327 BD_Shape<T>::BD_Shape(const Octagonal_Shape<U>& os,
328 Complexity_Class)
329 : dbm(os.space_dimension() + 1), status(), redundancy_dbm() {
330 // Check for emptiness for maximum precision.
331 if (os.is_empty()) {
332 set_empty();
333 }
334 else if (os.space_dimension() > 0) {
335 // A (non zero-dim) universe BDS is shortest-path closed.
336 set_shortest_path_closed();
337 refine_with_constraints(os.constraints());
338 // After refining, shortest-path closure is possibly lost
339 // (even when `os' was strongly closed: recall that U
340 // is possibly different from T).
341 }
342 }
343
344 template <typename T>
345 inline BD_Shape<T>&
operator =(const BD_Shape & y)346 BD_Shape<T>::operator=(const BD_Shape& y) {
347 dbm = y.dbm;
348 status = y.status;
349 if (y.marked_shortest_path_reduced()) {
350 redundancy_dbm = y.redundancy_dbm;
351 }
352 return *this;
353 }
354
355 template <typename T>
356 inline
~BD_Shape()357 BD_Shape<T>::~BD_Shape() {
358 }
359
360 template <typename T>
361 inline void
m_swap(BD_Shape & y)362 BD_Shape<T>::m_swap(BD_Shape& y) {
363 using std::swap;
364 swap(dbm, y.dbm);
365 swap(status, y.status);
366 swap(redundancy_dbm, y.redundancy_dbm);
367 }
368
369 template <typename T>
370 inline dimension_type
space_dimension() const371 BD_Shape<T>::space_dimension() const {
372 return dbm.num_rows() - 1;
373 }
374
375 template <typename T>
376 inline bool
is_empty() const377 BD_Shape<T>::is_empty() const {
378 shortest_path_closure_assign();
379 return marked_empty();
380 }
381
382 template <typename T>
383 inline bool
bounds_from_above(const Linear_Expression & expr) const384 BD_Shape<T>::bounds_from_above(const Linear_Expression& expr) const {
385 return bounds(expr, true);
386 }
387
388 template <typename T>
389 inline bool
bounds_from_below(const Linear_Expression & expr) const390 BD_Shape<T>::bounds_from_below(const Linear_Expression& expr) const {
391 return bounds(expr, false);
392 }
393
394 template <typename T>
395 inline bool
maximize(const Linear_Expression & expr,Coefficient & sup_n,Coefficient & sup_d,bool & maximum) const396 BD_Shape<T>::maximize(const Linear_Expression& expr,
397 Coefficient& sup_n, Coefficient& sup_d,
398 bool& maximum) const {
399 return max_min(expr, true, sup_n, sup_d, maximum);
400 }
401
402 template <typename T>
403 inline bool
maximize(const Linear_Expression & expr,Coefficient & sup_n,Coefficient & sup_d,bool & maximum,Generator & g) const404 BD_Shape<T>::maximize(const Linear_Expression& expr,
405 Coefficient& sup_n, Coefficient& sup_d, bool& maximum,
406 Generator& g) const {
407 return max_min(expr, true, sup_n, sup_d, maximum, g);
408 }
409
410 template <typename T>
411 inline bool
minimize(const Linear_Expression & expr,Coefficient & inf_n,Coefficient & inf_d,bool & minimum) const412 BD_Shape<T>::minimize(const Linear_Expression& expr,
413 Coefficient& inf_n, Coefficient& inf_d,
414 bool& minimum) const {
415 return max_min(expr, false, inf_n, inf_d, minimum);
416 }
417
418 template <typename T>
419 inline bool
minimize(const Linear_Expression & expr,Coefficient & inf_n,Coefficient & inf_d,bool & minimum,Generator & g) const420 BD_Shape<T>::minimize(const Linear_Expression& expr,
421 Coefficient& inf_n, Coefficient& inf_d, bool& minimum,
422 Generator& g) const {
423 return max_min(expr, false, inf_n, inf_d, minimum, g);
424 }
425
426 template <typename T>
427 inline bool
is_topologically_closed() const428 BD_Shape<T>::is_topologically_closed() const {
429 return true;
430 }
431
432 template <typename T>
433 inline bool
is_discrete() const434 BD_Shape<T>::is_discrete() const {
435 return affine_dimension() == 0;
436 }
437
438 template <typename T>
439 inline void
topological_closure_assign()440 BD_Shape<T>::topological_closure_assign() {
441 }
442
443 /*! \relates BD_Shape */
444 template <typename T>
445 inline bool
operator ==(const BD_Shape<T> & x,const BD_Shape<T> & y)446 operator==(const BD_Shape<T>& x, const BD_Shape<T>& y) {
447 const dimension_type x_space_dim = x.space_dimension();
448 // Dimension-compatibility check.
449 if (x_space_dim != y.space_dimension()) {
450 return false;
451 }
452
453 // Zero-dim BDSs are equal if and only if they are both empty or universe.
454 if (x_space_dim == 0) {
455 if (x.marked_empty()) {
456 return y.marked_empty();
457 }
458 else {
459 return !y.marked_empty();
460 }
461 }
462
463 // The exact equivalence test requires shortest-path closure.
464 x.shortest_path_closure_assign();
465 y.shortest_path_closure_assign();
466
467 // If one of two BDSs is empty, then they are equal
468 // if and only if the other BDS is empty too.
469 if (x.marked_empty()) {
470 return y.marked_empty();
471 }
472 if (y.marked_empty()) {
473 return false;
474 }
475 // Check for syntactic equivalence of the two (shortest-path closed)
476 // systems of bounded differences.
477 return x.dbm == y.dbm;
478 }
479
480 /*! \relates BD_Shape */
481 template <typename T>
482 inline bool
operator !=(const BD_Shape<T> & x,const BD_Shape<T> & y)483 operator!=(const BD_Shape<T>& x, const BD_Shape<T>& y) {
484 return !(x == y);
485 }
486
487 /*! \relates BD_Shape */
488 template <typename Temp, typename To, typename T>
489 inline bool
rectilinear_distance_assign(Checked_Number<To,Extended_Number_Policy> & r,const BD_Shape<T> & x,const BD_Shape<T> & y,const Rounding_Dir dir,Temp & tmp0,Temp & tmp1,Temp & tmp2)490 rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
491 const BD_Shape<T>& x,
492 const BD_Shape<T>& y,
493 const Rounding_Dir dir,
494 Temp& tmp0,
495 Temp& tmp1,
496 Temp& tmp2) {
497 const dimension_type x_space_dim = x.space_dimension();
498 // Dimension-compatibility check.
499 if (x_space_dim != y.space_dimension()) {
500 return false;
501 }
502
503 // Zero-dim BDSs are equal if and only if they are both empty or universe.
504 if (x_space_dim == 0) {
505 if (x.marked_empty() == y.marked_empty()) {
506 assign_r(r, 0, ROUND_NOT_NEEDED);
507 }
508 else {
509 assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
510 }
511 return true;
512 }
513
514 // The distance computation requires shortest-path closure.
515 x.shortest_path_closure_assign();
516 y.shortest_path_closure_assign();
517
518 // If one of two BDSs is empty, then they are equal if and only if
519 // the other BDS is empty too.
520 if (x.marked_empty() || y.marked_empty()) {
521 if (x.marked_empty() == y.marked_empty()) {
522 assign_r(r, 0, ROUND_NOT_NEEDED);
523 }
524 else {
525 assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
526 }
527 return true;
528 }
529
530 return rectilinear_distance_assign(r, x.dbm, y.dbm, dir, tmp0, tmp1, tmp2);
531 }
532
533 /*! \relates BD_Shape */
534 template <typename Temp, typename To, typename T>
535 inline bool
rectilinear_distance_assign(Checked_Number<To,Extended_Number_Policy> & r,const BD_Shape<T> & x,const BD_Shape<T> & y,const Rounding_Dir dir)536 rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
537 const BD_Shape<T>& x,
538 const BD_Shape<T>& y,
539 const Rounding_Dir dir) {
540 typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
541 PPL_DIRTY_TEMP(Checked_Temp, tmp0);
542 PPL_DIRTY_TEMP(Checked_Temp, tmp1);
543 PPL_DIRTY_TEMP(Checked_Temp, tmp2);
544 return rectilinear_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
545 }
546
547 /*! \relates BD_Shape */
548 template <typename To, typename T>
549 inline bool
rectilinear_distance_assign(Checked_Number<To,Extended_Number_Policy> & r,const BD_Shape<T> & x,const BD_Shape<T> & y,const Rounding_Dir dir)550 rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
551 const BD_Shape<T>& x,
552 const BD_Shape<T>& y,
553 const Rounding_Dir dir) {
554 return rectilinear_distance_assign<To, To, T>(r, x, y, dir);
555 }
556
557 /*! \relates BD_Shape */
558 template <typename Temp, typename To, typename T>
559 inline bool
euclidean_distance_assign(Checked_Number<To,Extended_Number_Policy> & r,const BD_Shape<T> & x,const BD_Shape<T> & y,const Rounding_Dir dir,Temp & tmp0,Temp & tmp1,Temp & tmp2)560 euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
561 const BD_Shape<T>& x,
562 const BD_Shape<T>& y,
563 const Rounding_Dir dir,
564 Temp& tmp0,
565 Temp& tmp1,
566 Temp& tmp2) {
567 const dimension_type x_space_dim = x.space_dimension();
568 // Dimension-compatibility check.
569 if (x_space_dim != y.space_dimension()) {
570 return false;
571 }
572
573 // Zero-dim BDSs are equal if and only if they are both empty or universe.
574 if (x_space_dim == 0) {
575 if (x.marked_empty() == y.marked_empty()) {
576 assign_r(r, 0, ROUND_NOT_NEEDED);
577 }
578 else {
579 assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
580 }
581 return true;
582 }
583
584 // The distance computation requires shortest-path closure.
585 x.shortest_path_closure_assign();
586 y.shortest_path_closure_assign();
587
588 // If one of two BDSs is empty, then they are equal if and only if
589 // the other BDS is empty too.
590 if (x.marked_empty() || y.marked_empty()) {
591 if (x.marked_empty() == y.marked_empty()) {
592 assign_r(r, 0, ROUND_NOT_NEEDED);
593 }
594 else {
595 assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
596 }
597 return true;
598 }
599
600 return euclidean_distance_assign(r, x.dbm, y.dbm, dir, tmp0, tmp1, tmp2);
601 }
602
603 /*! \relates BD_Shape */
604 template <typename Temp, typename To, typename T>
605 inline bool
euclidean_distance_assign(Checked_Number<To,Extended_Number_Policy> & r,const BD_Shape<T> & x,const BD_Shape<T> & y,const Rounding_Dir dir)606 euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
607 const BD_Shape<T>& x,
608 const BD_Shape<T>& y,
609 const Rounding_Dir dir) {
610 typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
611 PPL_DIRTY_TEMP(Checked_Temp, tmp0);
612 PPL_DIRTY_TEMP(Checked_Temp, tmp1);
613 PPL_DIRTY_TEMP(Checked_Temp, tmp2);
614 return euclidean_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
615 }
616
617 /*! \relates BD_Shape */
618 template <typename To, typename T>
619 inline bool
euclidean_distance_assign(Checked_Number<To,Extended_Number_Policy> & r,const BD_Shape<T> & x,const BD_Shape<T> & y,const Rounding_Dir dir)620 euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
621 const BD_Shape<T>& x,
622 const BD_Shape<T>& y,
623 const Rounding_Dir dir) {
624 return euclidean_distance_assign<To, To, T>(r, x, y, dir);
625 }
626
627 /*! \relates BD_Shape */
628 template <typename Temp, typename To, typename T>
629 inline bool
l_infinity_distance_assign(Checked_Number<To,Extended_Number_Policy> & r,const BD_Shape<T> & x,const BD_Shape<T> & y,const Rounding_Dir dir,Temp & tmp0,Temp & tmp1,Temp & tmp2)630 l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
631 const BD_Shape<T>& x,
632 const BD_Shape<T>& y,
633 const Rounding_Dir dir,
634 Temp& tmp0,
635 Temp& tmp1,
636 Temp& tmp2) {
637 const dimension_type x_space_dim = x.space_dimension();
638 // Dimension-compatibility check.
639 if (x_space_dim != y.space_dimension()) {
640 return false;
641 }
642 // Zero-dim BDSs are equal if and only if they are both empty or universe.
643 if (x_space_dim == 0) {
644 if (x.marked_empty() == y.marked_empty()) {
645 assign_r(r, 0, ROUND_NOT_NEEDED);
646 }
647 else {
648 assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
649 }
650 return true;
651 }
652
653 // The distance computation requires shortest-path closure.
654 x.shortest_path_closure_assign();
655 y.shortest_path_closure_assign();
656
657 // If one of two BDSs is empty, then they are equal if and only if
658 // the other BDS is empty too.
659 if (x.marked_empty() || y.marked_empty()) {
660 if (x.marked_empty() == y.marked_empty()) {
661 assign_r(r, 0, ROUND_NOT_NEEDED);
662 }
663 else {
664 assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
665 }
666 return true;
667 }
668
669 return l_infinity_distance_assign(r, x.dbm, y.dbm, dir, tmp0, tmp1, tmp2);
670 }
671
672 /*! \relates BD_Shape */
673 template <typename Temp, typename To, typename T>
674 inline bool
l_infinity_distance_assign(Checked_Number<To,Extended_Number_Policy> & r,const BD_Shape<T> & x,const BD_Shape<T> & y,const Rounding_Dir dir)675 l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
676 const BD_Shape<T>& x,
677 const BD_Shape<T>& y,
678 const Rounding_Dir dir) {
679 typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
680 PPL_DIRTY_TEMP(Checked_Temp, tmp0);
681 PPL_DIRTY_TEMP(Checked_Temp, tmp1);
682 PPL_DIRTY_TEMP(Checked_Temp, tmp2);
683 return l_infinity_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
684 }
685
686 /*! \relates BD_Shape */
687 template <typename To, typename T>
688 inline bool
l_infinity_distance_assign(Checked_Number<To,Extended_Number_Policy> & r,const BD_Shape<T> & x,const BD_Shape<T> & y,const Rounding_Dir dir)689 l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
690 const BD_Shape<T>& x,
691 const BD_Shape<T>& y,
692 const Rounding_Dir dir) {
693 return l_infinity_distance_assign<To, To, T>(r, x, y, dir);
694 }
695
696 template <typename T>
697 inline void
add_dbm_constraint(const dimension_type i,const dimension_type j,const N & k)698 BD_Shape<T>::add_dbm_constraint(const dimension_type i,
699 const dimension_type j,
700 const N& k) {
701 // Private method: the caller has to ensure the following.
702 PPL_ASSERT(i <= space_dimension() && j <= space_dimension() && i != j);
703 N& dbm_ij = dbm[i][j];
704 if (dbm_ij > k) {
705 dbm_ij = k;
706 if (marked_shortest_path_closed()) {
707 reset_shortest_path_closed();
708 }
709 }
710 }
711
712 template <typename T>
713 inline void
add_dbm_constraint(const dimension_type i,const dimension_type j,Coefficient_traits::const_reference numer,Coefficient_traits::const_reference denom)714 BD_Shape<T>::add_dbm_constraint(const dimension_type i,
715 const dimension_type j,
716 Coefficient_traits::const_reference numer,
717 Coefficient_traits::const_reference denom) {
718 // Private method: the caller has to ensure the following.
719 PPL_ASSERT(i <= space_dimension() && j <= space_dimension() && i != j);
720 PPL_ASSERT(denom != 0);
721 PPL_DIRTY_TEMP(N, k);
722 div_round_up(k, numer, denom);
723 add_dbm_constraint(i, j, k);
724 }
725
726 template <typename T>
727 inline void
time_elapse_assign(const BD_Shape & y)728 BD_Shape<T>::time_elapse_assign(const BD_Shape& y) {
729 // Dimension-compatibility check.
730 if (space_dimension() != y.space_dimension()) {
731 throw_dimension_incompatible("time_elapse_assign(y)", y);
732 }
733 // Compute time-elapse on polyhedra.
734 // TODO: provide a direct implementation.
735 C_Polyhedron ph_x(constraints());
736 C_Polyhedron ph_y(y.constraints());
737 ph_x.time_elapse_assign(ph_y);
738 BD_Shape<T> x(ph_x);
739 m_swap(x);
740 PPL_ASSERT(OK());
741 }
742
743 template <typename T>
744 inline bool
strictly_contains(const BD_Shape & y) const745 BD_Shape<T>::strictly_contains(const BD_Shape& y) const {
746 const BD_Shape<T>& x = *this;
747 return x.contains(y) && !y.contains(x);
748 }
749
750 template <typename T>
751 inline bool
upper_bound_assign_if_exact(const BD_Shape & y)752 BD_Shape<T>::upper_bound_assign_if_exact(const BD_Shape& y) {
753 if (space_dimension() != y.space_dimension()) {
754 throw_dimension_incompatible("upper_bound_assign_if_exact(y)", y);
755 }
756 #if 0
757 return BFT00_upper_bound_assign_if_exact(y);
758 #else
759 const bool integer_upper_bound = false;
760 return BHZ09_upper_bound_assign_if_exact<integer_upper_bound>(y);
761 #endif
762 }
763
764 template <typename T>
765 inline bool
integer_upper_bound_assign_if_exact(const BD_Shape & y)766 BD_Shape<T>::integer_upper_bound_assign_if_exact(const BD_Shape& y) {
767 PPL_COMPILE_TIME_CHECK(std::numeric_limits<T>::is_integer,
768 "BD_Shape<T>::integer_upper_bound_assign_if_exact(y):"
769 " T in not an integer datatype.");
770 if (space_dimension() != y.space_dimension()) {
771 throw_dimension_incompatible("integer_upper_bound_assign_if_exact(y)", y);
772 }
773 const bool integer_upper_bound = true;
774 return BHZ09_upper_bound_assign_if_exact<integer_upper_bound>(y);
775 }
776
777 template <typename T>
778 inline void
779 BD_Shape<T>
remove_higher_space_dimensions(const dimension_type new_dimension)780 ::remove_higher_space_dimensions(const dimension_type new_dimension) {
781 // Dimension-compatibility check: the variable having
782 // maximum index is the one occurring last in the set.
783 const dimension_type space_dim = space_dimension();
784 if (new_dimension > space_dim) {
785 throw_dimension_incompatible("remove_higher_space_dimensions(nd)",
786 new_dimension);
787 }
788
789 // The removal of no dimensions from any BDS is a no-op.
790 // Note that this case also captures the only legal removal of
791 // dimensions from a zero-dim space BDS.
792 if (new_dimension == space_dim) {
793 PPL_ASSERT(OK());
794 return;
795 }
796
797 // Shortest-path closure is necessary as in remove_space_dimensions().
798 shortest_path_closure_assign();
799 dbm.resize_no_copy(new_dimension + 1);
800
801 // Shortest-path closure is maintained.
802 // TODO: see whether or not reduction can be (efficiently!) maintained too.
803 if (marked_shortest_path_reduced()) {
804 reset_shortest_path_reduced();
805 }
806
807 // If we removed _all_ dimensions from a non-empty BDS,
808 // the zero-dim universe BDS has been obtained.
809 if (new_dimension == 0 && !marked_empty()) {
810 set_zero_dim_univ();
811 }
812 PPL_ASSERT(OK());
813 }
814
815 template <typename T>
816 void
wrap_assign(const Variables_Set & vars,Bounded_Integer_Type_Width w,Bounded_Integer_Type_Representation r,Bounded_Integer_Type_Overflow o,const Constraint_System * cs_p,unsigned complexity_threshold,bool wrap_individually)817 BD_Shape<T>::wrap_assign(const Variables_Set& vars,
818 Bounded_Integer_Type_Width w,
819 Bounded_Integer_Type_Representation r,
820 Bounded_Integer_Type_Overflow o,
821 const Constraint_System* cs_p,
822 unsigned complexity_threshold,
823 bool wrap_individually) {
824 Implementation::wrap_assign(*this,
825 vars, w, r, o, cs_p,
826 complexity_threshold, wrap_individually,
827 "BD_Shape");
828 }
829
830 template <typename T>
831 inline void
CC76_extrapolation_assign(const BD_Shape & y,unsigned * tp)832 BD_Shape<T>::CC76_extrapolation_assign(const BD_Shape& y, unsigned* tp) {
833 static N stop_points[] = {
834 N(-2, ROUND_UP),
835 N(-1, ROUND_UP),
836 N( 0, ROUND_UP),
837 N( 1, ROUND_UP),
838 N( 2, ROUND_UP)
839 };
840 CC76_extrapolation_assign(y,
841 stop_points,
842 stop_points
843 + sizeof(stop_points)/sizeof(stop_points[0]),
844 tp);
845 }
846
847 template <typename T>
848 inline void
H79_widening_assign(const BD_Shape & y,unsigned * tp)849 BD_Shape<T>::H79_widening_assign(const BD_Shape& y, unsigned* tp) {
850 // Compute the H79 widening on polyhedra.
851 // TODO: provide a direct implementation.
852 C_Polyhedron ph_x(constraints());
853 C_Polyhedron ph_y(y.constraints());
854 ph_x.H79_widening_assign(ph_y, tp);
855 BD_Shape x(ph_x);
856 m_swap(x);
857 PPL_ASSERT(OK());
858 }
859
860 template <typename T>
861 inline void
widening_assign(const BD_Shape & y,unsigned * tp)862 BD_Shape<T>::widening_assign(const BD_Shape& y, unsigned* tp) {
863 H79_widening_assign(y, tp);
864 }
865
866 template <typename T>
867 inline void
limited_H79_extrapolation_assign(const BD_Shape & y,const Constraint_System & cs,unsigned * tp)868 BD_Shape<T>::limited_H79_extrapolation_assign(const BD_Shape& y,
869 const Constraint_System& cs,
870 unsigned* tp) {
871 // Compute the limited H79 extrapolation on polyhedra.
872 // TODO: provide a direct implementation.
873 C_Polyhedron ph_x(constraints());
874 C_Polyhedron ph_y(y.constraints());
875 ph_x.limited_H79_extrapolation_assign(ph_y, cs, tp);
876 BD_Shape x(ph_x);
877 m_swap(x);
878 PPL_ASSERT(OK());
879 }
880
881 template <typename T>
882 inline memory_size_type
total_memory_in_bytes() const883 BD_Shape<T>::total_memory_in_bytes() const {
884 return sizeof(*this) + external_memory_in_bytes();
885 }
886
887 template <typename T>
888 inline int32_t
hash_code() const889 BD_Shape<T>::hash_code() const {
890 return hash_code_from_dimension(space_dimension());
891 }
892
893 template <typename T>
894 template <typename Interval_Info>
895 inline void
generalized_refine_with_linear_form_inequality(const Linear_Form<Interval<T,Interval_Info>> & left,const Linear_Form<Interval<T,Interval_Info>> & right,const Relation_Symbol relsym)896 BD_Shape<T>::generalized_refine_with_linear_form_inequality(
897 const Linear_Form<Interval<T, Interval_Info> >& left,
898 const Linear_Form<Interval<T, Interval_Info> >& right,
899 const Relation_Symbol relsym) {
900 switch (relsym) {
901 case EQUAL:
902 // TODO: see if we can handle this case more efficiently.
903 refine_with_linear_form_inequality(left, right);
904 refine_with_linear_form_inequality(right, left);
905 break;
906 case LESS_THAN:
907 case LESS_OR_EQUAL:
908 refine_with_linear_form_inequality(left, right);
909 break;
910 case GREATER_THAN:
911 case GREATER_OR_EQUAL:
912 refine_with_linear_form_inequality(right, left);
913 break;
914 case NOT_EQUAL:
915 break;
916 default:
917 PPL_UNREACHABLE;
918 }
919 }
920
921 template <typename T>
922 template <typename Interval_Info>
923 inline void
924 BD_Shape<T>
refine_fp_interval_abstract_store(Box<Interval<T,Interval_Info>> & store) const925 ::refine_fp_interval_abstract_store(Box<Interval<T, Interval_Info> >&
926 store) const {
927
928 // Check that T is a floating point type.
929 PPL_COMPILE_TIME_CHECK(!std::numeric_limits<T>::is_exact,
930 "BD_Shape<T>::refine_fp_interval_abstract_store:"
931 " T not a floating point type.");
932
933 typedef Interval<T, Interval_Info> FP_Interval_Type;
934 store.intersection_assign(Box<FP_Interval_Type>(*this));
935 }
936
937 template <typename T>
938 inline void
drop_some_non_integer_points_helper(N & elem)939 BD_Shape<T>::drop_some_non_integer_points_helper(N& elem) {
940 if (!is_integer(elem)) {
941 Result r = floor_assign_r(elem, elem, ROUND_DOWN);
942 PPL_USED(r);
943 PPL_ASSERT(r == V_EQ);
944 reset_shortest_path_closed();
945 }
946 }
947
948 /*! \relates BD_Shape */
949 template <typename T>
950 inline void
swap(BD_Shape<T> & x,BD_Shape<T> & y)951 swap(BD_Shape<T>& x, BD_Shape<T>& y) {
952 x.m_swap(y);
953 }
954
955 } // namespace Parma_Polyhedra_Library
956
957 #endif // !defined(PPL_BD_Shape_inlines_hh)
958