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
00026 #include "Grid.defs.hh"
00027 #include "Topology.hh"
00028 #include "Scalar_Products.defs.hh"
00029 #include "Polyhedron.defs.hh"
00030 #include "assert.hh"
00031 #include <iostream>
00032
00033 namespace PPL = Parma_Polyhedra_Library;
00034
00035
00036
00037
00038 PPL::Grid::Grid(const Grid& y, Complexity_Class)
00039 : con_sys(),
00040 gen_sys(),
00041 status(y.status),
00042 space_dim(y.space_dim),
00043 dim_kinds(y.dim_kinds) {
00044 if (space_dim == 0) {
00045 con_sys = y.con_sys;
00046 gen_sys = y.gen_sys;
00047 }
00048 else {
00049 if (y.congruences_are_up_to_date())
00050 con_sys = y.con_sys;
00051 else
00052 con_sys.increase_space_dimension(space_dim);
00053 if (y.generators_are_up_to_date())
00054 gen_sys = y.gen_sys;
00055 else
00056 gen_sys = Grid_Generator_System(y.space_dim);
00057 }
00058 }
00059
00060 PPL::Grid::Grid(const Constraint_System& cs)
00061 : con_sys(cs.space_dimension() > max_space_dimension()
00062 ? throw_space_dimension_overflow("Grid(cs)",
00063 "the space dimension of cs "
00064 "exceeds the maximum allowed "
00065 "space dimension"), 0
00066 : cs.space_dimension()),
00067 gen_sys(cs.space_dimension()) {
00068 space_dim = cs.space_dimension();
00069
00070 if (space_dim == 0) {
00071
00072 for (Constraint_System::const_iterator i = cs.begin(),
00073 cs_end = cs.end(); i != cs_end; ++i)
00074 if (i->is_inconsistent()) {
00075
00076 status.set_empty();
00077
00078
00079 con_sys.insert(Congruence::zero_dim_false());
00080 PPL_ASSERT(OK());
00081 return;
00082 }
00083 set_zero_dim_univ();
00084 PPL_ASSERT(OK());
00085 return;
00086 }
00087
00088 Congruence_System cgs;
00089 cgs.insert(0*Variable(space_dim - 1) %= 1);
00090 for (Constraint_System::const_iterator i = cs.begin(),
00091 cs_end = cs.end(); i != cs_end; ++i)
00092 if (i->is_equality())
00093 cgs.insert(*i);
00094 else
00095 throw_invalid_constraints("Grid(cs)", "cs");
00096 construct(cgs);
00097 }
00098
00099 PPL::Grid::Grid(Constraint_System& cs, Recycle_Input)
00100 : con_sys(cs.space_dimension() > max_space_dimension()
00101 ? throw_space_dimension_overflow("Grid(cs, recycle)",
00102 "the space dimension of cs "
00103 "exceeds the maximum allowed "
00104 "space dimension"), 0
00105 : cs.space_dimension()),
00106 gen_sys(cs.space_dimension()) {
00107 space_dim = cs.space_dimension();
00108
00109 if (space_dim == 0) {
00110
00111 for (Constraint_System::const_iterator i = cs.begin(),
00112 cs_end = cs.end(); i != cs_end; ++i)
00113 if (i->is_inconsistent()) {
00114
00115 status.set_empty();
00116
00117
00118 con_sys.insert(Congruence::zero_dim_false());
00119 PPL_ASSERT(OK());
00120 return;
00121 }
00122 set_zero_dim_univ();
00123 PPL_ASSERT(OK());
00124 return;
00125 }
00126
00127 Congruence_System cgs;
00128 cgs.insert(0*Variable(space_dim - 1) %= 1);
00129 for (Constraint_System::const_iterator i = cs.begin(),
00130 cs_end = cs.end(); i != cs_end; ++i)
00131 if (i->is_equality())
00132 cgs.insert(*i);
00133 else
00134 throw_invalid_constraint("Grid(cs)", "cs");
00135 construct(cgs);
00136 }
00137
00138 PPL::Grid::Grid(const Polyhedron& ph,
00139 Complexity_Class complexity)
00140 : con_sys(ph.space_dimension() > max_space_dimension()
00141 ? throw_space_dimension_overflow("Grid(ph)",
00142 "the space dimension of ph "
00143 "exceeds the maximum allowed "
00144 "space dimension"), 0
00145 : ph.space_dimension()),
00146 gen_sys(ph.space_dimension()) {
00147 space_dim = ph.space_dimension();
00148
00149
00150 if (space_dim == 0) {
00151 if (ph.is_empty())
00152 set_empty();
00153 else
00154 set_zero_dim_univ();
00155 return;
00156 }
00157
00158
00159 if (ph.marked_empty()) {
00160 set_empty();
00161 return;
00162 }
00163
00164 bool use_constraints = ph.constraints_are_minimized()
00165 || !ph.generators_are_up_to_date();
00166
00167
00168
00169 if (use_constraints && complexity == ANY_COMPLEXITY)
00170 if (!ph.minimize()) {
00171 set_empty();
00172 return;
00173 }
00174
00175 if (use_constraints) {
00176
00177 PPL_ASSERT(ph.constraints_are_up_to_date());
00178 const Constraint_System& cs = ph.constraints();
00179 Congruence_System cgs;
00180 cgs.insert(0*Variable(space_dim - 1) %= 1);
00181 for (Constraint_System::const_iterator i = cs.begin(),
00182 cs_end = cs.end(); i != cs_end; ++i)
00183 if (i->is_equality())
00184 cgs.insert(*i);
00185 construct(cgs);
00186 }
00187 else {
00188
00189
00190 PPL_ASSERT(ph.generators_are_up_to_date());
00191 const Generator_System& gs = ph.generators();
00192 Grid_Generator_System ggs(space_dim);
00193 Linear_Expression point_expr;
00194 PPL_DIRTY_TEMP_COEFFICIENT(point_divisor);
00195 for (Generator_System::const_iterator g = gs.begin(),
00196 gs_end = gs.end(); g != gs_end; ++g) {
00197 if (g->is_point() || g->is_closure_point()) {
00198 for (dimension_type i = space_dim; i-- > 0; ) {
00199 const Variable v(i);
00200 point_expr += g->coefficient(v) * v;
00201 point_divisor = g->divisor();
00202 }
00203 ggs.insert(grid_point(point_expr, point_divisor));
00204 break;
00205 }
00206 }
00207
00208
00209
00210
00211 PPL_DIRTY_TEMP_COEFFICIENT(coeff);
00212 PPL_DIRTY_TEMP_COEFFICIENT(g_divisor);
00213 for (Generator_System::const_iterator g = gs.begin(),
00214 gs_end = gs.end(); g != gs_end; ++g) {
00215 Linear_Expression e;
00216 if (g->is_point() || g->is_closure_point()) {
00217 g_divisor = g->divisor();
00218 for (dimension_type i = space_dim; i-- > 0; ) {
00219 const Variable v(i);
00220 coeff = point_expr.coefficient(v) * g_divisor;
00221 coeff -= g->coefficient(v) * point_divisor;
00222 e += coeff * v;
00223 }
00224 if (e.all_homogeneous_terms_are_zero())
00225 continue;
00226 }
00227 else
00228 for (dimension_type i = space_dim; i-- > 0; ) {
00229 const Variable v(i);
00230 e += g->coefficient(v) * v;
00231 }
00232 ggs.insert(grid_line(e));
00233 }
00234 construct(ggs);
00235 }
00236 PPL_ASSERT(OK());
00237 }
00238
00239 PPL::Grid&
00240 PPL::Grid::operator=(const Grid& y) {
00241 space_dim = y.space_dim;
00242 dim_kinds = y.dim_kinds;
00243 if (y.marked_empty())
00244 set_empty();
00245 else if (space_dim == 0)
00246 set_zero_dim_univ();
00247 else {
00248 status = y.status;
00249 if (y.congruences_are_up_to_date())
00250 con_sys = y.con_sys;
00251 if (y.generators_are_up_to_date())
00252 gen_sys = y.gen_sys;
00253 }
00254 return *this;
00255 }
00256
00257 PPL::dimension_type
00258 PPL::Grid::affine_dimension() const {
00259 if (space_dim == 0 || is_empty())
00260 return 0;
00261
00262 if (generators_are_up_to_date()) {
00263 if (generators_are_minimized())
00264 return gen_sys.num_rows() - 1;
00265 if (!(congruences_are_up_to_date() && congruences_are_minimized()))
00266 return minimized_grid_generators().num_rows() - 1;
00267 }
00268 else
00269 minimized_congruences();
00270 PPL_ASSERT(congruences_are_minimized());
00271 dimension_type d = space_dim;
00272 for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00273 if (con_sys[i].is_equality())
00274 --d;
00275 return d;
00276 }
00277
00278 const PPL::Congruence_System&
00279 PPL::Grid::congruences() const {
00280 if (marked_empty())
00281 return con_sys;
00282
00283 if (space_dim == 0) {
00284
00285 PPL_ASSERT(con_sys.num_rows() == 0 && con_sys.num_columns() == 2);
00286 return con_sys;
00287 }
00288
00289 if (!congruences_are_up_to_date())
00290 update_congruences();
00291
00292 return con_sys;
00293 }
00294
00295 const PPL::Congruence_System&
00296 PPL::Grid::minimized_congruences() const {
00297 if (congruences_are_up_to_date() && !congruences_are_minimized()) {
00298
00299 Grid& gr = const_cast<Grid&>(*this);
00300 if (gr.simplify(gr.con_sys, gr.dim_kinds))
00301 gr.set_empty();
00302 else
00303 gr.set_congruences_minimized();
00304 }
00305 return congruences();
00306 }
00307
00308 const PPL::Grid_Generator_System&
00309 PPL::Grid::grid_generators() const {
00310 if (space_dim == 0) {
00311 PPL_ASSERT(gen_sys.space_dimension() == 0
00312 && gen_sys.num_rows() == (marked_empty() ? 0 : 1));
00313 return gen_sys;
00314 }
00315
00316 if (marked_empty()) {
00317 PPL_ASSERT(gen_sys.has_no_rows());
00318 return gen_sys;
00319 }
00320
00321 if (!generators_are_up_to_date() && !update_generators()) {
00322
00323 const_cast<Grid&>(*this).set_empty();
00324 return gen_sys;
00325 }
00326
00327 return gen_sys;
00328 }
00329
00330 const PPL::Grid_Generator_System&
00331 PPL::Grid::minimized_grid_generators() const {
00332 if (space_dim == 0) {
00333 PPL_ASSERT(gen_sys.space_dimension() == 0
00334 && gen_sys.num_rows() == (marked_empty() ? 0 : 1));
00335 return gen_sys;
00336 }
00337
00338 if (marked_empty()) {
00339 PPL_ASSERT(gen_sys.has_no_rows());
00340 return gen_sys;
00341 }
00342
00343 if (generators_are_up_to_date()) {
00344 if (!generators_are_minimized()) {
00345
00346 Grid& gr = const_cast<Grid&>(*this);
00347 gr.simplify(gr.gen_sys, gr.dim_kinds);
00348 gr.set_generators_minimized();
00349 }
00350 }
00351 else if (!update_generators()) {
00352
00353 const_cast<Grid&>(*this).set_empty();
00354 return gen_sys;
00355 }
00356
00357 return gen_sys;
00358 }
00359
00360 PPL::Poly_Con_Relation
00361 PPL::Grid::relation_with(const Congruence& cg) const {
00362
00363 if (space_dim < cg.space_dimension())
00364 throw_dimension_incompatible("relation_with(cg)", "cg", cg);
00365
00366 if (marked_empty())
00367 return Poly_Con_Relation::saturates()
00368 && Poly_Con_Relation::is_included()
00369 && Poly_Con_Relation::is_disjoint();
00370
00371 if (space_dim == 0) {
00372 if (cg.is_inconsistent())
00373 return Poly_Con_Relation::is_disjoint();
00374 else if (cg.is_equality())
00375 return Poly_Con_Relation::saturates()
00376 && Poly_Con_Relation::is_included();
00377 else if (cg.inhomogeneous_term() % cg.modulus() == 0)
00378 return Poly_Con_Relation::saturates()
00379 && Poly_Con_Relation::is_included();
00380 }
00381
00382 if (!generators_are_up_to_date() && !update_generators())
00383
00384 return Poly_Con_Relation::saturates()
00385 && Poly_Con_Relation::is_included()
00386 && Poly_Con_Relation::is_disjoint();
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397 PPL_DIRTY_TEMP_COEFFICIENT(point_sp);
00398 point_sp = 0;
00399
00400 const Coefficient& modulus = cg.modulus();
00401
00402 PPL_DIRTY_TEMP_COEFFICIENT(div);
00403 div = modulus;
00404
00405 PPL_DIRTY_TEMP_COEFFICIENT(sp);
00406
00407 bool known_to_intersect = false;
00408
00409 for (Grid_Generator_System::const_iterator g = gen_sys.begin(),
00410 gen_sys_end = gen_sys.end(); g != gen_sys_end; ++g) {
00411 Scalar_Products::assign(sp, cg, *g);
00412
00413 switch (g->type()) {
00414
00415 case Grid_Generator::POINT:
00416 if (cg.is_proper_congruence())
00417 sp %= div;
00418 if (sp == 0)
00419
00420 if (point_sp == 0)
00421
00422 known_to_intersect = true;
00423 else
00424 return Poly_Con_Relation::strictly_intersects();
00425 else
00426 if (point_sp == 0) {
00427 if (known_to_intersect)
00428 return Poly_Con_Relation::strictly_intersects();
00429
00430
00431 point_sp = sp;
00432 }
00433 else {
00434
00435
00436
00437
00438
00439 sp -= point_sp;
00440
00441 if (sp != 0) {
00442
00443 gcd_assign(div, div, sp);
00444 if (point_sp % div == 0)
00445
00446 return Poly_Con_Relation::strictly_intersects();
00447 }
00448 }
00449 break;
00450
00451 case Grid_Generator::PARAMETER:
00452 if (cg.is_proper_congruence())
00453 sp %= (div * g->divisor());
00454 if (sp == 0)
00455
00456
00457 break;
00458
00459 if (known_to_intersect)
00460
00461
00462 return Poly_Con_Relation::strictly_intersects();
00463
00464
00465 gcd_assign(div, div, sp);
00466 if (point_sp != 0)
00467
00468
00469 if (point_sp % div == 0)
00471
00472 return Poly_Con_Relation::strictly_intersects();
00473
00474 break;
00475
00476 case Grid_Generator::LINE:
00477 if (sp == 0)
00478
00479
00480 break;
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495 return Poly_Con_Relation::strictly_intersects();
00496 }
00497 }
00498
00499 if (point_sp == 0) {
00500 if (cg.is_equality())
00501
00502 return Poly_Con_Relation::is_included()
00503 && Poly_Con_Relation::saturates();
00504 else
00505
00506 return Poly_Con_Relation::is_included();
00507 }
00508
00509 PPL_ASSERT(!known_to_intersect);
00510 return Poly_Con_Relation::is_disjoint();
00511 }
00512
00513 PPL::Poly_Gen_Relation
00514 PPL::Grid::relation_with(const Grid_Generator& g) const {
00515
00516 if (space_dim < g.space_dimension())
00517 throw_dimension_incompatible("relation_with(g)", "g", g);
00518
00519
00520 if (marked_empty())
00521 return Poly_Gen_Relation::nothing();
00522
00523
00524
00525 if (space_dim == 0)
00526 return Poly_Gen_Relation::subsumes();
00527
00528 if (!congruences_are_up_to_date())
00529 update_congruences();
00530
00531 return
00532 con_sys.satisfies_all_congruences(g)
00533 ? Poly_Gen_Relation::subsumes()
00534 : Poly_Gen_Relation::nothing();
00535 }
00536
00537 PPL::Poly_Gen_Relation
00538 PPL::Grid::relation_with(const Generator& g) const {
00539 dimension_type g_space_dim = g.space_dimension();
00540
00541
00542 if (space_dim < g_space_dim)
00543 throw_dimension_incompatible("relation_with(g)", "g", g);
00544
00545
00546 if (marked_empty())
00547 return Poly_Gen_Relation::nothing();
00548
00549
00550
00551 if (space_dim == 0)
00552 return Poly_Gen_Relation::subsumes();
00553
00554 if (!congruences_are_up_to_date())
00555 update_congruences();
00556
00557 Linear_Expression expr;
00558 for (dimension_type i = g_space_dim; i-- > 0; ) {
00559 const Variable v(i);
00560 expr += g.coefficient(v) * v;
00561 }
00562 Grid_Generator gg(grid_point());
00563 if (g.is_point() || g.is_closure_point())
00564
00565 gg = grid_point(expr, g.divisor());
00566 else
00567
00568
00569 gg = grid_line(expr);
00570
00571 return
00572 con_sys.satisfies_all_congruences(gg)
00573 ? Poly_Gen_Relation::subsumes()
00574 : Poly_Gen_Relation::nothing();
00575 }
00576
00577 PPL::Poly_Con_Relation
00578 PPL::Grid::relation_with(const Constraint& c) const {
00579
00580 if (space_dim < c.space_dimension())
00581 throw_dimension_incompatible("relation_with(c)", "c", c);
00582
00583 if (c.is_equality()) {
00584 Congruence cg(c);
00585 return relation_with(cg);
00586 }
00587
00588 if (marked_empty())
00589 return Poly_Con_Relation::saturates()
00590 && Poly_Con_Relation::is_included()
00591 && Poly_Con_Relation::is_disjoint();
00592
00593 if (space_dim == 0) {
00594 if (c.is_inconsistent())
00595 if (c.is_strict_inequality() && c.inhomogeneous_term() == 0)
00596
00597
00598 return Poly_Con_Relation::saturates()
00599 && Poly_Con_Relation::is_disjoint();
00600 else
00601 return Poly_Con_Relation::is_disjoint();
00602 else if (c.inhomogeneous_term() == 0)
00603 return Poly_Con_Relation::saturates()
00604 && Poly_Con_Relation::is_included();
00605 else
00606
00607
00608
00609 return Poly_Con_Relation::is_included();
00610 }
00611
00612 if (!generators_are_up_to_date() && !update_generators())
00613
00614 return Poly_Con_Relation::saturates()
00615 && Poly_Con_Relation::is_included()
00616 && Poly_Con_Relation::is_disjoint();
00617
00618
00619
00620
00621
00622
00623
00624
00625 bool point_is_included = false;
00626 bool point_saturates = false;
00627 const Grid_Generator* first_point = NULL;
00628
00629 for (Grid_Generator_System::const_iterator g = gen_sys.begin(),
00630 gen_sys_end = gen_sys.end(); g != gen_sys_end; ++g)
00631 switch (g->type()) {
00632
00633 case Grid_Generator::POINT:
00634 {
00635 Grid_Generator& gen = const_cast<Grid_Generator&>(*g);
00636 if (first_point == NULL) {
00637 first_point = &gen;
00638 const int sign = Scalar_Products::sign(c, gen);
00639 Constraint::Type type = c.type();
00640 if ((type == Constraint::NONSTRICT_INEQUALITY && sign == 0)) {
00641 point_saturates = true;
00642 }
00643 else if (sign > 0)
00644 point_is_included = true;
00645 break;
00646 }
00647
00648
00649 gen.set_is_parameter();
00650 const Grid_Generator& first = *first_point;
00651 for (dimension_type i = gen.size() - 1; i-- > 0; )
00652 gen[i] -= first[i];
00653 }
00654
00655 case Grid_Generator::PARAMETER:
00656 case Grid_Generator::LINE:
00657 Grid_Generator& gen = const_cast<Grid_Generator&>(*g);
00658 if (gen.is_line_or_parameter())
00659 for (dimension_type i = c.space_dimension(); i-- > 0; ) {
00660 Variable v(i);
00661 if (c.coefficient(v) != 0 && gen.coefficient(v) != 0)
00662 return Poly_Con_Relation::strictly_intersects();
00663 }
00664 break;
00665 }
00666
00667 if (point_saturates)
00668
00669 return Poly_Con_Relation::saturates()
00670 && Poly_Con_Relation::is_included();
00671 if (point_is_included)
00672
00673 return Poly_Con_Relation::is_included();
00674 return Poly_Con_Relation::is_disjoint();
00675 }
00676
00677 bool
00678 PPL::Grid::is_empty() const {
00679 if (marked_empty())
00680 return true;
00681
00682
00683 if (generators_are_up_to_date())
00684 return false;
00685 if (space_dim == 0)
00686 return false;
00687 if (congruences_are_minimized())
00688
00689 return false;
00690
00691 Grid& gr = const_cast<Grid&>(*this);
00692 if (gr.simplify(gr.con_sys, gr.dim_kinds)) {
00693 gr.set_empty();
00694 return true;
00695 }
00696 gr.set_congruences_minimized();
00697 return false;
00698 }
00699
00700 bool
00701 PPL::Grid::is_universe() const {
00702 if (marked_empty())
00703 return false;
00704
00705 if (space_dim == 0)
00706 return true;
00707
00708 if (congruences_are_up_to_date()) {
00709 if (congruences_are_minimized())
00710
00711
00712 return con_sys.num_rows() == 1 && con_sys[0].is_tautological();
00713 }
00714 else {
00715 update_congruences();
00716 return con_sys.num_rows() == 1 && con_sys[0].is_tautological();
00717 }
00718
00719
00720
00721
00722 Variable var(space_dim - 1);
00723 for (dimension_type i = space_dim; i-- > 0; )
00724 if (!con_sys.satisfies_all_congruences(grid_line(Variable(i) + var)))
00725 return false;
00726 PPL_ASSERT(con_sys.satisfies_all_congruences(grid_point(0*var)));
00727 return true;
00728 }
00729
00730 bool
00731 PPL::Grid::is_bounded() const {
00732
00733 if (space_dim == 0
00734 || marked_empty()
00735 || (!generators_are_up_to_date() && !update_generators()))
00736 return true;
00737
00738
00739
00740 if (gen_sys.num_rows() > 1) {
00741
00742 const Grid_Generator& first_point = gen_sys[0];
00743 if (first_point.is_line_or_parameter())
00744 return false;
00745 for (dimension_type row = gen_sys.num_rows(); row-- > 0; ) {
00746 const Grid_Generator& gen = gen_sys[row];
00747 if (gen.is_line_or_parameter() || gen != first_point)
00748 return false;
00749 }
00750 }
00751 return true;
00752 }
00753
00754 bool
00755 PPL::Grid::is_discrete() const {
00756
00757 if (space_dim == 0
00758 || marked_empty()
00759 || (!generators_are_up_to_date() && !update_generators()))
00760 return true;
00761
00762
00763 for (dimension_type row = gen_sys.num_rows(); row-- > 1; )
00764 if (gen_sys[row].is_line())
00765 return false;
00766
00767
00768
00769 return true;
00770 }
00771
00772 bool
00773 PPL::Grid::is_topologically_closed() const {
00774 return true;
00775 }
00776
00777 bool
00778 PPL::Grid::contains_integer_point() const {
00779
00780 if (marked_empty())
00781 return false;
00782
00783
00784
00785 if (space_dim == 0)
00786 return true;
00787
00788
00789
00790 Congruence_System cgs;
00791 for (dimension_type var_index = space_dim; var_index-- > 0; )
00792 cgs.insert(Variable(var_index) %= 0);
00793
00794 Grid gr = *this;
00795 gr.add_recycled_congruences(cgs);
00796 return !gr.is_empty();
00797 }
00798
00799 bool
00800 PPL::Grid::constrains(const Variable var) const {
00801
00802 const dimension_type var_space_dim = var.space_dimension();
00803 if (space_dim < var_space_dim)
00804 throw_dimension_incompatible("constrains(v)", "v", var);
00805
00806
00807 if (marked_empty())
00808 return true;
00809
00810 if (generators_are_up_to_date()) {
00811
00812
00813 if (congruences_are_up_to_date())
00814
00815
00816 goto syntactic_check;
00817
00818 if (generators_are_minimized()) {
00819
00820
00821
00822 dimension_type num_lines = 0;
00823 for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
00824 if (gen_sys[i].is_line())
00825 ++num_lines;
00826
00827 if (num_lines == space_dim)
00828 return false;
00829 }
00830
00831
00832 const dimension_type var_id = var.id();
00833 for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
00834 const Grid_Generator& g_i = gen_sys[i];
00835 if (g_i.is_line()) {
00836 if (sgn(g_i.coefficient(var)) != 0) {
00837 for (dimension_type j = 0; j < space_dim; ++j)
00838 if (g_i.coefficient(Variable(j)) != 0 && j != var_id)
00839 goto next;
00840 return true;
00841 }
00842 }
00843 next:
00844 ;
00845 }
00846
00847
00848 update_congruences();
00849 goto syntactic_check;
00850 }
00851
00852
00853 if (!minimize())
00854 return true;
00855
00856 syntactic_check:
00857 for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00858 if (con_sys[i].coefficient(var) != 0)
00859 return true;
00860 return false;
00861 }
00862
00863 bool
00864 PPL::Grid::OK(bool check_not_empty) const {
00865 #ifndef NDEBUG
00866 using std::endl;
00867 using std::cerr;
00868 #endif
00869
00870
00871 if (!status.OK())
00872 goto fail;
00873
00874 if (marked_empty()) {
00875 if (check_not_empty) {
00876
00877 #ifndef NDEBUG
00878 cerr << "Empty grid!" << endl;
00879 #endif
00880 goto fail;
00881 }
00882
00883 if (con_sys.space_dimension() != space_dim) {
00884 #ifndef NDEBUG
00885 cerr << "The grid is in a space of dimension " << space_dim
00886 << " while the system of congruences is in a space of dimension "
00887 << con_sys.space_dimension()
00888 << endl;
00889 #endif
00890 goto fail;
00891 }
00892 return true;
00893 }
00894
00895
00896
00897
00898 if (space_dim == 0) {
00899 if (con_sys.has_no_rows())
00900 if (gen_sys.num_rows() == 1 && gen_sys[0].is_point())
00901 return true;
00902 #ifndef NDEBUG
00903 cerr << "Zero-dimensional grid should have an empty congruence" << endl
00904 << "system and a generator system of a single point." << endl;
00905 #endif
00906 goto fail;
00907 }
00908
00909
00910
00911 if (!congruences_are_up_to_date() && !generators_are_up_to_date()) {
00912 #ifndef NDEBUG
00913 cerr << "Grid not empty, not zero-dimensional" << endl
00914 << "and with neither congruences nor generators up-to-date!"
00915 << endl;
00916 #endif
00917 goto fail;
00918 }
00919
00920 {
00921
00922
00923 const dimension_type num_columns = space_dim + 1;
00924
00925
00926
00927
00928
00929 if (congruences_are_up_to_date())
00930 if (con_sys.num_columns() != num_columns + 1 ) {
00931 #ifndef NDEBUG
00932 cerr << "Incompatible size! (con_sys and space_dim)"
00933 << endl;
00934 #endif
00935 goto fail;
00936 }
00937
00938 if (generators_are_up_to_date()) {
00939 if (gen_sys.space_dimension() + 1 != num_columns) {
00940 #ifndef NDEBUG
00941 cerr << "Incompatible size! (gen_sys and space_dim)"
00942 << endl;
00943 #endif
00944 goto fail;
00945 }
00946
00947
00948 if (!gen_sys.OK())
00949 goto fail;
00950
00951
00952 for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
00953 const Grid_Generator& g = gen_sys[i];
00954
00955 if (g.size() < 1) {
00956 #ifndef NDEBUG
00957 cerr << "Parameter should have coefficients." << endl;
00958 #endif
00959 goto fail;
00960 }
00961 }
00962
00963
00964
00965 if (!gen_sys.has_no_rows() && !gen_sys.has_points()) {
00966 #ifndef NDEBUG
00967 cerr << "Non-empty generator system declared up-to-date "
00968 << "has no points!"
00969 << endl;
00970 #endif
00971 goto fail;
00972 }
00973
00974 if (generators_are_minimized()) {
00975 Grid_Generator_System gs = gen_sys;
00976
00977 if (dim_kinds.size() != num_columns) {
00978 #ifndef NDEBUG
00979 cerr << "Size of dim_kinds should equal the number of columns."
00980 << endl;
00981 #endif
00982 goto fail;
00983 }
00984
00985 if (!upper_triangular(gs, dim_kinds)) {
00986 #ifndef NDEBUG
00987 cerr << "Reduced generators should be upper triangular."
00988 << endl;
00989 #endif
00990 goto fail;
00991 }
00992
00993
00994 for (dimension_type dim = space_dim,
00995 row = gen_sys.num_rows(); dim > 0; --dim) {
00996 if (dim_kinds[dim] == GEN_VIRTUAL)
00997 goto ok;
00998 if (gen_sys[--row].is_parameter_or_point()
00999 && dim_kinds[dim] == PARAMETER)
01000 goto ok;
01001 PPL_ASSERT(gen_sys[row].is_line());
01002 if (dim_kinds[dim] == LINE)
01003 goto ok;
01004 #ifndef NDEBUG
01005 cerr << "Kinds in dim_kinds should match those in gen_sys."
01006 << endl;
01007 #endif
01008 goto fail;
01009 ok:
01010 PPL_ASSERT(row <= dim);
01011 }
01012
01013
01014
01015 Dimension_Kinds dk = dim_kinds;
01016
01017
01018 PPL_ASSERT(!gs.has_no_rows());
01019 simplify(gs, dk);
01020
01021
01022 PPL_ASSERT(!gs.has_no_rows());
01023 for (dimension_type row = gen_sys.num_rows(); row-- > 0; ) {
01024 Grid_Generator& g = gs[row];
01025 const Grid_Generator& g_copy = gen_sys[row];
01026 if (g.is_equal_to(g_copy))
01027 continue;
01028 #ifndef NDEBUG
01029 cerr << "Generators are declared minimized,"
01030 " but they change under reduction.\n"
01031 << "Here is the generator system:\n";
01032 gen_sys.ascii_dump(cerr);
01033 cerr << "and here is the minimized form of the temporary copy:\n";
01034 gs.ascii_dump(cerr);
01035 #endif
01036 goto fail;
01037 }
01038 }
01039
01040 }
01041 }
01042
01043 if (congruences_are_up_to_date()) {
01044
01045 if (!con_sys.OK())
01046 goto fail;
01047
01048 Grid tmp_gr = *this;
01049 Congruence_System cs_copy = tmp_gr.con_sys;
01050
01051
01052 Grid_Generator_System gs(space_dim);
01053 std::swap(tmp_gr.gen_sys, gs);
01054 tmp_gr.clear_generators_up_to_date();
01055
01056 if (!tmp_gr.update_generators()) {
01057 if (check_not_empty) {
01058
01059 #ifndef NDEBUG
01060 cerr << "Unsatisfiable system of congruences!"
01061 << endl;
01062 #endif
01063 goto fail;
01064 }
01065
01066 return true;
01067 }
01068
01069 if (congruences_are_minimized()) {
01070
01071 if (!lower_triangular(con_sys, dim_kinds)) {
01072 #ifndef NDEBUG
01073 cerr << "Reduced congruences should be lower triangular." << endl;
01074 #endif
01075 goto fail;
01076 }
01077
01078
01079
01080
01081 if (!con_sys.is_equal_to(cs_copy)) {
01082 #ifndef NDEBUG
01083 cerr << "Congruences are declared minimized, but they change under reduction!"
01084 << endl
01085 << "Here is the minimized form of the congruence system:"
01086 << endl;
01087 cs_copy.ascii_dump(cerr);
01088 cerr << endl;
01089 #endif
01090 goto fail;
01091 }
01092
01093 if (dim_kinds.size() != con_sys.num_columns() - 1 ) {
01094 #ifndef NDEBUG
01095 cerr << "Size of dim_kinds should equal the number of columns."
01096 << endl;
01097 #endif
01098 goto fail;
01099 }
01100
01101
01102 for (dimension_type dim = space_dim, row = 0; dim > 0; --dim) {
01103 if (dim_kinds[dim] == CON_VIRTUAL)
01104 continue;
01105 if (con_sys[row++].is_proper_congruence()
01106 && dim_kinds[dim] == PROPER_CONGRUENCE)
01107 continue;
01108 PPL_ASSERT(con_sys[row-1].is_equality());
01109 if (dim_kinds[dim] == EQUALITY)
01110 continue;
01111 #ifndef NDEBUG
01112 cerr << "Kinds in dim_kinds should match those in con_sys." << endl;
01113 #endif
01114 goto fail;
01115 }
01116 }
01117 }
01118
01119 return true;
01120
01121 fail:
01122 #ifndef NDEBUG
01123 cerr << "Here is the grid under check:" << endl;
01124 ascii_dump(cerr);
01125 #endif
01126 return false;
01127 }
01128
01129 void
01130 PPL::Grid::add_constraints(const Constraint_System& cs) {
01131
01132 if (space_dim < cs.space_dimension())
01133 throw_dimension_incompatible("add_constraints(cs)", "cs", cs);
01134 if (marked_empty())
01135 return;
01136
01137 for (Constraint_System::const_iterator i = cs.begin(),
01138 cs_end = cs.end(); i != cs_end; ++i) {
01139 add_constraint_no_check(*i);
01140 if (marked_empty())
01141 return;
01142 }
01143 }
01144
01145 void
01146 PPL::Grid::add_grid_generator(const Grid_Generator& g) {
01147
01148 const dimension_type g_space_dim = g.space_dimension();
01149 if (space_dim < g_space_dim)
01150 throw_dimension_incompatible("add_grid_generator(g)", "g", g);
01151
01152
01153 if (space_dim == 0) {
01154
01155
01156 if (marked_empty()) {
01157 if (g.is_parameter())
01158 throw_invalid_generator("add_grid_generator(g)", "g");
01159 set_zero_dim_univ();
01160 }
01161 PPL_ASSERT(OK());
01162 return;
01163 }
01164
01165 if (marked_empty()
01166 || (!generators_are_up_to_date() && !update_generators())) {
01167
01168
01169 if (g.is_line_or_parameter())
01170 throw_invalid_generator("add_grid_generator(g)", "g");
01171 gen_sys.insert(g);
01172 clear_empty();
01173 }
01174 else {
01175 PPL_ASSERT(generators_are_up_to_date());
01176 gen_sys.insert(g);
01177 if (g.is_parameter_or_point())
01178 normalize_divisors(gen_sys);
01179 }
01180
01181
01182 clear_congruences_up_to_date();
01183
01184 clear_generators_minimized();
01185 set_generators_up_to_date();
01186 PPL_ASSERT(OK());
01187 }
01188
01189 void
01190 PPL::Grid::add_recycled_congruences(Congruence_System& cgs) {
01191
01192 const dimension_type cgs_space_dim = cgs.space_dimension();
01193 if (space_dim < cgs_space_dim)
01194 throw_dimension_incompatible("add_recycled_congruences(cgs)", "cgs", cgs);
01195
01196 if (cgs.has_no_rows())
01197 return;
01198
01199 if (marked_empty())
01200 return;
01201
01202 if (space_dim == 0) {
01203
01204
01205
01206
01207 if (cgs.begin() != cgs.end())
01208
01209 set_empty();
01210 return;
01211 }
01212
01213
01214 if (!congruences_are_up_to_date())
01215 update_congruences();
01216
01217
01218
01219 con_sys.recycling_insert(cgs);
01220
01221
01222 clear_congruences_minimized();
01223 clear_generators_up_to_date();
01224
01225
01226 PPL_ASSERT(OK());
01227 }
01228
01229 void
01230 PPL::Grid::add_recycled_grid_generators(Grid_Generator_System& gs) {
01231
01232 const dimension_type gs_space_dim = gs.space_dimension();
01233 if (space_dim < gs_space_dim)
01234 throw_dimension_incompatible("add_recycled_grid_generators(gs)", "gs", gs);
01235
01236
01237 if (gs.has_no_rows())
01238 return;
01239
01240
01241
01242 if (space_dim == 0) {
01243 if (marked_empty())
01244 set_zero_dim_univ();
01245 else {
01246 PPL_ASSERT(gs.has_points());
01247 }
01248 PPL_ASSERT(OK(true));
01249 return;
01250 }
01251
01252 if (!marked_empty()) {
01253
01254
01255 if (!generators_are_up_to_date())
01256 update_generators();
01257 normalize_divisors(gs, gen_sys);
01258
01259 gen_sys.recycling_insert(gs);
01260
01261
01262 clear_congruences_up_to_date();
01263 clear_generators_minimized();
01264
01265 PPL_ASSERT(OK(true));
01266 return;
01267 }
01268
01269
01270
01271
01272 if (!gs.has_points())
01273 throw_invalid_generators("add_recycled_grid_generators(gs)", "gs");
01274
01275
01276 gs.insert(parameter(0*Variable(space_dim-1)));
01277
01278 std::swap(gen_sys, gs);
01279
01280 normalize_divisors(gen_sys);
01281
01282
01283 set_generators_up_to_date();
01284 clear_empty();
01285
01286 PPL_ASSERT(OK());
01287 }
01288
01289 void
01290 PPL::Grid::add_grid_generators(const Grid_Generator_System& gs) {
01291
01292 Grid_Generator_System gs_copy = gs;
01293 add_recycled_grid_generators(gs_copy);
01294 }
01295
01296 void
01297 PPL::Grid::refine_with_constraint(const Constraint& c) {
01298
01299 if (space_dim < c.space_dimension())
01300 throw_dimension_incompatible("refine_with_constraint(c)", "c", c);
01301 if (marked_empty())
01302 return;
01303 refine_no_check(c);
01304 }
01305
01306 void
01307 PPL::Grid::refine_with_constraints(const Constraint_System& cs) {
01308
01309 if (space_dim < cs.space_dimension())
01310 throw_dimension_incompatible("refine_with_constraints(cs)", "cs", cs);
01311
01312 for (Constraint_System::const_iterator i = cs.begin(),
01313 cs_end = cs.end(); !marked_empty() && i != cs_end; ++i)
01314 refine_no_check(*i);
01315 }
01316
01317 void
01318 PPL::Grid::unconstrain(const Variable var) {
01319
01320 if (space_dim < var.space_dimension())
01321 throw_dimension_incompatible("unconstrain(var)", var.space_dimension());
01322
01323
01324 if (marked_empty()
01325 || (!generators_are_up_to_date() && !update_generators()))
01326
01327 return;
01328
01329 PPL_ASSERT(generators_are_up_to_date());
01330 Grid_Generator l = grid_line(var);
01331 gen_sys.recycling_insert(l);
01332
01333 clear_congruences_up_to_date();
01334 clear_generators_minimized();
01335 PPL_ASSERT(OK());
01336 }
01337
01338 void
01339 PPL::Grid::unconstrain(const Variables_Set& vars) {
01340
01341
01342
01343 if (vars.empty())
01344 return;
01345
01346
01347 const dimension_type min_space_dim = vars.space_dimension();
01348 if (space_dim < min_space_dim)
01349 throw_dimension_incompatible("unconstrain(vs)", min_space_dim);
01350
01351
01352 if (marked_empty()
01353 || (!generators_are_up_to_date() && !update_generators()))
01354
01355 return;
01356
01357 PPL_ASSERT(generators_are_up_to_date());
01358
01359
01360 for (Variables_Set::const_iterator vsi = vars.begin(),
01361 vsi_end = vars.end(); vsi != vsi_end; ++vsi) {
01362 Grid_Generator l = grid_line(Variable(*vsi));
01363 gen_sys.recycling_insert(l);
01364 }
01365
01366 clear_generators_minimized();
01367 clear_congruences_up_to_date();
01368 PPL_ASSERT(OK());
01369 }
01370
01371 void
01372 PPL::Grid::intersection_assign(const Grid& y) {
01373 Grid& x = *this;
01374
01375 if (x.space_dim != y.space_dim)
01376 throw_dimension_incompatible("intersection_assign(y)", "y", y);
01377
01378
01379 if (x.marked_empty())
01380 return;
01381 if (y.marked_empty()) {
01382 x.set_empty();
01383 return;
01384 }
01385
01386
01387
01388 if (x.space_dim == 0)
01389 return;
01390
01391
01392 if (!x.congruences_are_up_to_date())
01393 x.update_congruences();
01394 if (!y.congruences_are_up_to_date())
01395 y.update_congruences();
01396
01397 if (!y.con_sys.has_no_rows()) {
01398 x.con_sys.insert(y.con_sys);
01399
01400
01401 x.clear_generators_up_to_date();
01402 x.clear_congruences_minimized();
01403 }
01404
01405 PPL_ASSERT(x.OK() && y.OK());
01406 }
01407
01408 void
01409 PPL::Grid::upper_bound_assign(const Grid& y) {
01410 Grid& x = *this;
01411
01412 if (x.space_dim != y.space_dim)
01413 throw_dimension_incompatible("upper_bound_assign(y)", "y", y);
01414
01415
01416 if (y.marked_empty())
01417 return;
01418 if (x.marked_empty()) {
01419 x = y;
01420 return;
01421 }
01422
01423
01424
01425 if (x.space_dim == 0)
01426 return;
01427
01428
01429 if (!x.generators_are_up_to_date() && !x.update_generators()) {
01430
01431 x = y;
01432 return;
01433 }
01434 if (!y.generators_are_up_to_date() && !y.update_generators())
01435
01436 return;
01437
01438
01439 Grid_Generator_System gs(y.gen_sys);
01440 normalize_divisors(x.gen_sys, gs);
01441 x.gen_sys.recycling_insert(gs);
01442
01443
01444 x.clear_congruences_up_to_date();
01445 x.clear_generators_minimized();
01446
01447
01448 PPL_ASSERT(x.OK(true) && y.OK(true));
01449 }
01450
01451 bool
01452 PPL::Grid::upper_bound_assign_if_exact(const Grid& y) {
01453 Grid& x = *this;
01454
01455
01456 if (x.space_dim != y.space_dim)
01457 throw_dimension_incompatible("upper_bound_assign_if_exact(y)", "y", y);
01458
01459 if (x.marked_empty()
01460 || y.marked_empty()
01461 || x.space_dim == 0
01462 || x.is_included_in(y)
01463 || y.is_included_in(x)) {
01464 upper_bound_assign(y);
01465 return true;
01466 }
01467
01468
01469
01470 PPL_ASSERT(generators_are_up_to_date());
01471
01472 Grid x_copy = x;
01473 x_copy.upper_bound_assign(y);
01474 x_copy.difference_assign(y);
01475 if (x_copy.is_included_in(x)) {
01476 upper_bound_assign(y);
01477 return true;
01478 }
01479
01480 return false;
01481 }
01482
01483 void
01484 PPL::Grid::difference_assign(const Grid& y) {
01485 Grid& x = *this;
01486
01487 if (x.space_dim != y.space_dim)
01488 throw_dimension_incompatible("difference_assign(y)", "y", y);
01489
01490 if (y.marked_empty() || x.marked_empty())
01491 return;
01492
01493
01494
01495 if (x.space_dim == 0) {
01496 x.set_empty();
01497 return;
01498 }
01499
01500 if (y.contains(x)) {
01501 x.set_empty();
01502 return;
01503 }
01504
01505 Grid new_grid(x.space_dim, EMPTY);
01506
01507 const Congruence_System& y_cgs = y.congruences();
01508 for (Congruence_System::const_iterator i = y_cgs.begin(),
01509 y_cgs_end = y_cgs.end(); i != y_cgs_end; ++i) {
01510 const Congruence& cg = *i;
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524 if (x.relation_with(cg).implies(Poly_Con_Relation::is_included()))
01525 continue;
01526
01527 if (cg.is_proper_congruence()) {
01528 const Linear_Expression e = Linear_Expression(cg);
01529
01530 const Coefficient& m = cg.modulus();
01531
01532
01533
01534
01535 if (x.relation_with((2*e %= 0) / m)
01536 .implies(Poly_Con_Relation::is_included())) {
01537 Grid z = x;
01538 z.add_congruence_no_check((2*e %= m) / (2*m));
01539 new_grid.upper_bound_assign(z);
01540 continue;
01541 }
01542 }
01543 return;
01544 }
01545
01546 *this = new_grid;
01547
01548 PPL_ASSERT(OK());
01549 }
01550
01551 namespace {
01552
01553 struct Ruled_Out_Pair {
01554 PPL::dimension_type congruence_index;
01555 PPL::dimension_type num_ruled_out;
01556 };
01557
01558 struct Ruled_Out_Less_Than {
01559 bool operator()(const Ruled_Out_Pair& x,
01560 const Ruled_Out_Pair& y) const {
01561 return x.num_ruled_out > y.num_ruled_out;
01562 }
01563 };
01564
01565 }
01566
01567 bool
01568 PPL::Grid::simplify_using_context_assign(const Grid& y) {
01569 Grid& x = *this;
01570
01571 if (x.space_dim != y.space_dim)
01572 throw_dimension_incompatible("simplify_using_context_assign(y)", "y", y);
01573
01574
01575 if (x.space_dim == 0) {
01576 if (y.is_empty()) {
01577 set_zero_dim_univ();
01578 PPL_ASSERT(OK());
01579 return false;
01580 }
01581 else
01582 return !x.is_empty();
01583 }
01584
01585
01586 if (!y.minimize()) {
01587 Grid gr(x.space_dim, UNIVERSE);
01588 swap(gr);
01589 return false;
01590 }
01591
01592
01593 if (!x.minimize()) {
01594
01595 PPL_ASSERT(y.congruences_are_up_to_date());
01596 Grid gr(x.space_dim, UNIVERSE);
01597 for (dimension_type i = y.con_sys.num_rows(); i-- > 0; ) {
01598 const Congruence& y_con_sys_i = y.con_sys[i];
01599 if (!y_con_sys_i.is_tautological()) {
01600
01601
01602
01603 const Linear_Expression le(y_con_sys_i);
01604 if (y_con_sys_i.is_equality()) {
01605 gr.refine_no_check(le == 1);
01606 break;
01607 }
01608 else {
01609 const Coefficient& y_modulus_i = y_con_sys_i.modulus();
01610 if (y_modulus_i > 1)
01611 gr.refine_no_check(le == 1);
01612 else {
01613 Linear_Expression le2;
01614 for (dimension_type j = le.space_dimension(); j-- > 0; )
01615 le2 += 2 * le.coefficient(Variable(j)) * Variable(j);
01616 le2 += 2 * le.inhomogeneous_term();
01617 gr.refine_no_check(le2 == y_modulus_i);
01618 }
01619 break;
01620 }
01621 }
01622 }
01623 swap(gr);
01624 PPL_ASSERT(OK());
01625 return false;
01626 }
01627
01628 PPL_ASSERT(x.congruences_are_minimized()
01629 && y.generators_are_minimized());
01630
01631 const Congruence_System& x_cs = x.con_sys;
01632 const dimension_type x_cs_num_rows = x_cs.num_rows();
01633 const Grid_Generator_System& y_gs = y.gen_sys;
01634
01635
01636
01637
01638 std::vector<bool> redundant_by_y(x_cs_num_rows, false);
01639 dimension_type num_redundant_by_y = 0;
01640 for (dimension_type i = 0; i < x_cs_num_rows; ++i)
01641 if (y.relation_with(x_cs[i])
01642 .implies(Poly_Con_Relation::is_included())) {
01643 redundant_by_y[i] = true;
01644 ++num_redundant_by_y;
01645 }
01646
01647 if (num_redundant_by_y < x_cs_num_rows) {
01648
01649
01650
01651 Congruence_System result_cs;
01652 const Congruence_System& y_cs = y.con_sys;
01653 const dimension_type y_cs_num_rows = y_cs.num_rows();
01654
01655 const bool x_first = (x_cs_num_rows > y_cs_num_rows);
01656 Grid z(x_first ? x : y);
01657 if (x_first)
01658 z.add_congruences(y_cs);
01659 else {
01660
01661 Congruence_System tmp_cs;
01662 for (dimension_type i = 0; i < x_cs_num_rows; ++i) {
01663 if (!redundant_by_y[i])
01664 tmp_cs.insert(x_cs[i]);
01665 }
01666 z.add_recycled_congruences(tmp_cs);
01667 }
01668
01669
01670
01671
01672 Grid w;
01673 w.add_space_dimensions_and_embed(x.space_dim);
01674
01675 w.add_congruences(y_cs);
01676
01677
01678
01679
01680
01681
01682 std::vector<Ruled_Out_Pair>
01683 ruled_out_vec(x_cs_num_rows - num_redundant_by_y);
01684
01685 PPL_DIRTY_TEMP_COEFFICIENT(sp);
01686 PPL_DIRTY_TEMP_COEFFICIENT(div);
01687
01688 for (dimension_type i = 0, j = 0; i < x_cs_num_rows; ++i) {
01689 if (!redundant_by_y[i]) {
01690 const Congruence& c = x_cs[i];
01691 const Coefficient& modulus = c.modulus();
01692 div = modulus;
01693
01694 dimension_type num_ruled_out_generators = 0;
01695 for (Grid_Generator_System::const_iterator k = y_gs.begin(),
01696 y_gs_end = y_gs.end(); k != y_gs_end; ++k) {
01697 const Grid_Generator& g = *k;
01698
01699
01700 Scalar_Products::assign(sp, c, g);
01701
01702
01703 if (c.is_proper_congruence()) {
01704
01705
01706 if (g.is_parameter())
01707 sp %= (div * g.divisor());
01708 else
01709 if (g.is_point())
01710 sp %= div;
01711 }
01712 if (sp == 0)
01713 continue;
01714 ++num_ruled_out_generators;
01715 }
01716 ruled_out_vec[j].congruence_index = i;
01717 ruled_out_vec[j].num_ruled_out = num_ruled_out_generators;
01718 ++j;
01719 }
01720 }
01721 std::sort(ruled_out_vec.begin(), ruled_out_vec.end(),
01722 Ruled_Out_Less_Than());
01723
01724 bool empty_intersection = (!z.minimize());
01725
01726
01727
01728 for (std::vector<Ruled_Out_Pair>::const_iterator
01729 j = ruled_out_vec.begin(), rov_end = ruled_out_vec.end();
01730 j != rov_end;
01731 ++j) {
01732 const Congruence& c = x_cs[j->congruence_index];
01733 result_cs.insert(c);
01734 w.add_congruence(c);
01735 if ((empty_intersection && w.is_empty())
01736 || (!empty_intersection && w.is_included_in(z))) {
01737 Grid result_gr(x.space_dim, UNIVERSE);
01738 result_gr.add_congruences(result_cs);
01739 x.swap(result_gr);
01740 PPL_ASSERT(x.OK());
01741 return !empty_intersection;
01742 }
01743 }
01744
01745 PPL_ASSERT(false);
01746 }
01747
01748
01749
01750 Grid result_gr(x.space_dim, UNIVERSE);
01751 x.swap(result_gr);
01752 PPL_ASSERT(x.OK());
01753 return true;
01754 }
01755
01756 void
01757 PPL::Grid::affine_image(const Variable var,
01758 const Linear_Expression& expr,
01759 Coefficient_traits::const_reference denominator) {
01760
01761 if (denominator == 0)
01762 throw_invalid_argument("affine_image(v, e, d)", "d == 0");
01763
01764
01765
01766 const dimension_type expr_space_dim = expr.space_dimension();
01767 if (space_dim < expr_space_dim)
01768 throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
01769
01770 const dimension_type var_space_dim = var.space_dimension();
01771 if (space_dim < var_space_dim)
01772 throw_dimension_incompatible("affine_image(v, e, d)", "v", var);
01773
01774 if (marked_empty())
01775 return;
01776
01777 if (var_space_dim <= expr_space_dim && expr[var_space_dim] != 0) {
01778
01779 if (generators_are_up_to_date()) {
01780
01781
01782 if (denominator > 0)
01783 gen_sys.affine_image(var_space_dim, expr, denominator);
01784 else
01785 gen_sys.affine_image(var_space_dim, -expr, -denominator);
01786 clear_generators_minimized();
01787
01788
01789 normalize_divisors(gen_sys);
01790 }
01791 if (congruences_are_up_to_date()) {
01792
01793
01794
01795 Linear_Expression inverse;
01796 if (expr[var_space_dim] > 0) {
01797 inverse = -expr;
01798 inverse[var_space_dim] = denominator;
01799 con_sys.affine_preimage(var_space_dim, inverse, expr[var_space_dim]);
01800 }
01801 else {
01802
01803
01804
01805 inverse = expr;
01806 inverse[var_space_dim] = denominator;
01807 neg_assign(inverse[var_space_dim]);
01808 con_sys.affine_preimage(var_space_dim, inverse, -expr[var_space_dim]);
01809 }
01810 clear_congruences_minimized();
01811 }
01812 }
01813 else {
01814
01815
01816 if (!generators_are_up_to_date())
01817 minimize();
01818 if (!marked_empty()) {
01819
01820
01821 if (denominator > 0)
01822 gen_sys.affine_image(var_space_dim, expr, denominator);
01823 else
01824 gen_sys.affine_image(var_space_dim, -expr, -denominator);
01825
01826 clear_congruences_up_to_date();
01827 clear_generators_minimized();
01828
01829
01830 normalize_divisors(gen_sys);
01831 }
01832 }
01833 PPL_ASSERT(OK());
01834 }
01835
01836 void
01837 PPL::Grid::
01838 affine_preimage(const Variable var,
01839 const Linear_Expression& expr,
01840 Coefficient_traits::const_reference denominator) {
01841
01842 if (denominator == 0)
01843 throw_invalid_argument("affine_preimage(v, e, d)", "d == 0");
01844
01845
01846
01847
01848 const dimension_type expr_space_dim = expr.space_dimension();
01849 if (space_dim < expr_space_dim)
01850 throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
01851
01852 const dimension_type var_space_dim = var.space_dimension();
01853 if (space_dim < var_space_dim)
01854 throw_dimension_incompatible("affine_preimage(v, e, d)", "v", var);
01855
01856 if (marked_empty())
01857 return;
01858
01859 if (var_space_dim <= expr_space_dim && expr[var_space_dim] != 0) {
01860
01861 if (congruences_are_up_to_date()) {
01862
01863
01864 if (denominator > 0)
01865 con_sys.affine_preimage(var_space_dim, expr, denominator);
01866 else
01867 con_sys.affine_preimage(var_space_dim, -expr, -denominator);
01868 clear_congruences_minimized();
01869 }
01870 if (generators_are_up_to_date()) {
01871
01872
01873
01874 Linear_Expression inverse;
01875 if (expr[var_space_dim] > 0) {
01876 inverse = -expr;
01877 inverse[var_space_dim] = denominator;
01878 gen_sys.affine_image(var_space_dim, inverse, expr[var_space_dim]);
01879 }
01880 else {
01881
01882
01883
01884 inverse = expr;
01885 inverse[var_space_dim] = denominator;
01886 neg_assign(inverse[var_space_dim]);
01887 gen_sys.affine_image(var_space_dim, inverse, -expr[var_space_dim]);
01888 }
01889 clear_generators_minimized();
01890 }
01891 }
01892 else {
01893
01894
01895 if (!congruences_are_up_to_date())
01896 minimize();
01897
01898
01899 if (denominator > 0)
01900 con_sys.affine_preimage(var_space_dim, expr, denominator);
01901 else
01902 con_sys.affine_preimage(var_space_dim, -expr, -denominator);
01903
01904 clear_generators_up_to_date();
01905 clear_congruences_minimized();
01906 }
01907 PPL_ASSERT(OK());
01908 }
01909
01910 void
01911 PPL::Grid::
01912 generalized_affine_image(const Variable var,
01913 const Relation_Symbol relsym,
01914 const Linear_Expression& expr,
01915 Coefficient_traits::const_reference denominator,
01916 Coefficient_traits::const_reference modulus) {
01917
01918
01919 if (denominator == 0)
01920 throw_invalid_argument("generalized_affine_image(v, r, e, d, m)",
01921 "d == 0");
01922
01923
01924
01925
01926 const dimension_type expr_space_dim = expr.space_dimension();
01927 if (space_dim < expr_space_dim)
01928 throw_dimension_incompatible("generalized_affine_image(v, r, e, d, m)",
01929 "e", expr);
01930
01931 const dimension_type var_space_dim = var.space_dimension();
01932 if (space_dim < var_space_dim)
01933 throw_dimension_incompatible("generalized_affine_image(v, r, e, d, m)",
01934 "v", var);
01935
01936
01937 if (marked_empty())
01938 return;
01939
01940
01941
01942 if (relsym != EQUAL) {
01943
01944 if (modulus != 0)
01945 throw_invalid_argument("generalized_affine_image(v, r, e, d, m)",
01946 "r != EQUAL && m != 0");
01947
01948 if (!generators_are_up_to_date())
01949 minimize();
01950
01951
01952 if (marked_empty())
01953 return;
01954
01955 add_grid_generator(grid_line(var));
01956
01957 PPL_ASSERT(OK());
01958 return;
01959 }
01960
01961 PPL_ASSERT(relsym == EQUAL);
01962
01963 affine_image(var, expr, denominator);
01964
01965 if (modulus == 0)
01966 return;
01967
01968
01969
01970 if (!generators_are_up_to_date())
01971 minimize();
01972
01973
01974
01975 if (marked_empty())
01976 return;
01977
01978 if (modulus < 0)
01979 gen_sys.insert(parameter(-modulus * var));
01980 else
01981 gen_sys.insert(parameter(modulus * var));
01982
01983 normalize_divisors(gen_sys);
01984
01985 clear_generators_minimized();
01986 clear_congruences_up_to_date();
01987
01988 PPL_ASSERT(OK());
01989 }
01990
01991 void
01992 PPL::Grid::
01993 generalized_affine_preimage(const Variable var,
01994 const Relation_Symbol relsym,
01995 const Linear_Expression& expr,
01996 Coefficient_traits::const_reference denominator,
01997 Coefficient_traits::const_reference modulus) {
01998
01999 if (denominator == 0)
02000 throw_invalid_argument("generalized_affine_preimage(v, e, d, m)",
02001 "d == 0");
02002
02003
02004
02005 const dimension_type expr_space_dim = expr.space_dimension();
02006 if (space_dim < expr_space_dim)
02007 throw_dimension_incompatible("generalized_affine_preimage(v, e, d, m)",
02008 "e", expr);
02009
02010 const dimension_type var_space_dim = var.space_dimension();
02011 if (space_dim < var_space_dim)
02012 throw_dimension_incompatible("generalized_affine_preimage(v, e, d, m)",
02013 "v", var);
02014
02015
02016
02017 if (relsym != EQUAL) {
02018
02019 if (modulus != 0)
02020 throw_invalid_argument("generalized_affine_preimage(v, r, e, d, m)",
02021 "r != EQUAL && m != 0");
02022
02023 if (!generators_are_up_to_date())
02024 minimize();
02025
02026
02027 if (marked_empty())
02028 return;
02029
02030 add_grid_generator(grid_line(var));
02031
02032 PPL_ASSERT(OK());
02033 return;
02034 }
02035
02036 PPL_ASSERT(relsym == EQUAL);
02037
02038 if (marked_empty())
02039 return;
02040
02041
02042 if (modulus == 0) {
02043 affine_preimage(var, expr, denominator);
02044 return;
02045 }
02046
02047
02048
02049 const Coefficient& var_coefficient = expr.coefficient(var);
02050 if (var_space_dim <= expr_space_dim && var_coefficient != 0) {
02051 Linear_Expression inverse_expr
02052 = expr - (denominator + var_coefficient) * var;
02053 PPL_DIRTY_TEMP_COEFFICIENT(inverse_denominator);
02054 neg_assign(inverse_denominator, var_coefficient);
02055 if (modulus < 0)
02056 generalized_affine_image(var, EQUAL, inverse_expr, inverse_denominator,
02057 - modulus);
02058 else
02059 generalized_affine_image(var, EQUAL, inverse_expr, inverse_denominator,
02060 modulus);
02061 return;
02062 }
02063
02064
02065
02066
02067 {
02068 Congruence cg((denominator*var %= expr) / denominator);
02069 if (modulus < 0)
02070 cg /= -modulus;
02071 else
02072 cg /= modulus;
02073 add_congruence_no_check(cg);
02074 }
02075
02076
02077
02078 if (is_empty())
02079 return;
02080 add_grid_generator(grid_line(var));
02081 PPL_ASSERT(OK());
02082 }
02083
02084 void
02085 PPL::Grid::
02086 generalized_affine_image(const Linear_Expression& lhs,
02087 const Relation_Symbol relsym,
02088 const Linear_Expression& rhs,
02089 Coefficient_traits::const_reference modulus) {
02090
02091
02092
02093 dimension_type lhs_space_dim = lhs.space_dimension();
02094 if (space_dim < lhs_space_dim)
02095 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
02096 "e1", lhs);
02097
02098
02099 const dimension_type rhs_space_dim = rhs.space_dimension();
02100 if (space_dim < rhs_space_dim)
02101 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
02102 "e2", rhs);
02103
02104
02105 if (marked_empty())
02106 return;
02107
02108
02109
02110 if (relsym != EQUAL) {
02111
02112 if (modulus != 0)
02113 throw_invalid_argument("generalized_affine_image(e1, r, e2, m)",
02114 "r != EQUAL && m != 0");
02115
02116 if (!generators_are_up_to_date())
02117 minimize();
02118
02119
02120 if (marked_empty())
02121 return;
02122
02123 for (dimension_type i = space_dim; i-- > 0; )
02124 if (lhs.coefficient(Variable(i)) != 0)
02125 add_grid_generator(grid_line(Variable(i)));
02126
02127 PPL_ASSERT(OK());
02128 return;
02129 }
02130
02131 PPL_ASSERT(relsym == EQUAL);
02132
02133 PPL_DIRTY_TEMP_COEFFICIENT(tmp_modulus);
02134 tmp_modulus = modulus;
02135 if (tmp_modulus < 0)
02136 neg_assign(tmp_modulus);
02137
02138
02139
02140 do {
02141 if (lhs_space_dim == 0) {
02142
02143 add_congruence_no_check((lhs %= rhs) / tmp_modulus);
02144 return;
02145 }
02146 }
02147 while (lhs.coefficient(Variable(--lhs_space_dim)) == 0);
02148
02149
02150
02151
02152
02153 Grid_Generator_System new_lines;
02154 bool lhs_vars_intersect_rhs_vars = false;
02155 for (dimension_type i = lhs_space_dim + 1; i-- > 0; )
02156 if (lhs.coefficient(Variable(i)) != 0) {
02157 new_lines.insert(grid_line(Variable(i)));
02158 if (rhs.coefficient(Variable(i)) != 0)
02159 lhs_vars_intersect_rhs_vars = true;
02160 }
02161
02162 if (lhs_vars_intersect_rhs_vars) {
02163
02164
02165 const Variable new_var = Variable(space_dim);
02166 add_space_dimensions_and_embed(1);
02167
02168
02169
02170 Congruence_System new_cgs1(new_var == rhs);
02171 add_recycled_congruences(new_cgs1);
02172 if (!is_empty()) {
02173
02174
02175
02176
02177
02178
02179 new_lines.insert(parameter(0*Variable(space_dim-1)));
02180
02181 update_generators();
02182 gen_sys.recycling_insert(new_lines);
02183 normalize_divisors(gen_sys);
02184
02185 clear_congruences_up_to_date();
02186 clear_generators_minimized();
02187
02188
02189
02190
02191 Congruence_System new_cgs2((lhs %= new_var) / tmp_modulus);
02192 add_recycled_congruences(new_cgs2);
02193 }
02194
02195
02196 remove_higher_space_dimensions(space_dim-1);
02197 }
02198 else {
02199
02200
02201
02202
02203 if (is_empty())
02204 return;
02205
02206
02207
02208 add_recycled_grid_generators(new_lines);
02209
02210
02211
02212 add_congruence_no_check((lhs %= rhs) / tmp_modulus);
02213 }
02214
02215 PPL_ASSERT(OK());
02216 }
02217
02218 void
02219 PPL::Grid::
02220 generalized_affine_preimage(const Linear_Expression& lhs,
02221 const Relation_Symbol relsym,
02222 const Linear_Expression& rhs,
02223 Coefficient_traits::const_reference modulus) {
02224
02225
02226 dimension_type lhs_space_dim = lhs.space_dimension();
02227 if (space_dim < lhs_space_dim)
02228 throw_dimension_incompatible("generalized_affine_preimage(e1, e2, m)",
02229 "lhs", lhs);
02230
02231 const dimension_type rhs_space_dim = rhs.space_dimension();
02232 if (space_dim < rhs_space_dim)
02233 throw_dimension_incompatible("generalized_affine_preimage(e1, e2, m)",
02234 "e2", rhs);
02235
02236
02237 if (marked_empty())
02238 return;
02239
02240
02241
02242 if (relsym != EQUAL) {
02243
02244 if (modulus != 0)
02245 throw_invalid_argument("generalized_affine_preimage(e1, r, e2, m)",
02246 "r != EQUAL && m != 0");
02247
02248 if (!generators_are_up_to_date())
02249 minimize();
02250
02251
02252 if (marked_empty())
02253 return;
02254
02255 for (dimension_type i = lhs_space_dim + 1; i-- > 0; )
02256 if (lhs.coefficient(Variable(i)) != 0)
02257 add_grid_generator(grid_line(Variable(i)));
02258
02259 PPL_ASSERT(OK());
02260 return;
02261 }
02262
02263 PPL_ASSERT(relsym == EQUAL);
02264
02265 PPL_DIRTY_TEMP_COEFFICIENT(tmp_modulus);
02266 tmp_modulus = modulus;
02267 if (tmp_modulus < 0)
02268 neg_assign(tmp_modulus);
02269
02270
02271
02272 do {
02273 if (lhs_space_dim == 0) {
02274
02275
02276 add_congruence_no_check((lhs %= rhs) / tmp_modulus);
02277 return;
02278 }
02279 }
02280 while (lhs.coefficient(Variable(--lhs_space_dim)) == 0);
02281
02282
02283
02284
02285
02286 Grid_Generator_System new_lines;
02287 bool lhs_vars_intersect_rhs_vars = false;
02288 for (dimension_type i = lhs_space_dim + 1; i-- > 0; )
02289 if (lhs.coefficient(Variable(i)) != 0) {
02290 new_lines.insert(grid_line(Variable(i)));
02291 if (rhs.coefficient(Variable(i)) != 0)
02292 lhs_vars_intersect_rhs_vars = true;
02293 }
02294
02295 if (lhs_vars_intersect_rhs_vars) {
02296
02297
02298 const Variable new_var = Variable(space_dim);
02299 add_space_dimensions_and_embed(1);
02300
02301
02302
02303 Congruence_System new_cgs1(new_var == lhs);
02304 add_recycled_congruences(new_cgs1);
02305 if (!is_empty()) {
02306
02307
02308
02309
02310
02311
02312 new_lines.insert(parameter(0*Variable(space_dim-1)));
02313
02314 update_generators();
02315 gen_sys.recycling_insert(new_lines);
02316 normalize_divisors(gen_sys);
02317
02318 clear_congruences_up_to_date();
02319 clear_generators_minimized();
02320
02321
02322
02323
02324 Congruence_System new_cgs2((rhs %= new_var) / tmp_modulus);
02325 add_recycled_congruences(new_cgs2);
02326 }
02327
02328
02329 remove_higher_space_dimensions(space_dim-1);
02330 }
02331 else {
02332
02333
02334
02335
02336
02337 add_congruence_no_check((lhs %= rhs) / tmp_modulus);
02338
02339
02340 if (is_empty())
02341 return;
02342
02343
02344 add_recycled_grid_generators(new_lines);
02345 }
02346 PPL_ASSERT(OK());
02347 }
02348
02349 void
02350 PPL::Grid::
02351 bounded_affine_image(const Variable var,
02352 const Linear_Expression& lb_expr,
02353 const Linear_Expression& ub_expr,
02354 Coefficient_traits::const_reference denominator) {
02355
02356
02357 if (denominator == 0)
02358 throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0");
02359
02360
02361
02362 const dimension_type var_space_dim = var.space_dimension();
02363 if (space_dim < var_space_dim)
02364 throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02365 "v", var);
02366
02367
02368 const dimension_type lb_space_dim = lb_expr.space_dimension();
02369 if (space_dim < lb_space_dim)
02370 throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
02371 "lb", lb_expr);
02372 const dimension_type ub_space_dim = ub_expr.space_dimension();
02373 if (space_dim < ub_space_dim)
02374 throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
02375 "ub", ub_expr);
02376
02377
02378 if (marked_empty())
02379 return;
02380
02381
02382
02383 generalized_affine_image(var,
02384 LESS_OR_EQUAL,
02385 ub_expr,
02386 denominator);
02387
02388 PPL_ASSERT(OK());
02389 }
02390
02391
02392 void
02393 PPL::Grid::
02394 bounded_affine_preimage(const Variable var,
02395 const Linear_Expression& lb_expr,
02396 const Linear_Expression& ub_expr,
02397 Coefficient_traits::const_reference denominator) {
02398
02399
02400 if (denominator == 0)
02401 throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
02402
02403
02404
02405 const dimension_type var_space_dim = var.space_dimension();
02406 if (space_dim < var_space_dim)
02407 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
02408 "v", var);
02409
02410
02411 const dimension_type lb_space_dim = lb_expr.space_dimension();
02412 if (space_dim < lb_space_dim)
02413 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
02414 "lb", lb_expr);
02415 const dimension_type ub_space_dim = ub_expr.space_dimension();
02416 if (space_dim < ub_space_dim)
02417 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
02418 "ub", ub_expr);
02419
02420
02421 if (marked_empty())
02422 return;
02423
02424
02425
02426 generalized_affine_preimage(var,
02427 LESS_OR_EQUAL,
02428 ub_expr,
02429 denominator);
02430
02431 PPL_ASSERT(OK());
02432 }
02433
02434 void
02435 PPL::Grid::time_elapse_assign(const Grid& y) {
02436 Grid& x = *this;
02437
02438 if (x.space_dim != y.space_dim)
02439 throw_dimension_incompatible("time_elapse_assign(y)", "y", y);
02440
02441
02442 if (x.space_dim == 0) {
02443 if (y.marked_empty())
02444 x.set_empty();
02445 return;
02446 }
02447
02448
02449 if (x.marked_empty())
02450 return;
02451 if (y.marked_empty()
02452 || (!x.generators_are_up_to_date() && !x.update_generators())
02453 || (!y.generators_are_up_to_date() && !y.update_generators())) {
02454 x.set_empty();
02455 return;
02456 }
02457
02458
02459 Grid_Generator_System gs = y.gen_sys;
02460 dimension_type gs_num_rows = gs.num_rows();
02461
02462 normalize_divisors(gs, gen_sys);
02463
02464 for (dimension_type i = gs_num_rows; i-- > 0; ) {
02465 Grid_Generator& g = gs[i];
02466 if (g.is_point())
02467
02468 g.set_is_parameter();
02469 }
02470
02471 if (gs_num_rows == 0)
02472
02473
02474 return;
02475
02476
02477
02478 gen_sys.recycling_insert(gs);
02479
02480 x.clear_congruences_up_to_date();
02481 x.clear_generators_minimized();
02482
02483 PPL_ASSERT(x.OK(true) && y.OK(true));
02484 }
02485
02486 bool
02487 PPL::Grid::frequency(const Linear_Expression& expr,
02488 Coefficient& freq_n, Coefficient& freq_d,
02489 Coefficient& val_n, Coefficient& val_d) const {
02490
02491 if (space_dim < expr.space_dimension())
02492 throw_dimension_incompatible("frequency(e, ...)", "e", expr);
02493
02494
02495
02496 if (space_dim == 0) {
02497 if (is_empty())
02498 return false;
02499 freq_n = 0;
02500 freq_d = 1;
02501 val_n = 0;
02502 val_d = 1;
02503 return true;
02504 }
02505 if (!generators_are_minimized() && !minimize())
02506
02507 return false;
02508
02509 return frequency_no_check(expr, freq_n, freq_d, val_n, val_d);
02510 }
02511
02513 bool
02514 PPL::operator==(const Grid& x, const Grid& y) {
02515 if (x.space_dim != y.space_dim)
02516 return false;
02517
02518 if (x.marked_empty())
02519 return y.is_empty();
02520 if (y.marked_empty())
02521 return x.is_empty();
02522 if (x.space_dim == 0)
02523 return true;
02524
02525 switch (x.quick_equivalence_test(y)) {
02526 case Grid::TVB_TRUE:
02527 return true;
02528
02529 case Grid::TVB_FALSE:
02530 return false;
02531
02532 default:
02533 if (x.is_included_in(y)) {
02534 if (x.marked_empty())
02535 return y.is_empty();
02536 return y.is_included_in(x);
02537 }
02538 return false;
02539 }
02540 }
02541
02542 bool
02543 PPL::Grid::contains(const Grid& y) const {
02544 const Grid& x = *this;
02545
02546
02547 if (x.space_dim != y.space_dim)
02548 throw_dimension_incompatible("contains(y)", "y", y);
02549
02550 if (y.marked_empty())
02551 return true;
02552 if (x.marked_empty())
02553 return y.is_empty();
02554 if (y.space_dim == 0)
02555 return true;
02556 if (x.quick_equivalence_test(y) == Grid::TVB_TRUE)
02557 return true;
02558 return y.is_included_in(x);
02559 }
02560
02561 bool
02562 PPL::Grid::is_disjoint_from(const Grid& y) const {
02563
02564 if (space_dim != y.space_dim)
02565 throw_dimension_incompatible("is_disjoint_from(y)", "y", y);
02566 Grid z = *this;
02567 z.intersection_assign(y);
02568 return z.is_empty();
02569 }
02570
02571 void
02572 PPL::Grid::ascii_dump(std::ostream& s) const {
02573 using std::endl;
02574
02575 s << "space_dim "
02576 << space_dim
02577 << endl;
02578 status.ascii_dump(s);
02579 s << "con_sys ("
02580 << (congruences_are_up_to_date() ? "" : "not_")
02581 << "up-to-date)"
02582 << endl;
02583 con_sys.ascii_dump(s);
02584 s << "gen_sys ("
02585 << (generators_are_up_to_date() ? "" : "not_")
02586 << "up-to-date)"
02587 << endl;
02588 gen_sys.ascii_dump(s);
02589 s << "dimension_kinds";
02590 if ((generators_are_up_to_date() && generators_are_minimized())
02591 || (congruences_are_up_to_date() && congruences_are_minimized()))
02592 for (Dimension_Kinds::const_iterator i = dim_kinds.begin();
02593 i != dim_kinds.end();
02594 ++i)
02595 s << " " << *i;
02596 s << endl;
02597 }
02598
02599 PPL_OUTPUT_DEFINITIONS(Grid)
02600
02601 bool
02602 PPL::Grid::ascii_load(std::istream& s) {
02603 std::string str;
02604
02605 if (!(s >> str) || str != "space_dim")
02606 return false;
02607
02608 if (!(s >> space_dim))
02609 return false;
02610
02611 if (!status.ascii_load(s))
02612 return false;
02613
02614 if (!(s >> str) || str != "con_sys")
02615 return false;
02616
02617 if (s >> str) {
02618 if (str == "(up-to-date)")
02619 set_congruences_up_to_date();
02620 else if (str != "(not_up-to-date)")
02621 return false;
02622 }
02623 else
02624 return false;
02625
02626 if (!con_sys.ascii_load(s))
02627 return false;
02628
02629 if (!(s >> str) || str != "gen_sys")
02630 return false;
02631
02632 if (s >> str) {
02633 if (str == "(up-to-date)")
02634 set_generators_up_to_date();
02635 else if (str != "(not_up-to-date)")
02636 return false;
02637 }
02638 else
02639 return false;
02640
02641 if (!gen_sys.ascii_load(s))
02642 return false;
02643
02644 if (!(s >> str) || str != "dimension_kinds")
02645 return false;
02646
02647 if (!marked_empty()
02648 && ((generators_are_up_to_date() && generators_are_minimized())
02649 || (congruences_are_up_to_date() && congruences_are_minimized()))) {
02650 dim_kinds.resize(space_dim + 1);
02651 for (Dimension_Kinds::size_type dim = 0; dim <= space_dim; ++dim) {
02652 short unsigned int dim_kind;
02653 if (!(s >> dim_kind))
02654 return false;
02655 switch(dim_kind) {
02656 case 0: dim_kinds[dim] = PARAMETER; break;
02657 case 1: dim_kinds[dim] = LINE; break;
02658 case 2: dim_kinds[dim] = GEN_VIRTUAL; break;
02659 default: return false;
02660 }
02661 }
02662 }
02663
02664
02665 PPL_ASSERT(OK());
02666 return true;
02667 }
02668
02669 PPL::memory_size_type
02670 PPL::Grid::external_memory_in_bytes() const {
02671 return
02672 con_sys.external_memory_in_bytes()
02673 + gen_sys.external_memory_in_bytes();
02674 }
02675
02676 void
02677 PPL::Grid::wrap_assign(const Variables_Set& vars,
02678 Bounded_Integer_Type_Width w,
02679 Bounded_Integer_Type_Representation r,
02680 Bounded_Integer_Type_Overflow o,
02681 const Constraint_System* pcs,
02682 unsigned ,
02683 bool ) {
02684
02685
02686 if (pcs != 0) {
02687 const dimension_type pcs_space_dim = pcs->space_dimension();
02688 if (pcs->space_dimension() > space_dim)
02689 throw_dimension_incompatible("wrap_assign(vs, ...)", pcs_space_dim);
02690 }
02691
02692
02693 if (vars.empty())
02694 return;
02695
02696
02697 const dimension_type min_space_dim = vars.space_dimension();
02698 if (space_dim < min_space_dim)
02699 throw_dimension_incompatible("wrap_assign(vs, ...)", min_space_dim);
02700
02701
02702 if (marked_empty())
02703 return;
02704 if (!generators_are_minimized() && !minimize())
02705
02706 return;
02707
02708
02709
02710 PPL_DIRTY_TEMP_COEFFICIENT(wrap_frequency);
02711 mul_2exp_assign(wrap_frequency, Coefficient_one(), w);
02712
02713
02714 PPL_DIRTY_TEMP_COEFFICIENT(min_value);
02715 PPL_DIRTY_TEMP_COEFFICIENT(max_value);
02716 if (r == UNSIGNED) {
02717 min_value = 0;
02718 mul_2exp_assign(max_value, Coefficient_one(), w);
02719 --max_value;
02720 }
02721 else {
02722 PPL_ASSERT(r == SIGNED_2_COMPLEMENT);
02723 mul_2exp_assign(max_value, Coefficient_one(), w-1);
02724 neg_assign(min_value, max_value);
02725 --max_value;
02726 }
02727
02728
02729 const Grid gr = *this;
02730
02731
02732 if (o == OVERFLOW_IMPOSSIBLE || o == OVERFLOW_WRAPS) {
02733 PPL_DIRTY_TEMP_COEFFICIENT(f_n);
02734 PPL_DIRTY_TEMP_COEFFICIENT(f_d);
02735 PPL_DIRTY_TEMP_COEFFICIENT(v_n);
02736 PPL_DIRTY_TEMP_COEFFICIENT(v_d);
02737 for (Variables_Set::const_iterator i = vars.begin(),
02738 vars_end = vars.end(); i != vars.end(); ++i) {
02739 const Variable x = Variable(*i);
02740
02741 if (!gr.frequency_no_check(x, f_n, f_d, v_n, v_d))
02742 continue;
02743 if (f_n == 0) {
02744
02745
02746 if (v_d != 1) {
02747
02748
02749 set_empty();
02750 return;
02751 }
02752
02753
02754 if ((v_n > max_value) || (v_n < min_value)) {
02755
02756 if (o == OVERFLOW_IMPOSSIBLE) {
02757
02758 set_empty();
02759 return;
02760 }
02761 PPL_ASSERT(o == OVERFLOW_WRAPS);
02762
02763 v_n %= wrap_frequency;
02764
02765 if (r == UNSIGNED && v_n < 0)
02766 v_n += wrap_frequency;
02767 unconstrain(x);
02768 add_constraint(x == v_n);
02769 }
02770 continue;
02771 }
02772
02773
02774 PPL_ASSERT(f_n != 0);
02775
02776 if (f_d % v_d != 0) {
02777
02778 set_empty();
02779 return;
02780 }
02781 if (f_d != 1) {
02782
02783
02784 add_congruence((x %= 0) / 1);
02785 }
02786 if (o == OVERFLOW_WRAPS && f_n != wrap_frequency)
02787
02788
02789 add_grid_generator(parameter(wrap_frequency * x));
02790 else if ((o == OVERFLOW_IMPOSSIBLE && 2*f_n >= wrap_frequency)
02791 || (f_n == wrap_frequency)) {
02792
02793
02794 if (r == UNSIGNED && v_n < 0) {
02795
02796 v_n += f_n;
02797 }
02798 unconstrain(x);
02799 add_constraint(x == v_n);
02800 }
02801 else {
02802
02803
02804
02805
02806 PPL_ASSERT(o == OVERFLOW_IMPOSSIBLE && 2*f_n < wrap_frequency);
02807 }
02808 }
02809 return;
02810 }
02811
02812 PPL_ASSERT(o == OVERFLOW_UNDEFINED);
02813
02814
02815 const Grid_Generator& point = gr.gen_sys[0];
02816 const Coefficient& div = point.divisor();
02817 max_value *= div;
02818 min_value *= div;
02819 for (Variables_Set::const_iterator i = vars.begin(),
02820 vars_end = vars.end(); i != vars.end(); ++i) {
02821 const Variable x = Variable(*i);
02822 if (!gr.bounds_no_check(x)) {
02823
02824
02825
02826 if (point.coefficient(x) % div != 0) {
02827
02828
02829 unconstrain(x);
02830 add_congruence(x %= 0);
02831 }
02832 else
02833
02834
02835
02836 add_grid_generator(parameter(x));
02837 }
02838 else {
02839
02840 const Coefficient& coeff_x = point.coefficient(x);
02841
02842 if (coeff_x % div != 0) {
02843 set_empty();
02844 return;
02845 }
02846
02847
02848
02849 if (coeff_x > max_value || coeff_x < min_value) {
02850 add_grid_generator(parameter(x));
02851 }
02852 }
02853 }
02854 }
02855
02856 void
02857 PPL::Grid::drop_some_non_integer_points(Complexity_Class) {
02858 if (marked_empty() || space_dim == 0)
02859 return;
02860
02861
02862
02863
02864
02865 for (dimension_type i = space_dim; i-- > 0; )
02866 add_congruence(Variable(i) %= 0);
02867
02868 PPL_ASSERT(OK());
02869 }
02870
02871 void
02872 PPL::Grid::drop_some_non_integer_points(const Variables_Set& vars,
02873 Complexity_Class) {
02874
02875 const dimension_type min_space_dim = vars.space_dimension();
02876 if (space_dimension() < min_space_dim)
02877 throw_dimension_incompatible("drop_some_non_integer_points(vs, cmpl)",
02878 min_space_dim);
02879
02880 if (marked_empty() || min_space_dim == 0)
02881 return;
02882
02883
02884
02885
02886
02887
02888 for (Variables_Set::const_iterator i = vars.begin(),
02889 vars_end = vars.end(); i != vars.end(); ++i)
02890 add_congruence(Variable(*i) %= 0);
02891
02892 PPL_ASSERT(OK());
02893 }
02894
02896 std::ostream&
02897 PPL::IO_Operators::operator<<(std::ostream& s, const Grid& gr) {
02898 if (gr.is_empty())
02899 s << "false";
02900 else if (gr.is_universe())
02901 s << "true";
02902 else
02903 s << gr.minimized_congruences();
02904 return s;
02905 }