00001 /* Polyhedron class implementation: simplify(). 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 00026 #include "Linear_Row.defs.hh" 00027 #include "Linear_System.defs.hh" 00028 #include "Bit_Matrix.defs.hh" 00029 #include "Polyhedron.defs.hh" 00030 #include <cstddef> 00031 #include <limits> 00032 00033 namespace PPL = Parma_Polyhedra_Library; 00034 00083 PPL::dimension_type 00084 PPL::Polyhedron::simplify(Linear_System& sys, Bit_Matrix& sat) { 00085 // This method is only applied to a well-formed system `sys'. 00086 PPL_ASSERT(sys.OK(true)); 00087 PPL_ASSERT(sys.num_columns() >= 1); 00088 00089 dimension_type num_rows = sys.num_rows(); 00090 const dimension_type num_columns = sys.num_columns(); 00091 const dimension_type num_cols_sat = sat.num_columns(); 00092 00093 // Looking for the first inequality in `sys'. 00094 dimension_type num_lines_or_equalities = 0; 00095 while (num_lines_or_equalities < num_rows 00096 && sys[num_lines_or_equalities].is_line_or_equality()) 00097 ++num_lines_or_equalities; 00098 00099 // `num_saturators[i]' will contain the number of generators 00100 // that saturate the constraint `sys[i]'. 00101 if (num_rows > simplify_num_saturators_size) { 00102 delete [] simplify_num_saturators_p; 00103 simplify_num_saturators_p = 0; 00104 simplify_num_saturators_size = 0; 00105 const size_t max_size 00106 = std::numeric_limits<size_t>::max() / sizeof(dimension_type); 00107 const size_t new_size = compute_capacity(num_rows, max_size); 00108 simplify_num_saturators_p = new dimension_type[new_size]; 00109 simplify_num_saturators_size = new_size; 00110 } 00111 dimension_type* num_saturators = simplify_num_saturators_p; 00112 00113 // Computing the number of saturators for each inequality, 00114 // possibly identifying and swapping those that happen to be 00115 // equalities (see Proposition above). 00116 for (dimension_type i = num_lines_or_equalities; i < num_rows; ++i) { 00117 if (sat[i].empty()) { 00118 // The constraint `sys[i]' is saturated by all the generators. 00119 // Thus, either it is already an equality or it can be transformed 00120 // to an equality (see Proposition above). 00121 sys[i].set_is_line_or_equality(); 00122 // Note: simple normalization already holds. 00123 sys[i].sign_normalize(); 00124 // We also move it just after all the other equalities, 00125 // so that system `sys' keeps its partial sortedness. 00126 if (i != num_lines_or_equalities) { 00127 std::swap(sys[i], sys[num_lines_or_equalities]); 00128 std::swap(sat[i], sat[num_lines_or_equalities]); 00129 std::swap(num_saturators[i], num_saturators[num_lines_or_equalities]); 00130 } 00131 ++num_lines_or_equalities; 00132 // `sys' is no longer sorted. 00133 sys.set_sorted(false); 00134 } 00135 else 00136 // There exists a generator which does not saturate `sys[i]', 00137 // so that `sys[i]' is indeed an inequality. 00138 // We store the number of its saturators. 00139 num_saturators[i] = num_cols_sat - sat[i].count_ones(); 00140 } 00141 00142 // At this point, all the equalities of `sys' (included those 00143 // inequalities that we just transformed to equalities) have 00144 // indexes between 0 and `num_lines_or_equalities' - 1, 00145 // which is the property needed by method gauss(). 00146 // We can simplify the system of equalities, obtaining the rank 00147 // of `sys' as result. 00148 const dimension_type rank = sys.gauss(num_lines_or_equalities); 00149 00150 // Now the irredundant equalities of `sys' have indexes from 0 00151 // to `rank' - 1, whereas the equalities having indexes from `rank' 00152 // to `num_lines_or_equalities' - 1 are all redundant. 00153 // (The inequalities in `sys' have been left untouched.) 00154 // The rows containing equalities are not sorted. 00155 00156 if (rank < num_lines_or_equalities) { 00157 // We identified some redundant equalities. 00158 // Moving them at the bottom of `sys': 00159 // - index `redundant' runs through the redundant equalities 00160 // - index `erasing' identifies the first row that should 00161 // be erased after this loop. 00162 // Note that we exit the loop either because we have moved all 00163 // redundant equalities or because we have moved all the 00164 // inequalities. 00165 for (dimension_type redundant = rank, 00166 erasing = num_rows; 00167 redundant < num_lines_or_equalities 00168 && erasing > num_lines_or_equalities; 00169 ) { 00170 --erasing; 00171 std::swap(sys[redundant], sys[erasing]); 00172 std::swap(sat[redundant], sat[erasing]); 00173 std::swap(num_saturators[redundant], num_saturators[erasing]); 00174 sys.set_sorted(false); 00175 ++redundant; 00176 } 00177 // Adjusting the value of `num_rows' to the number of meaningful 00178 // rows of `sys': `num_lines_or_equalities' - `rank' is the number of 00179 // redundant equalities moved to the bottom of `sys', which are 00180 // no longer meaningful. 00181 num_rows -= num_lines_or_equalities - rank; 00182 // Adjusting the value of `num_lines_or_equalities'. 00183 num_lines_or_equalities = rank; 00184 } 00185 00186 // Now we use the definition of redundancy (given in the Introduction) 00187 // to remove redundant inequalities. 00188 00189 // First we check the saturation rule, which provides a necessary 00190 // condition for an inequality to be irredundant (i.e., it provides 00191 // a sufficient condition for identifying redundant inequalities). 00192 // Let 00193 // num_saturators[i] = num_sat_lines[i] + num_sat_rays_or_points[i]; 00194 // dim_lin_space = num_irred_lines; 00195 // dim_ray_space 00196 // = dim_vector_space - num_irred_equalities - dim_lin_space 00197 // = num_columns - 1 - num_lines_or_equalities - dim_lin_space; 00198 // min_sat_rays_or_points = dim_ray_space. 00199 // 00200 // An inequality saturated by less than `dim_ray_space' _rays/points_ 00201 // is redundant. Thus we have the implication 00202 // 00203 // (num_saturators[i] - num_sat_lines[i] < dim_ray_space) 00204 // ==> 00205 // redundant(sys[i]). 00206 // 00207 // Moreover, since every line saturates all inequalities, we also have 00208 // dim_lin_space = num_sat_lines[i] 00209 // so that we can rewrite the condition above as follows: 00210 // 00211 // (num_saturators[i] < num_columns - num_lines_or_equalities - 1) 00212 // ==> 00213 // redundant(sys[i]). 00214 // 00215 const dimension_type min_saturators 00216 = num_columns - num_lines_or_equalities - 1; 00217 for (dimension_type i = num_lines_or_equalities; i < num_rows; ) { 00218 if (num_saturators[i] < min_saturators) { 00219 // The inequality `sys[i]' is redundant. 00220 --num_rows; 00221 std::swap(sys[i], sys[num_rows]); 00222 std::swap(sat[i], sat[num_rows]); 00223 std::swap(num_saturators[i], num_saturators[num_rows]); 00224 sys.set_sorted(false); 00225 } 00226 else 00227 ++i; 00228 } 00229 00230 // Now we check the independence rule. 00231 for (dimension_type i = num_lines_or_equalities; i < num_rows; ) { 00232 bool redundant = false; 00233 // NOTE: in the inner loop, index `j' runs through _all_ the 00234 // inequalities and we do not test if `sat[i]' is strictly 00235 // contained into `sat[j]'. Experimentation has shown that this 00236 // is faster than having `j' only run through the indexes greater 00237 // than `i' and also doing the test `strict_subset(sat[i], 00238 // sat[k])'. 00239 for (dimension_type j = num_lines_or_equalities; j < num_rows; ) { 00240 if (i == j) 00241 // We want to compare different rows of `sys'. 00242 ++j; 00243 else { 00244 // Let us recall that each generator lies on a facet of the 00245 // polyhedron (see the Introduction). 00246 // Given two constraints `c_1' and `c_2', if there are `m' 00247 // generators lying on the hyper-plane corresponding to `c_1', 00248 // the same `m' generators lie on the hyper-plane 00249 // corresponding to `c_2', too, and there is another one lying 00250 // on the latter but not on the former, then `c_2' is more 00251 // restrictive than `c_1', i.e., `c_1' is redundant. 00252 bool strict_subset; 00253 if (subset_or_equal(sat[j], sat[i], strict_subset)) 00254 if (strict_subset) { 00255 // All the saturators of the inequality `sys[i]' are 00256 // saturators of the inequality `sys[j]' too, 00257 // and there exists at least one saturator of `sys[j]' 00258 // which is not a saturator of `sys[i]'. 00259 // It follows that inequality `sys[i]' is redundant. 00260 redundant = true; 00261 break; 00262 } 00263 else { 00264 // We have `sat[j] == sat[i]'. Hence inequalities 00265 // `sys[i]' and `sys[j]' are saturated by the same set of 00266 // generators. Then we can remove either one of the two 00267 // inequalities: we remove `sys[j]'. 00268 --num_rows; 00269 std::swap(sys[j], sys[num_rows]); 00270 std::swap(sat[j], sat[num_rows]); 00271 std::swap(num_saturators[j], num_saturators[num_rows]); 00272 sys.set_sorted(false); 00273 } 00274 else 00275 // If we reach this point then we know that `sat[i]' does 00276 // not contain (and is different from) `sat[j]', so that 00277 // `sys[i]' is not made redundant by inequality `sys[j]'. 00278 ++j; 00279 } 00280 } 00281 if (redundant) { 00282 // The inequality `sys[i]' is redundant. 00283 --num_rows; 00284 std::swap(sys[i], sys[num_rows]); 00285 std::swap(sat[i], sat[num_rows]); 00286 std::swap(num_saturators[i], num_saturators[num_rows]); 00287 sys.set_sorted(false); 00288 } 00289 else 00290 // The inequality `sys[i]' is not redundant. 00291 ++i; 00292 } 00293 00294 // Here we physically remove the redundant inequalities previously 00295 // moved to the bottom of `sys' and the corresponding `sat' rows. 00296 sys.erase_to_end(num_rows); 00297 sys.unset_pending_rows(); 00298 sat.rows_erase_to_end(num_rows); 00299 // At this point the first `num_lines_or_equalities' rows of 'sys' 00300 // represent the irredundant equalities, while the remaining rows 00301 // (i.e., those having indexes from `num_lines_or_equalities' to 00302 // `num_rows' - 1) represent the irredundant inequalities. 00303 #ifndef NDEBUG 00304 // Check if the flag is set (that of the equalities is already set). 00305 for (dimension_type i = num_lines_or_equalities; i < num_rows; ++i) 00306 PPL_ASSERT(sys[i].is_ray_or_point_or_inequality()); 00307 #endif 00308 00309 // Finally, since now the sub-system (of `sys') of the irredundant 00310 // equalities is in triangular form, we back substitute each 00311 // variables with the expression obtained considering the equalities 00312 // starting from the last one. 00313 sys.back_substitute(num_lines_or_equalities); 00314 00315 // The returned value is the number of irredundant equalities i.e., 00316 // the rank of the sub-system of `sys' containing only equalities. 00317 // (See the Introduction for definition of lineality space dimension.) 00318 return num_lines_or_equalities; 00319 }
1.6.3