|
PPL
0.12.1
|
00001 /* Dense_Matrix 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 "Dense_Matrix.defs.hh" 00026 #include "Dense_Row.defs.hh" 00027 #include <algorithm> 00028 #include <iostream> 00029 #include <string> 00030 00031 namespace PPL = Parma_Polyhedra_Library; 00032 00033 PPL::Dense_Matrix::Dense_Matrix(const dimension_type n_rows, 00034 const dimension_type n_columns, 00035 Dense_Row::Flags row_flags) 00036 : 00037 #ifdef NDEBUG 00038 rows(n_rows), 00039 #else 00040 rows(n_rows <= max_num_rows() ? n_rows : 0), 00041 #endif 00042 row_size(n_columns), 00043 row_capacity(compute_capacity(n_columns, max_num_columns())) { 00044 PPL_ASSERT(n_rows <= max_num_rows()); 00045 // Construct in direct order: will destroy in reverse order. 00046 for (dimension_type i = 0; i < n_rows; ++i) { 00047 rows[i].set_flags(row_flags); 00048 rows[i].resize(n_columns, row_capacity); 00049 } 00050 PPL_ASSERT(OK()); 00051 } 00052 00053 void 00054 PPL::Dense_Matrix::add_zero_rows(const dimension_type n, 00055 Dense_Row::Flags row_flags) { 00056 PPL_ASSERT(n > 0); 00057 PPL_ASSERT(n <= max_num_rows() - num_rows()); 00058 const dimension_type old_num_rows = rows.size(); 00059 const dimension_type new_num_rows = old_num_rows + n; 00060 00061 if (rows.capacity() < new_num_rows) { 00062 // Reallocation will take place. 00063 std::vector<Dense_Row> new_rows; 00064 new_rows.reserve(compute_capacity(new_num_rows, max_num_rows())); 00065 new_rows.insert(new_rows.end(), new_num_rows, Dense_Row(row_flags)); 00066 // Construct the new rows. 00067 dimension_type i = new_num_rows; 00068 while (i-- > old_num_rows) 00069 new_rows[i].resize(row_size, row_capacity); 00070 // Steal the old rows. 00071 ++i; 00072 while (i-- > 0) 00073 new_rows[i].m_swap(rows[i]); 00074 // Put the new vector into place. 00075 using std::swap; 00076 swap(rows, new_rows); 00077 } 00078 else { 00079 // Reallocation will NOT take place. 00080 rows.insert(rows.end(), n, Dense_Row(row_flags)); 00081 for (dimension_type i = new_num_rows; i-- > old_num_rows; ) 00082 rows[i].resize(row_size, row_capacity); 00083 } 00084 PPL_ASSERT(OK()); 00085 } 00086 00087 void 00088 PPL::Dense_Matrix::add_zero_columns(const dimension_type n) { 00089 PPL_ASSERT(n > 0); 00090 PPL_ASSERT(n <= max_num_columns() - num_columns()); 00091 const dimension_type num_rows = rows.size(); 00092 const dimension_type new_num_columns = row_size + n; 00093 00094 if (new_num_columns <= row_capacity) 00095 // We have enough capacity: we resize existing rows. 00096 for (dimension_type i = num_rows; i-- > 0; ) 00097 rows[i].expand_within_capacity(new_num_columns); 00098 else { 00099 // Capacity exhausted: we must reallocate the rows and 00100 // make sure all the rows have the same capacity. 00101 const dimension_type new_row_capacity 00102 = compute_capacity(new_num_columns, max_num_columns()); 00103 PPL_ASSERT(new_row_capacity <= max_num_columns()); 00104 for (dimension_type i = num_rows; i-- > 0; ) { 00105 Dense_Row new_row(rows[i], new_num_columns, new_row_capacity); 00106 using std::swap; 00107 swap(rows[i], new_row); 00108 } 00109 row_capacity = new_row_capacity; 00110 } 00111 // Rows have been expanded. 00112 row_size = new_num_columns; 00113 PPL_ASSERT(OK()); 00114 } 00115 00116 void 00117 PPL::Dense_Matrix::add_zero_columns(dimension_type n, dimension_type i) { 00118 const dimension_type old_num_columns = num_columns(); 00119 00120 PPL_ASSERT(i <= old_num_columns); 00121 00122 add_zero_columns(n); 00123 00124 if (i == old_num_columns) 00125 return; 00126 00127 // Shift to the right the columns between i and old_num_columns. 00128 std::vector<dimension_type> swaps; 00129 const dimension_type num_columns_to_swap = old_num_columns - i; 00130 swaps.reserve(3 * num_columns_to_swap); 00131 00132 for (dimension_type j = 0; j < num_columns_to_swap; ++j) { 00133 swaps.push_back(i + j); 00134 swaps.push_back(old_num_columns + j); 00135 swaps.push_back(0); 00136 } 00137 permute_columns(swaps); 00138 00139 PPL_ASSERT(OK()); 00140 } 00141 00142 void 00143 PPL::Dense_Matrix::add_zero_rows_and_columns(const dimension_type n, 00144 const dimension_type m, 00145 Dense_Row::Flags row_flags) { 00146 PPL_ASSERT(n > 0); 00147 PPL_ASSERT(n <= max_num_rows() - num_rows()); 00148 PPL_ASSERT(m > 0); 00149 PPL_ASSERT(m <= max_num_columns() - num_columns()); 00150 const dimension_type old_num_rows = rows.size(); 00151 const dimension_type new_num_rows = old_num_rows + n; 00152 const dimension_type new_num_columns = row_size + m; 00153 00154 if (new_num_columns <= row_capacity) { 00155 // We can recycle the old rows. 00156 if (rows.capacity() < new_num_rows) { 00157 // Reallocation will take place. 00158 std::vector<Dense_Row> new_rows; 00159 new_rows.reserve(compute_capacity(new_num_rows, max_num_rows())); 00160 new_rows.insert(new_rows.end(), new_num_rows, Dense_Row(row_flags)); 00161 // Construct the new rows. 00162 dimension_type i = new_num_rows; 00163 while (i-- > old_num_rows) 00164 new_rows[i].resize(new_num_columns, row_capacity); 00165 // Expand and steal the old rows. 00166 ++i; 00167 while (i-- > 0) { 00168 rows[i].expand_within_capacity(new_num_columns); 00169 new_rows[i].m_swap(rows[i]); 00170 } 00171 // Put the new vector into place. 00172 using std::swap; 00173 swap(rows, new_rows); 00174 } 00175 else { 00176 // Reallocation will NOT take place. 00177 rows.insert(rows.end(), n, Dense_Row(row_flags)); 00178 // Construct the new rows. 00179 dimension_type i = new_num_rows; 00180 while (i-- > old_num_rows) 00181 rows[i].resize(new_num_columns, row_capacity); 00182 // Expand the old rows. 00183 ++i; 00184 while (i-- > 0) 00185 rows[i].expand_within_capacity(new_num_columns); 00186 } 00187 row_size = new_num_columns; 00188 } 00189 else { 00190 // We cannot even recycle the old rows. 00191 Dense_Matrix new_matrix; 00192 new_matrix.rows.reserve(compute_capacity(new_num_rows, max_num_rows())); 00193 new_matrix.rows.insert(new_matrix.rows.end(), new_num_rows, 00194 Dense_Row(row_flags)); 00195 // Construct the new rows. 00196 new_matrix.row_size = new_num_columns; 00197 new_matrix.row_capacity = compute_capacity(new_num_columns, 00198 max_num_columns()); 00199 dimension_type i = new_num_rows; 00200 while (i-- > old_num_rows) 00201 new_matrix.rows[i].resize(new_matrix.row_size, new_matrix.row_capacity); 00202 // Copy the old rows. 00203 ++i; 00204 while (i-- > 0) { 00205 Dense_Row new_row(rows[i], 00206 new_matrix.row_size, 00207 new_matrix.row_capacity); 00208 using std::swap; 00209 swap(new_matrix.rows[i], new_row); 00210 } 00211 // Put the new vector into place. 00212 m_swap(new_matrix); 00213 } 00214 00215 PPL_ASSERT(OK()); 00216 } 00217 00218 void 00219 PPL::Dense_Matrix::add_recycled_row(Dense_Row& y) { 00220 // The added row must have the same size and capacity as the 00221 // existing rows of the system. 00222 PPL_ASSERT(y.OK(row_size, row_capacity)); 00223 using std::swap; 00224 const dimension_type new_rows_size = rows.size() + 1; 00225 if (rows.capacity() < new_rows_size) { 00226 // Reallocation will take place. 00227 std::vector<Dense_Row> new_rows; 00228 new_rows.reserve(compute_capacity(new_rows_size, max_num_rows())); 00229 new_rows.insert(new_rows.end(), new_rows_size, Dense_Row()); 00230 // Put the new row in place. 00231 dimension_type i = new_rows_size-1; 00232 swap(new_rows[i], y); 00233 // Steal the old rows. 00234 while (i-- > 0) 00235 new_rows[i].m_swap(rows[i]); 00236 // Put the new rows into place. 00237 swap(rows, new_rows); 00238 } 00239 else 00240 // Reallocation will NOT take place. 00241 // Inserts a new empty row at the end, 00242 // then substitutes it with a copy of the given row. 00243 swap(*rows.insert(rows.end(), Dense_Row()), y); 00244 00245 PPL_ASSERT(OK()); 00246 } 00247 00248 void 00249 PPL::Dense_Matrix::resize_no_copy(const dimension_type new_n_rows, 00250 const dimension_type new_n_columns, 00251 Dense_Row::Flags row_flags) { 00252 dimension_type old_n_rows = rows.size(); 00253 // Note that, if we have `new_n_rows <= old_n_rows' and 00254 // `new_n_columns >= row_size', the matrix will keep its sortedness. 00255 // This is obvious if `new_n_columns == row_size'. 00256 // If `new_n_columns > row_size', then sortedness is maintained 00257 // because trailing zeroes will be added to all rows. 00258 if (new_n_rows > old_n_rows) { 00259 if (new_n_columns <= row_capacity) { 00260 // We can recycle the old rows. 00261 if (rows.capacity() < new_n_rows) { 00262 // Reallocation (of vector `rows') will take place. 00263 std::vector<Dense_Row> new_rows; 00264 new_rows.reserve(compute_capacity(new_n_rows, max_num_rows())); 00265 new_rows.insert(new_rows.end(), new_n_rows, Dense_Row(row_flags)); 00266 // Construct the new rows (be careful: each new row must have 00267 // the same capacity as each one of the old rows). 00268 dimension_type i = new_n_rows; 00269 while (i-- > old_n_rows) 00270 new_rows[i].resize(new_n_columns, row_capacity); 00271 // Steal the old rows. 00272 ++i; 00273 while (i-- > 0) 00274 new_rows[i].m_swap(rows[i]); 00275 // Put the new vector into place. 00276 using std::swap; 00277 swap(rows, new_rows); 00278 } 00279 else { 00280 // Reallocation (of vector `rows') will NOT take place. 00281 rows.insert(rows.end(), new_n_rows - old_n_rows, Dense_Row(row_flags)); 00282 // Be careful: each new row must have 00283 // the same capacity as each one of the old rows. 00284 for (dimension_type i = new_n_rows; i-- > old_n_rows; ) 00285 rows[i].resize(new_n_columns, row_capacity); 00286 } 00287 } 00288 else { 00289 // We cannot even recycle the old rows: allocate a new matrix and swap. 00290 Dense_Matrix new_matrix(new_n_rows, new_n_columns, row_flags); 00291 m_swap(new_matrix); 00292 return; 00293 } 00294 } 00295 else if (new_n_rows < old_n_rows) { 00296 // Drop some rows. 00297 rows.resize(new_n_rows); 00298 old_n_rows = new_n_rows; 00299 } 00300 // Here we have the right number of rows. 00301 if (new_n_columns != row_size) { 00302 if (new_n_columns < row_size) { 00303 // Shrink the existing rows. 00304 for (dimension_type i = old_n_rows; i-- > 0; ) 00305 rows[i].shrink(new_n_columns); 00306 } 00307 else 00308 // We need more columns. 00309 if (new_n_columns <= row_capacity) 00310 // But we have enough capacity: we resize existing rows. 00311 for (dimension_type i = old_n_rows; i-- > 0; ) 00312 rows[i].expand_within_capacity(new_n_columns); 00313 else { 00314 // Capacity exhausted: we must reallocate the rows and 00315 // make sure all the rows have the same capacity. 00316 const dimension_type new_row_capacity 00317 = compute_capacity(new_n_columns, max_num_columns()); 00318 for (dimension_type i = old_n_rows; i-- > 0; ) { 00319 Dense_Row new_row(new_n_columns, new_row_capacity, row_flags); 00320 using std::swap; 00321 swap(rows[i], new_row); 00322 } 00323 row_capacity = new_row_capacity; 00324 } 00325 // Rows have grown or shrunk. 00326 row_size = new_n_columns; 00327 } 00328 00329 PPL_ASSERT(OK()); 00330 } 00331 00332 void 00333 PPL::Dense_Matrix::ascii_dump(std::ostream& s) const { 00334 const Dense_Matrix& x = *this; 00335 dimension_type x_num_rows = x.num_rows(); 00336 dimension_type x_num_columns = x.num_columns(); 00337 s << x_num_rows << " x " << x_num_columns << "\n"; 00338 for (dimension_type i = 0; i < x_num_rows; ++i) 00339 x[i].ascii_dump(s); 00340 } 00341 00342 PPL_OUTPUT_DEFINITIONS_ASCII_ONLY(Dense_Matrix) 00343 00344 bool 00345 PPL::Dense_Matrix::ascii_load(std::istream& s) { 00346 Dense_Matrix& x = *this; 00347 std::string str; 00348 dimension_type x_num_rows; 00349 dimension_type x_num_cols; 00350 if (!(s >> x_num_rows)) 00351 return false; 00352 if (!(s >> str) || str != "x") 00353 return false; 00354 if (!(s >> x_num_cols)) 00355 return false; 00356 00357 resize_no_copy(x_num_rows, x_num_cols, Dense_Row::Flags()); 00358 00359 for (dimension_type row = 0; row < x_num_rows; ++row) 00360 if (!x[row].ascii_load(s)) 00361 return false; 00362 00363 // Check invariants. 00364 PPL_ASSERT(OK()); 00365 return true; 00366 } 00367 00368 void 00369 PPL::Dense_Matrix::swap_columns(const dimension_type i, 00370 const dimension_type j) { 00371 PPL_ASSERT(i != j && i < num_columns() && j < num_columns()); 00372 for (dimension_type k = num_rows(); k-- > 0; ) { 00373 Dense_Row& rows_k = rows[k]; 00374 using std::swap; 00375 swap(rows_k[i], rows_k[j]); 00376 } 00377 00378 PPL_ASSERT(OK()); 00379 } 00380 00381 void 00382 PPL::Dense_Matrix::remove_trailing_columns(const dimension_type n) { 00383 PPL_ASSERT(n > 0); 00384 PPL_ASSERT(n <= row_size); 00385 row_size -= n; 00386 for (dimension_type i = num_rows(); i-- > 0; ) 00387 rows[i].shrink(row_size); 00388 00389 PPL_ASSERT(OK()); 00390 } 00391 00392 void 00393 PPL::Dense_Matrix::remove_column(const dimension_type i) { 00394 PPL_ASSERT(i < row_size); 00395 const dimension_type n_cols = num_columns(); 00396 if (i != n_cols - 1) { 00397 std::vector<dimension_type> cycle; 00398 for (dimension_type j = n_cols - 1; j >= i; --j) 00399 cycle.push_back(j); 00400 cycle.push_back(0); 00401 permute_columns(cycle); 00402 } 00403 remove_trailing_columns(1); 00404 00405 PPL_ASSERT(OK()); 00406 } 00407 00408 void 00409 PPL::Dense_Matrix::permute_columns(const std::vector<dimension_type>& cycles) { 00410 PPL_DIRTY_TEMP_COEFFICIENT(tmp); 00411 const dimension_type n = cycles.size(); 00412 PPL_ASSERT(cycles[n - 1] == 0); 00413 using std::swap; 00414 for (dimension_type k = num_rows(); k-- > 0; ) { 00415 Dense_Row& rows_k = rows[k]; 00416 for (dimension_type i = 0, j = 0; i < n; i = ++j) { 00417 // Make `j' be the index of the next cycle terminator. 00418 while (cycles[j] != 0) 00419 ++j; 00420 // Cycles of length less than 2 are not allowed. 00421 PPL_ASSERT(j - i >= 2); 00422 if (j - i == 2) 00423 // For cycles of length 2 no temporary is needed, just a swap. 00424 swap(rows_k[cycles[i]], rows_k[cycles[i+1]]); 00425 else { 00426 // Longer cycles need a temporary. 00427 swap(rows_k[cycles[j-1]], tmp); 00428 for (dimension_type l = j-1; l > i; --l) 00429 swap(rows_k[cycles[l-1]], rows_k[cycles[l]]); 00430 swap(tmp, rows_k[cycles[i]]); 00431 } 00432 } 00433 } 00434 PPL_ASSERT(OK()); 00435 } 00436 00438 bool 00439 PPL::operator==(const Dense_Matrix& x, const Dense_Matrix& y) { 00440 if (x.num_columns() != y.num_columns()) 00441 return false; 00442 const dimension_type x_num_rows = x.num_rows(); 00443 const dimension_type y_num_rows = y.num_rows(); 00444 if (x_num_rows != y_num_rows) 00445 return false; 00446 for (dimension_type i = x_num_rows; i-- > 0; ) 00447 if (x[i] != y[i]) 00448 return false; 00449 return true; 00450 } 00451 00452 PPL::memory_size_type 00453 PPL::Dense_Matrix::external_memory_in_bytes() const { 00454 memory_size_type n = rows.capacity() * sizeof(Dense_Row); 00455 for (dimension_type i = num_rows(); i-- > 0; ) 00456 n += rows[i].external_memory_in_bytes(row_capacity); 00457 return n; 00458 } 00459 00460 bool 00461 PPL::Dense_Matrix::OK() const { 00462 if (row_size > row_capacity) { 00463 #ifndef NDEBUG 00464 std::cerr << "Dense_Matrix completely broken: " 00465 << "row_capacity is " << row_capacity 00466 << ", row_size is " << row_size 00467 << std::endl; 00468 #endif 00469 return false; 00470 } 00471 00472 const Dense_Matrix& x = *this; 00473 for (dimension_type i = 0, n_rows = num_rows(); i < n_rows; ++i) 00474 if (!x[i].OK(row_size, row_capacity)) 00475 return false; 00476 00477 // All checks passed. 00478 return true; 00479 }