|
PPL
0.12.1
|
00001 /* Linear_System class implementation (non-inline functions). 00002 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it> 00003 Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com) 00004 00005 This file is part of the Parma Polyhedra Library (PPL). 00006 00007 The PPL is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU General Public License as published by the 00009 Free Software Foundation; either version 3 of the License, or (at your 00010 option) any later version. 00011 00012 The PPL is distributed in the hope that it will be useful, but WITHOUT 00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00015 for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software Foundation, 00019 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. 00020 00021 For the most up-to-date information see the Parma Polyhedra Library 00022 site: http://bugseng.com/products/ppl/ . */ 00023 00024 #include "ppl-config.h" 00025 #include "Linear_System.defs.hh" 00026 #include "Coefficient.defs.hh" 00027 #include "Dense_Row.defs.hh" 00028 #include "Bit_Matrix.defs.hh" 00029 #include "Scalar_Products.defs.hh" 00030 #include "swapping_sort.templates.hh" 00031 #include <algorithm> 00032 #include <iostream> 00033 #include <string> 00034 #include <deque> 00035 00036 namespace PPL = Parma_Polyhedra_Library; 00037 00038 PPL::dimension_type 00039 PPL::Linear_System::num_lines_or_equalities() const { 00040 PPL_ASSERT(num_pending_rows() == 0); 00041 const Linear_System& x = *this; 00042 dimension_type n = 0; 00043 for (dimension_type i = num_rows(); i-- > 0; ) 00044 if (x[i].is_line_or_equality()) 00045 ++n; 00046 return n; 00047 } 00048 00049 void 00050 PPL::Linear_System::merge_rows_assign(const Linear_System& y) { 00051 PPL_ASSERT(row_size >= y.row_size); 00052 // Both systems have to be sorted and have no pending rows. 00053 PPL_ASSERT(check_sorted() && y.check_sorted()); 00054 PPL_ASSERT(num_pending_rows() == 0 && y.num_pending_rows() == 0); 00055 00056 using std::swap; 00057 Linear_System& x = *this; 00058 00059 // A temporary vector of rows... 00060 std::vector<Dense_Row> tmp; 00061 // ... with enough capacity not to require any reallocations. 00062 tmp.reserve(compute_capacity(x.num_rows() + y.num_rows(), max_num_rows())); 00063 00064 dimension_type xi = 0; 00065 dimension_type x_num_rows = x.num_rows(); 00066 dimension_type yi = 0; 00067 dimension_type y_num_rows = y.num_rows(); 00068 00069 while (xi < x_num_rows && yi < y_num_rows) { 00070 const int comp = compare(x[xi], y[yi]); 00071 if (comp <= 0) { 00072 // Elements that can be taken from `x' are actually _stolen_ from `x' 00073 swap(x[xi++], *tmp.insert(tmp.end(), Linear_Row())); 00074 if (comp == 0) 00075 // A duplicate element. 00076 ++yi; 00077 } 00078 else { 00079 // (comp > 0) 00080 Linear_Row copy(y[yi++], row_size, row_capacity); 00081 swap(copy, *tmp.insert(tmp.end(), Linear_Row())); 00082 } 00083 } 00084 // Insert what is left. 00085 if (xi < x_num_rows) { 00086 while (xi < x_num_rows) 00087 swap(x[xi++], *tmp.insert(tmp.end(), Linear_Row())); 00088 } 00089 else { 00090 while (yi < y_num_rows) { 00091 Linear_Row copy(y[yi++], row_size, row_capacity); 00092 swap(copy, *tmp.insert(tmp.end(), Linear_Row())); 00093 } 00094 } 00095 00096 // We get the result vector and let the old one be destroyed. 00097 swap(tmp, rows); 00098 // There are no pending rows. 00099 unset_pending_rows(); 00100 PPL_ASSERT(check_sorted()); 00101 } 00102 00103 void 00104 PPL::Linear_System::set_rows_topology() { 00105 Linear_System& x = *this; 00106 if (is_necessarily_closed()) 00107 for (dimension_type i = num_rows(); i-- > 0; ) 00108 x[i].set_necessarily_closed(); 00109 else 00110 for (dimension_type i = num_rows(); i-- > 0; ) 00111 x[i].set_not_necessarily_closed(); 00112 } 00113 00114 void 00115 PPL::Linear_System::ascii_dump(std::ostream& s) const { 00116 // Prints the topology, the number of rows, the number of columns 00117 // and the sorted flag. The specialized methods provided by 00118 // Constraint_System and Generator_System take care of properly 00119 // printing the contents of the system. 00120 const Linear_System& x = *this; 00121 dimension_type x_num_rows = x.num_rows(); 00122 dimension_type x_num_columns = x.num_columns(); 00123 s << "topology " << (is_necessarily_closed() 00124 ? "NECESSARILY_CLOSED" 00125 : "NOT_NECESSARILY_CLOSED") 00126 << "\n" 00127 << x_num_rows << " x " << x_num_columns 00128 << (x.sorted ? "(sorted)" : "(not_sorted)") 00129 << "\n" 00130 << "index_first_pending " << x.first_pending_row() 00131 << "\n"; 00132 for (dimension_type i = 0; i < x_num_rows; ++i) 00133 x[i].ascii_dump(s); 00134 } 00135 00136 PPL_OUTPUT_DEFINITIONS_ASCII_ONLY(Linear_System) 00137 00138 bool 00139 PPL::Linear_System::ascii_load(std::istream& s) { 00140 std::string str; 00141 if (!(s >> str) || str != "topology") 00142 return false; 00143 if (!(s >> str)) 00144 return false; 00145 if (str == "NECESSARILY_CLOSED") 00146 set_necessarily_closed(); 00147 else { 00148 if (str != "NOT_NECESSARILY_CLOSED") 00149 return false; 00150 set_not_necessarily_closed(); 00151 } 00152 00153 dimension_type nrows; 00154 dimension_type ncols; 00155 if (!(s >> nrows)) 00156 return false; 00157 if (!(s >> str) || str != "x") 00158 return false; 00159 if (!(s >> ncols)) 00160 return false; 00161 resize_no_copy(nrows, ncols); 00162 00163 if (!(s >> str) || (str != "(sorted)" && str != "(not_sorted)")) 00164 return false; 00165 set_sorted(str == "(sorted)"); 00166 dimension_type index; 00167 if (!(s >> str) || str != "index_first_pending") 00168 return false; 00169 if (!(s >> index)) 00170 return false; 00171 set_index_first_pending_row(index); 00172 00173 Linear_System& x = *this; 00174 for (dimension_type row = 0; row < nrows; ++row) 00175 if (!x[row].ascii_load(s)) 00176 return false; 00177 00178 // Check invariants. 00179 PPL_ASSERT(OK(true)); 00180 return true; 00181 } 00182 00183 void 00184 PPL::Linear_System::insert(const Linear_Row& r) { 00185 // The added row must be strongly normalized and have the same 00186 // topology of the system. 00187 PPL_ASSERT(r.check_strong_normalized()); 00188 PPL_ASSERT(topology() == r.topology()); 00189 // This method is only used when the system has no pending rows. 00190 PPL_ASSERT(num_pending_rows() == 0); 00191 00192 using std::swap; 00193 const dimension_type old_num_rows = num_rows(); 00194 const dimension_type old_num_columns = num_columns(); 00195 const dimension_type r_size = r.size(); 00196 00197 // Resize the system, if necessary. 00198 if (r_size > old_num_columns) { 00199 add_zero_columns(r_size - old_num_columns); 00200 if (!is_necessarily_closed() && old_num_rows != 0) 00201 // Move the epsilon coefficients to the last column 00202 // (note: sorting is preserved). 00203 swap_columns(old_num_columns - 1, r_size - 1); 00204 add_row(r); 00205 } 00206 else if (r_size < old_num_columns) { 00207 // Create a resized copy of the row. 00208 Linear_Row tmp_row(r, old_num_columns, row_capacity); 00209 // If needed, move the epsilon coefficient to the last position. 00210 if (!is_necessarily_closed()) 00211 swap(tmp_row[r_size - 1], tmp_row[old_num_columns - 1]); 00212 add_row(tmp_row); 00213 } 00214 else 00215 // Here r_size == old_num_columns. 00216 add_row(r); 00217 00218 // The added row was not a pending row. 00219 PPL_ASSERT(num_pending_rows() == 0); 00220 // Do not check for strong normalization, 00221 // because no modification of rows has occurred. 00222 PPL_ASSERT(OK(false)); 00223 } 00224 00225 void 00226 PPL::Linear_System::insert_pending(const Linear_Row& r) { 00227 // The added row must be strongly normalized and have the same 00228 // topology of the system. 00229 PPL_ASSERT(r.check_strong_normalized()); 00230 PPL_ASSERT(topology() == r.topology()); 00231 00232 const dimension_type old_num_rows = num_rows(); 00233 const dimension_type old_num_columns = num_columns(); 00234 const dimension_type r_size = r.size(); 00235 00236 // Resize the system, if necessary. 00237 if (r_size > old_num_columns) { 00238 add_zero_columns(r_size - old_num_columns); 00239 if (!is_necessarily_closed() && old_num_rows != 0) 00240 // Move the epsilon coefficients to the last column 00241 // (note: sorting is preserved). 00242 swap_columns(old_num_columns - 1, r_size - 1); 00243 add_pending_row(r); 00244 } 00245 else if (r_size < old_num_columns) 00246 if (is_necessarily_closed() || old_num_rows == 0) 00247 add_pending_row(Linear_Row(r, old_num_columns, row_capacity)); 00248 else { 00249 // Create a resized copy of the row (and move the epsilon 00250 // coefficient to its last position). 00251 using std::swap; 00252 Linear_Row tmp_row(r, old_num_columns, row_capacity); 00253 swap(tmp_row[r_size - 1], tmp_row[old_num_columns - 1]); 00254 add_pending_row(tmp_row); 00255 } 00256 else 00257 // Here r_size == old_num_columns. 00258 add_pending_row(r); 00259 00260 // The added row was a pending row. 00261 PPL_ASSERT(num_pending_rows() > 0); 00262 // Do not check for strong normalization, 00263 // because no modification of rows has occurred. 00264 PPL_ASSERT(OK(false)); 00265 } 00266 00267 void 00268 PPL::Linear_System::add_pending_rows(const Linear_System& y) { 00269 Linear_System& x = *this; 00270 PPL_ASSERT(x.row_size == y.row_size); 00271 00272 const dimension_type x_n_rows = x.num_rows(); 00273 const dimension_type y_n_rows = y.num_rows(); 00274 // Grow to the required size without changing sortedness. 00275 const bool was_sorted = sorted; 00276 add_zero_rows(y_n_rows, Linear_Row::Flags(row_topology)); 00277 sorted = was_sorted; 00278 00279 // Copy the rows of `y', forcing size and capacity. 00280 for (dimension_type i = y_n_rows; i-- > 0; ) { 00281 Dense_Row copy(y[i], x.row_size, x.row_capacity); 00282 using std::swap; 00283 swap(copy, x[x_n_rows+i]); 00284 } 00285 // Do not check for strong normalization, 00286 // because no modification of rows has occurred. 00287 PPL_ASSERT(OK(false)); 00288 } 00289 00290 void 00291 PPL::Linear_System::add_rows(const Linear_System& y) { 00292 PPL_ASSERT(num_pending_rows() == 0); 00293 00294 // Adding no rows is a no-op. 00295 if (y.has_no_rows()) 00296 return; 00297 00298 // Check if sortedness is preserved. 00299 if (is_sorted()) { 00300 if (!y.is_sorted() || y.num_pending_rows() > 0) 00301 set_sorted(false); 00302 else { 00303 // `y' is sorted and has no pending rows. 00304 const dimension_type n_rows = num_rows(); 00305 if (n_rows > 0) 00306 set_sorted(compare((*this)[n_rows-1], y[0]) <= 0); 00307 } 00308 } 00309 00310 // Add the rows of `y' as if they were pending. 00311 add_pending_rows(y); 00312 // There are no pending_rows. 00313 unset_pending_rows(); 00314 00315 // Do not check for strong normalization, 00316 // because no modification of rows has occurred. 00317 PPL_ASSERT(OK(false)); 00318 } 00319 00320 void 00321 PPL::Linear_System::sort_rows() { 00322 const dimension_type num_pending = num_pending_rows(); 00323 // We sort the non-pending rows only. 00324 sort_rows(0, first_pending_row()); 00325 set_index_first_pending_row(num_rows() - num_pending); 00326 sorted = true; 00327 // Do not check for strong normalization, 00328 // because no modification of rows has occurred. 00329 PPL_ASSERT(OK(false)); 00330 } 00331 00332 void 00333 PPL::Linear_System::sort_rows(const dimension_type first_row, 00334 const dimension_type last_row) { 00335 PPL_ASSERT(first_row <= last_row && last_row <= num_rows()); 00336 // We cannot mix pending and non-pending rows. 00337 PPL_ASSERT(first_row >= first_pending_row() || last_row <= first_pending_row()); 00338 00339 // First sort without removing duplicates. 00340 std::vector<Dense_Row>::iterator first = nth_iter(rows, first_row); 00341 std::vector<Dense_Row>::iterator last = nth_iter(rows, last_row); 00342 Implementation::swapping_sort(first, last, Row_Less_Than()); 00343 // Second, move duplicates to the end. 00344 std::vector<Dense_Row>::iterator new_last 00345 = Implementation::swapping_unique(first, last); 00346 // Finally, remove duplicates. 00347 rows.erase(new_last, last); 00348 // NOTE: we cannot check all invariants of the system here, 00349 // because the caller still has to update `index_first_pending'. 00350 } 00351 00352 void 00353 PPL::Linear_System::add_row(const Linear_Row& r) { 00354 // The added row must be strongly normalized and have the same 00355 // number of elements as the existing rows of the system. 00356 PPL_ASSERT(r.check_strong_normalized()); 00357 PPL_ASSERT(r.size() == row_size); 00358 // This method is only used when the system has no pending rows. 00359 PPL_ASSERT(num_pending_rows() == 0); 00360 00361 const bool was_sorted = is_sorted(); 00362 00363 Dense_Matrix::add_row(r); 00364 00365 // We update `index_first_pending', because it must be equal to 00366 // `num_rows()'. 00367 set_index_first_pending_row(num_rows()); 00368 00369 if (was_sorted) { 00370 const dimension_type nrows = num_rows(); 00371 // The added row may have caused the system to be not sorted anymore. 00372 if (nrows > 1) { 00373 // If the system is not empty and the inserted row is the 00374 // greatest one, the system is set to be sorted. 00375 // If it is not the greatest one then the system is no longer sorted. 00376 Linear_System& x = *this; 00377 set_sorted(compare(x[nrows-2], x[nrows-1]) <= 0); 00378 } 00379 else 00380 // A system having only one row is sorted. 00381 set_sorted(true); 00382 } 00383 // The added row was not a pending row. 00384 PPL_ASSERT(num_pending_rows() == 0); 00385 // Do not check for strong normalization, because no modification of 00386 // rows has occurred. 00387 PPL_ASSERT(OK(false)); 00388 } 00389 00390 void 00391 PPL::Linear_System::add_pending_row(const Linear_Row& r) { 00392 // The added row must be strongly normalized and have the same 00393 // number of elements of the existing rows of the system. 00394 PPL_ASSERT(r.check_strong_normalized()); 00395 PPL_ASSERT(r.size() == row_size); 00396 00397 using std::swap; 00398 00399 const dimension_type new_rows_size = rows.size() + 1; 00400 if (rows.capacity() < new_rows_size) { 00401 // Reallocation will take place. 00402 std::vector<Dense_Row> new_rows; 00403 new_rows.reserve(compute_capacity(new_rows_size, max_num_rows())); 00404 new_rows.insert(new_rows.end(), new_rows_size, Dense_Row()); 00405 // Put the new row in place. 00406 Dense_Row new_row(r, row_capacity); 00407 dimension_type i = new_rows_size-1; 00408 swap(new_rows[i], new_row); 00409 // Steal the old rows. 00410 while (i-- > 0) 00411 new_rows[i].m_swap(rows[i]); 00412 // Put the new rows into place. 00413 swap(rows, new_rows); 00414 } 00415 else { 00416 // Reallocation will NOT take place. 00417 // Inserts a new empty row at the end, then substitutes it with a 00418 // copy of the given row. 00419 Dense_Row tmp(r, row_capacity); 00420 swap(*rows.insert(rows.end(), Dense_Row()), tmp); 00421 } 00422 00423 // The added row was a pending row. 00424 PPL_ASSERT(num_pending_rows() > 0); 00425 // Do not check for strong normalization, because no modification of 00426 // rows has occurred. 00427 PPL_ASSERT(OK(false)); 00428 } 00429 00430 void 00431 PPL::Linear_System::add_pending_row(const Linear_Row::Flags flags) { 00432 using std::swap; 00433 const dimension_type new_rows_size = rows.size() + 1; 00434 if (rows.capacity() < new_rows_size) { 00435 // Reallocation will take place. 00436 std::vector<Dense_Row> new_rows; 00437 new_rows.reserve(compute_capacity(new_rows_size, max_num_rows())); 00438 new_rows.insert(new_rows.end(), new_rows_size, Dense_Row()); 00439 // Put the new row in place. 00440 Linear_Row new_row(row_size, row_capacity, flags); 00441 dimension_type i = new_rows_size-1; 00442 swap(new_rows[i], new_row); 00443 // Steal the old rows. 00444 while (i-- > 0) 00445 new_rows[i].m_swap(rows[i]); 00446 // Put the new vector into place. 00447 swap(rows, new_rows); 00448 } 00449 else { 00450 // Reallocation will NOT take place. 00451 // Insert a new empty row at the end, then construct it assigning 00452 // it the given type. 00453 Dense_Row& new_row = *rows.insert(rows.end(), Dense_Row(flags)); 00454 static_cast<Linear_Row&>(new_row).resize(row_size, row_capacity); 00455 } 00456 00457 // The added row was a pending row. 00458 PPL_ASSERT(num_pending_rows() > 0); 00459 } 00460 00461 void 00462 PPL::Linear_System::normalize() { 00463 Linear_System& x = *this; 00464 const dimension_type nrows = x.num_rows(); 00465 // We normalize also the pending rows. 00466 for (dimension_type i = nrows; i-- > 0; ) 00467 x[i].normalize(); 00468 set_sorted(nrows <= 1); 00469 } 00470 00471 void 00472 PPL::Linear_System::strong_normalize() { 00473 Linear_System& x = *this; 00474 const dimension_type nrows = x.num_rows(); 00475 // We strongly normalize also the pending rows. 00476 for (dimension_type i = nrows; i-- > 0; ) 00477 x[i].strong_normalize(); 00478 set_sorted(nrows <= 1); 00479 } 00480 00481 void 00482 PPL::Linear_System::sign_normalize() { 00483 Linear_System& x = *this; 00484 const dimension_type nrows = x.num_rows(); 00485 // We sign-normalize also the pending rows. 00486 for (dimension_type i = num_rows(); i-- > 0; ) 00487 x[i].sign_normalize(); 00488 set_sorted(nrows <= 1); 00489 } 00490 00492 bool 00493 PPL::operator==(const Linear_System& x, const Linear_System& y) { 00494 if (x.num_columns() != y.num_columns()) 00495 return false; 00496 const dimension_type x_num_rows = x.num_rows(); 00497 const dimension_type y_num_rows = y.num_rows(); 00498 if (x_num_rows != y_num_rows) 00499 return false; 00500 if (x.first_pending_row() != y.first_pending_row()) 00501 return false; 00502 // Notice that calling operator==(const Dense_Matrix&, const Dense_Matrix&) 00503 // would be wrong here, as equality of the type fields would 00504 // not be checked. 00505 for (dimension_type i = x_num_rows; i-- > 0; ) 00506 if (x[i] != y[i]) 00507 return false; 00508 return true; 00509 } 00510 00511 void 00512 PPL::Linear_System::sort_and_remove_with_sat(Bit_Matrix& sat) { 00513 Linear_System& sys = *this; 00514 // We can only sort the non-pending part of the system. 00515 PPL_ASSERT(sys.first_pending_row() == sat.num_rows()); 00516 if (sys.first_pending_row() <= 1) { 00517 sys.set_sorted(true); 00518 return; 00519 } 00520 00521 // First, sort `sys' (keeping `sat' consistent) without removing duplicates. 00522 With_Bit_Matrix_iterator first(sys.rows.begin(), sat.rows.begin()); 00523 typedef With_Bit_Matrix_iterator::difference_type diff_type; 00524 With_Bit_Matrix_iterator last 00525 = first + static_cast<diff_type>(sat.num_rows()); 00526 Implementation::swapping_sort(first, last, Row_Less_Than()); 00527 // Second, move duplicates in `sys' to the end (keeping `sat' consistent). 00528 With_Bit_Matrix_iterator new_last 00529 = Implementation::swapping_unique(first, last); 00530 00531 const diff_type dist = last - new_last; 00532 PPL_ASSERT(dist >= 0); 00533 const dimension_type num_duplicates = static_cast<dimension_type>(dist); 00534 const dimension_type new_first_pending_row 00535 = sys.first_pending_row() - num_duplicates; 00536 00537 if (sys.num_pending_rows() > 0) { 00538 // In this case, we must put the duplicates after the pending rows. 00539 using std::swap; 00540 const dimension_type n_rows = sys.num_rows() - 1; 00541 for (dimension_type i = 0; i < num_duplicates; ++i) 00542 swap(sys[new_first_pending_row + i], sys[n_rows - i]); 00543 } 00544 // Erasing the duplicated rows... 00545 sys.remove_trailing_rows(num_duplicates); 00546 sys.set_index_first_pending_row(new_first_pending_row); 00547 // ... and the corresponding rows of the saturation matrix. 00548 sat.remove_trailing_rows(num_duplicates); 00549 PPL_ASSERT(sys.check_sorted()); 00550 // Now the system is sorted. 00551 sys.set_sorted(true); 00552 } 00553 00554 PPL::dimension_type 00555 PPL::Linear_System::gauss(const dimension_type n_lines_or_equalities) { 00556 Linear_System& x = *this; 00557 // This method is only applied to a well-formed linear system 00558 // having no pending rows and exactly `n_lines_or_equalities' 00559 // lines or equalities, all of which occur before the rays or points 00560 // or inequalities. 00561 PPL_ASSERT(x.OK(true)); 00562 PPL_ASSERT(x.num_pending_rows() == 0); 00563 PPL_ASSERT(n_lines_or_equalities == x.num_lines_or_equalities()); 00564 #ifndef NDEBUG 00565 for (dimension_type i = n_lines_or_equalities; i-- > 0; ) 00566 PPL_ASSERT(x[i].is_line_or_equality()); 00567 #endif 00568 00569 dimension_type rank = 0; 00570 // Will keep track of the variations on the system of equalities. 00571 bool changed = false; 00572 for (dimension_type j = x.num_columns(); j-- > 0; ) 00573 for (dimension_type i = rank; i < n_lines_or_equalities; ++i) { 00574 // Search for the first row having a non-zero coefficient 00575 // (the pivot) in the j-th column. 00576 if (x[i][j] == 0) 00577 continue; 00578 // Pivot found: if needed, swap rows so that this one becomes 00579 // the rank-th row in the linear system. 00580 if (i > rank) { 00581 using std::swap; 00582 swap(x[i], x[rank]); 00583 // After swapping the system is no longer sorted. 00584 changed = true; 00585 } 00586 // Combine the row containing the pivot with all the lines or 00587 // equalities following it, so that all the elements on the j-th 00588 // column in these rows become 0. 00589 for (dimension_type k = i + 1; k < n_lines_or_equalities; ++k) 00590 if (x[k][j] != 0) { 00591 x[k].linear_combine(x[rank], j); 00592 changed = true; 00593 } 00594 // Already dealt with the rank-th row. 00595 ++rank; 00596 // Consider another column index `j'. 00597 break; 00598 } 00599 if (changed) 00600 x.set_sorted(false); 00601 // A well-formed system is returned. 00602 PPL_ASSERT(x.OK(true)); 00603 return rank; 00604 } 00605 00606 void 00607 PPL::Linear_System 00608 ::back_substitute(const dimension_type n_lines_or_equalities) { 00609 Linear_System& x = *this; 00610 // This method is only applied to a well-formed system 00611 // having no pending rows and exactly `n_lines_or_equalities' 00612 // lines or equalities, all of which occur before the first ray 00613 // or point or inequality. 00614 PPL_ASSERT(x.OK(true)); 00615 PPL_ASSERT(x.num_columns() >= 1); 00616 PPL_ASSERT(x.num_pending_rows() == 0); 00617 PPL_ASSERT(n_lines_or_equalities <= x.num_lines_or_equalities()); 00618 #ifndef NDEBUG 00619 for (dimension_type i = n_lines_or_equalities; i-- > 0; ) 00620 PPL_ASSERT(x[i].is_line_or_equality()); 00621 #endif 00622 00623 const dimension_type nrows = x.num_rows(); 00624 const dimension_type ncols = x.num_columns(); 00625 // Trying to keep sortedness. 00626 bool still_sorted = x.is_sorted(); 00627 // This deque of Booleans will be used to flag those rows that, 00628 // before exiting, need to be re-checked for sortedness. 00629 std::deque<bool> check_for_sortedness; 00630 if (still_sorted) 00631 check_for_sortedness.insert(check_for_sortedness.end(), nrows, false); 00632 00633 for (dimension_type k = n_lines_or_equalities; k-- > 0; ) { 00634 // For each line or equality, starting from the last one, 00635 // looks for the last non-zero element. 00636 // `j' will be the index of such a element. 00637 Linear_Row& x_k = x[k]; 00638 dimension_type j = ncols - 1; 00639 while (j != 0 && x_k[j] == 0) 00640 --j; 00641 00642 // Go through the equalities above `x_k'. 00643 for (dimension_type i = k; i-- > 0; ) { 00644 Linear_Row& x_i = x[i]; 00645 if (x_i[j] != 0) { 00646 // Combine linearly `x_i' with `x_k' 00647 // so that `x_i[j]' becomes zero. 00648 x_i.linear_combine(x_k, j); 00649 if (still_sorted) { 00650 // Trying to keep sortedness: remember which rows 00651 // have to be re-checked for sortedness at the end. 00652 if (i > 0) 00653 check_for_sortedness[i-1] = true; 00654 check_for_sortedness[i] = true; 00655 } 00656 } 00657 } 00658 00659 // Due to strong normalization during previous iterations, 00660 // the pivot coefficient `x_k[j]' may now be negative. 00661 // Since an inequality (or ray or point) cannot be multiplied 00662 // by a negative factor, the coefficient of the pivot must be 00663 // forced to be positive. 00664 const bool have_to_negate = (x_k[j] < 0); 00665 if (have_to_negate) 00666 for (dimension_type h = ncols; h-- > 0; ) 00667 PPL::neg_assign(x_k[h]); 00668 // Note: we do not mark index `k' in `check_for_sortedness', 00669 // because we will later negate back the row. 00670 00671 // Go through all the other rows of the system. 00672 for (dimension_type i = n_lines_or_equalities; i < nrows; ++i) { 00673 Linear_Row& x_i = x[i]; 00674 if (x_i[j] != 0) { 00675 // Combine linearly the `x_i' with `x_k' 00676 // so that `x_i[j]' becomes zero. 00677 x_i.linear_combine(x_k, j); 00678 if (still_sorted) { 00679 // Trying to keep sortedness: remember which rows 00680 // have to be re-checked for sortedness at the end. 00681 if (i > n_lines_or_equalities) 00682 check_for_sortedness[i-1] = true; 00683 check_for_sortedness[i] = true; 00684 } 00685 } 00686 } 00687 if (have_to_negate) 00688 // Negate `x_k' to restore strong-normalization. 00689 for (dimension_type h = ncols; h-- > 0; ) 00690 PPL::neg_assign(x_k[h]); 00691 } 00692 00693 // Trying to keep sortedness. 00694 for (dimension_type i = 0; still_sorted && i+1 < nrows; ++i) 00695 if (check_for_sortedness[i]) 00696 // Have to check sortedness of `x[i]' with respect to `x[i+1]'. 00697 still_sorted = (compare(x[i], x[i+1]) <= 0); 00698 // Set the sortedness flag. 00699 x.set_sorted(still_sorted); 00700 00701 // A well-formed system is returned. 00702 PPL_ASSERT(x.OK(true)); 00703 } 00704 00705 void 00706 PPL::Linear_System::simplify() { 00707 Linear_System& x = *this; 00708 // This method is only applied to a well-formed system 00709 // having no pending rows. 00710 PPL_ASSERT(x.OK(true)); 00711 PPL_ASSERT(x.num_pending_rows() == 0); 00712 00713 // Partially sort the linear system so that all lines/equalities come first. 00714 const dimension_type old_nrows = x.num_rows(); 00715 dimension_type nrows = old_nrows; 00716 dimension_type n_lines_or_equalities = 0; 00717 for (dimension_type i = 0; i < nrows; ++i) 00718 if (x[i].is_line_or_equality()) { 00719 if (n_lines_or_equalities < i) { 00720 using std::swap; 00721 swap(x[i], x[n_lines_or_equalities]); 00722 // The system was not sorted. 00723 PPL_ASSERT(!x.sorted); 00724 } 00725 ++n_lines_or_equalities; 00726 } 00727 // Apply Gaussian elimination to the subsystem of lines/equalities. 00728 const dimension_type rank = x.gauss(n_lines_or_equalities); 00729 // Eliminate any redundant line/equality that has been detected. 00730 if (rank < n_lines_or_equalities) { 00731 const dimension_type 00732 n_rays_or_points_or_inequalities = nrows - n_lines_or_equalities; 00733 const dimension_type 00734 num_swaps = std::min(n_lines_or_equalities - rank, 00735 n_rays_or_points_or_inequalities); 00736 using std::swap; 00737 for (dimension_type i = num_swaps; i-- > 0; ) 00738 swap(x[--nrows], x[rank + i]); 00739 x.remove_trailing_rows(old_nrows - nrows); 00740 x.unset_pending_rows(); 00741 if (n_rays_or_points_or_inequalities > num_swaps) 00742 x.set_sorted(false); 00743 n_lines_or_equalities = rank; 00744 } 00745 // Apply back-substitution to the system of rays/points/inequalities. 00746 x.back_substitute(n_lines_or_equalities); 00747 // A well-formed system is returned. 00748 PPL_ASSERT(x.OK(true)); 00749 } 00750 00751 void 00752 PPL::Linear_System::add_rows_and_columns(const dimension_type n) { 00753 PPL_ASSERT(n > 0); 00754 const bool was_sorted = is_sorted(); 00755 const dimension_type old_n_rows = num_rows(); 00756 const dimension_type old_n_columns = num_columns(); 00757 add_zero_rows_and_columns(n, n, Linear_Row::Flags(row_topology)); 00758 Linear_System& x = *this; 00759 // The old system is moved to the bottom. 00760 using std::swap; 00761 for (dimension_type i = old_n_rows; i-- > 0; ) 00762 swap(x[i], x[i + n]); 00763 for (dimension_type i = n, c = old_n_columns; i-- > 0; ) { 00764 // The top right-hand sub-system (i.e., the system made of new 00765 // rows and columns) is set to the specular image of the identity 00766 // matrix. 00767 Linear_Row& r = x[i]; 00768 r[c++] = 1; 00769 r.set_is_line_or_equality(); 00770 // Note: `r' is strongly normalized. 00771 } 00772 // If the old system was empty, the last row added is either 00773 // a positivity constraint or a point. 00774 if (old_n_columns == 0) { 00775 x[n-1].set_is_ray_or_point_or_inequality(); 00776 // Since ray, points and inequalities come after lines 00777 // and equalities, this case implies the system is sorted. 00778 set_sorted(true); 00779 } 00780 else if (was_sorted) 00781 set_sorted(compare(x[n-1], x[n]) <= 0); 00782 00783 // A well-formed system has to be returned. 00784 PPL_ASSERT(OK(true)); 00785 } 00786 00787 void 00788 PPL::Linear_System::sort_pending_and_remove_duplicates() { 00789 PPL_ASSERT(num_pending_rows() > 0); 00790 PPL_ASSERT(is_sorted()); 00791 Linear_System& x = *this; 00792 00793 // The non-pending part of the system is already sorted. 00794 // Now sorting the pending part.. 00795 const dimension_type first_pending = x.first_pending_row(); 00796 x.sort_rows(first_pending, x.num_rows()); 00797 // Recompute the number of rows, because we may have removed 00798 // some rows occurring more than once in the pending part. 00799 const dimension_type old_num_rows = x.num_rows(); 00800 dimension_type num_rows = old_num_rows; 00801 00802 dimension_type k1 = 0; 00803 dimension_type k2 = first_pending; 00804 dimension_type num_duplicates = 0; 00805 // In order to erase them, put at the end of the system 00806 // those pending rows that also occur in the non-pending part. 00807 using std::swap; 00808 while (k1 < first_pending && k2 < num_rows) { 00809 const int cmp = compare(x[k1], x[k2]); 00810 if (cmp == 0) { 00811 // We found the same row. 00812 ++num_duplicates; 00813 --num_rows; 00814 // By initial sortedness, we can increment index `k1'. 00815 ++k1; 00816 // Do not increment `k2'; instead, swap there the next pending row. 00817 if (k2 < num_rows) 00818 swap(x[k2], x[k2 + num_duplicates]); 00819 } 00820 else if (cmp < 0) 00821 // By initial sortedness, we can increment `k1'. 00822 ++k1; 00823 else { 00824 // Here `cmp > 0'. 00825 // Increment `k2' and, if we already found any duplicate, 00826 // swap the next pending row in position `k2'. 00827 ++k2; 00828 if (num_duplicates > 0 && k2 < num_rows) 00829 swap(x[k2], x[k2 + num_duplicates]); 00830 } 00831 } 00832 // If needed, swap any duplicates found past the pending rows 00833 // that has not been considered yet; then erase the duplicates. 00834 if (num_duplicates > 0) { 00835 if (k2 < num_rows) 00836 for (++k2; k2 < num_rows; ++k2) 00837 swap(x[k2], x[k2 + num_duplicates]); 00838 x.remove_trailing_rows(old_num_rows - num_rows); 00839 } 00840 // Do not check for strong normalization, 00841 // because no modification of rows has occurred. 00842 PPL_ASSERT(OK(false)); 00843 } 00844 00845 bool 00846 PPL::Linear_System::check_sorted() const { 00847 const Linear_System& x = *this; 00848 for (dimension_type i = first_pending_row(); i-- > 1; ) 00849 if (compare(x[i], x[i-1]) < 0) 00850 return false; 00851 return true; 00852 } 00853 00854 bool 00855 PPL::Linear_System::OK(const bool check_strong_normalized) const { 00856 #ifndef NDEBUG 00857 using std::endl; 00858 using std::cerr; 00859 #endif 00860 00861 // `index_first_pending' must be less than or equal to `num_rows()'. 00862 if (first_pending_row() > num_rows()) { 00863 #ifndef NDEBUG 00864 cerr << "Linear_System has a negative number of pending rows!" 00865 << endl; 00866 #endif 00867 return false; 00868 } 00869 00870 // An empty system is OK, 00871 // unless it is an NNC system with exactly one column. 00872 if (has_no_rows()) { 00873 if (is_necessarily_closed() || num_columns() != 1) 00874 return true; 00875 else { 00876 #ifndef NDEBUG 00877 cerr << "NNC Linear_System has one column" << endl; 00878 #endif 00879 return false; 00880 } 00881 } 00882 00883 // A non-empty system will contain constraints or generators; in 00884 // both cases it must have at least one column for the inhomogeneous 00885 // term and, if it is NNC, another one for the epsilon coefficient. 00886 const dimension_type min_cols = is_necessarily_closed() ? 1U : 2U; 00887 if (num_columns() < min_cols) { 00888 #ifndef NDEBUG 00889 cerr << "Linear_System has fewer columns than the minimum " 00890 << "allowed by its topology:" 00891 << endl 00892 << "num_columns is " << num_columns() 00893 << ", minimum is " << min_cols 00894 << endl; 00895 #endif 00896 return false; 00897 } 00898 00899 const Linear_System& x = *this; 00900 const dimension_type n_rows = num_rows(); 00901 for (dimension_type i = 0; i < n_rows; ++i) { 00902 if (!x[i].OK(row_size, row_capacity)) 00903 return false; 00904 // Checking for topology mismatches. 00905 if (x.topology() != x[i].topology()) { 00906 #ifndef NDEBUG 00907 cerr << "Topology mismatch between the system " 00908 << "and one of its rows!" 00909 << endl; 00910 #endif 00911 return false; 00912 } 00913 } 00914 00915 if (check_strong_normalized) { 00916 // Check for strong normalization of rows. 00917 // Note: normalization cannot be checked inside the 00918 // Linear_Row::OK() method, because a Linear_Row object may also 00919 // implement a Linear_Expression object, which in general cannot 00920 // be (strongly) normalized. 00921 Linear_System tmp(x, With_Pending()); 00922 tmp.strong_normalize(); 00923 if (x != tmp) { 00924 #ifndef NDEBUG 00925 cerr << "Linear_System rows are not strongly normalized!" 00926 << endl; 00927 #endif 00928 return false; 00929 } 00930 } 00931 00932 if (sorted && !check_sorted()) { 00933 #ifndef NDEBUG 00934 cerr << "The system declares itself to be sorted but it is not!" 00935 << endl; 00936 #endif 00937 return false; 00938 } 00939 00940 // All checks passed. 00941 return true; 00942 }