PPL  0.12.1
Dense_Row.cc
Go to the documentation of this file.
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 }