PPL  1.2
Polyhedron_widenings.cc
Go to the documentation of this file.
1 /* Polyhedron class implementation
2  (non-inline widening-related member functions).
3  Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
4  Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
5 
6 This file is part of the Parma Polyhedra Library (PPL).
7 
8 The PPL is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 The PPL is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software Foundation,
20 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
21 
22 For the most up-to-date information see the Parma Polyhedra Library
23 site: http://bugseng.com/products/ppl/ . */
24 
25 #include "ppl-config.h"
26 #include "Polyhedron_defs.hh"
28 #include "Rational_Box.hh"
29 #include "Scalar_Products_defs.hh"
31 #include "assertions.hh"
32 #include <iostream>
33 #include <stdexcept>
34 #include <deque>
35 
36 namespace PPL = Parma_Polyhedra_Library;
37 
38 void
41  Constraint_System& cs_selection) const {
42  // Private method: the caller must ensure the following conditions.
43  PPL_ASSERT(topology() == y.topology()
44  && topology() == cs_selection.topology()
45  && space_dim == y.space_dim);
46  PPL_ASSERT(!marked_empty()
47  && !has_pending_constraints()
48  && generators_are_up_to_date());
49  PPL_ASSERT(!y.marked_empty()
50  && !y.has_something_pending()
52 
53  // A constraint in `y.con_sys' is copied to `cs_selection'
54  // if it is satisfied by all the generators of `gen_sys'.
55 
56  // Note: the loop index `i' goes upward to avoid reversing
57  // the ordering of the chosen constraints.
58  for (dimension_type i = 0, end = y.con_sys.num_rows(); i < end; ++i) {
59  const Constraint& c = y.con_sys[i];
60  if (gen_sys.satisfied_by_all_generators(c)) {
61  cs_selection.insert(c);
62  }
63  }
64 }
65 
66 void
69  Constraint_System& cs_selected,
70  Constraint_System& cs_not_selected) const {
71  // Private method: the caller must ensure the following conditions
72  // (beside the inclusion `y <= x').
73  PPL_ASSERT(topology() == y.topology()
74  && topology() == cs_selected.topology()
75  && topology() == cs_not_selected.topology());
76  PPL_ASSERT(space_dim == y.space_dim);
77  PPL_ASSERT(!marked_empty()
78  && !has_pending_generators()
79  && constraints_are_up_to_date());
80  PPL_ASSERT(!y.marked_empty()
81  && !y.has_something_pending()
84 
85  // FIXME: this is a workaround for NNC polyhedra.
86  if (!y.is_necessarily_closed()) {
87  // Force strong minimization of constraints.
89  // Recompute generators (without compromising constraint minimization).
91  }
92 
93  // Obtain a sorted copy of `y.sat_g'.
94  if (!y.sat_g_is_up_to_date()) {
95  y.update_sat_g();
96  }
97  Bit_Matrix tmp_sat_g = y.sat_g;
98  // Remove from `tmp_sat_g' the rows corresponding to tautologies
99  // (i.e., the positivity or epsilon-bounding constraints):
100  // this is needed in order to widen the polyhedron and not the
101  // corresponding homogenized polyhedral cone.
102  const Constraint_System& y_cs = y.con_sys;
103  const dimension_type old_num_rows = y_cs.num_rows();
104  dimension_type num_rows = old_num_rows;
105  for (dimension_type i = 0; i < num_rows; ++i) {
106  if (y_cs[i].is_tautological()) {
107  using std::swap;
108  --num_rows;
109  swap(tmp_sat_g[i], tmp_sat_g[num_rows]);
110  }
111  }
112  tmp_sat_g.remove_trailing_rows(old_num_rows - num_rows);
113  tmp_sat_g.sort_rows();
114 
115  // A constraint in `con_sys' is copied to `cs_selected'
116  // if its behavior with respect to `y.gen_sys' is the same
117  // as that of another constraint in `y.con_sys'.
118  // otherwise it is copied to `cs_not_selected'.
119  // Namely, we check whether the saturation row `buffer'
120  // (built starting from the given constraint and `y.gen_sys')
121  // is a row of the saturation matrix `tmp_sat_g'.
122 
123  // CHECKME: the following comment is only applicable when `y.gen_sys'
124  // is minimized. In that case, the comment suggests that it would be
125  // possible to use a fast (but incomplete) redundancy test based on
126  // the number of saturators in `buffer'.
127  // NOTE: If the considered constraint of `con_sys' does not
128  // satisfy the saturation rule (see Section \ref prelims), then
129  // it will not appear in the resulting constraint system,
130  // because `tmp_sat_g' is built starting from a minimized polyhedron.
131 
132  // The size of `buffer' will reach sat.num_columns() bits.
133  Bit_Row buffer;
134  // Note: the loop index `i' goes upward to avoid reversing
135  // the ordering of the chosen constraints.
136  for (dimension_type i = 0, end = con_sys.num_rows(); i < end; ++i) {
137  const Constraint& ci = con_sys[i];
138  // The saturation row `buffer' is built considering
139  // the `i'-th constraint of the polyhedron `x' and
140  // all the generators of the polyhedron `y'.
141  buffer.clear();
142  for (dimension_type j = y.gen_sys.num_rows(); j-- > 0; ) {
143  const int sp_sgn = Scalar_Products::sign(ci, y.gen_sys[j]);
144  // We are assuming that `y <= x'.
145  PPL_ASSERT(sp_sgn >= 0
146  || (!is_necessarily_closed()
147  && ci.is_strict_inequality()
148  && y.gen_sys[j].is_point()));
149  if (sp_sgn > 0) {
150  buffer.set(j);
151  }
152  }
153  // We check whether `buffer' is a row of `tmp_sat_g',
154  // exploiting its sortedness in order to have faster comparisons.
155  if (tmp_sat_g.sorted_contains(buffer)) {
156  cs_selected.insert(ci);
157  }
158  else {
159  cs_not_selected.insert(ci);
160  }
161  }
162 }
163 
164 void
166  Polyhedron& x = *this;
167  // Topology compatibility check.
168  const Topology topol = x.topology();
169  if (topol != y.topology()) {
170  throw_topology_incompatible("H79_widening_assign(y)", "y", y);
171  // Dimension-compatibility check.
172  }
173  if (x.space_dim != y.space_dim) {
174  throw_dimension_incompatible("H79_widening_assign(y)", "y", y);
175  }
176  // Assume `y' is contained in or equal to `x'.
177  PPL_EXPECT_HEAVY(copy_contains(x, y));
178 
179  // If any argument is zero-dimensional or empty,
180  // the H79-widening behaves as the identity function.
181  if (x.space_dim == 0 || x.marked_empty() || y.marked_empty()) {
182  return;
183  }
184 
185  // `y.gen_sys' should be in minimal form and
186  // `y.sat_g' should be up-to-date.
187  if (y.is_necessarily_closed()) {
188  if (!y.minimize()) {
189  // `y' is empty: the result is `x'.
190  return;
191  }
192  }
193  else {
194  // Dealing with a NNC polyhedron.
195  // To obtain a correct reasoning when comparing
196  // the constraints of `x' with the generators of `y',
197  // we enforce the inclusion relation holding between
198  // the two NNC polyhedra `x' and `y' (i.e., `y <= x')
199  // to also hold for the corresponding eps-representations:
200  // this is obtained by intersecting the two eps-representations.
201  Polyhedron& yy = const_cast<Polyhedron&>(y);
202  yy.intersection_assign(x);
203  if (yy.is_empty()) {
204  // The result is `x'.
205  return;
206  }
207  }
208 
209  // If we only have the generators of `x' and the dimensions of
210  // the two polyhedra are the same, we can compute the standard
211  // widening by using the specification in [CousotH78], therefore
212  // avoiding converting from generators to constraints.
214  Constraint_System CH78_cs(topol);
215  x.select_CH78_constraints(y, CH78_cs);
216 
217  if (CH78_cs.num_rows() == y.con_sys.num_rows()) {
218  // Having selected all the constraints, the result is `y'.
219  x = y;
220  return;
221  }
222  // Otherwise, check if `x' and `y' have the same dimension.
223  // Note that `y.con_sys' is minimized and `CH78_cs' has no redundant
224  // constraints, since it is a subset of the former.
225  else if (CH78_cs.num_equalities() == y.con_sys.num_equalities()) {
226  // Let `x' be defined by the constraints in `CH78_cs'.
227  Polyhedron CH78(topol, x.space_dim, UNIVERSE);
228  CH78.add_recycled_constraints(CH78_cs);
229 
230  // Check whether we are using the widening-with-tokens technique
231  // and there still are tokens available.
232  if (tp != 0 && *tp > 0) {
233  // There are tokens available. If `CH78' is not a subset of `x',
234  // then it is less precise and we use one of the available tokens.
235  if (!x.contains(CH78)) {
236  --(*tp);
237  }
238  }
239  else {
240  // No tokens.
241  x.m_swap(CH78);
242  }
243  PPL_ASSERT_HEAVY(x.OK(true));
244  return;
245  }
246  }
247 
248  // As the dimension of `x' is strictly greater than the dimension of `y',
249  // we have to compute the standard widening by selecting a subset of
250  // the constraints of `x'.
251  // `x.con_sys' is just required to be up-to-date, because:
252  // - if `x.con_sys' is unsatisfiable, then by assumption
253  // also `y' is empty, so that the resulting polyhedron is `x';
254  // - redundant constraints in `x.con_sys' do not affect the result
255  // of the widening, because if they are selected they will be
256  // redundant even in the result.
257  if (has_pending_generators()) {
259  }
260  else if (!x.constraints_are_up_to_date()) {
261  x.update_constraints();
262  }
263  // Copy into `H79_cs' the constraints of `x' that are common to `y',
264  // according to the definition of the H79 widening.
265  Constraint_System H79_cs(topol);
266  Constraint_System x_minus_H79_cs(topol);
267  x.select_H79_constraints(y, H79_cs, x_minus_H79_cs);
268 
269  if (x_minus_H79_cs.has_no_rows()) {
270  // We selected all of the constraints of `x',
271  // thus the result of the widening is `x'.
272  return;
273  }
274  else {
275  // We selected a strict subset of the constraints of `x'.
276  // NOTE: as `x.con_sys' was not necessarily in minimal form,
277  // this does not imply that the result strictly includes `x'.
278  // Let `H79' be defined by the constraints in `H79_cs'.
279  Polyhedron H79(topol, x.space_dim, UNIVERSE);
280  H79.add_recycled_constraints(H79_cs);
281 
282  // Check whether we are using the widening-with-tokens technique
283  // and there still are tokens available.
284  if (tp != 0 && *tp > 0) {
285  // There are tokens available. If `H79' is not a subset of `x',
286  // then it is less precise and we use one of the available tokens.
287  if (!x.contains(H79)) {
288  --(*tp);
289  }
290  }
291  else {
292  // No tokens.
293  x.m_swap(H79);
294  }
295  PPL_ASSERT_HEAVY(x.OK(true));
296  }
297 }
298 
299 void
301  const Constraint_System& cs,
302  unsigned* tp) {
303  Polyhedron& x = *this;
304 
305  const dimension_type cs_num_rows = cs.num_rows();
306  // If `cs' is empty, we fall back to ordinary, non-limited widening.
307  if (cs_num_rows == 0) {
308  x.H79_widening_assign(y, tp);
309  return;
310  }
311 
312  // Topology compatibility check.
313  if (x.is_necessarily_closed()) {
314  if (!y.is_necessarily_closed()) {
315  throw_topology_incompatible("limited_H79_extrapolation_assign(y, cs)",
316  "y", y);
317  }
318  if (cs.has_strict_inequalities()) {
319  throw_topology_incompatible("limited_H79_extrapolation_assign(y, cs)",
320  "cs", cs);
321  }
322  }
323  else if (y.is_necessarily_closed()) {
324  throw_topology_incompatible("limited_H79_extrapolation_assign(y, cs)",
325  "y", y);
326  }
327  // Dimension-compatibility check.
328  if (x.space_dim != y.space_dim) {
329  throw_dimension_incompatible("limited_H79_extrapolation_assign(y, cs)",
330  "y", y);
331  }
332  // `cs' must be dimension-compatible with the two polyhedra.
333  const dimension_type cs_space_dim = cs.space_dimension();
334  if (x.space_dim < cs_space_dim) {
335  throw_dimension_incompatible("limited_H79_extrapolation_assign(y, cs)",
336  "cs", cs);
337  }
338  // Assume `y' is contained in or equal to `x'.
339  PPL_EXPECT_HEAVY(copy_contains(x, y));
340 
341  if (y.marked_empty()) {
342  return;
343  }
344  if (x.marked_empty()) {
345  return;
346  }
347  // The limited H79-widening between two polyhedra in a
348  // zero-dimensional space is a polyhedron in a zero-dimensional
349  // space, too.
350  if (x.space_dim == 0) {
351  return;
352  }
353 
354  if (!y.minimize()) {
355  // We have just discovered that `y' is empty.
356  return;
357  }
358 
359  // Update the generators of `x': these are used to select,
360  // from the constraints in `cs', those that must be added
361  // to the resulting polyhedron.
363  || (!x.generators_are_up_to_date() && !x.update_generators())) {
364  // We have just discovered that `x' is empty.
365  return;
366  }
367 
368  Constraint_System new_cs;
369  // The constraints to be added must be satisfied by all the
370  // generators of `x'. We can disregard `y' because `y <= x'.
371  const Generator_System& x_gen_sys = x.gen_sys;
372  // Iterate upwards here so as to keep the relative ordering of constraints.
373  // Not really an issue: just aesthetics.
374  for (dimension_type i = 0; i < cs_num_rows; ++i) {
375  const Constraint& c = cs[i];
376  if (x_gen_sys.satisfied_by_all_generators(c)) {
377  new_cs.insert(c);
378  }
379  }
380  x.H79_widening_assign(y, tp);
381  x.add_recycled_constraints(new_cs);
382  PPL_ASSERT_HEAVY(OK());
383 }
384 
385 void
387  const Constraint_System& cs,
388  unsigned* tp) {
389  Rational_Box x_box(*this, ANY_COMPLEXITY);
390  const Rational_Box y_box(y, ANY_COMPLEXITY);
391  x_box.CC76_widening_assign(y_box);
392  limited_H79_extrapolation_assign(y, cs, tp);
393  Constraint_System x_box_cs = x_box.constraints();
394  add_recycled_constraints(x_box_cs);
395 }
396 
397 bool
400  const BHRZ03_Certificate& y_cert,
401  const Polyhedron& H79,
402  const Constraint_System& x_minus_H79_cs) {
403  Polyhedron& x = *this;
404  // It is assumed that `y <= x <= H79'.
405  PPL_ASSERT(x.topology() == y.topology()
406  && x.topology() == H79.topology()
407  && x.topology() == x_minus_H79_cs.topology());
408  PPL_ASSERT(x.space_dim == y.space_dim
409  && x.space_dim == H79.space_dim
410  && x.space_dim == x_minus_H79_cs.space_dimension());
411  PPL_ASSERT(!x.marked_empty() && !x.has_something_pending()
413  PPL_ASSERT(!y.marked_empty() && !y.has_something_pending()
415  PPL_ASSERT(!H79.marked_empty() && !H79.has_something_pending()
417 
418  // We will choose from `x_minus_H79_cs' many subsets of constraints,
419  // that will be collected (one at a time) in `combining_cs'.
420  // For each group collected, we compute an average constraint,
421  // that will be stored in `new_cs'.
422 
423  // There is no point in applying this technique when `x_minus_H79_cs'
424  // has one constraint at most (no ``new'' constraint can be computed).
425  const dimension_type x_minus_H79_cs_num_rows = x_minus_H79_cs.num_rows();
426  if (x_minus_H79_cs_num_rows <= 1) {
427  return false;
428  }
429 
430  const Topology topol = x.topology();
431  Constraint_System combining_cs(topol);
432  Constraint_System new_cs(topol);
433 
434  // Consider the points that belong to both `x.gen_sys' and `y.gen_sys'.
435  // For NNC polyhedra, the role of points is played by closure points.
436  const bool closed = x.is_necessarily_closed();
437  for (dimension_type i = y.gen_sys.num_rows(); i-- > 0; ) {
438  const Generator& g = y.gen_sys[i];
439  if ((g.is_point() && closed) || (g.is_closure_point() && !closed)) {
440  // If in `H79.con_sys' there is already an inequality constraint
441  // saturating this point, then there is no need to produce another
442  // constraint.
443  bool lies_on_the_boundary_of_H79 = false;
444  const Constraint_System& H79_cs = H79.con_sys;
445  for (dimension_type j = H79_cs.num_rows(); j-- > 0; ) {
446  const Constraint& c = H79_cs[j];
447  if (c.is_inequality() && Scalar_Products::sign(c, g) == 0) {
448  lies_on_the_boundary_of_H79 = true;
449  break;
450  }
451  }
452  if (lies_on_the_boundary_of_H79) {
453  continue;
454  }
455 
456  // Consider all the constraints in `x_minus_H79_cs'
457  // that are saturated by the point `g'.
458  combining_cs.clear();
459  for (dimension_type j = x_minus_H79_cs_num_rows; j-- > 0; ) {
460  const Constraint& c = x_minus_H79_cs[j];
461  if (Scalar_Products::sign(c, g) == 0) {
462  combining_cs.insert(c);
463  }
464  }
465  // Build a new constraint by combining all the chosen constraints.
466  const dimension_type combining_cs_num_rows = combining_cs.num_rows();
467  if (combining_cs_num_rows > 0) {
468  if (combining_cs_num_rows == 1) {
469  // No combination is needed.
470  new_cs.insert(combining_cs[0]);
471  }
472  else {
473  Linear_Expression e(0);
474  bool strict_inequality = false;
475  for (dimension_type h = combining_cs_num_rows; h-- > 0; ) {
476  if (combining_cs[h].is_strict_inequality()) {
477  strict_inequality = true;
478  }
479  e += Linear_Expression(combining_cs[h].expression());
480  }
481 
483  if (strict_inequality) {
484  new_cs.insert(e > 0);
485  }
486  else {
487  new_cs.insert(e >= 0);
488  }
489  }
490  }
491  }
492  }
493  }
494 
495  // If none of the collected constraints strictly intersects `H79',
496  // then the technique was unsuccessful.
497  bool improves_upon_H79 = false;
499  for (dimension_type i = new_cs.num_rows(); i-- > 0; ) {
500  if (H79.relation_with(new_cs[i]) == si) {
501  improves_upon_H79 = true;
502  break;
503  }
504  }
505  if (!improves_upon_H79) {
506  return false;
507  }
508 
509  // The resulting polyhedron is obtained by adding the constraints
510  // in `new_cs' to polyhedron `H79'.
511  Polyhedron result = H79;
512  result.add_recycled_constraints(new_cs);
513  // Force minimization.
514  result.minimize();
515 
516  // Check for stabilization with respect to `y_cert' and improvement
517  // over `H79'.
518  if (y_cert.is_stabilizing(result) && !result.contains(H79)) {
519  // The technique was successful.
520  x.m_swap(result);
521  PPL_ASSERT_HEAVY(x.OK(true));
522  return true;
523  }
524  else {
525  // The technique was unsuccessful.
526  return false;
527  }
528 }
529 
530 bool
532  const BHRZ03_Certificate& y_cert,
533  const Polyhedron& H79) {
534  Polyhedron& x = *this;
535  // It is assumed that `y <= x <= H79'.
536  PPL_ASSERT(x.topology() == y.topology()
537  && x.topology() == H79.topology());
538  PPL_ASSERT(x.space_dim == y.space_dim
539  && x.space_dim == H79.space_dim);
540  PPL_ASSERT(!x.marked_empty() && !x.has_something_pending()
542  PPL_ASSERT(!y.marked_empty() && !y.has_something_pending()
544  PPL_ASSERT(!H79.marked_empty() && !H79.has_something_pending()
546 
547  // For each point in `x.gen_sys' that is not in `y',
548  // this technique tries to identify a set of rays that:
549  // - are included in polyhedron `H79';
550  // - when added to `y' will subsume the point.
551  Generator_System candidate_rays;
552 
553  const dimension_type x_gen_sys_num_rows = x.gen_sys.num_rows();
554  const dimension_type y_gen_sys_num_rows = y.gen_sys.num_rows();
555  const bool closed = x.is_necessarily_closed();
556  for (dimension_type i = x_gen_sys_num_rows; i-- > 0; ) {
557  const Generator& g1 = x.gen_sys[i];
558  // For C polyhedra, we choose a point of `x.gen_sys'
559  // that is not included in `y'.
560  // In the case of NNC polyhedra, we can restrict attention to
561  // closure points (considering also points will only add redundancy).
562  if (((g1.is_point() && closed) || (g1.is_closure_point() && !closed))
564  // For each point (resp., closure point) `g2' in `y.gen_sys',
565  // where `g1' and `g2' are different,
566  // build the candidate ray `g1 - g2'.
567  for (dimension_type j = y_gen_sys_num_rows; j-- > 0; ) {
568  const Generator& g2 = y.gen_sys[j];
569  if ((g2.is_point() && closed)
570  || (g2.is_closure_point() && !closed)) {
571  PPL_ASSERT(compare(g1, g2) != 0);
572  Generator ray_from_g2_to_g1 = g1;
573  ray_from_g2_to_g1.linear_combine(g2, 0);
574  candidate_rays.insert(ray_from_g2_to_g1);
575  }
576  }
577  }
578  }
579 
580  // Be non-intrusive.
581  Polyhedron result = x;
582  result.add_recycled_generators(candidate_rays);
583  result.intersection_assign(H79);
584  // Force minimization.
585  result.minimize();
586 
587  // Check for stabilization with respect to `y_cert' and improvement
588  // over `H79'.
589  if (y_cert.is_stabilizing(result) && !result.contains(H79)) {
590  // The technique was successful.
591  x.m_swap(result);
592  PPL_ASSERT_HEAVY(x.OK(true));
593  return true;
594  }
595  else {
596  // The technique was unsuccessful.
597  return false;
598  }
599 }
600 
601 void
603  const Linear_Expression& x,
604  const Linear_Expression& y) {
606  std::deque<bool> considered(x.space_dimension());
611  x_k != x_end; ++x_k) {
612  const Variable k_var = x_k.variable();
613  const dimension_type k = k_var.id();
614  if (considered[k]) {
615  continue;
616  }
617 
618  while (y_k != y_end && y_k.variable().id() < k) {
619  ++y_k;
620  }
621 
622  if (y_k == y_end) {
623  break;
624  }
625 
626  const Variable y_k_var = y_k.variable();
627 
628  // Note that y_k_var.id() may be greater than k.
629 
631  // Do *not* increment y_h, since it may be after k already.
633  ++x_h;
634  for ( ; x_h != x_end; ++x_h) {
635  const dimension_type h = x_h.variable().id();
636  if (considered[h]) {
637  continue;
638  }
639 
640  while (y_h != y_end && y_h.variable().id() < h) {
641  ++y_h;
642  }
643 
644  // Note that y_h may be y_end, and y_h.variable().id() may not be k.
645 
646  if (y_h != y_end && y_h.variable().id() == h) {
647  tmp = (*x_k) * (*y_h);
648  }
649  else {
650  tmp = 0;
651  }
652 
653  if (y_k_var.id() == k) {
654  // The following line optimizes the computation of
655  // <CODE> tmp -= x[h] * y[k]; </CODE>
657  }
658 
659  const int clockwise = sgn(tmp);
660  const int first_or_third_quadrant = sgn(*x_k) * sgn(*x_h);
661  switch (clockwise * first_or_third_quadrant) {
662  case -1:
663  ray.set_coefficient(k_var, Coefficient_zero());
664  considered[k] = true;
665  break;
666  case 1:
668  considered[h] = true;
669  break;
670  default:
671  break;
672  }
673  }
674  }
675  ray.normalize();
676 }
677 
678 bool
680  const BHRZ03_Certificate& y_cert,
681  const Polyhedron& H79) {
682  Polyhedron& x = *this;
683  // It is assumed that `y <= x <= H79'.
684  PPL_ASSERT(x.topology() == y.topology()
685  && x.topology() == H79.topology());
686  PPL_ASSERT(x.space_dim == y.space_dim
687  && x.space_dim == H79.space_dim);
688  PPL_ASSERT(!x.marked_empty() && !x.has_something_pending()
690  PPL_ASSERT(!y.marked_empty() && !y.has_something_pending()
692  PPL_ASSERT(!H79.marked_empty() && !H79.has_something_pending()
694 
695  const dimension_type x_gen_sys_num_rows = x.gen_sys.num_rows();
696  const dimension_type y_gen_sys_num_rows = y.gen_sys.num_rows();
697 
698  // Candidate rays are kept in a temporary generator system.
699  Generator_System candidate_rays;
700  for (dimension_type i = x_gen_sys_num_rows; i-- > 0; ) {
701  const Generator& x_g = x.gen_sys[i];
702  // We choose a ray of `x' that does not belong to `y'.
703  if (x_g.is_ray() && y.relation_with(x_g) == Poly_Gen_Relation::nothing()) {
704  for (dimension_type j = y_gen_sys_num_rows; j-- > 0; ) {
705  const Generator& y_g = y.gen_sys[j];
706  if (y_g.is_ray()) {
707  Generator new_ray(x_g);
708  // Modify `new_ray' according to the evolution of `x_g' with
709  // respect to `y_g'.
710  modify_according_to_evolution(new_ray.expr, x_g.expr, y_g.expr);
711  PPL_ASSERT(new_ray.OK());
712  candidate_rays.insert(new_ray);
713  }
714  }
715  }
716  }
717 
718  // If there are no candidate rays, we cannot obtain stabilization.
719  if (candidate_rays.has_no_rows()) {
720  return false;
721  }
722 
723  // Be non-intrusive.
724  Polyhedron result = x;
725  result.add_recycled_generators(candidate_rays);
726  result.intersection_assign(H79);
727  // Force minimization.
728  result.minimize();
729 
730  // Check for stabilization with respect to `y' and improvement over `H79'.
731  if (y_cert.is_stabilizing(result) && !result.contains(H79)) {
732  // The technique was successful.
733  x.m_swap(result);
734  PPL_ASSERT_HEAVY(x.OK(true));
735  return true;
736  }
737  else {
738  // The technique was unsuccessful.
739  return false;
740  }
741 }
742 
743 void
745  Polyhedron& x = *this;
746  // Topology compatibility check.
747  if (x.topology() != y.topology()) {
748  throw_topology_incompatible("BHRZ03_widening_assign(y)", "y", y);
749  }
750  // Dimension-compatibility check.
751  if (x.space_dim != y.space_dim) {
752  throw_dimension_incompatible("BHRZ03_widening_assign(y)", "y", y);
753  }
754 
755  // Assume `y' is contained in or equal to `x'.
756  PPL_EXPECT_HEAVY(copy_contains(x, y));
757 
758  // If any argument is zero-dimensional or empty,
759  // the BHRZ03-widening behaves as the identity function.
760  if (x.space_dim == 0 || x.marked_empty() || y.marked_empty()) {
761  return;
762  }
763 
764  // `y.con_sys' and `y.gen_sys' should be in minimal form.
765  if (!y.minimize()) {
766  // `y' is empty: the result is `x'.
767  return;
768  }
769  // `x.con_sys' and `x.gen_sys' should be in minimal form.
770  x.minimize();
771 
772  // Compute certificate info for polyhedron `y'.
773  const BHRZ03_Certificate y_cert(y);
774 
775  // If the iteration is stabilizing, the resulting polyhedron is `x'.
776  // At this point, also check if the two polyhedra are the same
777  // (exploiting the knowledge that `y <= x').
778  if (y_cert.is_stabilizing(x) || y.contains(x)) {
779  PPL_ASSERT_HEAVY(OK());
780  return;
781  }
782 
783  // Here the iteration is not immediately stabilizing.
784  // If we are using the widening-with-tokens technique and
785  // there are tokens available, use one of them and return `x'.
786  if (tp != 0 && *tp > 0) {
787  --(*tp);
788  PPL_ASSERT_HEAVY(OK());
789  return;
790  }
791 
792  // Copy into `H79_cs' the constraints that are common to `x' and `y',
793  // according to the definition of the H79 widening.
794  // The other ones are copied into `x_minus_H79_cs'.
795  const Topology topol = x.topology();
796  Constraint_System H79_cs(topol);
797  Constraint_System x_minus_H79_cs(topol);
798  x.select_H79_constraints(y, H79_cs, x_minus_H79_cs);
799 
800  // We cannot have selected all of the rows, since otherwise
801  // the iteration should have been immediately stabilizing.
802  PPL_ASSERT(!x_minus_H79_cs.has_no_rows());
803  // Be careful to obtain the right space dimension
804  // (because `H79_cs' may be empty).
805  Polyhedron H79(topol, x.space_dim, UNIVERSE);
806  H79.add_recycled_constraints(H79_cs);
807  // Force minimization.
808  H79.minimize();
809 
810  // NOTE: none of the following widening heuristics is intrusive:
811  // they will modify `x' only when returning successfully.
812  if (x.BHRZ03_combining_constraints(y, y_cert, H79, x_minus_H79_cs)) {
813  return;
814  }
815 
816  PPL_ASSERT_HEAVY(H79.OK() && x.OK() && y.OK());
817 
818  if (x.BHRZ03_evolving_points(y, y_cert, H79)) {
819  return;
820  }
821 
822  PPL_ASSERT_HEAVY(H79.OK() && x.OK() && y.OK());
823 
824  if (x.BHRZ03_evolving_rays(y, y_cert, H79)) {
825  return;
826  }
827 
828  PPL_ASSERT_HEAVY(H79.OK() && x.OK() && y.OK());
829 
830  // No previous technique was successful: fall back to the H79 widening.
831  x.m_swap(H79);
832  PPL_ASSERT_HEAVY(x.OK(true));
833 
834  // The H79 widening is always stabilizing.
835  PPL_ASSERT(y_cert.is_stabilizing(x));
836 }
837 
838 void
841  const Constraint_System& cs,
842  unsigned* tp) {
843  Polyhedron& x = *this;
844  const dimension_type cs_num_rows = cs.num_rows();
845  // If `cs' is empty, we fall back to ordinary, non-limited widening.
846  if (cs_num_rows == 0) {
847  x.BHRZ03_widening_assign(y, tp);
848  return;
849  }
850 
851  // Topology compatibility check.
852  if (x.is_necessarily_closed()) {
853  if (!y.is_necessarily_closed()) {
854  throw_topology_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
855  "y", y);
856  }
857  if (cs.has_strict_inequalities()) {
858  throw_topology_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
859  "cs", cs);
860  }
861  }
862  else if (y.is_necessarily_closed()) {
863  throw_topology_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
864  "y", y);
865  }
866  // Dimension-compatibility check.
867  if (x.space_dim != y.space_dim) {
868  throw_dimension_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
869  "y", y);
870  }
871  // `cs' must be dimension-compatible with the two polyhedra.
872  const dimension_type cs_space_dim = cs.space_dimension();
873  if (x.space_dim < cs_space_dim) {
874  throw_dimension_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
875  "cs", cs);
876  }
877 
878  // Assume `y' is contained in or equal to `x'.
879  PPL_EXPECT_HEAVY(copy_contains(x, y));
880 
881  if (y.marked_empty()) {
882  return;
883  }
884  if (x.marked_empty()) {
885  return;
886  }
887 
888  // The limited BHRZ03-widening between two polyhedra in a
889  // zero-dimensional space is a polyhedron in a zero-dimensional
890  // space, too.
891  if (x.space_dim == 0) {
892  return;
893  }
894 
895  if (!y.minimize()) {
896  // We have just discovered that `y' is empty.
897  return;
898  }
899 
900  // Update the generators of `x': these are used to select,
901  // from the constraints in `cs', those that must be added
902  // to the resulting polyhedron.
904  || (!x.generators_are_up_to_date() && !x.update_generators())) {
905  // We have just discovered that `x' is empty.
906  return;
907  }
908 
909  Constraint_System new_cs;
910  // The constraints to be added must be satisfied by all the
911  // generators of `x'. We can disregard `y' because `y <= x'.
912  const Generator_System& x_gen_sys = x.gen_sys;
913  // Iterate upwards here so as to keep the relative ordering of constraints.
914  // Not really an issue: just aesthetics.
915  for (dimension_type i = 0; i < cs_num_rows; ++i) {
916  const Constraint& c = cs[i];
917  if (x_gen_sys.satisfied_by_all_generators(c)) {
918  new_cs.insert(c);
919  }
920  }
921  x.BHRZ03_widening_assign(y, tp);
922  x.add_recycled_constraints(new_cs);
923  PPL_ASSERT_HEAVY(OK());
924 }
925 
926 void
929  const Constraint_System& cs,
930  unsigned* tp) {
931  Rational_Box x_box(*this, ANY_COMPLEXITY);
932  const Rational_Box y_box(y, ANY_COMPLEXITY);
933  x_box.CC76_widening_assign(y_box);
934  limited_BHRZ03_extrapolation_assign(y, cs, tp);
935  Constraint_System x_box_cs = x_box.constraints();
936  add_recycled_constraints(x_box_cs);
937 }
void linear_combine(const Generator &y, dimension_type i)
Linearly combines *this with y so that i-th coefficient is 0.
Definition: Generator.cc:207
bool has_pending_constraints() const
Returns true if there are pending constraints.
bool constraints_are_minimized() const
Returns true if the system of constraints is minimized.
bool marked_empty() const
Returns true if the polyhedron is known to be empty.
A linear equality or inequality.
void swap(CO_Tree &x, CO_Tree &y)
bool strongly_minimize_constraints() const
Applies strong minimization to the constraints of an NNC polyhedron.
void select_CH78_constraints(const Polyhedron &y, Constraint_System &cs_selection) const
Copies to cs_selection the constraints of y corresponding to the definition of the CH78-widening of *...
size_t dimension_type
An unsigned integral type for representing space dimensions.
void update_constraints() const
Updates constraints starting from generators and minimizes them.
Generator_System gen_sys
The system of generators.
A line, ray, point or closure point.
Variable variable() const
Returns the variable of the coefficient pointed to by *this.
Linear_Expression expr
The linear expression encoding *this.
bool generators_are_minimized() const
Returns true if the system of generators is minimized.
bool is_empty() const
Returns true if and only if *this is an empty polyhedron.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
void insert(const Constraint &c)
Inserts in *this a copy of the constraint c, increasing the number of space dimensions if needed...
void BHRZ03_widening_assign(const Polyhedron &y, unsigned *tp=0)
Assigns to *this the result of computing the BHRZ03-widening between *this and y. ...
void set(unsigned long k)
Sets the bit in position k.
bool update_generators() const
Updates generators starting from constraints and minimizes them.
bool sat_g_is_up_to_date() const
Returns true if the saturation matrix sat_g is up-to-date.
void throw_dimension_incompatible(const char *method, const char *other_name, dimension_type other_dim) const
Topology topology() const
Returns the system topology.
void clear()
Removes all the constraints from the constraint system and sets its space dimension to 0...
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
void H79_widening_assign(const Polyhedron &y, unsigned *tp=0)
Assigns to *this the result of computing the H79_widening between *this and y.
void clear(unsigned long k)
Clears the bit in position k.
void set_coefficient(Variable v, Coefficient_traits::const_reference n)
Sets the coefficient of v in *this to n.
A row in a matrix of bits.
void limited_BHRZ03_extrapolation_assign(const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
Assigns to *this the result of computing the limited extrapolation between *this and y using the BHRZ...
void add_recycled_constraints(Constraint_System &cs)
Adds the constraints in cs to the system of constraints of *this (without minimizing the result)...
dimension_type id() const
Returns the index of the Cartesian axis associated to the variable.
A dimension of the vector space.
bool is_strict_inequality() const
Returns true if and only if *this is a strict inequality constraint.
The base class for convex polyhedra.
void limited_H79_extrapolation_assign(const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
Assigns to *this the result of computing the limited extrapolation between *this and y using the H79-...
static void modify_according_to_evolution(Linear_Expression &ray, const Linear_Expression &x, const Linear_Expression &y)
void update_sat_g() const
Updates sat_g using the updated constraints and generators.
bool is_inequality() const
Returns true if and only if *this is an inequality constraint (either strict or non-strict).
bool satisfied_by_all_generators(const Constraint &c) const
Returns true if all the generators satisfy c.
void add_recycled_generators(Generator_System &gs)
Adds the generators in gs to the system of generators of *this (without minimizing the result)...
Topology topology() const
Returns the topological kind of the polyhedron.
bool generators_are_up_to_date() const
Returns true if the system of generators is up-to-date.
Constraint_System con_sys
The system of constraints.
dimension_type num_equalities() const
Returns the number of equality constraints.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
bool constraints_are_up_to_date() const
Returns true if the system of constraints is up-to-date.
bool OK() const
Checks if all the invariants are satisfied.
Definition: Generator.cc:432
void throw_topology_incompatible(const char *method, const char *ph_name, const Polyhedron &ph) const
Bit_Matrix sat_g
The saturation matrix having generators on its columns.
void intersection_assign(const Polyhedron &y)
Assigns to *this the intersection of *this and y.
A not necessarily closed, iso-oriented hyperrectangle.
Definition: Box_defs.hh:299
bool BHRZ03_combining_constraints(const Polyhedron &y, const BHRZ03_Certificate &y_cert, const Polyhedron &H79, const Constraint_System &x_minus_H79_cs)
bool all_homogeneous_terms_are_zero() const
Returns true if and only if all the homogeneous terms of *this are .
bool is_point() const
Returns true if and only if *this is a point.
int compare(const Linear_Expression &x, const Linear_Expression &y)
void process_pending_generators() const
Processes the pending generators and obtains a minimized polyhedron.
void remove_trailing_rows(dimension_type n)
Removes the last n rows.
The universe element, i.e., the whole vector space.
bool BHRZ03_evolving_rays(const Polyhedron &y, const BHRZ03_Certificate &y_cert, const Polyhedron &H79)
bool BHRZ03_evolving_points(const Polyhedron &y, const BHRZ03_Certificate &y_cert, const Polyhedron &H79)
bool minimize(const Linear_Expression &expr, Coefficient &inf_n, Coefficient &inf_d, bool &minimum) const
Returns true if and only if *this is not empty and expr is bounded from below in *this, in which case the infimum value is computed.
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 convergence certificate for the BHRZ03 widening operator.
The entire library is confined to this namespace.
Definition: version.hh:61
dimension_type space_dim
The number of dimensions of the enclosing vector space.
bool is_stabilizing(const Polyhedron &ph) const
Returns true if and only if the certificate for polyhedron ph is strictly smaller than *this...
bool contains(const Polyhedron &y) const
Returns true if and only if *this contains y.
bool is_necessarily_closed() const
Returns true if and only if the polyhedron is necessarily closed.
Constraint_System constraints() const
Returns a system of constraints defining *this.
void swap(Affine_Space &x, Affine_Space &y)
Swaps x with y.
void select_H79_constraints(const Polyhedron &y, Constraint_System &cs_selected, Constraint_System &cs_not_selected) const
Splits the constraints of `x' into two subsets, depending on whether or not they are selected to comp...
bool OK(bool check_not_empty=false) const
Checks if all the invariants are satisfied.
bool process_pending_constraints() const
Processes the pending constraints and obtains a minimized polyhedron.
void sort_rows()
Sorts the rows and removes duplicates.
Definition: Bit_Matrix.cc:44
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)
bool sorted_contains(const Bit_Row &row) const
Looks for row in *this, which is assumed to be sorted.
static int sign(const Linear_Expression &x, const Linear_Expression &y)
Returns the sign of the scalar product between x and y.
bool has_pending_generators() const
Returns true if there are pending generators.
Coefficient c
Definition: PIP_Tree.cc:64
void bounded_BHRZ03_extrapolation_assign(const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
Assigns to *this the result of computing the bounded extrapolation between *this and y using the BHRZ...
void insert(const Generator &g)
Inserts in *this a copy of the generator g, increasing the number of space dimensions if needed...
void bounded_H79_extrapolation_assign(const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
Assigns to *this the result of computing the bounded extrapolation between *this and y using the H79-...
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.
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.
void m_swap(Polyhedron &y)
Swaps *this with polyhedron y. (*this and y can be dimension-incompatible.)
Topology
Kinds of polyhedra domains.
Poly_Con_Relation relation_with(const Constraint &c) const
Returns the relations holding between the polyhedron *this and the constraint c.
The relation between a polyhedron and a constraint.
bool has_something_pending() const
Returns true if there are either pending constraints or pending generators.
bool is_closure_point() const
Returns true if and only if *this is a closure point.
bool has_strict_inequalities() const
Returns true if and only if *this contains one or more strict inequality constraints.