|
PPL
0.12.1
|
00001 /* Dense_Row 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_Row.defs.hh" 00026 #include "Coefficient.defs.hh" 00027 #include "assert.hh" 00028 #include "Sparse_Row.defs.hh" 00029 #include <iostream> 00030 #include <iomanip> 00031 00032 namespace PPL = Parma_Polyhedra_Library; 00033 00034 void 00035 PPL::Dense_Row::resize(dimension_type new_size) { 00036 if (new_size <= size()) 00037 shrink(new_size); 00038 else { 00039 if (new_size > capacity()) { 00040 // Reallocation is required. 00041 // TODO: Consider using realloc() here. 00042 // TODO: Consider using a smarter allocation strategy. 00043 const dimension_type new_capacity = new_size; 00044 Coefficient* new_vec = impl.coeff_allocator.allocate(new_capacity); 00045 00046 if (impl.vec != 0) { 00047 memcpy(new_vec, impl.vec, sizeof(Coefficient) * impl.size); 00048 impl.coeff_allocator.deallocate(impl.vec, impl.capacity); 00049 } 00050 00051 impl.vec = new_vec; 00052 impl.capacity = new_capacity; 00053 } 00054 PPL_ASSERT(new_size <= impl.capacity); 00055 // Construct the additional elements. 00056 while (impl.size != new_size) { 00057 new (&impl.vec[impl.size]) Coefficient(); 00058 ++impl.size; 00059 } 00060 } 00061 PPL_ASSERT(size() == new_size); 00062 PPL_ASSERT(OK()); 00063 } 00064 00065 void 00066 PPL::Dense_Row::resize(dimension_type new_size, dimension_type new_capacity) { 00067 PPL_ASSERT(new_size <= new_capacity); 00068 00069 if (new_capacity == 0) { 00070 destroy(); 00071 impl.vec = 0; 00072 impl.size = 0; 00073 impl.capacity = 0; 00074 00075 PPL_ASSERT(size() == new_size); 00076 PPL_ASSERT(capacity() == new_capacity); 00077 PPL_ASSERT(OK()); 00078 00079 return; 00080 } 00081 00082 if (new_capacity < capacity()) { 00083 00084 shrink(new_size); 00085 00086 PPL_ASSERT(impl.size == new_size); 00087 00088 Coefficient* new_vec = impl.coeff_allocator.allocate(new_capacity); 00089 00090 PPL_ASSERT(impl.vec != 0); 00091 00092 memcpy(new_vec, impl.vec, sizeof(Coefficient) * impl.size); 00093 00094 impl.coeff_allocator.deallocate(impl.vec, impl.capacity); 00095 00096 impl.vec = new_vec; 00097 impl.capacity = new_capacity; 00098 } else { 00099 if (new_capacity > capacity()) { 00100 00101 Coefficient* new_vec = impl.coeff_allocator.allocate(new_capacity); 00102 00103 if (impl.vec != 0) { 00104 memcpy(new_vec, impl.vec, sizeof(Coefficient) * impl.size); 00105 impl.coeff_allocator.deallocate(impl.vec, impl.capacity); 00106 } 00107 00108 impl.vec = new_vec; 00109 impl.capacity = new_capacity; 00110 00111 resize(new_size); 00112 } 00113 } 00114 00115 PPL_ASSERT(size() == new_size); 00116 PPL_ASSERT(capacity() == new_capacity); 00117 PPL_ASSERT(OK()); 00118 } 00119 00120 void 00121 PPL::Dense_Row::expand_within_capacity(const dimension_type new_size) { 00122 PPL_ASSERT(new_size <= impl.capacity); 00123 PPL_ASSERT(size() <= new_size && new_size <= max_size()); 00124 while (impl.size != new_size) { 00125 new (&impl.vec[impl.size]) Coefficient(); 00126 ++impl.size; 00127 } 00128 PPL_ASSERT(size() == new_size); 00129 PPL_ASSERT(OK()); 00130 } 00131 00132 void 00133 PPL::Dense_Row::shrink(dimension_type new_size) { 00134 PPL_ASSERT(new_size <= size()); 00135 // Since ~Coefficient() does not throw exceptions, nothing here does. 00136 00137 // We assume construction was done "forward". 00138 // We thus perform destruction "backward". 00139 while (impl.size != new_size) { 00140 --impl.size; 00141 impl.vec[impl.size].~Coefficient(); 00142 } 00143 00144 PPL_ASSERT(size() == new_size); 00145 PPL_ASSERT(OK()); 00146 } 00147 00148 PPL::Dense_Row::Dense_Row(const Sparse_Row& row) 00149 : impl() { 00150 00151 init(row); 00152 00153 PPL_ASSERT(size() == row.size()); 00154 PPL_ASSERT(OK()); 00155 } 00156 00157 void 00158 PPL::Dense_Row::init(const Sparse_Row& row) { 00159 impl.capacity = row.size(); 00160 impl.flags = row.flags(); 00161 impl.vec = impl.coeff_allocator.allocate(impl.capacity); 00162 Sparse_Row::const_iterator itr = row.begin(); 00163 Sparse_Row::const_iterator itr_end = row.end(); 00164 while (impl.size != impl.capacity) { 00165 // Constructs (*this)[impl.size] with row[impl.size]. 00166 if (itr != itr_end && itr.index() == impl.size) { 00167 new (&impl.vec[impl.size]) Coefficient(*itr); 00168 ++itr; 00169 } else 00170 new (&impl.vec[impl.size]) Coefficient(); 00171 ++impl.size; 00172 } 00173 PPL_ASSERT(size() == row.size()); 00174 PPL_ASSERT(OK()); 00175 } 00176 00177 PPL::Dense_Row& 00178 PPL::Dense_Row::operator=(const Sparse_Row& row) { 00179 impl.flags = row.flags(); 00180 if (size() > row.size()) { 00181 // TODO: If the shrink() is modified to reallocate a smaller chunk, 00182 // this can be optimized. 00183 shrink(row.size()); 00184 Sparse_Row::const_iterator itr = row.begin(); 00185 Sparse_Row::const_iterator itr_end = row.end(); 00186 for (dimension_type i = 0; i < impl.size; ++i) { 00187 // Computes (*this)[impl.size] = row[impl.size]. 00188 if (itr != itr_end && itr.index() == i) { 00189 impl.vec[impl.size] = *itr; 00190 ++itr; 00191 } else 00192 impl.vec[impl.size] = Coefficient_zero(); 00193 } 00194 } else { 00195 if (capacity() >= row.size()) { 00196 // size() <= row.size() <= capacity(). 00197 Sparse_Row::const_iterator itr = row.begin(); 00198 Sparse_Row::const_iterator itr_end = row.end(); 00199 for (dimension_type i = 0; i < impl.size; ++i) { 00200 // The following code is equivalent to (*this)[i] = row[i]. 00201 if (itr != itr_end && itr.index() == impl.size) { 00202 new (&impl.vec[impl.size]) Coefficient(*itr); 00203 ++itr; 00204 } else 00205 new (&impl.vec[impl.size]) Coefficient(); 00206 } 00207 // Construct the additional elements. 00208 for ( ; impl.size != row.size(); ++impl.size) { 00209 // Constructs (*this)[impl.size] with row[impl.size]. 00210 if (itr != itr_end && itr.index() == impl.size) { 00211 new (&impl.vec[impl.size]) Coefficient(*itr); 00212 ++itr; 00213 } else 00214 new (&impl.vec[impl.size]) Coefficient(); 00215 } 00216 } else { 00217 // Reallocation is required. 00218 destroy(); 00219 init(row); 00220 } 00221 } 00222 PPL_ASSERT(size() == row.size()); 00223 PPL_ASSERT(OK()); 00224 00225 return *this; 00226 } 00227 00228 void 00229 PPL::Dense_Row::normalize() { 00230 Dense_Row& x = *this; 00231 // Compute the GCD of all the coefficients. 00232 const dimension_type sz = size(); 00233 dimension_type i = sz; 00234 PPL_DIRTY_TEMP_COEFFICIENT(gcd); 00235 while (i > 0) { 00236 Coefficient_traits::const_reference x_i = x[--i]; 00237 if (const int x_i_sign = sgn(x_i)) { 00238 gcd = x_i; 00239 if (x_i_sign < 0) 00240 neg_assign(gcd); 00241 goto compute_gcd; 00242 } 00243 } 00244 // We reach this point only if all the coefficients were zero. 00245 return; 00246 00247 compute_gcd: 00248 if (gcd == 1) 00249 return; 00250 while (i > 0) { 00251 Coefficient_traits::const_reference x_i = x[--i]; 00252 if (x_i != 0) { 00253 // Note: we use the ternary version instead of a more concise 00254 // gcd_assign(gcd, x_i) to take advantage of the fact that 00255 // `gcd' will decrease very rapidly (see D. Knuth, The Art of 00256 // Computer Programming, second edition, Section 4.5.2, 00257 // Algorithm C, and the discussion following it). Our 00258 // implementation of gcd_assign(x, y, z) for checked numbers is 00259 // optimized for the case where `z' is smaller than `y', so that 00260 // on checked numbers we gain. On the other hand, for the 00261 // implementation of gcd_assign(x, y, z) on GMP's unbounded 00262 // integers we cannot make any assumption, so here we draw. 00263 // Overall, we win. 00264 gcd_assign(gcd, x_i, gcd); 00265 if (gcd == 1) 00266 return; 00267 } 00268 } 00269 // Divide the coefficients by the GCD. 00270 for (dimension_type j = sz; j-- > 0; ) { 00271 Coefficient& x_j = x[j]; 00272 exact_div_assign(x_j, x_j, gcd); 00273 } 00274 } 00275 00276 void 00277 PPL::Dense_Row::reset(dimension_type first, dimension_type last) { 00278 PPL_ASSERT(first <= last); 00279 PPL_ASSERT(last <= size()); 00280 for (dimension_type i = first; i < last; ++i) 00281 (*this)[i] = 0; 00282 } 00283 00284 void 00285 PPL::Dense_Row::linear_combine(const Dense_Row& y, 00286 Coefficient_traits::const_reference coeff1, 00287 Coefficient_traits::const_reference coeff2) { 00288 Dense_Row& x = *this; 00289 PPL_ASSERT(x.size() == y.size()); 00290 for (dimension_type i = x.size(); i-- > 0; ) { 00291 Coefficient& x_i = x[i]; 00292 x_i *= coeff1; 00293 // The test against 0 gives rise to a consistent speed up: see 00294 // http://www.cs.unipr.it/pipermail/ppl-devel/2009-February/014000.html 00295 Coefficient_traits::const_reference y_i = y[i]; 00296 if (y_i != 0) 00297 add_mul_assign(x_i, y_i, coeff2); 00298 } 00299 } 00300 00301 void 00302 PPL::Dense_Row::ascii_dump(std::ostream& s) const { 00303 const Dense_Row& x = *this; 00304 const dimension_type x_size = x.size(); 00305 s << "size " << x_size << " "; 00306 for (dimension_type i = 0; i < x_size; ++i) 00307 s << x[i] << ' '; 00308 s << "f "; 00309 flags().ascii_dump(s); 00310 s << "\n"; 00311 } 00312 00313 PPL_OUTPUT_DEFINITIONS_ASCII_ONLY(Dense_Row) 00314 00315 bool 00316 PPL::Dense_Row::ascii_load(std::istream& s) { 00317 std::string str; 00318 if (!(s >> str) || str != "size") 00319 return false; 00320 dimension_type new_size; 00321 if (!(s >> new_size)) 00322 return false; 00323 00324 resize(new_size); 00325 00326 for (dimension_type col = 0; col < new_size; ++col) 00327 if (!(s >> (*this)[col])) 00328 return false; 00329 if (!(s >> str) || str != "f") 00330 return false; 00331 return impl.flags.ascii_load(s); 00332 } 00333 00334 PPL::memory_size_type 00335 PPL::Dense_Row::external_memory_in_bytes(dimension_type /* capacity */) const { 00336 return external_memory_in_bytes(); 00337 } 00338 00339 PPL::memory_size_type 00340 PPL::Dense_Row::external_memory_in_bytes() const { 00341 memory_size_type n = impl.capacity * sizeof(Coefficient); 00342 for (dimension_type i = size(); i-- > 0; ) 00343 n += PPL::external_memory_in_bytes(impl.vec[i]); 00344 return n; 00345 } 00346 00347 bool 00348 PPL::Dense_Row::OK() const { 00349 #ifndef NDEBUG 00350 using std::endl; 00351 using std::cerr; 00352 #endif 00353 00354 bool is_broken = false; 00355 00356 if (impl.capacity > max_size()) { 00357 #ifndef NDEBUG 00358 cerr << "Dense_Row capacity exceeds the maximum allowed size:" << endl 00359 << "is " << impl.capacity 00360 << ", should be less than or equal to " << max_size() << "." 00361 << endl; 00362 #endif 00363 is_broken = true; 00364 } 00365 00366 if (size() > max_size()) { 00367 #ifndef NDEBUG 00368 cerr << "Dense_Row size exceeds the maximum allowed size:" << endl 00369 << "is " << size() 00370 << ", should be less than or equal to " << max_size() << "." << endl; 00371 #endif 00372 is_broken = true; 00373 } 00374 00375 if (impl.capacity < size()) { 00376 #ifndef NDEBUG 00377 cerr << "Dense_Row is completely broken: capacity is " << impl.capacity 00378 << ", size is " << size() << "." << endl; 00379 #endif 00380 is_broken = true; 00381 } 00382 00383 if (capacity() == 0) { 00384 if (impl.vec != 0) 00385 is_broken = true; 00386 } else { 00387 if (impl.vec == 0) 00388 is_broken = true; 00389 } 00390 00391 return !is_broken; 00392 } 00393 00394 bool 00395 PPL::Dense_Row::OK(const dimension_type row_size, 00396 const dimension_type row_capacity) const { 00397 #ifndef NDEBUG 00398 using std::endl; 00399 using std::cerr; 00400 #endif 00401 00402 bool is_broken = !OK(); 00403 00404 // Check the declared capacity. 00405 if (impl.capacity != row_capacity) { 00406 #ifndef NDEBUG 00407 cerr << "Dense_Row capacity mismatch: is " << impl.capacity 00408 << ", should be " << row_capacity << "." << endl; 00409 #endif // NDEBUG 00410 is_broken = true; 00411 } 00412 00413 // Check the declared size. 00414 if (size() != row_size) { 00415 #ifndef NDEBUG 00416 cerr << "Dense_Row size mismatch: is " << size() 00417 << ", should be " << row_size << "." << endl; 00418 #endif 00419 is_broken = true; 00420 } 00421 return !is_broken; 00422 } 00423 00425 bool 00426 PPL::operator==(const Dense_Row& x, const Dense_Row& y) { 00427 const dimension_type x_size = x.size(); 00428 const dimension_type y_size = y.size(); 00429 00430 if (x_size != y_size) 00431 return false; 00432 00433 if (x.flags() != y.flags()) 00434 return false; 00435 00436 for (dimension_type i = x_size; i-- > 0; ) 00437 if (x[i] != y[i]) 00438 return false; 00439 00440 return true; 00441 }