PPL  0.12.1
minimize.cc
Go to the documentation of this file.
00001 /* Polyhedron class implementation: minimize() and add_and_minimize().
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_Row.defs.hh"
00026 #include "Linear_System.defs.hh"
00027 #include "Bit_Matrix.defs.hh"
00028 #include "Polyhedron.defs.hh"
00029 #include <stdexcept>
00030 
00031 namespace PPL = Parma_Polyhedra_Library;
00032 
00069 bool
00070 PPL::Polyhedron::minimize(const bool con_to_gen,
00071                           Linear_System& source,
00072                           Linear_System& dest,
00073                           Bit_Matrix& sat) {
00074   // Topologies have to agree.
00075   PPL_ASSERT(source.topology() == dest.topology());
00076   // `source' cannot be empty: even if it is an empty constraint system,
00077   // representing the universe polyhedron, homogenization has added
00078   // the positive constraint. It also cannot be an empty generator system,
00079   // since this function is always called starting from a non-empty
00080   // polyhedron.
00081   PPL_ASSERT(!source.has_no_rows());
00082 
00083   // Sort the source system, if necessary.
00084   if (!source.is_sorted())
00085     source.sort_rows();
00086 
00087   // Initialization of the system of generators `dest'.
00088   // The algorithm works incrementally and we haven't seen any
00089   // constraint yet: as a consequence, `dest' should describe
00090   // the universe polyhedron of the appropriate dimension.
00091   // To this end, we initialize it to the identity matrix of dimension
00092   // `source.num_columns()': the rows represent the lines corresponding
00093   // to the canonical basis of the vector space.
00094 
00095   // Resizing `dest' to be the appropriate square matrix.
00096   dimension_type dest_num_rows = source.num_columns();
00097   // Note that before calling `resize_no_copy()' we must update
00098   // `index_first_pending'.
00099   dest.set_index_first_pending_row(dest_num_rows);
00100   dest.resize_no_copy(dest_num_rows, dest_num_rows);
00101 
00102   // Initialize `dest' to the identity matrix.
00103   for (dimension_type i = dest_num_rows; i-- > 0; ) {
00104     Linear_Row& dest_i = dest[i];
00105     for (dimension_type j = dest_num_rows; j-- > 0; )
00106       dest_i[j] = (i == j) ? 1 : 0;
00107     dest_i.set_is_line_or_equality();
00108   }
00109   // The identity matrix `dest' is not sorted (see the sorting rules
00110   // in Linear_Row.cc).
00111   dest.set_sorted(false);
00112 
00113   // NOTE: the system `dest', as it is now, is not a _legal_ system of
00114   //       generators, because in the first row we have a line with a
00115   //       non-zero divisor (which should only happen for
00116   //       points). However, this is NOT a problem, because `source'
00117   //       necessarily contains the positivity constraint (or a
00118   //       combination of it with another constraint) which will
00119   //       restore things as they should be.
00120 
00121 
00122   // Building a saturation matrix and initializing it by setting
00123   // all of its elements to zero. This matrix will be modified together
00124   // with `dest' during the conversion.
00125   // NOTE: since we haven't seen any constraint yet, the relevant
00126   //       portion of `tmp_sat' is the sub-matrix consisting of
00127   //       the first 0 columns: thus the relevant portion correctly
00128   //       characterizes the initial saturation information.
00129   Bit_Matrix tmp_sat(dest_num_rows, source.num_rows());
00130 
00131   // By invoking the function conversion(), we populate `dest' with
00132   // the generators characterizing the polyhedron described by all
00133   // the constraints in `source'.
00134   // The `start' parameter is zero (we haven't seen any constraint yet)
00135   // and the 5th parameter (representing the number of lines in `dest'),
00136   // by construction, is equal to `dest_num_rows'.
00137   const dimension_type num_lines_or_equalities
00138     = conversion(source, 0, dest, tmp_sat, dest_num_rows);
00139   // conversion() may have modified the number of rows in `dest'.
00140   dest_num_rows = dest.num_rows();
00141 
00142   // Checking if the generators in `dest' represent an empty polyhedron:
00143   // the polyhedron is empty if there are no points
00144   // (because rays, lines and closure points need a supporting point).
00145   // Points can be detected by looking at:
00146   // - the divisor, for necessarily closed polyhedra;
00147   // - the epsilon coordinate, for NNC polyhedra.
00148   const dimension_type checking_index
00149     = dest.is_necessarily_closed()
00150     ? 0
00151     : (dest.num_columns() - 1);
00152   dimension_type first_point;
00153   for (first_point = num_lines_or_equalities;
00154        first_point < dest_num_rows;
00155        ++first_point)
00156     if (dest[first_point][checking_index] > 0)
00157       break;
00158 
00159   if (first_point == dest_num_rows)
00160     if (con_to_gen)
00161       // No point has been found: the polyhedron is empty.
00162       return true;
00163     else {
00164       // Here `con_to_gen' is false: `dest' is a system of constraints.
00165       // In this case the condition `first_point == dest_num_rows'
00166       // actually means that all the constraints in `dest' have their
00167       // inhomogeneous term equal to 0.
00168       // This is an ILLEGAL situation, because it implies that
00169       // the constraint system `dest' lacks the positivity constraint
00170       // and no linear combination of the constraints in `dest'
00171       // can reintroduce the positivity constraint.
00172       PPL_UNREACHABLE;
00173       return false;
00174     }
00175   else {
00176     // A point has been found: the polyhedron is not empty.
00177     // Now invoking simplify() to remove all the redundant constraints
00178     // from the system `source'.
00179     // Since the saturation matrix `tmp_sat' returned by conversion()
00180     // has rows indexed by generators (the rows of `dest') and columns
00181     // indexed by constraints (the rows of `source'), we have to
00182     // transpose it to obtain the saturation matrix needed by simplify().
00183     sat.transpose_assign(tmp_sat);
00184     simplify(source, sat);
00185     return false;
00186   }
00187 }
00188 
00189 
00235 bool
00236 PPL::Polyhedron::add_and_minimize(const bool con_to_gen,
00237                                   Linear_System& source1,
00238                                   Linear_System& dest,
00239                                   Bit_Matrix& sat,
00240                                   const Linear_System& source2) {
00241   // `source1' and `source2' cannot be empty.
00242   PPL_ASSERT(!source1.has_no_rows() && !source2.has_no_rows());
00243   // `source1' and `source2' must have the same number of columns
00244   // to be merged.
00245   PPL_ASSERT(source1.num_columns() == source2.num_columns());
00246   // `source1' and `source2' are fully sorted.
00247   PPL_ASSERT(source1.is_sorted() && source1.num_pending_rows() == 0);
00248   PPL_ASSERT(source2.is_sorted() && source2.num_pending_rows() == 0);
00249   PPL_ASSERT(dest.num_pending_rows() == 0);
00250 
00251   const dimension_type old_source1_num_rows = source1.num_rows();
00252   // `k1' and `k2' run through the rows of `source1' and `source2', resp.
00253   dimension_type k1 = 0;
00254   dimension_type k2 = 0;
00255   dimension_type source2_num_rows = source2.num_rows();
00256   while (k1 < old_source1_num_rows && k2 < source2_num_rows) {
00257     // Add to `source1' the constraints from `source2', as pending rows.
00258     // We exploit the property that initially both `source1' and `source2'
00259     // are sorted and index `k1' only scans the non-pending rows of `source1',
00260     // so that it is not influenced by the pending rows appended to it.
00261     // This way no duplicate (i.e., trivially redundant) constraint
00262     // is introduced in `source1'.
00263     const int cmp = compare(source1[k1], source2[k2]);
00264     if (cmp == 0) {
00265       // We found the same row: there is no need to add `source2[k2]'.
00266       ++k2;
00267       // By sortedness, since `k1 < old_source1_num_rows',
00268       // we can increment index `k1' too.
00269       ++k1;
00270     }
00271     else if (cmp < 0)
00272       // By sortedness, we can increment `k1'.
00273       ++k1;
00274     else {
00275       // Here `cmp > 0'.
00276       // By sortedness, `source2[k2]' cannot be in `source1'.
00277       // We add it as a pending row of `source1' (sortedness unaffected).
00278       source1.add_pending_row(source2[k2]);
00279       // We can increment `k2'.
00280       ++k2;
00281     }
00282   }
00283   // Have we scanned all the rows in `source2'?
00284   if (k2 < source2_num_rows)
00285     // By sortedness, all the rows in `source2' having indexes
00286     // greater than or equal to `k2' were not in `source1'.
00287     // We add them as pending rows of 'source1' (sortedness not affected).
00288     for ( ; k2 < source2_num_rows; ++k2)
00289       source1.add_pending_row(source2[k2]);
00290 
00291   if (source1.num_pending_rows() == 0)
00292     // No row was appended to `source1', because all the constraints
00293     // in `source2' were already in `source1'.
00294     // There is nothing left to do ...
00295     return false;
00296 
00297   return add_and_minimize(con_to_gen, source1, dest, sat);
00298 }
00299 
00336 bool
00337 PPL::Polyhedron::add_and_minimize(const bool con_to_gen,
00338                                   Linear_System& source,
00339                                   Linear_System& dest,
00340                                   Bit_Matrix& sat) {
00341   PPL_ASSERT(source.num_pending_rows() > 0);
00342   PPL_ASSERT(source.num_columns() == dest.num_columns());
00343   PPL_ASSERT(source.is_sorted());
00344 
00345   // First, pad the saturation matrix with new columns (of zeroes)
00346   // to accommodate for the pending rows of `source'.
00347   sat.resize(dest.num_rows(), source.num_rows());
00348 
00349   // Incrementally compute the new system of generators.
00350   // Parameter `start' is set to the index of the first pending constraint.
00351   const dimension_type num_lines_or_equalities
00352     = conversion(source, source.first_pending_row(),
00353                  dest, sat,
00354                  dest.num_lines_or_equalities());
00355 
00356   // conversion() may have modified the number of rows in `dest'.
00357   const dimension_type dest_num_rows = dest.num_rows();
00358 
00359   // Checking if the generators in `dest' represent an empty polyhedron:
00360   // the polyhedron is empty if there are no points
00361   // (because rays, lines and closure points need a supporting point).
00362   // Points can be detected by looking at:
00363   // - the divisor, for necessarily closed polyhedra;
00364   // - the epsilon coordinate, for NNC polyhedra.
00365   const dimension_type checking_index
00366     = dest.is_necessarily_closed()
00367     ? 0
00368     : (dest.num_columns() - 1);
00369   dimension_type first_point;
00370   for (first_point = num_lines_or_equalities;
00371        first_point < dest_num_rows;
00372        ++first_point)
00373     if (dest[first_point][checking_index] > 0)
00374       break;
00375 
00376   if (first_point == dest_num_rows)
00377     if (con_to_gen)
00378       // No point has been found: the polyhedron is empty.
00379       return true;
00380     else {
00381       // Here `con_to_gen' is false: `dest' is a system of constraints.
00382       // In this case the condition `first_point == dest_num_rows'
00383       // actually means that all the constraints in `dest' have their
00384       // inhomogeneous term equal to 0.
00385       // This is an ILLEGAL situation, because it implies that
00386       // the constraint system `dest' lacks the positivity constraint
00387       // and no linear combination of the constraints in `dest'
00388       // can reintroduce the positivity constraint.
00389       PPL_UNREACHABLE;
00390       return false;
00391     }
00392   else {
00393     // A point has been found: the polyhedron is not empty.
00394     // Now invoking `simplify()' to remove all the redundant constraints
00395     // from the system `source'.
00396     // Since the saturation matrix `sat' returned by `conversion()'
00397     // has rows indexed by generators (the rows of `dest') and columns
00398     // indexed by constraints (the rows of `source'), we have to
00399     // transpose it to obtain the saturation matrix needed by `simplify()'.
00400     sat.transpose();
00401     simplify(source, sat);
00402     // Transposing back.
00403     sat.transpose();
00404     return false;
00405   }
00406 }