00001 /* Polyhedron class implementation: minimize() and add_and_minimize(). 00002 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it> 00003 Copyright (C) 2010-2011 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://www.cs.unipr.it/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 throw std::runtime_error("PPL internal error"); 00173 else { 00174 // A point has been found: the polyhedron is not empty. 00175 // Now invoking simplify() to remove all the redundant constraints 00176 // from the system `source'. 00177 // Since the saturation matrix `tmp_sat' returned by conversion() 00178 // has rows indexed by generators (the rows of `dest') and columns 00179 // indexed by constraints (the rows of `source'), we have to 00180 // transpose it to obtain the saturation matrix needed by simplify(). 00181 sat.transpose_assign(tmp_sat); 00182 simplify(source, sat); 00183 return false; 00184 } 00185 } 00186 00187 00233 bool 00234 PPL::Polyhedron::add_and_minimize(const bool con_to_gen, 00235 Linear_System& source1, 00236 Linear_System& dest, 00237 Bit_Matrix& sat, 00238 const Linear_System& source2) { 00239 // `source1' and `source2' cannot be empty. 00240 PPL_ASSERT(!source1.has_no_rows() && !source2.has_no_rows()); 00241 // `source1' and `source2' must have the same number of columns 00242 // to be merged. 00243 PPL_ASSERT(source1.num_columns() == source2.num_columns()); 00244 // `source1' and `source2' are fully sorted. 00245 PPL_ASSERT(source1.is_sorted() && source1.num_pending_rows() == 0); 00246 PPL_ASSERT(source2.is_sorted() && source2.num_pending_rows() == 0); 00247 PPL_ASSERT(dest.num_pending_rows() == 0); 00248 00249 const dimension_type old_source1_num_rows = source1.num_rows(); 00250 // `k1' and `k2' run through the rows of `source1' and `source2', resp. 00251 dimension_type k1 = 0; 00252 dimension_type k2 = 0; 00253 dimension_type source2_num_rows = source2.num_rows(); 00254 while (k1 < old_source1_num_rows && k2 < source2_num_rows) { 00255 // Add to `source1' the constraints from `source2', as pending rows. 00256 // We exploit the property that initially both `source1' and `source2' 00257 // are sorted and index `k1' only scans the non-pending rows of `source1', 00258 // so that it is not influenced by the pending rows appended to it. 00259 // This way no duplicate (i.e., trivially redundant) constraint 00260 // is introduced in `source1'. 00261 const int cmp = compare(source1[k1], source2[k2]); 00262 if (cmp == 0) { 00263 // We found the same row: there is no need to add `source2[k2]'. 00264 ++k2; 00265 // By sortedness, since `k1 < old_source1_num_rows', 00266 // we can increment index `k1' too. 00267 ++k1; 00268 } 00269 else if (cmp < 0) 00270 // By sortedness, we can increment `k1'. 00271 ++k1; 00272 else { 00273 // Here `cmp > 0'. 00274 // By sortedness, `source2[k2]' cannot be in `source1'. 00275 // We add it as a pending row of `source1' (sortedness unaffected). 00276 source1.add_pending_row(source2[k2]); 00277 // We can increment `k2'. 00278 ++k2; 00279 } 00280 } 00281 // Have we scanned all the rows in `source2'? 00282 if (k2 < source2_num_rows) 00283 // By sortedness, all the rows in `source2' having indexes 00284 // greater than or equal to `k2' were not in `source1'. 00285 // We add them as pending rows of 'source1' (sortedness not affected). 00286 for ( ; k2 < source2_num_rows; ++k2) 00287 source1.add_pending_row(source2[k2]); 00288 00289 if (source1.num_pending_rows() == 0) 00290 // No row was appended to `source1', because all the constraints 00291 // in `source2' were already in `source1'. 00292 // There is nothing left to do ... 00293 return false; 00294 00295 return add_and_minimize(con_to_gen, source1, dest, sat); 00296 } 00297 00334 bool 00335 PPL::Polyhedron::add_and_minimize(const bool con_to_gen, 00336 Linear_System& source, 00337 Linear_System& dest, 00338 Bit_Matrix& sat) { 00339 PPL_ASSERT(source.num_pending_rows() > 0); 00340 PPL_ASSERT(source.num_columns() == dest.num_columns()); 00341 PPL_ASSERT(source.is_sorted()); 00342 00343 // First, pad the saturation matrix with new columns (of zeroes) 00344 // to accommodate for the pending rows of `source'. 00345 sat.resize(dest.num_rows(), source.num_rows()); 00346 00347 // Incrementally compute the new system of generators. 00348 // Parameter `start' is set to the index of the first pending constraint. 00349 const dimension_type num_lines_or_equalities 00350 = conversion(source, source.first_pending_row(), 00351 dest, sat, 00352 dest.num_lines_or_equalities()); 00353 00354 // conversion() may have modified the number of rows in `dest'. 00355 const dimension_type dest_num_rows = dest.num_rows(); 00356 00357 // Checking if the generators in `dest' represent an empty polyhedron: 00358 // the polyhedron is empty if there are no points 00359 // (because rays, lines and closure points need a supporting point). 00360 // Points can be detected by looking at: 00361 // - the divisor, for necessarily closed polyhedra; 00362 // - the epsilon coordinate, for NNC polyhedra. 00363 const dimension_type checking_index 00364 = dest.is_necessarily_closed() 00365 ? 0 00366 : dest.num_columns() - 1; 00367 dimension_type first_point; 00368 for (first_point = num_lines_or_equalities; 00369 first_point < dest_num_rows; 00370 ++first_point) 00371 if (dest[first_point][checking_index] > 0) 00372 break; 00373 00374 if (first_point == dest_num_rows) 00375 if (con_to_gen) 00376 // No point has been found: the polyhedron is empty. 00377 return true; 00378 else 00379 // Here `con_to_gen' is false: `dest' is a system of constraints. 00380 // In this case the condition `first_point == dest_num_rows' 00381 // actually means that all the constraints in `dest' have their 00382 // inhomogeneous term equal to 0. 00383 // This is an ILLEGAL situation, because it implies that 00384 // the constraint system `dest' lacks the positivity constraint 00385 // and no linear combination of the constraints in `dest' 00386 // can reintroduce the positivity constraint. 00387 throw std::runtime_error("PPL internal error"); 00388 else { 00389 // A point has been found: the polyhedron is not empty. 00390 // Now invoking `simplify()' to remove all the redundant constraints 00391 // from the system `source'. 00392 // Since the saturation matrix `sat' returned by `conversion()' 00393 // has rows indexed by generators (the rows of `dest') and columns 00394 // indexed by constraints (the rows of `source'), we have to 00395 // transpose it to obtain the saturation matrix needed by `simplify()'. 00396 sat.transpose(); 00397 simplify(source, sat); 00398 // Transposing back. 00399 sat.transpose(); 00400 return false; 00401 } 00402 }
1.6.3