1 /* Interval boundary 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_Boundary_defs_hh
25 #define PPL_Boundary_defs_hh 1
26 
27 #include "Checked_Number_defs.hh"
28 
29 namespace Parma_Polyhedra_Library {
30 
31 namespace Boundary_NS {
32 
33 struct Property {
34   enum Type {
35     SPECIAL_,
36     OPEN_
37   };
38   typedef bool Value;
39   static const Value default_value = true;
40   static const Value unsupported_value = false;
PropertyParma_Polyhedra_Library::Boundary_NS::Property41   Property(Type t)
42     : type(t) {
43   }
44   Type type;
45 };
46 
47 static const Property SPECIAL(Property::SPECIAL_);
48 static const Property OPEN(Property::OPEN_);
49 
50 enum Boundary_Type {
51   LOWER = ROUND_DOWN,
52   UPPER = ROUND_UP
53 };
54 
55 inline Rounding_Dir
round_dir_check(Boundary_Type t,bool check=false)56 round_dir_check(Boundary_Type t, bool check = false) {
57   if (check) {
58     return static_cast<Rounding_Dir>(t) | ROUND_STRICT_RELATION;
59   }
60   else {
61     return static_cast<Rounding_Dir>(t);
62   }
63 }
64 
65 template <typename T, typename Info>
66 inline Result
special_set_boundary_infinity(Boundary_Type type,T &,Info & info)67 special_set_boundary_infinity(Boundary_Type type, T&, Info& info) {
68   PPL_ASSERT(Info::store_special);
69   info.set_boundary_property(type, SPECIAL);
70   return V_EQ;
71 }
72 
73 template <typename T, typename Info>
74 inline bool
special_is_open(Boundary_Type,const T &,const Info &)75 special_is_open(Boundary_Type, const T&, const Info&) {
76   return !Info::may_contain_infinity;
77 }
78 
79 template <typename T, typename Info>
80 inline bool
normal_is_open(Boundary_Type type,const T & x,const Info & info)81 normal_is_open(Boundary_Type type, const T& x, const Info& info) {
82   if (Info::store_open) {
83     return info.get_boundary_property(type, OPEN);
84   }
85   else {
86     return !Info::store_special && !Info::may_contain_infinity
87       && normal_is_boundary_infinity(type, x, info);
88   }
89 }
90 
91 template <typename T, typename Info>
92 inline bool
is_open(Boundary_Type type,const T & x,const Info & info)93 is_open(Boundary_Type type, const T& x, const Info& info) {
94   if (Info::store_open) {
95     return info.get_boundary_property(type, OPEN);
96   }
97   else {
98     return !Info::may_contain_infinity
99       && is_boundary_infinity(type, x, info);
100   }
101 }
102 
103 template <typename T, typename Info>
104 inline Result
set_unbounded(Boundary_Type type,T & x,Info & info)105 set_unbounded(Boundary_Type type, T& x, Info& info) {
106   PPL_COMPILE_TIME_CHECK(Info::store_special
107                          || std::numeric_limits<T>::is_bounded
108                          || std::numeric_limits<T>::has_infinity,
109                          "unbounded is not representable");
110   Result r;
111   if (Info::store_special) {
112     r = special_set_boundary_infinity(type, x, info);
113   }
114   else if (type == LOWER) {
115     r = assign_r(x, MINUS_INFINITY, ROUND_UP);
116   }
117   else {
118     r = assign_r(x, PLUS_INFINITY, ROUND_DOWN);
119   }
120   if (result_relation(r) == VR_EQ && !Info::may_contain_infinity) {
121     info.set_boundary_property(type, OPEN);
122   }
123   return r;
124 }
125 
126 template <typename T, typename Info>
127 inline Result
set_minus_infinity(Boundary_Type type,T & x,Info & info,bool open=false)128 set_minus_infinity(Boundary_Type type, T& x, Info& info, bool open = false) {
129   if (open) {
130     PPL_ASSERT(type == LOWER);
131   }
132   else {
133     PPL_ASSERT(Info::may_contain_infinity);
134   }
135   Result r;
136   if (Info::store_special) {
137     PPL_ASSERT(type == LOWER);
138     r = special_set_boundary_infinity(type, x, info);
139   }
140   else {
141     r = assign_r(x, MINUS_INFINITY, round_dir_check(type));
142     PPL_ASSERT(result_representable(r));
143   }
144   if (open || result_relation(r) != VR_EQ) {
145     info.set_boundary_property(type, OPEN);
146   }
147   return r;
148 }
149 
150 template <typename T, typename Info>
151 inline Result
set_plus_infinity(Boundary_Type type,T & x,Info & info,bool open=false)152 set_plus_infinity(Boundary_Type type, T& x, Info& info, bool open = false) {
153   if (open) {
154     PPL_ASSERT(type == UPPER);
155   }
156   else {
157     PPL_ASSERT(Info::may_contain_infinity);
158   }
159   Result r;
160   if (Info::store_special) {
161     PPL_ASSERT(type == UPPER);
162     r = special_set_boundary_infinity(type, x, info);
163   }
164   else {
165     r = assign_r(x, PLUS_INFINITY, round_dir_check(type));
166     PPL_ASSERT(result_representable(r));
167   }
168   if (open || result_relation(r) != VR_EQ) {
169     info.set_boundary_property(type, OPEN);
170   }
171   return r;
172 }
173 
174 template <typename T, typename Info>
175 inline Result
set_boundary_infinity(Boundary_Type type,T & x,Info & info,bool open=false)176 set_boundary_infinity(Boundary_Type type, T& x, Info& info, bool open = false) {
177   PPL_ASSERT(open || Info::may_contain_infinity);
178   Result r;
179   if (Info::store_special) {
180     r = special_set_boundary_infinity(type, x, info);
181   }
182   else if (type == LOWER) {
183     r = assign_r(x, MINUS_INFINITY, round_dir_check(type));
184   }
185   else {
186     r = assign_r(x, PLUS_INFINITY, round_dir_check(type));
187   }
188   PPL_ASSERT(result_representable(r));
189   if (open) {
190     info.set_boundary_property(type, OPEN);
191   }
192   return r;
193 }
194 
195 template <typename T, typename Info>
196 inline bool
is_domain_inf(Boundary_Type type,const T & x,const Info & info)197 is_domain_inf(Boundary_Type type, const T& x, const Info& info) {
198   if (Info::store_special && type == LOWER) {
199     return info.get_boundary_property(type, SPECIAL);
200   }
201   else if (std::numeric_limits<T>::has_infinity) {
202     return Parma_Polyhedra_Library::is_minus_infinity(x);
203   }
204   else if (std::numeric_limits<T>::is_bounded) {
205     return x == std::numeric_limits<T>::min();
206   }
207   else {
208     return false;
209   }
210 }
211 
212 template <typename T, typename Info>
213 inline bool
is_domain_sup(Boundary_Type type,const T & x,const Info & info)214 is_domain_sup(Boundary_Type type, const T& x, const Info& info) {
215   if (Info::store_special && type == UPPER) {
216     return info.get_boundary_property(type, SPECIAL);
217   }
218   else if (std::numeric_limits<T>::has_infinity) {
219     return Parma_Polyhedra_Library::is_plus_infinity(x);
220   }
221   else if (std::numeric_limits<T>::is_bounded) {
222       return x == std::numeric_limits<T>::max();
223   }
224   else {
225     return false;
226   }
227 }
228 
229 template <typename T, typename Info>
230 inline bool
normal_is_boundary_infinity(Boundary_Type type,const T & x,const Info &)231 normal_is_boundary_infinity(Boundary_Type type, const T& x, const Info&) {
232   if (!std::numeric_limits<T>::has_infinity) {
233     return false;
234   }
235   if (type == LOWER) {
236     return Parma_Polyhedra_Library::is_minus_infinity(x);
237   }
238   else {
239     return Parma_Polyhedra_Library::is_plus_infinity(x);
240   }
241 }
242 
243 template <typename T, typename Info>
244 inline bool
is_boundary_infinity(Boundary_Type type,const T & x,const Info & info)245 is_boundary_infinity(Boundary_Type type, const T& x, const Info& info) {
246   if (Info::store_special) {
247     return info.get_boundary_property(type, SPECIAL);
248   }
249   else {
250     return normal_is_boundary_infinity(type, x, info);
251   }
252 }
253 
254 template <typename T, typename Info>
255 inline bool
normal_is_reverse_infinity(Boundary_Type type,const T & x,const Info &)256 normal_is_reverse_infinity(Boundary_Type type, const T& x, const Info&) {
257   if (!Info::may_contain_infinity) {
258     return false;
259   }
260   else if (type == LOWER) {
261     return Parma_Polyhedra_Library::is_plus_infinity(x);
262   }
263   else {
264     return Parma_Polyhedra_Library::is_minus_infinity(x);
265   }
266 }
267 
268 template <typename T, typename Info>
269 inline bool
is_minus_infinity(Boundary_Type type,const T & x,const Info & info)270 is_minus_infinity(Boundary_Type type, const T& x, const Info& info) {
271   if (type == LOWER) {
272     if (Info::store_special) {
273       return info.get_boundary_property(type, SPECIAL);
274     }
275     else {
276       return normal_is_boundary_infinity(type, x, info);
277     }
278   }
279   else {
280     return !Info::store_special && normal_is_reverse_infinity(type, x, info);
281   }
282 }
283 
284 template <typename T, typename Info>
285 inline bool
is_plus_infinity(Boundary_Type type,const T & x,const Info & info)286 is_plus_infinity(Boundary_Type type, const T& x, const Info& info) {
287   if (type == UPPER) {
288     if (Info::store_special) {
289       return info.get_boundary_property(type, SPECIAL);
290     }
291     else {
292       return normal_is_boundary_infinity(type, x, info);
293     }
294   }
295   else {
296     return !Info::store_special && normal_is_reverse_infinity(type, x, info);
297   }
298 }
299 
300 template <typename T, typename Info>
301 inline bool
is_reverse_infinity(Boundary_Type type,const T & x,const Info & info)302 is_reverse_infinity(Boundary_Type type, const T& x, const Info& info) {
303   return normal_is_reverse_infinity(type, x, info);
304 }
305 
306 template <typename T, typename Info>
307 inline int
infinity_sign(Boundary_Type type,const T & x,const Info & info)308 infinity_sign(Boundary_Type type, const T& x, const Info& info) {
309   if (is_boundary_infinity(type, x, info)) {
310     return (type == LOWER) ? -1 : 1;
311   }
312   else if (is_reverse_infinity(type, x, info)) {
313     return (type == UPPER) ? -1 : 1;
314   }
315   else {
316     return 0;
317   }
318 }
319 
320 template <typename T, typename Info>
321 inline bool
is_boundary_infinity_closed(Boundary_Type type,const T & x,const Info & info)322 is_boundary_infinity_closed(Boundary_Type type, const T& x, const Info& info) {
323   return Info::may_contain_infinity
324     && !info.get_boundary_property(type, OPEN)
325     && is_boundary_infinity(type, x, info);
326 }
327 
328 template <typename Info>
329 inline bool
boundary_infinity_is_open(Boundary_Type type,const Info & info)330 boundary_infinity_is_open(Boundary_Type type, const Info& info) {
331   return !Info::may_contain_infinity
332     || info.get_boundary_property(type, OPEN);
333 }
334 
335 template <typename T, typename Info>
336 inline int
sgn_b(Boundary_Type type,const T & x,const Info & info)337 sgn_b(Boundary_Type type, const T& x, const Info& info) {
338   if (info.get_boundary_property(type, SPECIAL)) {
339     return (type == LOWER) ? -1 : 1;
340   }
341   else {
342     // The following Parma_Polyhedra_Library:: qualification is to work
343     // around a bug of GCC 4.0.x.
344     return Parma_Polyhedra_Library::sgn(x);
345   }
346 }
347 
348 template <typename T, typename Info>
349 inline int
sgn(Boundary_Type type,const T & x,const Info & info)350 sgn(Boundary_Type type, const T& x, const Info& info) {
351   int sign = sgn_b(type, x, info);
352   if (x == 0 && info.get_boundary_property(type, OPEN)) {
353     return (type == LOWER) ? -1 : 1;
354   }
355   else {
356     return sign;
357   }
358 }
359 
360 template <typename T1, typename Info1, typename T2, typename Info2>
361 inline bool
eq(Boundary_Type type1,const T1 & x1,const Info1 & info1,Boundary_Type type2,const T2 & x2,const Info2 & info2)362 eq(Boundary_Type type1, const T1& x1, const Info1& info1,
363    Boundary_Type type2, const T2& x2, const Info2& info2) {
364   if (type1 == type2) {
365     if (is_open(type1, x1, info1)
366         != is_open(type2, x2, info2)) {
367       return false;
368     }
369   }
370   else if (is_open(type1, x1, info1)
371            || is_open(type2, x2, info2)) {
372     return false;
373   }
374   if (is_minus_infinity(type1, x1, info1)) {
375     return is_minus_infinity(type2, x2, info2);
376   }
377   else if (is_plus_infinity(type1, x1, info1)) {
378     return is_plus_infinity(type2, x2, info2);
379   }
380   else if (is_minus_infinity(type2, x2, info2)
381            || is_plus_infinity(type2, x2, info2)) {
382     return false;
383   }
384   else {
385     return equal(x1, x2);
386   }
387 }
388 
389 template <typename T1, typename Info1, typename T2, typename Info2>
390 inline bool
lt(Boundary_Type type1,const T1 & x1,const Info1 & info1,Boundary_Type type2,const T2 & x2,const Info2 & info2)391 lt(Boundary_Type type1, const T1& x1, const Info1& info1,
392    Boundary_Type type2, const T2& x2, const Info2& info2) {
393   if (is_open(type1, x1, info1)) {
394     if (type1 == UPPER
395         && (type2 == LOWER
396             || !is_open(type2, x2, info2))) {
397       goto le;
398     }
399   }
400   else if (type2 == LOWER
401            && is_open(type2, x2, info2)) {
402   le:
403     if (is_minus_infinity(type1, x1, info1)
404         || is_plus_infinity(type2, x2, info2)) {
405       return true;
406     }
407     if (is_plus_infinity(type1, x1, info1)
408         || is_minus_infinity(type2, x2, info2)) {
409       return false;
410     }
411     else {
412       return less_or_equal(x1, x2);
413     }
414   }
415   if (is_plus_infinity(type1, x1, info1)
416       || is_minus_infinity(type2, x2, info2)) {
417     return false;
418   }
419   if (is_minus_infinity(type1, x1, info1)
420       || is_plus_infinity(type2, x2, info2)) {
421     return true;
422   }
423   else {
424     return less_than(x1, x2);
425   }
426 }
427 
428 template <typename T1, typename Info1, typename T2, typename Info2>
429 inline bool
gt(Boundary_Type type1,const T1 & x1,const Info1 & info1,Boundary_Type type2,const T2 & x2,const Info2 & info2)430 gt(Boundary_Type type1, const T1& x1, const Info1& info1,
431    Boundary_Type type2, const T2& x2, const Info2& info2) {
432   return lt(type2, x2, info2, type1, x1, info1);
433 }
434 
435 template <typename T1, typename Info1, typename T2, typename Info2>
436 inline bool
le(Boundary_Type type1,const T1 & x1,const Info1 & info1,Boundary_Type type2,const T2 & x2,const Info2 & info2)437 le(Boundary_Type type1, const T1& x1, const Info1& info1,
438    Boundary_Type type2, const T2& x2, const Info2& info2) {
439   return !gt(type1, x1, info1, type2, x2, info2);
440 }
441 
442 template <typename T1, typename Info1, typename T2, typename Info2>
443 inline bool
ge(Boundary_Type type1,const T1 & x1,const Info1 & info1,Boundary_Type type2,const T2 & x2,const Info2 & info2)444 ge(Boundary_Type type1, const T1& x1, const Info1& info1,
445    Boundary_Type type2, const T2& x2, const Info2& info2) {
446   return !lt(type1, x1, info1, type2, x2, info2);
447 }
448 
449 template <typename T, typename Info>
450 inline Result
adjust_boundary(Boundary_Type type,T & x,Info & info,bool open,Result r)451 adjust_boundary(Boundary_Type type, T& x, Info& info,
452                 bool open, Result r) {
453   r = result_relation_class(r);
454   if (type == LOWER) {
455     switch (r) {
456     case V_GT_MINUS_INFINITY:
457       open = true;
458       /* Fall through */
459     case V_EQ_MINUS_INFINITY:
460       if (!Info::store_special) {
461         return r;
462       }
463       if (open) {
464         info.set_boundary_property(type, OPEN);
465       }
466       return special_set_boundary_infinity(type, x, info);
467     case V_GT:
468       open = true;
469       /* Fall through */
470     case V_GE:
471     case V_EQ:
472       if (open) {
473         info.set_boundary_property(type, OPEN);
474       }
475       return r;
476     default:
477       PPL_UNREACHABLE;
478       return V_NAN;
479     }
480   }
481   else {
482     switch (r) {
483     case V_LT_PLUS_INFINITY:
484       open = true;
485       /* Fall through */
486     case V_EQ_PLUS_INFINITY:
487       if (!Info::store_special) {
488         return r;
489       }
490       if (open) {
491         info.set_boundary_property(type, OPEN);
492       }
493       return special_set_boundary_infinity(type, x, info);
494     case V_LT:
495       open = true;
496       /* Fall through */
497     case V_LE:
498     case V_EQ:
499       if (open) {
500         info.set_boundary_property(type, OPEN);
501       }
502       return r;
503     default:
504       PPL_UNREACHABLE;
505       return V_NAN;
506     }
507   }
508 }
509 
510 template <typename To, typename To_Info, typename T, typename Info>
511 inline Result
complement(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type,const T & x,const Info & info)512 complement(Boundary_Type to_type, To& to, To_Info& to_info,
513            Boundary_Type type, const T& x, const Info& info) {
514   PPL_ASSERT(to_type != type);
515   bool should_shrink;
516   if (info.get_boundary_property(type, SPECIAL)) {
517     should_shrink = !special_is_open(type, x, info);
518     if (type == LOWER) {
519       return set_minus_infinity(to_type, to, to_info, should_shrink);
520     }
521     else {
522       return set_plus_infinity(to_type, to, to_info, should_shrink);
523     }
524   }
525   should_shrink = !normal_is_open(type, x, info);
526   bool check = (To_Info::check_inexact || (!should_shrink && To_Info::store_open));
527   Result r = assign_r(to, x, round_dir_check(to_type, check));
528   return adjust_boundary(to_type, to, to_info, should_shrink, r);
529 }
530 
531 template <typename To, typename To_Info, typename T, typename Info>
532 inline Result
assign(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type,const T & x,const Info & info,bool should_shrink=false)533 assign(Boundary_Type to_type, To& to, To_Info& to_info,
534        Boundary_Type type, const T& x, const Info& info,
535        bool should_shrink = false) {
536   PPL_ASSERT(to_type == type);
537   if (info.get_boundary_property(type, SPECIAL)) {
538     should_shrink = (should_shrink || special_is_open(type, x, info));
539     return set_boundary_infinity(to_type, to, to_info, should_shrink);
540   }
541   should_shrink = (should_shrink || normal_is_open(type, x, info));
542   const bool check
543     = (To_Info::check_inexact || (!should_shrink && To_Info::store_open));
544   const Result r = assign_r(to, x, round_dir_check(to_type, check));
545   return adjust_boundary(to_type, to, to_info, should_shrink, r);
546 }
547 
548 template <typename To, typename To_Info, typename T, typename Info>
549 inline Result
min_assign(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type,const T & x,const Info & info)550 min_assign(Boundary_Type to_type, To& to, To_Info& to_info,
551            Boundary_Type type, const T& x, const Info& info) {
552   if (lt(type, x, info, to_type, to, to_info)) {
553     to_info.clear_boundary_properties(to_type);
554     return assign(to_type, to, to_info, type, x, info);
555   }
556   return V_EQ;
557 }
558 
559 template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
560 inline Result
min_assign(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type1,const T1 & x1,const Info1 & info1,Boundary_Type type2,const T2 & x2,const Info2 & info2)561 min_assign(Boundary_Type to_type, To& to, To_Info& to_info,
562            Boundary_Type type1, const T1& x1, const Info1& info1,
563            Boundary_Type type2, const T2& x2, const Info2& info2) {
564   if (lt(type1, x1, info1, type2, x2, info2)) {
565     return assign(to_type, to, to_info, type1, x1, info1);
566   }
567   else {
568     return assign(to_type, to, to_info, type2, x2, info2);
569   }
570 }
571 
572 template <typename To, typename To_Info, typename T, typename Info>
573 inline Result
max_assign(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type,const T & x,const Info & info)574 max_assign(Boundary_Type to_type, To& to, To_Info& to_info,
575            Boundary_Type type, const T& x, const Info& info) {
576   if (gt(type, x, info, to_type, to, to_info)) {
577     to_info.clear_boundary_properties(to_type);
578     return assign(to_type, to, to_info, type, x, info);
579   }
580   return V_EQ;
581 }
582 
583 template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
584 inline Result
max_assign(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type1,const T1 & x1,const Info1 & info1,Boundary_Type type2,const T2 & x2,const Info2 & info2)585 max_assign(Boundary_Type to_type, To& to, To_Info& to_info,
586            Boundary_Type type1, const T1& x1, const Info1& info1,
587            Boundary_Type type2, const T2& x2, const Info2& info2) {
588   if (gt(type1, x1, info1, type2, x2, info2)) {
589     return assign(to_type, to, to_info, type1, x1, info1);
590   }
591   else {
592     return assign(to_type, to, to_info, type2, x2, info2);
593   }
594 }
595 
596 template <typename To, typename To_Info, typename T, typename Info>
597 inline Result
neg_assign(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type,const T & x,const Info & info)598 neg_assign(Boundary_Type to_type, To& to, To_Info& to_info,
599            Boundary_Type type, const T& x, const Info& info) {
600   PPL_ASSERT(to_type != type);
601   bool should_shrink;
602   if (info.get_boundary_property(type, SPECIAL)) {
603     should_shrink = special_is_open(type, x, info);
604     return set_boundary_infinity(to_type, to, to_info, should_shrink);
605   }
606   should_shrink = normal_is_open(type, x, info);
607   bool check = (To_Info::check_inexact || (!should_shrink && To_Info::store_open));
608   Result r = neg_assign_r(to, x, round_dir_check(to_type, check));
609   return adjust_boundary(to_type, to, to_info, should_shrink, r);
610 }
611 
612 template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
613 inline Result
add_assign(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type1,const T1 & x1,const Info1 & info1,Boundary_Type type2,const T2 & x2,const Info2 & info2)614 add_assign(Boundary_Type to_type, To& to, To_Info& to_info,
615            Boundary_Type type1, const T1& x1, const Info1& info1,
616            Boundary_Type type2, const T2& x2, const Info2& info2) {
617   PPL_ASSERT(type1 == type2);
618   bool should_shrink;
619   if (is_boundary_infinity(type1, x1, info1)) {
620     should_shrink = (boundary_infinity_is_open(type1, info1)
621                      && !is_boundary_infinity_closed(type2, x2, info2));
622     return set_boundary_infinity(to_type, to, to_info, should_shrink);
623   }
624   else if (is_boundary_infinity(type2, x2, info2)) {
625     should_shrink = (boundary_infinity_is_open(type2, info2)
626                      && !is_boundary_infinity_closed(type1, x1, info1));
627     return set_boundary_infinity(to_type, to, to_info, should_shrink);
628   }
629   should_shrink = (normal_is_open(type1, x1, info1)
630                    || normal_is_open(type2, x2, info2));
631   bool check = (To_Info::check_inexact || (!should_shrink && To_Info::store_open));
632   // FIXME: extended handling is not needed
633   Result r = add_assign_r(to, x1, x2, round_dir_check(to_type, check));
634   return adjust_boundary(to_type, to, to_info, should_shrink, r);
635 }
636 
637 template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
638 inline Result
sub_assign(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type1,const T1 & x1,const Info1 & info1,Boundary_Type type2,const T2 & x2,const Info2 & info2)639 sub_assign(Boundary_Type to_type, To& to, To_Info& to_info,
640            Boundary_Type type1, const T1& x1, const Info1& info1,
641            Boundary_Type type2, const T2& x2, const Info2& info2) {
642   PPL_ASSERT(type1 != type2);
643   bool should_shrink;
644   if (is_boundary_infinity(type1, x1, info1)) {
645     should_shrink = (boundary_infinity_is_open(type1, info1)
646                      && !is_boundary_infinity_closed(type2, x2, info2));
647     return set_boundary_infinity(to_type, to, to_info, should_shrink);
648   }
649   else if (is_boundary_infinity(type2, x2, info2)) {
650     should_shrink = (boundary_infinity_is_open(type2, info2)
651                      && !is_boundary_infinity_closed(type1, x1, info1));
652     return set_boundary_infinity(to_type, to, to_info, should_shrink);
653   }
654   should_shrink = (normal_is_open(type1, x1, info1)
655                    || normal_is_open(type2, x2, info2));
656   bool check = (To_Info::check_inexact || (!should_shrink && To_Info::store_open));
657   // FIXME: extended handling is not needed
658   Result r = sub_assign_r(to, x1, x2, round_dir_check(to_type, check));
659   return adjust_boundary(to_type, to, to_info, should_shrink, r);
660 }
661 
662 template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
663 inline Result
mul_assign(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type1,const T1 & x1,const Info1 & info1,Boundary_Type type2,const T2 & x2,const Info2 & info2)664 mul_assign(Boundary_Type to_type, To& to, To_Info& to_info,
665            Boundary_Type type1, const T1& x1, const Info1& info1,
666            Boundary_Type type2, const T2& x2, const Info2& info2) {
667   bool should_shrink;
668   if (is_boundary_infinity(type1, x1, info1)) {
669     should_shrink = (boundary_infinity_is_open(type1, info1)
670                      && !is_boundary_infinity_closed(type2, x2, info2));
671     return set_boundary_infinity(to_type, to, to_info, should_shrink);
672   }
673   else if (is_boundary_infinity(type2, x2, info2)) {
674     should_shrink = (boundary_infinity_is_open(type2, info2)
675                      && !is_boundary_infinity_closed(type1, x1, info1));
676     return set_boundary_infinity(to_type, to, to_info, should_shrink);
677   }
678   should_shrink = (normal_is_open(type1, x1, info1)
679                    || normal_is_open(type2, x2, info2));
680   bool check = (To_Info::check_inexact || (!should_shrink && To_Info::store_open));
681   PPL_ASSERT(x1 != Constant<0>::value && x2 != Constant<0>::value);
682   // FIXME: extended handling is not needed
683   Result r = mul_assign_r(to, x1, x2, round_dir_check(to_type, check));
684   return adjust_boundary(to_type, to, to_info, should_shrink, r);
685 }
686 
687 template <typename To, typename To_Info>
688 inline Result
set_zero(Boundary_Type to_type,To & to,To_Info & to_info,bool should_shrink)689 set_zero(Boundary_Type to_type, To& to, To_Info& to_info, bool should_shrink) {
690   bool check = (To_Info::check_inexact || (!should_shrink && To_Info::store_open));
691   Result r = assign_r(to, Constant<0>::value, round_dir_check(to_type, check));
692   return adjust_boundary(to_type, to, to_info, should_shrink, r);
693 }
694 
695 template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
696 inline Result
mul_assign_z(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type1,const T1 & x1,const Info1 & info1,int x1s,Boundary_Type type2,const T2 & x2,const Info2 & info2,int x2s)697 mul_assign_z(Boundary_Type to_type, To& to, To_Info& to_info,
698              Boundary_Type type1, const T1& x1, const Info1& info1, int x1s,
699              Boundary_Type type2, const T2& x2, const Info2& info2, int x2s) {
700   bool should_shrink;
701   if (x1s != 0) {
702     if (x2s != 0) {
703       return mul_assign(to_type, to, to_info,
704                         type1, x1, info1,
705                         type2, x2, info2);
706     }
707     else {
708       should_shrink = info2.get_boundary_property(type2, OPEN);
709     }
710   }
711   else {
712     should_shrink = (info1.get_boundary_property(type1, OPEN)
713                      && (x2s != 0 || info2.get_boundary_property(type2, OPEN)));
714   }
715   return set_zero(to_type, to, to_info, should_shrink);
716 }
717 
718 template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
719 inline Result
div_assign(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type1,const T1 & x1,const Info1 & info1,Boundary_Type type2,const T2 & x2,const Info2 & info2)720 div_assign(Boundary_Type to_type, To& to, To_Info& to_info,
721            Boundary_Type type1, const T1& x1, const Info1& info1,
722            Boundary_Type type2, const T2& x2, const Info2& info2) {
723   bool should_shrink;
724   if (is_boundary_infinity(type1, x1, info1)) {
725     should_shrink = boundary_infinity_is_open(type1, info1);
726     return set_boundary_infinity(to_type, to, to_info, should_shrink);
727   }
728   else if (is_boundary_infinity(type2, x2, info2)) {
729     should_shrink = boundary_infinity_is_open(type2, info2);
730     return set_zero(to_type, to, to_info, should_shrink);
731   }
732   should_shrink = (normal_is_open(type1, x1, info1)
733                    || normal_is_open(type2, x2, info2));
734   bool check = (To_Info::check_inexact || (!should_shrink && To_Info::store_open));
735   PPL_ASSERT(x1 != Constant<0>::value && x2 != Constant<0>::value);
736   // FIXME: extended handling is not needed
737   Result r = div_assign_r(to, x1, x2, round_dir_check(to_type, check));
738   return adjust_boundary(to_type, to, to_info, should_shrink, r);
739 }
740 
741 
742 template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
743 inline Result
div_assign_z(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type1,const T1 & x1,const Info1 & info1,int x1s,Boundary_Type type2,const T2 & x2,const Info2 & info2,int x2s)744 div_assign_z(Boundary_Type to_type, To& to, To_Info& to_info,
745              Boundary_Type type1, const T1& x1, const Info1& info1, int x1s,
746              Boundary_Type type2, const T2& x2, const Info2& info2, int x2s) {
747   if (x1s != 0) {
748     if (x2s != 0) {
749       return div_assign(to_type, to, to_info,
750                         type1, x1, info1,
751                         type2, x2, info2);
752     }
753     else {
754       return set_boundary_infinity(to_type, to, to_info, true);
755     }
756   }
757   else {
758     bool should_shrink = info1.get_boundary_property(type1, OPEN)
759       && !is_boundary_infinity_closed(type2, x2, info2);
760     return set_zero(to_type, to, to_info, should_shrink);
761   }
762 }
763 
764 template <typename To, typename To_Info, typename T, typename Info>
765 inline Result
umod_2exp_assign(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type,const T & x,const Info & info,unsigned int exp)766 umod_2exp_assign(Boundary_Type to_type, To& to, To_Info& to_info,
767                  Boundary_Type type, const T& x, const Info& info,
768                  unsigned int exp) {
769   PPL_ASSERT(to_type == type);
770   bool should_shrink;
771   if (is_boundary_infinity(type, x, info)) {
772     should_shrink = boundary_infinity_is_open(type, info);
773     return set_boundary_infinity(to_type, to, to_info, should_shrink);
774   }
775   should_shrink = normal_is_open(type, x, info);
776   bool check = (To_Info::check_inexact || (!should_shrink && To_Info::store_open));
777   Result r = umod_2exp_assign_r(to, x, exp, round_dir_check(to_type, check));
778   return adjust_boundary(to_type, to, to_info, should_shrink, r);
779 }
780 
781 template <typename To, typename To_Info, typename T, typename Info>
782 inline Result
smod_2exp_assign(Boundary_Type to_type,To & to,To_Info & to_info,Boundary_Type type,const T & x,const Info & info,unsigned int exp)783 smod_2exp_assign(Boundary_Type to_type, To& to, To_Info& to_info,
784                  Boundary_Type type, const T& x, const Info& info,
785                  unsigned int exp) {
786   PPL_ASSERT(to_type == type);
787   bool should_shrink;
788   if (is_boundary_infinity(type, x, info)) {
789     should_shrink = boundary_infinity_is_open(type, info);
790     return set_boundary_infinity(to_type, to, to_info, should_shrink);
791   }
792   should_shrink = normal_is_open(type, x, info);
793   bool check = (To_Info::check_inexact || (!should_shrink && To_Info::store_open));
794   Result r = smod_2exp_assign_r(to, x, exp, round_dir_check(to_type, check));
795   return adjust_boundary(to_type, to, to_info, should_shrink, r);
796 }
797 
798 } // namespace Boundary_NS
799 
800 } // namespace Parma_Polyhedra_Library
801 
802 #endif // !defined(PPL_Boundary_defs_hh)
803