00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <ppl-config.h>
00025 #include "Polyhedron.defs.hh"
00026 #include "C_Polyhedron.defs.hh"
00027 #include "NNC_Polyhedron.defs.hh"
00028 #include "Scalar_Products.defs.hh"
00029 #include "MIP_Problem.defs.hh"
00030 #include "wrap_assign.hh"
00031 #include <cstdlib>
00032 #include "assert.hh"
00033 #include <iostream>
00034
00035 #ifndef ENSURE_SORTEDNESS
00036 #define ENSURE_SORTEDNESS 0
00037 #endif
00038
00039 namespace PPL = Parma_Polyhedra_Library;
00040
00041 PPL::dimension_type* PPL::Polyhedron::simplify_num_saturators_p = 0;
00042
00043 size_t PPL::Polyhedron::simplify_num_saturators_size = 0;
00044
00045 void
00046 PPL::Polyhedron::initialize() {
00047 PPL_ASSERT(simplify_num_saturators_p == 0);
00048 PPL_ASSERT(simplify_num_saturators_size == 0);
00049 simplify_num_saturators_p = new dimension_type[simplify_num_saturators_size];
00050 }
00051
00052 void
00053 PPL::Polyhedron::finalize() {
00054 delete [] simplify_num_saturators_p;
00055 simplify_num_saturators_p = 0;
00056 simplify_num_saturators_size = 0;
00057 }
00058
00059 PPL::dimension_type
00060 PPL::Polyhedron::affine_dimension() const {
00061 if (is_empty())
00062 return 0;
00063
00064 const Constraint_System& cs = minimized_constraints();
00065 dimension_type d = space_dim;
00066 for (Constraint_System::const_iterator i = cs.begin(),
00067 cs_end = cs.end(); i != cs_end; ++i)
00068 if (i->is_equality())
00069 --d;
00070 return d;
00071 }
00072
00073 const PPL::Constraint_System&
00074 PPL::Polyhedron::constraints() const {
00075 if (marked_empty()) {
00076
00077
00078 if (con_sys.has_no_rows()) {
00079
00080
00081 Constraint_System unsat_cs = Constraint_System::zero_dim_empty();
00082 unsat_cs.adjust_topology_and_space_dimension(topology(), space_dim);
00083 const_cast<Constraint_System&>(con_sys).swap(unsat_cs);
00084 }
00085 else {
00086
00087 PPL_ASSERT(con_sys.space_dimension() == space_dim);
00088 PPL_ASSERT(con_sys.num_rows() == 1);
00089 PPL_ASSERT(con_sys[0].is_inconsistent());
00090 }
00091 return con_sys;
00092 }
00093
00094 if (space_dim == 0) {
00095
00096 PPL_ASSERT(con_sys.num_rows() == 0 && con_sys.num_columns() == 0);
00097 return con_sys;
00098 }
00099
00100
00101
00102
00103 if (has_pending_generators())
00104 process_pending_generators();
00105 else if (!constraints_are_up_to_date())
00106 update_constraints();
00107
00108
00109 #if ENSURE_SORTEDNESS
00110
00111
00112 if (!has_pending_constraints())
00113 obtain_sorted_constraints();
00114 #endif
00115 return con_sys;
00116 }
00117
00118 const PPL::Constraint_System&
00119 PPL::Polyhedron::minimized_constraints() const {
00120
00121
00122 if (is_necessarily_closed())
00123 minimize();
00124 else
00125 strongly_minimize_constraints();
00126 return constraints();
00127 }
00128
00129 const PPL::Generator_System&
00130 PPL::Polyhedron::generators() const {
00131 if (marked_empty()) {
00132 PPL_ASSERT(gen_sys.has_no_rows());
00133
00134
00135 if (gen_sys.space_dimension() != space_dim) {
00136 Generator_System gs;
00137 gs.adjust_topology_and_space_dimension(topology(), space_dim);
00138 const_cast<Generator_System&>(gen_sys).swap(gs);
00139 }
00140 return gen_sys;
00141 }
00142
00143 if (space_dim == 0) {
00144 PPL_ASSERT(gen_sys.num_rows() == 0 && gen_sys.num_columns() == 0);
00145 return Generator_System::zero_dim_univ();
00146 }
00147
00148
00149
00150
00151 if ((has_pending_constraints() && !process_pending_constraints())
00152 || (!generators_are_up_to_date() && !update_generators())) {
00153
00154 PPL_ASSERT(gen_sys.has_no_rows());
00155
00156
00157 if (gen_sys.space_dimension() != space_dim) {
00158 Generator_System gs;
00159 gs.adjust_topology_and_space_dimension(topology(), space_dim);
00160 const_cast<Generator_System&>(gen_sys).swap(gs);
00161 }
00162 return gen_sys;
00163 }
00164
00165
00166 #if ENSURE_SORTEDNESS
00167
00168
00169 if (!has_pending_generators())
00170 obtain_sorted_generators();
00171 #else
00172
00173
00174
00175
00176 if (!is_necessarily_closed()
00177 && generators_are_minimized() && !has_pending_generators())
00178 obtain_sorted_generators();
00179 #endif
00180 return gen_sys;
00181 }
00182
00183 const PPL::Generator_System&
00184 PPL::Polyhedron::minimized_generators() const {
00185
00186
00187 if (is_necessarily_closed())
00188 minimize();
00189 else
00190 strongly_minimize_generators();
00191
00192
00193
00194 return generators();
00195 }
00196
00197 PPL::Grid_Generator_System
00198 PPL::Polyhedron::grid_generators() const {
00199 Grid_Generator_System ggs(space_dim);
00200
00201 ggs.insert(grid_point(0*(Variable(0))));
00202
00203 dimension_type dim = 0;
00204 while (dim < space_dim)
00205 ggs.insert(grid_line(Variable(dim)));
00206 return ggs;
00207 }
00208
00209 PPL::Poly_Con_Relation
00210 PPL::Polyhedron::relation_with(const Constraint& c) const {
00211
00212 if (space_dim < c.space_dimension())
00213 throw_dimension_incompatible("relation_with(c)", "c", c);
00214
00215 if (marked_empty())
00216 return Poly_Con_Relation::saturates()
00217 && Poly_Con_Relation::is_included()
00218 && Poly_Con_Relation::is_disjoint();
00219
00220 if (space_dim == 0) {
00221 if (c.is_inconsistent())
00222 if (c.is_strict_inequality() && c.inhomogeneous_term() == 0)
00223
00224
00225 return Poly_Con_Relation::saturates()
00226 && Poly_Con_Relation::is_disjoint();
00227 else
00228 return Poly_Con_Relation::is_disjoint();
00229 else if (c.is_equality() || c.inhomogeneous_term() == 0)
00230 return Poly_Con_Relation::saturates()
00231 && Poly_Con_Relation::is_included();
00232 else
00233
00234
00235
00236 return Poly_Con_Relation::is_included();
00237 }
00238
00239 if ((has_pending_constraints() && !process_pending_constraints())
00240 || (!generators_are_up_to_date() && !update_generators()))
00241
00242 return Poly_Con_Relation::saturates()
00243 && Poly_Con_Relation::is_included()
00244 && Poly_Con_Relation::is_disjoint();
00245
00246 return gen_sys.relation_with(c);
00247 }
00248
00249 PPL::Poly_Gen_Relation
00250 PPL::Polyhedron::relation_with(const Generator& g) const {
00251
00252 if (space_dim < g.space_dimension())
00253 throw_dimension_incompatible("relation_with(g)", "g", g);
00254
00255
00256 if (marked_empty())
00257 return Poly_Gen_Relation::nothing();
00258
00259
00260
00261 if (space_dim == 0)
00262 return Poly_Gen_Relation::subsumes();
00263
00264 if (has_pending_generators())
00265 process_pending_generators();
00266 else if (!constraints_are_up_to_date())
00267 update_constraints();
00268
00269 return
00270 con_sys.satisfies_all_constraints(g)
00271 ? Poly_Gen_Relation::subsumes()
00272 : Poly_Gen_Relation::nothing();
00273 }
00274
00275 PPL::Poly_Con_Relation
00276 PPL::Polyhedron::relation_with(const Congruence& cg) const {
00277 dimension_type cg_space_dim = cg.space_dimension();
00278
00279 if (space_dim < cg_space_dim)
00280 throw_dimension_incompatible("relation_with(cg)", "cg", cg);
00281
00282 if (cg.is_equality()) {
00283 const Constraint c(cg);
00284 return relation_with(c);
00285 }
00286
00287 if (marked_empty())
00288 return Poly_Con_Relation::saturates()
00289 && Poly_Con_Relation::is_included()
00290 && Poly_Con_Relation::is_disjoint();
00291
00292 if (space_dim == 0) {
00293 if (cg.is_inconsistent())
00294 return Poly_Con_Relation::is_disjoint();
00295 else
00296 return Poly_Con_Relation::saturates()
00297 && Poly_Con_Relation::is_included();
00298 }
00299
00300 if ((has_pending_constraints() && !process_pending_constraints())
00301 || (!generators_are_up_to_date() && !update_generators()))
00302
00303 return Poly_Con_Relation::saturates()
00304 && Poly_Con_Relation::is_included()
00305 && Poly_Con_Relation::is_disjoint();
00306
00307
00308 Linear_Expression expr = Linear_Expression(cg);
00309 Constraint c(expr == 0);
00310
00311
00312
00313
00314 PPL_DIRTY_TEMP_COEFFICIENT(sp_point);
00315 for (Generator_System::const_iterator gs_i = gen_sys.begin(),
00316 gs_end = gen_sys.end(); gs_i != gs_end; ++gs_i) {
00317 if (gs_i->is_point()) {
00318 Scalar_Products::assign(sp_point, c, *gs_i);
00319 expr -= sp_point;
00320 break;
00321 }
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331 const Coefficient& modulus = cg.modulus();
00332 PPL_DIRTY_TEMP_COEFFICIENT(signed_distance);
00333 signed_distance = sp_point % modulus;
00334 if (signed_distance == 0)
00335
00336 return relation_with(expr == 0);
00337 else
00338
00339 expr += signed_distance;
00340
00341
00342 const bool positive = (signed_distance > 0);
00343 Constraint first_halfspace = positive ? (expr >= 0) : (expr <= 0);
00344
00345 Poly_Con_Relation first_rels = relation_with(first_halfspace);
00346 PPL_ASSERT(!first_rels.implies(Poly_Con_Relation::saturates())
00347 && !first_rels.implies(Poly_Con_Relation::is_disjoint()));
00348 if (first_rels.implies(Poly_Con_Relation::strictly_intersects()))
00349 return Poly_Con_Relation::strictly_intersects();
00350
00351
00352 if (positive)
00353 expr -= modulus;
00354 else
00355 expr += modulus;
00356 Constraint second_halfspace = positive ? (expr <= 0) : (expr >= 0);
00357
00358 PPL_ASSERT(first_rels == Poly_Con_Relation::is_included());
00359 Poly_Con_Relation second_rels = relation_with(second_halfspace);
00360 PPL_ASSERT(!second_rels.implies(Poly_Con_Relation::saturates())
00361 && !second_rels.implies(Poly_Con_Relation::is_disjoint()));
00362 if (second_rels.implies(Poly_Con_Relation::strictly_intersects()))
00363 return Poly_Con_Relation::strictly_intersects();
00364
00365 PPL_ASSERT(second_rels == Poly_Con_Relation::is_included());
00366 return Poly_Con_Relation::is_disjoint();
00367 }
00368
00369 bool
00370 PPL::Polyhedron::is_universe() const {
00371 if (marked_empty())
00372 return false;
00373
00374 if (space_dim == 0)
00375 return true;
00376
00377 if (!has_pending_generators() && constraints_are_up_to_date()) {
00378
00379 for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00380 if (!con_sys[i].is_tautological())
00381 return false;
00382
00383 return true;
00384 }
00385
00386 PPL_ASSERT(!has_pending_constraints() && generators_are_up_to_date());
00387
00388
00389 dimension_type num_lines = 0;
00390 dimension_type num_rays = 0;
00391 const dimension_type first_pending = gen_sys.first_pending_row();
00392 for (dimension_type i = first_pending; i-- > 0; )
00393 switch (gen_sys[i].type()) {
00394 case Generator::RAY:
00395 ++num_rays;
00396 break;
00397 case Generator::LINE:
00398 ++num_lines;
00399 break;
00400 default:
00401 break;
00402 }
00403
00404 if (has_pending_generators()) {
00405
00406
00407 PPL_ASSERT(generators_are_minimized());
00408 if (num_lines == space_dim) {
00409 PPL_ASSERT(num_rays == 0);
00410 return true;
00411 }
00412 PPL_ASSERT(num_lines < space_dim);
00413
00414 dimension_type num_pending_lines = 0;
00415 dimension_type num_pending_rays = 0;
00416 const dimension_type gs_num_rows = gen_sys.num_rows();
00417 for (dimension_type i = first_pending; i < gs_num_rows; ++i)
00418 switch (gen_sys[i].type()) {
00419 case Generator::RAY:
00420 ++num_pending_rays;
00421 break;
00422 case Generator::LINE:
00423 ++num_pending_lines;
00424 break;
00425 default:
00426 break;
00427 }
00428
00429
00430 if (num_pending_rays == 0 && num_pending_lines == 0)
00431 return false;
00432
00433
00434 if (num_lines + num_pending_lines < space_dim) {
00435 const dimension_type num_dims_missing
00436 = space_dim - (num_lines + num_pending_lines);
00437
00438
00439 if (num_rays + num_pending_rays <= num_dims_missing)
00440 return false;
00441 }
00442 }
00443 else {
00444
00445 if (generators_are_minimized()) {
00446
00447 PPL_ASSERT(num_rays == 0 || num_lines < space_dim);
00448 return num_lines == space_dim;
00449 }
00450 else
00451
00452
00453
00454 if (num_lines < space_dim && num_lines + num_rays <= space_dim)
00455 return false;
00456 }
00457
00458
00459 if (has_pending_generators())
00460 process_pending_generators();
00461 else if (!constraints_are_minimized())
00462 minimize();
00463 if (is_necessarily_closed())
00464 return con_sys.num_rows() == 1
00465 && con_sys[0].is_inequality()
00466 && con_sys[0].is_tautological();
00467 else {
00468
00469 if (con_sys.num_rows() != 2
00470 || con_sys[0].is_equality()
00471 || con_sys[1].is_equality())
00472 return false;
00473 else {
00474
00475
00476
00477
00478 #ifndef NDEBUG
00479 obtain_sorted_constraints();
00480 const Constraint& eps_leq_one = con_sys[0];
00481 const Constraint& eps_geq_zero = con_sys[1];
00482 const dimension_type eps_index = con_sys.num_columns() - 1;
00483 PPL_ASSERT(eps_leq_one[0] > 0 && eps_leq_one[eps_index] < 0
00484 && eps_geq_zero[0] == 0 && eps_geq_zero[eps_index] > 0);
00485 for (dimension_type i = 1; i < eps_index; ++i)
00486 PPL_ASSERT(eps_leq_one[i] == 0 && eps_geq_zero[i] == 0);
00487 #endif
00488 return true;
00489 }
00490 }
00491 }
00492
00493 bool
00494 PPL::Polyhedron::is_bounded() const {
00495
00496 if (space_dim == 0
00497 || marked_empty()
00498 || (has_pending_constraints() && !process_pending_constraints())
00499 || (!generators_are_up_to_date() && !update_generators()))
00500 return true;
00501
00502
00503
00504 for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
00505 if (gen_sys[i].is_line_or_ray())
00506 return false;
00507
00508
00509
00510 return true;
00511 }
00512
00513 bool
00514 PPL::Polyhedron::is_topologically_closed() const {
00515
00516 if (is_necessarily_closed())
00517 return true;
00518
00519 if (marked_empty()
00520 || space_dim == 0
00521 || (has_something_pending() && !process_pending()))
00522 return true;
00523
00524
00525 PPL_ASSERT(!has_something_pending());
00526
00527 if (generators_are_minimized()) {
00528
00529
00530 const dimension_type n_rows = gen_sys.num_rows();
00531 const dimension_type n_lines = gen_sys.num_lines();
00532 for (dimension_type i = n_rows; i-- > n_lines; ) {
00533 const Generator& gi = gen_sys[i];
00534 if (gi.is_closure_point()) {
00535 bool gi_has_no_matching_point = true;
00536 for (dimension_type j = n_rows; j-- > n_lines; ) {
00537 const Generator& gj = gen_sys[j];
00538 if (i != j
00539 && gj.is_point()
00540 && gi.is_matching_closure_point(gj)) {
00541 gi_has_no_matching_point = false;
00542 break;
00543 }
00544 }
00545 if (gi_has_no_matching_point)
00546 return false;
00547 }
00548 }
00549
00550 return true;
00551 }
00552
00553
00554
00555 strongly_minimize_constraints();
00556 return marked_empty() || !con_sys.has_strict_inequalities();
00557 }
00558
00559 bool
00560 PPL::Polyhedron::contains_integer_point() const {
00561
00562 if (marked_empty())
00563 return false;
00564
00565
00566
00567 if (space_dim == 0)
00568 return true;
00569
00570
00571 if (has_pending_constraints() && !process_pending())
00572
00573 return false;
00574
00575
00576
00577 PPL_ASSERT(!has_pending_constraints());
00578 if (generators_are_up_to_date())
00579 for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
00580 if (gen_sys[i].is_point() && gen_sys[i].divisor() == 1)
00581 return true;
00582
00583 const Constraint_System& cs = constraints();
00584 #if 0 // TEMPORARILY DISABLED.
00585 MIP_Problem mip(space_dim,
00586 cs.begin(), cs.end(),
00587 Variables_Set(Variable(0), Variable(space_dim-1)));
00588 #else
00589
00590
00591
00592 MIP_Problem mip(space_dim);
00593 mip.add_to_integer_space_dimensions(Variables_Set(Variable(0),
00594 Variable(space_dim-1)));
00595 PPL_DIRTY_TEMP_COEFFICIENT(homogeneous_gcd);
00596 PPL_DIRTY_TEMP_COEFFICIENT(gcd);
00597 PPL_DIRTY_TEMP0(mpq_class, rational_inhomogeneous);
00598 PPL_DIRTY_TEMP_COEFFICIENT(tightened_inhomogeneous);
00599 for (Constraint_System::const_iterator cs_i = cs.begin(),
00600 cs_end = cs.end(); cs_i != cs_end; ++cs_i) {
00601 const Constraint& c = *cs_i;
00602 const Constraint::Type c_type = c.type();
00603 const Coefficient& inhomogeneous = c.inhomogeneous_term();
00604 if (c_type == Constraint::STRICT_INEQUALITY) {
00605
00606
00607
00608 homogeneous_gcd = 0;
00609 for (dimension_type i = space_dim; i-- > 0; )
00610 gcd_assign(homogeneous_gcd,
00611 homogeneous_gcd, c.coefficient(Variable(i)));
00612 if (homogeneous_gcd == 0) {
00613
00614
00615 PPL_ASSERT(c.is_inconsistent());
00616 return false;
00617 }
00618 Linear_Expression le;
00619 for (dimension_type i = space_dim; i-- > 0; )
00620 le += (c.coefficient(Variable(i)) / homogeneous_gcd) * Variable(i);
00621
00622 le += (inhomogeneous / homogeneous_gcd);
00623
00624
00625 gcd_assign(gcd, homogeneous_gcd, inhomogeneous);
00626 if (gcd == homogeneous_gcd)
00627 le -= 1;
00628 mip.add_constraint(le >= 0);
00629 }
00630 else {
00631
00632
00633 if (inhomogeneous == 0)
00634
00635 mip.add_constraint(c);
00636 else {
00637
00638
00639
00640 homogeneous_gcd = 0;
00641 for (dimension_type i = space_dim; i-- > 0; )
00642 gcd_assign(homogeneous_gcd,
00643 homogeneous_gcd, c.coefficient(Variable(i)));
00644 if (homogeneous_gcd == 0) {
00645
00646
00647 PPL_ASSERT(c.is_inconsistent());
00648 return false;
00649 }
00650 else if (homogeneous_gcd == 1)
00651
00652
00653 mip.add_constraint(c);
00654 else {
00655 PPL_ASSERT(homogeneous_gcd > 1);
00656
00657
00658 #ifndef NDEBUG
00659
00660
00661 gcd_assign(gcd, homogeneous_gcd, inhomogeneous);
00662 PPL_ASSERT(gcd == 1);
00663 #endif
00664 if (c.type() == Constraint::EQUALITY)
00665 return false;
00666
00667 Linear_Expression le = Linear_Expression(c);
00668 le -= inhomogeneous;
00669
00670 assign_r(rational_inhomogeneous.get_num(),
00671 inhomogeneous, ROUND_NOT_NEEDED);
00672 assign_r(rational_inhomogeneous.get_den(),
00673 homogeneous_gcd, ROUND_NOT_NEEDED);
00674
00675 PPL_ASSERT(is_canonical(rational_inhomogeneous));
00676 assign_r(tightened_inhomogeneous,
00677 rational_inhomogeneous, ROUND_DOWN);
00678 tightened_inhomogeneous *= homogeneous_gcd;
00679 le += tightened_inhomogeneous;
00680 mip.add_constraint(le >= 0);
00681 }
00682 }
00683 }
00684 }
00685 #endif // TEMPORARY WORKAROUND.
00686 return mip.is_satisfiable();
00687 }
00688
00689 bool
00690 PPL::Polyhedron::constrains(const Variable var) const {
00691
00692 const dimension_type var_space_dim = var.space_dimension();
00693 if (space_dim < var_space_dim)
00694 throw_dimension_incompatible("constrains(v)", "v", var);
00695
00696
00697 if (marked_empty())
00698 return true;
00699
00700 if (generators_are_up_to_date() && !has_pending_constraints()) {
00701
00702
00703
00704 if (constraints_are_up_to_date() && !has_pending_generators())
00705
00706
00707 goto syntactic_check;
00708
00709 if (generators_are_minimized()) {
00710
00711
00712
00713
00714 dimension_type num_lines = 0;
00715 const dimension_type first_pending = gen_sys.first_pending_row();
00716 for (dimension_type i = first_pending; i-- > 0; )
00717 if (gen_sys[i].is_line())
00718 ++num_lines;
00719
00720 if (num_lines == space_dim)
00721 return false;
00722 }
00723
00724
00725
00726
00727 bool have_positive_ray = false;
00728 bool have_negative_ray = false;
00729 const dimension_type var_id = var.id();
00730 for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
00731 const Generator& gen_sys_i = gen_sys[i];
00732 if (gen_sys_i.is_line_or_ray()) {
00733 const Linear_Row& row = gen_sys_i;
00734 const int sign = sgn(row.coefficient(var_id));
00735 if (sign != 0) {
00736 for (dimension_type j = space_dim+1; --j > 0; )
00737 if (j != var_id && row[j] != 0)
00738 goto next;
00739 if (gen_sys_i.is_line())
00740 return true;
00741 if (sign > 0)
00742 if (have_negative_ray)
00743 return true;
00744 else
00745 have_positive_ray = true;
00746 else if (have_positive_ray)
00747 return true;
00748 else
00749 have_negative_ray = true;
00750 }
00751 }
00752 next:
00753 ;
00754 }
00755
00756
00757
00758
00759
00760 if (has_pending_generators())
00761 process_pending_generators();
00762 else if (!constraints_are_up_to_date())
00763 update_constraints();
00764 goto syntactic_check;
00765 }
00766
00767
00768 if (!minimize())
00769 return true;
00770
00771 syntactic_check:
00772 for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00773 if (con_sys[i].coefficient(var) != 0)
00774 return true;
00775 return false;
00776 }
00777
00778 bool
00779 PPL::Polyhedron::OK(bool check_not_empty) const {
00780 #ifndef NDEBUG
00781 using std::endl;
00782 using std::cerr;
00783 #endif
00784
00785
00786
00787 const dimension_type poly_num_columns
00788 = space_dim + (is_necessarily_closed() ? 1 : 2);
00789
00790
00791 if (con_sys.topology() != gen_sys.topology()) {
00792 #ifndef NDEBUG
00793 cerr << "Constraints and generators have different topologies!"
00794 << endl;
00795 #endif
00796 goto bomb;
00797 }
00798
00799
00800 if (!sat_c.OK())
00801 goto bomb;
00802 if (!sat_g.OK())
00803 goto bomb;
00804
00805
00806 if (!status.OK())
00807 goto bomb;
00808
00809 if (marked_empty()) {
00810 if (check_not_empty) {
00811
00812 #ifndef NDEBUG
00813 cerr << "Empty polyhedron!" << endl;
00814 #endif
00815 goto bomb;
00816 }
00817
00818
00819
00820
00821 if (has_something_pending()) {
00822 #ifndef NDEBUG
00823 cerr << "The polyhedron is empty, "
00824 << "but it has something pending" << endl;
00825 #endif
00826 goto bomb;
00827 }
00828 if (con_sys.has_no_rows())
00829 return true;
00830 else {
00831 if (con_sys.space_dimension() != space_dim) {
00832 #ifndef NDEBUG
00833 cerr << "The polyhedron is in a space of dimension "
00834 << space_dim
00835 << " while the system of constraints is in a space of dimension "
00836 << con_sys.space_dimension()
00837 << endl;
00838 #endif
00839 goto bomb;
00840 }
00841 if (con_sys.num_rows() != 1) {
00842 #ifndef NDEBUG
00843 cerr << "The system of constraints for an empty polyhedron "
00844 << "has more then one row"
00845 << endl;
00846 #endif
00847 goto bomb;
00848 }
00849 if (!con_sys[0].is_inconsistent()) {
00850 #ifndef NDEBUG
00851 cerr << "Empty polyhedron with a satisfiable system of constraints"
00852 << endl;
00853 #endif
00854 goto bomb;
00855 }
00856
00857 return true;
00858 }
00859 }
00860
00861
00862
00863
00864 if (space_dim == 0) {
00865 if (has_something_pending()) {
00866 #ifndef NDEBUG
00867 cerr << "Zero-dimensional polyhedron with something pending"
00868 << endl;
00869 #endif
00870 goto bomb;
00871 }
00872 if (!con_sys.has_no_rows() || !gen_sys.has_no_rows()) {
00873 #ifndef NDEBUG
00874 cerr << "Zero-dimensional polyhedron with a non-empty"
00875 << endl
00876 << "system of constraints or generators."
00877 << endl;
00878 #endif
00879 goto bomb;
00880 }
00881 return true;
00882 }
00883
00884
00885
00886 if (!constraints_are_up_to_date() && !generators_are_up_to_date()) {
00887 #ifndef NDEBUG
00888 cerr << "Polyhedron not empty, not zero-dimensional"
00889 << endl
00890 << "and with neither constraints nor generators up-to-date!"
00891 << endl;
00892 #endif
00893 goto bomb;
00894 }
00895
00896
00897
00898
00899
00900
00901
00902 if (constraints_are_up_to_date()) {
00903 if (con_sys.num_columns() != poly_num_columns) {
00904 #ifndef NDEBUG
00905 cerr << "Incompatible size! (con_sys and space_dim)"
00906 << endl;
00907 #endif
00908 goto bomb;
00909 }
00910 if (sat_c_is_up_to_date())
00911 if (con_sys.first_pending_row() != sat_c.num_columns()) {
00912 #ifndef NDEBUG
00913 cerr << "Incompatible size! (con_sys and sat_c)"
00914 << endl;
00915 #endif
00916 goto bomb;
00917 }
00918 if (sat_g_is_up_to_date())
00919 if (con_sys.first_pending_row() != sat_g.num_rows()) {
00920 #ifndef NDEBUG
00921 cerr << "Incompatible size! (con_sys and sat_g)"
00922 << endl;
00923 #endif
00924 goto bomb;
00925 }
00926 if (generators_are_up_to_date())
00927 if (con_sys.num_columns() != gen_sys.num_columns()) {
00928 #ifndef NDEBUG
00929 cerr << "Incompatible size! (con_sys and gen_sys)"
00930 << endl;
00931 #endif
00932 goto bomb;
00933 }
00934 }
00935
00936 if (generators_are_up_to_date()) {
00937 if (gen_sys.num_columns() != poly_num_columns) {
00938 #ifndef NDEBUG
00939 cerr << "Incompatible size! (gen_sys and space_dim)"
00940 << endl;
00941 #endif
00942 goto bomb;
00943 }
00944 if (sat_c_is_up_to_date())
00945 if (gen_sys.first_pending_row() != sat_c.num_rows()) {
00946 #ifndef NDEBUG
00947 cerr << "Incompatible size! (gen_sys and sat_c)"
00948 << endl;
00949 #endif
00950 goto bomb;
00951 }
00952 if (sat_g_is_up_to_date())
00953 if (gen_sys.first_pending_row() != sat_g.num_columns()) {
00954 #ifndef NDEBUG
00955 cerr << "Incompatible size! (gen_sys and sat_g)"
00956 << endl;
00957 #endif
00958 goto bomb;
00959 }
00960
00961
00962 if (!gen_sys.OK())
00963 goto bomb;
00964
00965 if (gen_sys.first_pending_row() == 0) {
00966 #ifndef NDEBUG
00967 cerr << "Up-to-date generator system with all rows pending!"
00968 << endl;
00969 #endif
00970 goto bomb;
00971 }
00972
00973
00974
00975 if (!gen_sys.has_no_rows() && !gen_sys.has_points()) {
00976 #ifndef NDEBUG
00977 cerr << "Non-empty generator system declared up-to-date "
00978 << "has no points!"
00979 << endl;
00980 #endif
00981 goto bomb;
00982 }
00983
00984 #if 0 // To be activated when Status keeps strong minimization flags.
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995 if (!is_necessarily_closed()) {
00996 dimension_type num_points = 0;
00997 dimension_type num_closure_points = 0;
00998 dimension_type eps_index = gen_sys.num_columns() - 1;
00999 for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
01000 if (!gen_sys[i].is_line_or_ray())
01001 if (gen_sys[i][eps_index] > 0)
01002 ++num_points;
01003 else
01004 ++num_closure_points;
01005 if (num_points > num_closure_points) {
01006 #ifndef NDEBUG
01007 cerr << "# POINTS > # CLOSURE_POINTS" << endl;
01008 #endif
01009 goto bomb;
01010 }
01011 }
01012
01013 #endif
01014
01015 if (generators_are_minimized()) {
01016
01017
01018
01019
01020 Constraint_System new_con_sys(topology());
01021 Generator_System gs_without_pending = gen_sys;
01022 gs_without_pending.erase_to_end(gen_sys.first_pending_row());
01023 gs_without_pending.unset_pending_rows();
01024 Generator_System copy_of_gen_sys = gs_without_pending;
01025 Bit_Matrix new_sat_c;
01026 minimize(false, copy_of_gen_sys, new_con_sys, new_sat_c);
01027 const dimension_type copy_num_lines = copy_of_gen_sys.num_lines();
01028 if (gs_without_pending.num_rows() != copy_of_gen_sys.num_rows()
01029 || gs_without_pending.num_lines() != copy_num_lines
01030 || gs_without_pending.num_rays() != copy_of_gen_sys.num_rays()) {
01031 #ifndef NDEBUG
01032 cerr << "Generators are declared minimized, but they are not!\n"
01033 << "Here is the minimized form of the generators:\n";
01034 copy_of_gen_sys.ascii_dump(cerr);
01035 cerr << endl;
01036 #endif
01037 goto bomb;
01038 }
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053 if (copy_num_lines == 0) {
01054 copy_of_gen_sys.strong_normalize();
01055 copy_of_gen_sys.sort_rows();
01056 gs_without_pending.strong_normalize();
01057 gs_without_pending.sort_rows();
01058 if (copy_of_gen_sys != gs_without_pending) {
01059 #ifndef NDEBUG
01060 cerr << "Generators are declared minimized, but they are not!\n"
01061 << "(we are in the case:\n"
01062 << "dimension of lineality space equal to 0)\n"
01063 << "Here is the minimized form of the generators:\n";
01064 copy_of_gen_sys.ascii_dump(cerr);
01065 cerr << endl;
01066 #endif
01067 goto bomb;
01068 }
01069 }
01070 }
01071 }
01072
01073 if (constraints_are_up_to_date()) {
01074
01075 if (!con_sys.OK())
01076 goto bomb;
01077
01078 if (con_sys.first_pending_row() == 0) {
01079 #ifndef NDEBUG
01080 cerr << "Up-to-date constraint system with all rows pending!"
01081 << endl;
01082 #endif
01083 goto bomb;
01084 }
01085
01086
01087
01088
01089
01090
01091
01092 bool no_positivity_constraint = true;
01093 for (dimension_type i = con_sys.num_rows(); i-- > 0; )
01094 if (con_sys[i].inhomogeneous_term() != 0) {
01095 no_positivity_constraint = false;
01096 break;
01097 }
01098 if (no_positivity_constraint) {
01099 #ifndef NDEBUG
01100 cerr << "Non-empty constraint system has no positivity constraint"
01101 << endl;
01102 #endif
01103 goto bomb;
01104 }
01105
01106 if (!is_necessarily_closed()) {
01107
01108
01109
01110 bool no_epsilon_geq_zero = true;
01111 const dimension_type eps_index = con_sys.num_columns() - 1;
01112 for (dimension_type i = con_sys.num_rows(); i-- > 0; )
01113 if (con_sys[i][eps_index] > 0) {
01114 no_epsilon_geq_zero = false;
01115 break;
01116 }
01117 if (no_epsilon_geq_zero) {
01118 #ifndef NDEBUG
01119 cerr << "Non-empty constraint system for NNC polyhedron "
01120 << "has no epsilon >= 0 constraint"
01121 << endl;
01122 #endif
01123 goto bomb;
01124 }
01125 }
01126
01127 Constraint_System cs_without_pending = con_sys;
01128 cs_without_pending.erase_to_end(con_sys.first_pending_row());
01129 cs_without_pending.unset_pending_rows();
01130 Constraint_System copy_of_con_sys = cs_without_pending;
01131 bool empty = false;
01132 if (check_not_empty || constraints_are_minimized()) {
01133 Generator_System new_gen_sys(topology());
01134 Bit_Matrix new_sat_g;
01135 empty = minimize(true, copy_of_con_sys, new_gen_sys, new_sat_g);
01136 }
01137
01138 if (empty && check_not_empty) {
01139 #ifndef NDEBUG
01140 cerr << "Unsatisfiable system of constraints!"
01141 << endl;
01142 #endif
01143 goto bomb;
01144 }
01145
01146 if (constraints_are_minimized()) {
01147
01148
01149
01150
01151 if (cs_without_pending.num_rows() != copy_of_con_sys.num_rows()
01152 || cs_without_pending.num_equalities()
01153 != copy_of_con_sys.num_equalities()) {
01154 #ifndef NDEBUG
01155 cerr << "Constraints are declared minimized, but they are not!\n"
01156 << "Here is the minimized form of the constraints:\n";
01157 copy_of_con_sys.ascii_dump(cerr);
01158 cerr << endl;
01159 #endif
01160 goto bomb;
01161 }
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171 copy_of_con_sys.strong_normalize();
01172 copy_of_con_sys.sort_rows();
01173 cs_without_pending.simplify();
01174 cs_without_pending.strong_normalize();
01175 cs_without_pending.sort_rows();
01176 if (cs_without_pending != copy_of_con_sys) {
01177 #ifndef NDEBUG
01178 cerr << "Constraints are declared minimized, but they are not!\n"
01179 << "Here is the minimized form of the constraints:\n";
01180 copy_of_con_sys.ascii_dump(cerr);
01181 cerr << endl;
01182 #endif
01183 goto bomb;
01184 }
01185 }
01186 }
01187
01188 if (sat_c_is_up_to_date())
01189 for (dimension_type i = sat_c.num_rows(); i-- > 0; ) {
01190 const Generator tmp_gen = gen_sys[i];
01191 const Bit_Row tmp_sat = sat_c[i];
01192 for (dimension_type j = sat_c.num_columns(); j-- > 0; )
01193 if (Scalar_Products::sign(con_sys[j], tmp_gen) != tmp_sat[j]) {
01194 #ifndef NDEBUG
01195 cerr << "sat_c is declared up-to-date, but it is not!"
01196 << endl;
01197 #endif
01198 goto bomb;
01199 }
01200 }
01201
01202 if (sat_g_is_up_to_date())
01203 for (dimension_type i = sat_g.num_rows(); i-- > 0; ) {
01204 const Constraint tmp_con = con_sys[i];
01205 const Bit_Row tmp_sat = sat_g[i];
01206 for (dimension_type j = sat_g.num_columns(); j-- > 0; )
01207 if (Scalar_Products::sign(tmp_con, gen_sys[j]) != tmp_sat[j]) {
01208 #ifndef NDEBUG
01209 cerr << "sat_g is declared up-to-date, but it is not!"
01210 << endl;
01211 #endif
01212 goto bomb;
01213 }
01214 }
01215
01216 if (has_pending_constraints()) {
01217 if (con_sys.num_pending_rows() == 0) {
01218 #ifndef NDEBUG
01219 cerr << "The polyhedron is declared to have pending constraints, "
01220 << "but con_sys has no pending rows!"
01221 << endl;
01222 #endif
01223 goto bomb;
01224 }
01225 }
01226
01227 if (has_pending_generators()) {
01228 if (gen_sys.num_pending_rows() == 0) {
01229 #ifndef NDEBUG
01230 cerr << "The polyhedron is declared to have pending generators, "
01231 << "but gen_sys has no pending rows!"
01232 << endl;
01233 #endif
01234 goto bomb;
01235 }
01236 }
01237
01238 return true;
01239
01240 bomb:
01241 #ifndef NDEBUG
01242 cerr << "Here is the guilty polyhedron:"
01243 << endl;
01244 ascii_dump(cerr);
01245 #endif
01246 return false;
01247 }
01248
01249 void
01250 PPL::Polyhedron::add_constraint(const Constraint& c) {
01251
01252 if (c.is_strict_inequality() && is_necessarily_closed()) {
01253
01254 if (c.is_tautological())
01255 return;
01256 if (c.is_inconsistent()) {
01257 set_empty();
01258 return;
01259 }
01260
01261 throw_topology_incompatible("add_constraint(c)", "c", c);
01262 }
01263
01264
01265
01266 if (space_dim < c.space_dimension())
01267 throw_dimension_incompatible("add_constraint(c)", "c", c);
01268
01269 if (!marked_empty())
01270 refine_no_check(c);
01271 }
01272
01273 void
01274 PPL::Polyhedron::add_congruence(const Congruence& cg) {
01275
01276
01277 if (space_dim < cg.space_dimension())
01278 throw_dimension_incompatible("add_congruence(cg)", "cg", cg);
01279
01280
01281 if (cg.is_proper_congruence()) {
01282 if (cg.is_tautological())
01283 return;
01284 if (cg.is_inconsistent()) {
01285 set_empty();
01286 return;
01287 }
01288
01289 throw_invalid_argument("add_congruence(cg)",
01290 "cg is a non-trivial, proper congruence");
01291 }
01292
01293 PPL_ASSERT(cg.is_equality());
01294
01295 if (marked_empty())
01296 return;
01297 if (space_dim == 0) {
01298 if (cg.is_inconsistent())
01299 set_empty();
01300 return;
01301 }
01302
01303
01304 Linear_Expression le(cg);
01305 Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01306
01307 c.strong_normalize();
01308 refine_no_check(c);
01309 }
01310
01311 void
01312 PPL::Polyhedron::add_generator(const Generator& g) {
01313
01314 if (g.is_closure_point() && is_necessarily_closed())
01315 throw_topology_incompatible("add_generator(g)", "g", g);
01316
01317
01318 const dimension_type g_space_dim = g.space_dimension();
01319 if (space_dim < g_space_dim)
01320 throw_dimension_incompatible("add_generator(g)", "g", g);
01321
01322
01323 if (space_dim == 0) {
01324
01325 PPL_ASSERT(g.is_point() || g.is_closure_point());
01326
01327 if (marked_empty()) {
01328 if (g.type() != Generator::POINT)
01329 throw_invalid_generator("add_generator(g)", "g");
01330 else
01331 set_zero_dim_univ();
01332 }
01333 PPL_ASSERT_HEAVY(OK());
01334 return;
01335 }
01336
01337 if (marked_empty()
01338 || (has_pending_constraints() && !process_pending_constraints())
01339 || (!generators_are_up_to_date() && !update_generators())) {
01340
01341
01342 if (!g.is_point())
01343 throw_invalid_generator("add_generator(g)", "g");
01344 if (g.is_necessarily_closed() || !is_necessarily_closed()) {
01345 gen_sys.insert(g);
01346
01347
01348 gen_sys.adjust_topology_and_space_dimension(topology(), space_dim);
01349 if (!is_necessarily_closed()) {
01350
01351
01352
01353
01354 Generator& cp = gen_sys[gen_sys.num_rows() - 1];
01355 cp[space_dim + 1] = 0;
01356 cp.normalize();
01357
01358 gen_sys.insert(g);
01359 }
01360 }
01361 else {
01362
01363
01364
01365
01366
01367 const Linear_Expression nc_expr = Linear_Expression(g);
01368 gen_sys.insert(Generator::point(nc_expr, g.divisor()));
01369
01370
01371 gen_sys.adjust_topology_and_space_dimension(topology(), space_dim);
01372 }
01373
01374 clear_empty();
01375 set_generators_minimized();
01376 }
01377 else {
01378 PPL_ASSERT(generators_are_up_to_date());
01379 const bool has_pending = can_have_something_pending();
01380 if (g.is_necessarily_closed() || !is_necessarily_closed()) {
01381
01382
01383 if (has_pending)
01384 gen_sys.insert_pending(g);
01385 else
01386 gen_sys.insert(g);
01387 if (!is_necessarily_closed() && g.is_point()) {
01388
01389
01390
01391
01392 Generator& cp = gen_sys[gen_sys.num_rows() - 1];
01393 cp[space_dim + 1] = 0;
01394 cp.normalize();
01395
01396 if (has_pending)
01397 gen_sys.insert_pending(g);
01398 else
01399 gen_sys.insert(g);
01400 }
01401 }
01402 else {
01403 PPL_ASSERT(!g.is_closure_point());
01404
01405
01406
01407
01408
01409 const Linear_Expression nc_expr = Linear_Expression(g);
01410 switch (g.type()) {
01411 case Generator::LINE:
01412 if (has_pending)
01413 gen_sys.insert_pending(Generator::line(nc_expr));
01414 else
01415 gen_sys.insert(Generator::line(nc_expr));
01416 break;
01417 case Generator::RAY:
01418 if (has_pending)
01419 gen_sys.insert_pending(Generator::ray(nc_expr));
01420 else
01421 gen_sys.insert(Generator::ray(nc_expr));
01422 break;
01423 case Generator::POINT:
01424 if (has_pending)
01425 gen_sys.insert_pending(Generator::point(nc_expr, g.divisor()));
01426 else
01427 gen_sys.insert(Generator::point(nc_expr, g.divisor()));
01428 break;
01429 default:
01430 throw_runtime_error("add_generator(const Generator& g)");
01431 }
01432 }
01433
01434 if (has_pending)
01435 set_generators_pending();
01436 else {
01437
01438
01439 clear_generators_minimized();
01440 clear_constraints_up_to_date();
01441 }
01442 }
01443 PPL_ASSERT_HEAVY(OK());
01444 }
01445
01446 void
01447 PPL::Polyhedron::add_recycled_constraints(Constraint_System& cs) {
01448
01449 if (is_necessarily_closed() && cs.has_strict_inequalities()) {
01450
01451
01452 for (Constraint_System::const_iterator i = cs.begin(),
01453 i_end = cs.end(); i != i_end; ++i) {
01454 if (i->is_strict_inequality()
01455 && !i->is_inconsistent())
01456 throw_topology_incompatible("add_recycled_constraints(cs)",
01457 "cs", cs);
01458 }
01459
01460 set_empty();
01461 return;
01462 }
01463
01464
01465
01466 const dimension_type cs_space_dim = cs.space_dimension();
01467 if (space_dim < cs_space_dim)
01468 throw_dimension_incompatible("add_recycled_constraints(cs)", "cs", cs);
01469
01470
01471 if (cs.has_no_rows())
01472 return;
01473
01474 if (space_dim == 0) {
01475
01476
01477
01478
01479
01480 if (cs.begin() != cs.end())
01481
01482
01483 status.set_empty();
01484 return;
01485 }
01486
01487 if (marked_empty())
01488 return;
01489
01490
01491 if (has_pending_generators())
01492 process_pending_generators();
01493 else if (!constraints_are_up_to_date())
01494 update_constraints();
01495
01496
01497
01498 cs.adjust_topology_and_space_dimension(topology(), space_dim);
01499
01500 const bool adding_pending = can_have_something_pending();
01501
01502
01503
01504
01505 const dimension_type old_num_rows = con_sys.num_rows();
01506 const dimension_type cs_num_rows = cs.num_rows();
01507 const dimension_type cs_num_columns = cs.num_columns();
01508 con_sys.add_zero_rows(cs_num_rows,
01509 Linear_Row::Flags(topology(),
01510 Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
01511 for (dimension_type i = cs_num_rows; i-- > 0; ) {
01512
01513
01514
01515 Constraint& new_c = con_sys[old_num_rows + i];
01516 Constraint& old_c = cs[i];
01517 if (old_c.is_equality())
01518 new_c.set_is_equality();
01519 for (dimension_type j = cs_num_columns; j-- > 0; )
01520 std::swap(new_c[j], old_c[j]);
01521 }
01522
01523 if (adding_pending)
01524 set_constraints_pending();
01525 else {
01526
01527 con_sys.unset_pending_rows();
01528
01529 con_sys.set_sorted(false);
01530
01531 clear_constraints_minimized();
01532 clear_generators_up_to_date();
01533 }
01534
01535
01536 PPL_ASSERT_HEAVY(OK());
01537 }
01538
01539 void
01540 PPL::Polyhedron::add_constraints(const Constraint_System& cs) {
01541
01542 Constraint_System cs_copy = cs;
01543 add_recycled_constraints(cs_copy);
01544 }
01545
01546 void
01547 PPL::Polyhedron::add_recycled_generators(Generator_System& gs) {
01548
01549 if (is_necessarily_closed() && gs.has_closure_points())
01550 throw_topology_incompatible("add_recycled_generators(gs)", "gs", gs);
01551
01552
01553 const dimension_type gs_space_dim = gs.space_dimension();
01554 if (space_dim < gs_space_dim)
01555 throw_dimension_incompatible("add_recycled_generators(gs)", "gs", gs);
01556
01557
01558 if (gs.has_no_rows())
01559 return;
01560
01561
01562
01563 if (space_dim == 0) {
01564 if (marked_empty() && !gs.has_points())
01565 throw_invalid_generators("add_recycled_generators(gs)", "gs");
01566 set_zero_dim_univ();
01567 PPL_ASSERT_HEAVY(OK(true));
01568 return;
01569 }
01570
01571
01572
01573 gs.adjust_topology_and_space_dimension(topology(), space_dim);
01574
01575
01576 if (!is_necessarily_closed())
01577 gs.add_corresponding_closure_points();
01578
01579
01580 if ((has_pending_constraints() && !process_pending_constraints())
01581 || (!generators_are_up_to_date() && !minimize())) {
01582
01583
01584 if (!gs.has_points())
01585 throw_invalid_generators("add_recycled_generators(gs)", "gs");
01586
01587 std::swap(gen_sys, gs);
01588 if (gen_sys.num_pending_rows() > 0) {
01589
01590
01591
01592
01593 gen_sys.unset_pending_rows();
01594 gen_sys.set_sorted(false);
01595 }
01596 set_generators_up_to_date();
01597 clear_empty();
01598 PPL_ASSERT_HEAVY(OK());
01599 return;
01600 }
01601
01602 const bool adding_pending = can_have_something_pending();
01603
01604
01605
01606
01607 const dimension_type old_num_rows = gen_sys.num_rows();
01608 const dimension_type gs_num_rows = gs.num_rows();
01609 const dimension_type gs_num_columns = gs.num_columns();
01610 gen_sys.add_zero_rows(gs_num_rows,
01611 Linear_Row::Flags(topology(),
01612 Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
01613 for (dimension_type i = gs_num_rows; i-- > 0; ) {
01614
01615
01616
01617 Generator& new_g = gen_sys[old_num_rows + i];
01618 Generator& old_g = gs[i];
01619 if (old_g.is_line())
01620 new_g.set_is_line();
01621 for (dimension_type j = gs_num_columns; j-- > 0; )
01622 std::swap(new_g[j], old_g[j]);
01623 }
01624
01625 if (adding_pending)
01626 set_generators_pending();
01627 else {
01628
01629 gen_sys.unset_pending_rows();
01630
01631 gen_sys.set_sorted(false);
01632
01633 clear_constraints_up_to_date();
01634 clear_generators_minimized();
01635 }
01636 PPL_ASSERT_HEAVY(OK(true));
01637 }
01638
01639 void
01640 PPL::Polyhedron::add_generators(const Generator_System& gs) {
01641
01642 Generator_System gs_copy = gs;
01643 add_recycled_generators(gs_copy);
01644 }
01645
01646 void
01647 PPL::Polyhedron::add_congruences(const Congruence_System& cgs) {
01648
01649 if (space_dim < cgs.space_dimension())
01650 throw_dimension_incompatible("add_congruences(cgs)", "cgs", cgs);
01651
01652 Constraint_System cs;
01653 bool inserted = false;
01654 for (Congruence_System::const_iterator i = cgs.begin(),
01655 cgs_end = cgs.end(); i != cgs_end; ++i) {
01656 const Congruence& cg = *i;
01657 if (cg.is_equality()) {
01658 Linear_Expression le(cg);
01659 Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01660
01661 c.strong_normalize();
01662
01663 cs.insert(c);
01664 inserted = true;
01665 }
01666 else {
01667 PPL_ASSERT(cg.is_proper_congruence());
01668 if (cg.is_inconsistent()) {
01669 set_empty();
01670 return;
01671 }
01672 if (!cg.is_tautological())
01673 throw_invalid_argument("add_congruences(cgs)",
01674 "cgs has a non-trivial, proper congruence");
01675 }
01676 }
01677
01678 if (inserted)
01679 add_recycled_constraints(cs);
01680 }
01681
01682 void
01683 PPL::Polyhedron::refine_with_constraint(const Constraint& c) {
01684
01685 if (space_dim < c.space_dimension())
01686 throw_dimension_incompatible("refine_with_constraint(c)", "c", c);
01687
01688 if (!marked_empty())
01689 refine_no_check(c);
01690 }
01691
01692 void
01693 PPL::Polyhedron::refine_with_congruence(const Congruence& cg) {
01694
01695 if (space_dim < cg.space_dimension())
01696 throw_dimension_incompatible("refine_with_congruence(cg)", "cg", cg);
01697
01698
01699 if (marked_empty())
01700 return;
01701
01702
01703 if (space_dim == 0) {
01704 if (!cg.is_tautological())
01705 set_empty();
01706 return;
01707 }
01708
01709 if (cg.is_equality()) {
01710 Linear_Expression le(cg);
01711 Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01712
01713 c.strong_normalize();
01714 refine_no_check(c);
01715 }
01716 }
01717
01718 void
01719 PPL::Polyhedron::refine_with_constraints(const Constraint_System& cs) {
01720
01721
01722
01723 const dimension_type cs_space_dim = cs.space_dimension();
01724 if (space_dim < cs_space_dim)
01725 throw_dimension_incompatible("refine_with_constraints(cs)a",
01726 "cs", cs);
01727
01728
01729 if (cs.has_no_rows())
01730 return;
01731
01732 if (space_dim == 0) {
01733
01734
01735
01736
01737
01738 if (cs.begin() != cs.end())
01739
01740
01741 status.set_empty();
01742 return;
01743 }
01744
01745 if (marked_empty())
01746 return;
01747
01748
01749 if (has_pending_generators())
01750 process_pending_generators();
01751 else if (!constraints_are_up_to_date())
01752 update_constraints();
01753
01754 const bool adding_pending = can_have_something_pending();
01755 for (dimension_type i = cs.num_rows(); i-- > 0; ) {
01756 const Constraint& c = cs[i];
01757
01758 if (c.is_necessarily_closed() || !is_necessarily_closed())
01759
01760
01761 if (adding_pending)
01762 con_sys.insert_pending(c);
01763 else
01764 con_sys.insert(c);
01765 else {
01766
01767
01768
01769
01770
01771 Linear_Expression nc_expr = Linear_Expression(c);
01772 if (c.is_equality())
01773 if (adding_pending)
01774 con_sys.insert_pending(nc_expr == 0);
01775 else
01776 con_sys.insert(nc_expr == 0);
01777 else
01778 if (adding_pending)
01779 con_sys.insert_pending(nc_expr >= 0);
01780 else
01781 con_sys.insert(nc_expr >= 0);
01782 }
01783 }
01784
01785 if (adding_pending)
01786 set_constraints_pending();
01787 else {
01788
01789 clear_constraints_minimized();
01790 clear_generators_up_to_date();
01791 }
01792
01793
01794
01795 PPL_ASSERT_HEAVY(OK());
01796 }
01797
01798 void
01799 PPL::Polyhedron::refine_with_congruences(const Congruence_System& cgs) {
01800
01801 if (space_dim < cgs.space_dimension())
01802 throw_dimension_incompatible("refine_with_congruences(cgs)", "cgs", cgs);
01803
01804 Constraint_System cs;
01805 bool inserted = false;
01806 for (Congruence_System::const_iterator i = cgs.begin(),
01807 cgs_end = cgs.end(); i != cgs_end; ++i) {
01808 if (i->is_equality()) {
01809 Linear_Expression le(*i);
01810 Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01811
01812 c.strong_normalize();
01813
01814 cs.insert(c);
01815 inserted = true;
01816 }
01817 else if (i->is_inconsistent()) {
01818 set_empty();
01819 return;
01820 }
01821 }
01822
01823
01824 if (inserted)
01825 add_recycled_constraints(cs);
01826 }
01827
01828 void
01829 PPL::Polyhedron::unconstrain(const Variable var) {
01830
01831 if (space_dim < var.space_dimension())
01832 throw_dimension_incompatible("unconstrain(var)", var.space_dimension());
01833
01834
01835 if (marked_empty()
01836 || (has_pending_constraints() && !process_pending_constraints())
01837 || (!generators_are_up_to_date() && !update_generators()))
01838
01839 return;
01840
01841 PPL_ASSERT(generators_are_up_to_date());
01842
01843
01844 if (can_have_something_pending()) {
01845 gen_sys.insert_pending(Generator::line(var));
01846 set_generators_pending();
01847 }
01848 else {
01849 gen_sys.insert(Generator::line(var));
01850
01851
01852 clear_generators_minimized();
01853 clear_constraints_up_to_date();
01854 }
01855 PPL_ASSERT_HEAVY(OK(true));
01856 }
01857
01858 void
01859 PPL::Polyhedron::unconstrain(const Variables_Set& vars) {
01860
01861
01862
01863 if (vars.empty())
01864 return;
01865
01866
01867 const dimension_type min_space_dim = vars.space_dimension();
01868 if (space_dim < min_space_dim)
01869 throw_dimension_incompatible("unconstrain(vs)", min_space_dim);
01870
01871
01872 if (marked_empty()
01873 || (has_pending_constraints() && !process_pending_constraints())
01874 || (!generators_are_up_to_date() && !update_generators()))
01875
01876 return;
01877
01878 PPL_ASSERT(generators_are_up_to_date());
01879
01880
01881 Variables_Set::const_iterator vsi = vars.begin();
01882 Variables_Set::const_iterator vsi_end = vars.end();
01883 if (can_have_something_pending()) {
01884 for ( ; vsi != vsi_end; ++vsi)
01885 gen_sys.insert_pending(Generator::line(Variable(*vsi)));
01886 set_generators_pending();
01887 }
01888 else {
01889 for ( ; vsi != vsi_end; ++vsi)
01890 gen_sys.insert(Generator::line(Variable(*vsi)));
01891
01892
01893 clear_generators_minimized();
01894 clear_constraints_up_to_date();
01895 }
01896 PPL_ASSERT_HEAVY(OK(true));
01897 }
01898
01899 void
01900 PPL::Polyhedron::intersection_assign(const Polyhedron& y) {
01901 Polyhedron& x = *this;
01902
01903 if (x.topology() != y.topology())
01904 throw_topology_incompatible("intersection_assign(y)", "y", y);
01905
01906 if (x.space_dim != y.space_dim)
01907 throw_dimension_incompatible("intersection_assign(y)", "y", y);
01908
01909
01910 if (x.marked_empty())
01911 return;
01912 if (y.marked_empty()) {
01913 x.set_empty();
01914 return;
01915 }
01916
01917
01918
01919
01920 if (x.space_dim == 0)
01921 return;
01922
01923
01924
01925 if (x.has_pending_generators())
01926 x.process_pending_generators();
01927 else if (!x.constraints_are_up_to_date())
01928 x.update_constraints();
01929
01930 if (y.has_pending_generators())
01931 y.process_pending_generators();
01932 else if (!y.constraints_are_up_to_date())
01933 y.update_constraints();
01934
01935
01936
01937 PPL_ASSERT(!x.has_pending_generators() && x.constraints_are_up_to_date());
01938 PPL_ASSERT(!y.has_pending_generators() && y.constraints_are_up_to_date());
01939
01940
01941
01942 if (x.can_have_something_pending()) {
01943 x.con_sys.add_pending_rows(y.con_sys);
01944 x.set_constraints_pending();
01945 }
01946 else {
01947
01948
01949
01950 if (x.con_sys.is_sorted()
01951 && y.con_sys.is_sorted() && !y.has_pending_constraints())
01952 x.con_sys.merge_rows_assign(y.con_sys);
01953 else
01954 x.con_sys.add_rows(y.con_sys);
01955
01956
01957 x.clear_generators_up_to_date();
01958 x.clear_constraints_minimized();
01959 }
01960 PPL_ASSERT_HEAVY(x.OK() && y.OK());
01961 }
01962
01963 namespace {
01964
01965 struct Ruled_Out_Pair {
01966 PPL::dimension_type constraint_index;
01967 PPL::dimension_type num_ruled_out;
01968 };
01969
01970 struct Ruled_Out_Less_Than {
01971 bool operator()(const Ruled_Out_Pair& x,
01972 const Ruled_Out_Pair& y) const {
01973 return x.num_ruled_out > y.num_ruled_out;
01974 }
01975 };
01976
01977 bool
01978 add_to_system_and_check_independence(PPL::Linear_System& eq_sys,
01979 const PPL::Linear_Row& eq) {
01980
01981 PPL_ASSERT(eq.is_line_or_equality());
01982 eq_sys.insert(eq);
01983 const PPL::dimension_type eq_sys_num_rows = eq_sys.num_rows();
01984 const PPL::dimension_type rank = eq_sys.gauss(eq_sys_num_rows);
01985 if (rank == eq_sys_num_rows)
01986
01987 return true;
01988 else {
01989
01990 PPL_ASSERT(rank == eq_sys_num_rows - 1);
01991 eq_sys.erase_to_end(rank);
01992 return false;
01993 }
01994 }
01995
01996
01997
01998
01999
02000
02001
02002
02003 void
02004 drop_redundant_inequalities(std::vector<const PPL::Constraint*>& p_ineqs,
02005 const PPL::Topology topology,
02006 const PPL::Bit_Matrix& sat,
02007 const PPL::dimension_type rank) {
02008 using namespace Parma_Polyhedra_Library;
02009 const dimension_type num_rows = p_ineqs.size();
02010 PPL_ASSERT(num_rows > 0);
02011
02012 const dimension_type space_dim = p_ineqs[0]->space_dimension();
02013 PPL_ASSERT(space_dim > 0 && space_dim >= rank);
02014 const dimension_type num_coefficients
02015 = space_dim + (topology == NECESSARILY_CLOSED ? 0 : 1);
02016 const dimension_type min_sat = num_coefficients - rank;
02017 const dimension_type num_cols_sat = sat.num_columns();
02018
02019
02020 for (dimension_type i = num_rows; i-- > 0; ) {
02021 if (sat[i].empty())
02022
02023 p_ineqs[i] = 0;
02024 else {
02025 const dimension_type num_sat = num_cols_sat - sat[i].count_ones();
02026 if (num_sat < min_sat)
02027 p_ineqs[i] = 0;
02028 }
02029 }
02030
02031
02032
02033 for (dimension_type i = 0; i < num_rows; ++i) {
02034 if (p_ineqs[i]) {
02035 for (dimension_type j = 0; j < num_rows; ++j) {
02036 bool strict_subset;
02037 if (p_ineqs[j] && i != j
02038 && subset_or_equal(sat[j], sat[i], strict_subset)) {
02039 if (strict_subset) {
02040 p_ineqs[i] = 0;
02041 break;
02042 }
02043 else
02044
02045 p_ineqs[j] = 0;
02046 }
02047 }
02048 }
02049 }
02050 }
02051
02052 }
02053
02054 bool
02055 PPL::Polyhedron::simplify_using_context_assign(const Polyhedron& y) {
02056 Polyhedron& x = *this;
02057
02058 if (x.topology() != y.topology())
02059 throw_topology_incompatible("simplify_using_context_assign(y)", "y", y);
02060
02061 if (x.space_dim != y.space_dim)
02062 throw_dimension_incompatible("simplify_using_context_assign(y)", "y", y);
02063
02064
02065 if (x.space_dim == 0) {
02066 if (y.is_empty()) {
02067 x.set_zero_dim_univ();
02068 return false;
02069 }
02070 else
02071 return !x.is_empty();
02072 }
02073
02074
02075 if (!y.minimize()) {
02076 Polyhedron ph(x.topology(), x.space_dim, UNIVERSE);
02077 swap(ph);
02078 return false;
02079 }
02080
02081
02082 if (!x.minimize()) {
02083
02084 PPL_ASSERT(!y.has_pending_generators() && y.constraints_are_up_to_date());
02085 for (dimension_type i = y.con_sys.num_rows(); i-- > 0; ) {
02086 const Constraint& y_con_sys_i = y.con_sys[i];
02087 if (!y_con_sys_i.is_tautological()) {
02088
02089
02090
02091 Polyhedron ph(x.topology(), x.space_dim, UNIVERSE);
02092 Linear_Expression le(y_con_sys_i);
02093 switch (y_con_sys_i.type()) {
02094 case Constraint::EQUALITY:
02095 ph.refine_no_check(le == 1);
02096 break;
02097 case Constraint::NONSTRICT_INEQUALITY:
02098 ph.refine_no_check(le <= -1);
02099 break;
02100 case Constraint::STRICT_INEQUALITY:
02101 ph.refine_no_check(le == 0);
02102 break;
02103 }
02104 swap(ph);
02105 PPL_ASSERT_HEAVY(OK());
02106 return false;
02107 }
02108 }
02109
02110 return false;
02111 }
02112
02113 PPL_ASSERT(x.constraints_are_minimized()
02114 && !x.has_something_pending()
02115 && y.generators_are_minimized()
02116 && !y.has_something_pending());
02117 const Constraint_System& x_cs = x.con_sys;
02118 const dimension_type x_cs_num_rows = x_cs.num_rows();
02119 const Generator_System& y_gs = y.gen_sys;
02120
02121
02122
02123
02124 std::vector<bool> redundant_by_y(x_cs_num_rows, false);
02125 dimension_type num_redundant_by_y = 0;
02126 for (dimension_type i = 0; i < x_cs_num_rows; ++i)
02127 if (y_gs.satisfied_by_all_generators(x_cs[i])) {
02128 redundant_by_y[i] = true;
02129 ++num_redundant_by_y;
02130 }
02131
02132 Constraint_System result_cs;
02133
02134 if (num_redundant_by_y < x_cs_num_rows) {
02135
02136 const Constraint_System& y_cs = y.con_sys;
02137 const dimension_type y_cs_num_rows = y_cs.num_rows();
02138
02139 const bool x_first = (x_cs_num_rows > y_cs_num_rows);
02140 Polyhedron z(x_first ? x : y);
02141 if (x_first)
02142 z.add_constraints(y_cs);
02143 else {
02144
02145 Constraint_System tmp_cs;
02146 for (dimension_type i = 0; i < x_cs_num_rows; ++i) {
02147 if (!redundant_by_y[i])
02148 tmp_cs.insert(x_cs[i]);
02149 }
02150 z.add_recycled_constraints(tmp_cs);
02151 }
02152 if (!z.minimize()) {
02153
02154
02155
02156 MIP_Problem lp;
02157 if (x.is_necessarily_closed()) {
02158 lp.add_space_dimensions_and_embed(x.space_dim);
02159 lp.add_constraints(y_cs);
02160 }
02161 else {
02162
02163
02164
02165
02166 const_cast<Constraint_System&>(y_cs).set_necessarily_closed();
02167 try {
02168 lp.add_space_dimensions_and_embed(x.space_dim+1);
02169 lp.add_constraints(y_cs);
02170 const_cast<Constraint_System&>(y_cs).set_not_necessarily_closed();
02171 }
02172 catch (...) {
02173 const_cast<Constraint_System&>(y_cs).set_not_necessarily_closed();
02174 throw;
02175 }
02176 }
02177
02178
02179
02180
02181
02182 std::vector<Ruled_Out_Pair>
02183 ruled_out_vec(x_cs_num_rows - num_redundant_by_y);
02184 for (dimension_type i = 0, j = 0; i < x_cs_num_rows; ++i) {
02185 if (!redundant_by_y[i]) {
02186 const Constraint& c = x_cs[i];
02187 Topology_Adjusted_Scalar_Product_Sign sps(c);
02188 dimension_type num_ruled_out_generators = 0;
02189 for (Generator_System::const_iterator k = y_gs.begin(),
02190 y_gs_end = y_gs.end(); k != y_gs_end; ++k) {
02191 const Generator& g = *k;
02192 const int sp_sign = sps(g, c);
02193 if (x.is_necessarily_closed()) {
02194 if (g.is_line()) {
02195
02196 if (sp_sign != 0)
02197 goto ruled_out;
02198 }
02199 else {
02200
02201 if (c.is_inequality()) {
02202
02203 if (sp_sign < 0)
02204 goto ruled_out;
02205 }
02206 else
02207
02208 if (sp_sign != 0)
02209 goto ruled_out;
02210 }
02211 }
02212 else
02213
02214 switch (g.type()) {
02215 case Generator::LINE:
02216
02217 if (sp_sign != 0)
02218 goto ruled_out;
02219 break;
02220 case Generator::POINT:
02221
02222
02223 switch (c.type()) {
02224 case Constraint::EQUALITY:
02225 if (sp_sign != 0)
02226 goto ruled_out;
02227 break;
02228 case Constraint::NONSTRICT_INEQUALITY:
02229 if (sp_sign < 0)
02230 goto ruled_out;
02231 break;
02232 case Constraint::STRICT_INEQUALITY:
02233 if (sp_sign <= 0)
02234 goto ruled_out;
02235 break;
02236 }
02237 break;
02238 case Generator::RAY:
02239
02240 case Generator::CLOSURE_POINT:
02241 if (c.is_inequality()) {
02242
02243
02244 if (sp_sign < 0)
02245 goto ruled_out;
02246 }
02247 else
02248
02249 if (sp_sign != 0)
02250 goto ruled_out;
02251 break;
02252 }
02253
02254
02255 continue;
02256 ruled_out:
02257 ++num_ruled_out_generators;
02258 }
02259 ruled_out_vec[j].constraint_index = i;
02260 ruled_out_vec[j].num_ruled_out = num_ruled_out_generators;
02261 ++j;
02262 }
02263 }
02264 std::sort(ruled_out_vec.begin(), ruled_out_vec.end(),
02265 Ruled_Out_Less_Than());
02266
02267 for (std::vector<Ruled_Out_Pair>::const_iterator
02268 j = ruled_out_vec.begin(), rov_end = ruled_out_vec.end();
02269 j != rov_end;
02270 ++j) {
02271 const Constraint& c = x_cs[j->constraint_index];
02272 result_cs.insert(c);
02273 lp.add_constraint(c);
02274 MIP_Problem_Status status = lp.solve();
02275 if (status == UNFEASIBLE_MIP_PROBLEM) {
02276 Polyhedron result_ph(x.topology(), x.space_dim, UNIVERSE);
02277 result_ph.add_constraints(result_cs);
02278 x.swap(result_ph);
02279 PPL_ASSERT_HEAVY(x.OK());
02280 return false;
02281 }
02282 }
02283
02284 PPL_ASSERT(false);
02285 }
02286 else {
02287
02288 PPL_ASSERT(z.constraints_are_minimized()
02289 && z.generators_are_minimized()
02290 && !z.has_something_pending());
02291 const Constraint_System& z_cs = z.con_sys;
02292 const Generator_System& z_gs = z.gen_sys;
02293 const dimension_type z_gs_num_rows = z_gs.num_rows();
02294
02295
02296
02297 dimension_type x_cs_num_eq = 0;
02298 while (x_cs[x_cs_num_eq].is_equality())
02299 ++x_cs_num_eq;
02300 dimension_type y_cs_num_eq = 0;
02301 while (y_cs[y_cs_num_eq].is_equality())
02302 ++y_cs_num_eq;
02303 dimension_type z_cs_num_eq = 0;
02304 while (z_cs[z_cs_num_eq].is_equality())
02305 ++z_cs_num_eq;
02306 PPL_ASSERT(x_cs_num_eq <= z_cs_num_eq && y_cs_num_eq <= z_cs_num_eq);
02307
02308
02309 Constraint_System nonred_eq;
02310 dimension_type num_nonred_eq = 0;
02311 const dimension_type needed_nonred_eq = z_cs_num_eq - y_cs_num_eq;
02312 Linear_System eqs(x.topology());
02313 if (needed_nonred_eq > 0) {
02314
02315 for (dimension_type i = 0; i < y_cs_num_eq; ++i)
02316 eqs.insert(y_cs[i]);
02317
02318
02319 for (dimension_type i = 0; i < x_cs_num_eq; ++i) {
02320 const Constraint& x_cs_i = x_cs[i];
02321 if (add_to_system_and_check_independence(eqs, x_cs_i)) {
02322
02323 nonred_eq.insert(x_cs_i);
02324 ++num_nonred_eq;
02325 if (num_nonred_eq == needed_nonred_eq)
02326
02327 break;
02328 }
02329 }
02330
02331
02332
02333
02334 PPL_ASSERT(eqs.num_rows() <= z_cs_num_eq);
02335 PPL_ASSERT(num_nonred_eq <= needed_nonred_eq);
02336 PPL_ASSERT(z_cs_num_eq - eqs.num_rows()
02337 == needed_nonred_eq - num_nonred_eq);
02338 }
02339
02340
02341
02342 std::vector<const Constraint*> p_nonred_ineq;
02343
02344 for (dimension_type i = y_cs_num_eq; i < y_cs_num_rows; ++i)
02345 p_nonred_ineq.push_back(&y_cs[i]);
02346
02347 for (dimension_type i = x_cs_num_eq; i < x_cs_num_rows; ++i)
02348 if (!redundant_by_y[i])
02349 p_nonred_ineq.push_back(&x_cs[i]);
02350
02351 const dimension_type p_nonred_ineq_size = p_nonred_ineq.size();
02352 const dimension_type y_cs_num_ineq = y_cs_num_rows - y_cs_num_eq;
02353
02354
02355 const dimension_type sat_num_rows = p_nonred_ineq_size;
02356 Bit_Matrix sat(sat_num_rows, z_gs_num_rows);
02357 for (dimension_type i = sat_num_rows; i-- > 0; ) {
02358 const Constraint& nonred_ineq_i = *(p_nonred_ineq[i]);
02359 Bit_Row& sat_i = sat[i];
02360 for (dimension_type j = z_gs_num_rows; j-- > 0; )
02361 if (Scalar_Products::sign(nonred_ineq_i, z_gs[j]))
02362 sat_i.set(j);
02363 if (sat_i.empty() && num_nonred_eq < needed_nonred_eq) {
02364
02365
02366
02367 PPL_ASSERT(i >= y_cs_num_ineq);
02368
02369 Linear_Row masked_eq = Linear_Row(nonred_ineq_i);
02370 masked_eq.set_is_line_or_equality();
02371 masked_eq.sign_normalize();
02372 if (add_to_system_and_check_independence(eqs, masked_eq)) {
02373
02374 nonred_eq.insert(nonred_ineq_i);
02375 ++num_nonred_eq;
02376 }
02377 }
02378 }
02379
02380 PPL_ASSERT(num_nonred_eq == needed_nonred_eq);
02381
02382 drop_redundant_inequalities(p_nonred_ineq, x.topology(),
02383 sat, z_cs_num_eq);
02384
02385
02386 result_cs.swap(nonred_eq);
02387
02388
02389 for (dimension_type i = y_cs_num_ineq; i < p_nonred_ineq_size; ++i)
02390 if (p_nonred_ineq[i])
02391 result_cs.insert(*p_nonred_ineq[i]);
02392 }
02393 }
02394
02395 Polyhedron result_ph(x.topology(), x.space_dim, UNIVERSE);
02396 result_ph.add_recycled_constraints(result_cs);
02397 x.swap(result_ph);
02398 PPL_ASSERT_HEAVY(x.OK());
02399 return true;
02400 }
02401
02402 void
02403 PPL::Polyhedron::poly_hull_assign(const Polyhedron& y) {
02404 Polyhedron& x = *this;
02405
02406 if (x.topology() != y.topology())
02407 throw_topology_incompatible("poly_hull_assign(y)", "y", y);
02408
02409 if (x.space_dim != y.space_dim)
02410 throw_dimension_incompatible("poly_hull_assign(y)", "y", y);
02411
02412
02413 if (y.marked_empty())
02414 return;
02415 if (x.marked_empty()) {
02416 x = y;
02417 return;
02418 }
02419
02420
02421
02422
02423 if (x.space_dim == 0)
02424 return;
02425
02426
02427
02428 if ((x.has_pending_constraints() && !x.process_pending_constraints())
02429 || (!x.generators_are_up_to_date() && !x.update_generators())) {
02430
02431 x = y;
02432 return;
02433 }
02434 if ((y.has_pending_constraints() && !y.process_pending_constraints())
02435 || (!y.generators_are_up_to_date() && !y.update_generators()))
02436
02437 return;
02438
02439
02440
02441 PPL_ASSERT(!x.has_pending_constraints() && x.generators_are_up_to_date());
02442 PPL_ASSERT(!y.has_pending_constraints() && y.generators_are_up_to_date());
02443
02444
02445
02446 if (x.can_have_something_pending()) {
02447 x.gen_sys.add_pending_rows(y.gen_sys);
02448 x.set_generators_pending();
02449 }
02450 else {
02451
02452
02453
02454 if (x.gen_sys.is_sorted()
02455 && y.gen_sys.is_sorted() && !y.has_pending_generators())
02456 x.gen_sys.merge_rows_assign(y.gen_sys);
02457 else
02458 x.gen_sys.add_rows(y.gen_sys);
02459
02460
02461 x.clear_constraints_up_to_date();
02462 x.clear_generators_minimized();
02463 }
02464
02465 PPL_ASSERT_HEAVY(x.OK(true) && y.OK(true));
02466 }
02467
02468 void
02469 PPL::Polyhedron::poly_difference_assign(const Polyhedron& y) {
02470 Polyhedron& x = *this;
02471
02472 if (x.topology() != y.topology())
02473 throw_topology_incompatible("poly_difference_assign(y)", "y", y);
02474
02475 if (x.space_dim != y.space_dim)
02476 throw_dimension_incompatible("poly_difference_assign(y)", "y", y);
02477
02478
02479 if (y.marked_empty())
02480 return;
02481
02482 if (x.marked_empty())
02483 return;
02484
02485
02486
02487
02488 if (x.space_dim == 0) {
02489 x.set_empty();
02490 return;
02491 }
02492
02493
02494
02495
02496 if (y.contains(x)) {
02497 x.set_empty();
02498 return;
02499 }
02500
02501
02502
02503 if (!y.minimize())
02504 return;
02505 x.minimize();
02506
02507 Polyhedron new_polyhedron(topology(), x.space_dim, EMPTY);
02508
02509 const Constraint_System& y_cs = y.constraints();
02510 for (Constraint_System::const_iterator i = y_cs.begin(),
02511 y_cs_end = y_cs.end(); i != y_cs_end; ++i) {
02512 const Constraint& c = *i;
02513 PPL_ASSERT(!c.is_tautological());
02514 PPL_ASSERT(!c.is_inconsistent());
02515
02516
02517
02518
02519
02520
02521 if (x.relation_with(c).implies(Poly_Con_Relation::is_included()))
02522 continue;
02523 Polyhedron z = x;
02524 const Linear_Expression e = Linear_Expression(c);
02525 switch (c.type()) {
02526 case Constraint::NONSTRICT_INEQUALITY:
02527 if (is_necessarily_closed())
02528 z.refine_no_check(e <= 0);
02529 else
02530 z.refine_no_check(e < 0);
02531 break;
02532 case Constraint::STRICT_INEQUALITY:
02533 z.refine_no_check(e <= 0);
02534 break;
02535 case Constraint::EQUALITY:
02536 if (is_necessarily_closed())
02537
02538
02539 return;
02540 else {
02541 Polyhedron w = x;
02542 w.refine_no_check(e < 0);
02543 new_polyhedron.poly_hull_assign(w);
02544 z.refine_no_check(e > 0);
02545 }
02546 break;
02547 }
02548 new_polyhedron.poly_hull_assign(z);
02549 }
02550 *this = new_polyhedron;
02551
02552 PPL_ASSERT_HEAVY(OK());
02553 }
02554
02555 void
02556 PPL::Polyhedron::
02557 affine_image(const Variable var,
02558 const Linear_Expression& expr,
02559 Coefficient_traits::const_reference denominator) {
02560
02561 if (denominator == 0)
02562 throw_invalid_argument("affine_image(v, e, d)", "d == 0");
02563
02564
02565
02566
02567 if (space_dim < expr.space_dimension())
02568 throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
02569
02570 const dimension_type var_space_dim = var.space_dimension();
02571 if (space_dim < var_space_dim)
02572 throw_dimension_incompatible("affine_image(v, e, d)", "v", var);
02573
02574 if (marked_empty())
02575 return;
02576
02577 if (expr.coefficient(var) != 0) {
02578
02579
02580
02581 if (generators_are_up_to_date()) {
02582
02583
02584 if (denominator > 0)
02585 gen_sys.affine_image(var_space_dim, expr, denominator);
02586 else
02587 gen_sys.affine_image(var_space_dim, -expr, -denominator);
02588 }
02589 if (constraints_are_up_to_date()) {
02590
02591
02592
02593 Linear_Expression inverse;
02594 if (expr[var_space_dim] > 0) {
02595 inverse = -expr;
02596 inverse[var_space_dim] = denominator;
02597 con_sys.affine_preimage(var_space_dim, inverse, expr[var_space_dim]);
02598 }
02599 else {
02600
02601
02602
02603 inverse = expr;
02604 inverse[var_space_dim] = denominator;
02605 neg_assign(inverse[var_space_dim]);
02606 con_sys.affine_preimage(var_space_dim, inverse, -expr[var_space_dim]);
02607 }
02608 }
02609 }
02610 else {
02611
02612
02613 if (has_something_pending())
02614 remove_pending_to_obtain_generators();
02615 else if (!generators_are_up_to_date())
02616 minimize();
02617 if (!marked_empty()) {
02618
02619
02620 if (denominator > 0)
02621 gen_sys.affine_image(var_space_dim, expr, denominator);
02622 else
02623 gen_sys.affine_image(var_space_dim, -expr, -denominator);
02624
02625 clear_constraints_up_to_date();
02626 clear_generators_minimized();
02627 clear_sat_c_up_to_date();
02628 clear_sat_g_up_to_date();
02629 }
02630 }
02631 PPL_ASSERT_HEAVY(OK());
02632 }
02633
02634
02635 void
02636 PPL::Polyhedron::
02637 affine_preimage(const Variable var,
02638 const Linear_Expression& expr,
02639 Coefficient_traits::const_reference denominator) {
02640
02641 if (denominator == 0)
02642 throw_invalid_argument("affine_preimage(v, e, d)", "d == 0");
02643
02644
02645
02646
02647 if (space_dim < expr.space_dimension())
02648 throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
02649
02650 const dimension_type var_space_dim = var.space_dimension();
02651 if (space_dim < var_space_dim)
02652 throw_dimension_incompatible("affine_preimage(v, e, d)", "v", var);
02653
02654 if (marked_empty())
02655 return;
02656
02657 if (expr.coefficient(var) != 0) {
02658
02659
02660 if (constraints_are_up_to_date()) {
02661
02662
02663 if (denominator > 0)
02664 con_sys.affine_preimage(var_space_dim, expr, denominator);
02665 else
02666 con_sys.affine_preimage(var_space_dim, -expr, -denominator);
02667 }
02668 if (generators_are_up_to_date()) {
02669
02670
02671
02672 Linear_Expression inverse;
02673 if (expr[var_space_dim] > 0) {
02674 inverse = -expr;
02675 inverse[var_space_dim] = denominator;
02676 gen_sys.affine_image(var_space_dim, inverse, expr[var_space_dim]);
02677 }
02678 else {
02679
02680
02681
02682 inverse = expr;
02683 inverse[var_space_dim] = denominator;
02684 neg_assign(inverse[var_space_dim]);
02685 gen_sys.affine_image(var_space_dim, inverse, -expr[var_space_dim]);
02686 }
02687 }
02688 }
02689 else {
02690
02691
02692 if (has_something_pending())
02693 remove_pending_to_obtain_constraints();
02694 else if (!constraints_are_up_to_date())
02695 minimize();
02696
02697
02698 if (denominator > 0)
02699 con_sys.affine_preimage(var_space_dim, expr, denominator);
02700 else
02701 con_sys.affine_preimage(var_space_dim, -expr, -denominator);
02702
02703 clear_generators_up_to_date();
02704 clear_constraints_minimized();
02705 clear_sat_c_up_to_date();
02706 clear_sat_g_up_to_date();
02707 }
02708 PPL_ASSERT_HEAVY(OK());
02709 }
02710
02711 void
02712 PPL::Polyhedron::
02713 bounded_affine_image(const Variable var,
02714 const Linear_Expression& lb_expr,
02715 const Linear_Expression& ub_expr,
02716 Coefficient_traits::const_reference denominator) {
02717
02718 if (denominator == 0)
02719 throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0");
02720
02721
02722
02723 const dimension_type var_space_dim = var.space_dimension();
02724 if (space_dim < var_space_dim)
02725 throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02726 "v", var);
02727
02728
02729 const dimension_type lb_space_dim = lb_expr.space_dimension();
02730 if (space_dim < lb_space_dim)
02731 throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
02732 "lb", lb_expr);
02733 const dimension_type ub_space_dim = ub_expr.space_dimension();
02734 if (space_dim < ub_space_dim)
02735 throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
02736 "ub", ub_expr);
02737
02738
02739 if (marked_empty())
02740 return;
02741
02742
02743 if (lb_expr.coefficient(var) == 0) {
02744
02745 generalized_affine_image(var,
02746 LESS_OR_EQUAL,
02747 ub_expr,
02748 denominator);
02749 if (denominator > 0)
02750 refine_no_check(lb_expr <= denominator*var);
02751 else
02752 refine_no_check(denominator*var <= lb_expr);
02753 }
02754 else if (ub_expr.coefficient(var) == 0) {
02755
02756 generalized_affine_image(var,
02757 GREATER_OR_EQUAL,
02758 lb_expr,
02759 denominator);
02760 if (denominator > 0)
02761 refine_no_check(denominator*var <= ub_expr);
02762 else
02763 refine_no_check(ub_expr <= denominator*var);
02764 }
02765 else {
02766
02767
02768 const Variable new_var = Variable(space_dim);
02769 add_space_dimensions_and_embed(1);
02770
02771 refine_no_check(denominator*new_var == ub_expr);
02772
02773 generalized_affine_image(var,
02774 GREATER_OR_EQUAL,
02775 lb_expr,
02776 denominator);
02777 if (!marked_empty())
02778
02779 refine_no_check(new_var >= var);
02780
02781 remove_higher_space_dimensions(space_dim-1);
02782 }
02783 PPL_ASSERT_HEAVY(OK());
02784 }
02785
02786 void
02787 PPL::Polyhedron::
02788 bounded_affine_preimage(const Variable var,
02789 const Linear_Expression& lb_expr,
02790 const Linear_Expression& ub_expr,
02791 Coefficient_traits::const_reference denominator) {
02792
02793 if (denominator == 0)
02794 throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
02795
02796
02797
02798 const dimension_type var_space_dim = var.space_dimension();
02799 if (space_dim < var_space_dim)
02800 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
02801 "v", var);
02802
02803
02804 const dimension_type lb_space_dim = lb_expr.space_dimension();
02805 if (space_dim < lb_space_dim)
02806 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
02807 "lb", lb_expr);
02808 const dimension_type ub_space_dim = ub_expr.space_dimension();
02809 if (space_dim < ub_space_dim)
02810 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
02811 "ub", ub_expr);
02812
02813
02814 if (marked_empty())
02815 return;
02816
02817
02818 if (lb_expr.coefficient(var) == 0 && ub_expr.coefficient(var) == 0) {
02819 if (denominator > 0) {
02820 refine_no_check(lb_expr <= denominator*var);
02821 refine_no_check(denominator*var <= ub_expr);
02822 }
02823 else {
02824 refine_no_check(ub_expr <= denominator*var);
02825 refine_no_check(denominator*var <= lb_expr);
02826 }
02827 unconstrain(var);
02828 }
02829 else {
02830
02831
02832 const Variable new_var = Variable(space_dim);
02833 add_space_dimensions_and_embed(1);
02834
02835 std::vector<dimension_type> swapping_cycle;
02836 swapping_cycle.push_back(var_space_dim);
02837 swapping_cycle.push_back(space_dim);
02838 swapping_cycle.push_back(0);
02839 if (constraints_are_up_to_date())
02840 con_sys.permute_columns(swapping_cycle);
02841 if (generators_are_up_to_date())
02842 gen_sys.permute_columns(swapping_cycle);
02843
02844
02845 if (denominator > 0) {
02846 refine_no_check(lb_expr <= denominator*new_var);
02847 refine_no_check(denominator*new_var <= ub_expr);
02848 }
02849 else {
02850 refine_no_check(ub_expr <= denominator*new_var);
02851 refine_no_check(denominator*new_var <= lb_expr);
02852 }
02853
02854 remove_higher_space_dimensions(space_dim-1);
02855 }
02856 PPL_ASSERT_HEAVY(OK());
02857 }
02858
02859 void
02860 PPL::Polyhedron::
02861 generalized_affine_image(const Variable var,
02862 const Relation_Symbol relsym,
02863 const Linear_Expression& expr,
02864 Coefficient_traits::const_reference denominator) {
02865
02866 if (denominator == 0)
02867 throw_invalid_argument("generalized_affine_image(v, r, e, d)", "d == 0");
02868
02869
02870
02871
02872 if (space_dim < expr.space_dimension())
02873 throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
02874 "e", expr);
02875
02876 const dimension_type var_space_dim = var.space_dimension();
02877 if (space_dim < var_space_dim)
02878 throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
02879 "v", var);
02880
02881
02882 if (is_necessarily_closed()
02883 && (relsym == LESS_THAN || relsym == GREATER_THAN))
02884 throw_invalid_argument("generalized_affine_image(v, r, e, d)",
02885 "r is a strict relation symbol");
02886
02887 if (relsym == NOT_EQUAL)
02888 throw_invalid_argument("generalized_affine_image(v, r, e, d)",
02889 "r is the disequality relation symbol");
02890
02891
02892 affine_image(var, expr, denominator);
02893
02894 if (relsym == EQUAL)
02895
02896 return;
02897
02898
02899
02900 if (is_empty())
02901 return;
02902
02903 switch (relsym) {
02904 case LESS_OR_EQUAL:
02905 add_generator(ray(-var));
02906 break;
02907 case GREATER_OR_EQUAL:
02908 add_generator(ray(var));
02909 break;
02910 case LESS_THAN:
02911
02912 case GREATER_THAN:
02913 {
02914
02915 PPL_ASSERT(!is_necessarily_closed());
02916
02917
02918 add_generator(ray(relsym == GREATER_THAN ? var : -var));
02919 minimize();
02920
02921
02922
02923
02924
02925 const dimension_type eps_index = space_dim + 1;
02926 for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
02927 if (gen_sys[i].is_point()) {
02928
02929 gen_sys.add_row(gen_sys[i]);
02930 if (relsym == GREATER_THAN)
02931 ++gen_sys[gen_sys.num_rows()-1][var_space_dim];
02932 else
02933 --gen_sys[gen_sys.num_rows()-1][var_space_dim];
02934
02935 gen_sys[i][eps_index] = 0;
02936 }
02937 clear_constraints_up_to_date();
02938 clear_generators_minimized();
02939 gen_sys.set_sorted(false);
02940 clear_sat_c_up_to_date();
02941 clear_sat_g_up_to_date();
02942 }
02943 break;
02944 default:
02945
02946 throw std::runtime_error("PPL internal error");
02947 }
02948 PPL_ASSERT_HEAVY(OK());
02949 }
02950
02951 void
02952 PPL::Polyhedron::
02953 generalized_affine_preimage(const Variable var,
02954 const Relation_Symbol relsym,
02955 const Linear_Expression& expr,
02956 Coefficient_traits::const_reference denominator) {
02957
02958 if (denominator == 0)
02959 throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
02960 "d == 0");
02961
02962
02963
02964
02965 if (space_dim < expr.space_dimension())
02966 throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
02967 "e", expr);
02968
02969 const dimension_type var_space_dim = var.space_dimension();
02970 if (space_dim < var_space_dim)
02971 throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
02972 "v", var);
02973
02974
02975 if (is_necessarily_closed()
02976 && (relsym == LESS_THAN || relsym == GREATER_THAN))
02977 throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
02978 "r is a strict relation symbol");
02979
02980 if (relsym == NOT_EQUAL)
02981 throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
02982 "r is the disequality relation symbol");
02983
02984
02985 if (relsym == EQUAL) {
02986 affine_preimage(var, expr, denominator);
02987 return;
02988 }
02989
02990
02991 Relation_Symbol reversed_relsym;
02992 switch (relsym) {
02993 case LESS_THAN:
02994 reversed_relsym = GREATER_THAN;
02995 break;
02996 case LESS_OR_EQUAL:
02997 reversed_relsym = GREATER_OR_EQUAL;
02998 break;
02999 case GREATER_OR_EQUAL:
03000 reversed_relsym = LESS_OR_EQUAL;
03001 break;
03002 case GREATER_THAN:
03003 reversed_relsym = LESS_THAN;
03004 break;
03005 default:
03006
03007 throw std::runtime_error("PPL internal error");
03008 }
03009
03010
03011
03012 const Coefficient& var_coefficient = expr.coefficient(var);
03013 if (var_coefficient != 0) {
03014 Linear_Expression inverse_expr
03015 = expr - (denominator + var_coefficient) * var;
03016 PPL_DIRTY_TEMP_COEFFICIENT(inverse_denominator);
03017 neg_assign(inverse_denominator, var_coefficient);
03018 Relation_Symbol inverse_relsym
03019 = (sgn(denominator) == sgn(inverse_denominator))
03020 ? relsym : reversed_relsym;
03021 generalized_affine_image(var, inverse_relsym, inverse_expr,
03022 inverse_denominator);
03023 return;
03024 }
03025
03026
03027
03028
03029
03030 const Relation_Symbol corrected_relsym
03031 = (denominator > 0) ? relsym : reversed_relsym;
03032 switch (corrected_relsym) {
03033 case LESS_THAN:
03034 refine_no_check(denominator*var < expr);
03035 break;
03036 case LESS_OR_EQUAL:
03037 refine_no_check(denominator*var <= expr);
03038 break;
03039 case GREATER_OR_EQUAL:
03040 refine_no_check(denominator*var >= expr);
03041 break;
03042 case GREATER_THAN:
03043 refine_no_check(denominator*var > expr);
03044 break;
03045 default:
03046
03047 throw std::runtime_error("PPL internal error");
03048 }
03049 unconstrain(var);
03050 PPL_ASSERT_HEAVY(OK());
03051 }
03052
03053 void
03054 PPL::Polyhedron::generalized_affine_image(const Linear_Expression& lhs,
03055 const Relation_Symbol relsym,
03056 const Linear_Expression& rhs) {
03057
03058
03059
03060 dimension_type lhs_space_dim = lhs.space_dimension();
03061 if (space_dim < lhs_space_dim)
03062 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
03063 "e1", lhs);
03064
03065
03066 const dimension_type rhs_space_dim = rhs.space_dimension();
03067 if (space_dim < rhs_space_dim)
03068 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
03069 "e2", rhs);
03070
03071
03072 if (is_necessarily_closed()
03073 && (relsym == LESS_THAN || relsym == GREATER_THAN))
03074 throw_invalid_argument("generalized_affine_image(e1, r, e2)",
03075 "r is a strict relation symbol");
03076
03077 if (relsym == NOT_EQUAL)
03078 throw_invalid_argument("generalized_affine_image(e1, r, e2)",
03079 "r is the disequality relation symbol");
03080
03081
03082 if (marked_empty())
03083 return;
03084
03085
03086
03087 for ( ; lhs_space_dim > 0; lhs_space_dim--)
03088 if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0)
03089 break;
03090
03091
03092 if (lhs_space_dim == 0) {
03093 switch (relsym) {
03094 case LESS_THAN:
03095 refine_no_check(lhs < rhs);
03096 break;
03097 case LESS_OR_EQUAL:
03098 refine_no_check(lhs <= rhs);
03099 break;
03100 case EQUAL:
03101 refine_no_check(lhs == rhs);
03102 break;
03103 case GREATER_OR_EQUAL:
03104 refine_no_check(lhs >= rhs);
03105 break;
03106 case GREATER_THAN:
03107 refine_no_check(lhs > rhs);
03108 break;
03109 case NOT_EQUAL:
03110
03111 throw std::runtime_error("PPL internal error");
03112 }
03113 return;
03114 }
03115
03116
03117
03118
03119
03120 Generator_System new_lines;
03121 bool lhs_vars_intersects_rhs_vars = false;
03122 for (dimension_type i = lhs_space_dim; i-- > 0; )
03123 if (lhs.coefficient(Variable(i)) != 0) {
03124 new_lines.insert(line(Variable(i)));
03125 if (rhs.coefficient(Variable(i)) != 0)
03126 lhs_vars_intersects_rhs_vars = true;
03127 }
03128
03129 if (lhs_vars_intersects_rhs_vars) {
03130
03131
03132 const Variable new_var = Variable(space_dim);
03133 add_space_dimensions_and_embed(1);
03134
03135
03136
03137 refine_no_check(new_var == rhs);
03138 if (!is_empty()) {
03139
03140 add_recycled_generators(new_lines);
03141
03142
03143
03144
03145 switch (relsym) {
03146 case LESS_THAN:
03147 refine_no_check(lhs < new_var);
03148 break;
03149 case LESS_OR_EQUAL:
03150 refine_no_check(lhs <= new_var);
03151 break;
03152 case EQUAL:
03153 refine_no_check(lhs == new_var);
03154 break;
03155 case GREATER_OR_EQUAL:
03156 refine_no_check(lhs >= new_var);
03157 break;
03158 case GREATER_THAN:
03159 refine_no_check(lhs > new_var);
03160 break;
03161 case NOT_EQUAL:
03162
03163 throw std::runtime_error("PPL internal error");
03164 }
03165 }
03166
03167 remove_higher_space_dimensions(space_dim-1);
03168 }
03169 else {
03170
03171
03172
03173
03174
03175 if (is_empty())
03176 return;
03177
03178
03179 add_recycled_generators(new_lines);
03180
03181
03182
03183 switch (relsym) {
03184 case LESS_THAN:
03185 refine_no_check(lhs < rhs);
03186 break;
03187 case LESS_OR_EQUAL:
03188 refine_no_check(lhs <= rhs);
03189 break;
03190 case EQUAL:
03191 refine_no_check(lhs == rhs);
03192 break;
03193 case GREATER_OR_EQUAL:
03194 refine_no_check(lhs >= rhs);
03195 break;
03196 case GREATER_THAN:
03197 refine_no_check(lhs > rhs);
03198 break;
03199 case NOT_EQUAL:
03200
03201 throw std::runtime_error("PPL internal error");
03202 }
03203 }
03204 PPL_ASSERT_HEAVY(OK());
03205 }
03206
03207 void
03208 PPL::Polyhedron::generalized_affine_preimage(const Linear_Expression& lhs,
03209 const Relation_Symbol relsym,
03210 const Linear_Expression& rhs) {
03211
03212
03213
03214 dimension_type lhs_space_dim = lhs.space_dimension();
03215 if (space_dim < lhs_space_dim)
03216 throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
03217 "e1", lhs);
03218
03219
03220 const dimension_type rhs_space_dim = rhs.space_dimension();
03221 if (space_dim < rhs_space_dim)
03222 throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
03223 "e2", rhs);
03224
03225
03226 if (is_necessarily_closed()
03227 && (relsym == LESS_THAN || relsym == GREATER_THAN))
03228 throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
03229 "r is a strict relation symbol");
03230
03231 if (relsym == NOT_EQUAL)
03232 throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
03233 "r is the disequality relation symbol");
03234
03235
03236 if (marked_empty())
03237 return;
03238
03239
03240
03241 for ( ; lhs_space_dim > 0; lhs_space_dim--)
03242 if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0)
03243 break;
03244
03245
03246
03247 if (lhs_space_dim == 0) {
03248 generalized_affine_image(lhs, relsym, rhs);
03249 return;
03250 }
03251
03252
03253
03254
03255
03256 Generator_System new_lines;
03257 bool lhs_vars_intersects_rhs_vars = false;
03258 for (dimension_type i = lhs_space_dim; i-- > 0; )
03259 if (lhs.coefficient(Variable(i)) != 0) {
03260 new_lines.insert(line(Variable(i)));
03261 if (rhs.coefficient(Variable(i)) != 0)
03262 lhs_vars_intersects_rhs_vars = true;
03263 }
03264
03265 if (lhs_vars_intersects_rhs_vars) {
03266
03267
03268 const Variable new_var = Variable(space_dim);
03269 add_space_dimensions_and_embed(1);
03270
03271
03272
03273 refine_no_check(new_var == lhs);
03274 if (!is_empty()) {
03275
03276 add_recycled_generators(new_lines);
03277
03278
03279
03280 switch (relsym) {
03281 case LESS_THAN:
03282 refine_no_check(new_var < rhs);
03283 break;
03284 case LESS_OR_EQUAL:
03285 refine_no_check(new_var <= rhs);
03286 break;
03287 case EQUAL:
03288 refine_no_check(new_var == rhs);
03289 break;
03290 case GREATER_OR_EQUAL:
03291 refine_no_check(new_var >= rhs);
03292 break;
03293 case GREATER_THAN:
03294 refine_no_check(new_var > rhs);
03295 break;
03296 case NOT_EQUAL:
03297
03298 throw std::runtime_error("PPL internal error");
03299 }
03300 }
03301
03302 remove_higher_space_dimensions(space_dim-1);
03303 }
03304 else {
03305
03306
03307
03308
03309
03310 switch (relsym) {
03311 case LESS_THAN:
03312 refine_no_check(lhs < rhs);
03313 break;
03314 case LESS_OR_EQUAL:
03315 refine_no_check(lhs <= rhs);
03316 break;
03317 case EQUAL:
03318 refine_no_check(lhs == rhs);
03319 break;
03320 case GREATER_OR_EQUAL:
03321 refine_no_check(lhs >= rhs);
03322 break;
03323 case GREATER_THAN:
03324 refine_no_check(lhs > rhs);
03325 break;
03326 case NOT_EQUAL:
03327
03328 throw std::runtime_error("PPL internal error");
03329 }
03330
03331
03332 if (is_empty())
03333 return;
03334
03335 add_recycled_generators(new_lines);
03336 }
03337 PPL_ASSERT_HEAVY(OK());
03338 }
03339
03340 void
03341 PPL::Polyhedron::time_elapse_assign(const Polyhedron& y) {
03342 Polyhedron& x = *this;
03343
03344 if (x.topology() != y.topology())
03345 throw_topology_incompatible("time_elapse_assign(y)", "y", y);
03346
03347 if (x.space_dim != y.space_dim)
03348 throw_dimension_incompatible("time_elapse_assign(y)", "y", y);
03349
03350
03351 if (x.space_dim == 0) {
03352 if (y.marked_empty())
03353 x.set_empty();
03354 return;
03355 }
03356
03357
03358 if (x.marked_empty() || y.marked_empty()
03359 || (x.has_pending_constraints() && !x.process_pending_constraints())
03360 || (!x.generators_are_up_to_date() && !x.update_generators())
03361 || (y.has_pending_constraints() && !y.process_pending_constraints())
03362 || (!y.generators_are_up_to_date() && !y.update_generators())) {
03363 x.set_empty();
03364 return;
03365 }
03366
03367
03368
03369 Generator_System gs = y.gen_sys;
03370 dimension_type gs_num_rows = gs.num_rows();
03371
03372 if (!x.is_necessarily_closed())
03373
03374 for (dimension_type i = gs_num_rows; i-- > 0; )
03375 switch (gs[i].type()) {
03376 case Generator::POINT:
03377
03378
03379 --gs_num_rows;
03380 std::swap(gs[i], gs[gs_num_rows]);
03381 break;
03382 case Generator::CLOSURE_POINT:
03383 {
03384 Generator& cp = gs[i];
03385
03386 if (cp.all_homogeneous_terms_are_zero()) {
03387 --gs_num_rows;
03388 std::swap(cp, gs[gs_num_rows]);
03389 }
03390
03391 else {
03392 cp[0] = 0;
03393
03394 cp.normalize();
03395 }
03396 }
03397 break;
03398 default:
03399
03400 break;
03401 }
03402 else
03403
03404 for (dimension_type i = gs_num_rows; i-- > 0; )
03405 switch (gs[i].type()) {
03406 case Generator::POINT:
03407 {
03408 Generator& p = gs[i];
03409
03410 if (p.all_homogeneous_terms_are_zero()) {
03411 --gs_num_rows;
03412 std::swap(p, gs[gs_num_rows]);
03413 }
03414
03415 else {
03416 p[0] = 0;
03417
03418 p.normalize();
03419 }
03420 }
03421 break;
03422 default:
03423
03424 break;
03425 }
03426
03427
03428
03429
03430
03431 gs.erase_to_end(gs_num_rows);
03432 gs.unset_pending_rows();
03433
03434
03435
03436
03437
03438 if (gs_num_rows == 0)
03439 return;
03440
03441
03442
03443 if (x.can_have_something_pending()) {
03444 x.gen_sys.add_pending_rows(gs);
03445 x.set_generators_pending();
03446 }
03447
03448
03449 else {
03450 if (!x.gen_sys.is_sorted())
03451 x.gen_sys.sort_rows();
03452 gs.sort_rows();
03453 x.gen_sys.merge_rows_assign(gs);
03454
03455 x.clear_constraints_up_to_date();
03456 x.clear_generators_minimized();
03457 }
03458 PPL_ASSERT_HEAVY(x.OK(true) && y.OK(true));
03459 }
03460
03461 bool
03462 PPL::Polyhedron::frequency(const Linear_Expression& expr,
03463 Coefficient& freq_n, Coefficient& freq_d,
03464 Coefficient& val_n, Coefficient& val_d) const {
03465
03466 if (space_dim < expr.space_dimension())
03467 throw_dimension_incompatible("frequency(e, ...)", "e", expr);
03468
03469
03470
03471
03472
03473
03474
03475 if (space_dim == 0) {
03476 if (is_empty())
03477 return false;
03478 freq_n = 0;
03479 freq_d = 1;
03480 val_n = expr.inhomogeneous_term();
03481 val_d = 1;
03482 return true;
03483 }
03484
03485
03486 if (marked_empty()
03487 || (has_pending_constraints() && !process_pending_constraints())
03488 || (!generators_are_up_to_date() && !update_generators()))
03489 return false;
03490
03491
03492
03493
03494 PPL_DIRTY_TEMP0(mpq_class, value);
03495
03496
03497 bool first_candidate = true;
03498
03499 PPL_DIRTY_TEMP_COEFFICIENT(sp);
03500 PPL_DIRTY_TEMP0(mpq_class, candidate);
03501 for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
03502 const Generator& gen_sys_i = gen_sys[i];
03503 Scalar_Products::homogeneous_assign(sp, expr, gen_sys_i);
03504
03505 if (gen_sys_i.is_line_or_ray()) {
03506 const int sp_sign = sgn(sp);
03507 if (sp_sign != 0)
03508
03509 return false;
03510 }
03511 else {
03512
03513 PPL_ASSERT(gen_sys_i.is_point() || gen_sys_i.is_closure_point());
03514
03515
03516 assign_r(candidate.get_num(), sp, ROUND_NOT_NEEDED);
03517 assign_r(candidate.get_den(), gen_sys_i[0], ROUND_NOT_NEEDED);
03518 candidate.canonicalize();
03519 if (first_candidate) {
03520
03521 first_candidate = false;
03522 value = candidate;
03523 }
03524 else if (candidate != value)
03525 return false;
03526 }
03527 }
03528
03529
03530 PPL_DIRTY_TEMP0(mpz_class, n);
03531 assign_r(n, expr.inhomogeneous_term(), ROUND_NOT_NEEDED);
03532 value += n;
03533
03534
03535
03536
03537
03538
03539
03540 val_n = Coefficient(value.get_num());
03541 val_d = Coefficient(value.get_den());
03542
03543 freq_n = 0;
03544 freq_d = 1;
03545 return true;
03546 }
03547
03548 void
03549 PPL::Polyhedron::topological_closure_assign() {
03550
03551 if (is_necessarily_closed())
03552 return;
03553
03554 if (marked_empty() || space_dim == 0)
03555 return;
03556
03557
03558
03559
03560
03561
03562
03563 if (has_pending_constraints() && !process_pending_constraints())
03564 return;
03565
03566
03567
03568 if (!has_pending_generators() && constraints_are_up_to_date()) {
03569 const dimension_type eps_index = space_dim + 1;
03570 bool changed = false;
03571
03572 for (dimension_type i = con_sys.num_rows(); i-- > 0; ) {
03573 Constraint& c = con_sys[i];
03574 if (c[eps_index] < 0 && !c.is_tautological()) {
03575 c[eps_index] = 0;
03576
03577 c.normalize();
03578 changed = true;
03579 }
03580 }
03581 if (changed) {
03582 con_sys.insert(Constraint::epsilon_leq_one());
03583 con_sys.set_sorted(false);
03584
03585
03586
03587 clear_generators_up_to_date();
03588 clear_constraints_minimized();
03589 }
03590 }
03591 else {
03592
03593 PPL_ASSERT(generators_are_up_to_date());
03594
03595 gen_sys.add_corresponding_points();
03596 if (can_have_something_pending())
03597 set_generators_pending();
03598 else {
03599
03600
03601 gen_sys.unset_pending_rows();
03602 gen_sys.set_sorted(false);
03603
03604 clear_constraints_up_to_date();
03605 clear_generators_minimized();
03606 }
03607 }
03608 PPL_ASSERT_HEAVY(OK());
03609 }
03610
03612 bool
03613 PPL::operator==(const Polyhedron& x, const Polyhedron& y) {
03614
03615
03616 if (x.topology() != y.topology() || x.space_dim != y.space_dim)
03617 return false;
03618
03619 if (x.marked_empty())
03620 return y.is_empty();
03621 else if (y.marked_empty())
03622 return x.is_empty();
03623 else if (x.space_dim == 0)
03624 return true;
03625
03626 switch (x.quick_equivalence_test(y)) {
03627 case Polyhedron::TVB_TRUE:
03628 return true;
03629
03630 case Polyhedron::TVB_FALSE:
03631 return false;
03632
03633 default:
03634 if (x.is_included_in(y))
03635 if (x.marked_empty())
03636 return y.is_empty();
03637 else
03638 return y.is_included_in(x);
03639 else
03640 return false;
03641 }
03642 }
03643
03644 bool
03645 PPL::Polyhedron::contains(const Polyhedron& y) const {
03646 const Polyhedron& x = *this;
03647
03648
03649 if (x.topology() != y.topology())
03650 throw_topology_incompatible("contains(y)", "y", y);
03651
03652
03653 if (x.space_dim != y.space_dim)
03654 throw_dimension_incompatible("contains(y)", "y", y);
03655
03656 if (y.marked_empty())
03657 return true;
03658 else if (x.marked_empty())
03659 return y.is_empty();
03660 else if (y.space_dim == 0)
03661 return true;
03662 else if (x.quick_equivalence_test(y) == Polyhedron::TVB_TRUE)
03663 return true;
03664 else
03665 return y.is_included_in(x);
03666 }
03667
03668 bool
03669 PPL::Polyhedron::is_disjoint_from(const Polyhedron& y) const {
03670 Polyhedron z = *this;
03671 z.intersection_assign(y);
03672 return z.is_empty();
03673 }
03674
03675 void
03676 PPL::Polyhedron::ascii_dump(std::ostream& s) const {
03677 s << "space_dim " << space_dim << "\n";
03678 status.ascii_dump(s);
03679 s << "\ncon_sys ("
03680 << (constraints_are_up_to_date() ? "" : "not_")
03681 << "up-to-date)"
03682 << "\n";
03683 con_sys.ascii_dump(s);
03684 s << "\ngen_sys ("
03685 << (generators_are_up_to_date() ? "" : "not_")
03686 << "up-to-date)"
03687 << "\n";
03688 gen_sys.ascii_dump(s);
03689 s << "\nsat_c\n";
03690 sat_c.ascii_dump(s);
03691 s << "\nsat_g\n";
03692 sat_g.ascii_dump(s);
03693 s << "\n";
03694 }
03695
03696 PPL_OUTPUT_DEFINITIONS(Polyhedron)
03697
03698 bool
03699 PPL::Polyhedron::ascii_load(std::istream& s) {
03700 std::string str;
03701
03702 if (!(s >> str) || str != "space_dim")
03703 return false;
03704
03705 if (!(s >> space_dim))
03706 return false;
03707
03708 if (!status.ascii_load(s))
03709 return false;
03710
03711 if (!(s >> str) || str != "con_sys")
03712 return false;
03713
03714 if (!(s >> str) || (str != "(not_up-to-date)" && str != "(up-to-date)"))
03715 return false;
03716
03717 if (!con_sys.ascii_load(s))
03718 return false;
03719
03720 if (!(s >> str) || str != "gen_sys")
03721 return false;
03722
03723 if (!(s >> str) || (str != "(not_up-to-date)" && str != "(up-to-date)"))
03724 return false;
03725
03726 if (!gen_sys.ascii_load(s))
03727 return false;
03728
03729 if (!(s >> str) || str != "sat_c")
03730 return false;
03731
03732 if (!sat_c.ascii_load(s))
03733 return false;
03734
03735 if (!(s >> str) || str != "sat_g")
03736 return false;
03737
03738 if (!sat_g.ascii_load(s))
03739 return false;
03740
03741
03742 PPL_ASSERT_HEAVY(OK());
03743 return true;
03744 }
03745
03746 PPL::memory_size_type
03747 PPL::Polyhedron::external_memory_in_bytes() const {
03748 return
03749 con_sys.external_memory_in_bytes()
03750 + gen_sys.external_memory_in_bytes()
03751 + sat_c.external_memory_in_bytes()
03752 + sat_g.external_memory_in_bytes();
03753 }
03754
03755 void
03756 PPL::Polyhedron::wrap_assign(const Variables_Set& vars,
03757 Bounded_Integer_Type_Width w,
03758 Bounded_Integer_Type_Representation r,
03759 Bounded_Integer_Type_Overflow o,
03760 const Constraint_System* pcs,
03761 unsigned complexity_threshold,
03762 bool wrap_individually) {
03763 if (is_necessarily_closed())
03764 Implementation::wrap_assign(static_cast<C_Polyhedron&>(*this),
03765 vars, w, r, o, pcs,
03766 complexity_threshold, wrap_individually,
03767 "C_Polyhedron");
03768 else
03769 Implementation::wrap_assign(static_cast<NNC_Polyhedron&>(*this),
03770 vars, w, r, o, pcs,
03771 complexity_threshold, wrap_individually,
03772 "NNC_Polyhedron");
03773 }
03774
03776 std::ostream&
03777 PPL::IO_Operators::operator<<(std::ostream& s, const Polyhedron& ph) {
03778 if (ph.is_empty())
03779 s << "false";
03780 else
03781 s << ph.minimized_constraints();
03782 return s;
03783 }