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