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