|
PPL
0.12.1
|
00001 /* Polyhedron class implementation 00002 (non-inline operators that may change the dimension of the vector space). 00003 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it> 00004 Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com) 00005 00006 This file is part of the Parma Polyhedra Library (PPL). 00007 00008 The PPL is free software; you can redistribute it and/or modify it 00009 under the terms of the GNU General Public License as published by the 00010 Free Software Foundation; either version 3 of the License, or (at your 00011 option) any later version. 00012 00013 The PPL is distributed in the hope that it will be useful, but WITHOUT 00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00015 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00016 for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software Foundation, 00020 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. 00021 00022 For the most up-to-date information see the Parma Polyhedra Library 00023 site: http://bugseng.com/products/ppl/ . */ 00024 00025 #include "ppl-config.h" 00026 #include "Polyhedron.defs.hh" 00027 #include "Variables_Set.defs.hh" 00028 #include "assert.hh" 00029 00030 #define BE_LAZY 1 00031 00032 namespace PPL = Parma_Polyhedra_Library; 00033 00034 void 00035 PPL::Polyhedron::add_space_dimensions(Linear_System& sys1, 00036 Linear_System& sys2, 00037 Bit_Matrix& sat1, 00038 Bit_Matrix& sat2, 00039 dimension_type add_dim) { 00040 PPL_ASSERT(sys1.topology() == sys2.topology()); 00041 PPL_ASSERT(sys1.num_columns() == sys2.num_columns()); 00042 PPL_ASSERT(add_dim != 0); 00043 using std::swap; 00044 00045 sys1.add_zero_columns(add_dim); 00046 dimension_type old_index = sys2.first_pending_row(); 00047 sys2.add_rows_and_columns(add_dim); 00048 // The added rows are in the non-pending part. 00049 sys2.set_index_first_pending_row(old_index + add_dim); 00050 00051 // The resulting saturation matrix will be as follows: 00052 // from row 0 to add_dim-1 : only zeroes 00053 // add_dim add_dim+num_rows-1 : old saturation matrix 00054 00055 // In fact all the old generators saturate all the new constraints 00056 // because the polyhedron has not been embedded in the new space. 00057 sat1.resize(sat1.num_rows() + add_dim, sat1.num_columns()); 00058 // The old matrix is moved to the end of the new matrix. 00059 for (dimension_type i = sat1.num_rows() - add_dim; i-- > 0; ) 00060 swap(sat1[i], sat1[i+add_dim]); 00061 // Computes the "sat_c", too. 00062 sat2.transpose_assign(sat1); 00063 00064 if (!sys1.is_necessarily_closed()) { 00065 // Moving the epsilon coefficients to the new last column. 00066 dimension_type new_eps_index = sys1.num_columns() - 1; 00067 dimension_type old_eps_index = new_eps_index - add_dim; 00068 // This swap preserves sortedness of `sys1'. 00069 sys1.swap_columns(old_eps_index, new_eps_index); 00070 00071 // Try to preserve sortedness of `sys2'. 00072 if (!sys2.is_sorted()) 00073 sys2.swap_columns(old_eps_index, new_eps_index); 00074 else { 00075 for (dimension_type i = sys2.num_rows(); i-- > add_dim; ) { 00076 Linear_Row& r = sys2[i]; 00077 swap(r[old_eps_index], r[new_eps_index]); 00078 } 00079 // The upper-right corner of `sys2' contains the J matrix: 00080 // swap coefficients to preserve sortedness. 00081 for (dimension_type i = add_dim; i-- > 0; ++old_eps_index) { 00082 Linear_Row& r = sys2[i]; 00083 swap(r[old_eps_index], r[old_eps_index + 1]); 00084 } 00085 } 00086 // NOTE: since we swapped columns in both `sys1' and `sys2', 00087 // no swapping is required for `sat1' and `sat2'. 00088 } 00089 } 00090 00091 void 00092 PPL::Polyhedron::add_space_dimensions_and_embed(dimension_type m) { 00093 // The space dimension of the resulting polyhedron should not 00094 // overflow the maximum allowed space dimension. 00095 check_space_dimension_overflow(m, max_space_dimension() - space_dimension(), 00096 topology(), 00097 "add_space_dimensions_and_embed(m)", 00098 "adding m new space dimensions exceeds " 00099 "the maximum allowed space dimension"); 00100 00101 // Adding no dimensions to any polyhedron is a no-op. 00102 if (m == 0) 00103 return; 00104 00105 // Adding dimensions to an empty polyhedron is obtained by adjusting 00106 // `space_dim' and clearing `con_sys' (since it can contain the 00107 // unsatisfiable constraint system of the wrong dimension). 00108 if (marked_empty()) { 00109 space_dim += m; 00110 con_sys.clear(); 00111 return; 00112 } 00113 00114 // The case of a zero-dimensional space polyhedron. 00115 if (space_dim == 0) { 00116 // Since it is not empty, it has to be the universe polyhedron. 00117 PPL_ASSERT(status.test_zero_dim_univ()); 00118 // We swap `*this' with a newly created 00119 // universe polyhedron of dimension `m'. 00120 Polyhedron ph(topology(), m, UNIVERSE); 00121 m_swap(ph); 00122 return; 00123 } 00124 00125 // To embed an n-dimension space polyhedron in a (n+m)-dimension space, 00126 // we just add `m' zero-columns to the rows in the system of constraints; 00127 // in contrast, the system of generators needs additional rows, 00128 // corresponding to the vectors of the canonical basis 00129 // for the added dimensions. That is, for each new dimension `x[k]' 00130 // we add the line having that direction. This is done by invoking 00131 // the function add_space_dimensions() giving the system of generators 00132 // as the second argument. 00133 if (constraints_are_up_to_date()) 00134 if (generators_are_up_to_date()) { 00135 // `sat_c' must be up to date for add_space_dimensions(). 00136 if (!sat_c_is_up_to_date()) 00137 update_sat_c(); 00138 // Adds rows and/or columns to both matrices. 00139 // `add_space_dimensions' correctly handles pending constraints 00140 // or generators. 00141 add_space_dimensions(con_sys, gen_sys, sat_c, sat_g, m); 00142 } 00143 else { 00144 // Only constraints are up-to-date: no need to modify the generators. 00145 con_sys.add_zero_columns(m); 00146 // If the polyhedron is not necessarily closed, 00147 // move the epsilon coefficients to the last column. 00148 if (!is_necessarily_closed()) 00149 con_sys.swap_columns(space_dim + 1, space_dim + 1 + m); 00150 } 00151 else { 00152 // Only generators are up-to-date: no need to modify the constraints. 00153 PPL_ASSERT(generators_are_up_to_date()); 00154 gen_sys.add_rows_and_columns(m); 00155 // The polyhedron does not support pending generators. 00156 gen_sys.unset_pending_rows(); 00157 // If the polyhedron is not necessarily closed, 00158 // move the epsilon coefficients to the last column. 00159 if (!is_necessarily_closed()) { 00160 // Try to preserve sortedness of `gen_sys'. 00161 if (!gen_sys.is_sorted()) 00162 gen_sys.swap_columns(space_dim + 1, space_dim + 1 + m); 00163 else { 00164 using std::swap; 00165 dimension_type old_eps_index = space_dim + 1; 00166 dimension_type new_eps_index = old_eps_index + m; 00167 for (dimension_type i = gen_sys.num_rows(); i-- > m; ) { 00168 Generator& r = gen_sys[i]; 00169 swap(r[old_eps_index], r[new_eps_index]); 00170 } 00171 // The upper-right corner of `gen_sys' contains the J matrix: 00172 // swap coefficients to preserve sortedness. 00173 for (dimension_type i = m; i-- > 0; ++old_eps_index) { 00174 Generator& r = gen_sys[i]; 00175 swap(r[old_eps_index], r[old_eps_index + 1]); 00176 } 00177 } 00178 } 00179 } 00180 // Update the space dimension. 00181 space_dim += m; 00182 00183 // Note: we do not check for satisfiability, because the system of 00184 // constraints may be unsatisfiable. 00185 PPL_ASSERT_HEAVY(OK()); 00186 } 00187 00188 void 00189 PPL::Polyhedron::add_space_dimensions_and_project(dimension_type m) { 00190 // The space dimension of the resulting polyhedron should not 00191 // overflow the maximum allowed space dimension. 00192 check_space_dimension_overflow(m, max_space_dimension() - space_dimension(), 00193 topology(), 00194 "add_space_dimensions_and_project(m)", 00195 "adding m new space dimensions exceeds " 00196 "the maximum allowed space dimension"); 00197 00198 // Adding no dimensions to any polyhedron is a no-op. 00199 if (m == 0) 00200 return; 00201 00202 // Adding dimensions to an empty polyhedron is obtained 00203 // by merely adjusting `space_dim'. 00204 if (marked_empty()) { 00205 space_dim += m; 00206 con_sys.clear(); 00207 return; 00208 } 00209 00210 if (space_dim == 0) { 00211 PPL_ASSERT(status.test_zero_dim_univ() && gen_sys.has_no_rows()); 00212 // The system of generators for this polyhedron has only 00213 // the origin as a point. 00214 // In an NNC polyhedron, all points have to be accompanied 00215 // by the corresponding closure points 00216 // (this time, dimensions are automatically adjusted). 00217 if (!is_necessarily_closed()) 00218 gen_sys.insert(Generator::zero_dim_closure_point()); 00219 gen_sys.insert(Generator::zero_dim_point()); 00220 gen_sys.adjust_topology_and_space_dimension(topology(), m); 00221 set_generators_minimized(); 00222 space_dim = m; 00223 PPL_ASSERT_HEAVY(OK()); 00224 return; 00225 } 00226 00227 // To project an n-dimension space polyhedron in a (n+m)-dimension space, 00228 // we just add to the system of generators `m' zero-columns; 00229 // In contrast, in the system of constraints, new rows are needed 00230 // in order to avoid embedding the old polyhedron in the new space. 00231 // Thus, for each new dimensions `x[k]', we add the constraint 00232 // x[k] = 0: this is done by invoking the function add_space_dimensions() 00233 // giving the system of constraints as the second argument. 00234 if (constraints_are_up_to_date()) 00235 if (generators_are_up_to_date()) { 00236 // `sat_g' must be up to date for add_space_dimensions(). 00237 if (!sat_g_is_up_to_date()) 00238 update_sat_g(); 00239 // Adds rows and/or columns to both matrices. 00240 // `add_space_dimensions()' correctly handles pending constraints 00241 // or generators. 00242 add_space_dimensions(gen_sys, con_sys, sat_g, sat_c, m); 00243 } 00244 else { 00245 // Only constraints are up-to-date: no need to modify the generators. 00246 con_sys.add_rows_and_columns(m); 00247 // The polyhedron does not support pending constraints. 00248 con_sys.unset_pending_rows(); 00249 // If the polyhedron is not necessarily closed, 00250 // move the epsilon coefficients to the last column. 00251 if (!is_necessarily_closed()) { 00252 // Try to preserve sortedness of `con_sys'. 00253 if (!con_sys.is_sorted()) 00254 con_sys.swap_columns(space_dim + 1, space_dim + 1 + m); 00255 else { 00256 using std::swap; 00257 dimension_type old_eps_index = space_dim + 1; 00258 dimension_type new_eps_index = old_eps_index + m; 00259 for (dimension_type i = con_sys.num_rows(); i-- > m; ) { 00260 Constraint& r = con_sys[i]; 00261 swap(r[old_eps_index], r[new_eps_index]); 00262 } 00263 // The upper-right corner of `con_sys' contains the J matrix: 00264 // swap coefficients to preserve sortedness. 00265 for (dimension_type i = m; i-- > 0; ++old_eps_index) { 00266 Constraint& r = con_sys[i]; 00267 swap(r[old_eps_index], r[old_eps_index + 1]); 00268 } 00269 } 00270 } 00271 } 00272 else { 00273 // Only generators are up-to-date: no need to modify the constraints. 00274 PPL_ASSERT(generators_are_up_to_date()); 00275 gen_sys.add_zero_columns(m); 00276 // If the polyhedron is not necessarily closed, 00277 // move the epsilon coefficients to the last column. 00278 if (!is_necessarily_closed()) 00279 gen_sys.swap_columns(space_dim + 1, space_dim + 1 + m); 00280 } 00281 // Now we update the space dimension. 00282 space_dim += m; 00283 00284 // Note: we do not check for satisfiability, because the system of 00285 // constraints may be unsatisfiable. 00286 PPL_ASSERT_HEAVY(OK()); 00287 } 00288 00289 void 00290 PPL::Polyhedron::concatenate_assign(const Polyhedron& y) { 00291 if (topology() != y.topology()) 00292 throw_topology_incompatible("concatenate_assign(y)", "y", y); 00293 00294 // The space dimension of the resulting polyhedron should not 00295 // overflow the maximum allowed space dimension. 00296 const dimension_type added_columns = y.space_dim; 00297 check_space_dimension_overflow(added_columns, 00298 max_space_dimension() - space_dimension(), 00299 topology(), 00300 "concatenate_assign(y)", 00301 "concatenation exceeds the maximum " 00302 "allowed space dimension"); 00303 00304 // If `*this' or `y' are empty polyhedra, it is sufficient to adjust 00305 // the dimension of the space. 00306 if (marked_empty() || y.marked_empty()) { 00307 space_dim += added_columns; 00308 set_empty(); 00309 return; 00310 } 00311 00312 // If `y' is a non-empty 0-dim space polyhedron, the result is `*this'. 00313 if (added_columns == 0) 00314 return; 00315 00316 // If `*this' is a non-empty 0-dim space polyhedron, the result is `y'. 00317 if (space_dim == 0) { 00318 *this = y; 00319 return; 00320 } 00321 00322 // TODO: this implementation is just an executable specification. 00323 Constraint_System cs = y.constraints(); 00324 00325 // The constraints of `x' (possibly with pending rows) are required. 00326 if (has_pending_generators()) 00327 process_pending_generators(); 00328 else if (!constraints_are_up_to_date()) 00329 update_constraints(); 00330 00331 // The matrix for the new system of constraints is obtained 00332 // by leaving the old system of constraints in the upper left-hand side 00333 // and placing the constraints of `cs' in the lower right-hand side. 00334 // NOTE: here topologies agree, whereas dimensions may not agree. 00335 dimension_type old_num_rows = con_sys.num_rows(); 00336 dimension_type old_num_columns = con_sys.num_columns(); 00337 dimension_type added_rows = cs.num_rows(); 00338 00339 // We already dealt with the cases of an empty or zero-dim `y' polyhedron; 00340 // also, `cs' contains the low-level constraints, at least. 00341 PPL_ASSERT(added_rows > 0 && added_columns > 0); 00342 00343 con_sys.add_zero_rows_and_columns(added_rows, added_columns, 00344 Linear_Row::Flags(topology(), 00345 Linear_Row::RAY_OR_POINT_OR_INEQUALITY)); 00346 // Move the epsilon coefficient to the last column, if needed. 00347 if (!is_necessarily_closed()) 00348 con_sys.swap_columns(old_num_columns - 1, 00349 old_num_columns - 1 + added_columns); 00350 dimension_type cs_num_columns = cs.num_columns(); 00351 // Steal the constraints from `cs' and put them in `con_sys' 00352 // using the right displacement for coefficients. 00353 for (dimension_type i = added_rows; i-- > 0; ) { 00354 Constraint& c_old = cs[i]; 00355 Constraint& c_new = con_sys[old_num_rows + i]; 00356 // Method `add_zero_rows_and_columns', by default, added inequalities. 00357 if (c_old.is_equality()) 00358 c_new.set_is_equality(); 00359 // The inhomogeneous term is not displaced. 00360 using std::swap; 00361 swap(c_new[0], c_old[0]); 00362 // All homogeneous terms (included the epsilon coefficient, 00363 // if present) are displaced by `space_dim' columns. 00364 for (dimension_type j = 1; j < cs_num_columns; ++j) 00365 swap(c_old[j], c_new[space_dim + j]); 00366 } 00367 00368 if (can_have_something_pending()) { 00369 // If `*this' can support pending constraints, then, since we have 00370 // resized the system of constraints, we must also add to the generator 00371 // system those lines corresponding to the newly added dimensions, 00372 // because the non-pending parts of `con_sys' and `gen_sys' must still 00373 // be a DD pair in minimal form. 00374 gen_sys.add_rows_and_columns(added_columns); 00375 gen_sys.set_sorted(false); 00376 if (!is_necessarily_closed()) 00377 gen_sys.swap_columns(old_num_columns - 1, 00378 old_num_columns - 1 + added_columns); 00379 // The added lines are not pending. 00380 gen_sys.unset_pending_rows(); 00381 // Since we added new lines at the beginning of `x.gen_sys', 00382 // we also have to adjust the saturation matrix `sat_c'. 00383 // FIXME: if `sat_c' is not up-to-date, could not we directly update 00384 // `sat_g' by resizing it and shifting its columns? 00385 if (!sat_c_is_up_to_date()) { 00386 sat_c.transpose_assign(sat_g); 00387 set_sat_c_up_to_date(); 00388 } 00389 clear_sat_g_up_to_date(); 00390 sat_c.resize(sat_c.num_rows() + added_columns, sat_c.num_columns()); 00391 // The old saturation rows are copied at the end of the matrix. 00392 // The newly introduced lines saturate all the non-pending constraints, 00393 // thus their saturation rows are made of zeroes. 00394 using std::swap; 00395 for (dimension_type i = sat_c.num_rows() - added_columns; i-- > 0; ) 00396 swap(sat_c[i], sat_c[i+added_columns]); 00397 // Since `added_rows > 0', we now have pending constraints. 00398 set_constraints_pending(); 00399 } 00400 else { 00401 // The polyhedron cannot have pending constraints. 00402 con_sys.unset_pending_rows(); 00403 #if BE_LAZY 00404 con_sys.set_sorted(false); 00405 #else 00406 con_sys.sort_rows(); 00407 #endif 00408 clear_constraints_minimized(); 00409 clear_generators_up_to_date(); 00410 clear_sat_g_up_to_date(); 00411 clear_sat_c_up_to_date(); 00412 } 00413 // Update space dimension. 00414 space_dim += added_columns; 00415 00416 // The system of constraints may be unsatisfiable, 00417 // thus we do not check for satisfiability. 00418 PPL_ASSERT_HEAVY(OK()); 00419 } 00420 00421 void 00422 PPL::Polyhedron::remove_space_dimensions(const Variables_Set& vars) { 00423 // The removal of no dimensions from any polyhedron is a no-op. 00424 // Note that this case also captures the only legal removal of 00425 // dimensions from a polyhedron in a 0-dim space. 00426 if (vars.empty()) { 00427 PPL_ASSERT_HEAVY(OK()); 00428 return; 00429 } 00430 00431 // Dimension-compatibility check. 00432 const dimension_type min_space_dim = vars.space_dimension(); 00433 if (space_dim < min_space_dim) 00434 throw_dimension_incompatible("remove_space_dimensions(vs)", min_space_dim); 00435 00436 const dimension_type new_space_dim = space_dim - vars.size(); 00437 00438 // We need updated generators; note that keeping pending generators 00439 // is useless because the constraints will be dropped anyway. 00440 if (marked_empty() 00441 || (has_something_pending() && !remove_pending_to_obtain_generators()) 00442 || (!generators_are_up_to_date() && !update_generators())) { 00443 // Removing dimensions from the empty polyhedron: 00444 // we clear `con_sys' since it could have contained the 00445 // unsatisfiable constraint of the wrong dimension. 00446 con_sys.clear(); 00447 // Update the space dimension. 00448 space_dim = new_space_dim; 00449 PPL_ASSERT_HEAVY(OK()); 00450 return; 00451 } 00452 00453 // When removing _all_ dimensions from a non-empty polyhedron, 00454 // we obtain the zero-dimensional universe polyhedron. 00455 if (new_space_dim == 0) { 00456 set_zero_dim_univ(); 00457 return; 00458 } 00459 00460 // For each variable to be removed, we fill the corresponding column 00461 // by shifting left those columns that will not be removed. 00462 Variables_Set::const_iterator vsi = vars.begin(); 00463 Variables_Set::const_iterator vsi_end = vars.end(); 00464 dimension_type dst_col = *vsi + 1; 00465 dimension_type src_col = dst_col + 1; 00466 for (++vsi; vsi != vsi_end; ++vsi) { 00467 const dimension_type vsi_col = *vsi + 1; 00468 // All columns in between are moved to the left. 00469 while (src_col < vsi_col) 00470 gen_sys.Dense_Matrix::swap_columns(dst_col++, src_col++); 00471 ++src_col; 00472 } 00473 // Moving the remaining columns. 00474 const dimension_type gen_sys_num_columns = gen_sys.num_columns(); 00475 while (src_col < gen_sys_num_columns) 00476 gen_sys.Dense_Matrix::swap_columns(dst_col++, src_col++); 00477 00478 // The number of remaining columns is `dst_col'. 00479 // Note that resizing also calls `set_sorted(false)'. 00480 gen_sys.remove_trailing_columns(gen_sys_num_columns - dst_col); 00481 // We may have invalid lines and rays now. 00482 gen_sys.remove_invalid_lines_and_rays(); 00483 00484 // Constraints are not up-to-date and generators are not minimized. 00485 clear_constraints_up_to_date(); 00486 clear_generators_minimized(); 00487 00488 // Update the space dimension. 00489 space_dim = new_space_dim; 00490 00491 PPL_ASSERT_HEAVY(OK(true)); 00492 } 00493 00494 void 00495 PPL::Polyhedron::remove_higher_space_dimensions(dimension_type new_dimension) { 00496 // Dimension-compatibility check. 00497 if (new_dimension > space_dim) 00498 throw_dimension_incompatible("remove_higher_space_dimensions(nd)", 00499 new_dimension); 00500 00501 // The removal of no dimensions from any polyhedron is a no-op. 00502 // Note that this case also captures the only legal removal of 00503 // dimensions from a polyhedron in a 0-dim space. 00504 if (new_dimension == space_dim) { 00505 PPL_ASSERT_HEAVY(OK()); 00506 return; 00507 } 00508 00509 // We need updated generators; note that keeping pending generators 00510 // is useless because constraints will be dropped anyway. 00511 if (marked_empty() 00512 || (has_something_pending() && !remove_pending_to_obtain_generators()) 00513 || (!generators_are_up_to_date() && !update_generators())) { 00514 // Removing dimensions from the empty polyhedron: 00515 // just updates the space dimension. 00516 space_dim = new_dimension; 00517 con_sys.clear(); 00518 PPL_ASSERT_HEAVY(OK()); 00519 return; 00520 } 00521 00522 if (new_dimension == 0) { 00523 // Removing all dimensions from a non-empty polyhedron: 00524 // just return the zero-dimensional universe polyhedron. 00525 set_zero_dim_univ(); 00526 return; 00527 } 00528 00529 dimension_type new_num_cols = new_dimension + 1; 00530 if (!is_necessarily_closed()) { 00531 // The polyhedron is not necessarily closed: move the column 00532 // of the epsilon coefficients to its new place. 00533 gen_sys.swap_columns(gen_sys.num_columns() - 1, new_num_cols); 00534 // The number of remaining columns is `new_dimension + 2'. 00535 ++new_num_cols; 00536 } 00537 // Note that resizing also calls `set_sorted(false)'. 00538 gen_sys.remove_trailing_columns(space_dim - new_dimension); 00539 // We may have invalid lines and rays now. 00540 gen_sys.remove_invalid_lines_and_rays(); 00541 00542 // Constraints are not up-to-date and generators are not minimized. 00543 clear_constraints_up_to_date(); 00544 clear_generators_minimized(); 00545 00546 // Update the space dimension. 00547 space_dim = new_dimension; 00548 00549 PPL_ASSERT_HEAVY(OK(true)); 00550 } 00551 00552 void 00553 PPL::Polyhedron::expand_space_dimension(Variable var, dimension_type m) { 00554 // TODO: this implementation is _really_ an executable specification. 00555 00556 // `var' should be one of the dimensions of the vector space. 00557 if (var.space_dimension() > space_dim) 00558 throw_dimension_incompatible("expand_space_dimension(v, m)", "v", var); 00559 00560 // The space dimension of the resulting polyhedron should not 00561 // overflow the maximum allowed space dimension. 00562 check_space_dimension_overflow(m, max_space_dimension() - space_dimension(), 00563 topology(), 00564 "expand_dimension(v, m)", 00565 "adding m new space dimensions exceeds " 00566 "the maximum allowed space dimension"); 00567 00568 // Nothing to do, if no dimensions must be added. 00569 if (m == 0) 00570 return; 00571 00572 // Keep track of the dimension before adding the new ones. 00573 dimension_type old_dim = space_dim; 00574 00575 // Add the required new dimensions. 00576 add_space_dimensions_and_embed(m); 00577 00578 const dimension_type src_d = var.id(); 00579 const Constraint_System& cs = constraints(); 00580 Constraint_System new_constraints; 00581 for (Constraint_System::const_iterator i = cs.begin(), 00582 cs_end = cs.end(); i != cs_end; ++i) { 00583 const Constraint& c = *i; 00584 00585 // If `c' does not constrain `var', skip it. 00586 if (c.coefficient(var) == 0) 00587 continue; 00588 00589 // Each relevant constraint results in `m' new constraints. 00590 for (dimension_type dst_d = old_dim; dst_d < old_dim+m; ++dst_d) { 00591 Linear_Expression e; 00592 for (dimension_type j = old_dim; j-- > 0; ) 00593 e += 00594 c.coefficient(Variable(j)) 00595 * ((j == src_d) ? Variable(dst_d) : Variable(j)); 00596 e += c.inhomogeneous_term(); 00597 new_constraints.insert(c.is_equality() 00598 ? (e == 0) 00599 : (c.is_nonstrict_inequality() 00600 ? (e >= 0) 00601 : (e > 0))); 00602 } 00603 } 00604 add_recycled_constraints(new_constraints); 00605 PPL_ASSERT_HEAVY(OK()); 00606 } 00607 00608 void 00609 PPL::Polyhedron::fold_space_dimensions(const Variables_Set& vars, 00610 Variable dest) { 00611 // TODO: this implementation is _really_ an executable specification. 00612 00613 // `dest' should be one of the dimensions of the polyhedron. 00614 if (dest.space_dimension() > space_dim) 00615 throw_dimension_incompatible("fold_space_dimensions(vs, v)", "v", dest); 00616 00617 // The folding of no dimensions is a no-op. 00618 if (vars.empty()) 00619 return; 00620 00621 // All variables in `vars' should be dimensions of the polyhedron. 00622 if (vars.space_dimension() > space_dim) 00623 throw_dimension_incompatible("fold_space_dimensions(vs, v)", 00624 "vs.space_dimension()", 00625 vars.space_dimension()); 00626 00627 // Moreover, `dest.id()' should not occur in `vars'. 00628 if (vars.find(dest.id()) != vars.end()) 00629 throw_invalid_argument("fold_space_dimensions(vs, v)", 00630 "v should not occur in vs"); 00631 00632 // All of the affine images we are going to compute are not invertible, 00633 // hence we will need to compute the generators of the polyhedron. 00634 // Since we keep taking copies, make sure that a single conversion 00635 // from constraints to generators is computed. 00636 (void) generators(); 00637 // Having generators, we now know if the polyhedron is empty: 00638 // in that case, folding is equivalent to just removing space dimensions. 00639 if (!marked_empty()) { 00640 for (Variables_Set::const_iterator i = vars.begin(), 00641 vs_end = vars.end(); i != vs_end; ++i) { 00642 Polyhedron copy = *this; 00643 copy.affine_image(dest, Linear_Expression(Variable(*i))); 00644 poly_hull_assign(copy); 00645 } 00646 } 00647 remove_space_dimensions(vars); 00648 PPL_ASSERT_HEAVY(OK()); 00649 }