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 #include "assert.hh"
00026
00027 #include "Grid.defs.hh"
00028
00029 namespace Parma_Polyhedra_Library {
00030
00031 void
00032 Grid::reduce_line_with_line(Grid_Generator& row, Grid_Generator& pivot,
00033 dimension_type column) {
00034 const Coefficient& pivot_column = pivot[column];
00035 Coefficient& row_column = row[column];
00036 PPL_DIRTY_TEMP_COEFFICIENT(reduced_row_col);
00037
00038 gcd_assign(reduced_row_col, pivot_column, row_column);
00039
00040 PPL_DIRTY_TEMP_COEFFICIENT(reduced_pivot_col);
00041 exact_div_assign(reduced_pivot_col, pivot_column, reduced_row_col);
00042 exact_div_assign(reduced_row_col, row_column, reduced_row_col);
00043
00044
00045 row_column = 0;
00046
00047
00048 for (dimension_type col = pivot.size() - 2;
00049 col > column;
00050 --col) {
00051 Coefficient& row_col = row[col];
00052 row_col *= reduced_pivot_col;
00053 sub_mul_assign(row_col, reduced_row_col, pivot[col]);
00054 }
00055 }
00056
00057 void
00058 Grid::reduce_equality_with_equality(Congruence& row,
00059 const Congruence& pivot,
00060 const dimension_type column) {
00061
00062 PPL_ASSERT(row.modulus() == 0 && pivot.modulus() == 0);
00063
00064 const Coefficient& pivot_column = pivot[column];
00065 Coefficient& row_column = row[column];
00066 PPL_DIRTY_TEMP_COEFFICIENT(reduced_row_col);
00067
00068 gcd_assign(reduced_row_col, pivot_column, row_column);
00069
00070 PPL_DIRTY_TEMP_COEFFICIENT(reduced_pivot_col);
00071 exact_div_assign(reduced_pivot_col, pivot_column, reduced_row_col);
00072 exact_div_assign(reduced_row_col, row_column, reduced_row_col);
00073
00074
00075 row_column = 0;
00076 for (dimension_type col = column; col-- > 0; ) {
00077 Coefficient& row_col = row[col];
00078 row_col *= reduced_pivot_col;
00079 sub_mul_assign(row_col, reduced_row_col, pivot[col]);
00080 }
00081 }
00082
00083 template <typename R>
00084 void
00085 Grid::reduce_pc_with_pc(R& row, R& pivot,
00086 const dimension_type column,
00087 const dimension_type start,
00088 const dimension_type end) {
00089 Coefficient& pivot_column = pivot[column];
00090 Coefficient& row_column = row[column];
00091
00092 PPL_DIRTY_TEMP_COEFFICIENT(s);
00093 PPL_DIRTY_TEMP_COEFFICIENT(t);
00094 PPL_DIRTY_TEMP_COEFFICIENT(reduced_row_col);
00095
00096 gcdext_assign(reduced_row_col, s, t, pivot_column, row_column);
00097
00098
00099
00100 PPL_DIRTY_TEMP_COEFFICIENT(reduced_pivot_col);
00101 exact_div_assign(reduced_pivot_col, pivot_column, reduced_row_col);
00102 pivot_column = reduced_row_col ;
00103 exact_div_assign(reduced_row_col, row_column, reduced_row_col);
00104
00105
00106
00107
00108
00109
00110 PPL_ASSERT(pivot.size() > 0);
00111 PPL_ASSERT(row.size() > 0);
00112 row_column = 0;
00113 PPL_DIRTY_TEMP_COEFFICIENT(old_pivot_col);
00114 for (dimension_type col = start; col < end; ++col) {
00115 Coefficient& pivot_col = pivot[col];
00116 old_pivot_col = pivot_col;
00117 pivot_col *= s;
00118 Coefficient& row_col = row[col];
00119 add_mul_assign(pivot_col, t, row_col);
00120 row_col *= reduced_pivot_col;
00121 sub_mul_assign(row_col, reduced_row_col, old_pivot_col);
00122 }
00123 }
00124
00125 void
00126 Grid::reduce_parameter_with_line(Grid_Generator& row,
00127 const Grid_Generator& pivot,
00128 const dimension_type column,
00129 Grid_Generator_System& sys) {
00130
00131
00132
00133 const Coefficient& pivot_column = pivot[column];
00134 Coefficient& row_column = row[column];
00135
00136
00137 const dimension_type num_columns = sys.num_columns() - 1;
00138
00139
00140
00141 if (row_column == pivot_column) {
00142 for (dimension_type col = num_columns; col-- > 0; )
00143 row[col] -= pivot[col];
00144 return;
00145 }
00146
00147 PPL_DIRTY_TEMP_COEFFICIENT(reduced_row_col);
00148
00149 gcd_assign(reduced_row_col, pivot_column, row_column);
00150
00151 PPL_DIRTY_TEMP_COEFFICIENT(reduced_pivot_col);
00152 exact_div_assign(reduced_pivot_col, pivot_column, reduced_row_col);
00153 exact_div_assign(reduced_row_col, row_column, reduced_row_col);
00154
00155
00156
00157
00158
00159
00160 if (reduced_pivot_col < 0) {
00161 neg_assign(reduced_pivot_col);
00162 neg_assign(reduced_row_col);
00163 }
00164
00165
00166
00167
00168 for (dimension_type index = sys.num_rows(); index-- > 0; ) {
00169 Grid_Generator& gen = sys[index];
00170 if (gen.is_parameter_or_point())
00171 for (dimension_type col = num_columns; col-- > 0; )
00172 gen[col] *= reduced_pivot_col;
00173 }
00174
00175
00176 row_column = 0;
00177 for (dimension_type col = num_columns - 1; col > column; --col)
00178 sub_mul_assign(row[col], reduced_row_col, pivot[col]);
00179 }
00180
00181 void
00182 Grid::reduce_congruence_with_equality(Congruence& row,
00183 const Congruence& pivot,
00184 const dimension_type column,
00185 Congruence_System& sys) {
00186
00187
00188 PPL_ASSERT(row.modulus() > 0 && pivot.modulus() == 0);
00189
00190 const Coefficient& pivot_column = pivot[column];
00191 Coefficient& row_column = row[column];
00192
00193 dimension_type num_columns = sys.num_columns();
00194
00195
00196
00197 if (row_column == pivot_column) {
00198 for (dimension_type col = num_columns; col-- > 0; )
00199 row[col] -= pivot[col];
00200 return;
00201 }
00202
00203 PPL_DIRTY_TEMP_COEFFICIENT(reduced_row_col);
00204
00205 gcd_assign(reduced_row_col, pivot_column, row_column);
00206 PPL_DIRTY_TEMP_COEFFICIENT(reduced_pivot_col);
00207 exact_div_assign(reduced_pivot_col, pivot_column, reduced_row_col);
00208 exact_div_assign(reduced_row_col, row_column, reduced_row_col);
00209
00210
00211
00212 if (reduced_pivot_col < 0) {
00213 neg_assign(reduced_pivot_col);
00214 neg_assign(reduced_row_col);
00215 }
00216
00217
00218
00219 for (dimension_type index = sys.num_rows(); index-- > 0; ) {
00220 Congruence& cg = sys[index];
00221 if (cg.is_proper_congruence())
00222 for (dimension_type col = num_columns; col-- > 0; )
00223 cg[col] *= reduced_pivot_col;
00224 }
00225
00226
00227 --num_columns;
00228 row_column = 0;
00229
00230
00231 for (dimension_type col = column; col-- > 0; )
00232 sub_mul_assign(row[col], reduced_row_col, pivot[col]);
00233 }
00234
00235 #ifndef NDEBUG
00236 template <typename M, typename R>
00237 bool
00238 Grid::rows_are_zero(M& system, dimension_type first,
00239 dimension_type last, dimension_type row_size) {
00240 while (first <= last) {
00241 const R& row = system[first++];
00242 for (dimension_type col = 0; col < row_size; ++col)
00243 if (row[col] != 0)
00244 return false;
00245 }
00246 return true;
00247 }
00248 #endif
00249
00250 void
00251 Grid::simplify(Grid_Generator_System& sys, Dimension_Kinds& dim_kinds) {
00252 PPL_ASSERT(!sys.has_no_rows());
00253
00254 PPL_ASSERT(sys.num_columns() > 0);
00255
00256
00257
00258
00259
00260 const dimension_type num_columns = sys.num_columns() - 1;
00261
00262 if (dim_kinds.size() != num_columns)
00263 dim_kinds.resize(num_columns);
00264
00265 const dimension_type num_rows = sys.num_rows();
00266
00267
00268
00269
00270
00271 dimension_type pivot_index = 0;
00272 for (dimension_type dim = 0; dim < num_columns; ++dim) {
00273
00274 dimension_type row_index = pivot_index;
00275
00276
00277 while (row_index < num_rows && sys[row_index][dim] == 0)
00278 ++row_index;
00279
00280 if (row_index == num_rows)
00281
00282 dim_kinds[dim] = GEN_VIRTUAL;
00283 else {
00284 if (row_index != pivot_index)
00285 std::swap(sys[row_index], sys[pivot_index]);
00286 Grid_Generator& pivot = sys[pivot_index];
00287 bool pivot_is_line = pivot.is_line();
00288
00289
00290
00291 while (row_index < num_rows - 1) {
00292 ++row_index;
00293
00294 Grid_Generator& row = sys[row_index];
00295
00296 if (row[dim] == 0)
00297 continue;
00298
00299 if (row.is_line())
00300 if (pivot_is_line)
00301 reduce_line_with_line(row, pivot, dim);
00302 else {
00303 PPL_ASSERT(pivot.is_parameter_or_point());
00304 std::swap(row, pivot);
00305 pivot_is_line = true;
00306 reduce_parameter_with_line(row, pivot, dim, sys);
00307 }
00308 else {
00309 PPL_ASSERT(row.is_parameter_or_point());
00310 if (pivot_is_line)
00311 reduce_parameter_with_line(row, pivot, dim, sys);
00312 else {
00313 PPL_ASSERT(pivot.is_parameter_or_point());
00314 reduce_pc_with_pc(row, pivot, dim, dim + 1, num_columns);
00315 }
00316 }
00317 }
00318
00319 if (pivot_is_line)
00320 dim_kinds[dim] = LINE;
00321 else {
00322 PPL_ASSERT(pivot.is_parameter_or_point());
00323 dim_kinds[dim] = PARAMETER;
00324 }
00325
00326
00327
00328 if (pivot[dim] < 0)
00329 pivot.negate(dim, num_columns - 1);
00330
00331
00332 reduce_reduced<Grid_Generator_System, Grid_Generator>
00333 (sys, dim, pivot_index, dim, num_columns - 1, dim_kinds);
00334
00335 ++pivot_index;
00336 }
00337 }
00338
00339
00340 if (num_rows > pivot_index) {
00341 #ifndef NDEBUG
00342 const bool ret = rows_are_zero<Grid_Generator_System, Grid_Generator>
00343 (sys,
00344
00345 pivot_index,
00346
00347 sys.num_rows() - 1,
00348
00349 sys.num_columns() - 1);
00350 PPL_ASSERT(ret == true);
00351 #endif
00352 sys.erase_to_end(pivot_index);
00353 }
00354
00355 sys.unset_pending_rows();
00356
00357
00358
00359 const Coefficient& system_divisor = sys[0][0];
00360 for (dimension_type row = sys.num_rows() - 1,
00361 dim = sys.num_columns() - 2;
00362 dim > 0; --dim)
00363 switch (dim_kinds[dim]) {
00364 case PARAMETER:
00365 sys[row].set_divisor(system_divisor);
00366 case LINE:
00367 --row;
00368 case GEN_VIRTUAL:
00369 break;
00370 }
00371
00372 PPL_ASSERT(sys.OK());
00373 }
00374
00375 bool
00376 Grid::simplify(Congruence_System& sys, Dimension_Kinds& dim_kinds) {
00377 PPL_ASSERT(sys.num_columns() > 2);
00378
00379
00380
00381
00382
00383 sys.normalize_moduli();
00384
00385 const dimension_type num_columns = sys.num_columns() - 1 ;
00386
00387 if (dim_kinds.size() != num_columns)
00388 dim_kinds.resize(num_columns);
00389
00390 const dimension_type num_rows = sys.num_rows();
00391
00392
00393
00394
00395
00396 dimension_type pivot_index = 0;
00397 for (dimension_type dim = num_columns; dim-- > 0; ) {
00398
00399 dimension_type row_index = pivot_index;
00400
00401
00402 while (row_index < num_rows && sys[row_index][dim] == 0)
00403 ++row_index;
00404
00405 if (row_index == num_rows)
00406
00407
00408 dim_kinds[dim] = CON_VIRTUAL;
00409 else {
00410
00411 if (row_index != pivot_index)
00412 std::swap(sys[row_index], sys[pivot_index]);
00413 Congruence& pivot = sys[pivot_index];
00414 bool pivot_is_equality = pivot.is_equality();
00415
00416
00417
00418 while (row_index < num_rows - 1) {
00419 ++row_index;
00420
00421 Congruence& row = sys[row_index];
00422
00423 if (row[dim] == 0)
00424 continue;
00425
00426 if (row.is_equality())
00427 if (pivot_is_equality)
00428 reduce_equality_with_equality(row, pivot, dim);
00429 else {
00430 PPL_ASSERT(pivot.is_proper_congruence());
00431 std::swap(row, pivot);
00432 pivot_is_equality = true;
00433 reduce_congruence_with_equality(row, pivot, dim, sys);
00434 }
00435 else {
00436 PPL_ASSERT(row.is_proper_congruence());
00437 if (pivot_is_equality)
00438 reduce_congruence_with_equality(row, pivot, dim, sys);
00439 else {
00440 PPL_ASSERT(pivot.is_proper_congruence());
00441 reduce_pc_with_pc(row, pivot, dim, 0, dim);
00442 }
00443 }
00444 }
00445
00446 if (pivot_is_equality)
00447 dim_kinds[dim] = EQUALITY;
00448 else {
00449 PPL_ASSERT(pivot.is_proper_congruence());
00450 dim_kinds[dim] = PROPER_CONGRUENCE;
00451 }
00452
00453
00454
00455 if (pivot[dim] < 0)
00456 pivot.negate(0, dim);
00457
00458 reduce_reduced<Congruence_System, Congruence>
00459 (sys, dim, pivot_index, 0, dim, dim_kinds, false);
00460
00461 ++pivot_index;
00462 }
00463 }
00464
00465
00466 dimension_type& reduced_num_rows = pivot_index;
00467
00468 if (reduced_num_rows > 0) {
00469
00470
00471 Congruence& last_row = sys[reduced_num_rows - 1];
00472 if (dim_kinds[0] == PROPER_CONGRUENCE) {
00473 if (last_row.inhomogeneous_term() % last_row.modulus() != 0) {
00474
00475 last_row.set_is_equality();
00476 dim_kinds[0] = EQUALITY;
00477 goto return_empty;
00478 }
00479 }
00480 else if (dim_kinds[0] == EQUALITY) {
00481
00482
00483
00484 return_empty:
00485 last_row[0] = 1;
00486 dim_kinds.resize(1);
00487 std::swap(sys.rows[0], sys.rows.back());
00488 sys.erase_to_end(1);
00489
00490 PPL_ASSERT(sys.OK());
00491 return true;
00492 }
00493 }
00494 else {
00495
00496
00497
00498
00499 dim_kinds[0] = PROPER_CONGRUENCE;
00500 if (num_rows == 0) {
00501 sys.add_zero_rows(1,
00502 Linear_Row::Flags(NECESSARILY_CLOSED,
00503 Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
00504 Congruence& cg = sys[0];
00505 cg[num_columns] = 1;
00506 cg[0] = 1;
00507
00508 PPL_ASSERT(sys.OK());
00509 return false;
00510 }
00511 sys[0][num_columns] = 1;
00512
00513
00514 reduced_num_rows = 1;
00515 }
00516
00517
00518 if (num_rows > 1 && num_rows > reduced_num_rows) {
00519 #ifndef NDEBUG
00520 const bool ret = rows_are_zero<Congruence_System, Congruence>
00521 (sys,
00522
00523 reduced_num_rows,
00524
00525 num_rows - 1,
00526
00527 num_columns);
00528 PPL_ASSERT(ret == true);
00529 #endif
00530 sys.erase_to_end(reduced_num_rows);
00531 }
00532
00533 PPL_ASSERT(sys.num_rows() == reduced_num_rows);
00534
00535
00536 const dimension_type mod_index = num_columns;
00537 if (dim_kinds[0] == CON_VIRTUAL) {
00538
00539 dim_kinds[0] = PROPER_CONGRUENCE;
00540 sys.add_zero_rows(1,
00541 Linear_Row::Flags(NECESSARILY_CLOSED,
00542 Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
00543 Congruence& new_last_row = sys[reduced_num_rows];
00544 new_last_row[mod_index] = 1;
00545
00546 dimension_type row_index = reduced_num_rows;
00547 while (row_index-- > 0) {
00548 Congruence& row = sys[row_index];
00549 if (row[mod_index] > 0) {
00550 new_last_row[mod_index] = row[mod_index];
00551 break;
00552 }
00553 }
00554 new_last_row[0] = new_last_row[mod_index];
00555
00556
00557 ++reduced_num_rows;
00558 }
00559 else {
00560 Congruence& last_row = sys[reduced_num_rows - 1];
00561 last_row[0] = last_row[mod_index];
00562 }
00563
00564
00565
00566 reduce_reduced<Congruence_System, Congruence>
00567 (sys, 0, reduced_num_rows - 1, 0, 0, dim_kinds, false);
00568
00569 PPL_ASSERT(sys.OK());
00570 return false;
00571 }
00572
00573 }