00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <ppl-config.h>
00025
00026 #include "Generator.defs.hh"
00027
00028 #include "Variable.defs.hh"
00029 #include <iostream>
00030 #include <sstream>
00031 #include <stdexcept>
00032
00033 namespace PPL = Parma_Polyhedra_Library;
00034
00035 void
00036 PPL::Generator::throw_dimension_incompatible(const char* method,
00037 const char* name_var,
00038 const Variable v) const {
00039 std::ostringstream s;
00040 s << "PPL::Generator::" << method << ":" << std::endl
00041 << "this->space_dimension() == " << space_dimension() << ", "
00042 << name_var << ".space_dimension() == " << v.space_dimension() << ".";
00043 throw std::invalid_argument(s.str());
00044 }
00045
00046 void
00047 PPL::Generator::throw_invalid_argument(const char* method,
00048 const char* reason) const {
00049 std::ostringstream s;
00050 s << "PPL::Generator::" << method << ":" << std::endl
00051 << reason << ".";
00052 throw std::invalid_argument(s.str());
00053 }
00054
00055 PPL::Generator
00056 PPL::Generator::point(const Linear_Expression& e,
00057 Coefficient_traits::const_reference d) {
00058 if (d == 0)
00059 throw std::invalid_argument("PPL::point(e, d):\n"
00060 "d == 0.");
00061 Linear_Expression ec = e;
00062 Generator g(ec, Generator::POINT, NECESSARILY_CLOSED);
00063 g[0] = d;
00064
00065
00066
00067
00068 if (d < 0)
00069 for (dimension_type i = g.size(); i-- > 0; )
00070 neg_assign(g[i]);
00071
00072
00073 g.normalize();
00074 return g;
00075 }
00076
00077 PPL::Generator
00078 PPL::Generator::closure_point(const Linear_Expression& e,
00079 Coefficient_traits::const_reference d) {
00080 if (d == 0)
00081 throw std::invalid_argument("PPL::closure_point(e, d):\n"
00082 "d == 0.");
00083
00084 Linear_Expression ec = 0 * Variable(e.space_dimension());
00085 ec += e;
00086
00087 Generator g = point(ec, d);
00088
00089 g.set_not_necessarily_closed();
00090
00091 g.normalize();
00092 return g;
00093 }
00094
00095 PPL::Generator
00096 PPL::Generator::ray(const Linear_Expression& e) {
00097
00098 if (e.all_homogeneous_terms_are_zero())
00099 throw std::invalid_argument("PPL::ray(e):\n"
00100 "e == 0, but the origin cannot be a ray.");
00101
00102 Linear_Expression ec = e;
00103 Generator g(ec, Generator::RAY, NECESSARILY_CLOSED);
00104 g[0] = 0;
00105
00106 g.normalize();
00107 return g;
00108 }
00109
00110 PPL::Generator
00111 PPL::Generator::line(const Linear_Expression& e) {
00112
00113 if (e.all_homogeneous_terms_are_zero())
00114 throw std::invalid_argument("PPL::line(e):\n"
00115 "e == 0, but the origin cannot be a line.");
00116
00117 Linear_Expression ec = e;
00118 Generator g(ec, Generator::LINE, NECESSARILY_CLOSED);
00119 g[0] = 0;
00120
00121 g.strong_normalize();
00122 return g;
00123 }
00124
00125 bool
00126 PPL::Generator::is_equivalent_to(const Generator& y) const {
00127 const Generator& x = *this;
00128 const dimension_type x_space_dim = x.space_dimension();
00129 if (x_space_dim != y.space_dimension())
00130 return false;
00131
00132 const Type x_type = x.type();
00133 if (x_type != y.type())
00134 return false;
00135
00136 if (x_type == POINT
00137 && !(x.is_necessarily_closed() && y.is_necessarily_closed())) {
00138
00139
00140
00141 Linear_Expression x_expr(x);
00142 Linear_Expression y_expr(y);
00143
00144 x_expr.normalize();
00145 y_expr.normalize();
00146
00147 for (dimension_type i = x_space_dim + 1; i-- > 0; )
00148 if (x_expr[i] != y_expr[i])
00149 return false;
00150 return true;
00151 }
00152
00153
00154
00155 for (dimension_type i = x_space_dim + 1; i-- > 0; )
00156 if (x[i] != y[i])
00157 return false;
00158 return true;
00159 }
00160
00161 const PPL::Generator* PPL::Generator::zero_dim_point_p = 0;
00162 const PPL::Generator* PPL::Generator::zero_dim_closure_point_p = 0;
00163
00164 void
00165 PPL::Generator::initialize() {
00166 PPL_ASSERT(zero_dim_point_p == 0);
00167 zero_dim_point_p
00168 = new Generator(point());
00169
00170 PPL_ASSERT(zero_dim_closure_point_p == 0);
00171 zero_dim_closure_point_p
00172 = new Generator(closure_point());
00173 }
00174
00175 void
00176 PPL::Generator::finalize() {
00177 PPL_ASSERT(zero_dim_point_p != 0);
00178 delete zero_dim_point_p;
00179 zero_dim_point_p = 0;
00180
00181 PPL_ASSERT(zero_dim_closure_point_p != 0);
00182 delete zero_dim_closure_point_p;
00183 zero_dim_closure_point_p = 0;
00184 }
00185
00187 std::ostream&
00188 PPL::IO_Operators::operator<<(std::ostream& s, const Generator& g) {
00189 bool needed_divisor = false;
00190 bool extra_parentheses = false;
00191 const dimension_type num_variables = g.space_dimension();
00192 Generator::Type t = g.type();
00193 switch (t) {
00194 case Generator::LINE:
00195 s << "l(";
00196 break;
00197 case Generator::RAY:
00198 s << "r(";
00199 break;
00200 case Generator::POINT:
00201 s << "p(";
00202 goto any_point;
00203 case Generator::CLOSURE_POINT:
00204 s << "c(";
00205 any_point:
00206 if (g[0] != 1) {
00207 needed_divisor = true;
00208 dimension_type num_non_zero_coefficients = 0;
00209 for (dimension_type v = 0; v < num_variables; ++v)
00210 if (g[v+1] != 0)
00211 if (++num_non_zero_coefficients > 1) {
00212 extra_parentheses = true;
00213 s << "(";
00214 break;
00215 }
00216 }
00217 break;
00218 }
00219
00220 PPL_DIRTY_TEMP_COEFFICIENT(gv);
00221 bool first = true;
00222 for (dimension_type v = 0; v < num_variables; ++v) {
00223 gv = g[v+1];
00224 if (gv != 0) {
00225 if (!first) {
00226 if (gv > 0)
00227 s << " + ";
00228 else {
00229 s << " - ";
00230 neg_assign(gv);
00231 }
00232 }
00233 else
00234 first = false;
00235 if (gv == -1)
00236 s << "-";
00237 else if (gv != 1)
00238 s << gv << "*";
00239 s << PPL::Variable(v);
00240 }
00241 }
00242 if (first)
00243
00244 s << 0;
00245 if (extra_parentheses)
00246 s << ")";
00247 if (needed_divisor)
00248 s << "/" << g[0];
00249 s << ")";
00250 return s;
00251 }
00252
00254 std::ostream&
00255 PPL::IO_Operators::operator<<(std::ostream& s, const Generator::Type& t) {
00256 const char* n = 0;
00257 switch (t) {
00258 case Generator::LINE:
00259 n = "LINE";
00260 break;
00261 case Generator::RAY:
00262 n = "RAY";
00263 break;
00264 case Generator::POINT:
00265 n = "POINT";
00266 break;
00267 case Generator::CLOSURE_POINT:
00268 n = "CLOSURE_POINT";
00269 break;
00270 }
00271 s << n;
00272 return s;
00273 }
00274
00275 bool
00276 PPL::Generator::is_matching_closure_point(const Generator& p) const {
00277 PPL_ASSERT(topology() == p.topology()
00278 && space_dimension() == p.space_dimension()
00279 && type() == CLOSURE_POINT
00280 && p.type() == POINT);
00281 const Generator& cp = *this;
00282 if (cp[0] == p[0]) {
00283
00284
00285 for (dimension_type i = cp.size() - 2; i > 0; --i)
00286 if (cp[i] != p[i])
00287 return false;
00288 return true;
00289 }
00290 else {
00291
00292
00293 PPL_DIRTY_TEMP_COEFFICIENT(gcd);
00294 gcd_assign(gcd, cp[0], p[0]);
00295 const bool rel_prime = (gcd == 1);
00296 PPL_DIRTY_TEMP_COEFFICIENT(cp_0_scaled);
00297 PPL_DIRTY_TEMP_COEFFICIENT(p_0_scaled);
00298 if (!rel_prime) {
00299 exact_div_assign(cp_0_scaled, cp[0], gcd);
00300 exact_div_assign(p_0_scaled, p[0], gcd);
00301 }
00302 const Coefficient& cp_div = rel_prime ? cp[0] : cp_0_scaled;
00303 const Coefficient& p_div = rel_prime ? p[0] : p_0_scaled;
00304 PPL_DIRTY_TEMP_COEFFICIENT(prod1);
00305 PPL_DIRTY_TEMP_COEFFICIENT(prod2);
00306 for (dimension_type i = cp.size() - 2; i > 0; --i) {
00307 prod1 = cp[i] * p_div;
00308 prod2 = p[i] * cp_div;
00309 if (prod1 != prod2)
00310 return false;
00311 }
00312 return true;
00313 }
00314 }
00315
00316 PPL_OUTPUT_DEFINITIONS(Generator)
00317
00318 bool
00319 PPL::Generator::OK() const {
00320
00321 if (!Linear_Row::OK())
00322 return false;
00323
00324
00325 const dimension_type min_size = is_necessarily_closed() ? 1 : 2;
00326 if (size() < min_size) {
00327 #ifndef NDEBUG
00328 std::cerr << "Generator has fewer coefficients than the minimum "
00329 << "allowed by its topology:"
00330 << std::endl
00331 << "size is " << size()
00332 << ", minimum is " << min_size << "."
00333 << std::endl;
00334 #endif
00335 return false;
00336 }
00337
00338
00339 const Generator& g = *this;
00340 Generator tmp = g;
00341 tmp.strong_normalize();
00342 if (tmp != g) {
00343 #ifndef NDEBUG
00344 std::cerr << "Generators should be strongly normalized!"
00345 << std::endl;
00346 #endif
00347 return false;
00348 }
00349
00350 switch (g.type()) {
00351 case LINE:
00352
00353 case RAY:
00354 if (g[0] != 0) {
00355 #ifndef NDEBUG
00356 std::cerr << "Lines must have a zero inhomogeneous term!"
00357 << std::endl;
00358 #endif
00359 return false;
00360 }
00361 if (!g.is_necessarily_closed() && g[size() - 1] != 0) {
00362 #ifndef NDEBUG
00363 std::cerr << "Lines and rays must have a zero coefficient "
00364 << "for the epsilon dimension!"
00365 << std::endl;
00366 #endif
00367 return false;
00368 }
00369
00370
00371 if (g.all_homogeneous_terms_are_zero()) {
00372 #ifndef NDEBUG
00373 std::cerr << "The origin of the vector space cannot be a line or a ray!"
00374 << std::endl;
00375 #endif
00376 return false;
00377 }
00378 break;
00379
00380 case POINT:
00381 if (g[0] <= 0) {
00382 #ifndef NDEBUG
00383 std::cerr << "Points must have a positive divisor!"
00384 << std::endl;
00385 #endif
00386 return false;
00387 }
00388 if (!g.is_necessarily_closed())
00389 if (g[size() - 1] <= 0) {
00390 #ifndef NDEBUG
00391 std::cerr << "In the NNC topology, points must have epsilon > 0"
00392 << std::endl;
00393 #endif
00394 return false;
00395 }
00396 break;
00397
00398 case CLOSURE_POINT:
00399 if (g[0] <= 0) {
00400 #ifndef NDEBUG
00401 std::cerr << "Closure points must have a positive divisor!"
00402 << std::endl;
00403 #endif
00404 return false;
00405 }
00406 break;
00407 }
00408
00409
00410 return true;
00411 }