PPL  1.2
Box_templates.hh
Go to the documentation of this file.
1 /* Box class implementation: non-inline template functions.
2  Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3  Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #ifndef PPL_Box_templates_hh
25 #define PPL_Box_templates_hh 1
26 
27 #include "Variables_Set_defs.hh"
30 #include "Generator_System_defs.hh"
34 #include "Polyhedron_defs.hh"
35 #include "Grid_defs.hh"
36 #include "Interval_defs.hh"
37 #include "Linear_Form_defs.hh"
38 #include "BD_Shape_defs.hh"
39 #include "Octagonal_Shape_defs.hh"
40 #include "MIP_Problem_defs.hh"
41 #include "Rational_Interval.hh"
42 #include <vector>
43 #include <map>
44 #include <iostream>
45 
46 namespace Parma_Polyhedra_Library {
47 
48 template <typename ITV>
49 inline
51  : seq(check_space_dimension_overflow(num_dimensions,
53  "PPL::Box::",
54  "Box(n, k)",
55  "n exceeds the maximum "
56  "allowed space dimension")),
57  status() {
58  // In a box that is marked empty the intervals are completely
59  // meaningless: we exploit this by avoiding their initialization.
60  if (kind == UNIVERSE) {
61  for (dimension_type i = num_dimensions; i-- > 0; ) {
62  seq[i].assign(UNIVERSE);
63  }
65  }
66  else {
67  set_empty();
68  }
69  PPL_ASSERT(OK());
70 }
71 
72 template <typename ITV>
73 inline
75  : seq(check_space_dimension_overflow(cs.space_dimension(),
77  "PPL::Box::",
78  "Box(cs)",
79  "cs exceeds the maximum "
80  "allowed space dimension")),
81  status() {
82  // FIXME: check whether we can avoid the double initialization.
83  for (dimension_type i = cs.space_dimension(); i-- > 0; ) {
84  seq[i].assign(UNIVERSE);
85  }
87 }
88 
89 template <typename ITV>
90 inline
92  : seq(check_space_dimension_overflow(cgs.space_dimension(),
94  "PPL::Box::",
95  "Box(cgs)",
96  "cgs exceeds the maximum "
97  "allowed space dimension")),
98  status() {
99  // FIXME: check whether we can avoid the double initialization.
100  for (dimension_type i = cgs.space_dimension(); i-- > 0; ) {
101  seq[i].assign(UNIVERSE);
102  }
104 }
105 
106 template <typename ITV>
107 template <typename Other_ITV>
108 inline
110  : seq(y.space_dimension()),
111  // FIXME: why the following does not work?
112  // status(y.status) {
113  status() {
114  // FIXME: remove when the above is fixed.
115  if (y.marked_empty()) {
116  set_empty();
117  }
118 
119  if (!y.marked_empty()) {
120  for (dimension_type k = y.space_dimension(); k-- > 0; ) {
121  seq[k].assign(y.seq[k]);
122  }
123  }
124  PPL_ASSERT(OK());
125 }
126 
127 template <typename ITV>
129  : seq(check_space_dimension_overflow(gs.space_dimension(),
131  "PPL::Box::",
132  "Box(gs)",
133  "gs exceeds the maximum "
134  "allowed space dimension")),
135  status() {
136  const Generator_System::const_iterator gs_begin = gs.begin();
137  const Generator_System::const_iterator gs_end = gs.end();
138  if (gs_begin == gs_end) {
139  // An empty generator system defines the empty box.
140  set_empty();
141  return;
142  }
143 
144  // The empty flag will be meaningful, whatever happens from now on.
146 
147  const dimension_type space_dim = space_dimension();
148  PPL_DIRTY_TEMP(mpq_class, q);
149  bool point_seen = false;
150  // Going through all the points.
152  gs_i = gs_begin; gs_i != gs_end; ++gs_i) {
153  const Generator& g = *gs_i;
154  if (g.is_point()) {
155  const Coefficient& d = g.divisor();
156  if (point_seen) {
157  // This is not the first point: `seq' already contains valid values.
158  // TODO: If the variables in the expression that have coefficient 0
159  // have no effect on seq[i], this loop can be optimized using
160  // Generator::expr_type::const_iterator.
161  for (dimension_type i = space_dim; i-- > 0; ) {
162  assign_r(q.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED);
163  assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
164  q.canonicalize();
165  PPL_DIRTY_TEMP(ITV, iq);
166  iq.build(i_constraint(EQUAL, q));
167  seq[i].join_assign(iq);
168  }
169  }
170  else {
171  // This is the first point seen: initialize `seq'.
172  point_seen = true;
173  // TODO: If the variables in the expression that have coefficient 0
174  // have no effect on seq[i], this loop can be optimized using
175  // Generator::expr_type::const_iterator.
176  for (dimension_type i = space_dim; i-- > 0; ) {
177  assign_r(q.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED);
178  assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
179  q.canonicalize();
180  seq[i].build(i_constraint(EQUAL, q));
181  }
182  }
183  }
184  }
185 
186  if (!point_seen) {
187  // The generator system is not empty, but contains no points.
188  throw std::invalid_argument("PPL::Box<ITV>::Box(gs):\n"
189  "the non-empty generator system gs "
190  "contains no points.");
191  }
192 
193  // Going through all the lines, rays and closure points.
194  for (Generator_System::const_iterator gs_i = gs_begin;
195  gs_i != gs_end; ++gs_i) {
196  const Generator& g = *gs_i;
197  switch (g.type()) {
198  case Generator::LINE:
200  i_end = g.expression().end();
201  i != i_end; ++i) {
202  seq[i.variable().id()].assign(UNIVERSE);
203  }
204  break;
205  case Generator::RAY:
207  i_end = g.expression().end();
208  i != i_end; ++i) {
209  switch (sgn(*i)) {
210  case 1:
211  seq[i.variable().id()].upper_extend();
212  break;
213  case -1:
214  seq[i.variable().id()].lower_extend();
215  break;
216  default:
217  PPL_UNREACHABLE;
218  break;
219  }
220  }
221  break;
223  {
224  const Coefficient& d = g.divisor();
225  // TODO: If the variables in the expression that have coefficient 0
226  // have no effect on seq[i], this loop can be optimized using
227  // Generator::expr_type::const_iterator.
228  for (dimension_type i = space_dim; i-- > 0; ) {
229  assign_r(q.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED);
230  assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
231  q.canonicalize();
232  ITV& seq_i = seq[i];
233  seq_i.lower_extend(i_constraint(GREATER_THAN, q));
234  seq_i.upper_extend(i_constraint(LESS_THAN, q));
235  }
236  }
237  break;
238  default:
239  // Points already dealt with.
240  break;
241  }
242  }
243  PPL_ASSERT(OK());
244 }
245 
246 template <typename ITV>
247 template <typename T>
249  : seq(check_space_dimension_overflow(bds.space_dimension(),
251  "PPL::Box::",
252  "Box(bds)",
253  "bds exceeds the maximum "
254  "allowed space dimension")),
255  status() {
256  // Expose all the interval constraints.
258  if (bds.marked_empty()) {
259  set_empty();
260  PPL_ASSERT(OK());
261  return;
262  }
263 
264  // The empty flag will be meaningful, whatever happens from now on.
266 
267  const dimension_type space_dim = space_dimension();
268  if (space_dim == 0) {
269  PPL_ASSERT(OK());
270  return;
271  }
272 
273  typedef typename BD_Shape<T>::coefficient_type Coeff;
274  PPL_DIRTY_TEMP(Coeff, tmp);
275  const DB_Row<Coeff>& dbm_0 = bds.dbm[0];
276  for (dimension_type i = space_dim; i-- > 0; ) {
277  I_Constraint<Coeff> lower;
278  I_Constraint<Coeff> upper;
279  ITV& seq_i = seq[i];
280 
281  // Set the upper bound.
282  const Coeff& u = dbm_0[i+1];
283  if (!is_plus_infinity(u)) {
284  upper.set(LESS_OR_EQUAL, u, true);
285  }
286 
287  // Set the lower bound.
288  const Coeff& negated_l = bds.dbm[i+1][0];
289  if (!is_plus_infinity(negated_l)) {
290  neg_assign_r(tmp, negated_l, ROUND_DOWN);
291  lower.set(GREATER_OR_EQUAL, tmp);
292  }
293 
294  seq_i.build(lower, upper);
295  }
296  PPL_ASSERT(OK());
297 }
298 
299 template <typename ITV>
300 template <typename T>
302  : seq(check_space_dimension_overflow(oct.space_dimension(),
304  "PPL::Box::",
305  "Box(oct)",
306  "oct exceeds the maximum "
307  "allowed space dimension")),
308  status() {
309  // Expose all the interval constraints.
310  oct.strong_closure_assign();
311  if (oct.marked_empty()) {
312  set_empty();
313  return;
314  }
315 
316  // The empty flag will be meaningful, whatever happens from now on.
318 
319  const dimension_type space_dim = space_dimension();
320  if (space_dim == 0) {
321  return;
322  }
323 
324  PPL_DIRTY_TEMP(mpq_class, lower_bound);
325  PPL_DIRTY_TEMP(mpq_class, upper_bound);
326  for (dimension_type i = space_dim; i-- > 0; ) {
327  typedef typename Octagonal_Shape<T>::coefficient_type Coeff;
330  ITV& seq_i = seq[i];
331  const dimension_type ii = 2*i;
332  const dimension_type cii = ii + 1;
333 
334  // Set the upper bound.
335  const Coeff& twice_ub = oct.matrix[cii][ii];
336  if (!is_plus_infinity(twice_ub)) {
337  assign_r(upper_bound, twice_ub, ROUND_NOT_NEEDED);
338  div_2exp_assign_r(upper_bound, upper_bound, 1, ROUND_NOT_NEEDED);
339  upper.set(LESS_OR_EQUAL, upper_bound);
340  }
341 
342  // Set the lower bound.
343  const Coeff& twice_lb = oct.matrix[ii][cii];
344  if (!is_plus_infinity(twice_lb)) {
345  assign_r(lower_bound, twice_lb, ROUND_NOT_NEEDED);
346  neg_assign_r(lower_bound, lower_bound, ROUND_NOT_NEEDED);
347  div_2exp_assign_r(lower_bound, lower_bound, 1, ROUND_NOT_NEEDED);
348  lower.set(GREATER_OR_EQUAL, lower_bound);
349  }
350  seq_i.build(lower, upper);
351  }
352 }
353 
354 template <typename ITV>
356  : seq(check_space_dimension_overflow(ph.space_dimension(),
358  "PPL::Box::",
359  "Box(ph)",
360  "ph exceeds the maximum "
361  "allowed space dimension")),
362  status() {
363  // The empty flag will be meaningful, whatever happens from now on.
365 
366  // We do not need to bother about `complexity' if:
367  // a) the polyhedron is already marked empty; or ...
368  if (ph.marked_empty()) {
369  set_empty();
370  return;
371  }
372 
373  // b) the polyhedron is zero-dimensional; or ...
374  const dimension_type space_dim = ph.space_dimension();
375  if (space_dim == 0) {
376  return;
377  }
378 
379  // c) the polyhedron is already described by a generator system.
381  Box tmp(ph.generators());
382  m_swap(tmp);
383  return;
384  }
385 
386  // Here generators are not up-to-date or there are pending constraints.
387  PPL_ASSERT(ph.constraints_are_up_to_date());
388 
389  if (complexity == POLYNOMIAL_COMPLEXITY) {
390  // FIXME: is there a way to avoid this initialization?
391  for (dimension_type i = space_dim; i-- > 0; ) {
392  seq[i].assign(UNIVERSE);
393  }
394  // Get a simplified version of the constraints.
396  // Propagate easy-to-find bounds from the constraints,
397  // allowing for a limited number of iterations.
398  // FIXME: 20 is just a wild guess.
399  const dimension_type max_iterations = 20;
400  propagate_constraints_no_check(cs, max_iterations);
401  }
402  else if (complexity == SIMPLEX_COMPLEXITY) {
403  MIP_Problem lp(space_dim);
404  const Constraint_System& ph_cs = ph.constraints();
405  if (!ph_cs.has_strict_inequalities()) {
406  lp.add_constraints(ph_cs);
407  }
408  else {
409  // Adding to `lp' a topologically closed version of `ph_cs'.
410  for (Constraint_System::const_iterator i = ph_cs.begin(),
411  ph_cs_end = ph_cs.end(); i != ph_cs_end; ++i) {
412  const Constraint& c = *i;
413  if (c.is_strict_inequality()) {
414  const Linear_Expression expr(c.expression());
415  lp.add_constraint(expr >= 0);
416  }
417  else {
418  lp.add_constraint(c);
419  }
420  }
421  }
422  // Check for unsatisfiability.
423  if (!lp.is_satisfiable()) {
424  set_empty();
425  return;
426  }
427  // Get all the bounds for the space dimensions.
428  Generator g(point());
429  PPL_DIRTY_TEMP(mpq_class, lower_bound);
430  PPL_DIRTY_TEMP(mpq_class, upper_bound);
431  PPL_DIRTY_TEMP_COEFFICIENT(bound_numer);
432  PPL_DIRTY_TEMP_COEFFICIENT(bound_denom);
433  for (dimension_type i = space_dim; i-- > 0; ) {
436  ITV& seq_i = seq[i];
438  // Evaluate upper bound.
440  if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
441  g = lp.optimizing_point();
442  lp.evaluate_objective_function(g, bound_numer, bound_denom);
443  assign_r(upper_bound.get_num(), bound_numer, ROUND_NOT_NEEDED);
444  assign_r(upper_bound.get_den(), bound_denom, ROUND_NOT_NEEDED);
445  PPL_ASSERT(is_canonical(upper_bound));
446  upper.set(LESS_OR_EQUAL, upper_bound);
447  }
448  // Evaluate optimal lower bound.
450  if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
451  g = lp.optimizing_point();
452  lp.evaluate_objective_function(g, bound_numer, bound_denom);
453  assign_r(lower_bound.get_num(), bound_numer, ROUND_NOT_NEEDED);
454  assign_r(lower_bound.get_den(), bound_denom, ROUND_NOT_NEEDED);
455  PPL_ASSERT(is_canonical(lower_bound));
456  lower.set(GREATER_OR_EQUAL, lower_bound);
457  }
458  seq_i.build(lower, upper);
459  }
460  }
461  else {
462  PPL_ASSERT(complexity == ANY_COMPLEXITY);
463  if (ph.is_empty()) {
464  set_empty();
465  }
466  else {
467  Box tmp(ph.generators());
468  m_swap(tmp);
469  }
470  }
471 }
472 
473 template <typename ITV>
475  : seq(check_space_dimension_overflow(gr.space_dimension(),
477  "PPL::Box::",
478  "Box(gr)",
479  "gr exceeds the maximum "
480  "allowed space dimension")),
481  status() {
482 
483  if (gr.marked_empty()) {
484  set_empty();
485  return;
486  }
487 
488  // The empty flag will be meaningful, whatever happens from now on.
490 
491  const dimension_type space_dim = gr.space_dimension();
492 
493  if (space_dim == 0) {
494  return;
495  }
496 
497  if (!gr.generators_are_up_to_date() && !gr.update_generators()) {
498  // Updating found the grid empty.
499  set_empty();
500  return;
501  }
502 
503  PPL_ASSERT(!gr.gen_sys.empty());
504 
505  // For each dimension that is bounded by the grid, set both bounds
506  // of the interval to the value of the associated coefficient in a
507  // generator point.
508  PPL_DIRTY_TEMP(mpq_class, bound);
509  PPL_DIRTY_TEMP_COEFFICIENT(bound_numer);
510  PPL_DIRTY_TEMP_COEFFICIENT(bound_denom);
511  for (dimension_type i = space_dim; i-- > 0; ) {
512  ITV& seq_i = seq[i];
513  Variable var(i);
514  bool max;
515  if (gr.maximize(var, bound_numer, bound_denom, max)) {
516  assign_r(bound.get_num(), bound_numer, ROUND_NOT_NEEDED);
517  assign_r(bound.get_den(), bound_denom, ROUND_NOT_NEEDED);
518  bound.canonicalize();
519  seq_i.build(i_constraint(EQUAL, bound));
520  }
521  else {
522  seq_i.assign(UNIVERSE);
523  }
524  }
525 }
526 
527 template <typename ITV>
528 template <typename D1, typename D2, typename R>
530  Complexity_Class complexity)
531  : seq(), status() {
534  "PPL::Box::",
535  "Box(dp)",
536  "dp exceeds the maximum "
537  "allowed space dimension");
538  Box tmp1(dp.domain1(), complexity);
539  Box tmp2(dp.domain2(), complexity);
540  tmp1.intersection_assign(tmp2);
541  m_swap(tmp1);
542 }
543 
544 template <typename ITV>
545 inline void
547  // Adding no dimensions is a no-op.
548  if (m == 0) {
549  return;
550  }
551  check_space_dimension_overflow(m, max_space_dimension() - space_dimension(),
552  "PPL::Box::",
553  "add_space_dimensions_and_embed(m)",
554  "adding m new space dimensions exceeds "
555  "the maximum allowed space dimension");
556  // To embed an n-dimension space box in a (n+m)-dimension space,
557  // we just add `m' new universe elements to the sequence.
558  seq.insert(seq.end(), m, ITV(UNIVERSE));
559  PPL_ASSERT(OK());
560 }
561 
562 template <typename ITV>
563 inline void
565  // Adding no dimensions is a no-op.
566  if (m == 0) {
567  return;
568  }
569  check_space_dimension_overflow(m, max_space_dimension() - space_dimension(),
570  "PPL::Box::",
571  "add_space_dimensions_and_project(m)",
572  "adding m new space dimensions exceeds "
573  "the maximum allowed space dimension");
574  // Add `m' new zero elements to the sequence.
575  seq.insert(seq.end(), m, ITV(0));
576  PPL_ASSERT(OK());
577 }
578 
579 template <typename ITV>
580 bool
581 operator==(const Box<ITV>& x, const Box<ITV>& y) {
582  const dimension_type x_space_dim = x.space_dimension();
583  if (x_space_dim != y.space_dimension()) {
584  return false;
585  }
586 
587  if (x.is_empty()) {
588  return y.is_empty();
589  }
590 
591  if (y.is_empty()) {
592  return x.is_empty();
593  }
594 
595  for (dimension_type k = x_space_dim; k-- > 0; ) {
596  if (x.seq[k] != y.seq[k]) {
597  return false;
598  }
599  }
600  return true;
601 }
602 
603 template <typename ITV>
604 bool
605 Box<ITV>::bounds(const Linear_Expression& expr, const bool from_above) const {
606  // `expr' should be dimension-compatible with `*this'.
607  const dimension_type expr_space_dim = expr.space_dimension();
608  const dimension_type space_dim = space_dimension();
609  if (space_dim < expr_space_dim) {
610  throw_dimension_incompatible((from_above
611  ? "bounds_from_above(e)"
612  : "bounds_from_below(e)"), "e", expr);
613  }
614  // A zero-dimensional or empty Box bounds everything.
615  if (space_dim == 0 || is_empty()) {
616  return true;
617  }
618  const int from_above_sign = from_above ? 1 : -1;
619  // TODO: This loop can be optimized more, if needed, exploiting the
620  // (possible) sparseness of expr.
622  i_end = expr.end(); i != i_end; ++i) {
623  const Variable v = i.variable();
624  switch (sgn(*i) * from_above_sign) {
625  case 1:
626  if (seq[v.id()].upper_is_boundary_infinity()) {
627  return false;
628  }
629  break;
630  case 0:
631  PPL_UNREACHABLE;
632  break;
633  case -1:
634  if (seq[v.id()].lower_is_boundary_infinity()) {
635  return false;
636  }
637  break;
638  }
639  }
640  return true;
641 }
642 
643 template <typename ITV>
645 interval_relation(const ITV& i,
646  const Constraint::Type constraint_type,
647  Coefficient_traits::const_reference numer,
648  Coefficient_traits::const_reference denom) {
649 
650  if (i.is_universe()) {
652  }
653 
654  PPL_DIRTY_TEMP(mpq_class, bound);
655  assign_r(bound.get_num(), numer, ROUND_NOT_NEEDED);
656  assign_r(bound.get_den(), denom, ROUND_NOT_NEEDED);
657  bound.canonicalize();
658  neg_assign_r(bound, bound, ROUND_NOT_NEEDED);
659  const bool is_lower_bound = (denom > 0);
660 
661  PPL_DIRTY_TEMP(mpq_class, bound_diff);
662  if (constraint_type == Constraint::EQUALITY) {
663  if (i.lower_is_boundary_infinity()) {
664  PPL_ASSERT(!i.upper_is_boundary_infinity());
665  assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
666  sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
667  switch (sgn(bound_diff)) {
668  case 1:
670  case 0:
671  return i.upper_is_open()
674  case -1:
676  }
677  }
678  else {
679  assign_r(bound_diff, i.lower(), ROUND_NOT_NEEDED);
680  sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
681  switch (sgn(bound_diff)) {
682  case 1:
684  case 0:
685  if (i.lower_is_open()) {
687  }
688  if (i.is_singleton()) {
691  }
693  case -1:
694  if (i.upper_is_boundary_infinity()) {
696  }
697  else {
698  assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
699  sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
700  switch (sgn(bound_diff)) {
701  case 1:
703  case 0:
704  if (i.upper_is_open()) {
706  }
707  else {
709  }
710  case -1:
712  }
713  }
714  }
715  }
716  }
717 
718  PPL_ASSERT(constraint_type != Constraint::EQUALITY);
719  if (is_lower_bound) {
720  if (i.lower_is_boundary_infinity()) {
721  PPL_ASSERT(!i.upper_is_boundary_infinity());
722  assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
723  sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
724  switch (sgn(bound_diff)) {
725  case 1:
727  case 0:
728  if (constraint_type == Constraint::STRICT_INEQUALITY
729  || i.upper_is_open()) {
731  }
732  else {
734  }
735  case -1:
737  }
738  }
739  else {
740  assign_r(bound_diff, i.lower(), ROUND_NOT_NEEDED);
741  sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
742  switch (sgn(bound_diff)) {
743  case 1:
745  case 0:
746  if (constraint_type == Constraint::NONSTRICT_INEQUALITY
747  || i.lower_is_open()) {
749  if (i.is_singleton()) {
750  result = result && Poly_Con_Relation::saturates();
751  }
752  return result;
753  }
754  else {
755  PPL_ASSERT(constraint_type == Constraint::STRICT_INEQUALITY
756  && !i.lower_is_open());
757  if (i.is_singleton()) {
760  }
761  else {
763  }
764  }
765  case -1:
766  if (i.upper_is_boundary_infinity()) {
768  }
769  else {
770  assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
771  sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
772  switch (sgn(bound_diff)) {
773  case 1:
775  case 0:
776  if (constraint_type == Constraint::STRICT_INEQUALITY
777  || i.upper_is_open()) {
779  }
780  else {
782  }
783  case -1:
785  }
786  }
787  }
788  }
789  }
790  else {
791  // `c' is an upper bound.
792  if (i.upper_is_boundary_infinity()) {
794  }
795  else {
796  assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
797  sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
798  switch (sgn(bound_diff)) {
799  case -1:
801  case 0:
802  if (constraint_type == Constraint::NONSTRICT_INEQUALITY
803  || i.upper_is_open()) {
805  if (i.is_singleton()) {
806  result = result && Poly_Con_Relation::saturates();
807  }
808  return result;
809  }
810  else {
811  PPL_ASSERT(constraint_type == Constraint::STRICT_INEQUALITY
812  && !i.upper_is_open());
813  if (i.is_singleton()) {
816  }
817  else {
819  }
820  }
821  case 1:
822  if (i.lower_is_boundary_infinity()) {
824  }
825  else {
826  assign_r(bound_diff, i.lower(), ROUND_NOT_NEEDED);
827  sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
828  switch (sgn(bound_diff)) {
829  case -1:
831  case 0:
832  if (constraint_type == Constraint::STRICT_INEQUALITY
833  || i.lower_is_open()) {
835  }
836  else {
838  }
839  case 1:
841  }
842  }
843  }
844  }
845  }
846 
847  // Quiet a compiler warning: this program point is unreachable.
848  PPL_UNREACHABLE;
850 }
851 
852 template <typename ITV>
853 Poly_Con_Relation
855  const dimension_type cg_space_dim = cg.space_dimension();
856  const dimension_type space_dim = space_dimension();
857 
858  // Dimension-compatibility check.
859  if (cg_space_dim > space_dim) {
860  throw_dimension_incompatible("relation_with(cg)", cg);
861  }
862  if (is_empty()) {
866  }
867 
868  if (space_dim == 0) {
869  if (cg.is_inconsistent()) {
871  }
872  else {
875  }
876  }
877 
878  if (cg.is_equality()) {
879  const Constraint c(cg);
880  return relation_with(c);
881  }
882 
885  PPL_DIRTY_TEMP(mpq_class, m);
886  r = 0;
888  i_end = cg.expression().end(); i != i_end; ++i) {
889  const Coefficient& cg_i = *i;
890  const Variable v = i.variable();
891  assign_r(m, cg_i, ROUND_NOT_NEEDED);
892  // FIXME: an add_mul_assign() method would come handy here.
893  t.build(seq[v.id()].lower_constraint(), seq[v.id()].upper_constraint());
894  t *= m;
895  r += t;
896  }
897 
898  if (r.lower_is_boundary_infinity() || r.upper_is_boundary_infinity()) {
900  }
901 
902  // Find the value that satisfies the congruence and is
903  // nearest to the lower bound such that the point lies on or above it.
904 
908  mod = cg.modulus();
909  v = cg.inhomogeneous_term() % mod;
910  assign_r(lower, r.lower(), ROUND_DOWN);
911  v -= ((lower / mod) * mod);
912  if (v + lower > 0) {
913  v -= mod;
914  }
916 }
917 
918 template <typename ITV>
921  const dimension_type c_space_dim = c.space_dimension();
922  const dimension_type space_dim = space_dimension();
923 
924  // Dimension-compatibility check.
925  if (c_space_dim > space_dim) {
926  throw_dimension_incompatible("relation_with(c)", c);
927  }
928 
929  if (is_empty()) {
933  }
934 
935  if (space_dim == 0) {
936  if ((c.is_equality() && c.inhomogeneous_term() != 0)
937  || (c.is_inequality() && c.inhomogeneous_term() < 0)) {
939  }
940  else if (c.is_strict_inequality() && c.inhomogeneous_term() == 0) {
941  // The constraint 0 > 0 implicitly defines the hyperplane 0 = 0;
942  // thus, the zero-dimensional point also saturates it.
945  }
946  else if (c.is_equality() || c.inhomogeneous_term() == 0) {
949  }
950  else {
951  // The zero-dimensional point saturates
952  // neither the positivity constraint 1 >= 0,
953  // nor the strict positivity constraint 1 > 0.
955  }
956  }
957 
958  dimension_type c_num_vars = 0;
959  dimension_type c_only_var = 0;
960 
961  if (Box_Helpers::extract_interval_constraint(c, c_num_vars, c_only_var)) {
962  if (c_num_vars == 0) {
963  // c is a trivial constraint.
964  switch (sgn(c.inhomogeneous_term())) {
965  case -1:
967  case 0:
968  if (c.is_strict_inequality()) {
971  }
972  else {
975  }
976  case 1:
978  }
979  }
980  else {
981  // c is an interval constraint.
982  return interval_relation(seq[c_only_var],
983  c.type(),
984  c.inhomogeneous_term(),
985  c.coefficient(Variable(c_only_var)));
986  }
987  }
988  else {
989  // Deal with a non-trivial and non-interval constraint.
992  PPL_DIRTY_TEMP(mpq_class, m);
993  r = 0;
994  const Constraint::expr_type& e = c.expression();
995  for (Constraint::expr_type::const_iterator i = e.begin(), i_end = e.end();
996  i != i_end; ++i) {
997  assign_r(m, *i, ROUND_NOT_NEEDED);
998  const Variable v = i.variable();
999  // FIXME: an add_mul_assign() method would come handy here.
1000  t.build(seq[v.id()].lower_constraint(), seq[v.id()].upper_constraint());
1001  t *= m;
1002  r += t;
1003  }
1004  return interval_relation(r,
1005  c.type(),
1006  c.inhomogeneous_term());
1007  }
1008 
1009  // Quiet a compiler warning: this program point is unreachable.
1010  PPL_UNREACHABLE;
1011  return Poly_Con_Relation::nothing();
1012 }
1013 
1014 template <typename ITV>
1017  const dimension_type space_dim = space_dimension();
1018  const dimension_type g_space_dim = g.space_dimension();
1019 
1020  // Dimension-compatibility check.
1021  if (space_dim < g_space_dim) {
1022  throw_dimension_incompatible("relation_with(g)", g);
1023  }
1024 
1025  // The empty box cannot subsume a generator.
1026  if (is_empty()) {
1027  return Poly_Gen_Relation::nothing();
1028  }
1029 
1030  // A universe box in a zero-dimensional space subsumes
1031  // all the generators of a zero-dimensional space.
1032  if (space_dim == 0) {
1033  return Poly_Gen_Relation::subsumes();
1034  }
1035 
1036  if (g.is_line_or_ray()) {
1037  if (g.is_line()) {
1038  const Generator::expr_type& e = g.expression();
1039  for (Generator::expr_type::const_iterator i = e.begin(), i_end = e.end();
1040  i != i_end; ++i) {
1041  if (!seq[i.variable().id()].is_universe()) {
1042  return Poly_Gen_Relation::nothing();
1043  }
1044  }
1045  return Poly_Gen_Relation::subsumes();
1046  }
1047  else {
1048  PPL_ASSERT(g.is_ray());
1049  const Generator::expr_type& e = g.expression();
1050  for (Generator::expr_type::const_iterator i = e.begin(), i_end = e.end();
1051  i != i_end; ++i) {
1052  const Variable v = i.variable();
1053  switch (sgn(*i)) {
1054  case 1:
1055  if (!seq[v.id()].upper_is_boundary_infinity()) {
1056  return Poly_Gen_Relation::nothing();
1057  }
1058  break;
1059  case 0:
1060  PPL_UNREACHABLE;
1061  break;
1062  case -1:
1063  if (!seq[v.id()].lower_is_boundary_infinity()) {
1064  return Poly_Gen_Relation::nothing();
1065  }
1066  break;
1067  }
1068  }
1069  return Poly_Gen_Relation::subsumes();
1070  }
1071  }
1072 
1073  // Here `g' is a point or closure point.
1074  const Coefficient& g_divisor = g.divisor();
1075  PPL_DIRTY_TEMP(mpq_class, g_coord);
1076  PPL_DIRTY_TEMP(mpq_class, bound);
1077  // TODO: If the variables in the expression that have coefficient 0
1078  // have no effect on seq[i], this loop can be optimized using
1079  // Generator::expr_type::const_iterator.
1080  for (dimension_type i = g_space_dim; i-- > 0; ) {
1081  const ITV& seq_i = seq[i];
1082  if (seq_i.is_universe()) {
1083  continue;
1084  }
1085  assign_r(g_coord.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED);
1086  assign_r(g_coord.get_den(), g_divisor, ROUND_NOT_NEEDED);
1087  g_coord.canonicalize();
1088  // Check lower bound.
1089  if (!seq_i.lower_is_boundary_infinity()) {
1090  assign_r(bound, seq_i.lower(), ROUND_NOT_NEEDED);
1091  if (g_coord <= bound) {
1092  if (seq_i.lower_is_open()) {
1093  if (g.is_point() || g_coord != bound) {
1094  return Poly_Gen_Relation::nothing();
1095  }
1096  }
1097  else if (g_coord != bound) {
1098  return Poly_Gen_Relation::nothing();
1099  }
1100  }
1101  }
1102  // Check upper bound.
1103  if (!seq_i.upper_is_boundary_infinity()) {
1104  assign_r(bound, seq_i.upper(), ROUND_NOT_NEEDED);
1105  if (g_coord >= bound) {
1106  if (seq_i.upper_is_open()) {
1107  if (g.is_point() || g_coord != bound) {
1108  return Poly_Gen_Relation::nothing();
1109  }
1110  }
1111  else if (g_coord != bound) {
1112  return Poly_Gen_Relation::nothing();
1113  }
1114  }
1115  }
1116  }
1117  return Poly_Gen_Relation::subsumes();
1118 }
1119 
1120 
1121 template <typename ITV>
1122 bool
1124  const bool maximize,
1125  Coefficient& ext_n, Coefficient& ext_d,
1126  bool& included) const {
1127  // `expr' should be dimension-compatible with `*this'.
1128  const dimension_type space_dim = space_dimension();
1129  const dimension_type expr_space_dim = expr.space_dimension();
1130  if (space_dim < expr_space_dim) {
1131  throw_dimension_incompatible((maximize
1132  ? "maximize(e, ...)"
1133  : "minimize(e, ...)"), "e", expr);
1134  }
1135 
1136  // Deal with zero-dim Box first.
1137  if (space_dim == 0) {
1138  if (marked_empty()) {
1139  return false;
1140  }
1141  else {
1142  ext_n = expr.inhomogeneous_term();
1143  ext_d = 1;
1144  included = true;
1145  return true;
1146  }
1147  }
1148 
1149  // For an empty Box we simply return false.
1150  if (is_empty()) {
1151  return false;
1152  }
1153 
1154  PPL_DIRTY_TEMP(mpq_class, result);
1155  assign_r(result, expr.inhomogeneous_term(), ROUND_NOT_NEEDED);
1156  bool is_included = true;
1157  const int maximize_sign = maximize ? 1 : -1;
1158  PPL_DIRTY_TEMP(mpq_class, bound_i);
1159  PPL_DIRTY_TEMP(mpq_class, expr_i);
1160  for (Linear_Expression::const_iterator i = expr.begin(),
1161  i_end = expr.end(); i != i_end; ++i) {
1162  const ITV& seq_i = seq[i.variable().id()];
1163  assign_r(expr_i, *i, ROUND_NOT_NEEDED);
1164  switch (sgn(expr_i) * maximize_sign) {
1165  case 1:
1166  if (seq_i.upper_is_boundary_infinity()) {
1167  return false;
1168  }
1169  assign_r(bound_i, seq_i.upper(), ROUND_NOT_NEEDED);
1170  add_mul_assign_r(result, bound_i, expr_i, ROUND_NOT_NEEDED);
1171  if (seq_i.upper_is_open()) {
1172  is_included = false;
1173  }
1174  break;
1175  case 0:
1176  PPL_UNREACHABLE;
1177  break;
1178  case -1:
1179  if (seq_i.lower_is_boundary_infinity()) {
1180  return false;
1181  }
1182  assign_r(bound_i, seq_i.lower(), ROUND_NOT_NEEDED);
1183  add_mul_assign_r(result, bound_i, expr_i, ROUND_NOT_NEEDED);
1184  if (seq_i.lower_is_open()) {
1185  is_included = false;
1186  }
1187  break;
1188  }
1189  }
1190  // Extract output info.
1191  PPL_ASSERT(is_canonical(result));
1192  ext_n = result.get_num();
1193  ext_d = result.get_den();
1194  included = is_included;
1195  return true;
1196 }
1197 
1198 template <typename ITV>
1199 bool
1201  const bool maximize,
1202  Coefficient& ext_n, Coefficient& ext_d,
1203  bool& included,
1204  Generator& g) const {
1205  if (!max_min(expr, maximize, ext_n, ext_d, included)) {
1206  return false;
1207  }
1208  // Compute generator `g'.
1209  Linear_Expression g_expr;
1210  PPL_DIRTY_TEMP_COEFFICIENT(g_divisor);
1211  g_divisor = 1;
1212  const int maximize_sign = maximize ? 1 : -1;
1213  PPL_DIRTY_TEMP(mpq_class, g_coord);
1218  // TODO: Check if the following loop can be optimized to exploit the
1219  // (possible) sparseness of expr.
1220  for (dimension_type i = space_dimension(); i-- > 0; ) {
1221  const ITV& seq_i = seq[i];
1222  switch (sgn(expr.coefficient(Variable(i))) * maximize_sign) {
1223  case 1:
1224  assign_r(g_coord, seq_i.upper(), ROUND_NOT_NEEDED);
1225  break;
1226  case 0:
1227  // If 0 belongs to the interval, choose it
1228  // (and directly proceed to the next iteration).
1229  // FIXME: name qualification issue.
1230  if (seq_i.contains(0)) {
1231  continue;
1232  }
1233  if (!seq_i.lower_is_boundary_infinity()) {
1234  if (seq_i.lower_is_open()) {
1235  if (!seq_i.upper_is_boundary_infinity()) {
1236  if (seq_i.upper_is_open()) {
1237  // Bounded and open interval: compute middle point.
1238  assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED);
1239  PPL_DIRTY_TEMP(mpq_class, q_seq_i_upper);
1240  assign_r(q_seq_i_upper, seq_i.upper(), ROUND_NOT_NEEDED);
1241  g_coord += q_seq_i_upper;
1242  g_coord /= 2;
1243  }
1244  else {
1245  // The upper bound is in the interval.
1246  assign_r(g_coord, seq_i.upper(), ROUND_NOT_NEEDED);
1247  }
1248  }
1249  else {
1250  // Lower is open, upper is unbounded.
1251  assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED);
1252  ++g_coord;
1253  }
1254  }
1255  else {
1256  // The lower bound is in the interval.
1257  assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED);
1258  }
1259  }
1260  else {
1261  // Lower is unbounded, hence upper is bounded
1262  // (since we know that 0 does not belong to the interval).
1263  PPL_ASSERT(!seq_i.upper_is_boundary_infinity());
1264  assign_r(g_coord, seq_i.upper(), ROUND_NOT_NEEDED);
1265  if (seq_i.upper_is_open()) {
1266  --g_coord;
1267  }
1268  }
1269  break;
1270  case -1:
1271  assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED);
1272  break;
1273  }
1274  // Add g_coord * Variable(i) to the generator.
1275  assign_r(denom, g_coord.get_den(), ROUND_NOT_NEEDED);
1276  lcm_assign(lcm, g_divisor, denom);
1277  exact_div_assign(factor, lcm, g_divisor);
1278  g_expr *= factor;
1279  exact_div_assign(factor, lcm, denom);
1280  assign_r(numer, g_coord.get_num(), ROUND_NOT_NEEDED);
1281  numer *= factor;
1282  g_expr += numer * Variable(i);
1283  g_divisor = lcm;
1284  }
1285  g = Generator::point(g_expr, g_divisor);
1286  return true;
1287 }
1288 
1289 template <typename ITV>
1290 bool
1291 Box<ITV>::contains(const Box& y) const {
1292  const Box& x = *this;
1293  // Dimension-compatibility check.
1294  if (x.space_dimension() != y.space_dimension()) {
1295  x.throw_dimension_incompatible("contains(y)", y);
1296  }
1297 
1298  // If `y' is empty, then `x' contains `y'.
1299  if (y.is_empty()) {
1300  return true;
1301  }
1302 
1303  // If `x' is empty, then `x' cannot contain `y'.
1304  if (x.is_empty()) {
1305  return false;
1306  }
1307 
1308  for (dimension_type k = x.seq.size(); k-- > 0; ) {
1309  // FIXME: fix this name qualification issue.
1310  if (!x.seq[k].contains(y.seq[k])) {
1311  return false;
1312  }
1313  }
1314  return true;
1315 }
1316 
1317 template <typename ITV>
1318 bool
1320  const Box& x = *this;
1321  // Dimension-compatibility check.
1322  if (x.space_dimension() != y.space_dimension()) {
1323  x.throw_dimension_incompatible("is_disjoint_from(y)", y);
1324  }
1325 
1326  // If any of `x' or `y' is marked empty, then they are disjoint.
1327  // Note: no need to use `is_empty', as the following loop is anyway correct.
1328  if (x.marked_empty() || y.marked_empty()) {
1329  return true;
1330  }
1331 
1332  for (dimension_type k = x.seq.size(); k-- > 0; ) {
1333  // FIXME: fix this name qualification issue.
1334  if (x.seq[k].is_disjoint_from(y.seq[k])) {
1335  return true;
1336  }
1337  }
1338  return false;
1339 }
1340 
1341 template <typename ITV>
1342 inline bool
1344  Box& x = *this;
1345 
1346  // Dimension-compatibility check.
1347  if (x.space_dimension() != y.space_dimension()) {
1348  x.throw_dimension_incompatible("upper_bound_assign_if_exact(y)", y);
1349  }
1350 
1351  // The lub of a box with an empty box is equal to the first box.
1352  if (y.is_empty()) {
1353  return true;
1354  }
1355  if (x.is_empty()) {
1356  x = y;
1357  return true;
1358  }
1359 
1360  bool x_j_does_not_contain_y_j = false;
1361  bool y_j_does_not_contain_x_j = false;
1362 
1363  for (dimension_type i = x.seq.size(); i-- > 0; ) {
1364  const ITV& x_seq_i = x.seq[i];
1365  const ITV& y_seq_i = y.seq[i];
1366 
1367  if (!x_seq_i.can_be_exactly_joined_to(y_seq_i)) {
1368  return false;
1369  }
1370 
1371  // Note: the use of `y_i_does_not_contain_x_i' is needed
1372  // because we want to temporarily preserve the old value
1373  // of `y_j_does_not_contain_x_j'.
1374  bool y_i_does_not_contain_x_i = !y_seq_i.contains(x_seq_i);
1375  if (y_i_does_not_contain_x_i && x_j_does_not_contain_y_j) {
1376  return false;
1377  }
1378  if (!x_seq_i.contains(y_seq_i)) {
1379  if (y_j_does_not_contain_x_j) {
1380  return false;
1381  }
1382  else {
1383  x_j_does_not_contain_y_j = true;
1384  }
1385  }
1386  if (y_i_does_not_contain_x_i) {
1387  y_j_does_not_contain_x_j = true;
1388  }
1389  }
1390 
1391  // The upper bound is exact: compute it into *this.
1392  for (dimension_type k = x.seq.size(); k-- > 0; ) {
1393  x.seq[k].join_assign(y.seq[k]);
1394  }
1395  return true;
1396 }
1397 
1398 template <typename ITV>
1399 bool
1400 Box<ITV>::OK() const {
1401  if (status.test_empty_up_to_date() && !status.test_empty()) {
1402  Box tmp = *this;
1403  tmp.reset_empty_up_to_date();
1404  if (tmp.check_empty()) {
1405 #ifndef NDEBUG
1406  std::cerr << "The box is empty, but it is marked as non-empty."
1407  << std::endl;
1408 #endif // NDEBUG
1409  return false;
1410  }
1411  }
1412 
1413  // A box that is not marked empty must have meaningful intervals.
1414  if (!marked_empty()) {
1415  for (dimension_type k = seq.size(); k-- > 0; ) {
1416  if (!seq[k].OK()) {
1417  return false;
1418  }
1419  }
1420  }
1421 
1422  return true;
1423 }
1424 
1425 template <typename ITV>
1428  dimension_type d = space_dimension();
1429  // A zero-space-dim box always has affine dimension zero.
1430  if (d == 0) {
1431  return 0;
1432  }
1433 
1434  // An empty box has affine dimension zero.
1435  if (is_empty()) {
1436  return 0;
1437  }
1438 
1439  for (dimension_type k = d; k-- > 0; ) {
1440  if (seq[k].is_singleton()) {
1441  --d;
1442  }
1443  }
1444 
1445  return d;
1446 }
1447 
1448 template <typename ITV>
1449 bool
1451  PPL_ASSERT(!marked_empty());
1452  Box<ITV>& x = const_cast<Box<ITV>&>(*this);
1453  for (dimension_type k = seq.size(); k-- > 0; ) {
1454  if (seq[k].is_empty()) {
1455  x.set_empty();
1456  return true;
1457  }
1458  }
1459  x.set_nonempty();
1460  return false;
1461 }
1462 
1463 template <typename ITV>
1464 bool
1466  if (marked_empty()) {
1467  return false;
1468  }
1469  for (dimension_type k = seq.size(); k-- > 0; ) {
1470  if (!seq[k].is_universe()) {
1471  return false;
1472  }
1473  }
1474  return true;
1475 }
1476 
1477 template <typename ITV>
1478 bool
1480  if (ITV::is_always_topologically_closed() || is_empty()) {
1481  return true;
1482  }
1483 
1484  for (dimension_type k = seq.size(); k-- > 0; ) {
1485  if (!seq[k].is_topologically_closed()) {
1486  return false;
1487  }
1488  }
1489  return true;
1490 }
1491 
1492 template <typename ITV>
1493 bool
1495  if (is_empty()) {
1496  return true;
1497  }
1498  for (dimension_type k = seq.size(); k-- > 0; ) {
1499  if (!seq[k].is_singleton()) {
1500  return false;
1501  }
1502  }
1503  return true;
1504 }
1505 
1506 template <typename ITV>
1507 bool
1509  if (is_empty()) {
1510  return true;
1511  }
1512  for (dimension_type k = seq.size(); k-- > 0; ) {
1513  if (!seq[k].is_bounded()) {
1514  return false;
1515  }
1516  }
1517  return true;
1518 }
1519 
1520 template <typename ITV>
1521 bool
1523  if (marked_empty()) {
1524  return false;
1525  }
1526  for (dimension_type k = seq.size(); k-- > 0; ) {
1527  if (!seq[k].contains_integer_point()) {
1528  return false;
1529  }
1530  }
1531  return true;
1532 }
1533 
1534 template <typename ITV>
1535 bool
1537  Coefficient& freq_n, Coefficient& freq_d,
1538  Coefficient& val_n, Coefficient& val_d) const {
1539  dimension_type space_dim = space_dimension();
1540  // The dimension of `expr' must be at most the dimension of *this.
1541  if (space_dim < expr.space_dimension()) {
1542  throw_dimension_incompatible("frequency(e, ...)", "e", expr);
1543  }
1544 
1545  // Check if `expr' has a constant value.
1546  // If it is constant, set the frequency `freq_n' to 0
1547  // and return true. Otherwise the values for \p expr
1548  // are not discrete so return false.
1549 
1550  // Space dimension is 0: if empty, then return false;
1551  // otherwise the frequency is 0 and the value is the inhomogeneous term.
1552  if (space_dim == 0) {
1553  if (is_empty()) {
1554  return false;
1555  }
1556  freq_n = 0;
1557  freq_d = 1;
1558  val_n = expr.inhomogeneous_term();
1559  val_d = 1;
1560  return true;
1561  }
1562 
1563  // For an empty Box, we simply return false.
1564  if (is_empty()) {
1565  return false;
1566  }
1567 
1568  // The Box has at least 1 dimension and is not empty.
1571  PPL_DIRTY_TEMP(mpq_class, tmp);
1572  Coefficient c = expr.inhomogeneous_term();
1573 
1574  PPL_DIRTY_TEMP_COEFFICIENT(val_denom);
1575  val_denom = 1;
1576 
1577  for (Linear_Expression::const_iterator i = expr.begin(), i_end = expr.end();
1578  i != i_end; ++i) {
1579  const ITV& seq_i = seq[i.variable().id()];
1580  // Check if `v' is constant in the BD shape.
1581  if (seq_i.is_singleton()) {
1582  // If `v' is constant, replace it in `le' by the value.
1583  assign_r(tmp, seq_i.lower(), ROUND_NOT_NEEDED);
1584  numer = tmp.get_num();
1585  denom = tmp.get_den();
1586  c *= denom;
1587  c += numer * val_denom * (*i);
1588  val_denom *= denom;
1589  continue;
1590  }
1591  // The expression `expr' is not constant.
1592  return false;
1593  }
1594 
1595  // The expression `expr' is constant.
1596  freq_n = 0;
1597  freq_d = 1;
1598 
1599  // Reduce `val_n' and `val_d'.
1600  normalize2(c, val_denom, val_n, val_d);
1601  return true;
1602 }
1603 
1604 template <typename ITV>
1605 bool
1607  // `var' should be one of the dimensions of the polyhedron.
1608  const dimension_type var_space_dim = var.space_dimension();
1609  if (space_dimension() < var_space_dim) {
1610  throw_dimension_incompatible("constrains(v)", "v", var);
1611  }
1612 
1613  if (marked_empty() || !seq[var_space_dim-1].is_universe()) {
1614  return true;
1615  }
1616  // Now force an emptiness check.
1617  return is_empty();
1618 }
1619 
1620 template <typename ITV>
1621 void
1623  // The cylindrification with respect to no dimensions is a no-op.
1624  // This case also captures the only legal cylindrification
1625  // of a box in a 0-dim space.
1626  if (vars.empty()) {
1627  return;
1628  }
1629 
1630  // Dimension-compatibility check.
1631  const dimension_type min_space_dim = vars.space_dimension();
1632  if (space_dimension() < min_space_dim) {
1633  throw_dimension_incompatible("unconstrain(vs)", min_space_dim);
1634  }
1635  // If the box is already empty, there is nothing left to do.
1636  if (marked_empty()) {
1637  return;
1638  }
1639 
1640  // Here the box might still be empty (but we haven't detected it yet):
1641  // check emptiness of the interval for each of the variables in
1642  // `vars' before cylindrification.
1643  for (Variables_Set::const_iterator vsi = vars.begin(),
1644  vsi_end = vars.end(); vsi != vsi_end; ++vsi) {
1645  ITV& seq_vsi = seq[*vsi];
1646  if (!seq_vsi.is_empty()) {
1647  seq_vsi.assign(UNIVERSE);
1648  }
1649  else {
1650  set_empty();
1651  break;
1652  }
1653  }
1654  PPL_ASSERT(OK());
1655 }
1656 
1657 template <typename ITV>
1658 void
1660  if (ITV::is_always_topologically_closed() || is_empty()) {
1661  return;
1662  }
1663 
1664  for (dimension_type k = seq.size(); k-- > 0; ) {
1665  seq[k].topological_closure_assign();
1666  }
1667 }
1668 
1669 template <typename ITV>
1670 void
1675  const Constraint_System* cs_p,
1676  unsigned complexity_threshold,
1677  bool wrap_individually) {
1678 #if 0 // Generic implementation commented out.
1680  vars, w, r, o, cs_p,
1681  complexity_threshold, wrap_individually,
1682  "Box");
1683 #else // Specialized implementation.
1684  PPL_USED(wrap_individually);
1685  PPL_USED(complexity_threshold);
1686  Box& x = *this;
1687 
1688  // Dimension-compatibility check for `*cs_p', if any.
1689  const dimension_type vars_space_dim = vars.space_dimension();
1690  if (cs_p != 0 && cs_p->space_dimension() > vars_space_dim) {
1691  std::ostringstream s;
1692  s << "PPL::Box<ITV>::wrap_assign(vars, w, r, o, cs_p, ...):"
1693  << std::endl
1694  << "vars.space_dimension() == " << vars_space_dim
1695  << ", cs_p->space_dimension() == " << cs_p->space_dimension() << ".";
1696  throw std::invalid_argument(s.str());
1697  }
1698 
1699  // Wrapping no variable only requires refining with *cs_p, if any.
1700  if (vars.empty()) {
1701  if (cs_p != 0) {
1702  refine_with_constraints(*cs_p);
1703  }
1704  return;
1705  }
1706 
1707  // Dimension-compatibility check for `vars'.
1708  const dimension_type space_dim = x.space_dimension();
1709  if (space_dim < vars_space_dim) {
1710  std::ostringstream s;
1711  s << "PPL::Box<ITV>::wrap_assign(vars, ...):"
1712  << std::endl
1713  << "this->space_dimension() == " << space_dim
1714  << ", required space dimension == " << vars_space_dim << ".";
1715  throw std::invalid_argument(s.str());
1716  }
1717 
1718  // Wrapping an empty polyhedron is a no-op.
1719  if (x.is_empty()) {
1720  return;
1721  }
1722 
1723  // FIXME: temporarily (ab-) using Coefficient.
1724  // Set `min_value' and `max_value' to the minimum and maximum values
1725  // a variable of width `w' and signedness `s' can take.
1726  PPL_DIRTY_TEMP_COEFFICIENT(min_value);
1727  PPL_DIRTY_TEMP_COEFFICIENT(max_value);
1728  if (r == UNSIGNED) {
1729  min_value = 0;
1730  mul_2exp_assign(max_value, Coefficient_one(), w);
1731  --max_value;
1732  }
1733  else {
1734  PPL_ASSERT(r == SIGNED_2_COMPLEMENT);
1735  mul_2exp_assign(max_value, Coefficient_one(), w-1);
1736  neg_assign(min_value, max_value);
1737  --max_value;
1738  }
1739 
1740  // FIXME: Build the (integer) quadrant interval.
1741  PPL_DIRTY_TEMP(ITV, integer_quadrant_itv);
1742  PPL_DIRTY_TEMP(ITV, rational_quadrant_itv);
1743  {
1746  integer_quadrant_itv.build(lower, upper);
1747  // The rational quadrant is only needed if overflow is undefined.
1748  if (o == OVERFLOW_UNDEFINED) {
1749  ++max_value;
1750  upper = i_constraint(LESS_THAN, max_value);
1751  rational_quadrant_itv.build(lower, upper);
1752  }
1753  }
1754 
1755  const Variables_Set::const_iterator vs_end = vars.end();
1756 
1757  if (cs_p == 0) {
1758  // No constraint refinement is needed here.
1759  switch (o) {
1760  case OVERFLOW_WRAPS:
1761  for (Variables_Set::const_iterator i = vars.begin(); i != vs_end; ++i) {
1762  x.seq[*i].wrap_assign(w, r, integer_quadrant_itv);
1763  }
1764  reset_empty_up_to_date();
1765  break;
1766  case OVERFLOW_UNDEFINED:
1767  for (Variables_Set::const_iterator i = vars.begin(); i != vs_end; ++i) {
1768  ITV& x_seq_v = x.seq[*i];
1769  if (!rational_quadrant_itv.contains(x_seq_v)) {
1770  x_seq_v.assign(integer_quadrant_itv);
1771  }
1772  }
1773  break;
1774  case OVERFLOW_IMPOSSIBLE:
1775  for (Variables_Set::const_iterator i = vars.begin(); i != vs_end; ++i) {
1776  x.seq[*i].intersect_assign(integer_quadrant_itv);
1777  }
1778  reset_empty_up_to_date();
1779  break;
1780  }
1781  PPL_ASSERT(x.OK());
1782  return;
1783  }
1784 
1785  PPL_ASSERT(cs_p != 0);
1786  const Constraint_System& cs = *cs_p;
1787  // A map associating interval constraints to variable indexes.
1788  typedef std::map<dimension_type, std::vector<const Constraint*> > map_type;
1789  map_type var_cs_map;
1791  i_end = cs.end(); i != i_end; ++i) {
1792  const Constraint& c = *i;
1793  dimension_type c_num_vars = 0;
1794  dimension_type c_only_var = 0;
1795  if (Box_Helpers::extract_interval_constraint(c, c_num_vars, c_only_var)) {
1796  if (c_num_vars == 1) {
1797  // An interval constraint on variable index `c_only_var'.
1798  PPL_ASSERT(c_only_var < space_dim);
1799  // We do care about c if c_only_var is going to be wrapped.
1800  if (vars.find(c_only_var) != vs_end) {
1801  var_cs_map[c_only_var].push_back(&c);
1802  }
1803  }
1804  else {
1805  PPL_ASSERT(c_num_vars == 0);
1806  // Note: tautologies have been filtered out by iterators.
1807  PPL_ASSERT(c.is_inconsistent());
1808  x.set_empty();
1809  return;
1810  }
1811  }
1812  }
1813 
1814  PPL_DIRTY_TEMP(ITV, refinement_itv);
1815  const map_type::const_iterator var_cs_map_end = var_cs_map.end();
1816  // Loop through the variable indexes in `vars'.
1817  for (Variables_Set::const_iterator i = vars.begin(); i != vs_end; ++i) {
1818  const dimension_type v = *i;
1819  refinement_itv = integer_quadrant_itv;
1820  // Look for the refinement constraints for space dimension index `v'.
1821  map_type::const_iterator var_cs_map_iter = var_cs_map.find(v);
1822  if (var_cs_map_iter != var_cs_map_end) {
1823  // Refine interval for variable `v'.
1824  const map_type::mapped_type& var_cs = var_cs_map_iter->second;
1825  for (dimension_type j = var_cs.size(); j-- > 0; ) {
1826  const Constraint& c = *var_cs[j];
1827  refine_interval_no_check(refinement_itv,
1828  c.type(),
1829  c.inhomogeneous_term(),
1830  c.coefficient(Variable(v)));
1831  }
1832  }
1833  // Wrap space dimension index `v'.
1834  ITV& x_seq_v = x.seq[v];
1835  switch (o) {
1836  case OVERFLOW_WRAPS:
1837  x_seq_v.wrap_assign(w, r, refinement_itv);
1838  break;
1839  case OVERFLOW_UNDEFINED:
1840  if (!rational_quadrant_itv.contains(x_seq_v)) {
1841  x_seq_v.assign(UNIVERSE);
1842  }
1843  break;
1844  case OVERFLOW_IMPOSSIBLE:
1845  x_seq_v.intersect_assign(refinement_itv);
1846  break;
1847  }
1848  }
1849  PPL_ASSERT(x.OK());
1850 #endif
1851 }
1852 
1853 template <typename ITV>
1854 void
1857  && !ITV::info_type::store_open) {
1858  return;
1859  }
1860 
1861  if (marked_empty()) {
1862  return;
1863  }
1864 
1865  for (dimension_type k = seq.size(); k-- > 0; ) {
1866  seq[k].drop_some_non_integer_points();
1867  }
1868 
1869  PPL_ASSERT(OK());
1870 }
1871 
1872 template <typename ITV>
1873 void
1875  Complexity_Class) {
1876  // Dimension-compatibility check.
1877  const dimension_type min_space_dim = vars.space_dimension();
1878  if (space_dimension() < min_space_dim) {
1879  throw_dimension_incompatible("drop_some_non_integer_points(vs, cmpl)",
1880  min_space_dim);
1881  }
1883  && !ITV::info_type::store_open) {
1884  return;
1885  }
1886 
1887  if (marked_empty()) {
1888  return;
1889  }
1890 
1891  for (Variables_Set::const_iterator v_i = vars.begin(),
1892  v_end = vars.end(); v_i != v_end; ++v_i) {
1893  seq[*v_i].drop_some_non_integer_points();
1894  }
1895 
1896  PPL_ASSERT(OK());
1897 }
1898 
1899 template <typename ITV>
1900 void
1902  Box& x = *this;
1903  const dimension_type space_dim = space_dimension();
1904 
1905  // Dimension-compatibility check.
1906  if (space_dim != y.space_dimension()) {
1907  x.throw_dimension_incompatible("intersection_assign(y)", y);
1908  }
1909 
1910  // If one of the two boxes is empty, the intersection is empty.
1911  if (x.marked_empty()) {
1912  return;
1913  }
1914  if (y.marked_empty()) {
1915  x.set_empty();
1916  return;
1917  }
1918 
1919  // If both boxes are zero-dimensional, then at this point they are
1920  // necessarily non-empty, so that their intersection is non-empty too.
1921  if (space_dim == 0) {
1922  return;
1923  }
1924 
1925  // FIXME: here we may conditionally exploit a capability of the
1926  // underlying interval to eagerly detect empty results.
1927  reset_empty_up_to_date();
1928 
1929  for (dimension_type k = space_dim; k-- > 0; ) {
1930  x.seq[k].intersect_assign(y.seq[k]);
1931  }
1932 
1933  PPL_ASSERT(x.OK());
1934 }
1935 
1936 template <typename ITV>
1937 void
1939  Box& x = *this;
1940 
1941  // Dimension-compatibility check.
1942  if (x.space_dimension() != y.space_dimension()) {
1943  x.throw_dimension_incompatible("upper_bound_assign(y)", y);
1944  }
1945 
1946  // The lub of a box with an empty box is equal to the first box.
1947  if (y.is_empty()) {
1948  return;
1949  }
1950  if (x.is_empty()) {
1951  x = y;
1952  return;
1953  }
1954 
1955  for (dimension_type k = x.seq.size(); k-- > 0; ) {
1956  x.seq[k].join_assign(y.seq[k]);
1957  }
1958 
1959  PPL_ASSERT(x.OK());
1960 }
1961 
1962 template <typename ITV>
1963 void
1965  Box& x = *this;
1966  const dimension_type x_space_dim = x.space_dimension();
1967  const dimension_type y_space_dim = y.space_dimension();
1968 
1969  // If `y' is marked empty, the result will be empty too.
1970  if (y.marked_empty()) {
1971  x.set_empty();
1972  }
1973 
1974  // If `y' is a 0-dim space box, there is nothing left to do.
1975  if (y_space_dim == 0) {
1976  return;
1977  }
1978  // The resulting space dimension must be at most the maximum.
1980  max_space_dimension() - space_dimension(),
1981  "PPL::Box::",
1982  "concatenate_assign(y)",
1983  "concatenation exceeds the maximum "
1984  "allowed space dimension");
1985  // Here `y_space_dim > 0', so that a non-trivial concatenation will occur:
1986  // make sure that reallocation will occur once at most.
1987  x.seq.reserve(x_space_dim + y_space_dim);
1988 
1989  // If `x' is marked empty, then it is sufficient to adjust
1990  // the dimension of the vector space.
1991  if (x.marked_empty()) {
1992  x.seq.insert(x.seq.end(), y_space_dim, ITV(EMPTY));
1993  PPL_ASSERT(x.OK());
1994  return;
1995  }
1996 
1997  // Here neither `x' nor `y' are marked empty: concatenate them.
1998  std::copy(y.seq.begin(), y.seq.end(),
1999  std::back_insert_iterator<Sequence>(x.seq));
2000  // Update the `empty_up_to_date' flag.
2001  if (!y.status.test_empty_up_to_date()) {
2002  reset_empty_up_to_date();
2003  }
2004 
2005  PPL_ASSERT(x.OK());
2006 }
2007 
2008 template <typename ITV>
2009 void
2011  const dimension_type space_dim = space_dimension();
2012 
2013  // Dimension-compatibility check.
2014  if (space_dim != y.space_dimension()) {
2015  throw_dimension_incompatible("difference_assign(y)", y);
2016  }
2017 
2018  Box& x = *this;
2019  if (x.is_empty() || y.is_empty()) {
2020  return;
2021  }
2022  switch (space_dim) {
2023  case 0:
2024  // If `x' is zero-dimensional, then at this point both `x' and `y'
2025  // are the universe box, so that their difference is empty.
2026  x.set_empty();
2027  break;
2028 
2029  case 1:
2030  x.seq[0].difference_assign(y.seq[0]);
2031  if (x.seq[0].is_empty()) {
2032  x.set_empty();
2033  }
2034  break;
2035 
2036  default:
2037  {
2038  dimension_type index_non_contained = space_dim;
2039  dimension_type number_non_contained = 0;
2040  for (dimension_type i = space_dim; i-- > 0; ) {
2041  if (!y.seq[i].contains(x.seq[i])) {
2042  if (++number_non_contained == 1) {
2043  index_non_contained = i;
2044  }
2045  else {
2046  break;
2047  }
2048  }
2049  }
2050 
2051  switch (number_non_contained) {
2052  case 0:
2053  // `y' covers `x': the difference is empty.
2054  x.set_empty();
2055  break;
2056  case 1:
2057  x.seq[index_non_contained]
2058  .difference_assign(y.seq[index_non_contained]);
2059  if (x.seq[index_non_contained].is_empty()) {
2060  x.set_empty();
2061  }
2062  break;
2063  default:
2064  // Nothing to do: the difference is `x'.
2065  break;
2066  }
2067  }
2068  break;
2069  }
2070  PPL_ASSERT(OK());
2071 }
2072 
2073 template <typename ITV>
2074 bool
2076  Box& x = *this;
2077  const dimension_type num_dims = x.space_dimension();
2078  // Dimension-compatibility check.
2079  if (num_dims != y.space_dimension()) {
2080  x.throw_dimension_incompatible("simplify_using_context_assign(y)", y);
2081  }
2082 
2083  // Filter away the zero-dimensional case.
2084  if (num_dims == 0) {
2085  if (y.marked_empty()) {
2086  x.set_nonempty();
2087  return false;
2088  }
2089  else {
2090  return !x.marked_empty();
2091  }
2092  }
2093 
2094  // Filter away the case when `y' is empty.
2095  if (y.is_empty()) {
2096  for (dimension_type i = num_dims; i-- > 0; ) {
2097  x.seq[i].assign(UNIVERSE);
2098  }
2099  x.set_nonempty();
2100  return false;
2101  }
2102 
2103  if (x.is_empty()) {
2104  // Find in `y' a non-universe interval, if any.
2105  for (dimension_type i = 0; i < num_dims; ++i) {
2106  if (y.seq[i].is_universe()) {
2107  x.seq[i].assign(UNIVERSE);
2108  }
2109  else {
2110  // Set x.seq[i] so as to contradict y.seq[i], if possible.
2111  ITV& seq_i = x.seq[i];
2112  seq_i.empty_intersection_assign(y.seq[i]);
2113  if (seq_i.is_empty()) {
2114  // We were not able to assign to `seq_i' a non-empty interval:
2115  // reset `seq_i' to the universe interval and keep searching.
2116  seq_i.assign(UNIVERSE);
2117  continue;
2118  }
2119  // We assigned to `seq_i' a non-empty interval:
2120  // set the other intervals to universe and return.
2121  for (++i; i < num_dims; ++i) {
2122  x.seq[i].assign(UNIVERSE);
2123  }
2124  x.set_nonempty();
2125  PPL_ASSERT(x.OK());
2126  return false;
2127  }
2128  }
2129  // All intervals in `y' are universe or could not be contradicted:
2130  // simplification can leave the empty box `x' as is.
2131  PPL_ASSERT(x.OK() && x.is_empty());
2132  return false;
2133  }
2134 
2135  // Loop index `i' is intentionally going upwards.
2136  for (dimension_type i = 0; i < num_dims; ++i) {
2137  if (!x.seq[i].simplify_using_context_assign(y.seq[i])) {
2138  PPL_ASSERT(!x.seq[i].is_empty());
2139  // The intersection of `x' and `y' is empty due to the i-th interval:
2140  // reset other intervals to UNIVERSE.
2141  for (dimension_type j = num_dims; j-- > i; ) {
2142  x.seq[j].assign(UNIVERSE);
2143  }
2144  for (dimension_type j = i; j-- > 0; ) {
2145  x.seq[j].assign(UNIVERSE);
2146  }
2147  PPL_ASSERT(x.OK());
2148  return false;
2149  }
2150  }
2151  PPL_ASSERT(x.OK());
2152  return true;
2153 }
2154 
2155 template <typename ITV>
2156 void
2158  Box& x = *this;
2159  const dimension_type x_space_dim = x.space_dimension();
2160 
2161  // Dimension-compatibility check.
2162  if (x_space_dim != y.space_dimension()) {
2163  x.throw_dimension_incompatible("time_elapse_assign(y)", y);
2164  }
2165 
2166  // Dealing with the zero-dimensional case.
2167  if (x_space_dim == 0) {
2168  if (y.marked_empty()) {
2169  x.set_empty();
2170  }
2171  return;
2172  }
2173 
2174  // If either one of `x' or `y' is empty, the result is empty too.
2175  // Note: if possible, avoid cost of checking for emptiness.
2176  if (x.marked_empty() || y.marked_empty()
2177  || x.is_empty() || y.is_empty()) {
2178  x.set_empty();
2179  return;
2180  }
2181 
2182  for (dimension_type i = x_space_dim; i-- > 0; ) {
2183  ITV& x_seq_i = x.seq[i];
2184  const ITV& y_seq_i = y.seq[i];
2185  if (!x_seq_i.lower_is_boundary_infinity()) {
2186  if (y_seq_i.lower_is_boundary_infinity() || y_seq_i.lower() < 0) {
2187  x_seq_i.lower_extend();
2188  }
2189  }
2190  if (!x_seq_i.upper_is_boundary_infinity()) {
2191  if (y_seq_i.upper_is_boundary_infinity() || y_seq_i.upper() > 0) {
2192  x_seq_i.upper_extend();
2193  }
2194  }
2195  }
2196  PPL_ASSERT(x.OK());
2197 }
2198 
2199 template <typename ITV>
2200 inline void
2202  // The removal of no dimensions from any box is a no-op.
2203  // Note that this case also captures the only legal removal of
2204  // space dimensions from a box in a zero-dimensional space.
2205  if (vars.empty()) {
2206  PPL_ASSERT(OK());
2207  return;
2208  }
2209 
2210  const dimension_type old_space_dim = space_dimension();
2211 
2212  // Dimension-compatibility check.
2213  const dimension_type vsi_space_dim = vars.space_dimension();
2214  if (old_space_dim < vsi_space_dim) {
2215  throw_dimension_incompatible("remove_space_dimensions(vs)",
2216  vsi_space_dim);
2217  }
2218 
2219  const dimension_type new_space_dim = old_space_dim - vars.size();
2220 
2221  // If the box is empty (this must be detected), then resizing is all
2222  // what is needed. If it is not empty and we are removing _all_ the
2223  // dimensions then, again, resizing suffices.
2224  if (is_empty() || new_space_dim == 0) {
2225  seq.resize(new_space_dim);
2226  PPL_ASSERT(OK());
2227  return;
2228  }
2229 
2230  // For each variable to be removed, we fill the corresponding interval
2231  // by shifting left those intervals that will not be removed.
2232  Variables_Set::const_iterator vsi = vars.begin();
2233  Variables_Set::const_iterator vsi_end = vars.end();
2234  dimension_type dst = *vsi;
2235  dimension_type src = dst + 1;
2236  for (++vsi; vsi != vsi_end; ++vsi) {
2237  const dimension_type vsi_next = *vsi;
2238  // All intervals in between are moved to the left.
2239  while (src < vsi_next) {
2240  swap(seq[dst++], seq[src++]);
2241  }
2242  ++src;
2243  }
2244 
2245  // Moving the remaining intervals.
2246  while (src < old_space_dim) {
2247  swap(seq[dst++], seq[src++]);
2248  }
2249 
2250  PPL_ASSERT(dst == new_space_dim);
2251  seq.resize(new_space_dim);
2252 
2253  PPL_ASSERT(OK());
2254 }
2255 
2256 template <typename ITV>
2257 void
2259  // Dimension-compatibility check: the variable having
2260  // maximum index is the one occurring last in the set.
2261  const dimension_type space_dim = space_dimension();
2262  if (new_dimension > space_dim) {
2263  throw_dimension_incompatible("remove_higher_space_dimensions(nd)",
2264  new_dimension);
2265  }
2266 
2267  // The removal of no dimensions from any box is a no-op.
2268  // Note that this case also captures the only legal removal of
2269  // dimensions from a zero-dim space box.
2270  if (new_dimension == space_dim) {
2271  PPL_ASSERT(OK());
2272  return;
2273  }
2274 
2275  seq.resize(new_dimension);
2276  PPL_ASSERT(OK());
2277 }
2278 
2279 template <typename ITV>
2280 template <typename Partial_Function>
2281 void
2283  const dimension_type space_dim = space_dimension();
2284  if (space_dim == 0) {
2285  return;
2286  }
2287 
2288  if (pfunc.has_empty_codomain()) {
2289  // All dimensions vanish: the box becomes zero_dimensional.
2290  remove_higher_space_dimensions(0);
2291  return;
2292  }
2293 
2294  const dimension_type new_space_dim = pfunc.max_in_codomain() + 1;
2295  // If the box is empty, then simply adjust the space dimension.
2296  if (is_empty()) {
2297  remove_higher_space_dimensions(new_space_dim);
2298  return;
2299  }
2300 
2301  // We create a new Box with the new space dimension.
2302  Box<ITV> tmp(new_space_dim);
2303  // Map the intervals, exchanging the indexes.
2304  for (dimension_type i = 0; i < space_dim; ++i) {
2305  dimension_type new_i;
2306  if (pfunc.maps(i, new_i)) {
2307  swap(seq[i], tmp.seq[new_i]);
2308  }
2309  }
2310  m_swap(tmp);
2311  PPL_ASSERT(OK());
2312 }
2313 
2314 template <typename ITV>
2315 void
2317  const Variable dest) {
2318  const dimension_type space_dim = space_dimension();
2319  // `dest' should be one of the dimensions of the box.
2320  if (dest.space_dimension() > space_dim) {
2321  throw_dimension_incompatible("fold_space_dimensions(vs, v)", "v", dest);
2322  }
2323 
2324  // The folding of no dimensions is a no-op.
2325  if (vars.empty()) {
2326  return;
2327  }
2328 
2329  // All variables in `vars' should be dimensions of the box.
2330  if (vars.space_dimension() > space_dim) {
2331  throw_dimension_incompatible("fold_space_dimensions(vs, v)",
2332  vars.space_dimension());
2333  }
2334  // Moreover, `dest.id()' should not occur in `vars'.
2335  if (vars.find(dest.id()) != vars.end()) {
2336  throw_invalid_argument("fold_space_dimensions(vs, v)",
2337  "v should not occur in vs");
2338  }
2339 
2340  // Note: the check for emptiness is needed for correctness.
2341  if (!is_empty()) {
2342  // Join the interval corresponding to variable `dest' with the intervals
2343  // corresponding to the variables in `vars'.
2344  ITV& seq_v = seq[dest.id()];
2345  for (Variables_Set::const_iterator i = vars.begin(),
2346  vs_end = vars.end(); i != vs_end; ++i) {
2347  seq_v.join_assign(seq[*i]);
2348  }
2349  }
2350  remove_space_dimensions(vars);
2351 }
2352 
2353 template <typename ITV>
2354 void
2356  PPL_ASSERT(c.space_dimension() <= space_dimension());
2357 
2358  dimension_type c_num_vars = 0;
2359  dimension_type c_only_var = 0;
2360  // Throw an exception if c is not an interval constraints.
2361  if (!Box_Helpers::extract_interval_constraint(c, c_num_vars, c_only_var)) {
2362  throw_invalid_argument("add_constraint(c)",
2363  "c is not an interval constraint");
2364  }
2365 
2366  // Throw an exception if c is a nontrivial strict constraint
2367  // and ITV does not support open boundaries.
2368  if (c.is_strict_inequality() && c_num_vars != 0
2369  && ITV::is_always_topologically_closed()) {
2370  throw_invalid_argument("add_constraint(c)",
2371  "c is a nontrivial strict constraint");
2372  }
2373 
2374  // Avoid doing useless work if the box is known to be empty.
2375  if (marked_empty()) {
2376  return;
2377  }
2378 
2379  const Coefficient& n = c.inhomogeneous_term();
2380  if (c_num_vars == 0) {
2381  // Dealing with a trivial constraint.
2382  if (n < 0
2383  || (c.is_equality() && n != 0)
2384  || (c.is_strict_inequality() && n == 0)) {
2385  set_empty();
2386  }
2387  return;
2388  }
2389 
2390  PPL_ASSERT(c_num_vars == 1);
2391  const Coefficient& d = c.coefficient(Variable(c_only_var));
2392  add_interval_constraint_no_check(c_only_var, c.type(), n, d);
2393 }
2394 
2395 template <typename ITV>
2396 void
2398  PPL_ASSERT(cs.space_dimension() <= space_dimension());
2399  // Note: even when the box is known to be empty, we need to go
2400  // through all the constraints to fulfill the method's contract
2401  // for what concerns exception throwing.
2403  cs_end = cs.end(); i != cs_end; ++i) {
2404  add_constraint_no_check(*i);
2405  }
2406  PPL_ASSERT(OK());
2407 }
2408 
2409 template <typename ITV>
2410 void
2412  PPL_ASSERT(cg.space_dimension() <= space_dimension());
2413 
2414  // Set aside the case of proper congruences.
2415  if (cg.is_proper_congruence()) {
2416  if (cg.is_inconsistent()) {
2417  set_empty();
2418  return;
2419  }
2420  else if (cg.is_tautological()) {
2421  return;
2422  }
2423  else {
2424  throw_invalid_argument("add_congruence(cg)",
2425  "cg is a nontrivial proper congruence");
2426  }
2427  }
2428 
2429  PPL_ASSERT(cg.is_equality());
2430  dimension_type cg_num_vars = 0;
2431  dimension_type cg_only_var = 0;
2432  // Throw an exception if c is not an interval congruence.
2433  if (!Box_Helpers::extract_interval_congruence(cg, cg_num_vars, cg_only_var)) {
2434  throw_invalid_argument("add_congruence(cg)",
2435  "cg is not an interval congruence");
2436  }
2437 
2438  // Avoid doing useless work if the box is known to be empty.
2439  if (marked_empty()) {
2440  return;
2441  }
2442 
2443  const Coefficient& n = cg.inhomogeneous_term();
2444  if (cg_num_vars == 0) {
2445  // Dealing with a trivial equality congruence.
2446  if (n != 0) {
2447  set_empty();
2448  }
2449  return;
2450  }
2451 
2452  PPL_ASSERT(cg_num_vars == 1);
2453  const Coefficient& d = cg.coefficient(Variable(cg_only_var));
2454  add_interval_constraint_no_check(cg_only_var, Constraint::EQUALITY, n, d);
2455 }
2456 
2457 template <typename ITV>
2458 void
2460  PPL_ASSERT(cgs.space_dimension() <= space_dimension());
2461  // Note: even when the box is known to be empty, we need to go
2462  // through all the congruences to fulfill the method's contract
2463  // for what concerns exception throwing.
2465  cgs_end = cgs.end(); i != cgs_end; ++i) {
2466  add_congruence_no_check(*i);
2467  }
2468  PPL_ASSERT(OK());
2469 }
2470 
2471 template <typename ITV>
2472 void
2474  PPL_ASSERT(c.space_dimension() <= space_dimension());
2475  PPL_ASSERT(!marked_empty());
2476 
2477  dimension_type c_num_vars = 0;
2478  dimension_type c_only_var = 0;
2479  // Non-interval constraints are approximated.
2480  if (!Box_Helpers::extract_interval_constraint(c, c_num_vars, c_only_var)) {
2481  propagate_constraint_no_check(c);
2482  return;
2483  }
2484 
2485  const Coefficient& n = c.inhomogeneous_term();
2486  if (c_num_vars == 0) {
2487  // Dealing with a trivial constraint.
2488  if (n < 0
2489  || (c.is_equality() && n != 0)
2490  || (c.is_strict_inequality() && n == 0)) {
2491  set_empty();
2492  }
2493  return;
2494  }
2495 
2496  PPL_ASSERT(c_num_vars == 1);
2497  const Coefficient& d = c.coefficient(Variable(c_only_var));
2498  add_interval_constraint_no_check(c_only_var, c.type(), n, d);
2499 }
2500 
2501 template <typename ITV>
2502 void
2504  PPL_ASSERT(cs.space_dimension() <= space_dimension());
2506  cs_end = cs.end(); !marked_empty() && i != cs_end; ++i) {
2507  refine_no_check(*i);
2508  }
2509  PPL_ASSERT(OK());
2510 }
2511 
2512 template <typename ITV>
2513 void
2515  PPL_ASSERT(!marked_empty());
2516 
2517  PPL_ASSERT(cg.space_dimension() <= space_dimension());
2518 
2519  if (cg.is_proper_congruence()) {
2520  // A proper congruences is also an interval constraint
2521  // if and only if it is trivial.
2522  if (cg.is_inconsistent()) {
2523  set_empty();
2524  }
2525  return;
2526  }
2527 
2528  PPL_ASSERT(cg.is_equality());
2529  Constraint c(cg);
2530  refine_no_check(c);
2531 }
2532 
2533 template <typename ITV>
2534 void
2536  PPL_ASSERT(cgs.space_dimension() <= space_dimension());
2538  cgs_end = cgs.end(); !marked_empty() && i != cgs_end; ++i) {
2539  refine_no_check(*i);
2540  }
2541  PPL_ASSERT(OK());
2542 }
2543 
2544 #if 1 // Alternative implementations for propagate_constraint_no_check.
2545 namespace Implementation {
2546 
2547 namespace Boxes {
2548 
2549 inline bool
2551  r = result_relation_class(r);
2552  switch (r) {
2553  case V_GT_MINUS_INFINITY:
2554  case V_LT_PLUS_INFINITY:
2555  return true;
2556  case V_LT:
2557  case V_GT:
2558  open = T_YES;
2559  return false;
2560  case V_LE:
2561  case V_GE:
2562  if (open == T_NO) {
2563  open = T_MAYBE;
2564  }
2565  return false;
2566  case V_EQ:
2567  return false;
2568  default:
2569  PPL_UNREACHABLE;
2570  return true;
2571  }
2572 }
2573 
2574 } // namespace Boxes
2575 
2576 } // namespace Implementation
2577 
2578 
2579 template <typename ITV>
2580 void
2582  using namespace Implementation::Boxes;
2583 
2584  PPL_ASSERT(c.space_dimension() <= space_dimension());
2585 
2586  typedef
2588  Temp_Boundary_Type;
2589 
2590  const dimension_type c_space_dim = c.space_dimension();
2591  const Constraint::Type c_type = c.type();
2592  const Coefficient& c_inhomogeneous_term = c.inhomogeneous_term();
2593 
2594  // Find a space dimension having a non-zero coefficient (if any).
2595  const dimension_type last_k
2596  = c.expression().last_nonzero(1, c_space_dim + 1);
2597  if (last_k == c_space_dim + 1) {
2598  // Constraint c is trivial: check if it is inconsistent.
2599  if (c_inhomogeneous_term < 0
2600  || (c_inhomogeneous_term == 0
2601  && c_type != Constraint::NONSTRICT_INEQUALITY)) {
2602  set_empty();
2603  }
2604  return;
2605  }
2606 
2607  // Here constraint c is non-trivial.
2608  PPL_ASSERT(last_k <= c_space_dim);
2609  Temp_Boundary_Type t_bound;
2610  Temp_Boundary_Type t_a;
2611  Temp_Boundary_Type t_x;
2612  Ternary open;
2613  const Constraint::expr_type c_e = c.expression();
2615  k_end = c_e.lower_bound(Variable(last_k)); k != k_end; ++k) {
2616  const Coefficient& a_k = *k;
2617  const Variable k_var = k.variable();
2618  const int sgn_a_k = sgn(a_k);
2619  if (sgn_a_k == 0) {
2620  continue;
2621  }
2622  Result r;
2623  if (sgn_a_k > 0) {
2624  open = (c_type == Constraint::STRICT_INEQUALITY) ? T_YES : T_NO;
2625  if (open == T_NO) {
2626  maybe_reset_fpu_inexact<Temp_Boundary_Type>();
2627  }
2628  r = assign_r(t_bound, c_inhomogeneous_term, ROUND_UP);
2629  if (propagate_constraint_check_result(r, open)) {
2630  goto maybe_refine_upper_1;
2631  }
2632  r = neg_assign_r(t_bound, t_bound, ROUND_DOWN);
2633  if (propagate_constraint_check_result(r, open)) {
2634  goto maybe_refine_upper_1;
2635  }
2637  i_end = c_e.lower_bound(Variable(last_k)); i != i_end; ++i) {
2638  const Variable i_var = i.variable();
2639  if (i_var.id() == k_var.id()) {
2640  continue;
2641  }
2642  const Coefficient& a_i = *i;
2643  const int sgn_a_i = sgn(a_i);
2644  ITV& x_i = seq[i_var.id()];
2645  if (sgn_a_i < 0) {
2646  if (x_i.lower_is_boundary_infinity()) {
2647  goto maybe_refine_upper_1;
2648  }
2649  r = assign_r(t_a, a_i, ROUND_DOWN);
2650  if (propagate_constraint_check_result(r, open)) {
2651  goto maybe_refine_upper_1;
2652  }
2653  r = assign_r(t_x, x_i.lower(), ROUND_DOWN);
2654  if (propagate_constraint_check_result(r, open)) {
2655  goto maybe_refine_upper_1;
2656  }
2657  if (x_i.lower_is_open()) {
2658  open = T_YES;
2659  }
2660  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_DOWN);
2661  if (propagate_constraint_check_result(r, open)) {
2662  goto maybe_refine_upper_1;
2663  }
2664  }
2665  else {
2666  PPL_ASSERT(sgn_a_i > 0);
2667  if (x_i.upper_is_boundary_infinity()) {
2668  goto maybe_refine_upper_1;
2669  }
2670  r = assign_r(t_a, a_i, ROUND_UP);
2671  if (propagate_constraint_check_result(r, open)) {
2672  goto maybe_refine_upper_1;
2673  }
2674  r = assign_r(t_x, x_i.upper(), ROUND_UP);
2675  if (propagate_constraint_check_result(r, open)) {
2676  goto maybe_refine_upper_1;
2677  }
2678  if (x_i.upper_is_open()) {
2679  open = T_YES;
2680  }
2681  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_DOWN);
2682  if (propagate_constraint_check_result(r, open)) {
2683  goto maybe_refine_upper_1;
2684  }
2685  }
2686  }
2687  r = assign_r(t_a, a_k, ROUND_UP);
2688  if (propagate_constraint_check_result(r, open)) {
2689  goto maybe_refine_upper_1;
2690  }
2691  r = div_assign_r(t_bound, t_bound, t_a, ROUND_DOWN);
2692  if (propagate_constraint_check_result(r, open)) {
2693  goto maybe_refine_upper_1;
2694  }
2695 
2696  // Refine the lower bound of `seq[k]' with `t_bound'.
2697  if (open == T_MAYBE
2698  && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1) {
2699  open = T_YES;
2700  }
2701  {
2702  const Relation_Symbol rel
2703  = (open == T_YES) ? GREATER_THAN : GREATER_OR_EQUAL;
2704  seq[k_var.id()].add_constraint(i_constraint(rel, t_bound));
2705  }
2706  reset_empty_up_to_date();
2707  maybe_refine_upper_1:
2708  if (c_type != Constraint::EQUALITY) {
2709  continue;
2710  }
2711  open = T_NO;
2712  maybe_reset_fpu_inexact<Temp_Boundary_Type>();
2713  r = assign_r(t_bound, c_inhomogeneous_term, ROUND_DOWN);
2714  if (propagate_constraint_check_result(r, open)) {
2715  goto next_k;
2716  }
2717  r = neg_assign_r(t_bound, t_bound, ROUND_UP);
2718  if (propagate_constraint_check_result(r, open)) {
2719  goto next_k;
2720  }
2722  i_end = c_e.lower_bound(Variable(c_space_dim)); i != i_end; ++i) {
2723  const Variable i_var = i.variable();
2724  if (i_var.id() == k_var.id()) {
2725  continue;
2726  }
2727  const Coefficient& a_i = *i;
2728  const int sgn_a_i = sgn(a_i);
2729  ITV& x_i = seq[i_var.id()];
2730  if (sgn_a_i < 0) {
2731  if (x_i.upper_is_boundary_infinity()) {
2732  goto next_k;
2733  }
2734  r = assign_r(t_a, a_i, ROUND_UP);
2735  if (propagate_constraint_check_result(r, open)) {
2736  goto next_k;
2737  }
2738  r = assign_r(t_x, x_i.upper(), ROUND_UP);
2739  if (propagate_constraint_check_result(r, open)) {
2740  goto next_k;
2741  }
2742  if (x_i.upper_is_open()) {
2743  open = T_YES;
2744  }
2745  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
2746  if (propagate_constraint_check_result(r, open)) {
2747  goto next_k;
2748  }
2749  }
2750  else {
2751  PPL_ASSERT(sgn_a_i > 0);
2752  if (x_i.lower_is_boundary_infinity()) {
2753  goto next_k;
2754  }
2755  r = assign_r(t_a, a_i, ROUND_DOWN);
2756  if (propagate_constraint_check_result(r, open)) {
2757  goto next_k;
2758  }
2759  r = assign_r(t_x, x_i.lower(), ROUND_DOWN);
2760  if (propagate_constraint_check_result(r, open)) {
2761  goto next_k;
2762  }
2763  if (x_i.lower_is_open()) {
2764  open = T_YES;
2765  }
2766  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
2767  if (propagate_constraint_check_result(r, open)) {
2768  goto next_k;
2769  }
2770  }
2771  }
2772  r = assign_r(t_a, a_k, ROUND_DOWN);
2773  if (propagate_constraint_check_result(r, open)) {
2774  goto next_k;
2775  }
2776  r = div_assign_r(t_bound, t_bound, t_a, ROUND_UP);
2777  if (propagate_constraint_check_result(r, open)) {
2778  goto next_k;
2779  }
2780 
2781  // Refine the upper bound of seq[k] with t_bound.
2782  if (open == T_MAYBE
2783  && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1) {
2784  open = T_YES;
2785  }
2786  const Relation_Symbol rel
2787  = (open == T_YES) ? LESS_THAN : LESS_OR_EQUAL;
2788  seq[k_var.id()].add_constraint(i_constraint(rel, t_bound));
2789  reset_empty_up_to_date();
2790  }
2791  else {
2792  PPL_ASSERT(sgn_a_k < 0);
2793  open = (c_type == Constraint::STRICT_INEQUALITY) ? T_YES : T_NO;
2794  if (open == T_NO) {
2795  maybe_reset_fpu_inexact<Temp_Boundary_Type>();
2796  }
2797  r = assign_r(t_bound, c_inhomogeneous_term, ROUND_UP);
2798  if (propagate_constraint_check_result(r, open)) {
2799  goto maybe_refine_upper_2;
2800  }
2801  r = neg_assign_r(t_bound, t_bound, ROUND_DOWN);
2802  if (propagate_constraint_check_result(r, open)) {
2803  goto maybe_refine_upper_2;
2804  }
2806  i_end = c_e.lower_bound(Variable(c_space_dim)); i != i_end; ++i) {
2807  const Variable i_var = i.variable();
2808  if (i_var.id() == k_var.id()) {
2809  continue;
2810  }
2811  const Coefficient& a_i = *i;
2812  const int sgn_a_i = sgn(a_i);
2813  ITV& x_i = seq[i_var.id()];
2814  if (sgn_a_i < 0) {
2815  if (x_i.lower_is_boundary_infinity()) {
2816  goto maybe_refine_upper_2;
2817  }
2818  r = assign_r(t_a, a_i, ROUND_DOWN);
2819  if (propagate_constraint_check_result(r, open)) {
2820  goto maybe_refine_upper_2;
2821  }
2822  r = assign_r(t_x, x_i.lower(), ROUND_DOWN);
2823  if (propagate_constraint_check_result(r, open)) {
2824  goto maybe_refine_upper_2;
2825  }
2826  if (x_i.lower_is_open()) {
2827  open = T_YES;
2828  }
2829  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
2830  if (propagate_constraint_check_result(r, open)) {
2831  goto maybe_refine_upper_2;
2832  }
2833  }
2834  else {
2835  PPL_ASSERT(sgn_a_i > 0);
2836  if (x_i.upper_is_boundary_infinity()) {
2837  goto maybe_refine_upper_2;
2838  }
2839  r = assign_r(t_a, a_i, ROUND_UP);
2840  if (propagate_constraint_check_result(r, open)) {
2841  goto maybe_refine_upper_2;
2842  }
2843  r = assign_r(t_x, x_i.upper(), ROUND_UP);
2844  if (propagate_constraint_check_result(r, open)) {
2845  goto maybe_refine_upper_2;
2846  }
2847  if (x_i.upper_is_open()) {
2848  open = T_YES;
2849  }
2850  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_DOWN);
2851  if (propagate_constraint_check_result(r, open)) {
2852  goto maybe_refine_upper_2;
2853  }
2854  }
2855  }
2856  r = assign_r(t_a, a_k, ROUND_UP);
2857  if (propagate_constraint_check_result(r, open)) {
2858  goto maybe_refine_upper_2;
2859  }
2860  r = div_assign_r(t_bound, t_bound, t_a, ROUND_UP);
2861  if (propagate_constraint_check_result(r, open)) {
2862  goto maybe_refine_upper_2;
2863  }
2864  // Refine the upper bound of seq[k] with t_bound.
2865  if (open == T_MAYBE
2866  && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1) {
2867  open = T_YES;
2868  }
2869  {
2870  const Relation_Symbol rel
2871  = (open == T_YES) ? LESS_THAN : LESS_OR_EQUAL;
2872  seq[k_var.id()].add_constraint(i_constraint(rel, t_bound));
2873  }
2874  reset_empty_up_to_date();
2875  maybe_refine_upper_2:
2876  if (c_type != Constraint::EQUALITY) {
2877  continue;
2878  }
2879  open = T_NO;
2880  maybe_reset_fpu_inexact<Temp_Boundary_Type>();
2881  r = assign_r(t_bound, c_inhomogeneous_term, ROUND_DOWN);
2882  if (propagate_constraint_check_result(r, open)) {
2883  goto next_k;
2884  }
2885  r = neg_assign_r(t_bound, t_bound, ROUND_UP);
2886  if (propagate_constraint_check_result(r, open)) {
2887  goto next_k;
2888  }
2890  i_end = c_e.lower_bound(Variable(c_space_dim)); i != i_end; ++i) {
2891  const Variable i_var = i.variable();
2892  if (i_var.id() == k_var.id()) {
2893  continue;
2894  }
2895  const Coefficient& a_i = *i;
2896  const int sgn_a_i = sgn(a_i);
2897  ITV& x_i = seq[i_var.id()];
2898  if (sgn_a_i < 0) {
2899  if (x_i.upper_is_boundary_infinity()) {
2900  goto next_k;
2901  }
2902  r = assign_r(t_a, a_i, ROUND_UP);
2903  if (propagate_constraint_check_result(r, open)) {
2904  goto next_k;
2905  }
2906  r = assign_r(t_x, x_i.upper(), ROUND_UP);
2907  if (propagate_constraint_check_result(r, open)) {
2908  goto next_k;
2909  }
2910  if (x_i.upper_is_open()) {
2911  open = T_YES;
2912  }
2913  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
2914  if (propagate_constraint_check_result(r, open)) {
2915  goto next_k;
2916  }
2917  }
2918  else {
2919  PPL_ASSERT(sgn_a_i > 0);
2920  if (x_i.lower_is_boundary_infinity()) {
2921  goto next_k;
2922  }
2923  r = assign_r(t_a, a_i, ROUND_DOWN);
2924  if (propagate_constraint_check_result(r, open)) {
2925  goto next_k;
2926  }
2927  r = assign_r(t_x, x_i.lower(), ROUND_DOWN);
2928  if (propagate_constraint_check_result(r, open)) {
2929  goto next_k;
2930  }
2931  if (x_i.lower_is_open()) {
2932  open = T_YES;
2933  }
2934  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
2935  if (propagate_constraint_check_result(r, open)) {
2936  goto next_k;
2937  }
2938  }
2939  }
2940  r = assign_r(t_a, a_k, ROUND_DOWN);
2941  if (propagate_constraint_check_result(r, open)) {
2942  goto next_k;
2943  }
2944  r = div_assign_r(t_bound, t_bound, t_a, ROUND_DOWN);
2945  if (propagate_constraint_check_result(r, open)) {
2946  goto next_k;
2947  }
2948 
2949  // Refine the lower bound of seq[k] with t_bound.
2950  if (open == T_MAYBE
2951  && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1) {
2952  open = T_YES;
2953  }
2954  const Relation_Symbol rel
2955  = (open == T_YES) ? GREATER_THAN : GREATER_OR_EQUAL;
2956  seq[k_var.id()].add_constraint(i_constraint(rel, t_bound));
2957  reset_empty_up_to_date();
2958  }
2959  next_k:
2960  ;
2961  }
2962 }
2963 
2964 #else // Alternative implementations for propagate_constraint_no_check.
2965 
2966 template <typename ITV>
2967 void
2969  PPL_ASSERT(c.space_dimension() <= space_dimension());
2970 
2971  dimension_type c_space_dim = c.space_dimension();
2972  ITV k[c_space_dim];
2973  ITV p[c_space_dim];
2974  for (Constraint::expr_type::const_iterator i = c_e.begin(),
2975  i_end = c_e.lower_bound(Variable(c_space_dim)); i != i_end; ++i) {
2976  const Variable i_var = i.variable();
2977  k[i_var.id()] = *i;
2978  ITV& p_i = p[i_var.id()];
2979  p_i = seq[i_var.id()];
2980  p_i.mul_assign(p_i, k[i_var.id()]);
2981  }
2982  const Coefficient& inhomogeneous_term = c.inhomogeneous_term();
2983  for (Constraint::expr_type::const_iterator i = c_e.begin(),
2984  i_end = c_e.lower_bound(Variable(c_space_dim)); i != i_end; ++i) {
2985  const Variable i_var = i.variable();
2986  int sgn_coefficient_i = sgn(*i);
2987  ITV q(inhomogeneous_term);
2988  for (Constraint::expr_type::const_iterator j = c_e.begin(),
2989  j_end = c_e.lower_bound(Variable(c_space_dim)); j != j_end; ++j) {
2990  const Variable j_var = j.variable();
2991  if (i_var == j_var) {
2992  continue;
2993  }
2994  q.add_assign(q, p[j_var.id()]);
2995  }
2996  q.div_assign(q, k[i_var.id()]);
2997  q.neg_assign(q);
2998  Relation_Symbol rel;
2999  switch (c.type()) {
3000  case Constraint::EQUALITY:
3001  rel = EQUAL;
3002  break;
3004  rel = (sgn_coefficient_i > 0) ? GREATER_OR_EQUAL : LESS_OR_EQUAL;
3005  break;
3007  rel = (sgn_coefficient_i > 0) ? GREATER_THAN : LESS_THAN;
3008  break;
3009  }
3010  seq[i_var.id()].add_constraint(i_constraint(rel, q));
3011  // FIXME: could/should we exploit the return value of add_constraint
3012  // in case it is available?
3013  // FIXME: should we instead be lazy and do not even bother about
3014  // the possibility the interval becomes empty apart from setting
3015  // empty_up_to_date = false?
3016  if (seq[i_var.id()].is_empty()) {
3017  set_empty();
3018  break;
3019  }
3020  }
3021 
3022  PPL_ASSERT(OK());
3023 }
3024 
3025 #endif // Alternative implementations for propagate_constraint_no_check.
3026 
3027 template <typename ITV>
3028 void
3029 Box<ITV>
3031  const dimension_type max_iterations) {
3032  const dimension_type space_dim = space_dimension();
3033  PPL_ASSERT(cs.space_dimension() <= space_dim);
3034 
3035  const Constraint_System::const_iterator cs_begin = cs.begin();
3036  const Constraint_System::const_iterator cs_end = cs.end();
3037  const dimension_type propagation_weight
3038  = Implementation::num_constraints(cs) * space_dim;
3039 
3040  Sequence copy;
3041  bool changed;
3042  dimension_type num_iterations = 0;
3043  do {
3044  WEIGHT_BEGIN();
3045  ++num_iterations;
3046  copy = seq;
3047  for (Constraint_System::const_iterator i = cs_begin; i != cs_end; ++i) {
3048  propagate_constraint_no_check(*i);
3049  }
3050 
3051  WEIGHT_ADD_MUL(40, propagation_weight);
3052  // Check if the client has requested abandoning all expensive
3053  // computations. If so, the exception specified by the client
3054  // is thrown now.
3055  maybe_abandon();
3056 
3057  // NOTE: if max_iterations == 0 (i.e., no iteration limit is set)
3058  // the following test will anyway trigger on wrap around.
3059  if (num_iterations == max_iterations) {
3060  break;
3061  }
3062 
3063  changed = (copy != seq);
3064  } while (changed);
3065 }
3066 
3067 template <typename ITV>
3068 void
3070  const Linear_Expression& expr,
3071  Coefficient_traits::const_reference denominator) {
3072  // The denominator cannot be zero.
3073  if (denominator == 0) {
3074  throw_invalid_argument("affine_image(v, e, d)", "d == 0");
3075  }
3076 
3077  // Dimension-compatibility checks.
3078  const dimension_type space_dim = space_dimension();
3079  const dimension_type expr_space_dim = expr.space_dimension();
3080  if (space_dim < expr_space_dim) {
3081  throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
3082  }
3083  // `var' should be one of the dimensions of the polyhedron.
3084  const dimension_type var_space_dim = var.space_dimension();
3085  if (space_dim < var_space_dim) {
3086  throw_dimension_incompatible("affine_image(v, e, d)", "v", var);
3087  }
3088 
3089  if (is_empty()) {
3090  return;
3091  }
3092 
3093  Tmp_Interval_Type expr_value;
3094  Tmp_Interval_Type temp0;
3095  Tmp_Interval_Type temp1;
3096  expr_value.assign(expr.inhomogeneous_term());
3097  for (Linear_Expression::const_iterator i = expr.begin(),
3098  i_end = expr.end(); i != i_end; ++i) {
3099  temp0.assign(*i);
3100  temp1.assign(seq[i.variable().id()]);
3101  temp0.mul_assign(temp0, temp1);
3102  expr_value.add_assign(expr_value, temp0);
3103  }
3104  if (denominator != 1) {
3105  temp0.assign(denominator);
3106  expr_value.div_assign(expr_value, temp0);
3107  }
3108  seq[var.id()].assign(expr_value);
3109 
3110  PPL_ASSERT(OK());
3111 }
3112 
3113 template <typename ITV>
3114 void
3116  const Linear_Form<ITV>& lf) {
3117 
3118  // Check that ITV has a floating point boundary type.
3119  PPL_COMPILE_TIME_CHECK(!std::numeric_limits<typename ITV::boundary_type>
3120  ::is_exact, "Box<ITV>::affine_form_image(Variable, Linear_Form):"
3121  "ITV has not a floating point boundary type.");
3122 
3123  // Dimension-compatibility checks.
3124  const dimension_type space_dim = space_dimension();
3125  const dimension_type lf_space_dim = lf.space_dimension();
3126  if (space_dim < lf_space_dim) {
3127  throw_dimension_incompatible("affine_form_image(var, lf)", "lf", lf);
3128  }
3129 
3130  // `var' should be one of the dimensions of the polyhedron.
3131  const dimension_type var_space_dim = var.space_dimension();
3132  if (space_dim < var_space_dim) {
3133  throw_dimension_incompatible("affine_form_image(var, lf)", "var", var);
3134  }
3135 
3136  if (is_empty()) {
3137  return;
3138  }
3139 
3140  // Intervalization of 'lf'.
3141  ITV result = lf.inhomogeneous_term();
3142  for (dimension_type i = 0; i < lf_space_dim; ++i) {
3143  ITV current_addend = lf.coefficient(Variable(i));
3144  const ITV& curr_int = seq[i];
3145  current_addend *= curr_int;
3146  result += current_addend;
3147  }
3148 
3149  seq[var.id()].assign(result);
3150  PPL_ASSERT(OK());
3151 }
3152 
3153 template <typename ITV>
3154 void
3156  const Linear_Expression& expr,
3157  Coefficient_traits::const_reference
3158  denominator) {
3159  // The denominator cannot be zero.
3160  if (denominator == 0) {
3161  throw_invalid_argument("affine_preimage(v, e, d)", "d == 0");
3162  }
3163 
3164  // Dimension-compatibility checks.
3165  const dimension_type x_space_dim = space_dimension();
3166  const dimension_type expr_space_dim = expr.space_dimension();
3167  if (x_space_dim < expr_space_dim) {
3168  throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
3169  }
3170  // `var' should be one of the dimensions of the polyhedron.
3171  const dimension_type var_space_dim = var.space_dimension();
3172  if (x_space_dim < var_space_dim) {
3173  throw_dimension_incompatible("affine_preimage(v, e, d)", "v", var);
3174  }
3175 
3176  if (is_empty()) {
3177  return;
3178  }
3179 
3180  const Coefficient& expr_v = expr.coefficient(var);
3181  const bool invertible = (expr_v != 0);
3182  if (!invertible) {
3183  Tmp_Interval_Type expr_value;
3184  Tmp_Interval_Type temp0;
3185  Tmp_Interval_Type temp1;
3186  expr_value.assign(expr.inhomogeneous_term());
3187  for (Linear_Expression::const_iterator i = expr.begin(),
3188  i_end = expr.end(); i != i_end; ++i) {
3189  temp0.assign(*i);
3190  temp1.assign(seq[i.variable().id()]);
3191  temp0.mul_assign(temp0, temp1);
3192  expr_value.add_assign(expr_value, temp0);
3193  }
3194  if (denominator != 1) {
3195  temp0.assign(denominator);
3196  expr_value.div_assign(expr_value, temp0);
3197  }
3198  ITV& x_seq_v = seq[var.id()];
3199  expr_value.intersect_assign(x_seq_v);
3200  if (expr_value.is_empty()) {
3201  set_empty();
3202  }
3203  else {
3204  x_seq_v.assign(UNIVERSE);
3205  }
3206  }
3207  else {
3208  // The affine transformation is invertible.
3209  // CHECKME: for efficiency, would it be meaningful to avoid
3210  // the computation of inverse by partially evaluating the call
3211  // to affine_image?
3213  inverse -= expr;
3214  inverse += (expr_v + denominator) * var;
3215  affine_image(var, inverse, expr_v);
3216  }
3217  PPL_ASSERT(OK());
3218 }
3219 
3220 template <typename ITV>
3221 void
3222 Box<ITV>
3224  const Linear_Expression& lb_expr,
3225  const Linear_Expression& ub_expr,
3226  Coefficient_traits::const_reference denominator) {
3227  // The denominator cannot be zero.
3228  if (denominator == 0) {
3229  throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0");
3230  }
3231 
3232  // Dimension-compatibility checks.
3233  const dimension_type space_dim = space_dimension();
3234  // The dimension of `lb_expr' and `ub_expr' should not be
3235  // greater than the dimension of `*this'.
3236  const dimension_type lb_space_dim = lb_expr.space_dimension();
3237  if (space_dim < lb_space_dim) {
3238  throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
3239  "lb", lb_expr);
3240  }
3241  const dimension_type ub_space_dim = ub_expr.space_dimension();
3242  if (space_dim < ub_space_dim) {
3243  throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
3244  "ub", ub_expr);
3245  }
3246  // `var' should be one of the dimensions of the box.
3247  const dimension_type var_space_dim = var.space_dimension();
3248  if (space_dim < var_space_dim) {
3249  throw_dimension_incompatible("affine_image(v, e, d)", "v", var);
3250  }
3251  // Any image of an empty box is empty.
3252  if (is_empty()) {
3253  return;
3254  }
3255  // Add the constraint implied by the `lb_expr' and `ub_expr'.
3256  if (denominator > 0) {
3257  refine_with_constraint(lb_expr <= ub_expr);
3258  }
3259  else {
3260  refine_with_constraint(lb_expr >= ub_expr);
3261  }
3262 
3263  // Check whether `var' occurs in `lb_expr' and/or `ub_expr'.
3264  if (lb_expr.coefficient(var) == 0) {
3265  // Here `var' can only occur in `ub_expr'.
3266  generalized_affine_image(var,
3267  LESS_OR_EQUAL,
3268  ub_expr,
3269  denominator);
3270  if (denominator > 0) {
3271  refine_with_constraint(lb_expr <= denominator*var);
3272  }
3273  else {
3274  refine_with_constraint(denominator*var <= lb_expr);
3275  }
3276  }
3277  else if (ub_expr.coefficient(var) == 0) {
3278  // Here `var' can only occur in `lb_expr'.
3279  generalized_affine_image(var,
3281  lb_expr,
3282  denominator);
3283  if (denominator > 0) {
3284  refine_with_constraint(denominator*var <= ub_expr);
3285  }
3286  else {
3287  refine_with_constraint(ub_expr <= denominator*var);
3288  }
3289  }
3290  else {
3291  // Here `var' occurs in both `lb_expr' and `ub_expr'. As boxes
3292  // can only use the non-relational constraints, we find the
3293  // maximum/minimum values `ub_expr' and `lb_expr' obtain with the
3294  // box and use these instead of the `ub-expr' and `lb-expr'.
3295  PPL_DIRTY_TEMP_COEFFICIENT(max_numer);
3296  PPL_DIRTY_TEMP_COEFFICIENT(max_denom);
3297  bool max_included;
3298  PPL_DIRTY_TEMP_COEFFICIENT(min_numer);
3299  PPL_DIRTY_TEMP_COEFFICIENT(min_denom);
3300  bool min_included;
3301  ITV& seq_v = seq[var.id()];
3302  if (maximize(ub_expr, max_numer, max_denom, max_included)) {
3303  if (minimize(lb_expr, min_numer, min_denom, min_included)) {
3304  // The `ub_expr' has a maximum value and the `lb_expr'
3305  // has a minimum value for the box.
3306  // Set the bounds for `var' using the minimum for `lb_expr'.
3307  min_denom *= denominator;
3308  PPL_DIRTY_TEMP(mpq_class, q1);
3309  PPL_DIRTY_TEMP(mpq_class, q2);
3310  assign_r(q1.get_num(), min_numer, ROUND_NOT_NEEDED);
3311  assign_r(q1.get_den(), min_denom, ROUND_NOT_NEEDED);
3312  q1.canonicalize();
3313  // Now make the maximum of lb_expr the upper bound. If the
3314  // maximum is not at a box point, then inequality is strict.
3315  max_denom *= denominator;
3316  assign_r(q2.get_num(), max_numer, ROUND_NOT_NEEDED);
3317  assign_r(q2.get_den(), max_denom, ROUND_NOT_NEEDED);
3318  q2.canonicalize();
3319 
3320  if (denominator > 0) {
3321  Relation_Symbol gr = min_included ? GREATER_OR_EQUAL : GREATER_THAN;
3322  Relation_Symbol lr = max_included ? LESS_OR_EQUAL : LESS_THAN;
3323  seq_v.build(i_constraint(gr, q1), i_constraint(lr, q2));
3324  }
3325  else {
3326  Relation_Symbol gr = max_included ? GREATER_OR_EQUAL : GREATER_THAN;
3327  Relation_Symbol lr = min_included ? LESS_OR_EQUAL : LESS_THAN;
3328  seq_v.build(i_constraint(gr, q2), i_constraint(lr, q1));
3329  }
3330  }
3331  else {
3332  // The `ub_expr' has a maximum value but the `lb_expr'
3333  // has no minimum value for the box.
3334  // Set the bounds for `var' using the maximum for `lb_expr'.
3335  PPL_DIRTY_TEMP(mpq_class, q);
3336  max_denom *= denominator;
3337  assign_r(q.get_num(), max_numer, ROUND_NOT_NEEDED);
3338  assign_r(q.get_den(), max_denom, ROUND_NOT_NEEDED);
3339  q.canonicalize();
3340  Relation_Symbol rel = (denominator > 0)
3341  ? (max_included ? LESS_OR_EQUAL : LESS_THAN)
3342  : (max_included ? GREATER_OR_EQUAL : GREATER_THAN);
3343  seq_v.build(i_constraint(rel, q));
3344  }
3345  }
3346  else if (minimize(lb_expr, min_numer, min_denom, min_included)) {
3347  // The `ub_expr' has no maximum value but the `lb_expr'
3348  // has a minimum value for the box.
3349  // Set the bounds for `var' using the minimum for `lb_expr'.
3350  min_denom *= denominator;
3351  PPL_DIRTY_TEMP(mpq_class, q);
3352  assign_r(q.get_num(), min_numer, ROUND_NOT_NEEDED);
3353  assign_r(q.get_den(), min_denom, ROUND_NOT_NEEDED);
3354  q.canonicalize();
3355 
3356  Relation_Symbol rel = (denominator > 0)
3357  ? (min_included ? GREATER_OR_EQUAL : GREATER_THAN)
3358  : (min_included ? LESS_OR_EQUAL : LESS_THAN);
3359  seq_v.build(i_constraint(rel, q));
3360  }
3361  else {
3362  // The `ub_expr' has no maximum value and the `lb_expr'
3363  // has no minimum value for the box.
3364  // So we set the bounds to be unbounded.
3365  seq_v.assign(UNIVERSE);
3366  }
3367  }
3368  PPL_ASSERT(OK());
3369 }
3370 
3371 template <typename ITV>
3372 void
3373 Box<ITV>
3375  const Linear_Expression& lb_expr,
3376  const Linear_Expression& ub_expr,
3377  Coefficient_traits::const_reference denominator) {
3378  // The denominator cannot be zero.
3379  const dimension_type space_dim = space_dimension();
3380  if (denominator == 0) {
3381  throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
3382  }
3383 
3384  // Dimension-compatibility checks.
3385  // `var' should be one of the dimensions of the polyhedron.
3386  const dimension_type var_space_dim = var.space_dimension();
3387  if (space_dim < var_space_dim) {
3388  throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
3389  "v", var);
3390  }
3391  // The dimension of `lb_expr' and `ub_expr' should not be
3392  // greater than the dimension of `*this'.
3393  const dimension_type lb_space_dim = lb_expr.space_dimension();
3394  if (space_dim < lb_space_dim) {
3395  throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
3396  "lb", lb_expr);
3397  }
3398  const dimension_type ub_space_dim = ub_expr.space_dimension();
3399  if (space_dim < ub_space_dim) {
3400  throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
3401  "ub", ub_expr);
3402  }
3403 
3404  // Any preimage of an empty polyhedron is empty.
3405  if (marked_empty()) {
3406  return;
3407  }
3408 
3409  const bool negative_denom = (denominator < 0);
3410  const Coefficient& lb_var_coeff = lb_expr.coefficient(var);
3411  const Coefficient& ub_var_coeff = ub_expr.coefficient(var);
3412 
3413  // If the implied constraint between `ub_expr and `lb_expr' is
3414  // independent of `var', then impose it now.
3415  if (lb_var_coeff == ub_var_coeff) {
3416  if (negative_denom) {
3417  refine_with_constraint(lb_expr >= ub_expr);
3418  }
3419  else {
3420  refine_with_constraint(lb_expr <= ub_expr);
3421  }
3422  }
3423 
3424  ITV& seq_var = seq[var.id()];
3425  if (!seq_var.is_universe()) {
3426  // We want to work with a positive denominator,
3427  // so the sign and its (unsigned) value are separated.
3428  PPL_DIRTY_TEMP_COEFFICIENT(pos_denominator);
3429  pos_denominator = denominator;
3430  if (negative_denom) {
3431  neg_assign(pos_denominator, pos_denominator);
3432  }
3433  // Store all the information about the upper and lower bounds
3434  // for `var' before making this interval unbounded.
3435  bool open_lower = seq_var.lower_is_open();
3436  bool unbounded_lower = seq_var.lower_is_boundary_infinity();
3437  PPL_DIRTY_TEMP(mpq_class, q_seq_var_lower);
3438  PPL_DIRTY_TEMP_COEFFICIENT(numer_lower);
3439  PPL_DIRTY_TEMP_COEFFICIENT(denom_lower);
3440  if (!unbounded_lower) {
3441  assign_r(q_seq_var_lower, seq_var.lower(), ROUND_NOT_NEEDED);
3442  assign_r(numer_lower, q_seq_var_lower.get_num(), ROUND_NOT_NEEDED);
3443  assign_r(denom_lower, q_seq_var_lower.get_den(), ROUND_NOT_NEEDED);
3444  if (negative_denom) {
3445  neg_assign(denom_lower, denom_lower);
3446  }
3447  numer_lower *= pos_denominator;
3448  seq_var.lower_extend();
3449  }
3450  bool open_upper = seq_var.upper_is_open();
3451  bool unbounded_upper = seq_var.upper_is_boundary_infinity();
3452  PPL_DIRTY_TEMP(mpq_class, q_seq_var_upper);
3453  PPL_DIRTY_TEMP_COEFFICIENT(numer_upper);
3454  PPL_DIRTY_TEMP_COEFFICIENT(denom_upper);
3455  if (!unbounded_upper) {
3456  assign_r(q_seq_var_upper, seq_var.upper(), ROUND_NOT_NEEDED);
3457  assign_r(numer_upper, q_seq_var_upper.get_num(), ROUND_NOT_NEEDED);
3458  assign_r(denom_upper, q_seq_var_upper.get_den(), ROUND_NOT_NEEDED);
3459  if (negative_denom) {
3460  neg_assign(denom_upper, denom_upper);
3461  }
3462  numer_upper *= pos_denominator;
3463  seq_var.upper_extend();
3464  }
3465 
3466  if (!unbounded_lower) {
3467  // `lb_expr' is revised by removing the `var' component,
3468  // multiplying by `-' denominator of the lower bound for `var',
3469  // and adding the lower bound for `var' to the inhomogeneous term.
3470  Linear_Expression revised_lb_expr(ub_expr);
3471  revised_lb_expr -= ub_var_coeff * var;
3473  neg_assign(d, denom_lower);
3474  revised_lb_expr *= d;
3475  revised_lb_expr += numer_lower;
3476 
3477  // Find the minimum value for the revised lower bound expression
3478  // and use this to refine the appropriate bound.
3479  bool included;
3481  if (minimize(revised_lb_expr, numer_lower, denom, included)) {
3482  denom_lower *= (denom * ub_var_coeff);
3483  PPL_DIRTY_TEMP(mpq_class, q);
3484  assign_r(q.get_num(), numer_lower, ROUND_NOT_NEEDED);
3485  assign_r(q.get_den(), denom_lower, ROUND_NOT_NEEDED);
3486  q.canonicalize();
3487  if (!included) {
3488  open_lower = true;
3489  }
3490  Relation_Symbol rel;
3491  if ((ub_var_coeff >= 0) ? !negative_denom : negative_denom) {
3492  rel = open_lower ? GREATER_THAN : GREATER_OR_EQUAL;
3493  }
3494  else {
3495  rel = open_lower ? LESS_THAN : LESS_OR_EQUAL;
3496  }
3497  seq_var.add_constraint(i_constraint(rel, q));
3498  if (seq_var.is_empty()) {
3499  set_empty();
3500  return;
3501  }
3502  }
3503  }
3504 
3505  if (!unbounded_upper) {
3506  // `ub_expr' is revised by removing the `var' component,
3507  // multiplying by `-' denominator of the upper bound for `var',
3508  // and adding the upper bound for `var' to the inhomogeneous term.
3509  Linear_Expression revised_ub_expr(lb_expr);
3510  revised_ub_expr -= lb_var_coeff * var;
3512  neg_assign(d, denom_upper);
3513  revised_ub_expr *= d;
3514  revised_ub_expr += numer_upper;
3515 
3516  // Find the maximum value for the revised upper bound expression
3517  // and use this to refine the appropriate bound.
3518  bool included;
3520  if (maximize(revised_ub_expr, numer_upper, denom, included)) {
3521  denom_upper *= (denom * lb_var_coeff);
3522  PPL_DIRTY_TEMP(mpq_class, q);
3523  assign_r(q.get_num(), numer_upper, ROUND_NOT_NEEDED);
3524  assign_r(q.get_den(), denom_upper, ROUND_NOT_NEEDED);
3525  q.canonicalize();
3526  if (!included) {
3527  open_upper = true;
3528  }
3529  Relation_Symbol rel;
3530  if ((lb_var_coeff >= 0) ? !negative_denom : negative_denom) {
3531  rel = open_upper ? LESS_THAN : LESS_OR_EQUAL;
3532  }
3533  else {
3534  rel = open_upper ? GREATER_THAN : GREATER_OR_EQUAL;
3535  }
3536  seq_var.add_constraint(i_constraint(rel, q));
3537  if (seq_var.is_empty()) {
3538  set_empty();
3539  return;
3540  }
3541  }
3542  }
3543  }
3544 
3545  // If the implied constraint between `ub_expr and `lb_expr' is
3546  // dependent on `var', then impose on the new box.
3547  if (lb_var_coeff != ub_var_coeff) {
3548  if (denominator > 0) {
3549  refine_with_constraint(lb_expr <= ub_expr);
3550  }
3551  else {
3552  refine_with_constraint(lb_expr >= ub_expr);
3553  }
3554  }
3555 
3556  PPL_ASSERT(OK());
3557 }
3558 
3559 template <typename ITV>
3560 void
3561 Box<ITV>
3563  const Relation_Symbol relsym,
3564  const Linear_Expression& expr,
3565  Coefficient_traits::const_reference denominator) {
3566  // The denominator cannot be zero.
3567  if (denominator == 0) {
3568  throw_invalid_argument("generalized_affine_image(v, r, e, d)", "d == 0");
3569  }
3570 
3571  // Dimension-compatibility checks.
3572  const dimension_type space_dim = space_dimension();
3573  // The dimension of `expr' should not be greater than the dimension
3574  // of `*this'.
3575  if (space_dim < expr.space_dimension()) {
3576  throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
3577  "e", expr);
3578  }
3579  // `var' should be one of the dimensions of the box.
3580  const dimension_type var_space_dim = var.space_dimension();
3581  if (space_dim < var_space_dim) {
3582  throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
3583  "v", var);
3584  }
3585 
3586  // The relation symbol cannot be a disequality.
3587  if (relsym == NOT_EQUAL) {
3588  throw_invalid_argument("generalized_affine_image(v, r, e, d)",
3589  "r is the disequality relation symbol");
3590  }
3591 
3592  // First compute the affine image.
3593  affine_image(var, expr, denominator);
3594 
3595  if (relsym == EQUAL) {
3596  // The affine relation is indeed an affine function.
3597  return;
3598  }
3599  // Any image of an empty box is empty.
3600  if (is_empty()) {
3601  return;
3602  }
3603 
3604  ITV& seq_var = seq[var.id()];
3605  switch (relsym) {
3606  case LESS_OR_EQUAL:
3607  seq_var.lower_extend();
3608  break;
3609  case LESS_THAN:
3610  seq_var.lower_extend();
3611  if (!seq_var.upper_is_boundary_infinity()) {
3612  seq_var.remove_sup();
3613  }
3614  break;
3615  case GREATER_OR_EQUAL:
3616  seq_var.upper_extend();
3617  break;
3618  case GREATER_THAN:
3619  seq_var.upper_extend();
3620  if (!seq_var.lower_is_boundary_infinity()) {
3621  seq_var.remove_inf();
3622  }
3623  break;
3624  default:
3625  // The EQUAL and NOT_EQUAL cases have been already dealt with.
3626  PPL_UNREACHABLE;
3627  break;
3628  }
3629  PPL_ASSERT(OK());
3630 }
3631 
3632 template <typename ITV>
3633 void
3634 Box<ITV>
3636  const Relation_Symbol relsym,
3637  const Linear_Expression& expr,
3638  Coefficient_traits::const_reference denominator)
3639 {
3640  // The denominator cannot be zero.
3641  if (denominator == 0) {
3642  throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
3643  "d == 0");
3644  }
3645  // Dimension-compatibility checks.
3646  const dimension_type space_dim = space_dimension();
3647  // The dimension of `expr' should not be greater than the dimension
3648  // of `*this'.
3649  if (space_dim < expr.space_dimension()) {
3650  throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
3651  "e", expr);
3652  }
3653  // `var' should be one of the dimensions of the box.
3654  const dimension_type var_space_dim = var.space_dimension();
3655  if (space_dim < var_space_dim) {
3656  throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
3657  "v", var);
3658  }
3659  // The relation symbol cannot be a disequality.
3660  if (relsym == NOT_EQUAL) {
3661  throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
3662  "r is the disequality relation symbol");
3663  }
3664 
3665  // Check whether the affine relation is indeed an affine function.
3666  if (relsym == EQUAL) {
3667  affine_preimage(var, expr, denominator);
3668  return;
3669  }
3670 
3671  // Compute the reversed relation symbol to simplify later coding.
3672  Relation_Symbol reversed_relsym;
3673  switch (relsym) {
3674  case LESS_THAN:
3675  reversed_relsym = GREATER_THAN;
3676  break;
3677  case LESS_OR_EQUAL:
3678  reversed_relsym = GREATER_OR_EQUAL;
3679  break;
3680  case GREATER_OR_EQUAL:
3681  reversed_relsym = LESS_OR_EQUAL;
3682  break;
3683  case GREATER_THAN:
3684  reversed_relsym = LESS_THAN;
3685  break;
3686  default:
3687  // The EQUAL and NOT_EQUAL cases have been already dealt with.
3688  PPL_UNREACHABLE;
3689  break;
3690  }
3691 
3692  // Check whether the preimage of this affine relation can be easily
3693  // computed as the image of its inverse relation.
3694  const Coefficient& var_coefficient = expr.coefficient(var);
3695  if (var_coefficient != 0) {
3696  Linear_Expression inverse_expr
3697  = expr - (denominator + var_coefficient) * var;
3698  PPL_DIRTY_TEMP_COEFFICIENT(inverse_denominator);
3699  neg_assign(inverse_denominator, var_coefficient);
3700  Relation_Symbol inverse_relsym
3701  = (sgn(denominator) == sgn(inverse_denominator))
3702  ? relsym
3703  : reversed_relsym;
3704  generalized_affine_image(var, inverse_relsym, inverse_expr,
3705  inverse_denominator);
3706  return;
3707  }
3708 
3709  // Here `var_coefficient == 0', so that the preimage cannot
3710  // be easily computed by inverting the affine relation.
3711  // Shrink the box by adding the constraint induced
3712  // by the affine relation.
3713  // First, compute the maximum and minimum value reached by
3714  // `denominator*var' on the box as we need to use non-relational
3715  // expressions.
3716  PPL_DIRTY_TEMP_COEFFICIENT(max_numer);
3717  PPL_DIRTY_TEMP_COEFFICIENT(max_denom);
3718  bool max_included;
3719  bool bound_above = maximize(denominator*var, max_numer, max_denom, max_included);
3720  PPL_DIRTY_TEMP_COEFFICIENT(min_numer);
3721  PPL_DIRTY_TEMP_COEFFICIENT(min_denom);
3722  bool min_included;
3723  bool bound_below = minimize(denominator*var, min_numer, min_denom, min_included);
3724  // Use the correct relation symbol
3725  const Relation_Symbol corrected_relsym
3726  = (denominator > 0) ? relsym : reversed_relsym;
3727  // Revise the expression to take into account the denominator of the
3728  // maximum/minimum value for `var'.
3729  Linear_Expression revised_expr;
3731  if (corrected_relsym == LESS_THAN || corrected_relsym == LESS_OR_EQUAL) {
3732  if (bound_below) {
3733  revised_expr = expr;
3734  revised_expr.set_inhomogeneous_term(Coefficient_zero());
3735  revised_expr *= d;
3736  }
3737  }
3738  else {
3739  if (bound_above) {
3740  revised_expr = expr;
3741  revised_expr.set_inhomogeneous_term(Coefficient_zero());
3742  revised_expr *= max_denom;
3743  }
3744  }
3745 
3746  switch (corrected_relsym) {
3747  case LESS_THAN:
3748  if (bound_below) {
3749  refine_with_constraint(min_numer < revised_expr);
3750  }
3751  break;
3752  case LESS_OR_EQUAL:
3753  if (bound_below) {
3754  (min_included)
3755  ? refine_with_constraint(min_numer <= revised_expr)
3756  : refine_with_constraint(min_numer < revised_expr);
3757  }
3758  break;
3759  case GREATER_OR_EQUAL:
3760  if (bound_above) {
3761  (max_included)
3762  ? refine_with_constraint(max_numer >= revised_expr)
3763  : refine_with_constraint(max_numer > revised_expr);
3764  }
3765  break;
3766  case GREATER_THAN:
3767  if (bound_above) {
3768  refine_with_constraint(max_numer > revised_expr);
3769  }
3770  break;
3771  default:
3772  // The EQUAL and NOT_EQUAL cases have been already dealt with.
3773  PPL_UNREACHABLE;
3774  break;
3775  }
3776  // If the shrunk box is empty, its preimage is empty too.
3777  if (is_empty()) {
3778  return;
3779  }
3780  ITV& seq_v = seq[var.id()];
3781  seq_v.assign(UNIVERSE);
3782  PPL_ASSERT(OK());
3783 }
3784 
3785 template <typename ITV>
3786 void
3787 Box<ITV>
3789  const Relation_Symbol relsym,
3790  const Linear_Expression& rhs) {
3791  // Dimension-compatibility checks.
3792  // The dimension of `lhs' should not be greater than the dimension
3793  // of `*this'.
3794  dimension_type lhs_space_dim = lhs.space_dimension();
3795  const dimension_type space_dim = space_dimension();
3796  if (space_dim < lhs_space_dim) {
3797  throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
3798  "e1", lhs);
3799  }
3800  // The dimension of `rhs' should not be greater than the dimension
3801  // of `*this'.
3802  const dimension_type rhs_space_dim = rhs.space_dimension();
3803  if (space_dim < rhs_space_dim) {
3804  throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
3805  "e2", rhs);
3806  }
3807 
3808  // The relation symbol cannot be a disequality.
3809  if (relsym == NOT_EQUAL) {
3810  throw_invalid_argument("generalized_affine_image(e1, r, e2)",
3811  "r is the disequality relation symbol");
3812  }
3813 
3814  // Any image of an empty box is empty.
3815  if (marked_empty()) {
3816  return;
3817  }
3818 
3819  // Compute the maximum and minimum value reached by the rhs on the box.
3820  PPL_DIRTY_TEMP_COEFFICIENT(max_numer);
3821  PPL_DIRTY_TEMP_COEFFICIENT(max_denom);
3822  bool max_included;
3823  bool max_rhs = maximize(rhs, max_numer, max_denom, max_included);
3824  PPL_DIRTY_TEMP_COEFFICIENT(min_numer);
3825  PPL_DIRTY_TEMP_COEFFICIENT(min_denom);
3826  bool min_included;
3827  bool min_rhs = minimize(rhs, min_numer, min_denom, min_included);
3828 
3829  // Check whether there is 0, 1 or more than one variable in the lhs
3830  // and record the variable with the highest dimension; set the box
3831  // intervals to be unbounded for all other dimensions with non-zero
3832  // coefficients in the lhs.
3833  bool has_var = false;
3834  dimension_type has_var_id = lhs.last_nonzero();
3835 
3836  if (has_var_id != 0) {
3837  has_var = true;
3838  --has_var_id;
3839  dimension_type other_var = lhs.first_nonzero(1, has_var_id + 1);
3840  --other_var;
3841  if (other_var != has_var_id) {
3842  // There is more than one dimension with non-zero coefficient, so
3843  // we cannot have any information about the dimensions in the lhs.
3844  ITV& seq_var = seq[has_var_id];
3845  seq_var.assign(UNIVERSE);
3846  // Since all but the highest dimension with non-zero coefficient
3847  // in the lhs have been set unbounded, it remains to set the
3848  // highest dimension in the lhs unbounded.
3849  ITV& seq_i = seq[other_var];
3850  seq_i.assign(UNIVERSE);
3851  PPL_ASSERT(OK());
3852  return;
3853  }
3854  }
3855 
3856  if (has_var) {
3857  // There is exactly one dimension with non-zero coefficient.
3858  ITV& seq_var = seq[has_var_id];
3859 
3860  // Compute the new bounds for this dimension defined by the rhs
3861  // expression.
3862  const Coefficient& inhomo = lhs.inhomogeneous_term();
3863  const Coefficient& coeff = lhs.coefficient(Variable(has_var_id));
3864  PPL_DIRTY_TEMP(mpq_class, q_max);
3865  PPL_DIRTY_TEMP(mpq_class, q_min);
3866  if (max_rhs) {
3867  max_numer -= inhomo * max_denom;
3868  max_denom *= coeff;
3869  assign_r(q_max.get_num(), max_numer, ROUND_NOT_NEEDED);
3870  assign_r(q_max.get_den(), max_denom, ROUND_NOT_NEEDED);
3871  q_max.canonicalize();
3872  }
3873  if (min_rhs) {
3874  min_numer -= inhomo * min_denom;
3875  min_denom *= coeff;
3876  assign_r(q_min.get_num(), min_numer, ROUND_NOT_NEEDED);
3877  assign_r(q_min.get_den(), min_denom, ROUND_NOT_NEEDED);
3878  q_min.canonicalize();
3879  }
3880 
3881  // The choice as to which bounds should be set depends on the sign
3882  // of the coefficient of the dimension `has_var_id' in the lhs.
3883  if (coeff > 0) {
3884  // The coefficient of the dimension in the lhs is positive.
3885  switch (relsym) {
3886  case LESS_OR_EQUAL:
3887  if (max_rhs) {
3888  Relation_Symbol rel = max_included ? LESS_OR_EQUAL : LESS_THAN;
3889  seq_var.build(i_constraint(rel, q_max));
3890  }
3891  else {
3892  seq_var.assign(UNIVERSE);
3893  }
3894  break;
3895  case LESS_THAN:
3896  if (max_rhs) {
3897  seq_var.build(i_constraint(LESS_THAN, q_max));
3898  }
3899  else {
3900  seq_var.assign(UNIVERSE);
3901  }
3902  break;
3903  case EQUAL:
3904  {
3907  if (max_rhs) {
3908  u.set(max_included ? LESS_OR_EQUAL : LESS_THAN, q_max);
3909  }
3910  if (min_rhs) {
3911  l.set(min_included ? GREATER_OR_EQUAL : GREATER_THAN, q_min);
3912  }
3913  seq_var.build(l, u);
3914  break;
3915  }
3916  case GREATER_OR_EQUAL:
3917  if (min_rhs) {
3918  Relation_Symbol rel = min_included ? GREATER_OR_EQUAL : GREATER_THAN;
3919  seq_var.build(i_constraint(rel, q_min));
3920  }
3921  else {
3922  seq_var.assign(UNIVERSE);
3923  }
3924  break;
3925  case GREATER_THAN:
3926  if (min_rhs) {
3927  seq_var.build(i_constraint(GREATER_THAN, q_min));
3928  }
3929  else {
3930  seq_var.assign(UNIVERSE);
3931  }
3932  break;
3933  default:
3934  // The NOT_EQUAL case has been already dealt with.
3935  PPL_UNREACHABLE;
3936  break;
3937  }
3938  }
3939  else {
3940  // The coefficient of the dimension in the lhs is negative.
3941  switch (relsym) {
3942  case GREATER_OR_EQUAL:
3943  if (min_rhs) {
3944  Relation_Symbol rel = min_included ? LESS_OR_EQUAL : LESS_THAN;
3945  seq_var.build(i_constraint(rel, q_min));
3946  }
3947  else {
3948  seq_var.assign(UNIVERSE);
3949  }
3950  break;
3951  case GREATER_THAN:
3952  if (min_rhs) {
3953  seq_var.build(i_constraint(LESS_THAN, q_min));
3954  }
3955  else {
3956  seq_var.assign(UNIVERSE);
3957  }
3958  break;
3959  case EQUAL:
3960  {
3963  if (max_rhs) {
3964  l.set(max_included ? GREATER_OR_EQUAL : GREATER_THAN, q_max);
3965  }
3966  if (min_rhs) {
3967  u.set(min_included ? LESS_OR_EQUAL : LESS_THAN, q_min);
3968  }
3969  seq_var.build(l, u);
3970  break;
3971  }
3972  case LESS_OR_EQUAL:
3973  if (max_rhs) {
3974  Relation_Symbol rel = max_included ? GREATER_OR_EQUAL : GREATER_THAN;
3975  seq_var.build(i_constraint(rel, q_max));
3976  }
3977  else {
3978  seq_var.assign(UNIVERSE);
3979  }
3980  break;
3981  case LESS_THAN:
3982  if (max_rhs) {
3983  seq_var.build(i_constraint(GREATER_THAN, q_max));
3984  }
3985  else {
3986  seq_var.assign(UNIVERSE);
3987  }
3988  break;
3989  default:
3990  // The NOT_EQUAL case has been already dealt with.
3991  PPL_UNREACHABLE;
3992  break;
3993  }
3994  }
3995  }
3996 
3997  else {
3998  // The lhs is a constant value, so we just need to add the
3999  // appropriate constraint.
4000  const Coefficient& inhomo = lhs.inhomogeneous_term();
4001  switch (relsym) {
4002  case LESS_THAN:
4003  refine_with_constraint(inhomo < rhs);
4004  break;
4005  case LESS_OR_EQUAL:
4006  refine_with_constraint(inhomo <= rhs);
4007  break;
4008  case EQUAL:
4009  refine_with_constraint(inhomo == rhs);
4010  break;
4011  case GREATER_OR_EQUAL:
4012  refine_with_constraint(inhomo >= rhs);
4013  break;
4014  case GREATER_THAN:
4015  refine_with_constraint(inhomo > rhs);
4016  break;
4017  default:
4018  // The NOT_EQUAL case has been already dealt with.
4019  PPL_UNREACHABLE;
4020  break;
4021  }
4022  }
4023  PPL_ASSERT(OK());
4024 }
4025 
4026 template <typename ITV>
4027 void
4029  const Relation_Symbol relsym,
4030  const Linear_Expression& rhs) {
4031  // Dimension-compatibility checks.
4032  // The dimension of `lhs' should not be greater than the dimension
4033  // of `*this'.
4034  dimension_type lhs_space_dim = lhs.space_dimension();
4035  const dimension_type space_dim = space_dimension();
4036  if (space_dim < lhs_space_dim) {
4037  throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
4038  "e1", lhs);
4039  }
4040  // The dimension of `rhs' should not be greater than the dimension
4041  // of `*this'.
4042  const dimension_type rhs_space_dim = rhs.space_dimension();
4043  if (space_dim < rhs_space_dim) {
4044  throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
4045  "e2", rhs);
4046  }
4047 
4048  // The relation symbol cannot be a disequality.
4049  if (relsym == NOT_EQUAL) {
4050  throw_invalid_argument("generalized_affine_image(e1, r, e2)",
4051  "r is the disequality relation symbol");
4052  }
4053  // Any image of an empty box is empty.
4054  if (marked_empty()) {
4055  return;
4056  }
4057  // For any dimension occurring in the lhs, swap and change the sign
4058  // of this component for the rhs and lhs. Then use these in a call
4059  // to generalized_affine_image/3.
4060  Linear_Expression revised_lhs = lhs;
4061  Linear_Expression revised_rhs = rhs;
4063  i_end = lhs.end(); i != i_end; ++i) {
4064  const Variable var = i.variable();
4066  tmp = *i;
4067  tmp += rhs.coefficient(var);
4068  sub_mul_assign(revised_rhs, tmp, var);
4069  sub_mul_assign(revised_lhs, tmp, var);
4070  }
4071  generalized_affine_image(revised_lhs, relsym, revised_rhs);
4072  PPL_ASSERT(OK());
4073 }
4074 
4075 template <typename ITV>
4076 template <typename T, typename Iterator>
4079  void>::type
4080 Box<ITV>::CC76_widening_assign(const T& y, Iterator first, Iterator last) {
4081  if (y.is_empty()) {
4082  return;
4083  }
4084  for (dimension_type i = seq.size(); i-- > 0; ) {
4085  seq[i].CC76_widening_assign(y.seq[i], first, last);
4086  }
4087 
4088  PPL_ASSERT(OK());
4089 }
4090 
4091 template <typename ITV>
4092 template <typename T>
4094  && Is_Same_Or_Derived<Interval_Base, ITV>::value,
4095  void>::type
4096 Box<ITV>::CC76_widening_assign(const T& y, unsigned* tp) {
4097  static typename ITV::boundary_type stop_points[] = {
4098  typename ITV::boundary_type(-2),
4099  typename ITV::boundary_type(-1),
4100  typename ITV::boundary_type(0),
4101  typename ITV::boundary_type(1),
4102  typename ITV::boundary_type(2)
4103  };
4104 
4105  Box& x = *this;
4106  // If there are tokens available, work on a temporary copy.
4107  if (tp != 0 && *tp > 0) {
4108  Box<ITV> x_tmp(x);
4109  x_tmp.CC76_widening_assign(y, 0);
4110  // If the widening was not precise, use one of the available tokens.
4111  if (!x.contains(x_tmp)) {
4112  --(*tp);
4113  }
4114  return;
4115  }
4117  stop_points,
4118  stop_points
4119  + sizeof(stop_points)/sizeof(stop_points[0]));
4120 }
4121 
4122 template <typename ITV>
4123 void
4125  Box& limiting_box) const {
4126  // Private method: the caller has to ensure the following.
4127  PPL_ASSERT(cs.space_dimension() <= space_dimension());
4128 
4129  for (Constraint_System::const_iterator cs_i = cs.begin(),
4130  cs_end = cs.end(); cs_i != cs_end; ++cs_i) {
4131  const Constraint& c = *cs_i;
4132  dimension_type c_num_vars = 0;
4133  dimension_type c_only_var = 0;
4134  // Constraints that are not interval constraints are ignored.
4135  if (!Box_Helpers::extract_interval_constraint(c, c_num_vars, c_only_var)) {
4136  continue;
4137  }
4138  // Trivial constraints are ignored.
4139  if (c_num_vars != 0) {
4140  // c is a non-trivial interval constraint.
4141  // add interval constraint to limiting box
4142  const Coefficient& n = c.inhomogeneous_term();
4143  const Coefficient& d = c.coefficient(Variable(c_only_var));
4144  if (interval_relation(seq[c_only_var], c.type(), n, d)
4146  limiting_box.add_interval_constraint_no_check(c_only_var, c.type(),
4147  n, d);
4148  }
4149  }
4150  }
4151 }
4152 
4153 template <typename ITV>
4154 void
4156  const Constraint_System& cs,
4157  unsigned* tp) {
4158  Box& x = *this;
4159  const dimension_type space_dim = x.space_dimension();
4160 
4161  // Dimension-compatibility check.
4162  if (space_dim != y.space_dimension()) {
4163  throw_dimension_incompatible("limited_CC76_extrapolation_assign(y, cs)",
4164  y);
4165  }
4166  // `cs' must be dimension-compatible with the two boxes.
4167  const dimension_type cs_space_dim = cs.space_dimension();
4168  if (space_dim < cs_space_dim) {
4169  throw_constraint_incompatible("limited_CC76_extrapolation_assign(y, cs)");
4170  }
4171  // The limited CC76-extrapolation between two boxes in a
4172  // zero-dimensional space is also a zero-dimensional box
4173  if (space_dim == 0) {
4174  return;
4175  }
4176  // Assume `y' is contained in or equal to `*this'.
4177  PPL_EXPECT_HEAVY(copy_contains(*this, y));
4178 
4179  // If `*this' is empty, since `*this' contains `y', `y' is empty too.
4180  if (marked_empty()) {
4181  return;
4182  }
4183  // If `y' is empty, we return.
4184  if (y.marked_empty()) {
4185  return;
4186  }
4187  // Build a limiting box using all the constraints in cs
4188  // that are satisfied by *this.
4189  Box limiting_box(space_dim, UNIVERSE);
4190  get_limiting_box(cs, limiting_box);
4191 
4192  x.CC76_widening_assign(y, tp);
4193 
4194  // Intersect the widened box with the limiting box.
4195  intersection_assign(limiting_box);
4196 }
4197 
4198 template <typename ITV>
4199 template <typename T>
4201  && Is_Same_Or_Derived<Interval_Base, ITV>::value,
4202  void>::type
4204  const dimension_type space_dim = space_dimension();
4205 
4206  // Dimension-compatibility check.
4207  if (space_dim != y.space_dimension()) {
4208  throw_dimension_incompatible("CC76_narrowing_assign(y)", y);
4209  }
4210 
4211  // Assume `*this' is contained in or equal to `y'.
4212  PPL_EXPECT_HEAVY(copy_contains(y, *this));
4213 
4214  // If both boxes are zero-dimensional,
4215  // since `y' contains `*this', we simply return `*this'.
4216  if (space_dim == 0) {
4217  return;
4218  }
4219  // If `y' is empty, since `y' contains `this', `*this' is empty too.
4220  if (y.is_empty()) {
4221  return;
4222  }
4223  // If `*this' is empty, we return.
4224  if (is_empty()) {
4225  return;
4226  }
4227  // Replace each constraint in `*this' by the corresponding constraint
4228  // in `y' if the corresponding inhomogeneous terms are both finite.
4229  for (dimension_type i = space_dim; i-- > 0; ) {
4230  ITV& x_i = seq[i];
4231  const ITV& y_i = y.seq[i];
4232  if (!x_i.lower_is_boundary_infinity()
4233  && !y_i.lower_is_boundary_infinity()
4234  && x_i.lower() != y_i.lower()) {
4235  x_i.lower() = y_i.lower();
4236  }
4237  if (!x_i.upper_is_boundary_infinity()
4238  && !y_i.upper_is_boundary_infinity()
4239  && x_i.upper() != y_i.upper()) {
4240  x_i.upper() = y_i.upper();
4241  }
4242  }
4243  PPL_ASSERT(OK());
4244 }
4245 
4246 template <typename ITV>
4249  const dimension_type space_dim = space_dimension();
4250  Constraint_System cs;
4251  cs.set_space_dimension(space_dim);
4252 
4253  if (space_dim == 0) {
4254  if (marked_empty()) {
4256  }
4257  return cs;
4258  }
4259 
4260  if (marked_empty()) {
4262  return cs;
4263  }
4264 
4265  for (dimension_type k = 0; k < space_dim; ++k) {
4266  const Variable v_k = Variable(k);
4269  bool closed = false;
4270  if (has_lower_bound(v_k, n, d, closed)) {
4271  if (closed) {
4272  cs.insert(d * v_k >= n);
4273  }
4274  else {
4275  cs.insert(d * v_k > n);
4276  }
4277  }
4278  if (has_upper_bound(v_k, n, d, closed)) {
4279  if (closed) {
4280  cs.insert(d * v_k <= n);
4281  }
4282  else {
4283  cs.insert(d * v_k < n);
4284  }
4285  }
4286  }
4287  return cs;
4288 }
4289 
4290 template <typename ITV>
4293  const dimension_type space_dim = space_dimension();
4294  Constraint_System cs;
4295  cs.set_space_dimension(space_dim);
4296 
4297  if (space_dim == 0) {
4298  if (marked_empty()) {
4300  }
4301  return cs;
4302  }
4303 
4304  // Make sure emptiness is detected.
4305  if (is_empty()) {
4307  return cs;
4308  }
4309 
4310  for (dimension_type k = 0; k < space_dim; ++k) {
4311  const Variable v_k = Variable(k);
4314  bool closed = false;
4315  if (has_lower_bound(v_k, n, d, closed)) {
4316  if (closed) {
4317  // Make sure equality constraints are detected.
4318  if (seq[k].is_singleton()) {
4319  cs.insert(d * v_k == n);
4320  continue;
4321  }
4322  else {
4323  cs.insert(d * v_k >= n);
4324  }
4325  }
4326  else {
4327  cs.insert(d * v_k > n);
4328  }
4329  }
4330  if (has_upper_bound(v_k, n, d, closed)) {
4331  if (closed) {
4332  cs.insert(d * v_k <= n);
4333  }
4334  else {
4335  cs.insert(d * v_k < n);
4336  }
4337  }
4338  }
4339  return cs;
4340 }
4341 
4342 template <typename ITV>
4345  const dimension_type space_dim = space_dimension();
4346  Congruence_System cgs(space_dim);
4347 
4348  if (space_dim == 0) {
4349  if (marked_empty()) {
4351  }
4352  return cgs;
4353  }
4354 
4355  // Make sure emptiness is detected.
4356  if (is_empty()) {
4358  return cgs;
4359  }
4360 
4361  for (dimension_type k = 0; k < space_dim; ++k) {
4362  const Variable v_k = Variable(k);
4365  bool closed = false;
4366  if (has_lower_bound(v_k, n, d, closed) && closed) {
4367  // Make sure equality congruences are detected.
4368  if (seq[k].is_singleton()) {
4369  cgs.insert((d * v_k %= n) / 0);
4370  }
4371  }
4372  }
4373  return cgs;
4374 }
4375 
4376 template <typename ITV>
4379  memory_size_type n = seq.capacity() * sizeof(ITV);
4380  for (dimension_type k = seq.size(); k-- > 0; ) {
4381  n += seq[k].external_memory_in_bytes();
4382  }
4383  return n;
4384 }
4385 
4387 template <typename ITV>
4388 std::ostream&
4389 IO_Operators::operator<<(std::ostream& s, const Box<ITV>& box) {
4390  if (box.is_empty()) {
4391  s << "false";
4392  }
4393  else if (box.is_universe()) {
4394  s << "true";
4395  }
4396  else {
4397  for (dimension_type k = 0,
4398  space_dim = box.space_dimension(); k < space_dim; ) {
4399  s << Variable(k) << " in " << box[k];
4400  ++k;
4401  if (k < space_dim) {
4402  s << ", ";
4403  }
4404  else {
4405  break;
4406  }
4407  }
4408  }
4409  return s;
4410 }
4411 
4412 template <typename ITV>
4413 void
4414 Box<ITV>::ascii_dump(std::ostream& s) const {
4415  const char separator = ' ';
4416  status.ascii_dump(s);
4417  const dimension_type space_dim = space_dimension();
4418  s << "space_dim" << separator << space_dim;
4419  s << "\n";
4420  for (dimension_type i = 0; i < space_dim; ++i) {
4421  seq[i].ascii_dump(s);
4422  }
4423 }
4424 
4426 
4427 template <typename ITV>
4428 bool
4429 Box<ITV>::ascii_load(std::istream& s) {
4430  if (!status.ascii_load(s)) {
4431  return false;
4432  }
4433  std::string str;
4434  dimension_type space_dim;
4435  if (!(s >> str) || str != "space_dim") {
4436  return false;
4437  }
4438  if (!(s >> space_dim)) {
4439  return false;
4440  }
4441  seq.clear();
4442  ITV seq_i;
4443  for (dimension_type i = 0; i < space_dim; ++i) {
4444  if (seq_i.ascii_load(s)) {
4445  seq.push_back(seq_i);
4446  }
4447  else {
4448  return false;
4449  }
4450  }
4451 
4452  // Check invariants.
4453  PPL_ASSERT(OK());
4454  return true;
4455 }
4456 
4457 template <typename ITV>
4458 void
4460  const Box& y) const {
4461  std::ostringstream s;
4462  s << "PPL::Box::" << method << ":" << std::endl
4463  << "this->space_dimension() == " << this->space_dimension()
4464  << ", y->space_dimension() == " << y.space_dimension() << ".";
4465  throw std::invalid_argument(s.str());
4466 }
4467 
4468 template <typename ITV>
4469 void
4470 Box<ITV>
4472  dimension_type required_dim) const {
4473  std::ostringstream s;
4474  s << "PPL::Box::" << method << ":" << std::endl
4475  << "this->space_dimension() == " << space_dimension()
4476  << ", required dimension == " << required_dim << ".";
4477  throw std::invalid_argument(s.str());
4478 }
4479 
4480 template <typename ITV>
4481 void
4483  const Constraint& c) const {
4484  std::ostringstream s;
4485  s << "PPL::Box::" << method << ":" << std::endl
4486  << "this->space_dimension() == " << space_dimension()
4487  << ", c->space_dimension == " << c.space_dimension() << ".";
4488  throw std::invalid_argument(s.str());
4489 }
4490 
4491 template <typename ITV>
4492 void
4494  const Congruence& cg) const {
4495  std::ostringstream s;
4496  s << "PPL::Box::" << method << ":" << std::endl
4497  << "this->space_dimension() == " << space_dimension()
4498  << ", cg->space_dimension == " << cg.space_dimension() << ".";
4499  throw std::invalid_argument(s.str());
4500 }
4501 
4502 template <typename ITV>
4503 void
4505  const Constraint_System& cs) const {
4506  std::ostringstream s;
4507  s << "PPL::Box::" << method << ":" << std::endl
4508  << "this->space_dimension() == " << space_dimension()
4509  << ", cs->space_dimension == " << cs.space_dimension() << ".";
4510  throw std::invalid_argument(s.str());
4511 }
4512 
4513 template <typename ITV>
4514 void
4516  const Congruence_System& cgs) const {
4517  std::ostringstream s;
4518  s << "PPL::Box::" << method << ":" << std::endl
4519  << "this->space_dimension() == " << space_dimension()
4520  << ", cgs->space_dimension == " << cgs.space_dimension() << ".";
4521  throw std::invalid_argument(s.str());
4522 }
4523 
4524 template <typename ITV>
4525 void
4527  const Generator& g) const {
4528  std::ostringstream s;
4529  s << "PPL::Box::" << method << ":" << std::endl
4530  << "this->space_dimension() == " << space_dimension()
4531  << ", g->space_dimension == " << g.space_dimension() << ".";
4532  throw std::invalid_argument(s.str());
4533 }
4534 
4535 template <typename ITV>
4536 void
4538  std::ostringstream s;
4539  s << "PPL::Box::" << method << ":" << std::endl
4540  << "the constraint is incompatible.";
4541  throw std::invalid_argument(s.str());
4542 }
4543 
4544 template <typename ITV>
4545 void
4547  const Linear_Expression& le) {
4548  using namespace IO_Operators;
4549  std::ostringstream s;
4550  s << "PPL::Box::" << method << ":" << std::endl
4551  << le << " is too complex.";
4552  throw std::invalid_argument(s.str());
4553 }
4554 
4555 template <typename ITV>
4556 void
4558  const char* le_name,
4559  const Linear_Expression& le) const {
4560  std::ostringstream s;
4561  s << "PPL::Box::" << method << ":" << std::endl
4562  << "this->space_dimension() == " << space_dimension()
4563  << ", " << le_name << "->space_dimension() == "
4564  << le.space_dimension() << ".";
4565  throw std::invalid_argument(s.str());
4566 }
4567 
4568 template <typename ITV>
4569 template <typename C>
4570 void
4572  const char* lf_name,
4573  const Linear_Form<C>& lf) const {
4574  std::ostringstream s;
4575  s << "PPL::Box::" << method << ":\n"
4576  << "this->space_dimension() == " << space_dimension()
4577  << ", " << lf_name << "->space_dimension() == "
4578  << lf.space_dimension() << ".";
4579  throw std::invalid_argument(s.str());
4580 }
4581 
4582 template <typename ITV>
4583 void
4584 Box<ITV>::throw_invalid_argument(const char* method, const char* reason) {
4585  std::ostringstream s;
4586  s << "PPL::Box::" << method << ":" << std::endl
4587  << reason;
4588  throw std::invalid_argument(s.str());
4589 }
4590 
4591 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
4592 
4593 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
4594 template <typename Specialization,
4595  typename Temp, typename To, typename ITV>
4596 bool
4598  const Box<ITV>& x, const Box<ITV>& y,
4599  const Rounding_Dir dir,
4600  Temp& tmp0, Temp& tmp1, Temp& tmp2) {
4601  const dimension_type x_space_dim = x.space_dimension();
4602  // Dimension-compatibility check.
4603  if (x_space_dim != y.space_dimension()) {
4604  return false;
4605  }
4606  // Zero-dim boxes are equal if and only if they are both empty or universe.
4607  if (x_space_dim == 0) {
4608  if (x.marked_empty() == y.marked_empty()) {
4609  assign_r(r, 0, ROUND_NOT_NEEDED);
4610  }
4611  else {
4613  }
4614  return true;
4615  }
4616 
4617  // The distance computation requires a check for emptiness.
4618  (void) x.is_empty();
4619  (void) y.is_empty();
4620  // If one of two boxes is empty, then they are equal if and only if
4621  // the other box is empty too.
4622  if (x.marked_empty() || y.marked_empty()) {
4623  if (x.marked_empty() == y.marked_empty()) {
4624  assign_r(r, 0, ROUND_NOT_NEEDED);
4625  return true;
4626  }
4627  else {
4628  goto pinf;
4629  }
4630  }
4631 
4632  assign_r(tmp0, 0, ROUND_NOT_NEEDED);
4633  for (dimension_type i = x_space_dim; i-- > 0; ) {
4634  const ITV& x_i = x.seq[i];
4635  const ITV& y_i = y.seq[i];
4636  // Dealing with the lower bounds.
4637  if (x_i.lower_is_boundary_infinity()) {
4638  if (!y_i.lower_is_boundary_infinity()) {
4639  goto pinf;
4640  }
4641  }
4642  else if (y_i.lower_is_boundary_infinity()) {
4643  goto pinf;
4644  }
4645  else {
4646  const Temp* tmp1p;
4647  const Temp* tmp2p;
4648  if (x_i.lower() > y_i.lower()) {
4649  maybe_assign(tmp1p, tmp1, x_i.lower(), dir);
4650  maybe_assign(tmp2p, tmp2, y_i.lower(), inverse(dir));
4651  }
4652  else {
4653  maybe_assign(tmp1p, tmp1, y_i.lower(), dir);
4654  maybe_assign(tmp2p, tmp2, x_i.lower(), inverse(dir));
4655  }
4656  sub_assign_r(tmp1, *tmp1p, *tmp2p, dir);
4657  PPL_ASSERT(sgn(tmp1) >= 0);
4658  Specialization::combine(tmp0, tmp1, dir);
4659  }
4660  // Dealing with the lower bounds.
4661  if (x_i.upper_is_boundary_infinity()) {
4662  if (y_i.upper_is_boundary_infinity()) {
4663  continue;
4664  }
4665  else {
4666  goto pinf;
4667  }
4668  }
4669  else if (y_i.upper_is_boundary_infinity()) {
4670  goto pinf;
4671  }
4672  else {
4673  const Temp* tmp1p;
4674  const Temp* tmp2p;
4675  if (x_i.upper() > y_i.upper()) {
4676  maybe_assign(tmp1p, tmp1, x_i.upper(), dir);
4677  maybe_assign(tmp2p, tmp2, y_i.upper(), inverse(dir));
4678  }
4679  else {
4680  maybe_assign(tmp1p, tmp1, y_i.upper(), dir);
4681  maybe_assign(tmp2p, tmp2, x_i.upper(), inverse(dir));
4682  }
4683  sub_assign_r(tmp1, *tmp1p, *tmp2p, dir);
4684  PPL_ASSERT(sgn(tmp1) >= 0);
4685  Specialization::combine(tmp0, tmp1, dir);
4686  }
4687  }
4688  Specialization::finalize(tmp0, dir);
4689  assign_r(r, tmp0, dir);
4690  return true;
4691 
4692  pinf:
4694  return true;
4695 }
4696 
4697 } // namespace Parma_Polyhedra_Library
4698 
4699 #endif // !defined(PPL_Box_templates_hh)
Congruence_System congruences() const
Returns a system of congruences approximating *this.
Grid_Generator_System gen_sys
The system of generators.
Definition: Grid_defs.hh:1973
bool marked_empty() const
Returns true if the BDS is known to be empty.
Minimization is requested.
bool has_pending_constraints() const
Returns true if there are pending constraints.
bool is_satisfiable() const
Checks satisfiability of *this.
Definition: MIP_Problem.cc:247
static bool extract_interval_congruence(const Congruence &cg, dimension_type &cg_num_vars, dimension_type &cg_only_var)
Definition: Box.cc:48
Enable_If< Is_Native_Or_Checked< To >::value &&Is_Special< From >::value, Result >::type assign_r(To &to, const From &, Rounding_Dir dir)
dimension_type space_dimension() const
Returns the dimension of the smallest vector space enclosing all the variables whose indexes are in t...
void m_swap(Box &y)
Swaps *this with y (*this and y can be dimension-incompatible).
Definition: Box_inlines.hh:84
bool marked_empty() const
Returns true if the polyhedron is known to be empty.
I_Constraint< T > i_constraint(I_Constraint_Rel rel, const T &v)
The partially reduced product of two abstractions.
The empty element, i.e., the empty set.
static Poly_Con_Relation is_disjoint()
The polyhedron and the set of points satisfying the constraint are disjoint.
static Poly_Gen_Relation subsumes()
Adding the generator would not change the polyhedron.
dimension_type max_space_dimension()
Returns the maximum space dimension this library can handle.
bool is_disjoint_from(const Box &y) const
Returns true if and only if *this and y are disjoint.
The computed result is exact.
Definition: Result_defs.hh:81
void set_optimization_mode(Optimization_Mode mode)
Sets the optimization mode to mode.
void throw_dimension_incompatible(const char *method, const Box &y) const
Coefficient_traits::const_reference modulus() const
Returns a const reference to the modulus of *this.
bool l_m_distance_assign(Checked_Number< To, Extended_Number_Policy > &r, const Box< ITV > &x, const Box< ITV > &y, const Rounding_Dir dir, Temp &tmp0, Temp &tmp1, Temp &tmp2)
A linear equality or inequality.
std::vector< ITV > Sequence
The type of sequence used to implement the box.
Definition: Box_defs.hh:1756
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
Definition: Box_inlines.hh:123
bool is_equality() const
Returns true if and only if *this is an equality constraint.
void swap(CO_Tree &x, CO_Tree &y)
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
void add_congruences_no_check(const Congruence_System &cgs)
WRITE ME.
size_t dimension_type
An unsigned integral type for representing space dimensions.
bool empty() const
Returns true if and only if *this has no generators.
void limited_CC76_extrapolation_assign(const Box &y, const Constraint_System &cs, unsigned *tp=0)
Improves the result of the CC76-extrapolation computation by also enforcing those constraints in cs t...
Box(dimension_type num_dimensions=0, Degenerate_Element kind=UNIVERSE)
Builds a universe or empty box of the specified space dimension.
Type type() const
Returns the constraint type of *this.
Status status
The status flags to keep track of the internal state.
Definition: Box_defs.hh:1772
void insert(const Congruence &cg)
Inserts in *this a copy of the congruence cg, increasing the number of space dimensions if needed...
void generalized_affine_image(Variable var, Relation_Symbol relsym, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the image of *this with respect to the generalized affine relation ...
void set_space_dimension(dimension_type space_dim)
Sets the space dimension of the rows in the system to space_dim .
const C & coefficient(Variable v) const
Returns the coefficient of v in *this.
An std::set of variables' indexes.
A line, ray, point or closure point.
void add_constraints(const Constraint_System &cs)
Adds a copy of the constraints in cs to the MIP problem.
Definition: MIP_Problem.cc:184
void remove_higher_space_dimensions(dimension_type new_dimension)
Removes the higher dimensions so that the resulting space will have dimension new_dimension.
bool is_empty() const
Returns true if and only if *this is an empty polyhedron.
bool is_line_or_ray() const
Returns true if and only if *this is a line or a ray.
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
Rounding_Dir
Rounding directions for arithmetic computations.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
ITV Tmp_Interval_Type
The type of intervals used by inner computations when trying to limit the cumulative effect of approx...
Definition: Box_defs.hh:1762
void add_congruence_no_check(const Congruence &cg)
WRITE ME.
A positive integer overflow occurred (rounding up).
Definition: Result_defs.hh:111
bool is_inconsistent() const
Returns true if and only if *this is inconsistent (i.e., an always false congruence).
Definition: Congruence.cc:218
bool is_topologically_closed() const
Returns true if and only if *this is a topologically closed subset of the vector space.
bool contains_integer_point() const
Returns true if and only if *this contains at least one integer point.
Enable_If< Is_Native_Or_Checked< T >::value, bool >::type is_integer(const T &x)
static const Constraint_System & zero_dim_empty()
Returns the singleton system containing only Constraint::zero_dim_false().
bool is_empty() const
Returns true if and only if *this is an empty box.
Definition: Box_inlines.hh:183
static const Constraint & zero_dim_false()
The unsatisfiable (zero-dimension space) constraint .
void propagate_constraints_no_check(const Constraint_System &cs, dimension_type max_iterations)
Propagates the constraints in cs to refine *this.
void insert(const Constraint &c)
Inserts in *this a copy of the constraint c, increasing the number of space dimensions if needed...
dimension_type num_constraints(const Constraint_System &cs)
Helper returning number of constraints in system.
Result
Possible outcomes of a checked arithmetic computation.
Definition: Result_defs.hh:76
const_iterator end() const
Returns the past-the-end const_iterator.
From bool Type Type Rounding_Dir To
static const Congruence_System & zero_dim_empty()
Returns the system containing only Congruence::zero_dim_false().
void add_constraints_no_check(const Constraint_System &cs)
WRITE ME.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
static Poly_Con_Relation is_included()
The polyhedron is included in the set of points satisfying the constraint.
bool frequency(const Linear_Expression &expr, Coefficient &freq_n, Coefficient &freq_d, Coefficient &val_n, Coefficient &val_d) const
Returns true if and only if there exist a unique value val such that *this saturates the equality exp...
The standard C++ namespace.
expr_type expression() const
Partial read access to the (adapted) internal expression.
expr_type expression() const
Partial read access to the (adapted) internal expression.
#define PPL_OUTPUT_TEMPLATE_DEFINITIONS(type_symbol, class_prefix)
void lcm_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
void unconstrain(Variable var)
Computes the cylindrification of *this with respect to space dimension var, assigning the result to *...
Definition: Box_inlines.hh:555
void upper_bound_assign(const Box &y)
Assigns to *this the smallest box containing the union of *this and y.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
const Constraint_System & constraints() const
Returns the system of constraints.
bool has_empty_codomain() const
Returns true if and only if the represented partial function has an empty codomain (i...
static Poly_Con_Relation saturates()
The polyhedron is included in the set of points saturating the constraint.
void evaluate_objective_function(const Generator &evaluating_point, Coefficient &numer, Coefficient &denom) const
Sets num and denom so that is the result of evaluating the objective function on evaluating_point...
void set_inhomogeneous_term(Coefficient_traits::const_reference n)
Sets the inhomogeneous term of *this to n.
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
void add_constraint(const Constraint &c)
Adds a copy of constraint c to the MIP problem.
Definition: MIP_Problem.cc:164
const_iterator begin() const
Returns the const_iterator pointing to the first constraint, if *this is not empty; otherwise...
OR_Matrix< N > matrix
The matrix that represents the octagonal shape.
bool check_empty() const
Checks the hard way whether *this is an empty box: returns true if and only if it is so...
On overflow, wrapping takes place.
void exact_div_assign(Checked_Number< T, Policy > &x, const Checked_Number< T, Policy > &y, const Checked_Number< T, Policy > &z)
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
Coefficient_traits::const_reference coefficient(Variable v) const
Returns the coefficient of v in *this.
Worst-case polynomial complexity.
Coefficient_traits::const_reference coefficient(Variable v) const
Returns the coefficient of v in *this.
The computed result is inexact and rounded down.
Definition: Result_defs.hh:87
dimension_type id() const
Returns the index of the Cartesian axis associated to the variable.
static bool extract_interval_constraint(const Constraint &c, dimension_type &c_num_vars, dimension_type &c_only_var)
Decodes the constraint c as an interval constraint.
Definition: Box.cc:30
const Generator & optimizing_point() const
Returns an optimal point for *this, if it exists.
Definition: MIP_Problem.cc:236
bool is_proper_congruence() const
Returns true if the modulus is greater than zero.
static const Congruence & zero_dim_false()
Returns a reference to the false (zero-dimension space) congruence .
A dimension of the vector space.
void topological_closure_assign()
Assigns to *this its topological closure.
Enable_If< Is_Same< T, Box >::value &&Is_Same_Or_Derived< Interval_Base, ITV >::value, void >::type CC76_narrowing_assign(const T &y)
Assigns to *this the result of restoring in y the constraints of *this that were lost by CC76-extrapo...
void shortest_path_closure_assign() const
Assigns to this->dbm its shortest-path closure.
Rounding_Dir inverse(Rounding_Dir dir)
Constraint_System minimized_constraints() const
Returns a minimized system of constraints defining *this.
bool is_strict_inequality() const
Returns true if and only if *this is a strict inequality constraint.
Complexity_Class
Complexity pseudo-classes.
The base class for convex polyhedra.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
Worst-case exponential complexity but typically polynomial behavior.
The base class for the single rows of matrices.
Definition: DB_Row_defs.hh:120
void get_limiting_box(const Constraint_System &cs, Box &limiting_box) const
Adds to limiting_box the interval constraints in cs that are satisfied by *this.
bool is_inequality() const
Returns true if and only if *this is an inequality constraint (either strict or non-strict).
Constraint_System simplified_constraints() const
If constraints are up-to-date, obtain a simplified copy of them.
A wrapper for numeric types implementing a given policy.
bool generators_are_up_to_date() const
Returns true if the system of generators is up-to-date.
bool is_canonical(const mpq_class &x)
Returns true if and only if x is in canonical form.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
On overflow, the result is undefined.
Poly_Con_Relation interval_relation(const ITV &i, const Constraint::Type constraint_type, Coefficient_traits::const_reference numer, Coefficient_traits::const_reference denom=Coefficient_one())
Returns the relations holding between an interval and an interval constraint.
void finalize()
Finalizes the library.
Definition: initializer.hh:60
#define PPL_COMPILE_TIME_CHECK(e, msg)
Produces a compilation error if the compile-time constant e does not evaluate to true ...
void strong_closure_assign() const
Assigns to this->matrix its strong closure.
void intersection_assign(const Box &y)
Assigns to *this the intersection of *this and y.
A class holding a constant called value that evaluates to true if and only if Base is the same type a...
Relation_Symbol
Relation symbols.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
bool is_equality() const
Returns true if *this is an equality.
Degenerate_Element
Kinds of degenerate abstract elements.
Type type() const
Returns the generator type of *this.
bool constraints_are_up_to_date() const
Returns true if the system of constraints is up-to-date.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
dimension_type affine_dimension() const
Returns , if *this is empty; otherwise, returns the affine dimension of *this.
dimension_type check_space_dimension_overflow(const dimension_type dim, const dimension_type max, const char *domain, const char *method, const char *reason)
Definition: globals.cc:48
A linear form with interval coefficients.
void reset_empty_up_to_date()
Invalidates empty flag of *this.
Definition: Box_inlines.hh:64
void drop_some_non_integer_points(Complexity_Class complexity=ANY_COMPLEXITY)
Possibly tightens *this by dropping some points with non-integer coordinates.
const_iterator end() const
Returns the past-the-end const_iterator.
static void throw_constraint_incompatible(const char *method)
void set_nonempty()
Marks *this as definitely not empty.
Definition: Box_inlines.hh:51
A Mixed Integer (linear) Programming problem.
const_iterator end() const
Iterator pointing after the last nonzero variable coefficient.
const Generator_System & generators() const
Returns the system of generators.
void propagate_constraint_no_check(const Constraint &c)
Propagates the constraint c to refine *this.
bool is_inconsistent() const
Returns true if and only if *this is inconsistent (i.e., an always false constraint).
Definition: Constraint.cc:148
Sequence seq
A sequence of intervals, one for each dimension of the vector space.
Definition: Box_defs.hh:1765
#define WEIGHT_ADD_MUL(delta, factor)
Definition: globals_defs.hh:90
Result result_relation_class(Result r)
bool propagate_constraint_check_result(Result r, Ternary &open)
static dimension_type max_space_dimension()
Returns the maximum space dimension that a Box can handle.
Definition: Box_inlines.hh:129
Enable_If< Is_Native_Or_Checked< T >::value, bool >::type ascii_load(std::istream &s, T &t)
static void throw_invalid_argument(const char *method, const char *reason)
Coefficient value
Definition: PIP_Tree.cc:618
Enable_If< Is_Native_Or_Checked< T >::value, bool >::type is_plus_infinity(const T &x)
A not necessarily closed, iso-oriented hyperrectangle.
Definition: Box_defs.hh:299
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=0, unsigned complexity_threshold=16, bool wrap_individually=true)
Wraps the specified dimensions of the vector space.
const_iterator begin() const
Returns the const_iterator pointing to the first congruence, if this is not empty; otherwise...
void bounded_affine_preimage(Variable var, const Linear_Expression &lb_expr, const Linear_Expression &ub_expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the preimage of *this with respect to the bounded affine relation ...
PPL_COEFFICIENT_TYPE Coefficient
An alias for easily naming the type of PPL coefficients.
bool is_point() const
Returns true if and only if *this is a point.
bool marked_empty() const
Returns true if the OS is known to be empty.
#define WEIGHT_BEGIN()
Definition: globals_defs.hh:81
bool is_tautological() const
Returns true if and only if *this is a tautology (i.e., an always true congruence).
Definition: Congruence.cc:210
void wrap_assign(PSET &pointset, const Variables_Set &vars, const Bounded_Integer_Type_Width w, const Bounded_Integer_Type_Representation r, const Bounded_Integer_Type_Overflow o, const Constraint_System *cs_p, const unsigned complexity_threshold, const bool wrap_individually, const char *class_name)
Definition: wrap_assign.hh:152
void mul_2exp_assign(GMP_Integer &x, const GMP_Integer &y, unsigned int exp)
void add_space_dimensions_and_project(dimension_type m)
Adds m new dimensions to the box and does not embed it in the new vector space.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
void fold_space_dimensions(const Variables_Set &vars, Variable dest)
Folds the space dimensions in vars into dest.
The computed result may be inexact and rounded up.
Definition: Result_defs.hh:93
bool upper_bound_assign_if_exact(const Box &y)
If the upper bound of *this and y is exact, it is assigned to *this and true is returned, otherwise false is returned.
#define PPL_DIRTY_TEMP(T, id)
bool generators_are_up_to_date() const
Returns true if the system of generators is up-to-date.
Definition: Grid_inlines.hh:45
void bounded_affine_image(Variable var, const Linear_Expression &lb_expr, const Linear_Expression &ub_expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the image of *this with respect to the bounded affine relation . ...
The universe element, i.e., the whole vector space.
void add_constraint_no_check(const Constraint &c)
WRITE ME.
A generic, not necessarily closed, possibly restricted interval.
dimension_type max_in_codomain() const
If the codomain is not empty, returns the maximum value in it.
static Generator point(const Linear_Expression &e=Linear_Expression::zero(), Coefficient_traits::const_reference d=Coefficient_one(), Representation r=default_representation)
Returns the point at e / d.
Definition: Generator.cc:57
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
Plus_Infinity PLUS_INFINITY
Definition: checked.cc:31
void neg_assign(GMP_Integer &x)
Coefficient_traits::const_reference Coefficient_zero()
Returns a const reference to a Coefficient with value 0.
bool is_ray() const
Returns true if and only if *this is a ray.
The entire library is confined to this namespace.
Definition: version.hh:61
void refine_no_check(const Constraint &c)
Uses the constraint c to refine *this.
const D2 & domain2() const
Returns a constant reference to the second of the pair.
bool bounds(const Linear_Expression &expr, bool from_above) const
Checks if and how expr is bounded in *this.
Signed binary where negative values are represented by the two's complement of the absolute value...
bool marked_empty() const
Returns true if the grid is known to be empty.
Definition: Grid_inlines.hh:35
void concatenate_assign(const Box &y)
Seeing a box as a set of tuples (its points), assigns to *this all the tuples that can be obtained by...
Maximization is requested.
const C & inhomogeneous_term() const
Returns the inhomogeneous term of *this.
void set_empty_up_to_date()
Asserts the validity of the empty flag of *this.
Definition: Box_inlines.hh:58
const_iterator end() const
Returns the past-the-end const_iterator.
Constraint_System constraints() const
Returns a system of constraints defining *this.
const_iterator begin() const
Returns the const_iterator pointing to the first generator, if *this is not empty; otherwise...
bool is_bounded() const
Returns true if and only if *this is a bounded box.
void difference_assign(const Box &y)
Assigns to *this the difference of *this and y.
A bounded difference shape.
The computed result may be inexact and rounded down.
Definition: Result_defs.hh:96
I_Result combine(Result l, Result u)
void set_objective_function(const Linear_Expression &obj)
Sets the objective function to obj.
Definition: MIP_Problem.cc:208
MIP_Problem_Status solve() const
Optimizes the MIP problem.
Definition: MIP_Problem.cc:293
bool maximize(const Linear_Expression &expr, Coefficient &sup_n, Coefficient &sup_d, bool &maximum) const
Returns true if and only if *this is not empty and expr is bounded from above in *this, in which case the supremum value is computed.
void time_elapse_assign(const Box &y)
Assigns to *this the result of computing the time-elapse between *this and y.
base_type::const_iterator const_iterator
The type of const iterators on coefficients.
static void throw_expression_too_complex(const char *method, const Linear_Expression &le)
Coefficient_traits::const_reference coefficient(Variable v) const
Returns the coefficient of v in *this.
bool simplify_using_context_assign(const Box &y)
Assigns to *this a meet-preserving simplification of *this with respect to y. If false is returned...
int sgn(Boundary_Type type, const T &x, const Info &info)
void sub_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
void affine_form_image(Variable var, const Linear_Form< ITV > &lf)
Assigns to *this the affine form image of *this under the function mapping variable var into the affi...
#define PPL_USED(v)
No-op macro that allows to avoid unused variable warnings from the compiler.
Definition: compiler.hh:39
bool operator==(const Box< ITV > &x, const Box< ITV > &y)
void normalize2(Coefficient_traits::const_reference x, Coefficient_traits::const_reference y, Coefficient &n_x, Coefficient &n_y)
If is the GCD of x and y, the values of x and y divided by are assigned to n_x and n_y...
bool maps(dimension_type i, dimension_type &j) const
If *this maps i to a value k, assigns k to j and returns true; otherwise, j is unchanged and false is...
bool constrains(Variable var) const
Returns true if and only if var is constrained in *this.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
void generalized_affine_preimage(Variable var, Relation_Symbol relsym, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the preimage of *this with respect to the generalized affine relation ...
size_t memory_size_type
An unsigned integral type for representing memory size in bytes.
Coefficient_traits::const_reference divisor() const
If *this is either a point or a closure point, returns its divisor.
A negative integer overflow occurred (rounding down).
Definition: Result_defs.hh:114
base_type::const_iterator const_iterator
The type of const iterators on coefficients.
Coefficient c
Definition: PIP_Tree.cc:64
bool contains(const Box &y) const
Returns true if and only if *this contains y.
void map_space_dimensions(const Partial_Function &pfunc)
Remaps the dimensions of the vector space according to a partial function.
dimension_type first_nonzero(dimension_type first, dimension_type last) const
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
void affine_preimage(Variable var, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the affine preimage of *this under the function mapping variable var to the affine e...
Poly_Con_Relation relation_with(const Constraint &c) const
Returns the relations holding between *this and the constraint c.
Coefficient_traits::const_reference Coefficient_one()
Returns a const reference to a Coefficient with value 1.
expr_type expression() const
Partial read access to the (adapted) internal expression.
The computed result is inexact and rounded up.
Definition: Result_defs.hh:84
A class that provides a type member called type equivalent to T if and only if b is true...
Coefficient_traits::const_reference coefficient(Variable v) const
Returns the coefficient of v in *this.
void affine_image(Variable var, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the affine image of *this under the function mapping variable var to the affine expr...
const_iterator begin() const
Iterator pointing to the first nonzero variable coefficient.
bool OK() const
Returns true if and only if *this satisfies all its invariants.
bool is_discrete() const
Returns true if and only if *this is discrete.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
Enable_If< Is_Same< T, Box >::value &&Is_Same_Or_Derived< Interval_Base, ITV >::value, void >::type CC76_widening_assign(const T &y, unsigned *tp=0)
Assigns to *this the result of computing the CC76-widening between *this and y.
void remove_space_dimensions(const Variables_Set &vars)
Removes all the specified dimensions.
bool is_line() const
Returns true if and only if *this is a line.
static Poly_Con_Relation nothing()
The assertion that says nothing.
void set(I_Constraint_Rel r, Arg_Type v)
static Poly_Con_Relation strictly_intersects()
The polyhedron intersects the set of points satisfying the constraint, but it is not included in it...
static Poly_Gen_Relation nothing()
The assertion that says nothing.
bool max_min(const Linear_Expression &expr, bool maximize, Coefficient &ext_n, Coefficient &ext_d, bool &included, Generator &g) const
Maximizes or minimizes expr subject to *this.
An adapter for Linear_Expression that maybe hides the last coefficient.
bool le(Boundary_Type type1, const T1 &x1, const Info1 &info1, Boundary_Type type2, const T2 &x2, const Info2 &info2)
void add_interval_constraint_no_check(dimension_type var_id, Constraint::Type type, Coefficient_traits::const_reference numer, Coefficient_traits::const_reference denom)
WRITE ME.
Definition: Box_inlines.hh:442
The relation between a polyhedron and a generator.
bool update_generators() const
Updates and minimizes the generators from the congruences.
DB_Matrix< N > dbm
The matrix representing the system of bounded differences.
The problem has an optimal solution.
Result maybe_assign(const To *&top, To &tmp, const From &from, Rounding_Dir dir)
Assigns to top a pointer to a location that holds the conversion, according to dir, of from to type To. When necessary, and only when necessary, the variable tmp is used to hold the result of conversion.
const D1 & domain1() const
Returns a constant reference to the first of the pair.
bool is_universe() const
Returns true if and only if *this is a universe box.
bool marked_empty() const
Returns true if and only if the box is known to be empty.
Definition: Box_inlines.hh:38
The relation between a polyhedron and a constraint.
void add_space_dimensions_and_embed(dimension_type m)
Adds m new dimensions and embeds the old box into the new space.
const_iterator end() const
Iterator pointing after the last nonzero variable coefficient.
void set_empty()
Causes the box to become empty, i.e., to represent the empty set.
Definition: Box_inlines.hh:44
bool has_strict_inequalities() const
Returns true if and only if *this contains one or more strict inequality constraints.