PPL  1.2
Grid_Generator.cc
Go to the documentation of this file.
1 /* Grid_Generator class implementation (non-inline functions).
2  Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3  Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #include "ppl-config.h"
25 #include "Grid_Generator_defs.hh"
26 
27 #include "Variables_Set_defs.hh"
28 #include "math_utilities_defs.hh"
29 
30 #include <iostream>
31 #include <sstream>
32 
33 namespace PPL = Parma_Polyhedra_Library;
34 
35 void
37  const char* name_var,
38  const Variable v) const {
39  std::ostringstream s;
40  s << "PPL::Grid_Generator::" << method << ":" << std::endl
41  << "this->space_dimension() == " << space_dimension() << ", "
42  << name_var << ".space_dimension() == " << v.space_dimension() << ".";
43  throw std::invalid_argument(s.str());
44 }
45 
46 void
48  const char* reason) const {
49  std::ostringstream s;
50  s << "PPL::Grid_Generator::" << method << ":" << std::endl
51  << reason << ".";
52  throw std::invalid_argument(s.str());
53 }
54 
57  Coefficient_traits::const_reference d,
58  Representation r) {
59  if (d == 0) {
60  throw std::invalid_argument("PPL::parameter(e, d):\n"
61  "d == 0.");
62  }
63  // Add 1 to space dimension to allow for parameter divisor column.
64  Linear_Expression ec(e, e.space_dimension() + 1, r);
65 
67  const Variable divisor_var(e.space_dimension());
68  ec.set(divisor_var, d);
69 
70  // If the divisor is negative, negate it and all the coefficients of
71  // the parameter, so as to satisfy the invariant.
72  if (d < 0) {
73  neg_assign(ec);
74  }
75 
76  // Using this constructor saves reallocation when creating the
77  // coefficients.
78  const Grid_Generator gg(ec, PARAMETER);
79 
80  // NOTE: normalize() must *not* be called here, because this is a parameter,
81  // and it would change the represented parameter.
82  return gg;
83 }
84 
87  Coefficient_traits::const_reference d,
88  Representation r) {
89  if (d == 0) {
90  throw std::invalid_argument("PPL::grid_point(e, d):\n"
91  "d == 0.");
92  }
93  // Add 1 to space dimension to allow for parameter divisor column.
94  Linear_Expression ec(e, 1 + e.space_dimension(), r);
96 
97  // If the divisor is negative, negate it and all the coefficients of
98  // the point, so as to satisfy the invariant.
99  if (d < 0) {
100  neg_assign(ec);
101  }
102 
103  // Using this constructor saves reallocation when creating the
104  // coefficients.
105  Grid_Generator gg(ec, POINT);
106 
107  // Enforce normalization.
108  gg.expr.normalize();
109  return gg;
110 }
111 
114  return grid_point(Linear_Expression::zero(), Coefficient_one(), r);
115 }
116 
119  Representation r) {
120  return grid_point(e, Coefficient_one(), r);
121 }
122 
125  // The origin of the space cannot be a line.
127  throw std::invalid_argument("PPL::grid_line(e):\n"
128  "e == 0, but the origin cannot be a line.");
129  }
130 
131  // Add 1 to space dimension to allow for parameter divisor column.
132  Linear_Expression ec(e, 1 + e.space_dimension(), r);
134  // Using this constructor saves reallocation when creating the
135  // coefficients.
136  Grid_Generator gg(ec, LINE);
137 
138  // Enforce normalization.
139  gg.strong_normalize();
140  return gg;
141 }
142 
143 void
145  PPL_ASSERT(v1.space_dimension() <= space_dimension());
146  PPL_ASSERT(v2.space_dimension() <= space_dimension());
147  expr.swap_space_dimensions(v1, v2);
148  // *this is still normalized but it may not be strongly normalized.
149  if (!is_parameter()) {
150  sign_normalize();
151  }
152  PPL_ASSERT(OK());
153 }
154 
155 bool
157  PPL_ASSERT(vars.space_dimension() <= space_dimension());
158 
159  expr.remove_space_dimensions(vars);
160 
161  PPL_ASSERT(OK());
162  return true;
163 }
164 
165 void
167 ::permute_space_dimensions(const std::vector<Variable>& cycle) {
168  if (cycle.size() < 2) {
169  // No-op. No need to call sign_normalize().
170  return;
171  }
172 
173  expr.permute_space_dimensions(cycle);
174 
175  // *this is still normalized but may be not strongly normalized: sign
176  // normalization is necessary.
177  // Sign-normalizing a parameter changes its meaning, so do nothing for
178  // parameters.
179  if (!is_parameter()) {
180  sign_normalize();
181  }
182  PPL_ASSERT(OK());
183 }
184 
185 void
186 PPL::Grid_Generator::ascii_dump(std::ostream& s) const {
187  expr.ascii_dump(s);
188  s << ' ';
189  switch (type()) {
190  case LINE:
191  s << "L";
192  break;
193  case PARAMETER:
194  s << "Q";
195  break;
196  case POINT:
197  s << "P";
198  break;
199  }
200  s << "\n";
201 }
202 
204 
205 bool
207 
208  if (!expr.ascii_load(s)) {
209  return false;
210  }
211 
212  std::string str;
213 
214  if (!(s >> str)) {
215  return false;
216  }
217  if (str == "L") {
218  set_is_line();
219  }
220  else if (str == "P" || str == "Q") {
221  set_is_parameter_or_point();
222  }
223  else {
224  return false;
225  }
226 
227  PPL_ASSERT(OK());
228  return true;
229 }
230 
231 void
233  if (is_line()) {
234  set_is_parameter_or_point();
235  }
236  else if (!is_line_or_parameter()) {
237  // The grid generator is a point.
238  expr.set(Variable(expr.space_dimension() - 1), expr.inhomogeneous_term());
239  expr.set_inhomogeneous_term(Coefficient_zero());
240  }
241 }
242 
243 void
245  dimension_type i) {
246  expr.linear_combine(y.expr, i);
247  strong_normalize();
248 }
249 
251 int
253  const bool x_is_line_or_equality = x.is_line_or_equality();
254  const bool y_is_line_or_equality = y.is_line_or_equality();
255  if (x_is_line_or_equality != y_is_line_or_equality) {
256  // Equalities (lines) precede inequalities (ray/point).
257  return y_is_line_or_equality ? 2 : -2;
258  }
259 
260  return compare(x.expr, y.expr);
261 }
262 
263 bool
265  const Grid_Generator& x = *this;
266  const dimension_type x_space_dim = x.space_dimension();
267  if (x_space_dim != y.space_dimension()) {
268  return false;
269  }
270 
271  const Type x_type = x.type();
272  if (x_type != y.type()) {
273  return false;
274  }
275 
276  Grid_Generator tmp_x = *this;
277  Grid_Generator tmp_y = y;
278  const Variable last_var(x_space_dim);
279  if (x_type == POINT || x_type == LINE) {
280  tmp_x.expr.set(last_var, Coefficient_zero());
281  tmp_y.expr.set(last_var, Coefficient_zero());
282  }
283  // Normalize the copies, including the divisor column.
284  tmp_x.expr.normalize();
285  tmp_y.expr.normalize();
286  // Check for equality.
287  return tmp_x.is_equal_to(tmp_y);
288 }
289 
290 bool
292  return expr.is_equal_to(y.expr) && kind_ == y.kind_;
293 }
294 
295 bool
297  // This does not check neither the first nor the last coefficient.
298  return expr.all_zeroes(1, expr.space_dimension());
299 }
300 
301 void
302 PPL::Grid_Generator::scale_to_divisor(Coefficient_traits::const_reference d) {
303  PPL_ASSERT(d != 0);
304  if (is_line()) {
305  return;
306  }
307 
309  exact_div_assign(factor, d, divisor());
310  set_divisor(d);
311  PPL_ASSERT(factor > 0);
312  if (factor > 1) {
313  // Don't scale the first and last coefficients.
314  expr.mul_assign(factor, 1, expr.space_dimension());
315  }
316 }
317 
318 void
320  if (is_line_or_equality()) {
321  expr.sign_normalize();
322  }
323 }
324 
325 bool
327  Grid_Generator tmp = *this;
328  tmp.strong_normalize();
329  return compare(*this, tmp) == 0;
330 }
331 
333 
334 void
336  PPL_ASSERT(zero_dim_point_p == 0);
337  zero_dim_point_p = new Grid_Generator(grid_point());
338 }
339 
340 void
342  PPL_ASSERT(zero_dim_point_p != 0);
343  delete zero_dim_point_p;
344  zero_dim_point_p = 0;
345 }
346 
347 void
348 PPL::Grid_Generator::fancy_print(std::ostream& s) const {
349  bool need_divisor = false;
350  bool extra_parentheses = false;
351  const dimension_type num_variables = space_dimension();
352  const Grid_Generator::Type t = type();
353  switch (t) {
355  s << "l(";
356  break;
358  s << "q(";
359  if (expr.coefficient(Variable(num_variables)) == 1) {
360  break;
361  }
362  goto any_point;
364  s << "p(";
365  if (expr.inhomogeneous_term() > 1) {
366  any_point:
367  need_divisor = true;
368  if (!expr.all_zeroes(1, num_variables + 1)) {
369  extra_parentheses = true;
370  s << "(";
371  break;
372  }
373  }
374  break;
375  }
376 
378  bool first = true;
379  for (Linear_Expression::const_iterator i = expr.begin(),
380  i_end = expr.lower_bound(Variable(num_variables)); i != i_end; ++i) {
381  c = *i;
382  if (!first) {
383  if (c > 0) {
384  s << " + ";
385  }
386  else {
387  s << " - ";
388  neg_assign(c);
389  }
390  }
391  else {
392  first = false;
393  }
394  if (c == -1) {
395  s << "-";
396  }
397  else if (c != 1) {
398  s << c << "*";
399  }
400  IO_Operators::operator<<(s, i.variable());
401  }
402  if (first) {
403  // A grid generator in the origin.
404  s << 0;
405  }
406  if (extra_parentheses) {
407  s << ")";
408  }
409  if (need_divisor) {
410  s << "/" << divisor();
411  }
412  s << ")";
413 }
414 
416 std::ostream&
417 PPL::IO_Operators::operator<<(std::ostream& s, const Grid_Generator& g) {
418  g.fancy_print(s);
419  return s;
420 }
421 
423 std::ostream&
425  const Grid_Generator::Type& t) {
426  const char* n = 0;
427  switch (t) {
429  n = "LINE";
430  break;
432  n = "PARAMETER";
433  break;
435  n = "POINT";
436  break;
437  }
438  s << n;
439  return s;
440 }
441 
442 bool
444  // NOTE: do not check for normalization, as it does not hold.
445  const Grid_Generator& x = *this;
446 
447  if (!x.is_necessarily_closed()) {
448 #ifndef NDEBUG
449  std::cerr << "Grid_Generator should be necessarily closed.\n";
450 #endif
451  return false;
452  }
453 
454  if (x.expr.space_dimension() < 1) {
455 #ifndef NDEBUG
456  std::cerr << "Grid_Generator has fewer coefficients than the minimum "
457  << "allowed:\nspace dimension is " << x.expr.space_dimension()
458  << ", minimum is 1.\n";
459 #endif
460  return false;
461  }
462 
463  switch (x.type()) {
465  if (x.expr.inhomogeneous_term() != 0) {
466 #ifndef NDEBUG
467  std::cerr << "Inhomogeneous terms of lines must be zero!\n";
468 #endif
469  return false;
470  }
471  break;
472 
474  if (x.expr.inhomogeneous_term() != 0) {
475 #ifndef NDEBUG
476  std::cerr << "Inhomogeneous terms of parameters must be zero!\n";
477 #endif
478  return false;
479  }
480  if (x.divisor() <= 0) {
481 #ifndef NDEBUG
482  std::cerr << "Parameters must have positive divisors!\n";
483 #endif
484  return false;
485  }
486  break;
487 
489  if (x.expr.inhomogeneous_term() <= 0) {
490 #ifndef NDEBUG
491  std::cerr << "Points must have positive divisors!\n";
492 #endif
493  return false;
494  }
495  if (x.expr.coefficient(Variable(space_dimension())) != 0) {
496 #ifndef NDEBUG
497  std::cerr << "Points must have a zero parameter divisor!\n";
498 #endif
499  return false;
500  }
501  break;
502 
503  } // switch (x.type())
504 
505  // All tests passed.
506  return true;
507 }
dimension_type space_dimension() const
Returns the dimension of the smallest vector space enclosing all the variables whose indexes are in t...
bool is_equal_to(const Grid_Generator &y) const
Returns true if *this is identical to y.
size_t dimension_type
An unsigned integral type for representing space dimensions.
void permute_space_dimensions(const std::vector< Variable > &cycle)
Permutes the space dimensions of the grid generator.
An std::set of variables' indexes.
void set(dimension_type i, Coefficient_traits::const_reference n)
Sets the i-th coefficient to n.
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
bool remove_space_dimensions(const Variables_Set &vars)
Removes all the specified dimensions from the grid generator.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
std::ostream & operator<<(std::ostream &s, const Ask_Tell< D > &x)
bool check_strong_normalized() const
Returns true if and only if the coefficients are strongly normalized.
The standard C++ namespace.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
void fancy_print(std::ostream &s) const
A print function, with fancy, more human-friendly output.
void set_inhomogeneous_term(Coefficient_traits::const_reference n)
Sets the inhomogeneous term of *this to n.
void exact_div_assign(Checked_Number< T, Policy > &x, const Checked_Number< T, Policy > &y, const Checked_Number< T, Policy > &z)
Coefficient_traits::const_reference coefficient(Variable v) const
Returns the coefficient of v in *this.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
A dimension of the vector space.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
static Grid_Generator parameter(const Linear_Expression &e=Linear_Expression::zero(), Coefficient_traits::const_reference d=Coefficient_one(), Representation r=default_representation)
static void finalize()
Finalizes the class.
Coefficient_traits::const_reference divisor() const
Returns the divisor of *this.
bool is_necessarily_closed() const
Returns true if and only if the topology of *this row is necessarily closed.
void swap_space_dimensions(Variable v1, Variable v2)
Swaps the coefficients of the variables v1 and v2 .
Enable_If< Is_Native_Or_Checked< T >::value, bool >::type ascii_load(std::istream &s, T &t)
Type type() const
Returns the generator type of *this.
static const Grid_Generator * zero_dim_point_p
Holds (between class initialization and finalization) a pointer to the origin of the zero-dimensional...
bool all_homogeneous_terms_are_zero() const
Returns true if and only if all the homogeneous terms of *this are .
int compare(const Linear_Expression &x, const Linear_Expression &y)
bool is_equivalent_to(const Grid_Generator &y) const
Returns true if and only if *this and y are equivalent generators.
void linear_combine(const Grid_Generator &y, dimension_type i)
Linearly combines *this with y so that i-th coefficient is 0.
void sign_normalize()
Normalizes the sign of the coefficients so that the first non-zero (homogeneous) coefficient of a lin...
void throw_dimension_incompatible(const char *method, const char *name_var, const Variable v) const
Throw a std::invalid_argument exception containing the appropriate error message. ...
bool is_line_or_equality() const
Returns true if and only if *this row represents a line or an equality.
void neg_assign(GMP_Integer &x)
Coefficient_traits::const_reference Coefficient_zero()
Returns a const reference to a Coefficient with value 0.
static Grid_Generator grid_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.
#define PPL_OUTPUT_DEFINITIONS(class_name)
The entire library is confined to this namespace.
Definition: version.hh:61
bool all_homogeneous_terms_are_zero() const
Returns true if and only if all the homogeneous terms of *this are .
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
static Grid_Generator grid_line(const Linear_Expression &e, Representation r=default_representation)
Returns the line of direction e.
void strong_normalize()
Strong normalization: ensures that different Grid_Generator objects represent different hyperplanes o...
Coefficient c
Definition: PIP_Tree.cc:64
void throw_invalid_argument(const char *method, const char *reason) const
Throw a std::invalid_argument exception containing the appropriate error message. ...
static const Linear_Expression & zero()
Returns the (zero-dimension space) constant 0.
Coefficient_traits::const_reference Coefficient_one()
Returns a const reference to a Coefficient with value 1.
void scale_to_divisor(Coefficient_traits::const_reference d)
Scales *this to be represented with a divisor of d (if \*this is a parameter or point). Does nothing at all on lines.
bool OK() const
Checks if all the invariants are satisfied.
static void initialize()
Initializes the class.
A grid line, parameter or grid point.
void set_is_parameter()
Converts the Grid_Generator into a parameter.