|
PPL
0.12.1
|
00001 /* Generator_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 "Generator_System.defs.hh" 00026 #include "Generator_System.inlines.hh" 00027 #include "Constraint.defs.hh" 00028 #include "Scalar_Products.defs.hh" 00029 #include "assert.hh" 00030 #include <string> 00031 #include <vector> 00032 #include <iostream> 00033 #include <stdexcept> 00034 00035 namespace PPL = Parma_Polyhedra_Library; 00036 00037 bool 00038 PPL::Generator_System:: 00039 adjust_topology_and_space_dimension(const Topology new_topology, 00040 const dimension_type new_space_dim) { 00041 PPL_ASSERT(space_dimension() <= new_space_dim); 00042 00043 const dimension_type old_space_dim = space_dimension(); 00044 const Topology old_topology = topology(); 00045 dimension_type cols_to_be_added = new_space_dim - old_space_dim; 00046 00047 // Dealing with empty generator systems first. 00048 if (has_no_rows()) { 00049 if (num_columns() == 0) 00050 if (new_topology == NECESSARILY_CLOSED) { 00051 add_zero_columns(cols_to_be_added + 1); 00052 set_necessarily_closed(); 00053 } 00054 else { 00055 add_zero_columns(cols_to_be_added + 2); 00056 set_not_necessarily_closed(); 00057 } 00058 else 00059 // Here `num_columns() > 0'. 00060 if (old_topology != new_topology) 00061 if (new_topology == NECESSARILY_CLOSED) { 00062 switch (cols_to_be_added) { 00063 case 0: 00064 remove_trailing_columns(1); 00065 break; 00066 case 1: 00067 // Nothing to do. 00068 break; 00069 default: 00070 add_zero_columns(cols_to_be_added - 1); 00071 } 00072 set_necessarily_closed(); 00073 } 00074 else { 00075 // Here old_topology == NECESSARILY_CLOSED 00076 // and new_topology == NOT_NECESSARILY_CLOSED. 00077 add_zero_columns(cols_to_be_added + 1); 00078 set_not_necessarily_closed(); 00079 } 00080 else 00081 // Here topologies agree. 00082 if (cols_to_be_added > 0) 00083 add_zero_columns(cols_to_be_added); 00084 PPL_ASSERT(OK()); 00085 return true; 00086 } 00087 00088 // Here the generator system is not empty. 00089 if (cols_to_be_added > 0) 00090 if (old_topology != new_topology) 00091 if (new_topology == NECESSARILY_CLOSED) { 00092 // A NOT_NECESSARILY_CLOSED generator system 00093 // can be converted to a NECESSARILY_CLOSED one 00094 // only if it does not contain closure points. 00095 // This check has to be performed under the user viewpoint. 00096 if (has_closure_points()) 00097 return false; 00098 // For a correct implementation, we have to remove those 00099 // closure points that were matching a point (i.e., those 00100 // that are in the generator system, but are invisible to 00101 // the user). 00102 Generator_System& gs = *this; 00103 dimension_type num_closure_points = 0; 00104 dimension_type gs_end = gs.num_rows(); 00105 for (dimension_type i = 0; i < gs_end; ) { 00106 // All the closure points seen so far have consecutive 00107 // indices starting from `i'. 00108 if (num_closure_points > 0) { 00109 // Let next generator have index `i'. 00110 using std::swap; 00111 swap(gs[i], gs[i+num_closure_points]); 00112 } 00113 if (gs[i].is_closure_point()) { 00114 ++num_closure_points; 00115 --gs_end; 00116 } 00117 else 00118 ++i; 00119 } 00120 // We may have identified some closure points. 00121 if (num_closure_points > 0) { 00122 PPL_ASSERT(num_closure_points == num_rows() - gs_end); 00123 remove_trailing_rows(num_closure_points); 00124 } 00125 // Remove the epsilon column, re-normalize and, after that, 00126 // add the missing dimensions. This ensures that 00127 // non-zero epsilon coefficients will be cleared. 00128 remove_trailing_columns(1); 00129 set_necessarily_closed(); 00130 normalize(); 00131 add_zero_columns(cols_to_be_added); 00132 } 00133 else { 00134 // A NECESSARILY_CLOSED generator system is converted to 00135 // a NOT_NECESSARILY_CLOSED one by adding a further column 00136 // and setting the epsilon coordinate of all points to 1. 00137 // Note: normalization is preserved. 00138 add_zero_columns(cols_to_be_added + 1); 00139 Generator_System& gs = *this; 00140 const dimension_type eps_index = new_space_dim + 1; 00141 for (dimension_type i = num_rows(); i-- > 0; ) 00142 gs[i][eps_index] = gs[i][0]; 00143 set_not_necessarily_closed(); 00144 } 00145 else { 00146 // Topologies agree: first add the required zero columns ... 00147 add_zero_columns(cols_to_be_added); 00148 // ... and, if needed, move the epsilon coefficients 00149 // to the new last column. 00150 if (old_topology == NOT_NECESSARILY_CLOSED) 00151 swap_columns(old_space_dim + 1, new_space_dim + 1); 00152 } 00153 else 00154 // Here `cols_to_be_added == 0'. 00155 if (old_topology != new_topology) { 00156 if (new_topology == NECESSARILY_CLOSED) { 00157 // A NOT_NECESSARILY_CLOSED generator system 00158 // can be converted in to a NECESSARILY_CLOSED one 00159 // only if it does not contain closure points. 00160 if (has_closure_points()) 00161 return false; 00162 // We just remove the column of the epsilon coefficients. 00163 remove_trailing_columns(1); 00164 set_necessarily_closed(); 00165 } 00166 else { 00167 // Add the column of the epsilon coefficients 00168 // and set the epsilon coordinate of all points to 1. 00169 // Note: normalization is preserved. 00170 add_zero_columns(1); 00171 Generator_System& gs = *this; 00172 const dimension_type eps_index = new_space_dim + 1; 00173 for (dimension_type i = num_rows(); i-- > 0; ) 00174 gs[i][eps_index] = gs[i][0]; 00175 set_not_necessarily_closed(); 00176 } 00177 } 00178 // We successfully adjusted dimensions and topology. 00179 PPL_ASSERT(OK()); 00180 return true; 00181 } 00182 00183 // TODO: would be worth to avoid adding closure points 00184 // that already are in the system of generators? 00185 // To do this efficiently we could sort the system and 00186 // perform insertions keeping its sortedness. 00187 void 00188 PPL::Generator_System::add_corresponding_closure_points() { 00189 PPL_ASSERT(!is_necessarily_closed()); 00190 // NOTE: we always add (pending) rows at the end of the generator system. 00191 // Updating `index_first_pending', if needed, is done by the caller. 00192 Generator_System& gs = *this; 00193 const dimension_type n_rows = gs.num_rows(); 00194 const dimension_type eps_index = gs.num_columns() - 1; 00195 for (dimension_type i = n_rows; i-- > 0; ) { 00196 const Generator& g = gs[i]; 00197 if (g[eps_index] > 0) { 00198 // `g' is a point: adding the closure point. 00199 Generator cp = g; 00200 cp[eps_index] = 0; 00201 // Enforcing normalization. 00202 cp.normalize(); 00203 gs.add_pending_row(cp); 00204 } 00205 } 00206 PPL_ASSERT(OK()); 00207 } 00208 00209 00210 // TODO: would be worth to avoid adding points 00211 // that already are in the system of generators? 00212 // To do this efficiently we could sort the system and 00213 // perform insertions keeping its sortedness. 00214 void 00215 PPL::Generator_System::add_corresponding_points() { 00216 PPL_ASSERT(!is_necessarily_closed()); 00217 // NOTE: we always add (pending) rows at the end of the generator system. 00218 // Updating `index_first_pending', if needed, is done by the caller. 00219 Generator_System& gs = *this; 00220 const dimension_type n_rows = gs.num_rows(); 00221 const dimension_type eps_index = gs.num_columns() - 1; 00222 for (dimension_type i = 0; i < n_rows; i++) { 00223 const Generator& g = gs[i]; 00224 if (!g.is_line_or_ray() && g[eps_index] == 0) { 00225 // `g' is a closure point: adding the point. 00226 // Note: normalization is preserved. 00227 Generator p = g; 00228 p[eps_index] = p[0]; 00229 gs.add_pending_row(p); 00230 } 00231 } 00232 PPL_ASSERT(OK()); 00233 } 00234 00235 bool 00236 PPL::Generator_System::has_closure_points() const { 00237 if (is_necessarily_closed()) 00238 return false; 00239 // Adopt the point of view of the user. 00240 for (Generator_System::const_iterator i = begin(), 00241 this_end = end(); i != this_end; ++i) 00242 if (i->is_closure_point()) 00243 return true; 00244 return false; 00245 } 00246 00247 bool 00248 PPL::Generator_System::has_points() const { 00249 const Generator_System& gs = *this; 00250 // Avoiding the repeated tests on topology. 00251 if (is_necessarily_closed()) 00252 for (dimension_type i = num_rows(); i-- > 0; ) { 00253 if (!gs[i].is_line_or_ray()) 00254 return true; 00255 } 00256 else { 00257 // !is_necessarily_closed() 00258 const dimension_type eps_index = gs.num_columns() - 1; 00259 for (dimension_type i = num_rows(); i-- > 0; ) 00260 if (gs[i][eps_index] != 0) 00261 return true; 00262 } 00263 return false; 00264 } 00265 00266 void 00267 PPL::Generator_System::const_iterator::skip_forward() { 00268 const Linear_System::const_iterator gsp_end = gsp->end(); 00269 if (i != gsp_end) { 00270 Linear_System::const_iterator i_next = i; 00271 ++i_next; 00272 if (i_next != gsp_end) { 00273 const Generator& cp = static_cast<const Generator&>(*i); 00274 const Generator& p = static_cast<const Generator&>(*i_next); 00275 if (cp.is_closure_point() 00276 && p.is_point() 00277 && cp.is_matching_closure_point(p)) 00278 i = i_next; 00279 } 00280 } 00281 } 00282 00283 void 00284 PPL::Generator_System::insert(const Generator& g) { 00285 // We are sure that the matrix has no pending rows 00286 // and that the new row is not a pending generator. 00287 PPL_ASSERT(num_pending_rows() == 0); 00288 if (topology() == g.topology()) 00289 Linear_System::insert(g); 00290 else 00291 // `*this' and `g' have different topologies. 00292 if (is_necessarily_closed()) { 00293 // Padding the matrix with the column 00294 // corresponding to the epsilon coefficients: 00295 // all points must have epsilon coordinate equal to 1 00296 // (i.e., the epsilon coefficient is equal to the divisor); 00297 // rays and lines must have epsilon coefficient equal to 0. 00298 // Note: normalization is preserved. 00299 const dimension_type eps_index = num_columns(); 00300 add_zero_columns(1); 00301 Generator_System& gs = *this; 00302 for (dimension_type i = num_rows(); i-- > 0; ) { 00303 Generator& gen = gs[i]; 00304 if (!gen.is_line_or_ray()) 00305 gen[eps_index] = gen[0]; 00306 } 00307 set_not_necessarily_closed(); 00308 // Inserting the new generator. 00309 Linear_System::insert(g); 00310 } 00311 else { 00312 // The generator system is NOT necessarily closed: 00313 // copy the generator, adding the missing dimensions 00314 // and the epsilon coefficient. 00315 const dimension_type new_size = 2 + std::max(g.space_dimension(), 00316 space_dimension()); 00317 Generator tmp_g(g, new_size); 00318 // If it was a point, set the epsilon coordinate to 1 00319 // (i.e., set the coefficient equal to the divisor). 00320 // Note: normalization is preserved. 00321 if (!tmp_g.is_line_or_ray()) 00322 tmp_g[new_size - 1] = tmp_g[0]; 00323 tmp_g.set_not_necessarily_closed(); 00324 // Inserting the new generator. 00325 Linear_System::insert(tmp_g); 00326 } 00327 PPL_ASSERT(OK()); 00328 } 00329 00330 void 00331 PPL::Generator_System::insert_pending(const Generator& g) { 00332 if (topology() == g.topology()) 00333 Linear_System::insert_pending(g); 00334 else 00335 // `*this' and `g' have different topologies. 00336 if (is_necessarily_closed()) { 00337 // Padding the matrix with the column 00338 // corresponding to the epsilon coefficients: 00339 // all points must have epsilon coordinate equal to 1 00340 // (i.e., the epsilon coefficient is equal to the divisor); 00341 // rays and lines must have epsilon coefficient equal to 0. 00342 // Note: normalization is preserved. 00343 const dimension_type eps_index = num_columns(); 00344 add_zero_columns(1); 00345 Generator_System& gs = *this; 00346 for (dimension_type i = num_rows(); i-- > 0; ) { 00347 Generator& gen = gs[i]; 00348 if (!gen.is_line_or_ray()) 00349 gen[eps_index] = gen[0]; 00350 } 00351 set_not_necessarily_closed(); 00352 // Inserting the new generator. 00353 Linear_System::insert_pending(g); 00354 } 00355 else { 00356 // The generator system is NOT necessarily closed: 00357 // copy the generator, adding the missing dimensions 00358 // and the epsilon coefficient. 00359 const dimension_type new_size = 2 + std::max(g.space_dimension(), 00360 space_dimension()); 00361 Generator tmp_g(g, new_size); 00362 // If it was a point, set the epsilon coordinate to 1 00363 // (i.e., set the coefficient equal to the divisor). 00364 // Note: normalization is preserved. 00365 if (!tmp_g.is_line_or_ray()) 00366 tmp_g[new_size - 1] = tmp_g[0]; 00367 tmp_g.set_not_necessarily_closed(); 00368 // Inserting the new generator. 00369 Linear_System::insert_pending(tmp_g); 00370 } 00371 PPL_ASSERT(OK()); 00372 } 00373 00374 PPL::dimension_type 00375 PPL::Generator_System::num_lines() const { 00376 // We are sure that this method is applied only to a matrix 00377 // that does not contain pending rows. 00378 PPL_ASSERT(num_pending_rows() == 0); 00379 const Generator_System& gs = *this; 00380 dimension_type n = 0; 00381 // If the Linear_System happens to be sorted, take advantage of the fact 00382 // that lines are at the top of the system. 00383 if (is_sorted()) { 00384 dimension_type nrows = num_rows(); 00385 for (dimension_type i = 0; i < nrows && gs[i].is_line(); ++i) 00386 ++n; 00387 } 00388 else 00389 for (dimension_type i = num_rows(); i-- > 0 ; ) 00390 if (gs[i].is_line()) 00391 ++n; 00392 return n; 00393 } 00394 00395 PPL::dimension_type 00396 PPL::Generator_System::num_rays() const { 00397 // We are sure that this method is applied only to a matrix 00398 // that does not contain pending rows. 00399 PPL_ASSERT(num_pending_rows() == 0); 00400 const Generator_System& gs = *this; 00401 dimension_type n = 0; 00402 // If the Linear_System happens to be sorted, take advantage of the fact 00403 // that rays and points are at the bottom of the system and 00404 // rays have the inhomogeneous term equal to zero. 00405 if (is_sorted()) { 00406 for (dimension_type i = num_rows(); i != 0 && gs[--i].is_ray_or_point(); ) 00407 if (gs[i].is_line_or_ray()) 00408 ++n; 00409 } 00410 else 00411 for (dimension_type i = num_rows(); i-- > 0 ; ) 00412 if (gs[i].is_ray()) 00413 ++n; 00414 return n; 00415 } 00416 00417 PPL::Poly_Con_Relation 00418 PPL::Generator_System::relation_with(const Constraint& c) const { 00419 // Note: this method is not public and it is the responsibility 00420 // of the caller to actually test for dimension compatibility. 00421 // We simply assert it. 00422 PPL_ASSERT(space_dimension() >= c.space_dimension()); 00423 // Number of generators: the case of an empty polyhedron 00424 // has already been filtered out by the caller. 00425 const dimension_type n_rows = num_rows(); 00426 PPL_ASSERT(n_rows > 0); 00427 const Generator_System& gs = *this; 00428 00429 // `result' will keep the relation holding between the generators 00430 // we have seen so far and the constraint `c'. 00431 Poly_Con_Relation result = Poly_Con_Relation::saturates(); 00432 00433 switch (c.type()) { 00434 00435 case Constraint::EQUALITY: 00436 { 00437 // The hyperplane defined by the equality `c' is included 00438 // in the set of points satisfying `c' (it is the same set!). 00439 result = result && Poly_Con_Relation::is_included(); 00440 // The following integer variable will hold the scalar product sign 00441 // of either the first point or the first non-saturating ray we find. 00442 // If it is equal to 2, then it means that we haven't found such 00443 // a generator yet. 00444 int first_point_or_nonsaturating_ray_sign = 2; 00445 00446 for (dimension_type i = n_rows; i-- > 0; ) { 00447 const Generator& g = gs[i]; 00448 const int sp_sign = Scalar_Products::sign(c, g); 00449 // Checking whether the generator saturates the equality. 00450 // If that is the case, then we have to do something only if 00451 // the generator is a point. 00452 if (sp_sign == 0) { 00453 if (g.is_point()) { 00454 if (first_point_or_nonsaturating_ray_sign == 2) 00455 // It is the first time that we find a point and 00456 // we have not found a non-saturating ray yet. 00457 first_point_or_nonsaturating_ray_sign = 0; 00458 else 00459 // We already found a point or a non-saturating ray. 00460 if (first_point_or_nonsaturating_ray_sign != 0) 00461 return Poly_Con_Relation::strictly_intersects(); 00462 } 00463 } 00464 else 00465 // Here we know that sp_sign != 0. 00466 switch (g.type()) { 00467 00468 case Generator::LINE: 00469 // If a line does not saturate `c', then there is a strict 00470 // intersection between the points satisfying `c' 00471 // and the points generated by `gs'. 00472 return Poly_Con_Relation::strictly_intersects(); 00473 00474 case Generator::RAY: 00475 if (first_point_or_nonsaturating_ray_sign == 2) { 00476 // It is the first time that we have a non-saturating ray 00477 // and we have not found any point yet. 00478 first_point_or_nonsaturating_ray_sign = sp_sign; 00479 result = Poly_Con_Relation::is_disjoint(); 00480 } 00481 else 00482 // We already found a point or a non-saturating ray. 00483 if (sp_sign != first_point_or_nonsaturating_ray_sign) 00484 return Poly_Con_Relation::strictly_intersects(); 00485 break; 00486 00487 case Generator::POINT: 00488 case Generator::CLOSURE_POINT: 00489 // NOTE: a non-saturating closure point is treated as 00490 // a normal point. 00491 if (first_point_or_nonsaturating_ray_sign == 2) { 00492 // It is the first time that we find a point and 00493 // we have not found a non-saturating ray yet. 00494 first_point_or_nonsaturating_ray_sign = sp_sign; 00495 result = Poly_Con_Relation::is_disjoint(); 00496 } 00497 else 00498 // We already found a point or a non-saturating ray. 00499 if (sp_sign != first_point_or_nonsaturating_ray_sign) 00500 return Poly_Con_Relation::strictly_intersects(); 00501 break; 00502 } 00503 } 00504 } 00505 break; 00506 00507 case Constraint::NONSTRICT_INEQUALITY: 00508 { 00509 // The hyperplane implicitly defined by the non-strict inequality `c' 00510 // is included in the set of points satisfying `c'. 00511 result = result && Poly_Con_Relation::is_included(); 00512 // The following Boolean variable will be set to `false' 00513 // as soon as either we find (any) point or we find a 00514 // non-saturating ray. 00515 bool first_point_or_nonsaturating_ray = true; 00516 00517 for (dimension_type i = n_rows; i-- > 0; ) { 00518 const Generator& g = gs[i]; 00519 const int sp_sign = Scalar_Products::sign(c, g); 00520 // Checking whether the generator saturates the non-strict 00521 // inequality. If that is the case, then we have to do something 00522 // only if the generator is a point. 00523 if (sp_sign == 0) { 00524 if (g.is_point()) { 00525 if (first_point_or_nonsaturating_ray) 00526 // It is the first time that we have a point and 00527 // we have not found a non-saturating ray yet. 00528 first_point_or_nonsaturating_ray = false; 00529 else 00530 // We already found a point or a non-saturating ray before. 00531 if (result == Poly_Con_Relation::is_disjoint()) 00532 // Since g saturates c, we have a strict intersection if 00533 // none of the generators seen so far are included in `c'. 00534 return Poly_Con_Relation::strictly_intersects(); 00535 } 00536 } 00537 else 00538 // Here we know that sp_sign != 0. 00539 switch (g.type()) { 00540 00541 case Generator::LINE: 00542 // If a line does not saturate `c', then there is a strict 00543 // intersection between the points satisfying `c' and 00544 // the points generated by `gs'. 00545 return Poly_Con_Relation::strictly_intersects(); 00546 00547 case Generator::RAY: 00548 if (first_point_or_nonsaturating_ray) { 00549 // It is the first time that we have a non-saturating ray 00550 // and we have not found any point yet. 00551 first_point_or_nonsaturating_ray = false; 00552 result = (sp_sign > 0) 00553 ? Poly_Con_Relation::is_included() 00554 : Poly_Con_Relation::is_disjoint(); 00555 } 00556 else { 00557 // We already found a point or a non-saturating ray. 00558 if ((sp_sign > 0 00559 && result == Poly_Con_Relation::is_disjoint()) 00560 || (sp_sign < 0 00561 && result.implies(Poly_Con_Relation::is_included()))) 00562 // We have a strict intersection if either: 00563 // - `g' satisfies `c' but none of the generators seen 00564 // so far are included in `c'; or 00565 // - `g' does not satisfy `c' and all the generators 00566 // seen so far are included in `c'. 00567 return Poly_Con_Relation::strictly_intersects(); 00568 if (sp_sign > 0) 00569 // Here all the generators seen so far either saturate 00570 // or are included in `c'. 00571 // Since `g' does not saturate `c' ... 00572 result = Poly_Con_Relation::is_included(); 00573 } 00574 break; 00575 00576 case Generator::POINT: 00577 case Generator::CLOSURE_POINT: 00578 // NOTE: a non-saturating closure point is treated as 00579 // a normal point. 00580 if (first_point_or_nonsaturating_ray) { 00581 // It is the first time that we have a point and 00582 // we have not found a non-saturating ray yet. 00583 // - If point `g' saturates `c', then all the generators 00584 // seen so far saturate `c'. 00585 // - If point `g' is included (but does not saturate) `c', 00586 // then all the generators seen so far are included in `c'. 00587 // - If point `g' does not satisfy `c', then all the 00588 // generators seen so far are disjoint from `c'. 00589 first_point_or_nonsaturating_ray = false; 00590 if (sp_sign > 0) 00591 result = Poly_Con_Relation::is_included(); 00592 else if (sp_sign < 0) 00593 result = Poly_Con_Relation::is_disjoint(); 00594 } 00595 else { 00596 // We already found a point or a non-saturating ray before. 00597 if ((sp_sign > 0 00598 && result == Poly_Con_Relation::is_disjoint()) 00599 || (sp_sign < 0 00600 && result.implies(Poly_Con_Relation::is_included()))) 00601 // We have a strict intersection if either: 00602 // - `g' satisfies or saturates `c' but none of the 00603 // generators seen so far are included in `c'; or 00604 // - `g' does not satisfy `c' and all the generators 00605 // seen so far are included in `c'. 00606 return Poly_Con_Relation::strictly_intersects(); 00607 if (sp_sign > 0) 00608 // Here all the generators seen so far either saturate 00609 // or are included in `c'. 00610 // Since `g' does not saturate `c' ... 00611 result = Poly_Con_Relation::is_included(); 00612 } 00613 break; 00614 } 00615 } 00616 } 00617 break; 00618 00619 case Constraint::STRICT_INEQUALITY: 00620 { 00621 // The hyperplane implicitly defined by the strict inequality `c' 00622 // is disjoint from the set of points satisfying `c'. 00623 result = result && Poly_Con_Relation::is_disjoint(); 00624 // The following Boolean variable will be set to `false' 00625 // as soon as either we find (any) point or we find a 00626 // non-saturating ray. 00627 bool first_point_or_nonsaturating_ray = true; 00628 for (dimension_type i = n_rows; i-- > 0; ) { 00629 const Generator& g = gs[i]; 00630 // Using the reduced scalar product operator to avoid 00631 // both topology and num_columns mismatches. 00632 const int sp_sign = Scalar_Products::reduced_sign(c, g); 00633 // Checking whether the generator saturates the strict inequality. 00634 // If that is the case, then we have to do something 00635 // only if the generator is a point. 00636 if (sp_sign == 0) { 00637 if (g.is_point()) { 00638 if (first_point_or_nonsaturating_ray) 00639 // It is the first time that we have a point and 00640 // we have not found a non-saturating ray yet. 00641 first_point_or_nonsaturating_ray = false; 00642 else 00643 // We already found a point or a non-saturating ray before. 00644 if (result == Poly_Con_Relation::is_included()) 00645 return Poly_Con_Relation::strictly_intersects(); 00646 } 00647 } 00648 else 00649 // Here we know that sp_sign != 0. 00650 switch (g.type()) { 00651 00652 case Generator::LINE: 00653 // If a line does not saturate `c', then there is a strict 00654 // intersection between the points satisfying `c' and the points 00655 // generated by `gs'. 00656 return Poly_Con_Relation::strictly_intersects(); 00657 00658 case Generator::RAY: 00659 if (first_point_or_nonsaturating_ray) { 00660 // It is the first time that we have a non-saturating ray 00661 // and we have not found any point yet. 00662 first_point_or_nonsaturating_ray = false; 00663 result = (sp_sign > 0) 00664 ? Poly_Con_Relation::is_included() 00665 : Poly_Con_Relation::is_disjoint(); 00666 } 00667 else { 00668 // We already found a point or a non-saturating ray before. 00669 if ((sp_sign > 0 00670 && result.implies(Poly_Con_Relation::is_disjoint())) 00671 || 00672 (sp_sign <= 0 00673 && result == Poly_Con_Relation::is_included())) 00674 return Poly_Con_Relation::strictly_intersects(); 00675 if (sp_sign < 0) 00676 // Here all the generators seen so far either saturate 00677 // or are disjoint from `c'. 00678 // Since `g' does not saturate `c' ... 00679 result = Poly_Con_Relation::is_disjoint(); 00680 } 00681 break; 00682 00683 case Generator::POINT: 00684 case Generator::CLOSURE_POINT: 00685 if (first_point_or_nonsaturating_ray) { 00686 // It is the first time that we have a point and 00687 // we have not found a non-saturating ray yet. 00688 // - If point `g' saturates `c', then all the generators 00689 // seen so far saturate `c'. 00690 // - If point `g' is included in (but does not saturate) `c', 00691 // then all the generators seen so far are included in `c'. 00692 // - If point `g' strictly violates `c', then all the 00693 // generators seen so far are disjoint from `c'. 00694 first_point_or_nonsaturating_ray = false; 00695 if (sp_sign > 0) 00696 result = Poly_Con_Relation::is_included(); 00697 else if (sp_sign < 0) 00698 result = Poly_Con_Relation::is_disjoint(); 00699 } 00700 else { 00701 // We already found a point or a non-saturating ray before. 00702 if ((sp_sign > 0 00703 && result.implies(Poly_Con_Relation::is_disjoint())) 00704 || 00705 (sp_sign <= 0 00706 && result == Poly_Con_Relation::is_included())) 00707 return Poly_Con_Relation::strictly_intersects(); 00708 if (sp_sign < 0) 00709 // Here all the generators seen so far either saturate 00710 // or are disjoint from `c'. 00711 // Since `g' does not saturate `c' ... 00712 result = Poly_Con_Relation::is_disjoint(); 00713 } 00714 break; 00715 } 00716 } 00717 } 00718 break; 00719 } 00720 // We have seen all generators. 00721 return result; 00722 } 00723 00724 00725 bool 00726 PPL::Generator_System::satisfied_by_all_generators(const Constraint& c) const { 00727 PPL_ASSERT(c.space_dimension() <= space_dimension()); 00728 00729 // Setting `sps' to the appropriate scalar product sign operator. 00730 // This also avoids problems when having _legal_ topology mismatches 00731 // (which could also cause a mismatch in the number of columns). 00732 Topology_Adjusted_Scalar_Product_Sign sps(c); 00733 00734 const Generator_System& gs = *this; 00735 switch (c.type()) { 00736 case Constraint::EQUALITY: 00737 // Equalities must be saturated by all generators. 00738 for (dimension_type i = gs.num_rows(); i-- > 0; ) 00739 if (sps(c, gs[i]) != 0) 00740 return false; 00741 break; 00742 case Constraint::NONSTRICT_INEQUALITY: 00743 // Non-strict inequalities must be saturated by lines and 00744 // satisfied by all the other generators. 00745 for (dimension_type i = gs.num_rows(); i-- > 0; ) { 00746 const Generator& g = gs[i]; 00747 const int sp_sign = sps(c, g); 00748 if (g.is_line()) { 00749 if (sp_sign != 0) 00750 return false; 00751 } 00752 else 00753 // `g' is a ray, point or closure point. 00754 if (sp_sign < 0) 00755 return false; 00756 } 00757 break; 00758 case Constraint::STRICT_INEQUALITY: 00759 // Strict inequalities must be saturated by lines, 00760 // satisfied by all generators, and must not be saturated by points. 00761 for (dimension_type i = gs.num_rows(); i-- > 0; ) { 00762 const Generator& g = gs[i]; 00763 const int sp_sign = sps(c, g); 00764 switch (g.type()) { 00765 case Generator::POINT: 00766 if (sp_sign <= 0) 00767 return false; 00768 break; 00769 case Generator::LINE: 00770 if (sp_sign != 0) 00771 return false; 00772 break; 00773 default: 00774 // `g' is a ray or closure point. 00775 if (sp_sign < 0) 00776 return false; 00777 break; 00778 } 00779 } 00780 break; 00781 } 00782 // If we reach this point, `c' is satisfied by all generators. 00783 return true; 00784 } 00785 00786 00787 void 00788 PPL::Generator_System 00789 ::affine_image(dimension_type v, 00790 const Linear_Expression& expr, 00791 Coefficient_traits::const_reference denominator) { 00792 Generator_System& x = *this; 00793 // `v' is the index of a column corresponding to 00794 // a "user" variable (i.e., it cannot be the inhomogeneous term, 00795 // nor the epsilon dimension of NNC polyhedra). 00796 PPL_ASSERT(v > 0 && v <= x.space_dimension()); 00797 PPL_ASSERT(expr.space_dimension() <= x.space_dimension()); 00798 PPL_ASSERT(denominator > 0); 00799 00800 const dimension_type n_columns = x.num_columns(); 00801 const dimension_type n_rows = x.num_rows(); 00802 00803 // Compute the numerator of the affine transformation and assign it 00804 // to the column of `*this' indexed by `v'. 00805 PPL_DIRTY_TEMP_COEFFICIENT(numerator); 00806 for (dimension_type i = n_rows; i-- > 0; ) { 00807 Generator& row = x[i]; 00808 Scalar_Products::assign(numerator, expr, row); 00809 using std::swap; 00810 swap(numerator, row[v]); 00811 } 00812 00813 if (denominator != 1) { 00814 // Since we want integer elements in the matrix, 00815 // we multiply by `denominator' all the columns of `*this' 00816 // having an index different from `v'. 00817 for (dimension_type i = n_rows; i-- > 0; ) { 00818 Generator& row = x[i]; 00819 for (dimension_type j = n_columns; j-- > 0; ) 00820 if (j != v) 00821 row[j] *= denominator; 00822 } 00823 } 00824 00825 // If the mapping is not invertible we may have transformed 00826 // valid lines and rays into the origin of the space. 00827 const bool not_invertible = (v > expr.space_dimension() || expr[v] == 0); 00828 if (not_invertible) 00829 x.remove_invalid_lines_and_rays(); 00830 00831 // Strong normalization also resets the sortedness flag. 00832 x.strong_normalize(); 00833 } 00834 00835 void 00836 PPL::Generator_System::ascii_dump(std::ostream& s) const { 00837 const Generator_System& x = *this; 00838 const dimension_type x_num_rows = x.num_rows(); 00839 const dimension_type x_num_columns = x.num_columns(); 00840 s << "topology " << (is_necessarily_closed() 00841 ? "NECESSARILY_CLOSED" 00842 : "NOT_NECESSARILY_CLOSED") 00843 << "\n" 00844 << x_num_rows << " x " << x_num_columns << ' ' 00845 << (x.is_sorted() ? "(sorted)" : "(not_sorted)") 00846 << "\n" 00847 << "index_first_pending " << x.first_pending_row() 00848 << "\n"; 00849 for (dimension_type i = 0; i < x_num_rows; ++i) { 00850 const Generator& g = x[i]; 00851 for (dimension_type j = 0; j < x_num_columns; ++j) 00852 s << g[j] << ' '; 00853 switch (g.type()) { 00854 case Generator::LINE: 00855 s << "L"; 00856 break; 00857 case Generator::RAY: 00858 s << "R"; 00859 break; 00860 case Generator::POINT: 00861 s << "P"; 00862 break; 00863 case Generator::CLOSURE_POINT: 00864 s << "C"; 00865 break; 00866 } 00867 s << "\n"; 00868 } 00869 } 00870 00871 PPL_OUTPUT_DEFINITIONS(Generator_System) 00872 00873 bool 00874 PPL::Generator_System::ascii_load(std::istream& s) { 00875 std::string str; 00876 if (!(s >> str) || str != "topology") 00877 return false; 00878 if (!(s >> str)) 00879 return false; 00880 if (str == "NECESSARILY_CLOSED") 00881 set_necessarily_closed(); 00882 else { 00883 if (str != "NOT_NECESSARILY_CLOSED") 00884 return false; 00885 set_not_necessarily_closed(); 00886 } 00887 00888 dimension_type nrows; 00889 dimension_type ncols; 00890 if (!(s >> nrows)) 00891 return false; 00892 if (!(s >> str) || str != "x") 00893 return false; 00894 if (!(s >> ncols)) 00895 return false; 00896 resize_no_copy(nrows, ncols); 00897 00898 if (!(s >> str) || (str != "(sorted)" && str != "(not_sorted)")) 00899 return false; 00900 set_sorted(str == "(sorted)"); 00901 dimension_type index; 00902 if (!(s >> str) || str != "index_first_pending") 00903 return false; 00904 if (!(s >> index)) 00905 return false; 00906 set_index_first_pending_row(index); 00907 00908 Generator_System& x = *this; 00909 for (dimension_type i = 0; i < x.num_rows(); ++i) { 00910 for (dimension_type j = 0; j < x.num_columns(); ++j) 00911 if (!(s >> x[i][j])) 00912 return false; 00913 00914 if (!(s >> str)) 00915 return false; 00916 if (str == "L") 00917 x[i].set_is_line(); 00918 else if (str == "R" || str == "P" || str == "C") 00919 x[i].set_is_ray_or_point(); 00920 else 00921 return false; 00922 00923 // Checking for equality of actual and declared types. 00924 switch (x[i].type()) { 00925 case Generator::LINE: 00926 if (str == "L") 00927 continue; 00928 break; 00929 case Generator::RAY: 00930 if (str == "R") 00931 continue; 00932 break; 00933 case Generator::POINT: 00934 if (str == "P") 00935 continue; 00936 break; 00937 case Generator::CLOSURE_POINT: 00938 if (str == "C") 00939 continue; 00940 break; 00941 } 00942 // Reaching this point means that the input was illegal. 00943 return false; 00944 } 00945 00946 // Check invariants. 00947 PPL_ASSERT(OK()); 00948 return true; 00949 } 00950 00951 void 00952 PPL::Generator_System::remove_invalid_lines_and_rays() { 00953 // The origin of the vector space cannot be a valid line/ray. 00954 // NOTE: the following swaps will mix generators without even trying 00955 // to preserve sortedness: as a matter of fact, it will almost always 00956 // be the case that the input generator system is NOT sorted. 00957 using std::swap; 00958 Generator_System& gs = *this; 00959 const dimension_type old_n_rows = gs.num_rows(); 00960 dimension_type n_rows = old_n_rows; 00961 if (num_pending_rows() == 0) { 00962 for (dimension_type i = n_rows; i-- > 0; ) { 00963 Generator& g = gs[i]; 00964 if (g.is_line_or_ray() && g.all_homogeneous_terms_are_zero()) { 00965 // An invalid line/ray has been found. 00966 --n_rows; 00967 swap(g, gs[n_rows]); 00968 gs.set_sorted(false); 00969 } 00970 } 00971 set_index_first_pending_row(n_rows); 00972 } 00973 else { 00974 // If the matrix has some pending rows, we can not 00975 // swap the "normal" rows with the pending rows. So 00976 // we must put at the end of the "normal" rows 00977 // the invalid "normal" rows, put them at the end 00978 // of the matrix, find the invalid rows in the pending 00979 // part and then erase the invalid rows that now 00980 // are in the bottom part of the matrix. 00981 PPL_ASSERT(num_pending_rows() > 0); 00982 dimension_type first_pending = first_pending_row(); 00983 for (dimension_type i = first_pending; i-- > 0; ) { 00984 Generator& g = gs[i]; 00985 if (g.is_line_or_ray() && g.all_homogeneous_terms_are_zero()) { 00986 // An invalid line/ray has been found. 00987 --first_pending; 00988 swap(g, gs[first_pending]); 00989 gs.set_sorted(false); 00990 } 00991 } 00992 const dimension_type num_invalid_rows 00993 = first_pending_row() - first_pending; 00994 set_index_first_pending_row(first_pending); 00995 for (dimension_type i = 0; i < num_invalid_rows; ++i) 00996 swap(gs[n_rows - i], gs[first_pending + i]); 00997 n_rows -= num_invalid_rows; 00998 for (dimension_type i = n_rows; i-- > first_pending; ) { 00999 Generator& g = gs[i]; 01000 if (g.is_line_or_ray() && g.all_homogeneous_terms_are_zero()) { 01001 // An invalid line/ray has been found. 01002 --n_rows; 01003 swap(g, gs[n_rows]); 01004 gs.set_sorted(false); 01005 } 01006 } 01007 } 01008 gs.remove_trailing_rows(old_n_rows - n_rows); 01009 } 01010 01011 const PPL::Generator_System* PPL::Generator_System::zero_dim_univ_p = 0; 01012 01013 void 01014 PPL::Generator_System::initialize() { 01015 PPL_ASSERT(zero_dim_univ_p == 0); 01016 zero_dim_univ_p 01017 = new Generator_System(Generator::zero_dim_point()); 01018 } 01019 01020 void 01021 PPL::Generator_System::finalize() { 01022 PPL_ASSERT(zero_dim_univ_p != 0); 01023 delete zero_dim_univ_p; 01024 zero_dim_univ_p = 0; 01025 } 01026 01027 bool 01028 PPL::Generator_System::OK() const { 01029 // A Generator_System must be a valid Linear_System; do not check for 01030 // strong normalization, since this will be done when 01031 // checking each individual generator. 01032 if (!Linear_System::OK(false)) 01033 return false; 01034 01035 // Checking each generator in the system. 01036 const Generator_System& x = *this; 01037 for (dimension_type i = num_rows(); i-- > 0; ) 01038 if (!x[i].OK()) 01039 return false; 01040 01041 // All checks passed. 01042 return true; 01043 } 01044 01046 std::ostream& 01047 PPL::IO_Operators::operator<<(std::ostream& s, const Generator_System& gs) { 01048 Generator_System::const_iterator i = gs.begin(); 01049 const Generator_System::const_iterator gs_end = gs.end(); 01050 if (i == gs_end) 01051 return s << "false"; 01052 while (true) { 01053 s << *i++; 01054 if (i == gs_end) 01055 return s; 01056 s << ", "; 01057 } 01058 }