PPL  1.2
Grid_widenings.cc
Go to the documentation of this file.
1 /* Grid 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 "Grid_defs.hh"
27 #include "assertions.hh"
28 #include <iostream>
29 
30 namespace PPL = Parma_Polyhedra_Library;
31 
32 void
34  Congruence_System& selected_cgs) const {
35  // Private method: the caller must ensure the following conditions
36  // (beside the inclusion `y <= x').
37  PPL_ASSERT(space_dim == y.space_dim);
38  PPL_ASSERT(!marked_empty());
39  PPL_ASSERT(!y.marked_empty());
40  PPL_ASSERT(congruences_are_minimized());
41  PPL_ASSERT(y.congruences_are_minimized());
42 
43  // Note: row counters start at 0, to preserve the original order in
44  // the selected congruences.
45  for (dimension_type dim = con_sys.space_dimension(), x_row = 0, y_row = 0;
46  dim > 0; --dim) {
47  PPL_ASSERT(dim_kinds[dim] == CON_VIRTUAL
48  || dim_kinds[dim] == y.dim_kinds[dim]);
49  switch (dim_kinds[dim]) {
50  case PROPER_CONGRUENCE:
51  {
52  const Congruence& cg = con_sys[x_row];
53  const Congruence& y_cg = y.con_sys[y_row];
54  if (cg.is_equal_at_dimension(Variable(dim - 1), y_cg)) {
55  // The leading diagonal entries are equal.
56  selected_cgs.insert(cg);
57  }
58  ++x_row;
59  ++y_row;
60  }
61  break;
62  case EQUALITY:
63  selected_cgs.insert(con_sys[x_row]);
64  ++x_row;
65  ++y_row;
66  break;
67  case CON_VIRTUAL:
68  if (y.dim_kinds[dim] != CON_VIRTUAL) {
69  ++y_row;
70  }
71  break;
72  }
73  }
74 }
75 
76 void
78  Grid& x = *this;
79  // Dimension-compatibility check.
80  if (x.space_dim != y.space_dim) {
81  throw_dimension_incompatible("widening_assign(y)", "y", y);
82  }
83 
84  // Assume `y' is contained in or equal to `x'.
85  PPL_EXPECT_HEAVY(copy_contains(x, y));
86 
87  // Leave `x' the same if `x' or `y' is zero-dimensional or empty.
88  if (x.space_dim == 0 || x.marked_empty() || y.marked_empty()) {
89  return;
90  }
91 
92  // Ensure that the `x' congruences are in minimal form.
94  if (!x.congruences_are_minimized()) {
95  if (simplify(x.con_sys, x.dim_kinds)) {
96  // `x' is empty.
97  x.set_empty();
98  return;
99  }
101  }
102  }
103  else {
104  x.update_congruences();
105  }
106 
107  // Ensure that the `y' congruences are in minimal form.
108  Grid& yy = const_cast<Grid&>(y);
109  if (yy.congruences_are_up_to_date()) {
110  if (!yy.congruences_are_minimized()) {
111  if (simplify(yy.con_sys, yy.dim_kinds)) {
112  // `y' is empty.
113  yy.set_empty();
114  return;
115  }
117  }
118  }
119  else {
120  yy.update_congruences();
121  }
122 
123  if (con_sys.num_equalities() < yy.con_sys.num_equalities()) {
124  return;
125  }
126  // Copy into `cgs' the congruences of `x' that are common to `y',
127  // according to the grid widening.
128  Congruence_System cgs;
129  x.select_wider_congruences(yy, cgs);
130 
131  if (cgs.num_rows() == con_sys.num_rows()) {
132  // All congruences were selected, thus the result is `x'.
133  return;
134  }
135 
136  // A strict subset of the congruences was selected.
137 
138  Grid result(x.space_dim);
139  result.add_recycled_congruences(cgs);
140 
141  // Check whether we are using the widening-with-tokens technique
142  // and there are still tokens available.
143  if (tp != 0 && *tp > 0) {
144  // There are tokens available. If `result' is not a subset of
145  // `x', then it is less precise and we use one of the available
146  // tokens.
147  if (!x.contains(result)) {
148  --(*tp);
149  }
150  }
151  else {
152  // No tokens.
153  x.m_swap(result);
154  }
155 
156  PPL_ASSERT(x.OK(true));
157 }
158 
159 void
161  const Congruence_System& cgs,
162  unsigned* tp) {
163  Grid& x = *this;
164 
165  // Check dimension compatibility.
166  if (x.space_dim != y.space_dim) {
167  throw_dimension_incompatible("limited_extrapolation_assign(y, cgs)",
168  "y", y);
169  }
170  // `cgs' must be dimension-compatible with the two grids.
171  const dimension_type cgs_space_dim = cgs.space_dimension();
172  if (x.space_dim < cgs_space_dim) {
173  throw_dimension_incompatible("limited_extrapolation_assign(y, cgs)",
174  "cgs", cgs);
175  }
176 
177  const dimension_type cgs_num_rows = cgs.num_rows();
178  // If `cgs' is empty (of rows), fall back to ordinary widening.
179  if (cgs_num_rows == 0) {
180  x.widening_assign(y, tp);
181  return;
182  }
183 
184  // Assume `y' is contained in or equal to `x'.
185  PPL_EXPECT_HEAVY(copy_contains(x, y));
186 
187  if (y.marked_empty()) {
188  return;
189  }
190  if (x.marked_empty()) {
191  return;
192  }
193 
194  // The limited widening between two grids in a zero-dimensional
195  // space is also a grid in a zero-dimensional space.
196  if (x.space_dim == 0) {
197  return;
198  }
199 
200  // Update the generators of `x': these are used to select, from the
201  // congruences in `cgs', those that must be added to the widened
202  // grid.
203  if (!x.generators_are_up_to_date() && !x.update_generators()) {
204  // `x' is empty.
205  return;
206  }
207 
208  if (tp == NULL || *tp == 0) {
209  // Widening may change the grid, so add the congruences.
210  Congruence_System new_cgs;
211  // The congruences to be added need only be satisfied by all the
212  // generators of `x', as `y <= x'. Iterate upwards here, to keep
213  // the relative ordering of congruences (just for aesthetics).
214  for (dimension_type i = 0; i < cgs_num_rows; ++i) {
215  const Congruence& cg = cgs[i];
217  new_cgs.insert(cg);
218  }
219  }
221  x.add_recycled_congruences(new_cgs);
222  }
223  else {
224  // There are tokens, so widening will leave the grid the same.
226  }
227 
228  PPL_ASSERT(OK());
229 }
230 
231 void
233  Grid_Generator_System& widened_ggs) const {
234  // Private method: the caller must ensure the following conditions
235  // (beside the inclusion `y <= x').
236  PPL_ASSERT(space_dim == y.space_dim);
237  PPL_ASSERT(!marked_empty());
238  PPL_ASSERT(!y.marked_empty());
239  PPL_ASSERT(generators_are_minimized());
240  PPL_ASSERT(y.generators_are_minimized());
241 
242  // Note: row counters start at 0, to preserve the original order in
243  // the selected generators.
244  for (dimension_type dim = 0, x_row = 0, y_row = 0;
245  dim <= gen_sys.space_dimension(); ++dim) {
246  PPL_ASSERT(dim_kinds[dim] == LINE
247  || y.dim_kinds[dim] == GEN_VIRTUAL
248  || dim_kinds[dim] == y.dim_kinds[dim]);
249  switch (dim_kinds[dim]) {
250  case PARAMETER:
251  {
252  const Grid_Generator& gg = gen_sys[x_row];
253  const Grid_Generator& y_gg = y.gen_sys[y_row];
254  if (gg.is_equal_at_dimension(dim, y_gg)) {
255  // The leading diagonal entry is equal.
256  widened_ggs.insert(gg);
257  }
258  else {
259  const Linear_Expression expr(gg.expression());
260  Grid_Generator line = grid_line(expr);
261  widened_ggs.insert(line, Recycle_Input());
262  }
263  ++x_row;
264  ++y_row;
265  }
266  break;
267  case LINE:
268  widened_ggs.insert(gen_sys[x_row]);
269  ++x_row;
270  ++y_row;
271  break;
272  case GEN_VIRTUAL:
273  if (y.dim_kinds[dim] != GEN_VIRTUAL) {
274  ++y_row;
275  }
276  break;
277  }
278  }
279 }
280 
281 void
283  Grid& x = *this;
284 
285  // Dimension-compatibility check.
286  if (x.space_dim != y.space_dim) {
287  throw_dimension_incompatible("generator_widening_assign(y)", "y", y);
288  }
289 
290  // Assume `y' is contained in or equal to `x'.
291  PPL_EXPECT_HEAVY(copy_contains(x, y));
292 
293  // Leave `x' the same if `x' or `y' is zero-dimensional or empty.
294  if (x.space_dim == 0 || x.marked_empty() || y.marked_empty()) {
295  return;
296  }
297 
298  // Ensure that the `x' generators are in minimal form.
299  if (x.generators_are_up_to_date()) {
300  if (!x.generators_are_minimized()) {
301  simplify(x.gen_sys, x.dim_kinds);
302  PPL_ASSERT(!x.gen_sys.has_no_rows());
304  }
305  }
306  else {
307  x.update_generators();
308  }
309 
310  if (x.marked_empty()) {
311  return;
312  }
313 
314  // Ensure that the `y' generators are in minimal form.
315  Grid& yy = const_cast<Grid&>(y);
316  if (yy.generators_are_up_to_date()) {
317  if (!yy.generators_are_minimized()) {
318  simplify(yy.gen_sys, yy.dim_kinds);
319  PPL_ASSERT(!yy.gen_sys.has_no_rows());
321  }
322  }
323  else {
324  yy.update_generators();
325  }
326 
327  if (gen_sys.num_rows() > yy.gen_sys.num_rows()) {
328  return;
329  }
330 
331  if (gen_sys.num_lines() > yy.gen_sys.num_lines()) {
332  return;
333  }
334 
335  // Copy into `ggs' the generators of `x' that are common to `y',
336  // according to the grid widening.
338  x.select_wider_generators(yy, ggs);
339 
340  if (ggs.num_parameters() == gen_sys.num_parameters()) {
341  // All parameters are kept as parameters, thus the result is `x'.
342  return;
343  }
344 
345  // A strict subset of the parameters was selected.
346 
347  Grid result(x.space_dim, EMPTY);
348  result.add_recycled_grid_generators(ggs);
349 
350  // Check whether we are using the widening-with-tokens technique
351  // and there are still tokens available.
352  if (tp != 0 && *tp > 0) {
353  // There are tokens available. If `result' is not a subset of
354  // `x', then it is less precise and we use one of the available
355  // tokens.
356  if (!x.contains(result)) {
357  --(*tp);
358  }
359  }
360  else {
361  // No tokens.
362  x.m_swap(result);
363  }
364 
365  PPL_ASSERT(x.OK(true));
366 }
367 
368 void
370  const Congruence_System& cgs,
371  unsigned* tp) {
372  Grid& x = *this;
373 
374  // Check dimension compatibility.
375  if (x.space_dim != y.space_dim) {
376  throw_dimension_incompatible("limited_extrapolation_assign(y, cgs)",
377  "y", y);
378  }
379  // `cgs' must be dimension-compatible with the two grids.
380  const dimension_type cgs_space_dim = cgs.space_dimension();
381  if (x.space_dim < cgs_space_dim) {
382  throw_dimension_incompatible("limited_extrapolation_assign(y, cgs)",
383  "cgs", cgs);
384  }
385 
386  const dimension_type cgs_num_rows = cgs.num_rows();
387  // If `cgs' is empty (of rows), fall back to ordinary widening.
388  if (cgs_num_rows == 0) {
389  x.generator_widening_assign(y, tp);
390  return;
391  }
392 
393  // Assume `y' is contained in or equal to `x'.
394  PPL_EXPECT_HEAVY(copy_contains(x, y));
395 
396  if (y.marked_empty()) {
397  return;
398  }
399  if (x.marked_empty()) {
400  return;
401  }
402 
403  // The limited widening between two grids in a zero-dimensional
404  // space is also a grid in a zero-dimensional space.
405  if (x.space_dim == 0) {
406  return;
407  }
408 
409  // Update the generators of `x': these are used to select, from the
410  // congruences in `cgs', those that must be added to the widened
411  // grid.
412  if (!x.generators_are_up_to_date() && !x.update_generators()) {
413  // `x' is empty.
414  return;
415  }
416 
417  if (tp == NULL || *tp == 0) {
418  // Widening may change the grid, so add the congruences.
419  Congruence_System new_cgs;
420  // The congruences to be added need only be satisfied by all the
421  // generators of `x', as `y <= x'. Iterate upwards here, to keep
422  // the relative ordering of congruences (just for aesthetics).
423  for (dimension_type i = 0; i < cgs_num_rows; ++i) {
424  const Congruence& cg = cgs[i];
426  new_cgs.insert(cg);
427  }
428  }
429  x.generator_widening_assign(y, tp);
430  x.add_recycled_congruences(new_cgs);
431  }
432  else {
433  // There are tokens, so widening will leave the grid the same.
434  x.generator_widening_assign(y, tp);
435  }
436 
437  PPL_ASSERT(OK());
438 }
439 
440 void
441 PPL::Grid::widening_assign(const Grid& y, unsigned* tp) {
442  Grid& x = *this;
443 
444  // Dimension-compatibility check.
445  if (x.space_dim != y.space_dim) {
446  throw_dimension_incompatible("widening_assign(y)", "y", y);
447  }
448 
449  // Assume `y' is contained in or equal to `x'.
450  PPL_EXPECT_HEAVY(copy_contains(x, y));
451 
452  // If the `x' congruences are up to date and `y' congruences are up
453  // to date use the congruence widening.
456  return;
457  }
458 
459  // If the `x' generators are up to date and `y' generators are up to
460  // date use the generator widening.
462  x.generator_widening_assign(y, tp);
463  return;
464  }
465 
467 }
468 
469 void
471  const Congruence_System& cgs,
472  unsigned* tp) {
473  Grid& x = *this;
474 
475  // Check dimension compatibility.
476  if (x.space_dim != y.space_dim) {
477  throw_dimension_incompatible("limited_extrapolation_assign(y, cgs)",
478  "y", y);
479  }
480 
481  // `cgs' must be dimension-compatible with the two grids.
482  const dimension_type cgs_space_dim = cgs.space_dimension();
483  if (x.space_dim < cgs_space_dim) {
484  throw_dimension_incompatible("limited_extrapolation_assign(y, cgs)",
485  "cgs", cgs);
486  }
487 
488  const dimension_type cgs_num_rows = cgs.num_rows();
489  // If `cgs' is empty (of rows), fall back to ordinary widening.
490  if (cgs_num_rows == 0) {
491  x.widening_assign(y, tp);
492  return;
493  }
494 
495  // Assume `y' is contained in or equal to `x'.
496  PPL_EXPECT_HEAVY(copy_contains(x, y));
497 
498  if (y.marked_empty()) {
499  return;
500  }
501  if (x.marked_empty()) {
502  return;
503  }
504 
505  // The limited widening between two grids in a zero-dimensional
506  // space is also a grid in a zero-dimensional space.
507  if (x.space_dim == 0) {
508  return;
509  }
510 
511  // Update the generators of `x': these are used to select, from the
512  // congruences in `cgs', those that must be added to the widened
513  // grid.
514  if (!x.generators_are_up_to_date() && !x.update_generators()) {
515  // `x' is empty.
516  return;
517  }
518 
519  if (tp == NULL || *tp == 0) {
520  // Widening may change the grid, so add the congruences.
521  Congruence_System new_cgs;
522  // The congruences to be added need only be satisfied by all the
523  // generators of `x', as `y <= x'. Iterate upwards here, to keep
524  // the relative ordering of congruences (just for aesthetics).
525  for (dimension_type i = 0; i < cgs_num_rows; ++i) {
526  const Congruence& cg = cgs[i];
528  new_cgs.insert(cg);
529  }
530  }
531  x.widening_assign(y, tp);
532  x.add_recycled_congruences(new_cgs);
533  }
534  else {
535  // There are tokens, so widening will leave the grid the same.
536  x.widening_assign(y, tp);
537  }
538 
539  PPL_ASSERT(OK());
540 }
Grid_Generator_System gen_sys
The system of generators.
Definition: Grid_defs.hh:1973
void congruence_widening_assign(const Grid &y, unsigned *tp=NULL)
Assigns to *this the result of computing the Grid widening between *this and y using congruence syste...
The empty element, i.e., the empty set.
void limited_extrapolation_assign(const Grid &y, const Congruence_System &cgs, unsigned *tp=NULL)
Improves the result of the Grid widening computation by also enforcing those congruences in cgs that ...
void limited_generator_extrapolation_assign(const Grid &y, const Congruence_System &cgs, unsigned *tp=NULL)
Improves the result of the generator variant of the Grid widening computation by also enforcing those...
void generator_widening_assign(const Grid &y, unsigned *tp=NULL)
Assigns to *this the result of computing the Grid widening between *this and y using generator system...
void set_empty()
Sets status to express that the grid is empty, clearing all corresponding matrices.
size_t dimension_type
An unsigned integral type for representing space dimensions.
void insert(const Congruence &cg)
Inserts in *this a copy of the congruence cg, increasing the number of space dimensions if needed...
Congruence_System con_sys
The system of congruences.
Definition: Grid_defs.hh:1970
bool is_equal_at_dimension(Variable v, const Congruence &cg) const
Returns true if *this is equal to cg in dimension v.
bool is_equal_at_dimension(dimension_type dim, const Grid_Generator &gg) const
Returns true if *this is equal to gg in dimension dim.
dimension_type num_lines() const
Returns the number of lines in the system.
void widening_assign(const Grid &y, unsigned *tp=NULL)
Assigns to *this the result of computing the Grid widening between *this and y.
static Poly_Con_Relation is_included()
The polyhedron is included in the set of points satisfying the constraint.
dimension_type num_equalities() const
Returns the number of equalities.
Poly_Con_Relation relation_with(const Congruence &cg) const
Returns the relations holding between *this and cg.
Definition: Grid_public.cc:386
bool congruences_are_up_to_date() const
Returns true if the system of congruences is up-to-date.
Definition: Grid_inlines.hh:40
expr_type expression() const
Partial read access to the (adapted) internal expression.
void set_generators_minimized()
Sets status to express that generators are minimized.
Definition: Grid_inlines.hh:76
A dimension of the vector space.
void add_recycled_grid_generators(Grid_Generator_System &gs)
Adds the generators in gs to the system of generators of this.
bool OK(bool check_not_empty=false) const
Checks if all the invariants are satisfied.
Definition: Grid_public.cc:958
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
void limited_congruence_extrapolation_assign(const Grid &y, const Congruence_System &cgs, unsigned *tp=NULL)
Improves the result of the congruence variant of Grid widening computation by also enforcing those co...
bool contains(const Grid &y) const
Returns true if and only if *this contains y.
void select_wider_generators(const Grid &y, Grid_Generator_System &widened_ggs) const
Copies widened generators from y to widened_ggs.
bool generators_are_up_to_date() const
Returns true if the system of generators is up-to-date.
Definition: Grid_inlines.hh:45
dimension_type space_dim
The number of dimensions of the enclosing vector space.
Definition: Grid_defs.hh:1983
The entire library is confined to this namespace.
Definition: version.hh:61
dimension_type num_rows() const
Returns the number of rows in the system.
bool marked_empty() const
Returns true if the grid is known to be empty.
Definition: Grid_inlines.hh:35
dimension_type num_rows() const
Returns the number of rows (generators) in the system.
bool congruences_are_minimized() const
Returns true if the system of congruences is minimized.
Definition: Grid_inlines.hh:50
void update_congruences() const
Updates and minimizes the congruences from the generators.
dimension_type num_parameters() const
Returns the number of parameters in the system.
void m_swap(Grid &y)
Swaps *this with grid y. (*this and y can be dimension-incompatible.)
bool generators_are_minimized() const
Returns true if the system of generators is minimized.
Definition: Grid_inlines.hh:55
void select_wider_congruences(const Grid &y, Congruence_System &selected_cgs) const
Copies a widened selection of congruences from y to selected_cgs.
void add_recycled_congruences(Congruence_System &cgs)
Adds the congruences in cgs to *this.
void insert(const Grid_Generator &g)
Inserts into *this a copy of the generator g, increasing the number of space dimensions if needed...
bool update_generators() const
Updates and minimizes the generators from the congruences.
A grid line, parameter or grid point.
void set_congruences_minimized()
Sets status to express that congruences are minimized.
Definition: Grid_inlines.hh:70