00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef PPL_Box_templates_hh
00025 #define PPL_Box_templates_hh 1
00026
00027 #include "Variables_Set.defs.hh"
00028 #include "Constraint_System.defs.hh"
00029 #include "Constraint_System.inlines.hh"
00030 #include "Generator_System.defs.hh"
00031 #include "Generator_System.inlines.hh"
00032 #include "Poly_Con_Relation.defs.hh"
00033 #include "Poly_Gen_Relation.defs.hh"
00034 #include "Polyhedron.defs.hh"
00035 #include "Grid.defs.hh"
00036 #include "BD_Shape.defs.hh"
00037 #include "Octagonal_Shape.defs.hh"
00038 #include "MIP_Problem.defs.hh"
00039 #include "Rational_Interval.hh"
00040 #include <vector>
00041 #include <map>
00042 #include <iostream>
00043
00044 namespace Parma_Polyhedra_Library {
00045
00046 template <typename ITV>
00047 inline
00048 Box<ITV>::Box(dimension_type num_dimensions, Degenerate_Element kind)
00049 : seq(num_dimensions <= max_space_dimension()
00050 ? num_dimensions
00051 : (throw_space_dimension_overflow("Box(n, k)",
00052 "n exceeds the maximum "
00053 "allowed space dimension"),
00054 num_dimensions)),
00055 status() {
00056
00057
00058 if (kind == UNIVERSE) {
00059 for (dimension_type i = num_dimensions; i-- > 0; )
00060 seq[i].assign(UNIVERSE);
00061 set_empty_up_to_date();
00062 }
00063 else
00064 set_empty();
00065 PPL_ASSERT(OK());
00066 }
00067
00068 template <typename ITV>
00069 inline
00070 Box<ITV>::Box(const Constraint_System& cs)
00071 : seq(cs.space_dimension() <= max_space_dimension()
00072 ? cs.space_dimension()
00073 : (throw_space_dimension_overflow("Box(cs)",
00074 "cs exceeds the maximum "
00075 "allowed space dimension"),
00076 cs.space_dimension())),
00077 status() {
00078
00079 for (dimension_type i = cs.space_dimension(); i-- > 0; )
00080 seq[i].assign(UNIVERSE);
00081 add_constraints_no_check(cs);
00082 }
00083
00084 template <typename ITV>
00085 inline
00086 Box<ITV>::Box(const Congruence_System& cgs)
00087 : seq(cgs.space_dimension() <= max_space_dimension()
00088 ? cgs.space_dimension()
00089 : (throw_space_dimension_overflow("Box(cgs)",
00090 "cgs exceeds the maximum "
00091 "allowed space dimension"),
00092 cgs.space_dimension())),
00093 status() {
00094
00095 for (dimension_type i = cgs.space_dimension(); i-- > 0; )
00096 seq[i].assign(UNIVERSE);
00097 add_congruences_no_check(cgs);
00098 }
00099
00100 template <typename ITV>
00101 template <typename Other_ITV>
00102 inline
00103 Box<ITV>::Box(const Box<Other_ITV>& y, Complexity_Class)
00104 : seq(y.space_dimension()),
00105
00106
00107 status() {
00108
00109 if (y.marked_empty())
00110 set_empty();
00111
00112 if (!y.marked_empty())
00113 for (dimension_type k = y.space_dimension(); k-- > 0; )
00114 seq[k].assign(y.seq[k]);
00115 PPL_ASSERT(OK());
00116 }
00117
00118 template <typename ITV>
00119 Box<ITV>::Box(const Generator_System& gs)
00120 : seq(gs.space_dimension() <= max_space_dimension()
00121 ? gs.space_dimension()
00122 : (throw_space_dimension_overflow("Box(gs)",
00123 "gs exceeds the maximum "
00124 "allowed space dimension"),
00125 gs.space_dimension())),
00126 status() {
00127 const Generator_System::const_iterator gs_begin = gs.begin();
00128 const Generator_System::const_iterator gs_end = gs.end();
00129 if (gs_begin == gs_end) {
00130
00131 set_empty();
00132 return;
00133 }
00134
00135
00136 set_empty_up_to_date();
00137
00138 const dimension_type space_dim = space_dimension();
00139 PPL_DIRTY_TEMP(mpq_class, q);
00140 bool point_seen = false;
00141
00142 for (Generator_System::const_iterator
00143 gs_i = gs_begin; gs_i != gs_end; ++gs_i) {
00144 const Generator& g = *gs_i;
00145 if (g.is_point()) {
00146 const Coefficient& d = g.divisor();
00147 if (point_seen) {
00148
00149 for (dimension_type i = space_dim; i-- > 0; ) {
00150 assign_r(q.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED);
00151 assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
00152 q.canonicalize();
00153 PPL_DIRTY_TEMP(ITV, iq);
00154 iq.build(i_constraint(EQUAL, q));
00155 seq[i].join_assign(iq);
00156 }
00157 }
00158 else {
00159
00160 point_seen = true;
00161 for (dimension_type i = space_dim; i-- > 0; ) {
00162 assign_r(q.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED);
00163 assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
00164 q.canonicalize();
00165 seq[i].build(i_constraint(EQUAL, q));
00166 }
00167 }
00168 }
00169 }
00170
00171 if (!point_seen)
00172
00173 throw std::invalid_argument("PPL::Box<ITV>::Box(gs):\n"
00174 "the non-empty generator system gs "
00175 "contains no points.");
00176
00177
00178 ITV q_interval;
00179 for (Generator_System::const_iterator gs_i = gs_begin;
00180 gs_i != gs_end; ++gs_i) {
00181 const Generator& g = *gs_i;
00182 switch (g.type()) {
00183 case Generator::LINE:
00184 for (dimension_type i = space_dim; i-- > 0; )
00185 if (g.coefficient(Variable(i)) != 0)
00186 seq[i].assign(UNIVERSE);
00187 break;
00188 case Generator::RAY:
00189 for (dimension_type i = space_dim; i-- > 0; )
00190 switch (sgn(g.coefficient(Variable(i)))) {
00191 case 1:
00192 seq[i].upper_extend();
00193 break;
00194 case -1:
00195 seq[i].lower_extend();
00196 break;
00197 default:
00198 break;
00199 }
00200 break;
00201 case Generator::CLOSURE_POINT:
00202 {
00203 const Coefficient& d = g.divisor();
00204 for (dimension_type i = space_dim; i-- > 0; ) {
00205 assign_r(q.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED);
00206 assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
00207 q.canonicalize();
00208 ITV& seq_i = seq[i];
00209 seq_i.lower_extend(i_constraint(GREATER_THAN, q));
00210 seq_i.upper_extend(i_constraint(LESS_THAN, q));
00211 }
00212 }
00213 break;
00214 default:
00215
00216 break;
00217 }
00218 }
00219 PPL_ASSERT(OK());
00220 }
00221
00222 template <typename ITV>
00223 template <typename T>
00224 Box<ITV>::Box(const BD_Shape<T>& bds, Complexity_Class)
00225 : seq(bds.space_dimension() <= max_space_dimension()
00226 ? bds.space_dimension()
00227 : (throw_space_dimension_overflow("Box(bds)",
00228 "bds exceeds the maximum "
00229 "allowed space dimension"),
00230 bds.space_dimension())),
00231 status() {
00232
00233 bds.shortest_path_closure_assign();
00234 if (bds.marked_empty()) {
00235 set_empty();
00236 PPL_ASSERT(OK());
00237 return;
00238 }
00239
00240
00241 set_empty_up_to_date();
00242
00243 const dimension_type space_dim = space_dimension();
00244 if (space_dim == 0) {
00245 PPL_ASSERT(OK());
00246 return;
00247 }
00248
00249 typedef typename BD_Shape<T>::coefficient_type Coeff;
00250 PPL_DIRTY_TEMP(Coeff, tmp);
00251 const DB_Row<Coeff>& dbm_0 = bds.dbm[0];
00252 for (dimension_type i = space_dim; i-- > 0; ) {
00253 I_Constraint<Coeff> lower;
00254 I_Constraint<Coeff> upper;
00255 ITV& seq_i = seq[i];
00256
00257
00258 const Coeff& u = dbm_0[i+1];
00259 if (!is_plus_infinity(u))
00260 upper.set(LESS_OR_EQUAL, u, true);
00261
00262
00263 const Coeff& negated_l = bds.dbm[i+1][0];
00264 if (!is_plus_infinity(negated_l)) {
00265 neg_assign_r(tmp, negated_l, ROUND_DOWN);
00266 lower.set(GREATER_OR_EQUAL, tmp);
00267 }
00268
00269 seq_i.build(lower, upper);
00270 }
00271 PPL_ASSERT(OK());
00272 }
00273
00274 template <typename ITV>
00275 template <typename T>
00276 Box<ITV>::Box(const Octagonal_Shape<T>& oct, Complexity_Class)
00277 : seq(oct.space_dimension() <= max_space_dimension()
00278 ? oct.space_dimension()
00279 : (throw_space_dimension_overflow("Box(oct)",
00280 "oct exceeds the maximum "
00281 "allowed space dimension"),
00282 oct.space_dimension())),
00283 status() {
00284
00285 oct.strong_closure_assign();
00286 if (oct.marked_empty()) {
00287 set_empty();
00288 return;
00289 }
00290
00291
00292 set_empty_up_to_date();
00293
00294 const dimension_type space_dim = space_dimension();
00295 if (space_dim == 0)
00296 return;
00297
00298 PPL_DIRTY_TEMP0(mpq_class, lbound);
00299 PPL_DIRTY_TEMP0(mpq_class, ubound);
00300 for (dimension_type i = space_dim; i-- > 0; ) {
00301 typedef typename Octagonal_Shape<T>::coefficient_type Coeff;
00302 I_Constraint<mpq_class> lower;
00303 I_Constraint<mpq_class> upper;
00304 ITV& seq_i = seq[i];
00305 const dimension_type ii = 2*i;
00306 const dimension_type cii = ii + 1;
00307
00308
00309 const Coeff& twice_ub = oct.matrix[cii][ii];
00310 if (!is_plus_infinity(twice_ub)) {
00311 assign_r(ubound, twice_ub, ROUND_NOT_NEEDED);
00312 div_2exp_assign_r(ubound, ubound, 1, ROUND_NOT_NEEDED);
00313 upper.set(LESS_OR_EQUAL, ubound);
00314 }
00315
00316
00317 const Coeff& twice_lb = oct.matrix[ii][cii];
00318 if (!is_plus_infinity(twice_lb)) {
00319 assign_r(lbound, twice_lb, ROUND_NOT_NEEDED);
00320 neg_assign_r(lbound, lbound, ROUND_NOT_NEEDED);
00321 div_2exp_assign_r(lbound, lbound, 1, ROUND_NOT_NEEDED);
00322 lower.set(GREATER_OR_EQUAL, lbound);
00323 }
00324 seq_i.build(lower, upper);
00325 }
00326 }
00327
00328 template <typename ITV>
00329 Box<ITV>::Box(const Polyhedron& ph, Complexity_Class complexity)
00330 : seq(ph.space_dimension() <= max_space_dimension()
00331 ? ph.space_dimension()
00332 : (throw_space_dimension_overflow("Box(ph)",
00333 "ph exceeds the maximum "
00334 "allowed space dimension"),
00335 ph.space_dimension())),
00336 status() {
00337
00338 set_empty_up_to_date();
00339
00340
00341
00342 if (ph.marked_empty()) {
00343 set_empty();
00344 return;
00345 }
00346
00347
00348 const dimension_type space_dim = ph.space_dimension();
00349 if (space_dim == 0)
00350 return;
00351
00352
00353 if (ph.generators_are_up_to_date() && !ph.has_pending_constraints()) {
00354 Box tmp(ph.generators());
00355 swap(tmp);
00356 return;
00357 }
00358
00359
00360 PPL_ASSERT(ph.constraints_are_up_to_date());
00361
00362 if (complexity == POLYNOMIAL_COMPLEXITY) {
00363
00364 for (dimension_type i = space_dim; i-- > 0; )
00365 seq[i].assign(UNIVERSE);
00366
00367 Constraint_System cs = ph.simplified_constraints();
00368
00369
00370
00371 const dimension_type max_iterations = 20;
00372 propagate_constraints_no_check(cs, max_iterations);
00373 }
00374 else if (complexity == SIMPLEX_COMPLEXITY) {
00375 MIP_Problem lp(space_dim);
00376 const Constraint_System& ph_cs = ph.constraints();
00377 if (!ph_cs.has_strict_inequalities())
00378 lp.add_constraints(ph_cs);
00379 else
00380
00381 for (Constraint_System::const_iterator i = ph_cs.begin(),
00382 ph_cs_end = ph_cs.end(); i != ph_cs_end; ++i) {
00383 const Constraint& c = *i;
00384 if (c.is_strict_inequality())
00385 lp.add_constraint(Linear_Expression(c) >= 0);
00386 else
00387 lp.add_constraint(c);
00388 }
00389
00390 if (!lp.is_satisfiable()) {
00391 set_empty();
00392 return;
00393 }
00394
00395 Generator g(point());
00396 PPL_DIRTY_TEMP0(mpq_class, lbound);
00397 PPL_DIRTY_TEMP0(mpq_class, ubound);
00398 PPL_DIRTY_TEMP(Coefficient, bound_num);
00399 PPL_DIRTY_TEMP(Coefficient, bound_den);
00400 for (dimension_type i = space_dim; i-- > 0; ) {
00401 I_Constraint<mpq_class> lower;
00402 I_Constraint<mpq_class> upper;
00403 ITV& seq_i = seq[i];
00404 lp.set_objective_function(Variable(i));
00405
00406 lp.set_optimization_mode(MAXIMIZATION);
00407 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
00408 g = lp.optimizing_point();
00409 lp.evaluate_objective_function(g, bound_num, bound_den);
00410 assign_r(ubound.get_num(), bound_num, ROUND_NOT_NEEDED);
00411 assign_r(ubound.get_den(), bound_den, ROUND_NOT_NEEDED);
00412 PPL_ASSERT(is_canonical(ubound));
00413 upper.set(LESS_OR_EQUAL, ubound);
00414 }
00415
00416 lp.set_optimization_mode(MINIMIZATION);
00417 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
00418 g = lp.optimizing_point();
00419 lp.evaluate_objective_function(g, bound_num, bound_den);
00420 assign_r(lbound.get_num(), bound_num, ROUND_NOT_NEEDED);
00421 assign_r(lbound.get_den(), bound_den, ROUND_NOT_NEEDED);
00422 PPL_ASSERT(is_canonical(lbound));
00423 lower.set(GREATER_OR_EQUAL, lbound);
00424 }
00425 seq_i.build(lower, upper);
00426 }
00427 }
00428 else {
00429 PPL_ASSERT(complexity == ANY_COMPLEXITY);
00430 if (ph.is_empty())
00431 set_empty();
00432 else {
00433 Box tmp(ph.generators());
00434 swap(tmp);
00435 }
00436 }
00437 }
00438
00439 template <typename ITV>
00440 Box<ITV>::Box(const Grid& gr, Complexity_Class)
00441 : seq(gr.space_dimension() <= max_space_dimension()
00442 ? gr.space_dimension()
00443 : (throw_space_dimension_overflow("Box(gr)",
00444 "gr exceeds the maximum "
00445 "allowed space dimension"),
00446 gr.space_dimension())),
00447 status() {
00448
00449
00450
00451 if (gr.marked_empty()) {
00452 set_empty();
00453 return;
00454 }
00455
00456
00457 set_empty_up_to_date();
00458
00459 const dimension_type space_dim = gr.space_dimension();
00460
00461 if (space_dim == 0)
00462 return;
00463
00464 if (!gr.generators_are_up_to_date() && !gr.update_generators()) {
00465
00466 set_empty();
00467 return;
00468 }
00469
00470 PPL_ASSERT(!gr.gen_sys.empty());
00471
00472
00473
00474
00475 PPL_DIRTY_TEMP0(mpq_class, bound);
00476 PPL_DIRTY_TEMP(Coefficient, bound_num);
00477 PPL_DIRTY_TEMP(Coefficient, bound_den);
00478 for (dimension_type i = space_dim; i-- > 0; ) {
00479 ITV& seq_i = seq[i];
00480 Variable var(i);
00481 bool max;
00482 if (gr.maximize(var, bound_num, bound_den, max)) {
00483 assign_r(bound.get_num(), bound_num, ROUND_NOT_NEEDED);
00484 assign_r(bound.get_den(), bound_den, ROUND_NOT_NEEDED);
00485 bound.canonicalize();
00486 seq_i.build(i_constraint(EQUAL, bound));
00487 }
00488 else
00489 seq_i.assign(UNIVERSE);
00490 }
00491 }
00492
00493 template <typename ITV>
00494 template <typename D1, typename D2, typename R>
00495 Box<ITV>::Box(const Partially_Reduced_Product<D1, D2, R>& dp,
00496 Complexity_Class complexity)
00497 : seq(), status() {
00498 if (dp.space_dimension() > max_space_dimension())
00499 throw_space_dimension_overflow("Box(dp)",
00500 "dp exceeds the maximum "
00501 "allowed space dimension");
00502 Box tmp1(dp.domain1(), complexity);
00503 Box tmp2(dp.domain2(), complexity);
00504 tmp1.intersection_assign(tmp2);
00505 swap(tmp1);
00506 }
00507
00508 template <typename ITV>
00509 inline void
00510 Box<ITV>::add_space_dimensions_and_embed(const dimension_type m) {
00511
00512 if (m == 0)
00513 return;
00514
00515
00516 seq.insert(seq.end(), m, ITV(UNIVERSE));
00517 PPL_ASSERT(OK());
00518 }
00519
00520 template <typename ITV>
00521 inline void
00522 Box<ITV>::add_space_dimensions_and_project(const dimension_type m) {
00523
00524 if (m == 0)
00525 return;
00526
00527 seq.insert(seq.end(), m, ITV(0));
00528 PPL_ASSERT(OK());
00529 }
00530
00531 template <typename ITV>
00532 bool
00533 operator==(const Box<ITV>& x, const Box<ITV>& y) {
00534 const dimension_type x_space_dim = x.space_dimension();
00535 if (x_space_dim != y.space_dimension())
00536 return false;
00537
00538 if (x.is_empty())
00539 return y.is_empty();
00540
00541 if (y.is_empty())
00542 return x.is_empty();
00543
00544 for (dimension_type k = x_space_dim; k-- > 0; )
00545 if (x.seq[k] != y.seq[k])
00546 return false;
00547 return true;
00548 }
00549
00550 template <typename ITV>
00551 bool
00552 Box<ITV>::bounds(const Linear_Expression& expr, const bool from_above) const {
00553
00554 const dimension_type expr_space_dim = expr.space_dimension();
00555 const dimension_type space_dim = space_dimension();
00556 if (space_dim < expr_space_dim)
00557 throw_dimension_incompatible((from_above
00558 ? "bounds_from_above(e)"
00559 : "bounds_from_below(e)"), "e", expr);
00560
00561 if (space_dim == 0 || is_empty())
00562 return true;
00563
00564 const int from_above_sign = from_above ? 1 : -1;
00565 for (dimension_type i = expr_space_dim; i-- > 0; )
00566 switch (sgn(expr.coefficient(Variable(i))) * from_above_sign) {
00567 case 1:
00568 if (seq[i].upper_is_boundary_infinity())
00569 return false;
00570 break;
00571 case 0:
00572
00573 break;
00574 case -1:
00575 if (seq[i].lower_is_boundary_infinity())
00576 return false;
00577 break;
00578 }
00579 return true;
00580 }
00581
00582 template <typename ITV>
00583 Poly_Con_Relation
00584 interval_relation(const ITV& i,
00585 const Constraint::Type constraint_type,
00586 Coefficient_traits::const_reference num,
00587 Coefficient_traits::const_reference den) {
00588
00589 if (i.is_universe())
00590 return Poly_Con_Relation::strictly_intersects();
00591
00592 PPL_DIRTY_TEMP0(mpq_class, bound);
00593 assign_r(bound.get_num(), num, ROUND_NOT_NEEDED);
00594 assign_r(bound.get_den(), den, ROUND_NOT_NEEDED);
00595 bound.canonicalize();
00596 neg_assign_r(bound, bound, ROUND_NOT_NEEDED);
00597 const bool is_lower_bound = (den > 0);
00598
00599 PPL_DIRTY_TEMP0(mpq_class, bound_diff);
00600 if (constraint_type == Constraint::EQUALITY) {
00601 if (i.lower_is_boundary_infinity()) {
00602 PPL_ASSERT(!i.upper_is_boundary_infinity());
00603 assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
00604 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
00605 switch (sgn(bound_diff)) {
00606 case 1:
00607 return Poly_Con_Relation::strictly_intersects();
00608 case 0:
00609 return i.upper_is_open()
00610 ? Poly_Con_Relation::is_disjoint()
00611 : Poly_Con_Relation::strictly_intersects();
00612 case -1:
00613 return Poly_Con_Relation::is_disjoint();
00614 }
00615 }
00616 else {
00617 assign_r(bound_diff, i.lower(), ROUND_NOT_NEEDED);
00618 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
00619 switch (sgn(bound_diff)) {
00620 case 1:
00621 return Poly_Con_Relation::is_disjoint();
00622 case 0:
00623 if (i.lower_is_open())
00624 return Poly_Con_Relation::is_disjoint();
00625 if (i.is_singleton())
00626 return Poly_Con_Relation::is_included()
00627 && Poly_Con_Relation::saturates();
00628 return Poly_Con_Relation::strictly_intersects();
00629 case -1:
00630 if (i.upper_is_boundary_infinity())
00631 return Poly_Con_Relation::strictly_intersects();
00632 else {
00633 assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
00634 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
00635 switch (sgn(bound_diff)) {
00636 case 1:
00637 return Poly_Con_Relation::strictly_intersects();
00638 case 0:
00639 if (i.upper_is_open())
00640 return Poly_Con_Relation::is_disjoint();
00641 else
00642 return Poly_Con_Relation::strictly_intersects();
00643 case -1:
00644 return Poly_Con_Relation::is_disjoint();
00645 }
00646 }
00647 }
00648 }
00649 }
00650
00651 PPL_ASSERT(constraint_type != Constraint::EQUALITY);
00652 if (is_lower_bound) {
00653 if (i.lower_is_boundary_infinity()) {
00654 PPL_ASSERT(!i.upper_is_boundary_infinity());
00655 assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
00656 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
00657 switch (sgn(bound_diff)) {
00658 case 1:
00659 return Poly_Con_Relation::strictly_intersects();
00660 case 0:
00661 if (constraint_type == Constraint::STRICT_INEQUALITY
00662 || i.upper_is_open())
00663 return Poly_Con_Relation::is_disjoint();
00664 else
00665 return Poly_Con_Relation::strictly_intersects();
00666 case -1:
00667 return Poly_Con_Relation::is_disjoint();
00668 }
00669 }
00670 else {
00671 assign_r(bound_diff, i.lower(), ROUND_NOT_NEEDED);
00672 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
00673 switch (sgn(bound_diff)) {
00674 case 1:
00675 return Poly_Con_Relation::is_included();
00676 case 0:
00677 if (constraint_type == Constraint::NONSTRICT_INEQUALITY
00678 || i.lower_is_open()) {
00679 Poly_Con_Relation result = Poly_Con_Relation::is_included();
00680 if (i.is_singleton())
00681 result = result && Poly_Con_Relation::saturates();
00682 return result;
00683 }
00684 else {
00685 PPL_ASSERT(constraint_type == Constraint::STRICT_INEQUALITY
00686 && !i.lower_is_open());
00687 if (i.is_singleton())
00688 return Poly_Con_Relation::is_disjoint()
00689 && Poly_Con_Relation::saturates();
00690 else
00691 return Poly_Con_Relation::strictly_intersects();
00692 }
00693 case -1:
00694 if (i.upper_is_boundary_infinity())
00695 return Poly_Con_Relation::strictly_intersects();
00696 else {
00697 assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
00698 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
00699 switch (sgn(bound_diff)) {
00700 case 1:
00701 return Poly_Con_Relation::strictly_intersects();
00702 case 0:
00703 if (constraint_type == Constraint::STRICT_INEQUALITY
00704 || i.upper_is_open())
00705 return Poly_Con_Relation::is_disjoint();
00706 else
00707 return Poly_Con_Relation::strictly_intersects();
00708 case -1:
00709 return Poly_Con_Relation::is_disjoint();
00710 }
00711 }
00712 }
00713 }
00714 }
00715 else {
00716
00717 if (i.upper_is_boundary_infinity())
00718 return Poly_Con_Relation::strictly_intersects();
00719 else {
00720 assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
00721 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
00722 switch (sgn(bound_diff)) {
00723 case -1:
00724 return Poly_Con_Relation::is_included();
00725 case 0:
00726 if (constraint_type == Constraint::NONSTRICT_INEQUALITY
00727 || i.upper_is_open()) {
00728 Poly_Con_Relation result = Poly_Con_Relation::is_included();
00729 if (i.is_singleton())
00730 result = result && Poly_Con_Relation::saturates();
00731 return result;
00732 }
00733 else {
00734 PPL_ASSERT(constraint_type == Constraint::STRICT_INEQUALITY
00735 && !i.upper_is_open());
00736 if (i.is_singleton())
00737 return Poly_Con_Relation::is_disjoint()
00738 && Poly_Con_Relation::saturates();
00739 else
00740 return Poly_Con_Relation::strictly_intersects();
00741 }
00742 case 1:
00743 if (i.lower_is_boundary_infinity())
00744 return Poly_Con_Relation::strictly_intersects();
00745 else {
00746 assign_r(bound_diff, i.lower(), ROUND_NOT_NEEDED);
00747 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
00748 switch (sgn(bound_diff)) {
00749 case -1:
00750 return Poly_Con_Relation::strictly_intersects();
00751 case 0:
00752 if (constraint_type == Constraint::STRICT_INEQUALITY
00753 || i.lower_is_open())
00754 return Poly_Con_Relation::is_disjoint();
00755 else
00756 return Poly_Con_Relation::strictly_intersects();
00757 case 1:
00758 return Poly_Con_Relation::is_disjoint();
00759 }
00760 }
00761 }
00762 }
00763 }
00764
00765
00766 throw std::runtime_error("PPL internal error");
00767 }
00768
00769 template <typename ITV>
00770 Poly_Con_Relation
00771 Box<ITV>::relation_with(const Congruence& cg) const {
00772 const dimension_type cg_space_dim = cg.space_dimension();
00773 const dimension_type space_dim = space_dimension();
00774
00775
00776 if (cg_space_dim > space_dim)
00777 throw_dimension_incompatible("relation_with(cg)", cg);
00778
00779 if (is_empty())
00780 return Poly_Con_Relation::saturates()
00781 && Poly_Con_Relation::is_included()
00782 && Poly_Con_Relation::is_disjoint();
00783
00784 if (space_dim == 0) {
00785 if (cg.is_inconsistent())
00786 return Poly_Con_Relation::is_disjoint();
00787 else
00788 return Poly_Con_Relation::saturates()
00789 && Poly_Con_Relation::is_included();
00790 }
00791
00792 if (cg.is_equality()) {
00793 const Constraint c(cg);
00794 return relation_with(c);
00795 }
00796
00797 PPL_DIRTY_TEMP0(Rational_Interval, r);
00798 PPL_DIRTY_TEMP0(Rational_Interval, t);
00799 PPL_DIRTY_TEMP0(mpq_class, m);
00800 r = 0;
00801 for (dimension_type i = cg.space_dimension(); i-- > 0; ) {
00802 const Coefficient& cg_i = cg.coefficient(Variable(i));
00803 if (sgn(cg_i) != 0) {
00804 assign_r(m, cg_i, ROUND_NOT_NEEDED);
00805
00806 t.build(seq[i].lower_constraint(), seq[i].upper_constraint());
00807 t *= m;
00808 r += t;
00809 }
00810 }
00811
00812 if (r.lower_is_boundary_infinity() || r.upper_is_boundary_infinity())
00813 return Poly_Con_Relation::strictly_intersects();
00814
00815
00816
00817
00818
00819 PPL_DIRTY_TEMP_COEFFICIENT(lower);
00820 PPL_DIRTY_TEMP_COEFFICIENT(mod);
00821 PPL_DIRTY_TEMP_COEFFICIENT(v);
00822 mod = cg.modulus();
00823 v = cg.inhomogeneous_term() % mod;
00824 assign_r(lower, r.lower(), ROUND_DOWN);
00825 v -= ((lower / mod) * mod);
00826 if (v + lower > 0)
00827 v -= mod;
00828 return interval_relation(r, Constraint::EQUALITY, v);
00829 }
00830
00831 template <typename ITV>
00832 Poly_Con_Relation
00833 Box<ITV>::relation_with(const Constraint& c) const {
00834 const dimension_type c_space_dim = c.space_dimension();
00835 const dimension_type space_dim = space_dimension();
00836
00837
00838 if (c_space_dim > space_dim)
00839 throw_dimension_incompatible("relation_with(c)", c);
00840
00841 if (is_empty())
00842 return Poly_Con_Relation::saturates()
00843 && Poly_Con_Relation::is_included()
00844 && Poly_Con_Relation::is_disjoint();
00845
00846 if (space_dim == 0) {
00847 if ((c.is_equality() && c.inhomogeneous_term() != 0)
00848 || (c.is_inequality() && c.inhomogeneous_term() < 0))
00849 return Poly_Con_Relation::is_disjoint();
00850 else if (c.is_strict_inequality() && c.inhomogeneous_term() == 0)
00851
00852
00853 return Poly_Con_Relation::saturates()
00854 && Poly_Con_Relation::is_disjoint();
00855 else if (c.is_equality() || c.inhomogeneous_term() == 0)
00856 return Poly_Con_Relation::saturates()
00857 && Poly_Con_Relation::is_included();
00858 else
00859
00860
00861
00862 return Poly_Con_Relation::is_included();
00863 }
00864
00865 dimension_type c_num_vars = 0;
00866 dimension_type c_only_var = 0;
00867
00868 if (extract_interval_constraint(c, c_space_dim, c_num_vars, c_only_var))
00869 if (c_num_vars == 0)
00870
00871 switch (sgn(c.inhomogeneous_term())) {
00872 case -1:
00873 return Poly_Con_Relation::is_disjoint();
00874 case 0:
00875 if (c.is_strict_inequality())
00876 return Poly_Con_Relation::saturates()
00877 && Poly_Con_Relation::is_disjoint();
00878 else
00879 return Poly_Con_Relation::saturates()
00880 && Poly_Con_Relation::is_included();
00881 case 1:
00882 return Poly_Con_Relation::is_included();
00883 }
00884 else {
00885
00886 return interval_relation(seq[c_only_var],
00887 c.type(),
00888 c.inhomogeneous_term(),
00889 c.coefficient(Variable(c_only_var)));
00890 }
00891 else {
00892
00893 PPL_DIRTY_TEMP0(Rational_Interval, r);
00894 PPL_DIRTY_TEMP0(Rational_Interval, t);
00895 PPL_DIRTY_TEMP0(mpq_class, m);
00896 r = 0;
00897 for (dimension_type i = c.space_dimension(); i-- > 0; ) {
00898 const Coefficient& c_i = c.coefficient(Variable(i));
00899 if (sgn(c_i) != 0) {
00900 assign_r(m, c_i, ROUND_NOT_NEEDED);
00901
00902 t.build(seq[i].lower_constraint(), seq[i].upper_constraint());
00903 t *= m;
00904 r += t;
00905 }
00906 }
00907 return interval_relation(r,
00908 c.type(),
00909 c.inhomogeneous_term());
00910 }
00911
00912
00913 throw std::runtime_error("PPL internal error");
00914 }
00915
00916 template <typename ITV>
00917 Poly_Gen_Relation
00918 Box<ITV>::relation_with(const Generator& g) const {
00919 const dimension_type space_dim = space_dimension();
00920 const dimension_type g_space_dim = g.space_dimension();
00921
00922
00923 if (space_dim < g_space_dim)
00924 throw_dimension_incompatible("relation_with(g)", g);
00925
00926
00927 if (is_empty())
00928 return Poly_Gen_Relation::nothing();
00929
00930
00931
00932 if (space_dim == 0)
00933 return Poly_Gen_Relation::subsumes();
00934
00935 if (g.is_line_or_ray()) {
00936 if (g.is_line()) {
00937 for (dimension_type i = g_space_dim; i-- > 0; )
00938 if (g.coefficient(Variable(i)) != 0 && !seq[i].is_universe())
00939 return Poly_Gen_Relation::nothing();
00940 return Poly_Gen_Relation::subsumes();
00941 }
00942 else {
00943 PPL_ASSERT(g.is_ray());
00944 for (dimension_type i = g_space_dim; i-- > 0; )
00945 switch (sgn(g.coefficient(Variable(i)))) {
00946 case 1:
00947 if (!seq[i].upper_is_boundary_infinity())
00948 return Poly_Gen_Relation::nothing();
00949 break;
00950 case 0:
00951 break;
00952 case -1:
00953 if (!seq[i].lower_is_boundary_infinity())
00954 return Poly_Gen_Relation::nothing();
00955 break;
00956 }
00957 return Poly_Gen_Relation::subsumes();
00958 }
00959 }
00960
00961
00962 const Coefficient& g_divisor = g.divisor();
00963 PPL_DIRTY_TEMP0(mpq_class, g_coord);
00964 PPL_DIRTY_TEMP0(mpq_class, bound);
00965 for (dimension_type i = g_space_dim; i-- > 0; ) {
00966 const ITV& seq_i = seq[i];
00967 if (seq_i.is_universe())
00968 continue;
00969 assign_r(g_coord.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED);
00970 assign_r(g_coord.get_den(), g_divisor, ROUND_NOT_NEEDED);
00971 g_coord.canonicalize();
00972
00973 if (!seq_i.lower_is_boundary_infinity()) {
00974 assign_r(bound, seq_i.lower(), ROUND_NOT_NEEDED);
00975 if (g_coord <= bound) {
00976 if (seq_i.lower_is_open()) {
00977 if (g.is_point() || g_coord != bound)
00978 return Poly_Gen_Relation::nothing();
00979 }
00980 else if (g_coord != bound)
00981 return Poly_Gen_Relation::nothing();
00982 }
00983 }
00984
00985 if (!seq_i.upper_is_boundary_infinity()) {
00986 assign_r(bound, seq_i.upper(), ROUND_NOT_NEEDED);
00987 if (g_coord >= bound) {
00988 if (seq_i.upper_is_open()) {
00989 if (g.is_point() || g_coord != bound)
00990 return Poly_Gen_Relation::nothing();
00991 }
00992 else if (g_coord != bound)
00993 return Poly_Gen_Relation::nothing();
00994 }
00995 }
00996 }
00997 return Poly_Gen_Relation::subsumes();
00998 }
00999
01000
01001 template <typename ITV>
01002 bool
01003 Box<ITV>::max_min(const Linear_Expression& expr,
01004 const bool maximize,
01005 Coefficient& ext_n, Coefficient& ext_d,
01006 bool& included) const {
01007
01008 const dimension_type space_dim = space_dimension();
01009 const dimension_type expr_space_dim = expr.space_dimension();
01010 if (space_dim < expr_space_dim)
01011 throw_dimension_incompatible((maximize
01012 ? "maximize(e, ...)"
01013 : "minimize(e, ...)"), "e", expr);
01014
01015 if (space_dim == 0) {
01016 if (marked_empty())
01017 return false;
01018 else {
01019 ext_n = expr.inhomogeneous_term();
01020 ext_d = 1;
01021 included = true;
01022 return true;
01023 }
01024 }
01025
01026
01027 if (is_empty())
01028 return false;
01029
01030 PPL_DIRTY_TEMP0(mpq_class, result);
01031 assign_r(result, expr.inhomogeneous_term(), ROUND_NOT_NEEDED);
01032 bool is_included = true;
01033 const int maximize_sign = maximize ? 1 : -1;
01034 PPL_DIRTY_TEMP0(mpq_class, bound_i);
01035 PPL_DIRTY_TEMP0(mpq_class, expr_i);
01036 for (dimension_type i = expr_space_dim; i-- > 0; ) {
01037 const ITV& seq_i = seq[i];
01038 assign_r(expr_i, expr.coefficient(Variable(i)), ROUND_NOT_NEEDED);
01039 switch (sgn(expr_i) * maximize_sign) {
01040 case 1:
01041 if (seq_i.upper_is_boundary_infinity())
01042 return false;
01043 assign_r(bound_i, seq_i.upper(), ROUND_NOT_NEEDED);
01044 add_mul_assign_r(result, bound_i, expr_i, ROUND_NOT_NEEDED);
01045 if (seq_i.upper_is_open())
01046 is_included = false;
01047 break;
01048 case 0:
01049
01050 break;
01051 case -1:
01052 if (seq_i.lower_is_boundary_infinity())
01053 return false;
01054 assign_r(bound_i, seq_i.lower(), ROUND_NOT_NEEDED);
01055 add_mul_assign_r(result, bound_i, expr_i, ROUND_NOT_NEEDED);
01056 if (seq_i.lower_is_open())
01057 is_included = false;
01058 break;
01059 }
01060 }
01061
01062 PPL_ASSERT(is_canonical(result));
01063 ext_n = result.get_num();
01064 ext_d = result.get_den();
01065 included = is_included;
01066 return true;
01067 }
01068
01069 template <typename ITV>
01070 bool
01071 Box<ITV>::max_min(const Linear_Expression& expr,
01072 const bool maximize,
01073 Coefficient& ext_n, Coefficient& ext_d,
01074 bool& included,
01075 Generator& g) const {
01076 if (!max_min(expr, maximize, ext_n, ext_d, included))
01077 return false;
01078
01079
01080 Linear_Expression g_expr;
01081 PPL_DIRTY_TEMP(Coefficient, g_divisor);
01082 g_divisor = 1;
01083 const int maximize_sign = maximize ? 1 : -1;
01084 PPL_DIRTY_TEMP0(mpq_class, g_coord);
01085 PPL_DIRTY_TEMP(Coefficient, num);
01086 PPL_DIRTY_TEMP(Coefficient, den);
01087 PPL_DIRTY_TEMP(Coefficient, lcm);
01088 PPL_DIRTY_TEMP(Coefficient, factor);
01089 for (dimension_type i = space_dimension(); i-- > 0; ) {
01090 const ITV& seq_i = seq[i];
01091 switch (sgn(expr.coefficient(Variable(i))) * maximize_sign) {
01092 case 1:
01093 assign_r(g_coord, seq_i.upper(), ROUND_NOT_NEEDED);
01094 break;
01095 case 0:
01096
01097
01098
01099 if (seq_i.contains(0))
01100 continue;
01101 if (!seq_i.lower_is_boundary_infinity())
01102 if (seq_i.lower_is_open())
01103 if (!seq_i.upper_is_boundary_infinity())
01104 if (seq_i.upper_is_open()) {
01105
01106 assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED);
01107 PPL_DIRTY_TEMP0(mpq_class, q_seq_i_upper);
01108 assign_r(q_seq_i_upper, seq_i.upper(), ROUND_NOT_NEEDED);
01109 g_coord += q_seq_i_upper;
01110 g_coord /= 2;
01111 }
01112 else
01113
01114 assign_r(g_coord, seq_i.upper(), ROUND_NOT_NEEDED);
01115 else {
01116
01117 assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED);
01118 ++g_coord;
01119 }
01120 else
01121
01122 assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED);
01123 else {
01124
01125
01126 PPL_ASSERT(!seq_i.upper_is_boundary_infinity());
01127 assign_r(g_coord, seq_i.upper(), ROUND_NOT_NEEDED);
01128 if (seq_i.upper_is_open())
01129 --g_coord;
01130 }
01131 break;
01132 case -1:
01133 assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED);
01134 break;
01135 }
01136
01137 assign_r(den, g_coord.get_den(), ROUND_NOT_NEEDED);
01138 lcm_assign(lcm, g_divisor, den);
01139 exact_div_assign(factor, lcm, g_divisor);
01140 g_expr *= factor;
01141 exact_div_assign(factor, lcm, den);
01142 assign_r(num, g_coord.get_num(), ROUND_NOT_NEEDED);
01143 num *= factor;
01144 g_expr += num * Variable(i);
01145 g_divisor = lcm;
01146 }
01147 g = Generator::point(g_expr, g_divisor);
01148 return true;
01149 }
01150
01151 template <typename ITV>
01152 bool
01153 Box<ITV>::contains(const Box& y) const {
01154 const Box& x = *this;
01155
01156 if (x.space_dimension() != y.space_dimension())
01157 x.throw_dimension_incompatible("contains(y)", y);
01158
01159
01160 if (y.is_empty())
01161 return true;
01162
01163
01164 if (x.is_empty())
01165 return false;
01166
01167 for (dimension_type k = x.seq.size(); k-- > 0; )
01168
01169 if (!x.seq[k].contains(y.seq[k]))
01170 return false;
01171 return true;
01172 }
01173
01174 template <typename ITV>
01175 bool
01176 Box<ITV>::is_disjoint_from(const Box& y) const {
01177 const Box& x = *this;
01178
01179 if (x.space_dimension() != y.space_dimension())
01180 x.throw_dimension_incompatible("is_disjoint_from(y)", y);
01181
01182
01183
01184 if (x.marked_empty() || y.marked_empty())
01185 return true;
01186
01187 for (dimension_type k = x.seq.size(); k-- > 0; )
01188
01189 if (x.seq[k].is_disjoint_from(y.seq[k]))
01190 return true;
01191 return false;
01192 }
01193
01194 template <typename ITV>
01195 inline bool
01196 Box<ITV>::upper_bound_assign_if_exact(const Box& y) {
01197 Box& x = *this;
01198
01199
01200 if (x.space_dimension() != y.space_dimension())
01201 x.throw_dimension_incompatible("upper_bound_assign_if_exact(y)", y);
01202
01203
01204 if (y.marked_empty())
01205 return true;
01206 if (x.marked_empty()) {
01207 x = y;
01208 return true;
01209 }
01210
01211 bool x_j_does_not_contain_y_j = false;
01212 bool y_j_does_not_contain_x_j = false;
01213
01214 for (dimension_type i = x.seq.size(); i-- > 0; ) {
01215 const ITV& x_seq_i = x.seq[i];
01216 const ITV& y_seq_i = y.seq[i];
01217
01218 if (!x_seq_i.can_be_exactly_joined_to(y_seq_i))
01219 return false;
01220
01221
01222
01223
01224 bool y_i_does_not_contain_x_i = !y_seq_i.contains(x_seq_i);
01225 if (y_i_does_not_contain_x_i && x_j_does_not_contain_y_j)
01226 return false;
01227 if (!x_seq_i.contains(y_seq_i)) {
01228 if (y_j_does_not_contain_x_j)
01229 return false;
01230 else
01231 x_j_does_not_contain_y_j = true;
01232 }
01233 if (y_i_does_not_contain_x_i)
01234 y_j_does_not_contain_x_j = true;
01235 }
01236
01237
01238 for (dimension_type k = x.seq.size(); k-- > 0; )
01239 x.seq[k].join_assign(y.seq[k]);
01240 return true;
01241 }
01242
01243 template <typename ITV>
01244 bool
01245 Box<ITV>::OK() const {
01246 if (status.test_empty_up_to_date() && !status.test_empty()) {
01247 Box tmp = *this;
01248 tmp.reset_empty_up_to_date();
01249 if (tmp.check_empty()) {
01250 #ifndef NDEBUG
01251 std::cerr << "The box is empty, but it is marked as non-empty."
01252 << std::endl;
01253 #endif // NDEBUG
01254 return false;
01255 }
01256 }
01257
01258
01259 if (!marked_empty()) {
01260 for (dimension_type k = seq.size(); k-- > 0; )
01261 if (!seq[k].OK())
01262 return false;
01263 }
01264
01265 return true;
01266 }
01267
01268 template <typename ITV>
01269 dimension_type
01270 Box<ITV>::affine_dimension() const {
01271 dimension_type d = space_dimension();
01272
01273 if (d == 0)
01274 return 0;
01275
01276
01277 if (is_empty())
01278 return 0;
01279
01280 for (dimension_type k = d; k-- > 0; )
01281 if (seq[k].is_singleton())
01282 --d;
01283
01284 return d;
01285 }
01286
01287 template <typename ITV>
01288 bool
01289 Box<ITV>::check_empty() const {
01290 PPL_ASSERT(!marked_empty());
01291 Box<ITV>& x = const_cast<Box<ITV>&>(*this);
01292 for (dimension_type k = seq.size(); k-- > 0; )
01293 if (seq[k].is_empty()) {
01294 x.set_empty();
01295 return true;
01296 }
01297 x.set_nonempty();;
01298 return false;
01299 }
01300
01301 template <typename ITV>
01302 bool
01303 Box<ITV>::is_universe() const {
01304 if (marked_empty())
01305 return false;
01306 for (dimension_type k = seq.size(); k-- > 0; )
01307 if (!seq[k].is_universe())
01308 return false;
01309 return true;
01310 }
01311
01312 template <typename ITV>
01313 bool
01314 Box<ITV>::is_topologically_closed() const {
01315 if (ITV::is_always_topologically_closed() || is_empty())
01316 return true;
01317
01318 for (dimension_type k = seq.size(); k-- > 0; )
01319 if (!seq[k].is_topologically_closed())
01320 return false;
01321 return true;
01322 }
01323
01324 template <typename ITV>
01325 bool
01326 Box<ITV>::is_discrete() const {
01327 if (is_empty())
01328 return true;
01329 for (dimension_type k = seq.size(); k-- > 0; )
01330 if (!seq[k].is_singleton())
01331 return false;
01332 return true;
01333 }
01334
01335 template <typename ITV>
01336 bool
01337 Box<ITV>::is_bounded() const {
01338 if (is_empty())
01339 return true;
01340 for (dimension_type k = seq.size(); k-- > 0; )
01341 if (!seq[k].is_bounded())
01342 return false;
01343 return true;
01344 }
01345
01346 template <typename ITV>
01347 bool
01348 Box<ITV>::contains_integer_point() const {
01349 if (marked_empty())
01350 return false;
01351 for (dimension_type k = seq.size(); k-- > 0; )
01352 if (!seq[k].contains_integer_point())
01353 return false;
01354 return true;
01355 }
01356
01357 template <typename ITV>
01358 bool
01359 Box<ITV>::frequency(const Linear_Expression& expr,
01360 Coefficient& freq_n, Coefficient& freq_d,
01361 Coefficient& val_n, Coefficient& val_d) const {
01362 dimension_type space_dim = space_dimension();
01363
01364 if (space_dim < expr.space_dimension())
01365 throw_dimension_incompatible("frequency(e, ...)", "e", expr);
01366
01367
01368
01369
01370
01371
01372
01373
01374 if (space_dim == 0) {
01375 if (is_empty())
01376 return false;
01377 freq_n = 0;
01378 freq_d = 1;
01379 val_n = expr.inhomogeneous_term();
01380 val_d = 1;
01381 return true;
01382 }
01383
01384
01385 if (is_empty())
01386 return false;
01387
01388
01389 PPL_DIRTY_TEMP_COEFFICIENT(coeff);
01390 PPL_DIRTY_TEMP_COEFFICIENT(num);
01391 PPL_DIRTY_TEMP_COEFFICIENT(den);
01392 PPL_DIRTY_TEMP0(mpq_class, tmp);
01393 Linear_Expression le = expr;
01394
01395 PPL_DIRTY_TEMP_COEFFICIENT(val_den);
01396 val_den = 1;
01397
01398 for (dimension_type i = space_dim; i-- > 0; ) {
01399 const Variable v(i);
01400 coeff = le.coefficient(v);
01401 if (coeff == 0) {
01402 continue;
01403 }
01404
01405 const ITV& seq_i = seq[i];
01406
01407 if (seq_i.is_singleton()) {
01408
01409 assign_r(tmp, seq_i.lower(), ROUND_NOT_NEEDED);
01410 num = tmp.get_num();
01411 den = tmp.get_den();
01412 le -= coeff*v;
01413 le *= den;
01414 le += num*coeff;
01415 val_den *= den;
01416 continue;
01417 }
01418
01419 return false;
01420 }
01421
01422
01423 freq_n = 0;
01424 freq_d = 1;
01425
01426
01427 normalize2(le.inhomogeneous_term(), val_den, val_n, val_d);
01428 return true;
01429 }
01430
01431 template <typename ITV>
01432 bool
01433 Box<ITV>::constrains(Variable var) const {
01434
01435 const dimension_type var_space_dim = var.space_dimension();
01436 if (space_dimension() < var_space_dim)
01437 throw_dimension_incompatible("constrains(v)", "v", var);
01438
01439 if (marked_empty() || !seq[var_space_dim-1].is_universe())
01440 return true;
01441
01442 return is_empty();
01443 }
01444
01445 template <typename ITV>
01446 void
01447 Box<ITV>::unconstrain(const Variables_Set& vars) {
01448
01449
01450
01451 if (vars.empty())
01452 return;
01453
01454
01455 const dimension_type min_space_dim = vars.space_dimension();
01456 if (space_dimension() < min_space_dim)
01457 throw_dimension_incompatible("unconstrain(vs)", min_space_dim);
01458
01459
01460 if (marked_empty())
01461 return;
01462
01463
01464
01465
01466 for (Variables_Set::const_iterator vsi = vars.begin(),
01467 vsi_end = vars.end(); vsi != vsi_end; ++vsi) {
01468 ITV& seq_vsi = seq[*vsi];
01469 if (!seq_vsi.is_empty())
01470 seq_vsi.assign(UNIVERSE);
01471 else {
01472 set_empty();
01473 break;
01474 }
01475 }
01476 PPL_ASSERT(OK());
01477 }
01478
01479 template <typename ITV>
01480 void
01481 Box<ITV>::topological_closure_assign() {
01482 if (ITV::is_always_topologically_closed() || is_empty())
01483 return;
01484
01485 for (dimension_type k = seq.size(); k-- > 0; )
01486 seq[k].topological_closure_assign();
01487 }
01488
01489 template <typename ITV>
01490 void
01491 Box<ITV>::wrap_assign(const Variables_Set& vars,
01492 Bounded_Integer_Type_Width w,
01493 Bounded_Integer_Type_Representation r,
01494 Bounded_Integer_Type_Overflow o,
01495 const Constraint_System* pcs,
01496 unsigned complexity_threshold,
01497 bool wrap_individually) {
01498 #if 0 // Generic implementation commented out.
01499 Implementation::wrap_assign(*this,
01500 vars, w, r, o, pcs,
01501 complexity_threshold, wrap_individually,
01502 "Box");
01503 #else // Specialized implementation.
01504 used(wrap_individually);
01505 used(complexity_threshold);
01506 Box& x = *this;
01507
01508
01509 const dimension_type vars_space_dim = vars.space_dimension();
01510 if (pcs != 0 && pcs->space_dimension() > vars_space_dim) {
01511 std::ostringstream s;
01512 s << "PPL::Box<ITV>::wrap_assign(vars, w, r, o, pcs, ...):"
01513 << std::endl
01514 << "vars.space_dimension() == " << vars_space_dim
01515 << ", pcs->space_dimension() == " << pcs->space_dimension() << ".";
01516 throw std::invalid_argument(s.str());
01517 }
01518
01519
01520 if (vars.empty()) {
01521 if (pcs != 0)
01522 refine_with_constraints(*pcs);
01523 return;
01524 }
01525
01526
01527 const dimension_type space_dim = x.space_dimension();
01528 if (space_dim < vars_space_dim) {
01529 std::ostringstream s;
01530 s << "PPL::Box<ITV>::wrap_assign(vars, ...):"
01531 << std::endl
01532 << "this->space_dimension() == " << space_dim
01533 << ", required space dimension == " << vars_space_dim << ".";
01534 throw std::invalid_argument(s.str());
01535 }
01536
01537
01538 if (x.is_empty())
01539 return;
01540
01541
01542
01543
01544 PPL_DIRTY_TEMP_COEFFICIENT(min_value);
01545 PPL_DIRTY_TEMP_COEFFICIENT(max_value);
01546 if (r == UNSIGNED) {
01547 min_value = 0;
01548 mul_2exp_assign(max_value, Coefficient_one(), w);
01549 --max_value;
01550 }
01551 else {
01552 PPL_ASSERT(r == SIGNED_2_COMPLEMENT);
01553 mul_2exp_assign(max_value, Coefficient_one(), w-1);
01554 neg_assign(min_value, max_value);
01555 --max_value;
01556 }
01557
01558
01559 PPL_DIRTY_TEMP(ITV, integer_quadrant_itv);
01560 PPL_DIRTY_TEMP(ITV, rational_quadrant_itv);
01561 {
01562 I_Constraint<Coefficient> lower = i_constraint(GREATER_OR_EQUAL, min_value);
01563 I_Constraint<Coefficient> upper = i_constraint(LESS_OR_EQUAL, max_value);
01564 integer_quadrant_itv.build(lower, upper);
01565
01566 if (o == OVERFLOW_UNDEFINED) {
01567 ++max_value;
01568 upper = i_constraint(LESS_THAN, max_value);
01569 rational_quadrant_itv.build(lower, upper);
01570 }
01571 }
01572
01573 const Variables_Set::const_iterator vs_end = vars.end();
01574
01575 if (pcs == 0) {
01576
01577 switch (o) {
01578 case OVERFLOW_WRAPS:
01579 for (Variables_Set::const_iterator i = vars.begin(); i != vs_end; ++i)
01580 x.seq[*i].wrap_assign(w, r, integer_quadrant_itv);
01581 reset_empty_up_to_date();
01582 break;
01583 case OVERFLOW_UNDEFINED:
01584 for (Variables_Set::const_iterator i = vars.begin(); i != vs_end; ++i) {
01585 ITV& x_seq_v = x.seq[*i];
01586 if (!rational_quadrant_itv.contains(x_seq_v)) {
01587 x_seq_v.assign(integer_quadrant_itv);
01588 }
01589 }
01590 break;
01591 case OVERFLOW_IMPOSSIBLE:
01592 for (Variables_Set::const_iterator i = vars.begin(); i != vs_end; ++i)
01593 x.seq[*i].intersect_assign(integer_quadrant_itv);
01594 reset_empty_up_to_date();
01595 break;
01596 }
01597 PPL_ASSERT(x.OK());
01598 return;
01599 }
01600
01601 PPL_ASSERT(pcs != 0);
01602 const Constraint_System& cs = *pcs;
01603 const dimension_type cs_space_dim = cs.space_dimension();
01604
01605 typedef std::map<dimension_type, std::vector<const Constraint*> > map_type;
01606 map_type var_cs_map;
01607 for (Constraint_System::const_iterator i = cs.begin(),
01608 i_end = cs.end(); i != i_end; ++i) {
01609 const Constraint& c = *i;
01610 dimension_type c_num_vars = 0;
01611 dimension_type c_only_var = 0;
01612 if (extract_interval_constraint(c, cs_space_dim,
01613 c_num_vars, c_only_var)) {
01614 if (c_num_vars == 1) {
01615
01616 PPL_ASSERT(c_only_var < space_dim);
01617
01618 if (vars.find(c_only_var) != vs_end)
01619 var_cs_map[c_only_var].push_back(&c);
01620 }
01621 else {
01622 PPL_ASSERT(c_num_vars == 0);
01623
01624 PPL_ASSERT(c.is_inconsistent());
01625 x.set_empty();
01626 return;
01627 }
01628 }
01629 }
01630
01631 PPL_DIRTY_TEMP(ITV, refinement_itv);
01632 const map_type::const_iterator var_cs_map_end = var_cs_map.end();
01633
01634 for (Variables_Set::const_iterator i = vars.begin(); i != vs_end; ++i) {
01635 const dimension_type v = *i;
01636 refinement_itv = integer_quadrant_itv;
01637
01638 map_type::const_iterator var_cs_map_iter = var_cs_map.find(v);
01639 if (var_cs_map_iter != var_cs_map_end) {
01640
01641 const map_type::mapped_type& var_cs = var_cs_map_iter->second;
01642 for (dimension_type j = var_cs.size(); j-- > 0; ) {
01643 const Constraint& c = *var_cs[j];
01644 refine_interval_no_check(refinement_itv,
01645 c.type(),
01646 c.inhomogeneous_term(),
01647 c.coefficient(Variable(v)));
01648 }
01649 }
01650
01651 ITV& x_seq_v = x.seq[v];
01652 switch (o) {
01653 case OVERFLOW_WRAPS:
01654 x_seq_v.wrap_assign(w, r, refinement_itv);
01655 break;
01656 case OVERFLOW_UNDEFINED:
01657 if (!rational_quadrant_itv.contains(x_seq_v))
01658 x_seq_v.assign(UNIVERSE);
01659 break;
01660 case OVERFLOW_IMPOSSIBLE:
01661 x_seq_v.intersect_assign(refinement_itv);
01662 break;
01663 }
01664 }
01665 PPL_ASSERT(x.OK());
01666 #endif
01667 }
01668
01669 template <typename ITV>
01670 void
01671 Box<ITV>::drop_some_non_integer_points(Complexity_Class) {
01672 if (std::numeric_limits<typename ITV::boundary_type>::is_integer
01673 && !ITV::info_type::store_open)
01674 return;
01675
01676 if (marked_empty())
01677 return;
01678
01679 for (dimension_type k = seq.size(); k-- > 0; )
01680 seq[k].drop_some_non_integer_points();
01681
01682 PPL_ASSERT(OK());
01683 }
01684
01685 template <typename ITV>
01686 void
01687 Box<ITV>::drop_some_non_integer_points(const Variables_Set& vars,
01688 Complexity_Class) {
01689
01690 const dimension_type min_space_dim = vars.space_dimension();
01691 if (space_dimension() < min_space_dim)
01692 throw_dimension_incompatible("drop_some_non_integer_points(vs, cmpl)",
01693 min_space_dim);
01694
01695 if (std::numeric_limits<typename ITV::boundary_type>::is_integer
01696 && !ITV::info_type::store_open)
01697 return;
01698
01699 if (marked_empty())
01700 return;
01701
01702 for (Variables_Set::const_iterator v_i = vars.begin(),
01703 v_end = vars.end(); v_i != v_end; ++v_i)
01704 seq[*v_i].drop_some_non_integer_points();
01705
01706 PPL_ASSERT(OK());
01707 }
01708
01709 template <typename ITV>
01710 void
01711 Box<ITV>::intersection_assign(const Box& y) {
01712 Box& x = *this;
01713 const dimension_type space_dim = space_dimension();
01714
01715
01716 if (space_dim != y.space_dimension())
01717 x.throw_dimension_incompatible("intersection_assign(y)", y);
01718
01719
01720 if (x.marked_empty())
01721 return;
01722 if (y.marked_empty()) {
01723 x.set_empty();
01724 return;
01725 }
01726
01727
01728
01729 if (space_dim == 0)
01730 return;
01731
01732
01733
01734 reset_empty_up_to_date();
01735
01736 for (dimension_type k = space_dim; k-- > 0; )
01737 x.seq[k].intersect_assign(y.seq[k]);
01738
01739 PPL_ASSERT(x.OK());
01740 }
01741
01742 template <typename ITV>
01743 void
01744 Box<ITV>::upper_bound_assign(const Box& y) {
01745 Box& x = *this;
01746
01747
01748 if (x.space_dimension() != y.space_dimension())
01749 x.throw_dimension_incompatible("upper_bound_assign(y)", y);
01750
01751
01752 if (y.marked_empty())
01753 return;
01754 if (x.marked_empty()) {
01755 x = y;
01756 return;
01757 }
01758
01759 for (dimension_type k = x.seq.size(); k-- > 0; )
01760 x.seq[k].join_assign(y.seq[k]);
01761
01762 PPL_ASSERT(x.OK());
01763 }
01764
01765 template <typename ITV>
01766 void
01767 Box<ITV>::concatenate_assign(const Box& y) {
01768 Box& x = *this;
01769 const dimension_type x_space_dim = x.space_dimension();
01770 const dimension_type y_space_dim = y.space_dimension();
01771
01772
01773 if (y.marked_empty())
01774 x.set_empty();
01775
01776
01777 if (y_space_dim == 0)
01778 return;
01779
01780
01781
01782 x.seq.reserve(x_space_dim + y_space_dim);
01783
01784
01785
01786 if (x.marked_empty()) {
01787 x.seq.insert(x.seq.end(), y_space_dim, ITV(EMPTY));
01788 PPL_ASSERT(x.OK());
01789 return;
01790 }
01791
01792
01793 std::copy(y.seq.begin(), y.seq.end(),
01794 std::back_insert_iterator<Sequence>(x.seq));
01795
01796 if (!y.status.test_empty_up_to_date())
01797 reset_empty_up_to_date();
01798
01799 PPL_ASSERT(x.OK());
01800 }
01801
01802 template <typename ITV>
01803 void
01804 Box<ITV>::difference_assign(const Box& y) {
01805 const dimension_type space_dim = space_dimension();
01806
01807
01808 if (space_dim != y.space_dimension())
01809 throw_dimension_incompatible("difference_assign(y)", y);
01810
01811 Box& x = *this;
01812 if (x.is_empty() || y.is_empty())
01813 return;
01814
01815 switch (space_dim) {
01816 case 0:
01817
01818
01819 x.set_empty();
01820 break;
01821
01822 case 1:
01823 x.seq[0].difference_assign(y.seq[0]);
01824 if (x.seq[0].is_empty())
01825 x.set_empty();
01826 break;
01827
01828 default:
01829 {
01830 dimension_type index_non_contained = space_dim;
01831 dimension_type number_non_contained = 0;
01832 for (dimension_type i = space_dim; i-- > 0; )
01833 if (!y.seq[i].contains(x.seq[i])) {
01834 if (++number_non_contained == 1)
01835 index_non_contained = i;
01836 else
01837 break;
01838 }
01839
01840 switch (number_non_contained) {
01841 case 0:
01842
01843 x.set_empty();
01844 break;
01845 case 1:
01846 x.seq[index_non_contained]
01847 .difference_assign(y.seq[index_non_contained]);
01848 if (x.seq[index_non_contained].is_empty())
01849 x.set_empty();
01850 break;
01851 default:
01852
01853 break;
01854 }
01855 }
01856 break;
01857 }
01858 PPL_ASSERT(OK());
01859 }
01860
01861 template <typename ITV>
01862 bool
01863 Box<ITV>::simplify_using_context_assign(const Box& y) {
01864 Box& x = *this;
01865 const dimension_type num_dims = x.space_dimension();
01866
01867 if (num_dims != y.space_dimension())
01868 x.throw_dimension_incompatible("simplify_using_context_assign(y)", y);
01869
01870
01871 if (num_dims == 0) {
01872 if (y.marked_empty()) {
01873 x.set_nonempty();
01874 return false;
01875 }
01876 else
01877 return !x.marked_empty();
01878 }
01879
01880
01881 if (y.is_empty()) {
01882 for (dimension_type i = num_dims; i-- > 0; )
01883 x.seq[i].assign(UNIVERSE);
01884 x.set_nonempty();
01885 return false;
01886 }
01887
01888 if (x.is_empty()) {
01889
01890 for (dimension_type i = 0; i < num_dims; ++i) {
01891 if (y.seq[i].is_universe())
01892 x.seq[i].assign(UNIVERSE);
01893 else {
01894
01895 ITV& seq_i = x.seq[i];
01896 seq_i.empty_intersection_assign(y.seq[i]);
01897 if (seq_i.is_empty()) {
01898
01899
01900 seq_i.assign(UNIVERSE);
01901 continue;
01902 }
01903
01904
01905 for (++i; i < num_dims; ++i)
01906 x.seq[i].assign(UNIVERSE);
01907 x.set_nonempty();
01908 PPL_ASSERT(x.OK());
01909 return false;
01910 }
01911 }
01912
01913
01914 PPL_ASSERT(x.OK() && x.is_empty());
01915 return false;
01916 }
01917
01918
01919 dimension_type i = 0;
01920 for ( ; i < num_dims; ++i) {
01921 if (!x.seq[i].simplify_using_context_assign(y.seq[i])) {
01922 PPL_ASSERT(!x.seq[i].is_empty());
01923
01924
01925 for (dimension_type j = num_dims; j-- > i; )
01926 x.seq[j].assign(UNIVERSE);
01927 for (dimension_type j = i; j-- > 0; )
01928 x.seq[j].assign(UNIVERSE);
01929 PPL_ASSERT(x.OK());
01930 return false;
01931 }
01932 }
01933 PPL_ASSERT(x.OK());
01934 return true;
01935 }
01936
01937 template <typename ITV>
01938 void
01939 Box<ITV>::time_elapse_assign(const Box& y) {
01940 Box& x = *this;
01941 const dimension_type x_space_dim = x.space_dimension();
01942
01943
01944 if (x_space_dim != y.space_dimension())
01945 x.throw_dimension_incompatible("time_elapse_assign(y)", y);
01946
01947
01948 if (x_space_dim == 0) {
01949 if (y.marked_empty())
01950 x.set_empty();
01951 return;
01952 }
01953
01954
01955
01956 if (x.marked_empty() || y.marked_empty()
01957 || x.is_empty() || y.is_empty()) {
01958 x.set_empty();
01959 return;
01960 }
01961
01962 for (dimension_type i = x_space_dim; i-- > 0; ) {
01963 ITV& x_seq_i = x.seq[i];
01964 const ITV& y_seq_i = y.seq[i];
01965 if (!x_seq_i.lower_is_boundary_infinity())
01966 if (y_seq_i.lower_is_boundary_infinity() || y_seq_i.lower() < 0)
01967 x_seq_i.lower_extend();
01968 if (!x_seq_i.upper_is_boundary_infinity())
01969 if (y_seq_i.upper_is_boundary_infinity() || y_seq_i.upper() > 0)
01970 x_seq_i.upper_extend();
01971 }
01972 PPL_ASSERT(x.OK());
01973 }
01974
01975 template <typename ITV>
01976 inline void
01977 Box<ITV>::remove_space_dimensions(const Variables_Set& vars) {
01978
01979
01980
01981 if (vars.empty()) {
01982 PPL_ASSERT(OK());
01983 return;
01984 }
01985
01986 const dimension_type old_space_dim = space_dimension();
01987
01988
01989 const dimension_type vsi_space_dim = vars.space_dimension();
01990 if (old_space_dim < vsi_space_dim)
01991 throw_dimension_incompatible("remove_space_dimensions(vs)",
01992 vsi_space_dim);
01993
01994 const dimension_type new_space_dim = old_space_dim - vars.size();
01995
01996
01997
01998
01999 if (is_empty() || new_space_dim == 0) {
02000 seq.resize(new_space_dim);
02001 PPL_ASSERT(OK());
02002 return;
02003 }
02004
02005
02006
02007 Variables_Set::const_iterator vsi = vars.begin();
02008 Variables_Set::const_iterator vsi_end = vars.end();
02009 dimension_type dst = *vsi;
02010 dimension_type src = dst + 1;
02011 for (++vsi; vsi != vsi_end; ++vsi) {
02012 const dimension_type vsi_next = *vsi;
02013
02014 while (src < vsi_next)
02015 seq[dst++].swap(seq[src++]);
02016 ++src;
02017 }
02018
02019 while (src < old_space_dim)
02020 seq[dst++].swap(seq[src++]);
02021
02022 PPL_ASSERT(dst == new_space_dim);
02023 seq.resize(new_space_dim);
02024
02025 PPL_ASSERT(OK());
02026 }
02027
02028 template <typename ITV>
02029 void
02030 Box<ITV>::remove_higher_space_dimensions(const dimension_type new_dim) {
02031
02032
02033 const dimension_type old_dim = space_dimension();
02034 if (new_dim > old_dim)
02035 throw_dimension_incompatible("remove_higher_space_dimensions(nd)",
02036 new_dim);
02037
02038
02039
02040
02041 if (new_dim == old_dim) {
02042 PPL_ASSERT(OK());
02043 return;
02044 }
02045
02046 seq.erase(seq.begin() + new_dim, seq.end());
02047 PPL_ASSERT(OK());
02048 }
02049
02050 template <typename ITV>
02051 template <typename Partial_Function>
02052 void
02053 Box<ITV>::map_space_dimensions(const Partial_Function& pfunc) {
02054 const dimension_type space_dim = space_dimension();
02055 if (space_dim == 0)
02056 return;
02057
02058 if (pfunc.has_empty_codomain()) {
02059
02060 remove_higher_space_dimensions(0);
02061 return;
02062 }
02063
02064 const dimension_type new_space_dim = pfunc.max_in_codomain() + 1;
02065
02066 if (is_empty()) {
02067 remove_higher_space_dimensions(new_space_dim);
02068 return;
02069 }
02070
02071
02072 Box<ITV> tmp(new_space_dim);
02073
02074 for (dimension_type i = 0; i < space_dim; ++i) {
02075 dimension_type new_i;
02076 if (pfunc.maps(i, new_i))
02077 seq[i].swap(tmp.seq[new_i]);
02078 }
02079 swap(tmp);
02080 PPL_ASSERT(OK());
02081 }
02082
02083 template <typename ITV>
02084 void
02085 Box<ITV>::fold_space_dimensions(const Variables_Set& vars,
02086 const Variable dest) {
02087 const dimension_type space_dim = space_dimension();
02088
02089 if (dest.space_dimension() > space_dim)
02090 throw_dimension_incompatible("fold_space_dimensions(vs, v)", "v", dest);
02091
02092
02093 if (vars.empty())
02094 return;
02095
02096
02097 if (vars.space_dimension() > space_dim)
02098 throw_dimension_incompatible("fold_space_dimensions(vs, v)",
02099 vars.space_dimension());
02100
02101
02102 if (vars.find(dest.id()) != vars.end())
02103 throw_generic("fold_space_dimensions(vs, v)",
02104 "v should not occur in vs");
02105
02106
02107 if (!is_empty()) {
02108
02109
02110 ITV& seq_v = seq[dest.id()];
02111 for (Variables_Set::const_iterator i = vars.begin(),
02112 vs_end = vars.end(); i != vs_end; ++i)
02113 seq_v.join_assign(seq[*i]);
02114 }
02115 remove_space_dimensions(vars);
02116 }
02117
02118 template <typename ITV>
02119 void
02120 Box<ITV>::add_constraint_no_check(const Constraint& c) {
02121 const dimension_type c_space_dim = c.space_dimension();
02122 PPL_ASSERT(c_space_dim <= space_dimension());
02123
02124 dimension_type c_num_vars = 0;
02125 dimension_type c_only_var = 0;
02126
02127 if (!extract_interval_constraint(c, c_space_dim, c_num_vars, c_only_var))
02128 throw_generic("add_constraint(c)", "c is not an interval constraint");
02129
02130
02131
02132 if (c.is_strict_inequality() && c_num_vars != 0
02133 && ITV::is_always_topologically_closed())
02134 throw_generic("add_constraint(c)", "c is a nontrivial strict constraint");
02135
02136
02137 if (marked_empty())
02138 return;
02139
02140 const Coefficient& n = c.inhomogeneous_term();
02141 if (c_num_vars == 0) {
02142
02143 if (n < 0
02144 || (c.is_equality() && n != 0)
02145 || (c.is_strict_inequality() && n == 0))
02146 set_empty();
02147 return;
02148 }
02149
02150 PPL_ASSERT(c_num_vars == 1);
02151 const Coefficient& d = c.coefficient(Variable(c_only_var));
02152 add_interval_constraint_no_check(c_only_var, c.type(), n, d);
02153 }
02154
02155 template <typename ITV>
02156 void
02157 Box<ITV>::add_constraints_no_check(const Constraint_System& cs) {
02158 PPL_ASSERT(cs.space_dimension() <= space_dimension());
02159
02160
02161
02162 for (Constraint_System::const_iterator i = cs.begin(),
02163 cs_end = cs.end(); i != cs_end; ++i)
02164 add_constraint_no_check(*i);
02165 PPL_ASSERT(OK());
02166 }
02167
02168 template <typename ITV>
02169 void
02170 Box<ITV>::add_congruence_no_check(const Congruence& cg) {
02171 const dimension_type cg_space_dim = cg.space_dimension();
02172 PPL_ASSERT(cg_space_dim <= space_dimension());
02173
02174
02175 if (cg.is_proper_congruence()) {
02176 if (cg.is_inconsistent()) {
02177 set_empty();
02178 return;
02179 }
02180 else if (cg.is_tautological())
02181 return;
02182 else
02183
02184 throw_generic("add_congruence(cg)",
02185 "cg is a nontrivial proper congruence");
02186 }
02187
02188 PPL_ASSERT(cg.is_equality());
02189 dimension_type cg_num_vars = 0;
02190 dimension_type cg_only_var = 0;
02191
02192 if (!extract_interval_congruence(cg, cg_space_dim, cg_num_vars, cg_only_var))
02193 throw_generic("add_congruence(cg)", "cg is not an interval congruence");
02194
02195
02196 if (marked_empty())
02197 return;
02198
02199 const Coefficient& n = cg.inhomogeneous_term();
02200 if (cg_num_vars == 0) {
02201
02202 if (n != 0)
02203 set_empty();
02204 return;
02205 }
02206
02207 PPL_ASSERT(cg_num_vars == 1);
02208 const Coefficient& d = cg.coefficient(Variable(cg_only_var));
02209 add_interval_constraint_no_check(cg_only_var, Constraint::EQUALITY, n, d);
02210 }
02211
02212 template <typename ITV>
02213 void
02214 Box<ITV>::add_congruences_no_check(const Congruence_System& cgs) {
02215 PPL_ASSERT(cgs.space_dimension() <= space_dimension());
02216
02217
02218
02219 for (Congruence_System::const_iterator i = cgs.begin(),
02220 cgs_end = cgs.end(); i != cgs_end; ++i)
02221 add_congruence_no_check(*i);
02222 PPL_ASSERT(OK());
02223 }
02224
02225 template <typename ITV>
02226 void
02227 Box<ITV>::refine_no_check(const Constraint& c) {
02228 const dimension_type c_space_dim = c.space_dimension();
02229 PPL_ASSERT(c.space_dimension() <= space_dimension());
02230 PPL_ASSERT(!marked_empty());
02231
02232 dimension_type c_num_vars = 0;
02233 dimension_type c_only_var = 0;
02234
02235 if (!extract_interval_constraint(c, c_space_dim, c_num_vars, c_only_var)) {
02236 propagate_constraint_no_check(c);
02237 return;
02238 }
02239
02240 const Coefficient& n = c.inhomogeneous_term();
02241 if (c_num_vars == 0) {
02242
02243 if (n < 0
02244 || (c.is_equality() && n != 0)
02245 || (c.is_strict_inequality() && n == 0))
02246 set_empty();
02247 return;
02248 }
02249
02250 PPL_ASSERT(c_num_vars == 1);
02251 const Coefficient& d = c.coefficient(Variable(c_only_var));
02252 add_interval_constraint_no_check(c_only_var, c.type(), n, d);
02253 }
02254
02255 template <typename ITV>
02256 void
02257 Box<ITV>::refine_no_check(const Constraint_System& cs) {
02258 PPL_ASSERT(cs.space_dimension() <= space_dimension());
02259 for (Constraint_System::const_iterator i = cs.begin(),
02260 cs_end = cs.end(); !marked_empty() && i != cs_end; ++i)
02261 refine_no_check(*i);
02262 PPL_ASSERT(OK());
02263 }
02264
02265 template <typename ITV>
02266 void
02267 Box<ITV>::refine_no_check(const Congruence& cg) {
02268 PPL_ASSERT(!marked_empty());
02269
02270 PPL_ASSERT(cg.space_dimension() <= space_dimension());
02271
02272 if (cg.is_proper_congruence()) {
02273
02274
02275
02276 if (cg.is_inconsistent())
02277 set_empty();
02278 return;
02279 }
02280
02281 PPL_ASSERT(cg.is_equality());
02282 Constraint c(cg);
02283 refine_no_check(c);
02284 }
02285
02286 template <typename ITV>
02287 void
02288 Box<ITV>::refine_no_check(const Congruence_System& cgs) {
02289 PPL_ASSERT(cgs.space_dimension() <= space_dimension());
02290 for (Congruence_System::const_iterator i = cgs.begin(),
02291 cgs_end = cgs.end(); !marked_empty() && i != cgs_end; ++i)
02292 refine_no_check(*i);
02293 PPL_ASSERT(OK());
02294 }
02295
02296 #if 1 // Alternative implementations for propagate_constraint_no_check.
02297 namespace {
02298
02299 inline bool
02300 propagate_constraint_check_result(Result r, Ternary& open) {
02301 r = result_relation_class(r);
02302 switch (r) {
02303 case V_GT_MINUS_INFINITY:
02304 case V_LT_PLUS_INFINITY:
02305 return true;
02306 case V_LT:
02307 case V_GT:
02308 open = T_YES;
02309 return false;
02310 case V_LE:
02311 case V_GE:
02312 if (open == T_NO)
02313 open = T_MAYBE;
02314 return false;
02315 case V_EQ:
02316 return false;
02317 default:
02318 PPL_ASSERT(false);
02319 return true;
02320 }
02321 }
02322
02323 }
02324
02325 template <typename ITV>
02326 void
02327 Box<ITV>::propagate_constraint_no_check(const Constraint& c) {
02328 PPL_ASSERT(c.space_dimension() <= space_dimension());
02329
02330 typedef
02331 typename Select_Temp_Boundary_Type<typename ITV::boundary_type>::type
02332 Temp_Boundary_Type;
02333
02334 const dimension_type c_space_dim = c.space_dimension();
02335 const Constraint::Type c_type = c.type();
02336 const Coefficient& c_inhomogeneous_term = c.inhomogeneous_term();
02337
02338
02339 dimension_type last_k = c_space_dim;
02340 for (dimension_type k = c_space_dim; k-- > 0; ) {
02341 if (c.coefficient(Variable(k)) != 0) {
02342 last_k = k;
02343 break;
02344 }
02345 }
02346 if (last_k == c_space_dim) {
02347
02348 if (c_inhomogeneous_term < 0
02349 || (c_inhomogeneous_term == 0
02350 && c_type != Constraint::NONSTRICT_INEQUALITY))
02351 set_empty();
02352 return;
02353 }
02354
02355
02356 PPL_ASSERT(last_k < c_space_dim);
02357 Result r;
02358 Temp_Boundary_Type t_bound;
02359 Temp_Boundary_Type t_a;
02360 Temp_Boundary_Type t_x;
02361 Ternary open;
02362 for (dimension_type k = last_k+1; k-- > 0; ) {
02363 const Coefficient& a_k = c.coefficient(Variable(k));
02364 int sgn_a_k = sgn(a_k);
02365 if (sgn_a_k == 0)
02366 continue;
02367 if (sgn_a_k > 0) {
02368 open = (c_type == Constraint::STRICT_INEQUALITY) ? T_YES : T_NO;
02369 if (open == T_NO)
02370 maybe_reset_fpu_inexact<Temp_Boundary_Type>();
02371 r = assign_r(t_bound, c_inhomogeneous_term, ROUND_UP);
02372 if (propagate_constraint_check_result(r, open))
02373 goto maybe_refine_upper_1;
02374 r = neg_assign_r(t_bound, t_bound, ROUND_DOWN);
02375 if (propagate_constraint_check_result(r, open))
02376 goto maybe_refine_upper_1;
02377 for (dimension_type i = last_k+1; i-- > 0; ) {
02378 if (i == k)
02379 continue;
02380 const Coefficient& a_i = c.coefficient(Variable(i));
02381 int sgn_a_i = sgn(a_i);
02382 if (sgn_a_i == 0)
02383 continue;
02384 ITV& x_i = seq[i];
02385 if (sgn_a_i < 0) {
02386 if (x_i.lower_is_boundary_infinity())
02387 goto maybe_refine_upper_1;
02388 r = assign_r(t_a, a_i, ROUND_DOWN);
02389 if (propagate_constraint_check_result(r, open))
02390 goto maybe_refine_upper_1;
02391 r = assign_r(t_x, x_i.lower(), ROUND_DOWN);
02392 if (propagate_constraint_check_result(r, open))
02393 goto maybe_refine_upper_1;
02394 if (x_i.lower_is_open())
02395 open = T_YES;
02396 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_DOWN);
02397 if (propagate_constraint_check_result(r, open))
02398 goto maybe_refine_upper_1;
02399 }
02400 else {
02401 PPL_ASSERT(sgn_a_i > 0);
02402 if (x_i.upper_is_boundary_infinity())
02403 goto maybe_refine_upper_1;
02404 r = assign_r(t_a, a_i, ROUND_UP);
02405 if (propagate_constraint_check_result(r, open))
02406 goto maybe_refine_upper_1;
02407 r = assign_r(t_x, x_i.upper(), ROUND_UP);
02408 if (propagate_constraint_check_result(r, open))
02409 goto maybe_refine_upper_1;
02410 if (x_i.upper_is_open())
02411 open = T_YES;
02412 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_DOWN);
02413 if (propagate_constraint_check_result(r, open))
02414 goto maybe_refine_upper_1;
02415 }
02416 }
02417 r = assign_r(t_a, a_k, ROUND_UP);
02418 if (propagate_constraint_check_result(r, open))
02419 goto maybe_refine_upper_1;
02420 r = div_assign_r(t_bound, t_bound, t_a, ROUND_DOWN);
02421 if (propagate_constraint_check_result(r, open))
02422 goto maybe_refine_upper_1;
02423
02424
02425 if (open == T_MAYBE
02426 && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1)
02427 open = T_YES;
02428 seq[k].add_constraint(i_constraint(open == T_YES ? GREATER_THAN : GREATER_OR_EQUAL, t_bound));
02429 reset_empty_up_to_date();
02430 maybe_refine_upper_1:
02431 if (c_type != Constraint::EQUALITY)
02432 continue;
02433 open = T_NO;
02434 maybe_reset_fpu_inexact<Temp_Boundary_Type>();
02435 r = assign_r(t_bound, c_inhomogeneous_term, ROUND_DOWN);
02436 if (propagate_constraint_check_result(r, open))
02437 goto next_k;
02438 r = neg_assign_r(t_bound, t_bound, ROUND_UP);
02439 if (propagate_constraint_check_result(r, open))
02440 goto next_k;
02441 for (dimension_type i = c_space_dim; i-- > 0; ) {
02442 if (i == k)
02443 continue;
02444 const Coefficient& a_i = c.coefficient(Variable(i));
02445 int sgn_a_i = sgn(a_i);
02446 if (sgn_a_i == 0)
02447 continue;
02448 ITV& x_i = seq[i];
02449 if (sgn_a_i < 0) {
02450 if (x_i.upper_is_boundary_infinity())
02451 goto next_k;
02452 r = assign_r(t_a, a_i, ROUND_UP);
02453 if (propagate_constraint_check_result(r, open))
02454 goto next_k;
02455 r = assign_r(t_x, x_i.upper(), ROUND_UP);
02456 if (propagate_constraint_check_result(r, open))
02457 goto next_k;
02458 if (x_i.upper_is_open())
02459 open = T_YES;
02460 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
02461 if (propagate_constraint_check_result(r, open))
02462 goto next_k;
02463 }
02464 else {
02465 PPL_ASSERT(sgn_a_i > 0);
02466 if (x_i.lower_is_boundary_infinity())
02467 goto next_k;
02468 r = assign_r(t_a, a_i, ROUND_DOWN);
02469 if (propagate_constraint_check_result(r, open))
02470 goto next_k;
02471 r = assign_r(t_x, x_i.lower(), ROUND_DOWN);
02472 if (propagate_constraint_check_result(r, open))
02473 goto next_k;
02474 if (x_i.lower_is_open())
02475 open = T_YES;
02476 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
02477 if (propagate_constraint_check_result(r, open))
02478 goto next_k;
02479 }
02480 }
02481 r = assign_r(t_a, a_k, ROUND_DOWN);
02482 if (propagate_constraint_check_result(r, open))
02483 goto next_k;
02484 r = div_assign_r(t_bound, t_bound, t_a, ROUND_UP);
02485 if (propagate_constraint_check_result(r, open))
02486 goto next_k;
02487
02488
02489 if (open == T_MAYBE
02490 && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1)
02491 open = T_YES;
02492 seq[k].add_constraint(i_constraint(open == T_YES ? LESS_THAN : LESS_OR_EQUAL, t_bound));
02493 reset_empty_up_to_date();
02494 }
02495 else {
02496 PPL_ASSERT(sgn_a_k < 0);
02497 open = (c_type == Constraint::STRICT_INEQUALITY) ? T_YES : T_NO;
02498 if (open == T_NO)
02499 maybe_reset_fpu_inexact<Temp_Boundary_Type>();
02500 r = assign_r(t_bound, c_inhomogeneous_term, ROUND_UP);
02501 if (propagate_constraint_check_result(r, open))
02502 goto maybe_refine_upper_2;
02503 r = neg_assign_r(t_bound, t_bound, ROUND_DOWN);
02504 if (propagate_constraint_check_result(r, open))
02505 goto maybe_refine_upper_2;
02506 for (dimension_type i = c_space_dim; i-- > 0; ) {
02507 if (i == k)
02508 continue;
02509 const Coefficient& a_i = c.coefficient(Variable(i));
02510 int sgn_a_i = sgn(a_i);
02511 if (sgn_a_i == 0)
02512 continue;
02513 ITV& x_i = seq[i];
02514 if (sgn_a_i < 0) {
02515 if (x_i.lower_is_boundary_infinity())
02516 goto maybe_refine_upper_2;
02517 r = assign_r(t_a, a_i, ROUND_DOWN);
02518 if (propagate_constraint_check_result(r, open))
02519 goto maybe_refine_upper_2;
02520 r = assign_r(t_x, x_i.lower(), ROUND_DOWN);
02521 if (propagate_constraint_check_result(r, open))
02522 goto maybe_refine_upper_2;
02523 if (x_i.lower_is_open())
02524 open = T_YES;
02525 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
02526 if (propagate_constraint_check_result(r, open))
02527 goto maybe_refine_upper_2;
02528 }
02529 else {
02530 PPL_ASSERT(sgn_a_i > 0);
02531 if (x_i.upper_is_boundary_infinity())
02532 goto maybe_refine_upper_2;
02533 r = assign_r(t_a, a_i, ROUND_UP);
02534 if (propagate_constraint_check_result(r, open))
02535 goto maybe_refine_upper_2;
02536 r = assign_r(t_x, x_i.upper(), ROUND_UP);
02537 if (propagate_constraint_check_result(r, open))
02538 goto maybe_refine_upper_2;
02539 if (x_i.upper_is_open())
02540 open = T_YES;
02541 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_DOWN);
02542 if (propagate_constraint_check_result(r, open))
02543 goto maybe_refine_upper_2;
02544 }
02545 }
02546 r = assign_r(t_a, a_k, ROUND_UP);
02547 if (propagate_constraint_check_result(r, open))
02548 goto maybe_refine_upper_2;
02549 r = div_assign_r(t_bound, t_bound, t_a, ROUND_UP);
02550 if (propagate_constraint_check_result(r, open))
02551 goto maybe_refine_upper_2;
02552
02553
02554 if (open == T_MAYBE
02555 && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1)
02556 open = T_YES;
02557 seq[k].add_constraint(i_constraint(open == T_YES ? LESS_THAN : LESS_OR_EQUAL, t_bound));
02558 reset_empty_up_to_date();
02559 maybe_refine_upper_2:
02560 if (c_type != Constraint::EQUALITY)
02561 continue;
02562 open = T_NO;
02563 maybe_reset_fpu_inexact<Temp_Boundary_Type>();
02564 r = assign_r(t_bound, c_inhomogeneous_term, ROUND_DOWN);
02565 if (propagate_constraint_check_result(r, open))
02566 goto next_k;
02567 r = neg_assign_r(t_bound, t_bound, ROUND_UP);
02568 if (propagate_constraint_check_result(r, open))
02569 goto next_k;
02570 for (dimension_type i = c_space_dim; i-- > 0; ) {
02571 if (i == k)
02572 continue;
02573 const Coefficient& a_i = c.coefficient(Variable(i));
02574 int sgn_a_i = sgn(a_i);
02575 if (sgn_a_i == 0)
02576 continue;
02577 ITV& x_i = seq[i];
02578 if (sgn_a_i < 0) {
02579 if (x_i.upper_is_boundary_infinity())
02580 goto next_k;
02581 r = assign_r(t_a, a_i, ROUND_UP);
02582 if (propagate_constraint_check_result(r, open))
02583 goto next_k;
02584 r = assign_r(t_x, x_i.upper(), ROUND_UP);
02585 if (propagate_constraint_check_result(r, open))
02586 goto next_k;
02587 if (x_i.upper_is_open())
02588 open = T_YES;
02589 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
02590 if (propagate_constraint_check_result(r, open))
02591 goto next_k;
02592 }
02593 else {
02594 PPL_ASSERT(sgn_a_i > 0);
02595 if (x_i.lower_is_boundary_infinity())
02596 goto next_k;
02597 r = assign_r(t_a, a_i, ROUND_DOWN);
02598 if (propagate_constraint_check_result(r, open))
02599 goto next_k;
02600 r = assign_r(t_x, x_i.lower(), ROUND_DOWN);
02601 if (propagate_constraint_check_result(r, open))
02602 goto next_k;
02603 if (x_i.lower_is_open())
02604 open = T_YES;
02605 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
02606 if (propagate_constraint_check_result(r, open))
02607 goto next_k;
02608 }
02609 }
02610 r = assign_r(t_a, a_k, ROUND_DOWN);
02611 if (propagate_constraint_check_result(r, open))
02612 goto next_k;
02613 r = div_assign_r(t_bound, t_bound, t_a, ROUND_DOWN);
02614 if (propagate_constraint_check_result(r, open))
02615 goto next_k;
02616
02617
02618 if (open == T_MAYBE
02619 && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1)
02620 open = T_YES;
02621 seq[k].add_constraint(i_constraint(open == T_YES ? GREATER_THAN : GREATER_OR_EQUAL, t_bound));
02622 reset_empty_up_to_date();
02623 }
02624 next_k:
02625 ;
02626 }
02627 }
02628
02629 #else // Alternative implementations for propagate_constraint_no_check.
02630
02631 template <typename ITV>
02632 void
02633 Box<ITV>::propagate_constraint_no_check(const Constraint& c) {
02634 PPL_ASSERT(c.space_dimension() <= space_dimension());
02635
02636 dimension_type c_space_dim = c.space_dimension();
02637 ITV k[c_space_dim];
02638 ITV p[c_space_dim];
02639 for (dimension_type i = c_space_dim; i-- > 0; ) {
02640 k[i] = c.coefficient(Variable(i));
02641 ITV& p_i = p[i];
02642 p_i = seq[i];
02643 p_i.mul_assign(p_i, k[i]);
02644 }
02645 const Coefficient& inhomogeneous_term = c.inhomogeneous_term();
02646 for (dimension_type i = c_space_dim; i-- > 0; ) {
02647 int sgn_coefficient_i = sgn(c.coefficient(Variable(i)));
02648 if (sgn_coefficient_i == 0)
02649 continue;
02650 ITV q(inhomogeneous_term);
02651 for (dimension_type j = c_space_dim; j-- > 0; ) {
02652 if (i == j)
02653 continue;
02654 q.add_assign(q, p[j]);
02655 }
02656 q.div_assign(q, k[i]);
02657 q.neg_assign(q);
02658 Relation_Symbol rel;
02659 switch (c.type()) {
02660 case Constraint::EQUALITY:
02661 rel = EQUAL;
02662 break;
02663 case Constraint::NONSTRICT_INEQUALITY:
02664 rel = (sgn_coefficient_i > 0) ? GREATER_OR_EQUAL : LESS_OR_EQUAL;
02665 break;
02666 case Constraint::STRICT_INEQUALITY:
02667 rel = (sgn_coefficient_i > 0) ? GREATER_THAN : LESS_THAN;
02668 break;
02669 }
02670 seq[i].add_constraint(i_constraint(rel, q));
02671
02672
02673
02674
02675
02676 if (seq[i].is_empty()) {
02677 set_empty();
02678 break;
02679 }
02680 }
02681
02682 PPL_ASSERT(OK());
02683 }
02684
02685 #endif // Alternative implementations for propagate_constraint_no_check.
02686
02687 template <typename ITV>
02688 void
02689 Box<ITV>
02690 ::propagate_constraints_no_check(const Constraint_System& cs,
02691 const dimension_type max_iterations) {
02692 const dimension_type space_dim = space_dimension();
02693 PPL_ASSERT(cs.space_dimension() <= space_dim);
02694
02695 const Constraint_System::const_iterator cs_begin = cs.begin();
02696 const Constraint_System::const_iterator cs_end = cs.end();
02697 const dimension_type cs_size = std::distance(cs_begin, cs_end);
02698 const dimension_type propagation_weight = cs_size * space_dim;
02699
02700 Sequence copy;
02701 bool changed;
02702 dimension_type num_iterations = 0;
02703 do {
02704 WEIGHT_BEGIN();
02705 ++num_iterations;
02706 copy = seq;
02707 for (Constraint_System::const_iterator i = cs_begin; i != cs_end; ++i)
02708 propagate_constraint_no_check(*i);
02709
02710 WEIGHT_ADD_MUL(40, propagation_weight);
02711
02712
02713
02714 maybe_abandon();
02715
02716
02717
02718 if (num_iterations == max_iterations)
02719 break;
02720
02721 changed = (copy != seq);
02722 } while (changed);
02723 }
02724
02725 template <typename ITV>
02726 void
02727 Box<ITV>::affine_image(const Variable var,
02728 const Linear_Expression& expr,
02729 Coefficient_traits::const_reference denominator) {
02730
02731 if (denominator == 0)
02732 throw_generic("affine_image(v, e, d)", "d == 0");
02733
02734
02735 const dimension_type space_dim = space_dimension();
02736 const dimension_type expr_space_dim = expr.space_dimension();
02737 if (space_dim < expr_space_dim)
02738 throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
02739
02740 const dimension_type var_space_dim = var.space_dimension();
02741 if (space_dim < var_space_dim)
02742 throw_dimension_incompatible("affine_image(v, e, d)", "v", var);
02743
02744 if (is_empty())
02745 return;
02746
02747 Tmp_Interval_Type expr_value, temp0, temp1;
02748 expr_value.assign(expr.inhomogeneous_term());
02749 for (dimension_type i = expr_space_dim; i-- > 0; ) {
02750 const Coefficient& coeff = expr.coefficient(Variable(i));
02751 if (coeff != 0) {
02752 temp0.assign(coeff);
02753 temp1.assign(seq[i]);
02754 temp0.mul_assign(temp0, temp1);
02755 expr_value.add_assign(expr_value, temp0);
02756 }
02757 }
02758 if (denominator != 1) {
02759 temp0.assign(denominator);
02760 expr_value.div_assign(expr_value, temp0);
02761 }
02762 seq[var.id()].assign(expr_value);
02763
02764 PPL_ASSERT(OK());
02765 }
02766
02767 template <typename ITV>
02768 void
02769 Box<ITV>::affine_preimage(const Variable var,
02770 const Linear_Expression& expr,
02771 Coefficient_traits::const_reference
02772 denominator) {
02773
02774 if (denominator == 0)
02775 throw_generic("affine_preimage(v, e, d)", "d == 0");
02776
02777
02778 const dimension_type x_space_dim = space_dimension();
02779 const dimension_type expr_space_dim = expr.space_dimension();
02780 if (x_space_dim < expr_space_dim)
02781 throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
02782
02783 const dimension_type var_space_dim = var.space_dimension();
02784 if (x_space_dim < var_space_dim)
02785 throw_dimension_incompatible("affine_preimage(v, e, d)", "v", var);
02786
02787 if (is_empty())
02788 return;
02789
02790 const Coefficient& expr_v = expr.coefficient(var);
02791 const bool invertible = (expr_v != 0);
02792 if (!invertible) {
02793 Tmp_Interval_Type expr_value, temp0, temp1;
02794 expr_value.assign(expr.inhomogeneous_term());
02795 for (dimension_type i = expr_space_dim; i-- > 0; ) {
02796 const Coefficient& coeff = expr.coefficient(Variable(i));
02797 if (coeff != 0) {
02798 temp0.assign(coeff);
02799 temp1.assign(seq[i]);
02800 temp0.mul_assign(temp0, temp1);
02801 expr_value.add_assign(expr_value, temp0);
02802 }
02803 }
02804 if (denominator != 1) {
02805 temp0.assign(denominator);
02806 expr_value.div_assign(expr_value, temp0);
02807 }
02808 ITV& x_seq_v = seq[var.id()];
02809 expr_value.intersect_assign(x_seq_v);
02810 if (expr_value.is_empty())
02811 set_empty();
02812 else
02813 x_seq_v.assign(UNIVERSE);
02814 }
02815 else {
02816
02817
02818
02819
02820 Linear_Expression inverse;
02821 inverse -= expr;
02822 inverse += (expr_v + denominator) * var;
02823 affine_image(var, inverse, expr_v);
02824 }
02825 PPL_ASSERT(OK());
02826 }
02827
02828 template <typename ITV>
02829 void
02830 Box<ITV>
02831 ::bounded_affine_image(const Variable var,
02832 const Linear_Expression& lb_expr,
02833 const Linear_Expression& ub_expr,
02834 Coefficient_traits::const_reference denominator) {
02835
02836 if (denominator == 0)
02837 throw_generic("bounded_affine_image(v, lb, ub, d)", "d == 0");
02838
02839
02840 const dimension_type space_dim = space_dimension();
02841
02842
02843 const dimension_type lb_space_dim = lb_expr.space_dimension();
02844 if (space_dim < lb_space_dim)
02845 throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02846 "lb", lb_expr);
02847 const dimension_type ub_space_dim = ub_expr.space_dimension();
02848 if (space_dim < ub_space_dim)
02849 throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02850 "ub", ub_expr);
02851
02852 const dimension_type var_space_dim = var.space_dimension();
02853 if (space_dim < var_space_dim)
02854 throw_dimension_incompatible("affine_image(v, e, d)", "v", var);
02855
02856
02857 if (is_empty())
02858 return;
02859
02860
02861 if (denominator > 0)
02862 refine_with_constraint(lb_expr <= ub_expr);
02863 else
02864 refine_with_constraint(lb_expr >= ub_expr);
02865
02866
02867 if (lb_expr.coefficient(var) == 0) {
02868
02869 generalized_affine_image(var,
02870 LESS_OR_EQUAL,
02871 ub_expr,
02872 denominator);
02873 if (denominator > 0)
02874 refine_with_constraint(lb_expr <= denominator*var);
02875 else
02876 refine_with_constraint(denominator*var <= lb_expr);
02877 }
02878 else if (ub_expr.coefficient(var) == 0) {
02879
02880 generalized_affine_image(var,
02881 GREATER_OR_EQUAL,
02882 lb_expr,
02883 denominator);
02884 if (denominator > 0)
02885 refine_with_constraint(denominator*var <= ub_expr);
02886 else
02887 refine_with_constraint(ub_expr <= denominator*var);
02888 }
02889 else {
02890
02891
02892
02893
02894 PPL_DIRTY_TEMP(Coefficient, max_num);
02895 PPL_DIRTY_TEMP(Coefficient, max_den);
02896 bool max_included;
02897 PPL_DIRTY_TEMP(Coefficient, min_num);
02898 PPL_DIRTY_TEMP(Coefficient, min_den);
02899 bool min_included;
02900 ITV& seq_v = seq[var.id()];
02901 if (maximize(ub_expr, max_num, max_den, max_included)) {
02902 if (minimize(lb_expr, min_num, min_den, min_included)) {
02903
02904
02905
02906 min_den *= denominator;
02907 PPL_DIRTY_TEMP0(mpq_class, q1);
02908 PPL_DIRTY_TEMP0(mpq_class, q2);
02909 assign_r(q1.get_num(), min_num, ROUND_NOT_NEEDED);
02910 assign_r(q1.get_den(), min_den, ROUND_NOT_NEEDED);
02911 q1.canonicalize();
02912
02913
02914 max_den *= denominator;
02915 assign_r(q2.get_num(), max_num, ROUND_NOT_NEEDED);
02916 assign_r(q2.get_den(), max_den, ROUND_NOT_NEEDED);
02917 q2.canonicalize();
02918 if (denominator > 0)
02919 seq_v.build(i_constraint(min_included ? GREATER_OR_EQUAL : GREATER_THAN, q1),
02920 i_constraint(max_included ? LESS_OR_EQUAL : LESS_THAN, q2));
02921 else
02922 seq_v.build(i_constraint(max_included ? GREATER_OR_EQUAL : GREATER_THAN, q2),
02923 i_constraint(min_included ? LESS_OR_EQUAL : LESS_THAN, q1));
02924 }
02925 else {
02926
02927
02928
02929 PPL_DIRTY_TEMP0(mpq_class, q);
02930 max_den *= denominator;
02931 assign_r(q.get_num(), max_num, ROUND_NOT_NEEDED);
02932 assign_r(q.get_den(), max_den, ROUND_NOT_NEEDED);
02933 q.canonicalize();
02934 if (denominator > 0)
02935 seq_v.build(i_constraint(max_included ? LESS_OR_EQUAL : LESS_THAN, q));
02936 else
02937 seq_v.build(i_constraint(max_included ? GREATER_OR_EQUAL : GREATER_THAN, q));
02938 }
02939 }
02940 else if (minimize(lb_expr, min_num, min_den, min_included)) {
02941
02942
02943
02944 min_den *= denominator;
02945 PPL_DIRTY_TEMP0(mpq_class, q);
02946 assign_r(q.get_num(), min_num, ROUND_NOT_NEEDED);
02947 assign_r(q.get_den(), min_den, ROUND_NOT_NEEDED);
02948 q.canonicalize();
02949 if (denominator > 0)
02950 seq_v.build(i_constraint(min_included ? GREATER_OR_EQUAL : GREATER_THAN, q));
02951 else
02952 seq_v.build(i_constraint(min_included ? LESS_OR_EQUAL : LESS_THAN, q));
02953 }
02954 else {
02955
02956
02957
02958 seq_v.assign(UNIVERSE);
02959 }
02960 }
02961 PPL_ASSERT(OK());
02962 }
02963
02964 template <typename ITV>
02965 void
02966 Box<ITV>
02967 ::bounded_affine_preimage(const Variable var,
02968 const Linear_Expression& lb_expr,
02969 const Linear_Expression& ub_expr,
02970 Coefficient_traits::const_reference denominator) {
02971
02972 const dimension_type space_dim = space_dimension();
02973 if (denominator == 0)
02974 throw_generic("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
02975
02976
02977
02978 const dimension_type var_space_dim = var.space_dimension();
02979 if (space_dim < var_space_dim)
02980 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
02981 "v", var);
02982
02983
02984 const dimension_type lb_space_dim = lb_expr.space_dimension();
02985 if (space_dim < lb_space_dim)
02986 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
02987 "lb", lb_expr);
02988 const dimension_type ub_space_dim = ub_expr.space_dimension();
02989 if (space_dim < ub_space_dim)
02990 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
02991 "ub", ub_expr);
02992
02993
02994 if (marked_empty())
02995 return;
02996
02997 const bool negative_denom = (denominator < 0);
02998 const Coefficient& lb_var_coeff = lb_expr.coefficient(var);
02999 const Coefficient& ub_var_coeff = ub_expr.coefficient(var);
03000
03001
03002
03003 if (lb_var_coeff == ub_var_coeff) {
03004 if (negative_denom)
03005 refine_with_constraint(lb_expr >= ub_expr);
03006 else
03007 refine_with_constraint(lb_expr <= ub_expr);
03008 }
03009
03010 ITV& seq_var = seq[var.id()];
03011 if (!seq_var.is_universe()) {
03012
03013
03014 PPL_DIRTY_TEMP_COEFFICIENT(pos_denominator);
03015 pos_denominator = denominator;
03016 if (negative_denom)
03017 neg_assign(pos_denominator, pos_denominator);
03018
03019
03020 bool open_lower = seq_var.lower_is_open();
03021 bool unbounded_lower = seq_var.lower_is_boundary_infinity();
03022 PPL_DIRTY_TEMP0(mpq_class, q_seq_var_lower);
03023 PPL_DIRTY_TEMP(Coefficient, num_lower);
03024 PPL_DIRTY_TEMP(Coefficient, den_lower);
03025 if (!unbounded_lower) {
03026 assign_r(q_seq_var_lower, seq_var.lower(), ROUND_NOT_NEEDED);
03027 assign_r(num_lower, q_seq_var_lower.get_num(), ROUND_NOT_NEEDED);
03028 assign_r(den_lower, q_seq_var_lower.get_den(), ROUND_NOT_NEEDED);
03029 if (negative_denom)
03030 neg_assign(den_lower, den_lower);
03031 num_lower *= pos_denominator;
03032 seq_var.lower_extend();
03033 }
03034 bool open_upper = seq_var.upper_is_open();
03035 bool unbounded_upper = seq_var.upper_is_boundary_infinity();
03036 PPL_DIRTY_TEMP0(mpq_class, q_seq_var_upper);
03037 PPL_DIRTY_TEMP(Coefficient, num_upper);
03038 PPL_DIRTY_TEMP(Coefficient, den_upper);
03039 if (!unbounded_upper) {
03040 assign_r(q_seq_var_upper, seq_var.upper(), ROUND_NOT_NEEDED);
03041 assign_r(num_upper, q_seq_var_upper.get_num(), ROUND_NOT_NEEDED);
03042 assign_r(den_upper, q_seq_var_upper.get_den(), ROUND_NOT_NEEDED);
03043 if (negative_denom)
03044 neg_assign(den_upper, den_upper);
03045 num_upper *= pos_denominator;
03046 seq_var.upper_extend();
03047 }
03048
03049 if (!unbounded_lower) {
03050
03051
03052
03053 Linear_Expression revised_lb_expr(ub_expr);
03054 revised_lb_expr -= ub_var_coeff * var;
03055 PPL_DIRTY_TEMP(Coefficient, d);
03056 neg_assign(d, den_lower);
03057 revised_lb_expr *= d;
03058 revised_lb_expr += num_lower;
03059
03060
03061
03062 bool included;
03063 PPL_DIRTY_TEMP(Coefficient, den);
03064 if (minimize(revised_lb_expr, num_lower, den, included)) {
03065 den_lower *= (den * ub_var_coeff);
03066 PPL_DIRTY_TEMP0(mpq_class, q);
03067 assign_r(q.get_num(), num_lower, ROUND_NOT_NEEDED);
03068 assign_r(q.get_den(), den_lower, ROUND_NOT_NEEDED);
03069 q.canonicalize();
03070 open_lower |= !included;
03071 if ((ub_var_coeff >= 0) ? !negative_denom : negative_denom)
03072 seq_var.add_constraint(i_constraint(open_lower ? GREATER_THAN : GREATER_OR_EQUAL, q));
03073 else
03074 seq_var.add_constraint(i_constraint(open_lower ? LESS_THAN : LESS_OR_EQUAL, q));
03075 if (seq_var.is_empty()) {
03076 set_empty();
03077 return;
03078 }
03079 }
03080 }
03081
03082 if (!unbounded_upper) {
03083
03084
03085
03086 Linear_Expression revised_ub_expr(lb_expr);
03087 revised_ub_expr -= lb_var_coeff * var;
03088 PPL_DIRTY_TEMP(Coefficient, d);
03089 neg_assign(d, den_upper);
03090 revised_ub_expr *= d;
03091 revised_ub_expr += num_upper;
03092
03093
03094
03095 bool included;
03096 PPL_DIRTY_TEMP(Coefficient, den);
03097 if (maximize(revised_ub_expr, num_upper, den, included)) {
03098 den_upper *= (den * lb_var_coeff);
03099 PPL_DIRTY_TEMP0(mpq_class, q);
03100 assign_r(q.get_num(), num_upper, ROUND_NOT_NEEDED);
03101 assign_r(q.get_den(), den_upper, ROUND_NOT_NEEDED);
03102 q.canonicalize();
03103 open_upper |= !included;
03104 if ((lb_var_coeff >= 0) ? !negative_denom : negative_denom)
03105 seq_var.add_constraint(i_constraint(open_upper ? LESS_THAN : LESS_OR_EQUAL, q));
03106 else
03107 seq_var.add_constraint(i_constraint(open_upper ? GREATER_THAN : GREATER_OR_EQUAL, q));
03108 if (seq_var.is_empty()) {
03109 set_empty();
03110 return;
03111 }
03112 }
03113 }
03114 }
03115
03116
03117
03118 if (lb_var_coeff != ub_var_coeff) {
03119 if (denominator > 0)
03120 refine_with_constraint(lb_expr <= ub_expr);
03121 else
03122 refine_with_constraint(lb_expr >= ub_expr);
03123 }
03124
03125 PPL_ASSERT(OK());
03126 }
03127
03128 template <typename ITV>
03129 void
03130 Box<ITV>
03131 ::generalized_affine_image(const Variable var,
03132 const Relation_Symbol relsym,
03133 const Linear_Expression& expr,
03134 Coefficient_traits::const_reference denominator) {
03135
03136 if (denominator == 0)
03137 throw_generic("generalized_affine_image(v, r, e, d)", "d == 0");
03138
03139
03140 const dimension_type space_dim = space_dimension();
03141
03142
03143 if (space_dim < expr.space_dimension())
03144 throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
03145 "e", expr);
03146
03147 const dimension_type var_space_dim = var.space_dimension();
03148 if (space_dim < var_space_dim)
03149 throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
03150 "v", var);
03151
03152
03153 if (relsym == NOT_EQUAL)
03154 throw_generic("generalized_affine_image(v, r, e, d)",
03155 "r is the disequality relation symbol");
03156
03157
03158 affine_image(var, expr, denominator);
03159
03160 if (relsym == EQUAL)
03161
03162 return;
03163
03164
03165 if (is_empty())
03166 return;
03167
03168 ITV& seq_var = seq[var.id()];
03169 switch (relsym) {
03170 case LESS_OR_EQUAL:
03171 seq_var.lower_extend();
03172 break;
03173 case LESS_THAN:
03174 seq_var.lower_extend();
03175 if (!seq_var.upper_is_boundary_infinity())
03176 seq_var.remove_sup();
03177 break;
03178 case GREATER_OR_EQUAL:
03179 seq_var.upper_extend();
03180 break;
03181 case GREATER_THAN:
03182 seq_var.upper_extend();
03183 if (!seq_var.lower_is_boundary_infinity())
03184 seq_var.remove_inf();
03185 break;
03186 default:
03187
03188 throw std::runtime_error("PPL internal error");
03189 }
03190 PPL_ASSERT(OK());
03191 }
03192
03193 template <typename ITV>
03194 void
03195 Box<ITV>
03196 ::generalized_affine_preimage(const Variable var,
03197 const Relation_Symbol relsym,
03198 const Linear_Expression& expr,
03199 Coefficient_traits::const_reference denominator)
03200 {
03201
03202 if (denominator == 0)
03203 throw_generic("generalized_affine_preimage(v, r, e, d)",
03204 "d == 0");
03205
03206
03207 const dimension_type space_dim = space_dimension();
03208
03209
03210 if (space_dim < expr.space_dimension())
03211 throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
03212 "e", expr);
03213
03214 const dimension_type var_space_dim = var.space_dimension();
03215 if (space_dim < var_space_dim)
03216 throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
03217 "v", var);
03218
03219 if (relsym == NOT_EQUAL)
03220 throw_generic("generalized_affine_preimage(v, r, e, d)",
03221 "r is the disequality relation symbol");
03222
03223
03224 if (relsym == EQUAL) {
03225 affine_preimage(var, expr, denominator);
03226 return;
03227 }
03228
03229
03230 Relation_Symbol reversed_relsym;
03231 switch (relsym) {
03232 case LESS_THAN:
03233 reversed_relsym = GREATER_THAN;
03234 break;
03235 case LESS_OR_EQUAL:
03236 reversed_relsym = GREATER_OR_EQUAL;
03237 break;
03238 case GREATER_OR_EQUAL:
03239 reversed_relsym = LESS_OR_EQUAL;
03240 break;
03241 case GREATER_THAN:
03242 reversed_relsym = LESS_THAN;
03243 break;
03244 default:
03245
03246 throw std::runtime_error("PPL internal error");
03247 }
03248
03249
03250
03251 const Coefficient& var_coefficient = expr.coefficient(var);
03252 if (var_coefficient != 0) {
03253 Linear_Expression inverse_expr
03254 = expr - (denominator + var_coefficient) * var;
03255 PPL_DIRTY_TEMP_COEFFICIENT(inverse_denominator);
03256 neg_assign(inverse_denominator, var_coefficient);
03257 Relation_Symbol inverse_relsym
03258 = (sgn(denominator) == sgn(inverse_denominator))
03259 ? relsym : reversed_relsym;
03260 generalized_affine_image(var, inverse_relsym, inverse_expr,
03261 inverse_denominator);
03262 return;
03263 }
03264
03265
03266
03267
03268
03269
03270
03271
03272 PPL_DIRTY_TEMP(Coefficient, max_num);
03273 PPL_DIRTY_TEMP(Coefficient, max_den);
03274 bool max_included;
03275 bool bound_above = maximize(denominator*var, max_num, max_den, max_included);
03276 PPL_DIRTY_TEMP(Coefficient, min_num);
03277 PPL_DIRTY_TEMP(Coefficient, min_den);
03278 bool min_included;
03279 bool bound_below = minimize(denominator*var, min_num, min_den, min_included);
03280
03281 const Relation_Symbol corrected_relsym
03282 = (denominator > 0) ? relsym : reversed_relsym;
03283
03284
03285 PPL_DIRTY_TEMP(Linear_Expression, revised_expr);
03286 dimension_type dim = space_dim;
03287 PPL_DIRTY_TEMP_COEFFICIENT(d);
03288 if (corrected_relsym == LESS_THAN || corrected_relsym == LESS_OR_EQUAL) {
03289 if (bound_below) {
03290 for ( ; dim > 0; dim--) {
03291 d = min_den * expr.coefficient(Variable(dim - 1));
03292 revised_expr += d * Variable(dim - 1);
03293 }
03294 }
03295 }
03296 else {
03297 if (bound_above) {
03298 for ( ; dim > 0; dim--) {
03299 d = max_den * expr.coefficient(Variable(dim - 1));
03300 revised_expr += d * Variable(dim - 1);
03301 }
03302 }
03303 }
03304
03305 switch (corrected_relsym) {
03306 case LESS_THAN:
03307 if (bound_below)
03308 refine_with_constraint(min_num < revised_expr);
03309 break;
03310 case LESS_OR_EQUAL:
03311 if (bound_below)
03312 (min_included)
03313 ? refine_with_constraint(min_num <= revised_expr)
03314 : refine_with_constraint(min_num < revised_expr);
03315 break;
03316 case GREATER_OR_EQUAL:
03317 if (bound_above)
03318 (max_included)
03319 ? refine_with_constraint(max_num >= revised_expr)
03320 : refine_with_constraint(max_num > revised_expr);
03321 break;
03322 case GREATER_THAN:
03323 if (bound_above)
03324 refine_with_constraint(max_num > revised_expr);
03325 break;
03326 default:
03327
03328 throw std::runtime_error("PPL internal error");
03329 }
03330
03331 if (is_empty())
03332 return;
03333 ITV& seq_v = seq[var.id()];
03334 seq_v.assign(UNIVERSE);
03335 PPL_ASSERT(OK());
03336 }
03337
03338 template <typename ITV>
03339 void
03340 Box<ITV>
03341 ::generalized_affine_image(const Linear_Expression& lhs,
03342 const Relation_Symbol relsym,
03343 const Linear_Expression& rhs) {
03344
03345
03346
03347 dimension_type lhs_space_dim = lhs.space_dimension();
03348 const dimension_type space_dim = space_dimension();
03349 if (space_dim < lhs_space_dim)
03350 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
03351 "e1", lhs);
03352
03353
03354 const dimension_type rhs_space_dim = rhs.space_dimension();
03355 if (space_dim < rhs_space_dim)
03356 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
03357 "e2", rhs);
03358
03359
03360 if (relsym == NOT_EQUAL)
03361 throw_generic("generalized_affine_image(e1, r, e2)",
03362 "r is the disequality relation symbol");
03363
03364
03365 if (marked_empty())
03366 return;
03367
03368
03369 PPL_DIRTY_TEMP(Coefficient, max_num);
03370 PPL_DIRTY_TEMP(Coefficient, max_den);
03371 bool max_included;
03372 bool max_rhs = maximize(rhs, max_num, max_den, max_included);
03373 PPL_DIRTY_TEMP(Coefficient, min_num);
03374 PPL_DIRTY_TEMP(Coefficient, min_den);
03375 bool min_included;
03376 bool min_rhs = minimize(rhs, min_num, min_den, min_included);
03377
03378
03379
03380
03381
03382 bool has_var = false;
03383 bool has_more_than_one_var = false;
03384
03385 dimension_type has_var_id = 0;
03386 for ( ; lhs_space_dim > 0; --lhs_space_dim)
03387 if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0) {
03388 if (has_var) {
03389 ITV& seq_i = seq[lhs_space_dim - 1];
03390 seq_i.assign(UNIVERSE);
03391 has_more_than_one_var = true;
03392 }
03393 else {
03394 has_var = true;
03395 has_var_id = lhs_space_dim - 1;
03396 }
03397 }
03398
03399 if (has_more_than_one_var) {
03400
03401
03402
03403
03404
03405 ITV& seq_var = seq[has_var_id];
03406 seq_var.assign(UNIVERSE);
03407 PPL_ASSERT(OK());
03408 return;
03409 }
03410
03411 if (has_var) {
03412
03413 ITV& seq_var = seq[has_var_id];
03414
03415
03416
03417 const Coefficient& inhomo = lhs.inhomogeneous_term();
03418 const Coefficient& coeff = lhs.coefficient(Variable(has_var_id));
03419 PPL_DIRTY_TEMP0(mpq_class, q_max);
03420 PPL_DIRTY_TEMP0(mpq_class, q_min);
03421 if (max_rhs) {
03422 max_num -= inhomo * max_den;
03423 max_den *= coeff;
03424 assign_r(q_max.get_num(), max_num, ROUND_NOT_NEEDED);
03425 assign_r(q_max.get_den(), max_den, ROUND_NOT_NEEDED);
03426 q_max.canonicalize();
03427 }
03428 if (min_rhs) {
03429 min_num -= inhomo * min_den;
03430 min_den *= coeff;
03431 assign_r(q_min.get_num(), min_num, ROUND_NOT_NEEDED);
03432 assign_r(q_min.get_den(), min_den, ROUND_NOT_NEEDED);
03433 q_min.canonicalize();
03434 }
03435
03436
03437
03438 if (coeff > 0)
03439
03440 switch (relsym) {
03441 case LESS_OR_EQUAL:
03442 max_rhs
03443 ? seq_var.build(i_constraint(max_included ? LESS_OR_EQUAL : LESS_THAN, q_max))
03444 : seq_var.assign(UNIVERSE);
03445 break;
03446 case LESS_THAN:
03447 max_rhs
03448 ? seq_var.build(i_constraint(LESS_THAN, q_max))
03449 : seq_var.assign(UNIVERSE);
03450 break;
03451 case EQUAL:
03452 {
03453 I_Constraint<mpq_class> l;
03454 I_Constraint<mpq_class> u;
03455 if (max_rhs)
03456 u.set(max_included ? LESS_OR_EQUAL : LESS_THAN, q_max);
03457 if (min_rhs)
03458 l.set(min_included ? GREATER_OR_EQUAL : GREATER_THAN, q_min);
03459 seq_var.build(l, u);
03460 break;
03461 }
03462 case GREATER_OR_EQUAL:
03463 min_rhs
03464 ? seq_var.build(i_constraint(min_included ? GREATER_OR_EQUAL : GREATER_THAN, q_min))
03465 : seq_var.assign(UNIVERSE);
03466 break;
03467 case GREATER_THAN:
03468 min_rhs
03469 ? seq_var.build(i_constraint(GREATER_THAN, q_min))
03470 : seq_var.assign(UNIVERSE);
03471 break;
03472 default:
03473
03474 throw std::runtime_error("PPL internal error");
03475 }
03476 else
03477
03478 switch (relsym) {
03479 case GREATER_OR_EQUAL:
03480 min_rhs
03481 ? seq_var.build(i_constraint(min_included ? LESS_OR_EQUAL : LESS_THAN, q_min))
03482 : seq_var.assign(UNIVERSE);
03483 break;
03484 case GREATER_THAN:
03485 min_rhs
03486 ? seq_var.build(i_constraint(LESS_THAN, q_min))
03487 : seq_var.assign(UNIVERSE);
03488 break;
03489 case EQUAL:
03490 {
03491 I_Constraint<mpq_class> l;
03492 I_Constraint<mpq_class> u;
03493 if (max_rhs)
03494 l.set(max_included ? GREATER_OR_EQUAL : GREATER_THAN, q_max);
03495 if (min_rhs)
03496 u.set(min_included ? LESS_OR_EQUAL : LESS_THAN, q_min);
03497 seq_var.build(l, u);
03498 break;
03499 }
03500 case LESS_OR_EQUAL:
03501 max_rhs
03502 ? seq_var.build(i_constraint(max_included ? GREATER_OR_EQUAL : GREATER_THAN, q_max))
03503 : seq_var.assign(UNIVERSE);
03504 break;
03505 case LESS_THAN:
03506 max_rhs
03507 ? seq_var.build(i_constraint(GREATER_THAN, q_max))
03508 : seq_var.assign(UNIVERSE);
03509 break;
03510 default:
03511
03512 throw std::runtime_error("PPL internal error");
03513 }
03514 }
03515
03516 else {
03517
03518
03519 const Coefficient& inhomo = lhs.inhomogeneous_term();
03520 switch (relsym) {
03521 case LESS_THAN:
03522 refine_with_constraint(inhomo < rhs);
03523 break;
03524 case LESS_OR_EQUAL:
03525 refine_with_constraint(inhomo <= rhs);
03526 break;
03527 case EQUAL:
03528 refine_with_constraint(inhomo == rhs);
03529 break;
03530 case GREATER_OR_EQUAL:
03531 refine_with_constraint(inhomo >= rhs);
03532 break;
03533 case GREATER_THAN:
03534 refine_with_constraint(inhomo > rhs);
03535 break;
03536 default:
03537
03538 throw std::runtime_error("PPL internal error");
03539 }
03540 }
03541 PPL_ASSERT(OK());
03542 }
03543
03544 template <typename ITV>
03545 void
03546 Box<ITV>::generalized_affine_preimage(const Linear_Expression& lhs,
03547 const Relation_Symbol relsym,
03548 const Linear_Expression& rhs) {
03549
03550
03551
03552 dimension_type lhs_space_dim = lhs.space_dimension();
03553 const dimension_type space_dim = space_dimension();
03554 if (space_dim < lhs_space_dim)
03555 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
03556 "e1", lhs);
03557
03558
03559 const dimension_type rhs_space_dim = rhs.space_dimension();
03560 if (space_dim < rhs_space_dim)
03561 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
03562 "e2", rhs);
03563
03564
03565 if (relsym == NOT_EQUAL)
03566 throw_generic("generalized_affine_image(e1, r, e2)",
03567 "r is the disequality relation symbol");
03568
03569
03570 if (marked_empty())
03571 return;
03572
03573
03574
03575
03576 Linear_Expression revised_lhs = lhs;
03577 Linear_Expression revised_rhs = rhs;
03578 for (dimension_type d = lhs_space_dim; d-- > 0; ) {
03579 const Variable& var = Variable(d);
03580 if (lhs.coefficient(var) != 0) {
03581 PPL_DIRTY_TEMP(Coefficient, temp);
03582 temp = rhs.coefficient(var) + lhs.coefficient(var);
03583 revised_rhs -= temp * var;
03584 revised_lhs -= temp * var;
03585 }
03586 }
03587 generalized_affine_image(revised_lhs, relsym, revised_rhs);
03588 PPL_ASSERT(OK());
03589 }
03590
03591 template <typename ITV>
03592 template <typename T, typename Iterator>
03593 typename Enable_If<Is_Same<T, Box<ITV> >::value
03594 && Is_Same_Or_Derived<Interval_Base, ITV>::value,
03595 void>::type
03596 Box<ITV>::CC76_widening_assign(const T& y, Iterator first, Iterator last) {
03597 if (y.is_empty())
03598 return;
03599
03600 for (dimension_type i = seq.size(); i-- > 0; )
03601 seq[i].CC76_widening_assign(y.seq[i], first, last);
03602
03603 PPL_ASSERT(OK());
03604 }
03605
03606 template <typename ITV>
03607 template <typename T>
03608 typename Enable_If<Is_Same<T, Box<ITV> >::value
03609 && Is_Same_Or_Derived<Interval_Base, ITV>::value,
03610 void>::type
03611 Box<ITV>::CC76_widening_assign(const T& y, unsigned* tp) {
03612 static typename ITV::boundary_type stop_points[] = {
03613 typename ITV::boundary_type(-2),
03614 typename ITV::boundary_type(-1),
03615 typename ITV::boundary_type(0),
03616 typename ITV::boundary_type(1),
03617 typename ITV::boundary_type(2)
03618 };
03619
03620 Box& x = *this;
03621
03622 if (tp != 0 && *tp > 0) {
03623 Box<ITV> x_tmp(x);
03624 x_tmp.CC76_widening_assign(y, 0);
03625
03626 if (!x.contains(x_tmp))
03627 --(*tp);
03628 return;
03629 }
03630 x.CC76_widening_assign(y,
03631 stop_points,
03632 stop_points
03633 + sizeof(stop_points)/sizeof(stop_points[0]));
03634 }
03635
03636 template <typename ITV>
03637 void
03638 Box<ITV>::get_limiting_box(const Constraint_System& cs,
03639 Box& limiting_box) const {
03640 const dimension_type cs_space_dim = cs.space_dimension();
03641
03642 PPL_ASSERT(cs_space_dim <= space_dimension());
03643
03644 for (Constraint_System::const_iterator cs_i = cs.begin(),
03645 cs_end = cs.end(); cs_i != cs_end; ++cs_i) {
03646 const Constraint& c = *cs_i;
03647 dimension_type c_num_vars = 0;
03648 dimension_type c_only_var = 0;
03649
03650 if (!extract_interval_constraint(c, cs_space_dim, c_num_vars, c_only_var))
03651 continue;
03652
03653 if (c_num_vars != 0) {
03654
03655
03656 const Coefficient& n = c.inhomogeneous_term();
03657 const Coefficient& d = c.coefficient(Variable(c_only_var));
03658 if (interval_relation(seq[c_only_var], c.type(), n, d)
03659 == Poly_Con_Relation::is_included())
03660 limiting_box.add_interval_constraint_no_check(c_only_var, c.type(),
03661 n, d);
03662 }
03663 }
03664 }
03665
03666 template <typename ITV>
03667 void
03668 Box<ITV>::limited_CC76_extrapolation_assign(const Box& y,
03669 const Constraint_System& cs,
03670 unsigned* tp) {
03671 Box& x = *this;
03672 const dimension_type space_dim = x.space_dimension();
03673
03674
03675 if (space_dim != y.space_dimension())
03676 throw_dimension_incompatible("limited_CC76_extrapolation_assign(y, cs)",
03677 y);
03678
03679 const dimension_type cs_space_dim = cs.space_dimension();
03680 if (space_dim < cs_space_dim)
03681 throw_constraint_incompatible("limited_CC76_extrapolation_assign(y, cs)");
03682
03683
03684
03685 if (space_dim == 0)
03686 return;
03687
03688 #ifndef NDEBUG
03689 {
03690
03691 const Box x_copy = *this;
03692 const Box y_copy = y;
03693 PPL_ASSERT(x_copy.contains(y_copy));
03694 }
03695 #endif
03696
03697
03698 if (marked_empty())
03699 return;
03700
03701 if (y.marked_empty())
03702 return;
03703
03704
03705
03706 Box limiting_box(space_dim, UNIVERSE);
03707 get_limiting_box(cs, limiting_box);
03708
03709 x.CC76_widening_assign(y, tp);
03710
03711
03712 intersection_assign(limiting_box);
03713 }
03714
03715 template <typename ITV>
03716 template <typename T>
03717 typename Enable_If<Is_Same<T, Box<ITV> >::value
03718 && Is_Same_Or_Derived<Interval_Base, ITV>::value,
03719 void>::type
03720 Box<ITV>::CC76_narrowing_assign(const T& y) {
03721 const dimension_type space_dim = space_dimension();
03722
03723
03724 if (space_dim != y.space_dimension())
03725 throw_dimension_incompatible("CC76_narrowing_assign(y)", y);
03726
03727 #ifndef NDEBUG
03728 {
03729
03730 const Box x_copy = *this;
03731 const Box y_copy = y;
03732 PPL_ASSERT(y_copy.contains(x_copy));
03733 }
03734 #endif
03735
03736
03737
03738 if (space_dim == 0)
03739 return;
03740
03741
03742 if (y.is_empty())
03743 return;
03744
03745 if (is_empty())
03746 return;
03747
03748
03749
03750 for (dimension_type i = space_dim; i-- > 0; ) {
03751 ITV& x_i = seq[i];
03752 const ITV& y_i = y.seq[i];
03753 if (!x_i.lower_is_boundary_infinity()
03754 && !y_i.lower_is_boundary_infinity()
03755 && x_i.lower() != y_i.lower())
03756 x_i.lower() = y_i.lower();
03757 if (!x_i.upper_is_boundary_infinity()
03758 && !y_i.upper_is_boundary_infinity()
03759 && x_i.upper() != y_i.upper())
03760 x_i.upper() = y_i.upper();
03761 }
03762 PPL_ASSERT(OK());
03763 }
03764
03765 template <typename ITV>
03766 Constraint_System
03767 Box<ITV>::constraints() const {
03768 Constraint_System cs;
03769 const dimension_type space_dim = space_dimension();
03770 if (space_dim == 0) {
03771 if (marked_empty())
03772 cs = Constraint_System::zero_dim_empty();
03773 }
03774 else if (marked_empty())
03775 cs.insert(0*Variable(space_dim-1) <= -1);
03776 else {
03777
03778
03779 cs.insert(0*Variable(space_dim-1) <= 0);
03780
03781 for (dimension_type k = 0; k < space_dim; ++k) {
03782 bool closed = false;
03783 PPL_DIRTY_TEMP(Coefficient, n);
03784 PPL_DIRTY_TEMP(Coefficient, d);
03785 if (get_lower_bound(k, closed, n, d)) {
03786 if (closed)
03787 cs.insert(d*Variable(k) >= n);
03788 else
03789 cs.insert(d*Variable(k) > n);
03790 }
03791 if (get_upper_bound(k, closed, n, d)) {
03792 if (closed)
03793 cs.insert(d*Variable(k) <= n);
03794 else
03795 cs.insert(d*Variable(k) < n);
03796 }
03797 }
03798 }
03799 return cs;
03800 }
03801
03802 template <typename ITV>
03803 Constraint_System
03804 Box<ITV>::minimized_constraints() const {
03805 Constraint_System cs;
03806 const dimension_type space_dim = space_dimension();
03807 if (space_dim == 0) {
03808 if (marked_empty())
03809 cs = Constraint_System::zero_dim_empty();
03810 }
03811
03812 else if (is_empty())
03813 cs.insert(0*Variable(space_dim-1) <= -1);
03814 else {
03815
03816
03817 cs.insert(0*Variable(space_dim-1) <= 0);
03818
03819 for (dimension_type k = 0; k < space_dim; ++k) {
03820 bool closed = false;
03821 PPL_DIRTY_TEMP(Coefficient, n);
03822 PPL_DIRTY_TEMP(Coefficient, d);
03823 if (get_lower_bound(k, closed, n, d)) {
03824 if (closed)
03825
03826 if (seq[k].is_singleton()) {
03827 cs.insert(d*Variable(k) == n);
03828 continue;
03829 }
03830 else
03831 cs.insert(d*Variable(k) >= n);
03832 else
03833 cs.insert(d*Variable(k) > n);
03834 }
03835 if (get_upper_bound(k, closed, n, d)) {
03836 if (closed)
03837 cs.insert(d*Variable(k) <= n);
03838 else
03839 cs.insert(d*Variable(k) < n);
03840 }
03841 }
03842 }
03843 return cs;
03844 }
03845
03846 template <typename ITV>
03847 Congruence_System
03848 Box<ITV>::congruences() const {
03849 Congruence_System cgs;
03850 const dimension_type space_dim = space_dimension();
03851 if (space_dim == 0) {
03852 if (marked_empty())
03853 cgs = Congruence_System::zero_dim_empty();
03854 }
03855
03856 else if (is_empty())
03857 cgs.insert((0*Variable(space_dim-1) %= -1) / 0);
03858 else {
03859
03860
03861 cgs.insert(0*Variable(space_dim-1) %= 0);
03862
03863 for (dimension_type k = 0; k < space_dim; ++k) {
03864 bool closed = false;
03865 PPL_DIRTY_TEMP(Coefficient, n);
03866 PPL_DIRTY_TEMP(Coefficient, d);
03867 if (get_lower_bound(k, closed, n, d) && closed)
03868
03869 if (seq[k].is_singleton())
03870 cgs.insert((d*Variable(k) %= n) / 0);
03871 }
03872 }
03873 return cgs;
03874 }
03875
03876 template <typename ITV>
03877 memory_size_type
03878 Box<ITV>::external_memory_in_bytes() const {
03879 memory_size_type n = seq.capacity() * sizeof(ITV);
03880 for (dimension_type k = seq.size(); k-- > 0; )
03881 n += seq[k].external_memory_in_bytes();
03882 return n;
03883 }
03884
03886 template <typename ITV>
03887 std::ostream&
03888 IO_Operators::operator<<(std::ostream& s, const Box<ITV>& box) {
03889 if (box.is_empty())
03890 s << "false";
03891 else if (box.is_universe())
03892 s << "true";
03893 else
03894 for (dimension_type k = 0,
03895 space_dim = box.space_dimension(); k < space_dim; ) {
03896 s << Variable(k) << " in " << box[k];
03897 ++k;
03898 if (k < space_dim)
03899 s << ", ";
03900 else
03901 break;
03902 }
03903 return s;
03904 }
03905
03906 template <typename ITV>
03907 void
03908 Box<ITV>::ascii_dump(std::ostream& s) const {
03909 const char separator = ' ';
03910 status.ascii_dump(s);
03911 const dimension_type space_dim = space_dimension();
03912 s << "space_dim" << separator << space_dim;
03913 s << "\n";
03914 for (dimension_type i = 0; i < space_dim; ++i)
03915 seq[i].ascii_dump(s);
03916 }
03917
03918 PPL_OUTPUT_TEMPLATE_DEFINITIONS(ITV, Box<ITV>)
03919
03920 template <typename ITV>
03921 bool
03922 Box<ITV>::ascii_load(std::istream& s) {
03923 if (!status.ascii_load(s))
03924 return false;
03925
03926 std::string str;
03927 dimension_type space_dim;
03928 if (!(s >> str) || str != "space_dim")
03929 return false;
03930 if (!(s >> space_dim))
03931 return false;
03932
03933 seq.clear();
03934 ITV seq_i;
03935 for (dimension_type i = 0; i < space_dim; ++i) {
03936 if (seq_i.ascii_load(s))
03937 seq.push_back(seq_i);
03938 else
03939 return false;
03940 }
03941
03942
03943 PPL_ASSERT(OK());
03944 return true;
03945 }
03946
03947 template <typename ITV>
03948 void
03949 Box<ITV>::throw_dimension_incompatible(const char* method,
03950 const Box& y) const {
03951 std::ostringstream s;
03952 s << "PPL::Box::" << method << ":" << std::endl
03953 << "this->space_dimension() == " << this->space_dimension()
03954 << ", y->space_dimension() == " << y.space_dimension() << ".";
03955 throw std::invalid_argument(s.str());
03956 }
03957
03958 template <typename ITV>
03959 void
03960 Box<ITV>
03961 ::throw_dimension_incompatible(const char* method,
03962 dimension_type required_dim) const {
03963 std::ostringstream s;
03964 s << "PPL::Box::" << method << ":" << std::endl
03965 << "this->space_dimension() == " << space_dimension()
03966 << ", required dimension == " << required_dim << ".";
03967 throw std::invalid_argument(s.str());
03968 }
03969
03970 template <typename ITV>
03971 void
03972 Box<ITV>::throw_dimension_incompatible(const char* method,
03973 const Constraint& c) const {
03974 std::ostringstream s;
03975 s << "PPL::Box::" << method << ":" << std::endl
03976 << "this->space_dimension() == " << space_dimension()
03977 << ", c->space_dimension == " << c.space_dimension() << ".";
03978 throw std::invalid_argument(s.str());
03979 }
03980
03981 template <typename ITV>
03982 void
03983 Box<ITV>::throw_dimension_incompatible(const char* method,
03984 const Congruence& cg) const {
03985 std::ostringstream s;
03986 s << "PPL::Box::" << method << ":" << std::endl
03987 << "this->space_dimension() == " << space_dimension()
03988 << ", cg->space_dimension == " << cg.space_dimension() << ".";
03989 throw std::invalid_argument(s.str());
03990 }
03991
03992 template <typename ITV>
03993 void
03994 Box<ITV>::throw_dimension_incompatible(const char* method,
03995 const Constraint_System& cs) const {
03996 std::ostringstream s;
03997 s << "PPL::Box::" << method << ":" << std::endl
03998 << "this->space_dimension() == " << space_dimension()
03999 << ", cs->space_dimension == " << cs.space_dimension() << ".";
04000 throw std::invalid_argument(s.str());
04001 }
04002
04003 template <typename ITV>
04004 void
04005 Box<ITV>::throw_dimension_incompatible(const char* method,
04006 const Congruence_System& cgs) const {
04007 std::ostringstream s;
04008 s << "PPL::Box::" << method << ":" << std::endl
04009 << "this->space_dimension() == " << space_dimension()
04010 << ", cgs->space_dimension == " << cgs.space_dimension() << ".";
04011 throw std::invalid_argument(s.str());
04012 }
04013
04014 template <typename ITV>
04015 void
04016 Box<ITV>::throw_dimension_incompatible(const char* method,
04017 const Generator& g) const {
04018 std::ostringstream s;
04019 s << "PPL::Box::" << method << ":" << std::endl
04020 << "this->space_dimension() == " << space_dimension()
04021 << ", g->space_dimension == " << g.space_dimension() << ".";
04022 throw std::invalid_argument(s.str());
04023 }
04024
04025 template <typename ITV>
04026 void
04027 Box<ITV>::throw_constraint_incompatible(const char* method) {
04028 std::ostringstream s;
04029 s << "PPL::Box::" << method << ":" << std::endl
04030 << "the constraint is incompatible.";
04031 throw std::invalid_argument(s.str());
04032 }
04033
04034 template <typename ITV>
04035 void
04036 Box<ITV>::throw_expression_too_complex(const char* method,
04037 const Linear_Expression& e) {
04038 using namespace IO_Operators;
04039 std::ostringstream s;
04040 s << "PPL::Box::" << method << ":" << std::endl
04041 << e << " is too complex.";
04042 throw std::invalid_argument(s.str());
04043 }
04044
04045 template <typename ITV>
04046 void
04047 Box<ITV>::throw_dimension_incompatible(const char* method,
04048 const char* name_row,
04049 const Linear_Expression& e) const {
04050 std::ostringstream s;
04051 s << "PPL::Box::" << method << ":" << std::endl
04052 << "this->space_dimension() == " << space_dimension()
04053 << ", " << name_row << "->space_dimension() == "
04054 << e.space_dimension() << ".";
04055 throw std::invalid_argument(s.str());
04056 }
04057
04058 template <typename ITV>
04059 void
04060 Box<ITV>::throw_generic(const char* method, const char* reason) {
04061 std::ostringstream s;
04062 s << "PPL::Box::" << method << ":" << std::endl
04063 << reason;
04064 throw std::invalid_argument(s.str());
04065 }
04066
04067 template <typename ITV>
04068 void
04069 Box<ITV>::throw_space_dimension_overflow(const char* method,
04070 const char* reason) {
04071 std::ostringstream s;
04072 s << "PPL::Box::" << method << ":" << std::endl
04073 << reason;
04074 throw std::length_error(s.str());
04075 }
04076
04077 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
04078
04079 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
04080 template <typename Specialization,
04081 typename Temp, typename To, typename ITV>
04082 bool
04083 l_m_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
04084 const Box<ITV>& x, const Box<ITV>& y,
04085 const Rounding_Dir dir,
04086 Temp& tmp0, Temp& tmp1, Temp& tmp2) {
04087 const dimension_type x_space_dim = x.space_dimension();
04088
04089 if (x_space_dim != y.space_dimension())
04090 return false;
04091
04092
04093 if (x_space_dim == 0) {
04094 if (x.marked_empty() == y.marked_empty())
04095 assign_r(r, 0, ROUND_NOT_NEEDED);
04096 else
04097 assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
04098 return true;
04099 }
04100
04101
04102 (void) x.is_empty();
04103 (void) y.is_empty();
04104
04105
04106 if (x.marked_empty() || y.marked_empty()) {
04107 if (x.marked_empty() == y.marked_empty()) {
04108 assign_r(r, 0, ROUND_NOT_NEEDED);
04109 return true;
04110 }
04111 else
04112 goto pinf;
04113 }
04114
04115 assign_r(tmp0, 0, ROUND_NOT_NEEDED);
04116 for (dimension_type i = x_space_dim; i-- > 0; ) {
04117 const ITV& x_i = x.seq[i];
04118 const ITV& y_i = y.seq[i];
04119
04120 if (x_i.lower_is_boundary_infinity()) {
04121 if (!y_i.lower_is_boundary_infinity())
04122 goto pinf;
04123 }
04124 else if (y_i.lower_is_boundary_infinity())
04125 goto pinf;
04126 else {
04127 const Temp* tmp1p;
04128 const Temp* tmp2p;
04129 if (x_i.lower() > y_i.lower()) {
04130 maybe_assign(tmp1p, tmp1, x_i.lower(), dir);
04131 maybe_assign(tmp2p, tmp2, y_i.lower(), inverse(dir));
04132 }
04133 else {
04134 maybe_assign(tmp1p, tmp1, y_i.lower(), dir);
04135 maybe_assign(tmp2p, tmp2, x_i.lower(), inverse(dir));
04136 }
04137 sub_assign_r(tmp1, *tmp1p, *tmp2p, dir);
04138 PPL_ASSERT(sgn(tmp1) >= 0);
04139 Specialization::combine(tmp0, tmp1, dir);
04140 }
04141
04142 if (x_i.upper_is_boundary_infinity())
04143 if (y_i.upper_is_boundary_infinity())
04144 continue;
04145 else
04146 goto pinf;
04147 else if (y_i.upper_is_boundary_infinity())
04148 goto pinf;
04149 else {
04150 const Temp* tmp1p;
04151 const Temp* tmp2p;
04152 if (x_i.upper() > y_i.upper()) {
04153 maybe_assign(tmp1p, tmp1, x_i.upper(), dir);
04154 maybe_assign(tmp2p, tmp2, y_i.upper(), inverse(dir));
04155 }
04156 else {
04157 maybe_assign(tmp1p, tmp1, y_i.upper(), dir);
04158 maybe_assign(tmp2p, tmp2, x_i.upper(), inverse(dir));
04159 }
04160 sub_assign_r(tmp1, *tmp1p, *tmp2p, dir);
04161 PPL_ASSERT(sgn(tmp1) >= 0);
04162 Specialization::combine(tmp0, tmp1, dir);
04163 }
04164 }
04165 Specialization::finalize(tmp0, dir);
04166 assign_r(r, tmp0, dir);
04167 return true;
04168
04169 pinf:
04170 assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
04171 return true;
04172 }
04173
04174 }
04175
04176 #endif // !defined(PPL_Box_templates_hh)