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 "Congruence_System.defs.hh"
00027 #include "Congruence_System.inlines.hh"
00028 #include "Constraint_System.defs.hh"
00029 #include "Constraint_System.inlines.hh"
00030 #include "Congruence.defs.hh"
00031 #include "Grid_Generator.defs.hh"
00032 #include "Scalar_Products.defs.hh"
00033 #include "assert.hh"
00034 #include <string>
00035 #include <vector>
00036 #include <iostream>
00037 #include <stdexcept>
00038
00039 namespace PPL = Parma_Polyhedra_Library;
00040
00041 PPL::Congruence_System::Congruence_System(const Constraint_System& cs)
00042 : Matrix(0, cs.space_dimension() + 2) {
00043 for (Constraint_System::const_iterator i = cs.begin(),
00044 cs_end = cs.end(); i != cs_end; ++i)
00045 if (i->is_equality())
00046 insert(*i);
00047 }
00048
00049 bool
00050 PPL::Congruence_System::
00051 increase_space_dimension(const dimension_type new_space_dim) {
00052 PPL_ASSERT(space_dimension() <= new_space_dim);
00053
00054 const dimension_type cols_to_add = new_space_dim - space_dimension();
00055
00056 if (cols_to_add) {
00057 if (num_rows()) {
00058 const dimension_type old_num_columns = num_columns();
00059 add_zero_columns(cols_to_add);
00060
00061 swap_columns(num_columns() - 1, old_num_columns - 1);
00062 }
00063 else
00064
00065 add_zero_columns(cols_to_add);
00066 }
00067
00068 PPL_ASSERT(OK());
00069 return true;
00070 }
00071
00072 void
00073 PPL::Congruence_System::insert_verbatim(const Congruence& cg) {
00074 const dimension_type old_num_columns = num_columns();
00075 const dimension_type cg_size = cg.size();
00076
00077 if (cg_size > old_num_columns) {
00078
00079 add_zero_columns(cg_size - old_num_columns);
00080 if (!has_no_rows())
00081
00082 swap_columns(old_num_columns - 1, cg_size - 1);
00083 add_row(cg);
00084 }
00085 else if (cg_size < old_num_columns) {
00086
00087 Congruence rc(cg, old_num_columns, row_capacity);
00088
00089 std::swap(rc[cg_size - 1], rc[old_num_columns - 1]);
00090 add_recycled_row(rc);
00091 }
00092 else
00093
00094 add_row(cg);
00095
00096 PPL_ASSERT(OK());
00097 }
00098
00099 void
00100 PPL::Congruence_System::insert(const Constraint& c) {
00101 const dimension_type cg_size = c.space_dimension() + 2;
00102 const dimension_type old_num_columns = num_columns();
00103 if (cg_size < old_num_columns) {
00104
00105 Congruence cg(c, old_num_columns, row_capacity);
00106 add_recycled_row(cg);
00107 }
00108 else {
00109 if (cg_size > old_num_columns) {
00110
00111 add_zero_columns(cg_size - old_num_columns);
00112 if (!has_no_rows())
00113
00114 swap_columns(old_num_columns - 1, cg_size - 1);
00115 }
00116 Congruence cg(c, cg_size, row_capacity);
00117 add_recycled_row(cg);
00118 }
00119 operator[](rows.size()-1).strong_normalize();
00120
00121 PPL_ASSERT(OK());
00122 }
00123
00124 void
00125 PPL::Congruence_System::recycling_insert(Congruence_System& cgs) {
00126 const dimension_type old_num_rows = num_rows();
00127 const dimension_type cgs_num_rows = cgs.num_rows();
00128 const dimension_type old_num_columns = num_columns();
00129 dimension_type cgs_num_columns = cgs.num_columns();
00130 if (old_num_columns >= cgs_num_columns)
00131 add_zero_rows(cgs_num_rows, Row::Flags());
00132 else {
00133 add_zero_rows_and_columns(cgs_num_rows,
00134 cgs_num_columns - old_num_columns,
00135 Row::Flags());
00136
00137 swap_columns(old_num_columns - 1, num_columns() - 1);
00138 }
00139 --cgs_num_columns;
00140 const dimension_type mod_index = num_columns() - 1;
00141 for (dimension_type i = cgs_num_rows; i-- > 0; ) {
00142
00143
00144
00145 Congruence& new_cg = operator[](old_num_rows + i);
00146 Congruence& old_cg = cgs[i];
00147 for (dimension_type j = cgs_num_columns; j-- > 0; )
00148 std::swap(new_cg[j], old_cg[j]);
00149 std::swap(new_cg[mod_index], old_cg[cgs_num_columns]);
00150 }
00151
00152 PPL_ASSERT(OK());
00153 }
00154
00155 void
00156 PPL::Congruence_System::insert(const Congruence_System& y) {
00157 Congruence_System& x = *this;
00158
00159 const dimension_type x_num_rows = x.num_rows();
00160 const dimension_type y_num_rows = y.num_rows();
00161 const dimension_type old_num_columns = x.num_columns();
00162 const dimension_type y_num_columns = y.num_columns();
00163
00164 if (old_num_columns >= y_num_columns)
00165 add_zero_rows(y_num_rows, Row::Flags());
00166 else {
00167 add_zero_rows_and_columns(y_num_rows,
00168 y_num_columns - old_num_columns,
00169 Row::Flags());
00170
00171 swap_columns(old_num_columns - 1, num_columns() - 1);
00172 }
00173
00174
00175 const dimension_type x_mod_index = x.num_columns() - 1;
00176 const dimension_type y_mod_index = y_num_columns - 1;
00177 for (dimension_type i = y_num_rows; i-- > 0; ) {
00178 Row copy(y[i], x.row_size, x.row_capacity);
00179
00180 std::swap(copy[x_mod_index], copy[y_mod_index]);
00181 std::swap(copy, x[x_num_rows+i]);
00182 }
00183 PPL_ASSERT(OK());
00184 }
00185
00186 void
00187 PPL::Congruence_System::normalize_moduli() {
00188 dimension_type row = num_rows();
00189 if (row > 0) {
00190
00191 PPL_DIRTY_TEMP_COEFFICIENT(lcm);
00192
00193 while (true) {
00194 lcm = operator[](--row).modulus();
00195 if (lcm > 0)
00196 break;
00197 if (row == 0)
00198
00199 return;
00200 }
00201 while (row > 0) {
00202 const Coefficient& modulus = operator[](--row).modulus();
00203 if (modulus > 0)
00204 lcm_assign(lcm, lcm, modulus);
00205 }
00206
00207
00208 PPL_DIRTY_TEMP_COEFFICIENT(factor);
00209 dimension_type row_size = operator[](0).size();
00210 for (row = num_rows(); row-- > 0; ) {
00211 const Coefficient& modulus = operator[](row).modulus();
00212 if (modulus <= 0 || modulus == lcm)
00213 continue;
00214 exact_div_assign(factor, lcm, modulus);
00215 for (dimension_type col = row_size; col-- > 0; )
00216 operator[](row)[col] *= factor;
00217 operator[](row)[row_size-1] = lcm;
00218 }
00219 }
00220 PPL_ASSERT(OK());
00221 }
00222
00223 bool
00224 PPL::Congruence_System::is_equal_to(const Congruence_System& cgs) const {
00225 if (num_rows() != cgs.num_rows())
00226 return false;
00227
00228 for (dimension_type row = cgs.num_rows(); row-- > 0; )
00229 for (dimension_type col = cgs.num_columns(); col-- > 0; ) {
00230 if (operator[](row)[col] == cgs[row][col])
00231 continue;
00232 return false;
00233 }
00234 return true;
00235 }
00236
00237 bool
00238 PPL::Congruence_System::has_linear_equalities() const {
00239 const Congruence_System& cgs = *this;
00240 const dimension_type modulus_index = cgs.num_columns() - 1;
00241 for (dimension_type i = cgs.num_rows(); i-- > 0; )
00242 if (cgs[i][modulus_index] == 0)
00243 return true;
00244 return false;
00245 }
00246
00247 void
00248 PPL::Congruence_System::const_iterator::skip_forward() {
00249 const Matrix::const_iterator csp_end = csp->end();
00250 while (i != csp_end && (*this)->is_tautological())
00251 ++i;
00252 }
00253
00254 PPL::dimension_type
00255 PPL::Congruence_System::num_equalities() const {
00256 const Congruence_System& cgs = *this;
00257 dimension_type n = 0;
00258 for (dimension_type i = num_rows(); i-- > 0 ; )
00259 if (cgs[i].is_equality())
00260 ++n;
00261 return n;
00262 }
00263
00264 PPL::dimension_type
00265 PPL::Congruence_System::num_proper_congruences() const {
00266 const Congruence_System& cgs = *this;
00267 dimension_type n = 0;
00268 for (dimension_type i = num_rows(); i-- > 0 ; ) {
00269 const Congruence& cg = cgs[i];
00270 if (cg.is_proper_congruence())
00271 ++n;
00272 }
00273 return n;
00274 }
00275
00276 bool
00277 PPL::Congruence_System::
00278 satisfies_all_congruences(const Grid_Generator& g) const {
00279 PPL_ASSERT(g.space_dimension() <= space_dimension());
00280
00281 const Congruence_System& cgs = *this;
00282 PPL_DIRTY_TEMP_COEFFICIENT(sp);
00283 if (g.is_line())
00284 for (dimension_type i = cgs.num_rows(); i-- > 0; ) {
00285 const Congruence& cg = cgs[i];
00286 Scalar_Products::assign(sp, g, cg);
00287 if (sp != 0)
00288 return false;
00289 }
00290 else {
00291 const Coefficient& divisor = g.divisor();
00292 for (dimension_type i = cgs.num_rows(); i-- > 0; ) {
00293 const Congruence& cg = cgs[i];
00294 Scalar_Products::assign(sp, g, cg);
00295 if (cg.is_equality()) {
00296 if (sp != 0)
00297 return false;
00298 }
00299 else if (sp % (cg.modulus() * divisor) != 0)
00300 return false;
00301 }
00302 }
00303 return true;
00304 }
00305
00306 bool
00307 PPL::Congruence_System::has_a_free_dimension() const {
00308
00309
00310 dimension_type space_dim = space_dimension();
00311 std::vector<bool> free_dim(space_dim, true);
00312 dimension_type free_dims = space_dim;
00313 for (dimension_type row = num_rows(); row-- > 0; ) {
00314 const Congruence& cg = operator[](row);
00315 for (dimension_type dim = space_dim; dim-- > 0; )
00316 if (free_dim[dim] && cg[dim+1] != 0) {
00317 if (--free_dims == 0) {
00318
00319 #ifndef NDEBUG
00320 free_dim[dim] = false;
00321
00322
00323 dimension_type count = 0;
00324 for (dimension_type i = space_dim; i-- > 0; )
00325 count += free_dim[i];
00326 PPL_ASSERT(count == free_dims);
00327 #endif
00328 return true;
00329 }
00330 free_dim[dim] = false;
00331 }
00332 }
00333
00334 return false;
00335 }
00336
00337 void
00338 PPL::Congruence_System::
00339 affine_preimage(dimension_type v,
00340 const Linear_Expression& expr,
00341 Coefficient_traits::const_reference denominator) {
00342
00343
00344 PPL_ASSERT(v > 0 && v <= space_dimension());
00345 PPL_ASSERT(expr.space_dimension() <= space_dimension());
00346 PPL_ASSERT(denominator > 0);
00347
00348 const dimension_type num_columns = this->num_columns();
00349 const dimension_type num_rows = this->num_rows();
00350 const dimension_type expr_size = expr.size();
00351 const bool not_invertible = (v >= expr_size || expr[v] == 0);
00352 Congruence_System& x = *this;
00353
00354 if (denominator == 1)
00355
00356
00357 for (dimension_type i = num_rows; i-- > 0; ) {
00358 Congruence& row = x[i];
00359 Coefficient& row_v = row[v];
00360 if (row_v != 0) {
00361 for (dimension_type j = expr_size; j-- > 0; )
00362 if (j != v)
00363
00364 add_mul_assign(row[j], row_v, expr[j]);
00365 if (not_invertible)
00366 row_v = 0;
00367 else
00368 row_v *= expr[v];
00369 }
00370 }
00371 else
00372 for (dimension_type i = num_rows; i-- > 0; ) {
00373 Congruence& row = x[i];
00374 Coefficient& row_v = row[v];
00375 if (row_v != 0) {
00376 for (dimension_type j = num_columns; j-- > 0; )
00377 if (j != v) {
00378 Coefficient& row_j = row[j];
00379 row_j *= denominator;
00380 if (j < expr_size)
00381 add_mul_assign(row_j, row_v, expr[j]);
00382 }
00383 if (not_invertible)
00384 row_v = 0;
00385 else
00386 row_v *= expr[v];
00387 }
00388 }
00389 }
00390
00391 void
00392 PPL::Congruence_System::ascii_dump(std::ostream& s) const {
00393 const Congruence_System& x = *this;
00394 dimension_type x_num_rows = x.num_rows();
00395 dimension_type x_num_columns = x.num_columns();
00396 s << x_num_rows << " x " << x_num_columns
00397 << std::endl;
00398 if (x_num_rows && x_num_columns)
00399 for (dimension_type i = 0; i < x_num_rows; ++i)
00400 x[i].ascii_dump(s);
00401 }
00402
00403 PPL_OUTPUT_DEFINITIONS(Congruence_System)
00404
00405 bool
00406 PPL::Congruence_System::ascii_load(std::istream& s) {
00407 std::string str;
00408 dimension_type num_rows;
00409 dimension_type num_columns;
00410 if (!(s >> num_rows))
00411 return false;
00412 if (!(s >> str) || str != "x")
00413 return false;
00414 if (!(s >> num_columns))
00415 return false;
00416 resize_no_copy(num_rows, num_columns);
00417
00418 Congruence_System& x = *this;
00419 for (dimension_type i = 0; i < x.num_rows(); ++i)
00420 if (!x[i].ascii_load(s))
00421 return false;
00422
00423
00424 PPL_ASSERT(OK());
00425 return true;
00426 }
00427
00428 const PPL::Congruence_System* PPL::Congruence_System::zero_dim_empty_p = 0;
00429
00430 void
00431 PPL::Congruence_System::initialize() {
00432 PPL_ASSERT(zero_dim_empty_p == 0);
00433 zero_dim_empty_p
00434 = new Congruence_System(Congruence::zero_dim_false());
00435 }
00436
00437 void
00438 PPL::Congruence_System::finalize() {
00439 PPL_ASSERT(zero_dim_empty_p != 0);
00440 delete zero_dim_empty_p;
00441 zero_dim_empty_p = 0;
00442 }
00443
00444 bool
00445 PPL::Congruence_System::OK() const {
00446
00447 if (!Matrix::OK())
00448 return false;
00449
00450 if (num_rows()) {
00451 if (num_columns() < 2) {
00452 #ifndef NDEBUG
00453 std::cerr << "Congruence_System has rows and fewer than two columns."
00454 << std::endl;
00455 #endif
00456 return false;
00457 }
00458 }
00459
00460
00461 const Congruence_System& x = *this;
00462 for (dimension_type i = num_rows(); i-- > 0; ) {
00463 const Congruence& cg = x[i];
00464 if (!cg.OK())
00465 return false;
00466 }
00467
00468
00469 return true;
00470 }
00471
00473 std::ostream&
00474 PPL::IO_Operators::operator<<(std::ostream& s, const Congruence_System& cgs) {
00475 Congruence_System::const_iterator i = cgs.begin();
00476 const Congruence_System::const_iterator cgs_end = cgs.end();
00477 if (i == cgs_end)
00478 return s << "true";
00479 while (true) {
00480 Congruence cg = *i++;
00481 cg.strong_normalize();
00482 s << cg;
00483 if (i == cgs_end)
00484 return s;
00485 s << ", ";
00486 }
00487 }
00488
00490 bool
00491 PPL::operator==(const Congruence_System& x, const Congruence_System& y) {
00492 if (x.num_columns() == y.num_columns()) {
00493 dimension_type num_rows = x.num_rows();
00494 if (num_rows == y.num_rows()) {
00495 while (num_rows--) {
00496 if (x[num_rows] == y[num_rows])
00497 continue;
00498 return false;
00499 }
00500 return true;
00501 }
00502 }
00503 return false;
00504 }
00505
00506 void
00507 PPL::Congruence_System::add_unit_rows_and_columns(dimension_type dims) {
00508 PPL_ASSERT(num_columns() > 0);
00509 dimension_type col = num_columns() - 1;
00510 dimension_type old_num_rows = num_rows();
00511 add_zero_rows_and_columns(dims, dims,
00512 Linear_Row::Flags(NECESSARILY_CLOSED,
00513 Linear_Row::LINE_OR_EQUALITY));
00514
00515 swap_columns(col, col + dims);
00516
00517
00518 for (dimension_type row = old_num_rows; row-- > 0; )
00519 std::swap(operator[](row), operator[](row + dims));
00520
00521 col += dims - 1;
00522
00523 for (dimension_type row = dims; row-- > 0; )
00524 const_cast<Coefficient&>(operator[](row)[col - row]) = 1;
00525 }
00526
00527 void
00528 PPL::Congruence_System::concatenate(const Congruence_System& const_cgs) {
00529
00530 Congruence_System cgs = const_cgs;
00531
00532 dimension_type added_rows = cgs.num_rows();
00533 dimension_type added_columns = cgs.space_dimension();
00534
00535 dimension_type old_num_rows = num_rows();
00536 dimension_type old_modi = num_columns() - 1;
00537 dimension_type old_space_dim = space_dimension();
00538
00539 add_zero_rows_and_columns(added_rows, added_columns,
00540 Row::Flags());
00541
00542 dimension_type cgs_num_columns = cgs.num_columns();
00543 dimension_type modi = num_columns() - 1;
00544
00545
00546 for (dimension_type i = old_num_rows; i-- > 0; ) {
00547 Congruence& cg = operator[](i);
00548 std::swap(cg[old_modi], cg[modi]);
00549 }
00550
00551
00552
00553 for (dimension_type i = added_rows; i-- > 0; ) {
00554 Congruence& cg_old = cgs[i];
00555 Congruence& cg_new = operator[](old_num_rows + i);
00556
00557 std::swap(cg_new[0], cg_old[0]);
00558
00559 for (dimension_type j = cgs_num_columns; j-- > 1; )
00560 std::swap(cg_old[j], cg_new[old_space_dim + j]);
00561 }
00562 }
00563
00564 void
00565 PPL::Congruence_System
00566 ::remove_higher_space_dimensions(const dimension_type new_dimension) {
00567 dimension_type space_dim = space_dimension();
00568
00569 PPL_ASSERT(new_dimension <= space_dim);
00570
00571
00572
00573
00574 if (new_dimension == space_dim)
00575 return;
00576
00577
00578
00579 swap_columns(new_dimension + 1, space_dim + 1);
00580
00581 remove_trailing_columns(space_dim - new_dimension);
00582 PPL_ASSERT(OK());
00583 }