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