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_Octagonal_Shape_templates_hh
00025 #define PPL_Octagonal_Shape_templates_hh 1
00026
00027 #include "Generator_System.defs.hh"
00028 #include "Generator_System.inlines.hh"
00029 #include "Congruence_System.defs.hh"
00030 #include "Congruence_System.inlines.hh"
00031 #include "meta_programming.hh"
00032 #include "assert.hh"
00033 #include <vector>
00034 #include <deque>
00035 #include <string>
00036 #include <iostream>
00037 #include <sstream>
00038 #include <stdexcept>
00039 #include <algorithm>
00040
00041 namespace Parma_Polyhedra_Library {
00042
00043 template <typename T>
00044 Octagonal_Shape<T>::Octagonal_Shape(const Polyhedron& ph,
00045 const Complexity_Class complexity)
00046 : matrix(0), space_dim(0), status() {
00047 const dimension_type num_dimensions = ph.space_dimension();
00048
00049 if (ph.marked_empty()) {
00050 *this = Octagonal_Shape(num_dimensions, EMPTY);
00051 return;
00052 }
00053
00054 if (num_dimensions == 0) {
00055 *this = Octagonal_Shape(num_dimensions, UNIVERSE);
00056 return;
00057 }
00058
00059
00060
00061 if (complexity == ANY_COMPLEXITY
00062 || (!ph.has_pending_constraints() && ph.generators_are_up_to_date())) {
00063 *this = Octagonal_Shape(ph.generators());
00064 return;
00065 }
00066
00067
00068
00069
00070 PPL_ASSERT(ph.constraints_are_up_to_date());
00071
00072 if (!ph.has_something_pending() && ph.constraints_are_minimized()) {
00073
00074
00075 if (ph.is_universe()) {
00076 *this = Octagonal_Shape(num_dimensions, UNIVERSE);
00077 return;
00078 }
00079 }
00080
00081
00082 for (Constraint_System::const_iterator i = ph.con_sys.begin(),
00083 cs_end = ph.con_sys.end(); i != cs_end; ++i)
00084 if (i->is_inconsistent()) {
00085 *this = Octagonal_Shape(num_dimensions, EMPTY);
00086 return;
00087 }
00088
00089
00090
00091 if (complexity == SIMPLEX_COMPLEXITY) {
00092 MIP_Problem lp(num_dimensions);
00093 lp.set_optimization_mode(MAXIMIZATION);
00094
00095 const Constraint_System& ph_cs = ph.constraints();
00096 if (!ph_cs.has_strict_inequalities())
00097 lp.add_constraints(ph_cs);
00098 else
00099
00100 for (Constraint_System::const_iterator i = ph_cs.begin(),
00101 ph_cs_end = ph_cs.end(); i != ph_cs_end; ++i) {
00102 const Constraint& c = *i;
00103 if (c.is_strict_inequality())
00104 lp.add_constraint(Linear_Expression(c) >= 0);
00105 else
00106 lp.add_constraint(c);
00107 }
00108
00109
00110 if (!lp.is_satisfiable()) {
00111 *this = Octagonal_Shape<T>(num_dimensions, EMPTY);
00112 return;
00113 }
00114
00115
00116 *this = Octagonal_Shape<T>(num_dimensions, UNIVERSE);
00117
00118 Generator g(point());
00119 PPL_DIRTY_TEMP_COEFFICIENT(num);
00120 PPL_DIRTY_TEMP_COEFFICIENT(den);
00121 for (dimension_type i = 0; i < num_dimensions; ++i) {
00122 Variable x(i);
00123
00124 lp.set_objective_function(x);
00125 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
00126 g = lp.optimizing_point();
00127 lp.evaluate_objective_function(g, num, den);
00128 num *= 2;
00129 div_round_up(matrix[2*i+1][2*i], num, den);
00130 }
00131
00132 for (dimension_type j = 0; j < i; ++j) {
00133 Variable y(j);
00134 lp.set_objective_function(x + y);
00135 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
00136 g = lp.optimizing_point();
00137 lp.evaluate_objective_function(g, num, den);
00138 div_round_up(matrix[2*i+1][2*j], num, den);
00139 }
00140 }
00141
00142 for (dimension_type j = 0; j < num_dimensions; ++j) {
00143 if (i == j)
00144 continue;
00145 Variable y(j);
00146 lp.set_objective_function(x - y);
00147 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
00148 g = lp.optimizing_point();
00149 lp.evaluate_objective_function(g, num, den);
00150 div_round_up((i < j ? matrix[2*j][2*i] : matrix[2*i+1][2*j+1]),
00151 num, den);
00152 }
00153 }
00154
00155 for (dimension_type j = 0; j < num_dimensions; ++j) {
00156 if (i == j)
00157 continue;
00158 Variable y(j);
00159 lp.set_objective_function(x - y);
00160 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
00161 g = lp.optimizing_point();
00162 lp.evaluate_objective_function(g, num, den);
00163 div_round_up((i < j ? matrix[2*j][2*i] : matrix[2*i+1][2*j+1]),
00164 num, den);
00165 }
00166 }
00167
00168 for (dimension_type j = 0; j < i; ++j) {
00169 Variable y(j);
00170 lp.set_objective_function(-x - y);
00171 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
00172 g = lp.optimizing_point();
00173 lp.evaluate_objective_function(g, num, den);
00174 div_round_up(matrix[2*i][2*j+1], num, den);
00175 }
00176 }
00177
00178 lp.set_objective_function(-x);
00179 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
00180 g = lp.optimizing_point();
00181 lp.evaluate_objective_function(g, num, den);
00182 num *= 2;
00183 div_round_up(matrix[2*i][2*i+1], num, den);
00184 }
00185 }
00186 set_strongly_closed();
00187 PPL_ASSERT(OK());
00188 return;
00189 }
00190
00191
00192 PPL_ASSERT(complexity == POLYNOMIAL_COMPLEXITY);
00193 *this = Octagonal_Shape(num_dimensions, UNIVERSE);
00194 refine_with_constraints(ph.constraints());
00195 }
00196
00197 template <typename T>
00198 Octagonal_Shape<T>::Octagonal_Shape(const Generator_System& gs)
00199 : matrix(gs.space_dimension()),
00200 space_dim(gs.space_dimension()),
00201 status() {
00202 const Generator_System::const_iterator gs_begin = gs.begin();
00203 const Generator_System::const_iterator gs_end = gs.end();
00204 if (gs_begin == gs_end) {
00205
00206 set_empty();
00207 return;
00208 }
00209
00210 typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
00211 typename OR_Matrix<N>::row_iterator mat_begin = matrix.row_begin();
00212
00213 PPL_DIRTY_TEMP(N, tmp);
00214 bool mat_initialized = false;
00215 bool point_seen = false;
00216
00217 for (Generator_System::const_iterator k = gs_begin; k != gs_end; ++k) {
00218 const Generator& g = *k;
00219 switch (g.type()) {
00220 case Generator::POINT:
00221 point_seen = true;
00222
00223 case Generator::CLOSURE_POINT:
00224 if (!mat_initialized) {
00225
00226 mat_initialized = true;
00227 const Coefficient& d = g.divisor();
00228 for (dimension_type i = 0; i < space_dim; ++i) {
00229 const Coefficient& g_i = g.coefficient(Variable(i));
00230 const dimension_type di = 2*i;
00231 Row_Reference x_i = *(mat_begin+di);
00232 Row_Reference x_ii = *(mat_begin+di+1);
00233 for (dimension_type j = 0; j < i; ++j) {
00234 const Coefficient& g_j = g.coefficient(Variable(j));
00235 const dimension_type dj = 2*j;
00236
00237
00238
00239
00240 div_round_up(x_i[dj], g_j - g_i, d);
00241 div_round_up(x_ii[dj+1], g_i - g_j, d);
00242
00243 div_round_up(x_i[dj+1], -g_j - g_i, d);
00244 div_round_up(x_ii[dj], g_i + g_j, d);
00245 }
00246
00247 div_round_up(x_i[di+1], -g_i - g_i, d);
00248 div_round_up(x_ii[di], g_i + g_i, d);
00249 }
00250 }
00251 else {
00252
00253
00254 const Coefficient& d = g.divisor();
00255 for (dimension_type i = 0; i < space_dim; ++i) {
00256 const Coefficient& g_i = g.coefficient(Variable(i));
00257 const dimension_type di = 2*i;
00258 Row_Reference x_i = *(mat_begin+di);
00259 Row_Reference x_ii = *(mat_begin+di+1);
00260 for (dimension_type j = 0; j < i; ++j) {
00261 const Coefficient& g_j = g.coefficient(Variable(j));
00262 const dimension_type dj = 2*j;
00263
00264
00265
00266
00267 div_round_up(tmp, g_j - g_i, d);
00268 max_assign(x_i[dj], tmp);
00269 div_round_up(tmp, g_i - g_j, d);
00270 max_assign(x_ii[dj+1], tmp);
00271
00272 div_round_up(tmp, -g_j - g_i, d);
00273 max_assign(x_i[dj+1], tmp);
00274 div_round_up(tmp, g_i + g_j, d);
00275 max_assign(x_ii[dj], tmp);
00276 }
00277
00278 div_round_up(tmp, -g_i - g_i, d);
00279 max_assign(x_i[di+1], tmp);
00280 div_round_up(tmp, g_i + g_i, d);
00281 max_assign(x_ii[di], tmp);
00282 }
00283 }
00284 break;
00285 default:
00286
00287 break;
00288 }
00289 }
00290
00291 if (!point_seen)
00292
00293 throw_generic("Octagonal_Shape(gs)",
00294 "the non-empty generator system gs contains no points.");
00295
00296
00297 for (Generator_System::const_iterator k = gs_begin; k != gs_end; ++k) {
00298 const Generator& g = *k;
00299 switch (g.type()) {
00300 case Generator::LINE:
00301 for (dimension_type i = 0; i < space_dim; ++i) {
00302 const Coefficient& g_i = g.coefficient(Variable(i));
00303 const dimension_type di = 2*i;
00304 Row_Reference x_i = *(mat_begin+di);
00305 Row_Reference x_ii = *(mat_begin+di+1);
00306 for (dimension_type j = 0; j < i; ++j) {
00307 const Coefficient& g_j = g.coefficient(Variable(j));
00308 const dimension_type dj = 2*j;
00309
00310 if (g_i != g_j) {
00311
00312 assign_r(x_i[dj], PLUS_INFINITY, ROUND_NOT_NEEDED);
00313 assign_r(x_ii[dj+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
00314 }
00315 if (g_i != -g_j) {
00316
00317 assign_r(x_i[dj+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
00318 assign_r(x_ii[dj], PLUS_INFINITY, ROUND_NOT_NEEDED);
00319 }
00320 }
00321 if (g_i != 0) {
00322
00323 assign_r(x_i[di+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
00324 assign_r(x_ii[di], PLUS_INFINITY, ROUND_NOT_NEEDED);
00325 }
00326 }
00327 break;
00328 case Generator::RAY:
00329 for (dimension_type i = 0; i < space_dim; ++i) {
00330 const Coefficient& g_i = g.coefficient(Variable(i));
00331 const dimension_type di = 2*i;
00332 Row_Reference x_i = *(mat_begin+di);
00333 Row_Reference x_ii = *(mat_begin+di+1);
00334 for (dimension_type j = 0; j < i; ++j) {
00335 const Coefficient& g_j = g.coefficient(Variable(j));
00336 const dimension_type dj = 2*j;
00337
00338
00339 if (g_i < g_j)
00340
00341 assign_r(x_i[dj], PLUS_INFINITY, ROUND_NOT_NEEDED);
00342 if (g_i > g_j)
00343
00344 assign_r(x_ii[dj+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
00345 if (g_i < -g_j)
00346
00347 assign_r(x_i[dj+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
00348 if (g_i > -g_j)
00349
00350 assign_r(x_ii[dj], PLUS_INFINITY, ROUND_NOT_NEEDED);
00351 }
00352
00353 if (g_i < 0)
00354
00355 assign_r(x_i[di+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
00356 if (g_i > 0)
00357
00358 assign_r(x_ii[di], PLUS_INFINITY, ROUND_NOT_NEEDED);
00359 }
00360 break;
00361 default:
00362
00363 break;
00364 }
00365 }
00366 set_strongly_closed();
00367 PPL_ASSERT(OK());
00368 }
00369
00370 template <typename T>
00371 void
00372 Octagonal_Shape<T>::add_constraint(const Constraint& c) {
00373 const dimension_type c_space_dim = c.space_dimension();
00374
00375 if (c_space_dim > space_dim)
00376 throw_dimension_incompatible("add_constraint(c)", c);
00377
00378
00379 if (c.is_strict_inequality()) {
00380 if (c.is_inconsistent()) {
00381 set_empty();
00382 return;
00383 }
00384 if (c.is_tautological())
00385 return;
00386
00387 throw_generic("add_constraint(c)", "strict inequalities are not allowed");
00388 }
00389
00390 dimension_type num_vars = 0;
00391 dimension_type i = 0;
00392 dimension_type j = 0;
00393 PPL_DIRTY_TEMP_COEFFICIENT(coeff);
00394 PPL_DIRTY_TEMP_COEFFICIENT(term);
00395
00396 if (!extract_octagonal_difference(c, c_space_dim, num_vars,
00397 i, j, coeff, term))
00398 throw_generic("add_constraint(c)",
00399 "c is not an octagonal constraint");
00400
00401 if (num_vars == 0) {
00402
00403 if (c.inhomogeneous_term() < 0
00404 || (c.is_equality() && c.inhomogeneous_term() != 0))
00405 set_empty();
00406 return;
00407 }
00408
00409
00410 typename OR_Matrix<N>::row_iterator i_iter = matrix.row_begin() + i;
00411 typename OR_Matrix<N>::row_reference_type m_i = *i_iter;
00412 N& m_i_j = m_i[j];
00413
00414 if (coeff < 0)
00415 neg_assign(coeff);
00416
00417 bool is_oct_changed = false;
00418
00419 PPL_DIRTY_TEMP(N, d);
00420 div_round_up(d, term, coeff);
00421 if (m_i_j > d) {
00422 m_i_j = d;
00423 is_oct_changed = true;
00424 }
00425
00426 if (c.is_equality()) {
00427
00428 if (i % 2 == 0)
00429 ++i_iter;
00430 else
00431 --i_iter;
00432
00433 typename OR_Matrix<N>::row_reference_type m_ci = *i_iter;
00434 using namespace Implementation::Octagonal_Shapes;
00435 dimension_type cj = coherent_index(j);
00436 N& m_ci_cj = m_ci[cj];
00437
00438 neg_assign(term);
00439 div_round_up(d, term, coeff);
00440 if (m_ci_cj > d) {
00441 m_ci_cj = d;
00442 is_oct_changed = true;
00443 }
00444 }
00445
00446
00447 if (is_oct_changed && marked_strongly_closed())
00448 reset_strongly_closed();
00449 PPL_ASSERT(OK());
00450 }
00451
00452 template <typename T>
00453 void
00454 Octagonal_Shape<T>::add_congruence(const Congruence& cg) {
00455 const dimension_type cg_space_dim = cg.space_dimension();
00456
00457
00458 if (space_dimension() < cg_space_dim)
00459 throw_dimension_incompatible("add_congruence(cg)", cg);
00460
00461
00462 if (cg.is_proper_congruence()) {
00463 if (cg.is_tautological())
00464 return;
00465 if (cg.is_inconsistent()) {
00466 set_empty();
00467 return;
00468 }
00469
00470 throw_generic("add_congruence(cg)",
00471 "cg is a non-trivial, proper congruence");
00472 }
00473
00474 PPL_ASSERT(cg.is_equality());
00475 Constraint c(cg);
00476 add_constraint(c);
00477 }
00478
00479 template <typename T>
00480 void
00481 Octagonal_Shape<T>::refine_no_check(const Constraint& c) {
00482 PPL_ASSERT(!marked_empty());
00483 const dimension_type c_space_dim = c.space_dimension();
00484 PPL_ASSERT(c_space_dim <= space_dim);
00485
00486 dimension_type num_vars = 0;
00487 dimension_type i = 0;
00488 dimension_type j = 0;
00489 PPL_DIRTY_TEMP_COEFFICIENT(coeff);
00490 PPL_DIRTY_TEMP_COEFFICIENT(term);
00491
00492 if (!extract_octagonal_difference(c, c_space_dim, num_vars,
00493 i, j, coeff, term))
00494 return;
00495
00496 if (num_vars == 0) {
00497 const Coefficient& c_inhomo = c.inhomogeneous_term();
00498
00499 if (c_inhomo < 0
00500 || (c_inhomo != 0 && c.is_equality())
00501 || (c_inhomo == 0 && c.is_strict_inequality()))
00502 set_empty();
00503 return;
00504 }
00505
00506
00507 typename OR_Matrix<N>::row_iterator i_iter = matrix.row_begin() + i;
00508 typename OR_Matrix<N>::row_reference_type m_i = *i_iter;
00509 N& m_i_j = m_i[j];
00510
00511 if (coeff < 0)
00512 neg_assign(coeff);
00513
00514 bool is_oct_changed = false;
00515
00516 PPL_DIRTY_TEMP(N, d);
00517 div_round_up(d, term, coeff);
00518 if (m_i_j > d) {
00519 m_i_j = d;
00520 is_oct_changed = true;
00521 }
00522
00523 if (c.is_equality()) {
00524
00525 if (i % 2 == 0)
00526 ++i_iter;
00527 else
00528 --i_iter;
00529
00530 typename OR_Matrix<N>::row_reference_type m_ci = *i_iter;
00531 using namespace Implementation::Octagonal_Shapes;
00532 dimension_type cj = coherent_index(j);
00533 N& m_ci_cj = m_ci[cj];
00534
00535 neg_assign(term);
00536 div_round_up(d, term, coeff);
00537 if (m_ci_cj > d) {
00538 m_ci_cj = d;
00539 is_oct_changed = true;
00540 }
00541 }
00542
00543
00544 if (is_oct_changed && marked_strongly_closed())
00545 reset_strongly_closed();
00546 PPL_ASSERT(OK());
00547 }
00548
00549 template <typename T>
00550 dimension_type
00551 Octagonal_Shape<T>::affine_dimension() const {
00552 const dimension_type n_rows = matrix.num_rows();
00553
00554 if (n_rows == 0)
00555 return 0;
00556
00557
00558
00559 strong_closure_assign();
00560 if (marked_empty())
00561 return 0;
00562
00563
00564
00565
00566
00567 std::vector<dimension_type> leaders;
00568 compute_leaders(leaders);
00569
00570
00571
00572 dimension_type affine_dim = 0;
00573 for (dimension_type i = 0; i < n_rows; i += 2)
00574
00575 if (leaders[i] == i && leaders[i+1] == i+1)
00576 ++affine_dim;
00577
00578 return affine_dim;
00579 }
00580
00581 template <typename T>
00582 Congruence_System
00583 Octagonal_Shape<T>::minimized_congruences() const {
00584
00585
00586 strong_closure_assign();
00587 const dimension_type space_dim = space_dimension();
00588 Congruence_System cgs;
00589 if (space_dim == 0) {
00590 if (marked_empty())
00591 cgs = Congruence_System::zero_dim_empty();
00592 }
00593 else if (marked_empty())
00594 cgs.insert((0*Variable(space_dim-1) %= 1) / 0);
00595 else {
00596
00597
00598 cgs.insert(0*Variable(space_dim-1) == 0);
00599
00600
00601
00602
00603 std::vector<dimension_type> leaders;
00604 compute_leaders(leaders);
00605
00606 PPL_DIRTY_TEMP_COEFFICIENT(num);
00607 PPL_DIRTY_TEMP_COEFFICIENT(den);
00608 for (dimension_type i = 0, i_end = 2*space_dim; i != i_end; i += 2) {
00609 const dimension_type lead_i = leaders[i];
00610 if (i == lead_i) {
00611 if (leaders[i+1] == i)
00612
00613 goto singular;
00614 else
00615
00616 continue;
00617 }
00618 else {
00619
00620 if (leaders[i+1] == lead_i)
00621
00622 goto singular;
00623 else
00624
00625 goto non_singular;
00626 }
00627
00628 singular:
00629
00630
00631 {
00632 const Variable x(i/2);
00633 const N& c_ii_i = matrix[i+1][i];
00634 #ifndef NDEBUG
00635 const N& c_i_ii = matrix[i][i+1];
00636 PPL_ASSERT(is_additive_inverse(c_i_ii, c_ii_i));
00637 #endif
00638 numer_denom(c_ii_i, num, den);
00639 den *= 2;
00640 cgs.insert(den*x == num);
00641 }
00642 continue;
00643
00644 non_singular:
00645
00646
00647 {
00648 const N& c_i_li = matrix[i][lead_i];
00649 #ifndef NDEBUG
00650 using namespace Implementation::Octagonal_Shapes;
00651 const N& c_ii_lii = matrix[i+1][coherent_index(lead_i)];
00652 PPL_ASSERT(is_additive_inverse(c_ii_lii, c_i_li));
00653 #endif
00654 const Variable x(lead_i/2);
00655 const Variable y(i/2);
00656 numer_denom(c_i_li, num, den);
00657 if (lead_i % 2 == 0)
00658 cgs.insert(den*x - den*y == num);
00659 else
00660 cgs.insert(den*x + den*y + num == 0);
00661 }
00662 continue;
00663 }
00664 }
00665 return cgs;
00666 }
00667
00668 template <typename T>
00669 void
00670 Octagonal_Shape<T>::concatenate_assign(const Octagonal_Shape& y) {
00671
00672
00673 if (y.space_dim == 0) {
00674 if (y.marked_empty())
00675 set_empty();
00676 return;
00677 }
00678
00679
00680
00681 if (space_dim == 0 && marked_empty()) {
00682 add_space_dimensions_and_embed(y.space_dim);
00683 return;
00684 }
00685
00686
00687
00688 dimension_type old_num_rows = matrix.num_rows();
00689
00690
00691
00692
00693
00694
00695 add_space_dimensions_and_embed(y.space_dim);
00696 typename OR_Matrix<N>::const_element_iterator
00697 y_it = y.matrix.element_begin();
00698 for (typename OR_Matrix<N>::row_iterator i = matrix.row_begin()+old_num_rows,
00699 matrix_row_end = matrix.row_end(); i != matrix_row_end; ++i) {
00700 typename OR_Matrix<N>::row_reference_type r = *i;
00701 dimension_type rs_i = i.row_size();
00702 for (dimension_type j = old_num_rows; j < rs_i; ++j, ++y_it)
00703 r[j] = *y_it;
00704 }
00705
00706
00707 if (marked_strongly_closed())
00708 reset_strongly_closed();
00709 PPL_ASSERT(OK());
00710 }
00711
00712 template <typename T>
00713 bool
00714 Octagonal_Shape<T>::contains(const Octagonal_Shape& y) const {
00715
00716 if (space_dim != y.space_dim)
00717 throw_dimension_incompatible("contains(y)", y);
00718
00719
00720
00721
00722
00723 if (space_dim == 0) {
00724 if (!marked_empty())
00725 return true;
00726 else
00727 return y.marked_empty();
00728 }
00729
00730
00731 y.strong_closure_assign();
00732
00733 if (y.marked_empty())
00734 return true;
00735
00736
00737
00738 for (typename OR_Matrix<N>::const_element_iterator
00739 i = matrix.element_begin(), j = y.matrix.element_begin(),
00740 matrix_element_end = matrix.element_end(); i != matrix_element_end; ++i, ++j)
00741 if (*i < *j)
00742 return false;
00743 return true;
00744 }
00745
00746 template <typename T>
00747 bool
00748 Octagonal_Shape<T>::is_disjoint_from(const Octagonal_Shape& y) const {
00749
00750 if (space_dim != y.space_dim)
00751 throw_dimension_incompatible("is_disjoint_from(y)", y);
00752
00753
00754 strong_closure_assign();
00755 if (marked_empty())
00756 return true;
00757 y.strong_closure_assign();
00758 if (y.marked_empty())
00759 return true;
00760
00761
00762
00763
00764
00765
00766
00767 const dimension_type n_rows = matrix.num_rows();
00768
00769 typedef typename OR_Matrix<N>::const_row_iterator Row_Iterator;
00770 typedef typename OR_Matrix<N>::const_row_reference_type Row_Reference;
00771
00772 const Row_Iterator m_begin = matrix.row_begin();
00773 const Row_Iterator m_end = matrix.row_end();
00774
00775 const Row_Iterator y_begin = y.matrix.row_begin();
00776
00777 PPL_DIRTY_TEMP(N, neg_y_ci_cj);
00778 for (Row_Iterator i_iter = m_begin; i_iter != m_end; ++i_iter) {
00779 using namespace Implementation::Octagonal_Shapes;
00780 const dimension_type i = i_iter.index();
00781 const dimension_type ci = coherent_index(i);
00782 const dimension_type rs_i = i_iter.row_size();
00783 Row_Reference m_i = *i_iter;
00784 for (dimension_type j = 0; j < n_rows; ++j) {
00785 const dimension_type cj = coherent_index(j);
00786 Row_Reference m_cj = *(m_begin + cj);
00787 const N& m_i_j = (j < rs_i) ? m_i[j] : m_cj[ci];
00788 Row_Reference y_ci = *(y_begin + ci);
00789 Row_Reference y_j = *(y_begin + j);
00790 const N& y_ci_cj = (j < rs_i) ? y_ci[cj] : y_j[i];
00791 neg_assign_r(neg_y_ci_cj, y_ci_cj, ROUND_UP);
00792 if (m_i_j < neg_y_ci_cj)
00793 return true;
00794 }
00795 }
00796 return false;
00797 }
00798
00799 template <typename T>
00800 bool
00801 Octagonal_Shape<T>::is_universe() const {
00802
00803 if (marked_empty())
00804 return false;
00805
00806
00807
00808 if (space_dim == 0)
00809 return true;
00810
00811
00812 for (typename OR_Matrix<N>::const_element_iterator
00813 i = matrix.element_begin(), matrix_element_end = matrix.element_end();
00814 i != matrix_element_end;
00815 ++i)
00816 if (!is_plus_infinity(*i))
00817 return false;
00818
00819 return true;
00820 }
00821
00822 template <typename T>
00823 bool
00824 Octagonal_Shape<T>::is_bounded() const {
00825 strong_closure_assign();
00826
00827 if (marked_empty() || space_dim == 0)
00828 return true;
00829
00830
00831 for (typename OR_Matrix<N>::const_row_iterator i = matrix.row_begin(),
00832 matrix_row_end = matrix.row_end(); i != matrix_row_end; ++i) {
00833 typename OR_Matrix<N>::const_row_reference_type x_i = *i;
00834 const dimension_type i_index = i.index();
00835 for (dimension_type j = i.row_size(); j-- > 0; )
00836 if (i_index != j)
00837 if (is_plus_infinity(x_i[j]))
00838 return false;
00839 }
00840
00841 return true;
00842 }
00843
00844 template <typename T>
00845 bool
00846 Octagonal_Shape<T>::contains_integer_point() const {
00847
00848 if (is_empty())
00849 return false;
00850 const dimension_type space_dim = space_dimension();
00851 if (space_dim == 0)
00852 return true;
00853
00854
00855
00856 if (std::numeric_limits<T>::is_integer)
00857 return !tight_coherence_would_make_empty();
00858
00859
00860
00861
00862 Octagonal_Shape<mpz_class> oct_z(space_dim);
00863 oct_z.reset_strongly_closed();
00864
00865 typedef Octagonal_Shape<mpz_class>::N Z;
00866 bool all_integers = true;
00867 typename OR_Matrix<N>::const_element_iterator x_i = matrix.element_begin();
00868 for (typename OR_Matrix<Z>::element_iterator
00869 z_i = oct_z.matrix.element_begin(),
00870 z_end = oct_z.matrix.element_end(); z_i != z_end; ++z_i, ++x_i) {
00871 const N& d = *x_i;
00872 if (is_plus_infinity(d))
00873 continue;
00874 if (is_integer(d))
00875 assign_r(*z_i, d, ROUND_NOT_NEEDED);
00876 else {
00877 all_integers = false;
00878 assign_r(*z_i, d, ROUND_DOWN);
00879 }
00880 }
00881
00882 if (all_integers)
00883
00884 oct_z.set_strongly_closed();
00885 else {
00886
00887 oct_z.strong_closure_assign();
00888 if (oct_z.marked_empty())
00889 return false;
00890 }
00891 return !oct_z.tight_coherence_would_make_empty();
00892 }
00893
00894 template <typename T>
00895 bool
00896 Octagonal_Shape<T>::frequency(const Linear_Expression& expr,
00897 Coefficient& freq_n, Coefficient& freq_d,
00898 Coefficient& val_n, Coefficient& val_d) const {
00899 dimension_type space_dim = space_dimension();
00900
00901 if (space_dim < expr.space_dimension())
00902 throw_dimension_incompatible("frequency(e, ...)", "e", expr);
00903
00904
00905
00906
00907
00908
00909
00910
00911 if (space_dim == 0) {
00912 if (is_empty())
00913 return false;
00914 freq_n = 0;
00915 freq_d = 1;
00916 val_n = expr.inhomogeneous_term();
00917 val_d = 1;
00918 return true;
00919 }
00920
00921 strong_closure_assign();
00922
00923 if (marked_empty())
00924 return false;
00925
00926
00927 PPL_DIRTY_TEMP_COEFFICIENT(coeff);
00928 PPL_DIRTY_TEMP_COEFFICIENT(coeff_j);
00929 PPL_DIRTY_TEMP_COEFFICIENT(num);
00930 PPL_DIRTY_TEMP_COEFFICIENT(den);
00931 Linear_Expression le = expr;
00932
00933
00934
00935 bool constant_v = false;
00936
00937 typedef typename OR_Matrix<N>::const_row_iterator Row_Iterator;
00938 typedef typename OR_Matrix<N>::const_row_reference_type Row_Reference;
00939
00940 const Row_Iterator m_begin = matrix.row_begin();
00941 const Row_Iterator m_end = matrix.row_end();
00942
00943 PPL_DIRTY_TEMP_COEFFICIENT(val_den);
00944 val_den = 1;
00945
00946 for (Row_Iterator i_iter = m_begin; i_iter != m_end; i_iter += 2) {
00947 constant_v = false;
00948 dimension_type i = i_iter.index();
00949 const Variable v(i/2);
00950 coeff = le.coefficient(v);
00951 if (coeff == 0) {
00952 constant_v = true;
00953 continue;
00954 }
00955
00956 Row_Reference m_i = *i_iter;
00957 Row_Reference m_ii = *(i_iter+1);
00958 const N& m_i_ii = m_i[i+1];
00959 const N& m_ii_i = m_ii[i];
00960 if ((!is_plus_infinity(m_i_ii) && !is_plus_infinity(m_ii_i))
00961 && (is_additive_inverse(m_i_ii, m_ii_i))) {
00962
00963 numer_denom(m_i_ii, num, den);
00964 den *= 2;
00965 le -= coeff*v;
00966 le *= den;
00967 le -= num*coeff;
00968 val_den *= den;
00969 constant_v = true;
00970 continue;
00971 }
00972
00973
00974 else {
00975 PPL_ASSERT(!constant_v);
00976 using namespace Implementation::Octagonal_Shapes;
00977 const dimension_type ci = coherent_index(i);
00978 for (Row_Iterator j_iter = i_iter; j_iter != m_end; j_iter += 2) {
00979 dimension_type j = j_iter.index();
00980 const Variable vj(j/2);
00981 coeff_j = le.coefficient(vj);
00982 if (coeff_j == 0)
00983
00984 continue;
00985 const dimension_type cj = coherent_index(j);
00986 const dimension_type cjj = coherent_index(j+1);
00987
00988 Row_Reference m_j = *(m_begin + j);
00989 Row_Reference m_cj = *(m_begin + cj);
00990 const N& m_j_i = m_j[i];
00991 const N& m_i_j = m_cj[ci];
00992 if ((!is_plus_infinity(m_i_j) && !is_plus_infinity(m_j_i))
00993 && (is_additive_inverse(m_i_j, m_j_i))) {
00994
00995
00996
00997 numer_denom(m_i_j, num, den);
00998 le -= coeff*v;
00999 le += coeff*vj;
01000 le *= den;
01001 le -= num*coeff;
01002 val_den *= den;
01003 constant_v = true;
01004 break;
01005 }
01006
01007 m_j = *(m_begin + j + 1);
01008 m_cj = *(m_begin + cjj);
01009 const N& m_j_i1 = m_j[i];
01010 const N& m_i_j1 = m_cj[ci];
01011 if ((!is_plus_infinity(m_i_j1) && !is_plus_infinity(m_j_i1))
01012 && (is_additive_inverse(m_i_j1, m_j_i1))) {
01013
01014
01015
01016 numer_denom(m_i_j1, num, den);
01017 le -= coeff*v;
01018 le -= coeff*vj;
01019 le *= den;
01020 le -= num*coeff;
01021 val_den *= den;
01022 constant_v = true;
01023 break;
01024 }
01025 }
01026 if (!constant_v)
01027
01028 return false;
01029 }
01030 }
01031 if (!constant_v)
01032
01033 return false;
01034
01035
01036 freq_n = 0;
01037 freq_d = 1;
01038
01039
01040 normalize2(le.inhomogeneous_term(), val_den, val_n, val_d);
01041 return true;
01042 }
01043
01044 template <typename T>
01045 bool
01046 Octagonal_Shape<T>::constrains(const Variable var) const {
01047
01048 const dimension_type var_space_dim = var.space_dimension();
01049 if (space_dimension() < var_space_dim)
01050 throw_dimension_incompatible("constrains(v)", "v", var);
01051
01052
01053
01054 if (marked_empty())
01055 return true;
01056
01057
01058 const dimension_type n_v = 2*(var_space_dim - 1);
01059 typename OR_Matrix<N>::const_row_iterator m_iter = matrix.row_begin() + n_v;
01060 typename OR_Matrix<N>::const_row_reference_type r_v = *m_iter;
01061 typename OR_Matrix<N>::const_row_reference_type r_cv = *(++m_iter);
01062 for (dimension_type h = m_iter.row_size(); h-- > 0; ) {
01063 if (!is_plus_infinity(r_v[h]) || !is_plus_infinity(r_cv[h]))
01064 return true;
01065 }
01066 ++m_iter;
01067 for (typename OR_Matrix<N>::const_row_iterator m_end = matrix.row_end();
01068 m_iter != m_end; ++m_iter) {
01069 typename OR_Matrix<N>::const_row_reference_type r = *m_iter;
01070 if (!is_plus_infinity(r[n_v]) || !is_plus_infinity(r[n_v+1]))
01071 return true;
01072 }
01073
01074
01075
01076 return is_empty();
01077 }
01078
01079 template <typename T>
01080 bool
01081 Octagonal_Shape<T>::is_strong_coherent() const {
01082
01083
01084 const dimension_type num_rows = matrix.num_rows();
01085
01086
01087 PPL_DIRTY_TEMP(N, semi_sum);
01088
01089
01090
01091
01092
01093 for (dimension_type i = num_rows; i-- > 0; ) {
01094 typename OR_Matrix<N>::const_row_iterator iter = matrix.row_begin() + i;
01095 typename OR_Matrix<N>::const_row_reference_type m_i = *iter;
01096 using namespace Implementation::Octagonal_Shapes;
01097 const N& m_i_ci = m_i[coherent_index(i)];
01098 for (dimension_type j = matrix.row_size(i); j-- > 0; )
01099
01100 if (i != j) {
01101 const N& m_cj_j = matrix[coherent_index(j)][j];
01102 if (!is_plus_infinity(m_i_ci)
01103 && !is_plus_infinity(m_cj_j)) {
01104
01105
01106 add_assign_r(semi_sum, m_i_ci, m_cj_j, ROUND_UP);
01107 div_2exp_assign_r(semi_sum, semi_sum, 1, ROUND_UP);
01108 if (m_i[j] > semi_sum)
01109 return false;
01110 }
01111 }
01112 }
01113 return true;
01114 }
01115
01116 template <typename T>
01117 bool
01118 Octagonal_Shape<T>::is_strongly_reduced() const {
01119
01120
01121
01122 if (marked_empty())
01123 return true;
01124
01125 Octagonal_Shape x = *this;
01126
01127
01128 for (typename OR_Matrix<N>::const_row_iterator iter = matrix.row_begin(),
01129 matrix_row_end = matrix.row_end(); iter != matrix_row_end; ++iter) {
01130 typename OR_Matrix<N>::const_row_reference_type m_i = *iter;
01131 const dimension_type i = iter.index();
01132 for (dimension_type j = iter.row_size(); j-- > 0; ) {
01133 if (!is_plus_infinity(m_i[j])) {
01134 Octagonal_Shape x_copy = *this;
01135 assign_r(x_copy.matrix[i][j], PLUS_INFINITY, ROUND_NOT_NEEDED);
01136 if (x == x_copy)
01137 return false;
01138 }
01139 }
01140 }
01141
01142 return true;
01143 }
01144
01145 template <typename T>
01146 bool
01147 Octagonal_Shape<T>::bounds(const Linear_Expression& expr,
01148 const bool from_above) const {
01149
01150
01151 const dimension_type expr_space_dim = expr.space_dimension();
01152 if (space_dim < expr_space_dim)
01153 throw_dimension_incompatible((from_above
01154 ? "bounds_from_above(e)"
01155 : "bounds_from_below(e)"), "e", expr);
01156 strong_closure_assign();
01157
01158
01159 if (space_dim == 0 || marked_empty())
01160 return true;
01161
01162
01163
01164 const Constraint& c = (from_above) ? expr <= 0 : expr >= 0;
01165 dimension_type num_vars = 0;
01166 dimension_type i = 0;
01167 dimension_type j = 0;
01168 PPL_DIRTY_TEMP_COEFFICIENT(coeff);
01169 PPL_DIRTY_TEMP_COEFFICIENT(term);
01170 if (extract_octagonal_difference(c, c.space_dimension(), num_vars,
01171 i, j, coeff, term)) {
01172 if (num_vars == 0)
01173 return true;
01174
01175 typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin() + i;
01176 typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
01177 return !is_plus_infinity(m_i[j]);
01178 }
01179 else {
01180
01181 Optimization_Mode mode_bounds =
01182 from_above ? MAXIMIZATION : MINIMIZATION;
01183 MIP_Problem mip(space_dim, constraints(), expr, mode_bounds);
01184 return mip.solve() == OPTIMIZED_MIP_PROBLEM;
01185 }
01186 }
01187
01188 template <typename T>
01189 bool
01190 Octagonal_Shape<T>::max_min(const Linear_Expression& expr,
01191 const bool maximize,
01192 Coefficient& ext_n, Coefficient& ext_d,
01193 bool& included) const {
01194
01195
01196 const dimension_type expr_space_dim = expr.space_dimension();
01197 if (space_dim < expr_space_dim)
01198 throw_dimension_incompatible((maximize
01199 ? "maximize(e, ...)"
01200 : "minimize(e, ...)"), "e", expr);
01201
01202 if (space_dim == 0) {
01203 if (marked_empty())
01204 return false;
01205 else {
01206 ext_n = expr.inhomogeneous_term();
01207 ext_d = 1;
01208 included = true;
01209 return true;
01210 }
01211 }
01212
01213 strong_closure_assign();
01214
01215 if (marked_empty())
01216 return false;
01217
01218
01219
01220 const Constraint& c = (maximize) ? expr <= 0 : expr >= 0;
01221 dimension_type num_vars = 0;
01222 dimension_type i = 0;
01223 dimension_type j = 0;
01224 PPL_DIRTY_TEMP_COEFFICIENT(coeff);
01225 PPL_DIRTY_TEMP_COEFFICIENT(term);
01226 if (!extract_octagonal_difference(c, c.space_dimension(), num_vars,
01227 i, j, coeff, term)) {
01228
01229 Optimization_Mode max_min = (maximize) ? MAXIMIZATION : MINIMIZATION;
01230 MIP_Problem mip(space_dim, constraints(), expr, max_min);
01231 if (mip.solve() == OPTIMIZED_MIP_PROBLEM) {
01232 mip.optimal_value(ext_n, ext_d);
01233 included = true;
01234 return true;
01235 }
01236 else
01237
01238 return false;
01239 }
01240 else {
01241
01242 if (num_vars == 0) {
01243 ext_n = expr.inhomogeneous_term();
01244 ext_d = 1;
01245 included = true;
01246 return true;
01247 }
01248
01249
01250 typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin() + i;
01251 typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
01252 PPL_DIRTY_TEMP(N, d);
01253 if (!is_plus_infinity(m_i[j])) {
01254 const Coefficient& b = expr.inhomogeneous_term();
01255 PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
01256 neg_assign(minus_b, b);
01257 const Coefficient& sc_b = maximize ? b : minus_b;
01258 assign_r(d, sc_b, ROUND_UP);
01259
01260
01261 PPL_DIRTY_TEMP(N, coeff_expr);
01262 const Coefficient& coeff_i = expr.coefficient(Variable(i/2));
01263 const int sign_i = sgn(coeff_i);
01264 if (sign_i > 0)
01265 assign_r(coeff_expr, coeff_i, ROUND_UP);
01266 else {
01267 PPL_DIRTY_TEMP_COEFFICIENT(minus_coeff_i);
01268 neg_assign(minus_coeff_i, expr.coefficient(Variable(i/2)));
01269 assign_r(coeff_expr, minus_coeff_i, ROUND_UP);
01270 }
01271
01272 if (num_vars == 1) {
01273 PPL_DIRTY_TEMP(N, m_i_j);
01274 div_2exp_assign_r(m_i_j, m_i[j], 1, ROUND_UP);
01275 add_mul_assign_r(d, coeff_expr, m_i_j, ROUND_UP);
01276 }
01277 else
01278 add_mul_assign_r(d, coeff_expr, m_i[j], ROUND_UP);
01279 numer_denom(d, ext_n, ext_d);
01280 if (!maximize)
01281 neg_assign(ext_n);
01282 included = true;
01283 return true;
01284 }
01285
01286
01287 return false;
01288 }
01289 }
01290
01291 template <typename T>
01292 bool
01293 Octagonal_Shape<T>::max_min(const Linear_Expression& expr,
01294 const bool maximize,
01295 Coefficient& ext_n, Coefficient& ext_d,
01296 bool& included, Generator& g) const {
01297
01298
01299 const dimension_type expr_space_dim = expr.space_dimension();
01300 if (space_dim < expr_space_dim)
01301 throw_dimension_incompatible((maximize
01302 ? "maximize(e, ...)"
01303 : "minimize(e, ...)"), "e", expr);
01304
01305 if (space_dim == 0) {
01306 if (marked_empty())
01307 return false;
01308 else {
01309 ext_n = expr.inhomogeneous_term();
01310 ext_d = 1;
01311 included = true;
01312 g = point();
01313 return true;
01314 }
01315 }
01316
01317 strong_closure_assign();
01318
01319 if (marked_empty())
01320 return false;
01321 if (!is_universe()) {
01322
01323
01324 Optimization_Mode max_min = (maximize) ? MAXIMIZATION : MINIMIZATION;
01325 MIP_Problem mip(space_dim, constraints(), expr, max_min);
01326 if (mip.solve() == OPTIMIZED_MIP_PROBLEM) {
01327 g = mip.optimizing_point();
01328 mip.evaluate_objective_function(g, ext_n, ext_d);
01329 included = true;
01330 return true;
01331 }
01332 }
01333
01334 return false;
01335 }
01336
01337 template <typename T>
01338 Poly_Con_Relation
01339 Octagonal_Shape<T>::relation_with(const Congruence& cg) const {
01340 dimension_type cg_space_dim = cg.space_dimension();
01341
01342
01343 if (cg_space_dim > space_dim)
01344 throw_dimension_incompatible("relation_with(cg)", cg);
01345
01346
01347
01348 if (cg.is_equality()) {
01349 Constraint c(cg);
01350 return relation_with(c);
01351 }
01352
01353 strong_closure_assign();
01354
01355 if (marked_empty())
01356 return Poly_Con_Relation::saturates()
01357 && Poly_Con_Relation::is_included()
01358 && Poly_Con_Relation::is_disjoint();
01359
01360 if (space_dim == 0) {
01361 if (cg.is_inconsistent())
01362 return Poly_Con_Relation::is_disjoint();
01363 else
01364 return Poly_Con_Relation::saturates()
01365 && Poly_Con_Relation::is_included();
01366 }
01367
01368
01369
01370 Linear_Expression le = Linear_Expression(cg);
01371 PPL_DIRTY_TEMP_COEFFICIENT(min_num);
01372 PPL_DIRTY_TEMP_COEFFICIENT(min_den);
01373 bool min_included;
01374 bool bounded_below = minimize(le, min_num, min_den, min_included);
01375
01376
01377
01378 if (!bounded_below)
01379 return Poly_Con_Relation::strictly_intersects();
01380
01381
01382
01383
01384
01385
01386
01387 PPL_DIRTY_TEMP_COEFFICIENT(max_num);
01388 PPL_DIRTY_TEMP_COEFFICIENT(max_den);
01389 bool max_included;
01390 bool bounded_above = maximize(le, max_num, max_den, max_included);
01391
01392
01393
01394 if (!bounded_above)
01395 return Poly_Con_Relation::strictly_intersects();
01396
01397 PPL_DIRTY_TEMP_COEFFICIENT(signed_distance);
01398
01399
01400
01401 PPL_DIRTY_TEMP_COEFFICIENT(min_value);
01402 min_value = min_num / min_den;
01403 const Coefficient& modulus = cg.modulus();
01404 signed_distance = min_value % modulus;
01405 min_value -= signed_distance;
01406 if (min_value * min_den < min_num)
01407 min_value += modulus;
01408
01409
01410
01411 PPL_DIRTY_TEMP_COEFFICIENT(max_value);
01412 max_value = max_num / max_den;
01413 signed_distance = max_value % modulus;
01414 max_value += signed_distance;
01415 if (max_value * max_den > max_num)
01416 max_value -= modulus;
01417
01418
01419
01420
01421 if (max_value < min_value)
01422 return Poly_Con_Relation::is_disjoint();
01423 else
01424 return Poly_Con_Relation::strictly_intersects();
01425 }
01426
01427 template <typename T>
01428 Poly_Con_Relation
01429 Octagonal_Shape<T>::relation_with(const Constraint& c) const {
01430 dimension_type c_space_dim = c.space_dimension();
01431
01432
01433 if (c_space_dim > space_dim)
01434 throw_dimension_incompatible("relation_with(c)", c);
01435
01436
01437 strong_closure_assign();
01438
01439 if (marked_empty())
01440 return Poly_Con_Relation::saturates()
01441 && Poly_Con_Relation::is_included()
01442 && Poly_Con_Relation::is_disjoint();
01443
01444 if (space_dim == 0) {
01445
01446 if ((c.is_equality() && c.inhomogeneous_term() != 0)
01447 || (c.is_inequality() && c.inhomogeneous_term() < 0))
01448 return Poly_Con_Relation::is_disjoint();
01449 else if (c.is_strict_inequality() && c.inhomogeneous_term() == 0)
01450
01451
01452 return Poly_Con_Relation::saturates()
01453 && Poly_Con_Relation::is_disjoint();
01454
01455
01456 else if (c.is_equality() || c.inhomogeneous_term() == 0)
01457 return Poly_Con_Relation::saturates()
01458 && Poly_Con_Relation::is_included();
01459 else
01460
01461
01462
01463 return Poly_Con_Relation::is_included();
01464 }
01465
01466 dimension_type num_vars = 0;
01467 dimension_type i = 0;
01468 dimension_type j = 0;
01469 PPL_DIRTY_TEMP_COEFFICIENT(coeff);
01470 PPL_DIRTY_TEMP_COEFFICIENT(c_term);
01471 if (!extract_octagonal_difference(c, c_space_dim, num_vars,
01472 i, j, coeff, c_term)) {
01473
01474
01475
01476
01477
01478
01479 Linear_Expression le;
01480 for (dimension_type k = c_space_dim; k-- > 0; ) {
01481 Variable vk(k);
01482 le += c.coefficient(vk) * vk;
01483 }
01484 PPL_DIRTY_TEMP(Coefficient, max_num);
01485 PPL_DIRTY_TEMP(Coefficient, max_den);
01486 bool max_included;
01487 PPL_DIRTY_TEMP(Coefficient, min_num);
01488 PPL_DIRTY_TEMP(Coefficient, min_den);
01489 bool min_included;
01490 bool bounded_above = maximize(le, max_num, max_den, max_included);
01491 bool bounded_below = minimize(le, min_num, min_den, min_included);
01492 if (!bounded_above) {
01493 if (!bounded_below)
01494 return Poly_Con_Relation::strictly_intersects();
01495 min_num += c.inhomogeneous_term() * min_den;
01496 switch (sgn(min_num)) {
01497 case 1:
01498 if (c.is_equality())
01499 return Poly_Con_Relation::is_disjoint();
01500 return Poly_Con_Relation::is_included();
01501 case 0:
01502 if (c.is_strict_inequality() || c.is_equality())
01503 return Poly_Con_Relation::strictly_intersects();
01504 return Poly_Con_Relation::is_included();
01505 case -1:
01506 return Poly_Con_Relation::strictly_intersects();
01507 }
01508 }
01509 if (!bounded_below) {
01510 max_num += c.inhomogeneous_term() * max_den;
01511 switch (sgn(max_num)) {
01512 case 1:
01513 return Poly_Con_Relation::strictly_intersects();
01514 case 0:
01515 if (c.is_strict_inequality())
01516 return Poly_Con_Relation::is_disjoint();
01517 return Poly_Con_Relation::strictly_intersects();
01518 case -1:
01519 return Poly_Con_Relation::is_disjoint();
01520 }
01521 }
01522 else {
01523 max_num += c.inhomogeneous_term() * max_den;
01524 min_num += c.inhomogeneous_term() * min_den;
01525 switch (sgn(max_num)) {
01526 case 1:
01527 switch (sgn(min_num)) {
01528 case 1:
01529 if (c.is_equality())
01530 return Poly_Con_Relation::is_disjoint();
01531 return Poly_Con_Relation::is_included();
01532 case 0:
01533 if (c.is_equality())
01534 return Poly_Con_Relation::strictly_intersects();
01535 if (c.is_strict_inequality())
01536 return Poly_Con_Relation::strictly_intersects();
01537 return Poly_Con_Relation::is_included();
01538 case -1:
01539 return Poly_Con_Relation::strictly_intersects();
01540 }
01541 case 0:
01542 if (min_num == 0) {
01543 if (c.is_strict_inequality())
01544 return Poly_Con_Relation::is_disjoint()
01545 && Poly_Con_Relation::saturates();
01546 return Poly_Con_Relation::is_included()
01547 && Poly_Con_Relation::saturates();
01548 }
01549 if (c.is_strict_inequality())
01550 return Poly_Con_Relation::is_disjoint();
01551 return Poly_Con_Relation::strictly_intersects();
01552 case -1:
01553 return Poly_Con_Relation::is_disjoint();
01554 }
01555 }
01556 }
01557
01558 if (num_vars == 0) {
01559
01560 switch (sgn(c.inhomogeneous_term())) {
01561 case -1:
01562 return Poly_Con_Relation::is_disjoint();
01563 case 0:
01564 if (c.is_strict_inequality())
01565 return Poly_Con_Relation::saturates()
01566 && Poly_Con_Relation::is_disjoint();
01567 else
01568 return Poly_Con_Relation::saturates()
01569 && Poly_Con_Relation::is_included();
01570 case 1:
01571 if (c.is_equality())
01572 return Poly_Con_Relation::is_disjoint();
01573 else
01574 return Poly_Con_Relation::is_included();
01575 }
01576 }
01577
01578
01579 typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin() + i;
01580 typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
01581 const N& m_i_j = m_i[j];
01582
01583 if (coeff < 0)
01584 neg_assign(coeff);
01585
01586
01587
01588 if (i % 2 == 0)
01589 ++i_iter;
01590 else
01591 --i_iter;
01592 typename OR_Matrix<N>::const_row_reference_type m_ci = *i_iter;
01593 using namespace Implementation::Octagonal_Shapes;
01594 const N& m_ci_cj = m_ci[coherent_index(j)];
01595 PPL_DIRTY_TEMP_COEFFICIENT(numer);
01596 PPL_DIRTY_TEMP_COEFFICIENT(denom);
01597
01598
01599 PPL_DIRTY_TEMP0(mpq_class, q_x);
01600 PPL_DIRTY_TEMP0(mpq_class, q_y);
01601 PPL_DIRTY_TEMP0(mpq_class, d);
01602 PPL_DIRTY_TEMP0(mpq_class, d1);
01603 PPL_DIRTY_TEMP0(mpq_class, c_den);
01604 PPL_DIRTY_TEMP0(mpq_class, q_den);
01605 assign_r(c_den, coeff, ROUND_NOT_NEEDED);
01606 assign_r(d, c_term, ROUND_NOT_NEEDED);
01607 neg_assign_r(d1, d, ROUND_NOT_NEEDED);
01608 div_assign_r(d, d, c_den, ROUND_NOT_NEEDED);
01609 div_assign_r(d1, d1, c_den, ROUND_NOT_NEEDED);
01610
01611 if (is_plus_infinity(m_i_j)) {
01612 if (!is_plus_infinity(m_ci_cj)) {
01613
01614
01615
01616
01617
01618 numer_denom(m_ci_cj, numer, denom);
01619 assign_r(q_den, denom, ROUND_NOT_NEEDED);
01620 assign_r(q_y, numer, ROUND_NOT_NEEDED);
01621 div_assign_r(q_y, q_y, q_den, ROUND_NOT_NEEDED);
01622 if (q_y < d1)
01623 return Poly_Con_Relation::is_disjoint();
01624 if (q_y == d1 && c.is_strict_inequality())
01625 return Poly_Con_Relation::is_disjoint();
01626 }
01627
01628
01629 return Poly_Con_Relation::strictly_intersects();
01630 }
01631
01632
01633 numer_denom(m_i_j, numer, denom);
01634 assign_r(q_den, denom, ROUND_NOT_NEEDED);
01635 assign_r(q_x, numer, ROUND_NOT_NEEDED);
01636 div_assign_r(q_x, q_x, q_den, ROUND_NOT_NEEDED);
01637
01638 if (!is_plus_infinity(m_ci_cj)) {
01639 numer_denom(m_ci_cj, numer, denom);
01640 assign_r(q_den, denom, ROUND_NOT_NEEDED);
01641 assign_r(q_y, numer, ROUND_NOT_NEEDED);
01642 div_assign_r(q_y, q_y, q_den, ROUND_NOT_NEEDED);
01643 if (q_x == d && q_y == d1) {
01644 if (c.is_strict_inequality())
01645 return Poly_Con_Relation::saturates()
01646 && Poly_Con_Relation::is_disjoint();
01647 else
01648 return Poly_Con_Relation::saturates()
01649 && Poly_Con_Relation::is_included();
01650 }
01651
01652
01653 if (q_y < d1)
01654 return Poly_Con_Relation::is_disjoint();
01655 if (q_y == d1 && c.is_strict_inequality())
01656 return Poly_Con_Relation::is_disjoint();
01657 }
01658
01659
01660
01661
01662 if (d > q_x) {
01663 if (c.is_equality())
01664 return Poly_Con_Relation::is_disjoint();
01665 else
01666 return Poly_Con_Relation::is_included();
01667 }
01668
01669 if (d == q_x && c.is_nonstrict_inequality())
01670 return Poly_Con_Relation::is_included();
01671
01672
01673 return Poly_Con_Relation::strictly_intersects();
01674 }
01675
01676 template <typename T>
01677 Poly_Gen_Relation
01678 Octagonal_Shape<T>::relation_with(const Generator& g) const {
01679 const dimension_type g_space_dim = g.space_dimension();
01680
01681
01682 if (space_dim < g_space_dim)
01683 throw_dimension_incompatible("relation_with(g)", g);
01684
01685
01686
01687 strong_closure_assign();
01688
01689
01690 if (marked_empty())
01691 return Poly_Gen_Relation::nothing();
01692
01693
01694
01695 if (space_dim == 0)
01696 return Poly_Gen_Relation::subsumes();
01697
01698 const bool is_line = g.is_line();
01699 const bool is_line_or_ray = g.is_line_or_ray();
01700
01701
01702
01703
01704
01705
01706
01707 typedef typename OR_Matrix<N>::const_row_iterator Row_Iterator;
01708 typedef typename OR_Matrix<N>::const_row_reference_type Row_Reference;
01709
01710 const Row_Iterator m_begin = matrix.row_begin();
01711 const Row_Iterator m_end = matrix.row_end();
01712
01713 PPL_DIRTY_TEMP_COEFFICIENT(num);
01714 PPL_DIRTY_TEMP_COEFFICIENT(den);
01715 PPL_DIRTY_TEMP_COEFFICIENT(product);
01716
01717
01718 for (Row_Iterator i_iter = m_begin; i_iter != m_end; i_iter += 2) {
01719 dimension_type i = i_iter.index();
01720 Row_Reference m_i = *i_iter;
01721 Row_Reference m_ii = *(i_iter+1);
01722 const N& m_i_ii = m_i[i+1];
01723 const N& m_ii_i = m_ii[i];
01724
01725 const Variable x(i/2);
01726 const Coefficient& g_coeff_x
01727 = (x.space_dimension() > g_space_dim)
01728 ? Coefficient_zero()
01729 : g.coefficient(x);
01730 if (is_additive_inverse(m_i_ii, m_ii_i)) {
01731
01732
01733
01734
01735 numer_denom(m_ii_i, num, den);
01736 den *= 2;
01737 product = den * g_coeff_x;
01738
01739
01740 if (!is_line_or_ray) {
01741 neg_assign(num);
01742 add_mul_assign(product, num, g.divisor());
01743 }
01744 if (product != 0)
01745 return Poly_Gen_Relation::nothing();
01746 }
01747
01748 else {
01749 if (!is_plus_infinity(m_i_ii)) {
01750
01751
01752
01753 numer_denom(m_i_ii, num, den);
01754 den *= -2;
01755 product = den * g_coeff_x;
01756
01757
01758 if (!is_line_or_ray) {
01759 neg_assign(num);
01760 add_mul_assign(product, num, g.divisor());
01761 }
01762 if (is_line && product != 0)
01763 return Poly_Gen_Relation::nothing();
01764 else
01765
01766
01767
01768
01769 if (product > 0)
01770 return Poly_Gen_Relation::nothing();
01771 }
01772 if (!is_plus_infinity(m_ii_i)) {
01773
01774 numer_denom(m_ii_i, num, den);
01775 den *= 2;
01776 product = den * g_coeff_x;
01777
01778
01779 if (!is_line_or_ray) {
01780 neg_assign(num);
01781 add_mul_assign(product, num , g.divisor());
01782 }
01783 if (is_line && product != 0)
01784 return Poly_Gen_Relation::nothing();
01785 else
01786
01787
01788
01789
01790 if (product > 0)
01791 return Poly_Gen_Relation::nothing();
01792 }
01793 }
01794 }
01795
01796
01797 for (Row_Iterator i_iter = m_begin ; i_iter != m_end; i_iter += 2) {
01798 dimension_type i = i_iter.index();
01799 Row_Reference m_i = *i_iter;
01800 Row_Reference m_ii = *(i_iter+1);
01801 for (dimension_type j = 0; j < i; j += 2) {
01802 const N& m_i_j = m_i[j];
01803 const N& m_ii_jj = m_ii[j+1];
01804 const N& m_ii_j = m_ii[j];
01805 const N& m_i_jj = m_i[j+1];
01806 const Variable x(j/2);
01807 const Variable y(i/2);
01808 const Coefficient& g_coeff_x
01809 = (x.space_dimension() > g_space_dim)
01810 ? Coefficient_zero()
01811 : g.coefficient(x);
01812 const Coefficient& g_coeff_y
01813 = (y.space_dimension() > g_space_dim)
01814 ? Coefficient_zero()
01815 : g.coefficient(y);
01816
01817 const bool difference_is_equality = is_additive_inverse(m_ii_jj, m_i_j);
01818 if (difference_is_equality) {
01819
01820
01821
01822
01823
01824 numer_denom(m_i_j, num, den);
01825 product = den * g_coeff_x;
01826 neg_assign(den);
01827 add_mul_assign(product, den, g_coeff_y);
01828
01829
01830 if (!is_line_or_ray) {
01831 neg_assign(num);
01832 add_mul_assign(product, num, g.divisor());
01833 }
01834 if (product != 0)
01835 return Poly_Gen_Relation::nothing();
01836 }
01837 else {
01838 if (!is_plus_infinity(m_i_j)) {
01839
01840
01841
01842
01843
01844 numer_denom(m_i_j, num, den);
01845 product = den * g_coeff_x;
01846 neg_assign(den);
01847 add_mul_assign(product, den, g_coeff_y);
01848
01849
01850 if (!is_line_or_ray) {
01851 neg_assign(num);
01852 add_mul_assign(product, num, g.divisor());
01853 }
01854 if (is_line && product != 0)
01855 return Poly_Gen_Relation::nothing();
01856 else if (product > 0)
01857 return Poly_Gen_Relation::nothing();
01858 }
01859 if (!is_plus_infinity(m_ii_jj)) {
01860
01861
01862
01863
01864
01865 numer_denom(m_ii_jj, num, den);
01866 product = den * g_coeff_y;
01867 neg_assign(den);
01868 add_mul_assign(product, den, g_coeff_x);
01869
01870
01871 if (!is_line_or_ray) {
01872 neg_assign(num);
01873 add_mul_assign(product, num, g.divisor());
01874 }
01875 if (is_line && product != 0)
01876 return Poly_Gen_Relation::nothing();
01877 else if (product > 0)
01878 return Poly_Gen_Relation::nothing();
01879 }
01880 }
01881
01882 const bool sum_is_equality = is_additive_inverse(m_i_jj, m_ii_j);
01883 if (sum_is_equality) {
01884
01885
01886
01887
01888
01889 numer_denom(m_ii_j, num, den);
01890 product = den * g_coeff_x;
01891 add_mul_assign(product, den, g_coeff_y);
01892
01893
01894 if (!is_line_or_ray) {
01895 neg_assign(num);
01896 add_mul_assign(product, num, g.divisor());
01897 }
01898 if (product != 0)
01899 return Poly_Gen_Relation::nothing();
01900 }
01901 else {
01902 if (!is_plus_infinity(m_i_jj)) {
01903
01904
01905
01906
01907
01908 numer_denom(m_i_jj, num, den);
01909 neg_assign(den);
01910 product = den * g_coeff_x;
01911 add_mul_assign(product, den, g_coeff_y);
01912
01913
01914 if (!is_line_or_ray) {
01915 neg_assign(num);
01916 add_mul_assign(product, num, g.divisor());
01917 }
01918 if (is_line && product != 0)
01919 return Poly_Gen_Relation::nothing();
01920 else if (product > 0)
01921 return Poly_Gen_Relation::nothing();
01922 }
01923 if (!is_plus_infinity(m_ii_j)) {
01924
01925
01926
01927
01928
01929 numer_denom(m_ii_j, num, den);
01930 product = den * g_coeff_x;
01931 add_mul_assign(product, den, g_coeff_y);
01932
01933
01934 if (!is_line_or_ray) {
01935 neg_assign(num);
01936 add_mul_assign(product, num, g.divisor());
01937 }
01938 if (is_line && product != 0)
01939 return Poly_Gen_Relation::nothing();
01940 else if (product > 0)
01941 return Poly_Gen_Relation::nothing();
01942 }
01943 }
01944 }
01945 }
01946
01947
01948 return Poly_Gen_Relation::subsumes();
01949 }
01950
01951 template <typename T>
01952 void
01953 Octagonal_Shape<T>::strong_closure_assign() const {
01954
01955 if (marked_empty() || marked_strongly_closed() || space_dim == 0)
01956 return;
01957
01958
01959
01960 Octagonal_Shape& x = const_cast<Octagonal_Shape<T>&>(*this);
01961
01962 typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
01963 typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
01964
01965 const dimension_type n_rows = x.matrix.num_rows();
01966 const Row_Iterator m_begin = x.matrix.row_begin();
01967 const Row_Iterator m_end = x.matrix.row_end();
01968
01969
01970 for (Row_Iterator i = m_begin; i != m_end; ++i) {
01971 PPL_ASSERT(is_plus_infinity((*i)[i.index()]));
01972 assign_r((*i)[i.index()], 0, ROUND_NOT_NEEDED);
01973 }
01974
01975
01976
01977
01978
01979
01980
01981
01982
01983
01984
01985
01986 typename OR_Matrix<N>::element_iterator iter_ij;
01987 std::vector<N> vec_k(n_rows);
01988 std::vector<N> vec_ck(n_rows);
01989 PPL_DIRTY_TEMP(N, sum1);
01990 PPL_DIRTY_TEMP(N, sum2);
01991 Row_Reference x_k;
01992 Row_Reference x_ck;
01993 Row_Reference x_i;
01994 Row_Reference x_ci;
01995
01996
01997
01998 for (int twice = 0; twice < 2; ++twice) {
01999
02000 Row_Iterator x_k_iter = m_begin;
02001 Row_Iterator x_i_iter = m_begin;
02002 for (dimension_type k = 0; k < n_rows; k += 2) {
02003 const dimension_type ck = k+1;
02004
02005 iter_ij = x.matrix.element_begin();
02006
02007 x_k = *x_k_iter;
02008 ++x_k_iter;
02009 x_ck = *x_k_iter;
02010 ++x_k_iter;
02011
02012 for (dimension_type i = 0; i <= k; i += 2) {
02013 const dimension_type ci = i+1;
02014
02015 vec_k[i] = x_k[i];
02016
02017 vec_k[ci] = x_k[ci];
02018
02019 vec_ck[i] = x_ck[i];
02020
02021 vec_ck[ci] = x_ck[ci];
02022 }
02023 x_i_iter = x_k_iter;
02024 for (dimension_type i = k+2; i < n_rows; i += 2) {
02025 const dimension_type ci = i+1;
02026 x_i = *x_i_iter;
02027 ++x_i_iter;
02028 x_ci = *x_i_iter;
02029 ++x_i_iter;
02030
02031 vec_k[i] = x_ci[ck];
02032
02033 vec_k[ci] = x_i[ck];
02034
02035 vec_ck[i] = x_ci[k];
02036
02037 vec_ck[ci] = x_i[k];
02038 }
02039
02040 for (dimension_type i = 0; i < n_rows; ++i) {
02041 using namespace Implementation::Octagonal_Shapes;
02042 const dimension_type ci = coherent_index(i);
02043 const N& vec_k_ci = vec_k[ci];
02044 const N& vec_ck_ci = vec_ck[ci];
02045
02046
02047 for (dimension_type j = 0; j <= i; ) {
02048
02049
02050
02051 add_assign_r(sum1, vec_ck_ci, vec_k[j], ROUND_UP);
02052 add_assign_r(sum2, vec_k_ci, vec_ck[j], ROUND_UP);
02053 min_assign(sum1, sum2);
02054 min_assign(*iter_ij, sum1);
02055
02056 ++j;
02057 ++iter_ij;
02058
02059 add_assign_r(sum1, vec_ck_ci, vec_k[j], ROUND_UP);
02060 add_assign_r(sum2, vec_k_ci, vec_ck[j], ROUND_UP);
02061 min_assign(sum1, sum2);
02062 min_assign(*iter_ij, sum1);
02063
02064 ++j;
02065 ++iter_ij;
02066 }
02067 }
02068 }
02069 }
02070
02071
02072
02073 for (Row_Iterator i = m_begin; i != m_end; ++i) {
02074 N& x_i_i = (*i)[i.index()];
02075 if (sgn(x_i_i) < 0) {
02076 x.set_empty();
02077 return;
02078 }
02079 else {
02080 PPL_ASSERT(sgn(x_i_i) == 0);
02081
02082 assign_r(x_i_i, PLUS_INFINITY, ROUND_NOT_NEEDED);
02083 }
02084 }
02085
02086
02087 x.strong_coherence_assign();
02088
02089 x.set_strongly_closed();
02090 }
02091
02092 template <typename T>
02093 void
02094 Octagonal_Shape<T>::strong_coherence_assign() {
02095
02096
02097
02098
02099
02100 PPL_DIRTY_TEMP(N, semi_sum);
02101 for (typename OR_Matrix<N>::row_iterator i_iter = matrix.row_begin(),
02102 i_end = matrix.row_end(); i_iter != i_end; ++i_iter) {
02103 typename OR_Matrix<N>::row_reference_type x_i = *i_iter;
02104 const dimension_type i = i_iter.index();
02105 using namespace Implementation::Octagonal_Shapes;
02106 const N& x_i_ci = x_i[coherent_index(i)];
02107
02108 if (!is_plus_infinity(x_i_ci))
02109 for (dimension_type j = 0, rs_i = i_iter.row_size(); j < rs_i; ++j)
02110 if (i != j) {
02111 const N& x_cj_j = matrix[coherent_index(j)][j];
02112 if (!is_plus_infinity(x_cj_j)) {
02113 add_assign_r(semi_sum, x_i_ci, x_cj_j, ROUND_UP);
02114 div_2exp_assign_r(semi_sum, semi_sum, 1, ROUND_UP);
02115 min_assign(x_i[j], semi_sum);
02116 }
02117 }
02118 }
02119 }
02120
02121 template <typename T>
02122 bool
02123 Octagonal_Shape<T>::tight_coherence_would_make_empty() const {
02124 PPL_ASSERT(std::numeric_limits<N>::is_integer);
02125 PPL_ASSERT(marked_strongly_closed());
02126 const dimension_type space_dim = space_dimension();
02127 for (dimension_type i = 0; i < 2*space_dim; i += 2) {
02128 const dimension_type ci = i+1;
02129 const N& mat_i_ci = matrix[i][ci];
02130 if (!is_plus_infinity(mat_i_ci)
02131
02132 && !is_even(mat_i_ci)
02133
02134 && is_additive_inverse(mat_i_ci, matrix[ci][i]))
02135 return true;
02136 }
02137 return false;
02138 }
02139
02140 template <typename T>
02141 void
02142 Octagonal_Shape<T>::tight_closure_assign() {
02143 PPL_COMPILE_TIME_CHECK(std::numeric_limits<T>::is_integer,
02144 "Octagonal_Shape<T>::tight_closure_assign():"
02145 " T in not an integer datatype.");
02146
02147
02148 strong_closure_assign();
02149 if (marked_empty())
02150 return;
02151 if (tight_coherence_would_make_empty())
02152 set_empty();
02153 else {
02154
02155 PPL_DIRTY_TEMP(N, temp_one);
02156 assign_r(temp_one, 1, ROUND_NOT_NEEDED);
02157 const dimension_type space_dim = space_dimension();
02158 for (dimension_type i = 0; i < 2*space_dim; i += 2) {
02159 const dimension_type ci = i+1;
02160 N& mat_i_ci = matrix[i][ci];
02161 if (!is_plus_infinity(mat_i_ci) && !is_even(mat_i_ci))
02162 sub_assign_r(mat_i_ci, mat_i_ci, temp_one, ROUND_UP);
02163 N& mat_ci_i = matrix[ci][i];
02164 if (!is_plus_infinity(mat_ci_i) && !is_even(mat_ci_i))
02165 sub_assign_r(mat_ci_i, mat_ci_i, temp_one, ROUND_UP);
02166 }
02167
02168 strong_coherence_assign();
02169 }
02170 PPL_ASSERT(OK());
02171 }
02172
02173 template <typename T>
02174 void
02175 Octagonal_Shape<T>
02176 ::incremental_strong_closure_assign(const Variable var) const {
02177
02178 if (var.id() >= space_dim)
02179 throw_dimension_incompatible("incremental_strong_closure_assign(v)",
02180 var.id());
02181
02182
02183 if (marked_empty() || marked_strongly_closed())
02184 return;
02185
02186 Octagonal_Shape& x = const_cast<Octagonal_Shape<T>&>(*this);
02187
02188 typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
02189 typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
02190
02191 const Row_Iterator m_begin = x.matrix.row_begin();
02192 const Row_Iterator m_end = x.matrix.row_end();
02193
02194
02195 for (Row_Iterator i = m_begin; i != m_end; ++i) {
02196 PPL_ASSERT(is_plus_infinity((*i)[i.index()]));
02197 assign_r((*i)[i.index()], 0, ROUND_NOT_NEEDED);
02198 }
02199
02200
02201
02202 const dimension_type v = 2*var.id();
02203 const dimension_type cv = v+1;
02204 Row_Iterator v_iter = m_begin + v;
02205 Row_Iterator cv_iter = v_iter + 1;
02206 Row_Reference x_v = *v_iter;
02207 Row_Reference x_cv = *cv_iter;
02208 const dimension_type rs_v = v_iter.row_size();
02209 const dimension_type n_rows = x.matrix.num_rows();
02210 PPL_DIRTY_TEMP(N, sum);
02211 using namespace Implementation::Octagonal_Shapes;
02212 for (Row_Iterator k_iter = m_begin; k_iter != m_end; ++k_iter) {
02213 const dimension_type k = k_iter.index();
02214 const dimension_type ck = coherent_index(k);
02215 const dimension_type rs_k = k_iter.row_size();
02216 Row_Reference x_k = *k_iter;
02217 Row_Reference x_ck = (k % 2 != 0) ? *(k_iter-1) : *(k_iter+1);
02218
02219 for (Row_Iterator i_iter = m_begin; i_iter != m_end; ++i_iter) {
02220 const dimension_type i = i_iter.index();
02221 const dimension_type ci = coherent_index(i);
02222 const dimension_type rs_i = i_iter.row_size();
02223 Row_Reference x_i = *i_iter;
02224 Row_Reference x_ci = (i % 2 != 0) ? *(i_iter-1) : *(i_iter+1);
02225
02226 const N& x_i_k = (k < rs_i) ? x_i[k] : x_ck[ci];
02227 if (!is_plus_infinity(x_i_k)) {
02228 const N& x_k_v = (v < rs_k) ? x_k[v] : x_cv[ck];
02229 if (!is_plus_infinity(x_k_v)) {
02230 add_assign_r(sum, x_i_k, x_k_v, ROUND_UP);
02231 N& x_i_v = (v < rs_i) ? x_i[v] : x_cv[ci];
02232 min_assign(x_i_v, sum);
02233 }
02234 const N& x_k_cv = (cv < rs_k) ? x_k[cv] : x_v[ck];
02235 if (!is_plus_infinity(x_k_cv)) {
02236 add_assign_r(sum, x_i_k, x_k_cv, ROUND_UP);
02237 N& x_i_cv = (cv < rs_i) ? x_i[cv] : x_v[ci];
02238 min_assign(x_i_cv, sum);
02239 }
02240 }
02241 const N& x_k_i = (i < rs_k) ? x_k[i] : x_ci[ck];
02242 if (!is_plus_infinity(x_k_i)) {
02243 const N& x_v_k = (k < rs_v) ? x_v[k] : x_ck[cv];
02244 if (!is_plus_infinity(x_v_k)) {
02245 N& x_v_i = (i < rs_v) ? x_v[i] : x_ci[cv];
02246 add_assign_r(sum, x_v_k, x_k_i, ROUND_UP);
02247 min_assign(x_v_i, sum);
02248 }
02249 const N& x_cv_k = (k < rs_v) ? x_cv[k] : x_ck[v];
02250 if (!is_plus_infinity(x_cv_k)) {
02251 N& x_cv_i = (i < rs_v) ? x_cv[i] : x_ci[v];
02252 add_assign_r(sum, x_cv_k, x_k_i, ROUND_UP);
02253 min_assign(x_cv_i, sum);
02254 }
02255 }
02256
02257 }
02258 }
02259
02260
02261
02262 for (Row_Iterator i_iter = m_begin; i_iter != m_end; ++i_iter) {
02263 const dimension_type i = i_iter.index();
02264 const dimension_type ci = coherent_index(i);
02265 const dimension_type rs_i = i_iter.row_size();
02266 Row_Reference x_i = *i_iter;
02267 const N& x_i_v = (v < rs_i) ? x_i[v] : x_cv[ci];
02268
02269
02270
02271 for (dimension_type j = 0; j < n_rows; ++j) {
02272 const dimension_type cj = coherent_index(j);
02273 Row_Reference x_cj = *(m_begin+cj);
02274 N& x_i_j = (j < rs_i) ? x_i[j] : x_cj[ci];
02275 if (!is_plus_infinity(x_i_v)) {
02276 const N& x_v_j = (j < rs_v) ? x_v[j] : x_cj[cv];
02277 if (!is_plus_infinity(x_v_j)) {
02278 add_assign_r(sum, x_i_v, x_v_j, ROUND_UP);
02279 min_assign(x_i_j, sum);
02280 }
02281 }
02282 const N& x_i_cv = (cv < rs_i) ? x_i[cv] : x_v[ci];
02283 if (!is_plus_infinity(x_i_cv)) {
02284 const N& x_cv_j = (j < rs_v) ? x_cv[j] : x_cj[v];
02285 if (!is_plus_infinity(x_cv_j)) {
02286 add_assign_r(sum, x_i_cv, x_cv_j, ROUND_UP);
02287 min_assign(x_i_j, sum);
02288 }
02289 }
02290 }
02291 }
02292
02293
02294
02295 for (Row_Iterator i = m_begin; i != m_end; ++i) {
02296 N& x_i_i = (*i)[i.index()];
02297 if (sgn(x_i_i) < 0) {
02298 x.set_empty();
02299 return;
02300 }
02301 else {
02302
02303 PPL_ASSERT(sgn(x_i_i) == 0);
02304 assign_r(x_i_i, PLUS_INFINITY, ROUND_NOT_NEEDED);
02305 }
02306 }
02307
02308
02309 x.strong_coherence_assign();
02310
02311 x.set_strongly_closed();
02312 }
02313
02314 template <typename T>
02315 void
02316 Octagonal_Shape<T>
02317 ::compute_successors(std::vector<dimension_type>& successor) const {
02318 PPL_ASSERT(!marked_empty() && marked_strongly_closed());
02319 PPL_ASSERT(successor.size() == 0);
02320
02321
02322
02323 const dimension_type successor_size = matrix.num_rows();
02324
02325 successor.reserve(successor_size);
02326 for (dimension_type i = 0; i < successor_size; ++i)
02327 successor.push_back(i);
02328
02329 for (dimension_type i = successor_size; i-- > 0; ) {
02330 typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin()+i;
02331 typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
02332 typename OR_Matrix<N>::const_row_reference_type m_ci
02333 = (i % 2 != 0) ? *(i_iter-1) : *(i_iter+1);
02334 for (dimension_type j = 0; j < i; ++j) {
02335
02336
02337 using namespace Implementation::Octagonal_Shapes;
02338 dimension_type cj = coherent_index(j);
02339 if (is_additive_inverse(m_ci[cj], m_i[j]))
02340
02341 successor[j] = i;
02342 }
02343 }
02344 }
02345
02346 template <typename T>
02347 void
02348 Octagonal_Shape<T>
02349 ::compute_leaders(std::vector<dimension_type>& leaders) const {
02350 PPL_ASSERT(!marked_empty() && marked_strongly_closed());
02351 PPL_ASSERT(leaders.size() == 0);
02352
02353
02354
02355 const dimension_type leader_size = matrix.num_rows();
02356
02357 leaders.reserve(leader_size);
02358 for (dimension_type i = 0; i < leader_size; ++i)
02359 leaders.push_back(i);
02360
02361 for (typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin(),
02362 matrix_row_end = matrix.row_end();
02363 i_iter != matrix_row_end; ++i_iter) {
02364 typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
02365 dimension_type i = i_iter.index();
02366 typename OR_Matrix<N>::const_row_reference_type m_ci
02367 = (i % 2 != 0) ? *(i_iter-1) : *(i_iter+1);
02368 for (dimension_type j = 0; j < i; ++j) {
02369 using namespace Implementation::Octagonal_Shapes;
02370 dimension_type cj = coherent_index(j);
02371 if (is_additive_inverse(m_ci[cj], m_i[j]))
02372
02373 leaders[i] = leaders[j];
02374 }
02375 }
02376 }
02377
02378 template <typename T>
02379 void
02380 Octagonal_Shape<T>
02381 ::compute_leaders(std::vector<dimension_type>& successor,
02382 std::vector<dimension_type>& no_sing_leaders,
02383 bool& exist_sing_class,
02384 dimension_type& sing_leader) const {
02385 PPL_ASSERT(!marked_empty() && marked_strongly_closed());
02386 PPL_ASSERT(no_sing_leaders.size() == 0);
02387 dimension_type successor_size = successor.size();
02388 std::deque<bool> dealt_with(successor_size, false);
02389 for (dimension_type i = 0; i < successor_size; ++i) {
02390 dimension_type next_i = successor[i];
02391 if (!dealt_with[i]) {
02392
02393
02394 using namespace Implementation::Octagonal_Shapes;
02395 if (next_i == coherent_index(i)) {
02396 exist_sing_class = true;
02397 sing_leader = i;
02398 }
02399 else
02400 no_sing_leaders.push_back(i);
02401 }
02402
02403 dealt_with[next_i] = true;
02404 }
02405 }
02406
02407 template <typename T>
02408 void
02409 Octagonal_Shape<T>::strong_reduction_assign() const {
02410
02411 if (space_dim == 0)
02412 return;
02413 strong_closure_assign();
02414
02415 if (marked_empty())
02416 return;
02417
02418
02419 std::vector<Bit_Row> non_red;
02420 non_redundant_matrix_entries(non_red);
02421
02422
02423 Octagonal_Shape<T>& x = const_cast<Octagonal_Shape<T>&>(*this);
02424 #ifndef NDEBUG
02425 const Octagonal_Shape x_copy_before(x);
02426 #endif
02427 typename OR_Matrix<N>::element_iterator x_i = x.matrix.element_begin();
02428 for (dimension_type i = 0; i < 2 * space_dim; ++i) {
02429 const Bit_Row& non_red_i = non_red[i];
02430 for (dimension_type j = 0,
02431 j_end = OR_Matrix<N>::row_size(i); j < j_end; ++j, ++x_i) {
02432 if (!non_red_i[j])
02433 assign_r(*x_i, PLUS_INFINITY, ROUND_NOT_NEEDED);
02434 }
02435 }
02436 x.reset_strongly_closed();
02437 #ifndef NDEBUG
02438 const Octagonal_Shape x_copy_after(x);
02439 PPL_ASSERT(x_copy_before == x_copy_after);
02440 PPL_ASSERT(x.is_strongly_reduced());
02441 PPL_ASSERT(x.OK());
02442 #endif
02443 }
02444
02445 template <typename T>
02446 void
02447 Octagonal_Shape<T>
02448 ::non_redundant_matrix_entries(std::vector<Bit_Row>& nr_rows) const {
02449
02450 PPL_ASSERT(space_dim > 0 && !marked_empty() && marked_strongly_closed());
02451 PPL_ASSERT(nr_rows.empty());
02452
02453
02454
02455 nr_rows.resize(2*space_dim);
02456
02457
02458
02459
02460
02461 std::vector<dimension_type> no_sing_leaders;
02462 dimension_type sing_leader = 0;
02463 bool exist_sing_class = false;
02464 std::vector<dimension_type> successor;
02465 compute_successors(successor);
02466 compute_leaders(successor, no_sing_leaders, exist_sing_class, sing_leader);
02467 const dimension_type num_no_sing_leaders = no_sing_leaders.size();
02468
02469
02470
02471
02472 for (dimension_type li = 0; li < num_no_sing_leaders; ++li) {
02473 const dimension_type i = no_sing_leaders[li];
02474 using namespace Implementation::Octagonal_Shapes;
02475 const dimension_type ci = coherent_index(i);
02476 typename OR_Matrix<N>::const_row_reference_type
02477 m_i = *(matrix.row_begin()+i);
02478 if (i % 2 == 0) {
02479
02480
02481
02482
02483
02484 if (i != successor[i]) {
02485 dimension_type j = i;
02486 dimension_type next_j = successor[j];
02487 while (j != next_j) {
02488 nr_rows[next_j].set(j);
02489 j = next_j;
02490 next_j = successor[j];
02491 }
02492 const dimension_type cj = coherent_index(j);
02493 nr_rows[cj].set(ci);
02494 }
02495 }
02496
02497 dimension_type rs_li = (li % 2 != 0) ? li :li+1;
02498
02499 PPL_DIRTY_TEMP(N, tmp);
02500 for (dimension_type lj = 0 ; lj <= rs_li; ++lj) {
02501 const dimension_type j = no_sing_leaders[lj];
02502 const dimension_type cj = coherent_index(j);
02503 const N& m_i_j = m_i[j];
02504 const N& m_i_ci = m_i[ci];
02505 bool to_add = true;
02506
02507
02508
02509 if (j != ci) {
02510 add_assign_r(tmp, m_i_ci, matrix[cj][j], ROUND_UP);
02511 div_2exp_assign_r(tmp, tmp, 1, ROUND_UP);
02512 if (m_i_j >= tmp)
02513
02514 continue;
02515 }
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525
02526 for (dimension_type lk = 0; lk < num_no_sing_leaders; ++lk) {
02527 const dimension_type k = no_sing_leaders[lk];
02528 if (k != i && k != j) {
02529 dimension_type ck = coherent_index(k);
02530 if (k < j)
02531
02532 add_assign_r(tmp, m_i[k], matrix[cj][ck], ROUND_UP);
02533 else if (k < i)
02534
02535 add_assign_r(tmp, m_i[k], matrix[k][j], ROUND_UP);
02536 else
02537
02538 add_assign_r(tmp, matrix[ck][ci], matrix[k][j], ROUND_UP);
02539
02540
02541 if (m_i_j >= tmp) {
02542 to_add = false;
02543 break;
02544 }
02545 }
02546 }
02547
02548 if (to_add)
02549
02550 nr_rows[i].set(j);
02551 }
02552 }
02553
02554
02555
02556
02557
02558 if (exist_sing_class) {
02559 nr_rows[sing_leader].set(sing_leader+1);
02560 if (successor[sing_leader+1] != sing_leader+1) {
02561 dimension_type j = sing_leader;
02562 dimension_type next_jj = successor[j+1];
02563 while (next_jj != j+1) {
02564 nr_rows[next_jj].set(j);
02565 j = next_jj;
02566 next_jj = successor[j+1];
02567 }
02568 nr_rows[j+1].set(j);
02569 }
02570 else
02571 nr_rows[sing_leader+1].set(sing_leader);
02572 }
02573 }
02574
02575 template <typename T>
02576 void
02577 Octagonal_Shape<T>::upper_bound_assign(const Octagonal_Shape& y) {
02578
02579 if (space_dim != y.space_dim)
02580 throw_dimension_incompatible("upper_bound_assign(y)", y);
02581
02582
02583 y.strong_closure_assign();
02584 if (y.marked_empty())
02585 return;
02586 strong_closure_assign();
02587 if (marked_empty()) {
02588 *this = y;
02589 return;
02590 }
02591
02592
02593 typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
02594 for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
02595 matrix_element_end = matrix.element_end();
02596 i != matrix_element_end; ++i, ++j)
02597 max_assign(*i, *j);
02598
02599
02600 PPL_ASSERT(OK());
02601 }
02602
02603 template <typename T>
02604 void
02605 Octagonal_Shape<T>::difference_assign(const Octagonal_Shape& y) {
02606
02607 if (space_dim != y.space_dim)
02608 throw_dimension_incompatible("difference_assign(y)", y);
02609
02610 Octagonal_Shape& x = *this;
02611
02612
02613
02614 x.strong_closure_assign();
02615
02616 if (x.marked_empty())
02617 return;
02618
02619 if (y.marked_empty())
02620 return;
02621
02622
02623
02624
02625 if (x.space_dim == 0) {
02626 x.set_empty();
02627 return;
02628 }
02629
02630
02631
02632 if (y.contains(x)) {
02633 x.set_empty();
02634 return;
02635 }
02636
02637 Octagonal_Shape new_oct(space_dim, EMPTY);
02638
02639
02640
02641 const Constraint_System& y_cs = y.constraints();
02642 for (Constraint_System::const_iterator i = y_cs.begin(),
02643 y_cs_end = y_cs.end(); i != y_cs_end; ++i) {
02644 const Constraint& c = *i;
02645
02646
02647
02648
02649 if (x.relation_with(c).implies(Poly_Con_Relation::is_included()))
02650 continue;
02651 Octagonal_Shape z = x;
02652 const Linear_Expression e = Linear_Expression(c);
02653 z.add_constraint(e <= 0);
02654 if (!z.is_empty())
02655 new_oct.upper_bound_assign(z);
02656 if (c.is_equality()) {
02657 z = x;
02658 z.add_constraint(e >= 0);
02659 if (!z.is_empty())
02660 new_oct.upper_bound_assign(z);
02661 }
02662 }
02663 *this = new_oct;
02664 PPL_ASSERT(OK());
02665 }
02666
02667 template <typename T>
02668 bool
02669 Octagonal_Shape<T>::simplify_using_context_assign(const Octagonal_Shape& y) {
02670 Octagonal_Shape& x = *this;
02671 const dimension_type dim = x.space_dimension();
02672
02673 if (dim != y.space_dimension())
02674 throw_dimension_incompatible("simplify_using_context_assign(y)", y);
02675
02676
02677 if (dim == 0) {
02678 if (y.marked_empty()) {
02679 x.set_zero_dim_univ();
02680 return false;
02681 }
02682 else
02683 return !x.marked_empty();
02684 }
02685
02686
02687
02688 if (x.contains(y)) {
02689 Octagonal_Shape<T> res(dim, UNIVERSE);
02690 x.swap(res);
02691 return false;
02692 }
02693
02694 typedef typename OR_Matrix<N>::row_iterator Row_Iter;
02695 typedef typename OR_Matrix<N>::const_row_iterator Row_CIter;
02696 typedef typename OR_Matrix<N>::element_iterator Elem_Iter;
02697 typedef typename OR_Matrix<N>::const_element_iterator Elem_CIter;
02698
02699
02700 x.strong_closure_assign();
02701 if (x.marked_empty()) {
02702
02703 dimension_type i;
02704 dimension_type j;
02705
02706 for (i = 0; i < 2*dim; i += 2) {
02707
02708
02709
02710
02711 if (!is_plus_infinity(y.matrix_at(i, i+1))) {
02712 j = i+1;
02713 goto found;
02714 }
02715
02716 if (!is_plus_infinity(y.matrix_at(i+1, i))) {
02717 j = i;
02718 ++i;
02719 goto found;
02720 }
02721 }
02722
02723
02724 for (i = 2; i < 2*dim; ++i)
02725 for (j = 0; j < i; ++j) {
02726
02727 if (!is_plus_infinity(y.matrix_at(i, j)))
02728 goto found;
02729 }
02730
02731
02732
02733 return false;
02734
02735 found:
02736
02737 PPL_ASSERT(i < dim && j < dim && i != j);
02738 Octagonal_Shape<T> res(dim, UNIVERSE);
02739
02740 PPL_DIRTY_TEMP(N, tmp);
02741 assign_r(tmp, 1, ROUND_UP);
02742 add_assign_r(tmp, tmp, y.matrix_at(i, j), ROUND_UP);
02743
02744 neg_assign_r(res.matrix_at(j, i), tmp, ROUND_DOWN);
02745 PPL_ASSERT(!is_plus_infinity(res.matrix_at(j, i)));
02746 x.swap(res);
02747 return false;
02748 }
02749
02750
02751
02752
02753 Octagonal_Shape<T> target = x;
02754 target.intersection_assign(y);
02755 const bool bool_result = !target.is_empty();
02756
02757
02758
02759 std::vector<Bit_Row> x_nonred;
02760 x.non_redundant_matrix_entries(x_nonred);
02761
02762 dimension_type x_num_nonred = 0;
02763 for (size_t i = x_nonred.size(); i-- > 0 ; )
02764 x_num_nonred += x_nonred[i].count_ones();
02765 PPL_ASSERT(x_num_nonred > 0);
02766
02767
02768
02769
02770 Octagonal_Shape<T> yy = y;
02771
02772
02773 Octagonal_Shape<T> res(dim, UNIVERSE);
02774
02775 dimension_type res_num_nonred = 0;
02776
02777
02778 std::vector<dimension_type> x_leaders;
02779 x.compute_leaders(x_leaders);
02780
02781
02782
02783 dimension_type sing_leader;
02784 for (sing_leader = 0; sing_leader < 2*dim; sing_leader += 2) {
02785 if (sing_leader == x_leaders[sing_leader]) {
02786 const N& x_s_ss = x.matrix_at(sing_leader, sing_leader+1);
02787 const N& x_ss_s = x.matrix_at(sing_leader+1, sing_leader);
02788 if (is_additive_inverse(x_s_ss, x_ss_s))
02789
02790 break;
02791 }
02792 }
02793
02794
02795 for (dimension_type i = sing_leader; i < 2*dim; i += 2) {
02796 if (x_leaders[i] != sing_leader)
02797 continue;
02798
02799
02800 const N& x_i_ii = x.matrix_at(i, i+1);
02801 N& yy_i_ii = yy.matrix_at(i, i+1);
02802 if (x_i_ii < yy_i_ii) {
02803
02804 res.matrix_at(i, i+1) = x_i_ii;
02805 ++res_num_nonred;
02806
02807 yy_i_ii = x_i_ii;
02808 yy.reset_strongly_closed();
02809 }
02810 const N& x_ii_i = x.matrix_at(i+1, i);
02811 N& yy_ii_i = yy.matrix_at(i+1, i);
02812 if (x_ii_i < yy_ii_i) {
02813
02814 res.matrix_at(i+1, i) = x_ii_i;
02815 ++res_num_nonred;
02816
02817 yy_ii_i = x_ii_i;
02818 yy.reset_strongly_closed();
02819 }
02820
02821 if (!yy.marked_strongly_closed()) {
02822 Variable var_i(i/2);
02823 yy.incremental_strong_closure_assign(var_i);
02824 if (target.contains(yy)) {
02825
02826 if (res_num_nonred < x_num_nonred) {
02827 res.reset_strongly_closed();
02828 x.swap(res);
02829 }
02830 return bool_result;
02831 }
02832 }
02833 }
02834
02835
02836 for (dimension_type i = 0; i < 2*dim; ++i) {
02837 const dimension_type j = x_leaders[i];
02838 if (j == i || j == sing_leader)
02839 continue;
02840 const N& x_i_j = x.matrix_at(i, j);
02841 PPL_ASSERT(!is_plus_infinity(x_i_j));
02842 N& yy_i_j = yy.matrix_at(i, j);
02843 if (x_i_j < yy_i_j) {
02844 res.matrix_at(i, j) = x_i_j;
02845 ++res_num_nonred;
02846
02847 yy_i_j = x_i_j;
02848 yy.reset_strongly_closed();
02849 }
02850 const N& x_j_i = x.matrix_at(j, i);
02851 N& yy_j_i = yy.matrix_at(j, i);
02852 PPL_ASSERT(!is_plus_infinity(x_j_i));
02853 if (x_j_i < yy_j_i) {
02854 res.matrix_at(j, i) = x_j_i;
02855 ++res_num_nonred;
02856
02857 yy_j_i = x_j_i;
02858 yy.reset_strongly_closed();
02859 }
02860
02861 if (!yy.marked_strongly_closed()) {
02862 Variable var_j(j/2);
02863 yy.incremental_strong_closure_assign(var_j);
02864 if (target.contains(yy)) {
02865
02866 if (res_num_nonred < x_num_nonred) {
02867 res.reset_strongly_closed();
02868 x.swap(res);
02869 }
02870 return bool_result;
02871 }
02872 }
02873 }
02874
02875
02876
02877
02878 for (dimension_type i = 0; i < 2*dim; ++i) {
02879 if (i != x_leaders[i])
02880 continue;
02881 const Bit_Row& x_nonred_i = x_nonred[i];
02882 for (dimension_type j = 0; j < 2*dim; ++j) {
02883 if (j != x_leaders[j])
02884 continue;
02885 if (i >= j) {
02886 if (!x_nonred_i[j])
02887 continue;
02888 }
02889 else if (!x_nonred[j][i])
02890 continue;
02891 N& yy_i_j = yy.matrix_at(i, j);
02892 const N& x_i_j = x.matrix_at(i, j);
02893 if (x_i_j < yy_i_j) {
02894 res.matrix_at(i, j) = x_i_j;
02895 ++res_num_nonred;
02896
02897 yy_i_j = x_i_j;
02898 yy.reset_strongly_closed();
02899 Variable var(i/2);
02900 yy.incremental_strong_closure_assign(var);
02901 if (target.contains(yy)) {
02902
02903 if (res_num_nonred < x_num_nonred) {
02904 res.reset_strongly_closed();
02905 x.swap(res);
02906 }
02907 return bool_result;
02908 }
02909 }
02910 }
02911 }
02912
02913 throw std::runtime_error("PPL internal error");
02914 }
02915
02916 template <typename T>
02917 void
02918 Octagonal_Shape<T>::add_space_dimensions_and_embed(dimension_type m) {
02919
02920 if (m == 0)
02921 return;
02922
02923 const dimension_type new_dim = space_dim + m;
02924 const bool was_zero_dim_univ = !marked_empty() && space_dim == 0;
02925
02926
02927
02928 matrix.grow(new_dim);
02929 space_dim = new_dim;
02930
02931
02932 if (was_zero_dim_univ)
02933 set_strongly_closed();
02934
02935 PPL_ASSERT(OK());
02936 }
02937
02938 template <typename T>
02939 void
02940 Octagonal_Shape<T>::add_space_dimensions_and_project(dimension_type m) {
02941
02942 if (m == 0)
02943 return;
02944
02945 const dimension_type n = matrix.num_rows();
02946
02947
02948
02949 add_space_dimensions_and_embed(m);
02950
02951
02952 for (typename OR_Matrix<N>::row_iterator i = matrix.row_begin() + n,
02953 matrix_row_end = matrix.row_end(); i != matrix_row_end; i += 2) {
02954 typename OR_Matrix<N>::row_reference_type x_i = *i;
02955 typename OR_Matrix<N>::row_reference_type x_ci = *(i+1);
02956 const dimension_type ind = i.index();
02957 assign_r(x_i[ind+1], 0, ROUND_NOT_NEEDED);
02958 assign_r(x_ci[ind], 0, ROUND_NOT_NEEDED);
02959 }
02960
02961 if (marked_strongly_closed())
02962 reset_strongly_closed();
02963 PPL_ASSERT(OK());
02964 }
02965
02966 template <typename T>
02967 void
02968 Octagonal_Shape<T>::remove_space_dimensions(const Variables_Set& vars) {
02969
02970
02971
02972 if (vars.empty()) {
02973 PPL_ASSERT(OK());
02974 return;
02975 }
02976
02977
02978 const dimension_type min_space_dim = vars.space_dimension();
02979 if (space_dim < min_space_dim)
02980 throw_dimension_incompatible("remove_space_dimensions(vs)", min_space_dim);
02981
02982 const dimension_type new_space_dim = space_dim - vars.size();
02983
02984 strong_closure_assign();
02985
02986
02987 if (new_space_dim == 0) {
02988 matrix.shrink(0);
02989 if (!marked_empty())
02990
02991 set_zero_dim_univ();
02992 space_dim = 0;
02993 PPL_ASSERT(OK());
02994 return;
02995 }
02996
02997
02998
02999
03000 Variables_Set::const_iterator vsi = vars.begin();
03001 dimension_type ftr = *vsi;
03002 dimension_type ftr_size = 2*ftr*(ftr+1);
03003 typename OR_Matrix<N>::element_iterator
03004 iter = matrix.element_begin()+ftr_size;
03005
03006 dimension_type i = ftr + 1;
03007 while (i < space_dim) {
03008 if (vars.count(i) != 0)
03009 ++i;
03010 else {
03011 typename OR_Matrix<N>::row_iterator
03012 row_iter = matrix.row_begin()+2*i;
03013 typename OR_Matrix<N>::row_reference_type
03014 row_ref = *row_iter;
03015 typename OR_Matrix<N>::row_reference_type
03016 row_ref1 = *(++row_iter);
03017
03018
03019
03020
03021
03022
03023 for (dimension_type j = 0; j <= i; ++j)
03024 if (vars.count(j) == 0) {
03025 assign_or_swap(*(iter++), row_ref[2*j]);
03026 assign_or_swap(*(iter++), row_ref[2*j+1]);
03027 }
03028 for (dimension_type j = 0; j <= i; ++j)
03029 if (vars.count(j) == 0) {
03030 assign_or_swap(*(iter++), row_ref1[2*j]);
03031 assign_or_swap(*(iter++), row_ref1[2*j+1]);
03032 }
03033 ++i;
03034 }
03035 }
03036
03037 matrix.shrink(new_space_dim);
03038 space_dim = new_space_dim;
03039 PPL_ASSERT(OK());
03040 }
03041
03042 template <typename T>
03043 template <typename Partial_Function>
03044 void
03045 Octagonal_Shape<T>::map_space_dimensions(const Partial_Function& pfunc) {
03046 if (space_dim == 0)
03047 return;
03048
03049 if (pfunc.has_empty_codomain()) {
03050
03051 remove_higher_space_dimensions(0);
03052 return;
03053 }
03054
03055 const dimension_type new_space_dim = pfunc.max_in_codomain() + 1;
03056
03057
03058 if (new_space_dim < space_dim)
03059 strong_closure_assign();
03060
03061
03062
03063 if (marked_empty()) {
03064 remove_higher_space_dimensions(new_space_dim);
03065 return;
03066 }
03067
03068
03069 OR_Matrix<N> x(new_space_dim);
03070
03071 typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
03072 typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
03073
03074 Row_Iterator m_begin = x.row_begin();
03075
03076 for (Row_Iterator i_iter = matrix.row_begin(), i_end = matrix.row_end();
03077 i_iter != i_end; i_iter += 2) {
03078 dimension_type new_i;
03079 dimension_type i = i_iter.index()/2;
03080
03081
03082
03083 if (pfunc.maps(i, new_i)) {
03084 Row_Reference r_i = *i_iter;
03085 Row_Reference r_ii = *(i_iter + 1);
03086 dimension_type double_new_i = 2*new_i;
03087 Row_Iterator x_iter = m_begin + double_new_i;
03088 Row_Reference x_i = *x_iter;
03089 Row_Reference x_ii = *(x_iter + 1);
03090 for (dimension_type j = 0; j <= i; ++j) {
03091 dimension_type new_j;
03092
03093 if (pfunc.maps(j, new_j)) {
03094 dimension_type dj = 2*j;
03095 dimension_type double_new_j = 2*new_j;
03096
03097
03098
03099
03100 if (new_i >= new_j) {
03101 assign_or_swap(x_i[double_new_j], r_i[dj]);
03102 assign_or_swap(x_ii[double_new_j], r_ii[dj]);
03103 assign_or_swap(x_ii[double_new_j+1], r_ii[dj + 1]);
03104 assign_or_swap(x_i[double_new_j+1], r_i[dj + 1]);
03105 }
03106 else {
03107 Row_Iterator xj_iter = m_begin + double_new_j;
03108 Row_Reference x_j = *xj_iter;
03109 Row_Reference x_jj = *(xj_iter + 1);
03110 assign_or_swap(x_jj[double_new_i+1], r_i[dj]);
03111 assign_or_swap(x_jj[double_new_i], r_ii[dj]);
03112 assign_or_swap(x_j[double_new_i+1], r_i[dj+1]);
03113 assign_or_swap(x_j[double_new_i], r_ii[dj+1]);
03114 }
03115
03116 }
03117 }
03118 }
03119 }
03120
03121 std::swap(matrix, x);
03122 space_dim = new_space_dim;
03123 PPL_ASSERT(OK());
03124 }
03125
03126 template <typename T>
03127 void
03128 Octagonal_Shape<T>::intersection_assign(const Octagonal_Shape& y) {
03129
03130 if (space_dim != y.space_dim)
03131 throw_dimension_incompatible("intersection_assign(y)", y);
03132
03133
03134 if (marked_empty())
03135 return;
03136 if (y.marked_empty()) {
03137 set_empty();
03138 return;
03139 }
03140
03141
03142
03143 if (space_dim == 0)
03144 return;
03145
03146
03147
03148 bool changed = false;
03149
03150 typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
03151 for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
03152 matrix_element_end = matrix.element_end();
03153 i != matrix_element_end;
03154 ++i, ++j) {
03155 N& elem = *i;
03156 const N& y_elem = *j;
03157 if (y_elem < elem) {
03158 elem = y_elem;
03159 changed = true;
03160 }
03161 }
03162
03163
03164 if (changed && marked_strongly_closed())
03165 reset_strongly_closed();
03166 PPL_ASSERT(OK());
03167 }
03168
03169 template <typename T>
03170 template <typename Iterator>
03171 void
03172 Octagonal_Shape<T>::CC76_extrapolation_assign(const Octagonal_Shape& y,
03173 Iterator first, Iterator last,
03174 unsigned* tp) {
03175
03176 if (space_dim != y.space_dim)
03177 throw_dimension_incompatible("CC76_extrapolation_assign(y)", y);
03178
03179 #ifndef NDEBUG
03180 {
03181
03182 const Octagonal_Shape x_copy = *this;
03183 const Octagonal_Shape y_copy = y;
03184 PPL_ASSERT(x_copy.contains(y_copy));
03185 }
03186 #endif
03187
03188
03189
03190 if (space_dim == 0)
03191 return;
03192
03193 strong_closure_assign();
03194
03195 if (marked_empty())
03196 return;
03197 y.strong_closure_assign();
03198
03199 if (y.marked_empty())
03200 return;
03201
03202
03203 if (tp != 0 && *tp > 0) {
03204 Octagonal_Shape x_tmp(*this);
03205 x_tmp.CC76_extrapolation_assign(y, first, last, 0);
03206
03207 if (!contains(x_tmp))
03208 --(*tp);
03209 return;
03210 }
03211
03212
03213
03214
03215
03216
03217
03218
03219
03220 typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
03221 for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
03222 matrix_element_end = matrix.element_end();
03223 i != matrix_element_end;
03224 ++i, ++j) {
03225 const N& y_elem = *j;
03226 N& elem = *i;
03227 if (y_elem < elem) {
03228 Iterator k = std::lower_bound(first, last, elem);
03229 if (k != last) {
03230 if (elem < *k)
03231 assign_r(elem, *k, ROUND_UP);
03232 }
03233 else
03234 assign_r(elem, PLUS_INFINITY, ROUND_NOT_NEEDED);
03235 }
03236 }
03237
03238 reset_strongly_closed();
03239 PPL_ASSERT(OK());
03240 }
03241
03242 template <typename T>
03243 void
03244 Octagonal_Shape<T>
03245 ::get_limiting_octagon(const Constraint_System& cs,
03246 Octagonal_Shape& limiting_octagon) const {
03247 const dimension_type cs_space_dim = cs.space_dimension();
03248
03249 PPL_ASSERT(cs_space_dim <= space_dim);
03250
03251 strong_closure_assign();
03252 bool is_oct_changed = false;
03253
03254
03255 PPL_DIRTY_TEMP_COEFFICIENT(coeff);
03256 PPL_DIRTY_TEMP_COEFFICIENT(term);
03257 PPL_DIRTY_TEMP(N, d);
03258
03259 for (Constraint_System::const_iterator cs_i = cs.begin(),
03260 cs_end = cs.end(); cs_i != cs_end; ++cs_i) {
03261 const Constraint& c = *cs_i;
03262 dimension_type num_vars = 0;
03263 dimension_type i = 0;
03264 dimension_type j = 0;
03265
03266 if (!extract_octagonal_difference(c, cs_space_dim, num_vars, i, j,
03267 coeff, term))
03268 continue;
03269
03270 typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
03271 typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
03272 typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
03273 typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
03274 Row_iterator m_begin = matrix.row_begin();
03275
03276 Row_iterator i_iter = m_begin + i;
03277 Row_reference m_i = *i_iter;
03278 OR_Matrix<N>& lo_mat = limiting_octagon.matrix;
03279 Row_Iterator lo_iter = lo_mat.row_begin() + i;
03280 Row_Reference lo_m_i = *lo_iter;
03281 N& lo_m_i_j = lo_m_i[j];
03282 if (coeff < 0)
03283 neg_assign(coeff);
03284
03285 div_round_up(d, term, coeff);
03286 if (m_i[j] <= d)
03287 if (c.is_inequality()) {
03288 if (lo_m_i_j > d) {
03289 lo_m_i_j = d;
03290 is_oct_changed = true;
03291 }
03292 else {
03293
03294 if (i % 2 == 0) {
03295 ++i_iter;
03296 ++lo_iter;
03297 }
03298 else {
03299 --i_iter;
03300 --lo_iter;
03301 }
03302 Row_reference m_ci = *i_iter;
03303 Row_Reference lo_m_ci = *lo_iter;
03304
03305 using namespace Implementation::Octagonal_Shapes;
03306 dimension_type cj = coherent_index(j);
03307 N& lo_m_ci_cj = lo_m_ci[cj];
03308 neg_assign(term);
03309 div_round_up(d, term, coeff);
03310 if (m_ci[cj] <= d && lo_m_ci_cj > d) {
03311 lo_m_ci_cj = d;
03312 is_oct_changed = true;
03313 }
03314 }
03315 }
03316 }
03317
03318
03319 if (is_oct_changed && limiting_octagon.marked_strongly_closed())
03320 limiting_octagon.reset_strongly_closed();
03321 }
03322
03323 template <typename T>
03324 void
03325 Octagonal_Shape<T>
03326 ::limited_CC76_extrapolation_assign(const Octagonal_Shape& y,
03327 const Constraint_System& cs,
03328 unsigned* tp) {
03329
03330
03331 if (space_dim != y.space_dim)
03332 throw_dimension_incompatible("limited_CC76_extrapolation_assign(y, cs)",
03333 y);
03334
03335 const dimension_type cs_space_dim = cs.space_dimension();
03336 if (space_dim < cs_space_dim)
03337 throw_constraint_incompatible("limited_CC76_extrapolation_assign(y, cs)");
03338
03339
03340 if (cs.has_strict_inequalities())
03341 throw_constraint_incompatible("limited_CC76_extrapolation_assign(y, cs)");
03342
03343
03344
03345
03346 if (space_dim == 0)
03347 return;
03348
03349 #ifndef NDEBUG
03350 {
03351
03352 const Octagonal_Shape x_copy = *this;
03353 const Octagonal_Shape y_copy = y;
03354 PPL_ASSERT(x_copy.contains(y_copy));
03355 }
03356 #endif
03357
03358
03359 if (marked_empty())
03360 return;
03361
03362 if (y.marked_empty())
03363 return;
03364
03365 Octagonal_Shape limiting_octagon(space_dim, UNIVERSE);
03366 get_limiting_octagon(cs, limiting_octagon);
03367 CC76_extrapolation_assign(y, tp);
03368 intersection_assign(limiting_octagon);
03369 }
03370
03371 template <typename T>
03372 void
03373 Octagonal_Shape<T>::BHMZ05_widening_assign(const Octagonal_Shape& y,
03374 unsigned* tp) {
03375
03376 if (space_dim != y.space_dim)
03377 throw_dimension_incompatible("BHMZ05_widening_assign(y)", y);
03378
03379 #ifndef NDEBUG
03380 {
03381
03382 const Octagonal_Shape x_copy = *this;
03383 const Octagonal_Shape y_copy = y;
03384 PPL_ASSERT(x_copy.contains(y_copy));
03385 }
03386 #endif
03387
03388
03389 const dimension_type y_affine_dim = y.affine_dimension();
03390
03391
03392
03393 if (y_affine_dim == 0)
03394 return;
03395
03396
03397
03398 const dimension_type x_affine_dim = affine_dimension();
03399 PPL_ASSERT(x_affine_dim >= y_affine_dim);
03400 if (x_affine_dim != y_affine_dim)
03401 return;
03402
03403
03404 if (tp != 0 && *tp > 0) {
03405 Octagonal_Shape x_tmp(*this);
03406 x_tmp.BHMZ05_widening_assign(y, 0);
03407
03408 if (!contains(x_tmp))
03409 --(*tp);
03410 return;
03411 }
03412
03413
03414 PPL_ASSERT(marked_strongly_closed() && y.marked_strongly_closed());
03415
03416 y.strong_reduction_assign();
03417
03418
03419 typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
03420 for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
03421 matrix_element_end = matrix.element_end();
03422 i != matrix_element_end;
03423 ++i, ++j) {
03424 N& elem = *i;
03425
03426
03427
03428 if (*j != elem)
03429 assign_r(elem, PLUS_INFINITY, ROUND_NOT_NEEDED);
03430 }
03431 reset_strongly_closed();
03432 PPL_ASSERT(OK());
03433 }
03434
03435 template <typename T>
03436 void
03437 Octagonal_Shape<T>
03438 ::limited_BHMZ05_extrapolation_assign(const Octagonal_Shape& y,
03439 const Constraint_System& cs,
03440 unsigned* tp) {
03441
03442
03443 if (space_dim != y.space_dim)
03444 throw_dimension_incompatible("limited_BHMZ05_extrapolation_assign(y, cs)",
03445 y);
03446
03447 const dimension_type cs_space_dim = cs.space_dimension();
03448 if (space_dim < cs_space_dim)
03449 throw_constraint_incompatible("limited_CH78_extrapolation_assign(y, cs)");
03450
03451
03452 if (cs.has_strict_inequalities())
03453 throw_constraint_incompatible("limited_CH78_extrapolation_assign(y, cs)");
03454
03455
03456
03457
03458 if (space_dim == 0)
03459 return;
03460
03461 #ifndef NDEBUG
03462 {
03463
03464 const Octagonal_Shape x_copy = *this;
03465 const Octagonal_Shape y_copy = y;
03466 PPL_ASSERT(x_copy.contains(y_copy));
03467 }
03468 #endif
03469
03470
03471 if (marked_empty())
03472 return;
03473
03474 if (y.marked_empty())
03475 return;
03476
03477 Octagonal_Shape limiting_octagon(space_dim, UNIVERSE);
03478 get_limiting_octagon(cs, limiting_octagon);
03479 BHMZ05_widening_assign(y, tp);
03480 intersection_assign(limiting_octagon);
03481 }
03482
03483 template <typename T>
03484 void
03485 Octagonal_Shape<T>::CC76_narrowing_assign(const Octagonal_Shape& y) {
03486
03487 if (space_dim != y.space_dim)
03488 throw_dimension_incompatible("CC76_narrowing_assign(y)", y);
03489
03490 #ifndef NDEBUG
03491 {
03492
03493 const Octagonal_Shape x_copy = *this;
03494 const Octagonal_Shape y_copy = y;
03495 PPL_ASSERT(y_copy.contains(x_copy));
03496 }
03497 #endif
03498
03499
03500
03501 if (space_dim == 0)
03502 return;
03503
03504 y.strong_closure_assign();
03505
03506 if (y.marked_empty())
03507 return;
03508 strong_closure_assign();
03509
03510 if (marked_empty())
03511 return;
03512
03513
03514
03515 bool is_oct_changed = false;
03516 typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
03517 for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
03518 matrix_element_end = matrix.element_end();
03519 i != matrix_element_end;
03520 ++i, ++j) {
03521 if (!is_plus_infinity(*i)
03522 && !is_plus_infinity(*j)
03523 && *i != *j) {
03524 *i = *j;
03525 is_oct_changed = true;
03526 }
03527 }
03528
03529 if (is_oct_changed && marked_strongly_closed())
03530 reset_strongly_closed();
03531 PPL_ASSERT(OK());
03532 }
03533
03534 template <typename T>
03535 void
03536 Octagonal_Shape<T>
03537 ::deduce_v_pm_u_bounds(const dimension_type v_id,
03538 const dimension_type last_id,
03539 const Linear_Expression& sc_expr,
03540 Coefficient_traits::const_reference sc_den,
03541 const N& ub_v) {
03542
03543 PPL_ASSERT(sc_den > 0);
03544 PPL_ASSERT(!is_plus_infinity(ub_v));
03545
03546 PPL_DIRTY_TEMP0(mpq_class, mpq_sc_den);
03547 assign_r(mpq_sc_den, sc_den, ROUND_NOT_NEEDED);
03548
03549
03550 const dimension_type n_v = 2*v_id;
03551 typename OR_Matrix<N>::row_reference_type m_cv = matrix[n_v+1];
03552
03553
03554 PPL_DIRTY_TEMP(N, half);
03555 PPL_DIRTY_TEMP0(mpq_class, minus_lb_u);
03556 PPL_DIRTY_TEMP0(mpq_class, q);
03557 PPL_DIRTY_TEMP0(mpq_class, minus_q);
03558 PPL_DIRTY_TEMP0(mpq_class, ub_u);
03559 PPL_DIRTY_TEMP0(mpq_class, lb_u);
03560 PPL_DIRTY_TEMP(N, up_approx);
03561 PPL_DIRTY_TEMP_COEFFICIENT(minus_expr_u);
03562
03563 for (dimension_type u_id = last_id+1; u_id-- > 0; ) {
03564
03565 if (u_id == v_id)
03566 continue;
03567 const Coefficient& expr_u = sc_expr.coefficient(Variable(u_id));
03568
03569 if (expr_u == 0)
03570 continue;
03571
03572 const dimension_type n_u = u_id*2;
03573
03574 if (expr_u > 0) {
03575 if (expr_u >= sc_den) {
03576
03577
03578
03579
03580 div_2exp_assign_r(half, matrix[n_u+1][n_u], 1, ROUND_UP);
03581 N& m_v_minus_u = (n_v < n_u) ? matrix[n_u][n_v] : m_cv[n_u+1];
03582 sub_assign_r(m_v_minus_u, ub_v, half, ROUND_UP);
03583 }
03584 else {
03585
03586 typename OR_Matrix<N>::row_reference_type m_u = matrix[n_u];
03587 const N& m_u_cu = m_u[n_u+1];
03588 if (!is_plus_infinity(m_u_cu)) {
03589
03590
03591
03592
03593 assign_r(minus_lb_u, m_u_cu, ROUND_NOT_NEEDED);
03594 div_2exp_assign_r(minus_lb_u, minus_lb_u, 1, ROUND_NOT_NEEDED);
03595 assign_r(q, expr_u, ROUND_NOT_NEEDED);
03596 div_assign_r(q, q, mpq_sc_den, ROUND_NOT_NEEDED);
03597 assign_r(ub_u, matrix[n_u+1][n_u], ROUND_NOT_NEEDED);
03598 div_2exp_assign_r(ub_u, ub_u, 1, ROUND_NOT_NEEDED);
03599
03600 add_assign_r(ub_u, ub_u, minus_lb_u, ROUND_NOT_NEEDED);
03601
03602 sub_mul_assign_r(minus_lb_u, q, ub_u, ROUND_NOT_NEEDED);
03603 assign_r(up_approx, minus_lb_u, ROUND_UP);
03604
03605 N& m_v_minus_u = (n_v < n_u) ? m_u[n_v] : m_cv[n_u+1];
03606 add_assign_r(m_v_minus_u, ub_v, up_approx, ROUND_UP);
03607 }
03608 }
03609 }
03610 else {
03611 PPL_ASSERT(expr_u < 0);
03612
03613 neg_assign(minus_expr_u, expr_u);
03614 if (minus_expr_u >= sc_den) {
03615
03616
03617
03618
03619 div_2exp_assign_r(half, matrix[n_u][n_u+1], 1, ROUND_UP);
03620 N& m_v_plus_u = (n_v < n_u) ? matrix[n_u+1][n_v] : m_cv[n_u];
03621 sub_assign_r(m_v_plus_u, ub_v, half, ROUND_UP);
03622 }
03623 else {
03624
03625 typename OR_Matrix<N>::row_reference_type m_cu = matrix[n_u+1];
03626 const N& m_cu_u = m_cu[n_u];
03627 if (!is_plus_infinity(m_cu_u)) {
03628
03629
03630
03631
03632 assign_r(ub_u, m_cu[n_u], ROUND_NOT_NEEDED);
03633 div_2exp_assign_r(ub_u, ub_u, 1, ROUND_NOT_NEEDED);
03634 assign_r(minus_q, minus_expr_u, ROUND_NOT_NEEDED);
03635 div_assign_r(minus_q, minus_q, mpq_sc_den, ROUND_NOT_NEEDED);
03636 assign_r(lb_u, matrix[n_u][n_u+1], ROUND_NOT_NEEDED);
03637 div_2exp_assign_r(lb_u, lb_u, 1, ROUND_NOT_NEEDED);
03638 neg_assign_r(lb_u, lb_u, ROUND_NOT_NEEDED);
03639
03640 sub_assign_r(lb_u, lb_u, ub_u, ROUND_NOT_NEEDED);
03641
03642 add_mul_assign_r(ub_u, minus_q, lb_u, ROUND_NOT_NEEDED);
03643 assign_r(up_approx, ub_u, ROUND_UP);
03644
03645 N& m_v_plus_u = (n_v < n_u) ? m_cu[n_v] : m_cv[n_u];
03646 add_assign_r(m_v_plus_u, ub_v, up_approx, ROUND_UP);
03647 }
03648 }
03649 }
03650 }
03651 }
03652
03653 template <typename T>
03654 void
03655 Octagonal_Shape<T>
03656 ::deduce_minus_v_pm_u_bounds(const dimension_type v_id,
03657 const dimension_type last_id,
03658 const Linear_Expression& sc_expr,
03659 Coefficient_traits::const_reference sc_den,
03660 const N& minus_lb_v) {
03661
03662 PPL_ASSERT(sc_den > 0);
03663 PPL_ASSERT(!is_plus_infinity(minus_lb_v));
03664
03665 PPL_DIRTY_TEMP0(mpq_class, mpq_sc_den);
03666 assign_r(mpq_sc_den, sc_den, ROUND_NOT_NEEDED);
03667
03668
03669 const dimension_type n_v = 2*v_id;
03670 typename OR_Matrix<N>::row_reference_type m_v = matrix[n_v];
03671
03672
03673 PPL_DIRTY_TEMP(N, half);
03674 PPL_DIRTY_TEMP0(mpq_class, ub_u);
03675 PPL_DIRTY_TEMP0(mpq_class, q);
03676 PPL_DIRTY_TEMP0(mpq_class, minus_lb_u);
03677 PPL_DIRTY_TEMP(N, up_approx);
03678 PPL_DIRTY_TEMP_COEFFICIENT(minus_expr_u);
03679
03680 for (dimension_type u_id = last_id+1; u_id-- > 0; ) {
03681
03682 if (u_id == v_id)
03683 continue;
03684 const Coefficient& expr_u = sc_expr.coefficient(Variable(u_id));
03685
03686 if (expr_u == 0)
03687 continue;
03688
03689 const dimension_type n_u = u_id*2;
03690
03691 if (expr_u > 0) {
03692 if (expr_u >= sc_den) {
03693
03694
03695
03696
03697
03698 div_2exp_assign_r(half, matrix[n_u][n_u+1], 1, ROUND_UP);
03699 N& m_u_minus_v = (n_v < n_u) ? matrix[n_u+1][n_v+1] : m_v[n_u];
03700 sub_assign_r(m_u_minus_v, minus_lb_v, half, ROUND_UP);
03701 }
03702 else {
03703
03704 typename OR_Matrix<N>::row_reference_type m_cu = matrix[n_u+1];
03705 const N& m_cu_u = m_cu[n_u];
03706 if (!is_plus_infinity(m_cu_u)) {
03707
03708
03709
03710
03711 assign_r(ub_u, m_cu[n_u], ROUND_NOT_NEEDED);
03712 div_2exp_assign_r(ub_u, ub_u, 1, ROUND_NOT_NEEDED);
03713 assign_r(q, expr_u, ROUND_NOT_NEEDED);
03714 div_assign_r(q, q, mpq_sc_den, ROUND_NOT_NEEDED);
03715 assign_r(minus_lb_u, matrix[n_u][n_u+1], ROUND_NOT_NEEDED);
03716 div_2exp_assign_r(minus_lb_u, minus_lb_u, 1, ROUND_NOT_NEEDED);
03717
03718 add_assign_r(minus_lb_u, ub_u, minus_lb_u, ROUND_NOT_NEEDED);
03719
03720 sub_mul_assign_r(ub_u, q, minus_lb_u, ROUND_NOT_NEEDED);
03721 assign_r(up_approx, ub_u, ROUND_UP);
03722
03723 N& m_u_minus_v = (n_v < n_u) ? m_cu[n_v+1] : m_v[n_u];
03724 add_assign_r(m_u_minus_v, minus_lb_v, up_approx, ROUND_UP);
03725 }
03726 }
03727 }
03728 else {
03729 PPL_ASSERT(expr_u < 0);
03730
03731 neg_assign(minus_expr_u, expr_u);
03732 if (minus_expr_u >= sc_den) {
03733
03734
03735
03736
03737 div_2exp_assign_r(half, matrix[n_u+1][n_u], 1, ROUND_UP);
03738 N& m_minus_v_minus_u = (n_v < n_u) ? matrix[n_u][n_v+1] : m_v[n_u+1];
03739 sub_assign_r(m_minus_v_minus_u, minus_lb_v, half, ROUND_UP);
03740 }
03741 else {
03742
03743 typename OR_Matrix<N>::row_reference_type m_u = matrix[n_u];
03744 const N& m_u_cu = m_u[n_u+1];
03745 if (!is_plus_infinity(m_u_cu)) {
03746
03747
03748
03749
03750 assign_r(ub_u, matrix[n_u+1][n_u], ROUND_NOT_NEEDED);
03751 div_2exp_assign_r(ub_u, ub_u, 1, ROUND_NOT_NEEDED);
03752 assign_r(q, expr_u, ROUND_NOT_NEEDED);
03753 div_assign_r(q, q, mpq_sc_den, ROUND_NOT_NEEDED);
03754 assign_r(minus_lb_u, m_u[n_u+1], ROUND_NOT_NEEDED);
03755 div_2exp_assign_r(minus_lb_u, minus_lb_u, 1, ROUND_NOT_NEEDED);
03756
03757 add_assign_r(ub_u, ub_u, minus_lb_u, ROUND_NOT_NEEDED);
03758
03759 add_mul_assign_r(minus_lb_u, q, ub_u, ROUND_NOT_NEEDED);
03760 assign_r(up_approx, minus_lb_u, ROUND_UP);
03761
03762 N& m_minus_v_minus_u = (n_v < n_u) ? m_u[n_v+1] : m_v[n_u+1];
03763 add_assign_r(m_minus_v_minus_u, minus_lb_v, up_approx, ROUND_UP);
03764 }
03765 }
03766 }
03767 }
03768 }
03769
03770 template <typename T>
03771 void
03772 Octagonal_Shape<T>
03773 ::forget_all_octagonal_constraints(const dimension_type v_id) {
03774 PPL_ASSERT(v_id < space_dim);
03775 const dimension_type n_v = 2*v_id;
03776 typename OR_Matrix<N>::row_iterator m_iter = matrix.row_begin() + n_v;
03777 typename OR_Matrix<N>::row_reference_type r_v = *m_iter;
03778 typename OR_Matrix<N>::row_reference_type r_cv = *(++m_iter);
03779 for (dimension_type h = m_iter.row_size(); h-- > 0; ) {
03780 assign_r(r_v[h], PLUS_INFINITY, ROUND_NOT_NEEDED);
03781 assign_r(r_cv[h], PLUS_INFINITY, ROUND_NOT_NEEDED);
03782 }
03783 ++m_iter;
03784 for (typename OR_Matrix<N>::row_iterator m_end = matrix.row_end();
03785 m_iter != m_end; ++m_iter) {
03786 typename OR_Matrix<N>::row_reference_type r = *m_iter;
03787 assign_r(r[n_v], PLUS_INFINITY, ROUND_NOT_NEEDED);
03788 assign_r(r[n_v+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
03789 }
03790 }
03791
03792 template <typename T>
03793 void
03794 Octagonal_Shape<T>
03795 ::forget_binary_octagonal_constraints(const dimension_type v_id) {
03796 PPL_ASSERT(v_id < space_dim);
03797 const dimension_type n_v = 2*v_id;
03798 typename OR_Matrix<N>::row_iterator m_iter = matrix.row_begin() + n_v;
03799 typename OR_Matrix<N>::row_reference_type r_v = *m_iter;
03800 typename OR_Matrix<N>::row_reference_type r_cv = *(++m_iter);
03801 for (dimension_type k = n_v; k-- > 0; ) {
03802 assign_r(r_v[k], PLUS_INFINITY, ROUND_NOT_NEEDED);
03803 assign_r(r_cv[k], PLUS_INFINITY, ROUND_NOT_NEEDED);
03804 }
03805 ++m_iter;
03806 for (typename OR_Matrix<N>::row_iterator m_end = matrix.row_end();
03807 m_iter != m_end; ++m_iter) {
03808 typename OR_Matrix<N>::row_reference_type r = *m_iter;
03809 assign_r(r[n_v], PLUS_INFINITY, ROUND_NOT_NEEDED);
03810 assign_r(r[n_v+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
03811 }
03812 }
03813
03814 template <typename T>
03815 void
03816 Octagonal_Shape<T>::unconstrain(const Variable var) {
03817
03818 const dimension_type var_id = var.id();
03819 if (space_dimension() < var_id + 1)
03820 throw_dimension_incompatible("unconstrain(var)", var_id + 1);
03821
03822
03823 strong_closure_assign();
03824
03825
03826 if (marked_empty())
03827 return;
03828
03829 forget_all_octagonal_constraints(var_id);
03830
03831 PPL_ASSERT(OK());
03832 }
03833
03834 template <typename T>
03835 void
03836 Octagonal_Shape<T>::unconstrain(const Variables_Set& vars) {
03837
03838
03839 if (vars.empty())
03840 return;
03841
03842
03843 const dimension_type min_space_dim = vars.space_dimension();
03844 if (space_dimension() < min_space_dim)
03845 throw_dimension_incompatible("unconstrain(vs)", min_space_dim);
03846
03847
03848 strong_closure_assign();
03849
03850
03851 if (marked_empty())
03852 return;
03853
03854 for (Variables_Set::const_iterator vsi = vars.begin(),
03855 vsi_end = vars.end(); vsi != vsi_end; ++vsi)
03856 forget_all_octagonal_constraints(*vsi);
03857
03858 PPL_ASSERT(OK());
03859 }
03860
03861 template <typename T>
03862 void
03863 Octagonal_Shape<T>::refine(const Variable var,
03864 const Relation_Symbol relsym,
03865 const Linear_Expression& expr,
03866 Coefficient_traits::const_reference denominator) {
03867 PPL_ASSERT(denominator != 0);
03868 const dimension_type expr_space_dim = expr.space_dimension();
03869 PPL_ASSERT(space_dim >= expr_space_dim);
03870 const dimension_type var_id = var.id();
03871 PPL_ASSERT(var_id <= space_dim);
03872 PPL_ASSERT(expr.coefficient(var) == 0);
03873 PPL_ASSERT(relsym != LESS_THAN && relsym != GREATER_THAN);
03874
03875 const Coefficient& b = expr.inhomogeneous_term();
03876
03877
03878 dimension_type t = 0;
03879
03880
03881 dimension_type w_id = 0;
03882
03883
03884 for (dimension_type i = expr_space_dim; i-- > 0; )
03885 if (expr.coefficient(Variable(i)) != 0) {
03886 if (t++ == 1)
03887 break;
03888 else
03889 w_id = i;
03890 }
03891
03892
03893
03894
03895
03896 typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
03897 typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
03898 typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
03899 typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
03900
03901 const Row_Iterator m_begin = matrix.row_begin();
03902 const dimension_type n_var = 2*var_id;
03903 PPL_DIRTY_TEMP_COEFFICIENT(minus_den);
03904 neg_assign(minus_den, denominator);
03905
03906
03907
03908
03909
03910
03911 if (t == 1 && expr.coefficient(Variable(w_id)) != denominator
03912 && expr.coefficient(Variable(w_id)) != minus_den)
03913 t = 2;
03914
03915 if (t == 0) {
03916
03917 PPL_DIRTY_TEMP_COEFFICIENT(two_b);
03918 two_b = 2*b;
03919 switch (relsym) {
03920 case EQUAL:
03921
03922 add_octagonal_constraint(n_var+1, n_var, two_b, denominator);
03923 add_octagonal_constraint(n_var, n_var+1, two_b, minus_den);
03924 break;
03925 case LESS_OR_EQUAL:
03926
03927 add_octagonal_constraint(n_var+1, n_var, two_b, denominator);
03928 break;
03929 case GREATER_OR_EQUAL:
03930
03931
03932 add_octagonal_constraint(n_var, n_var+1, two_b, minus_den);
03933 break;
03934 default:
03935
03936 throw std::runtime_error("PPL internal error");
03937 }
03938 }
03939 else if (t == 1) {
03940
03941 const Coefficient& w_coeff = expr.coefficient(Variable(w_id));
03942 const dimension_type n_w = 2*w_id;
03943 switch (relsym) {
03944 case EQUAL:
03945 if (w_coeff == denominator)
03946
03947 if (var_id < w_id) {
03948 add_octagonal_constraint(n_w, n_var, b, denominator);
03949 add_octagonal_constraint(n_w+1, n_var+1, b, minus_den);
03950 }
03951 else {
03952 add_octagonal_constraint(n_var+1, n_w+1, b, denominator);
03953 add_octagonal_constraint(n_var, n_w, b, minus_den);
03954 }
03955 else
03956
03957 if (var_id < w_id) {
03958 add_octagonal_constraint(n_w+1, n_var, b, denominator);
03959 add_octagonal_constraint(n_w, n_var+1, b, minus_den);
03960 }
03961 else {
03962 add_octagonal_constraint(n_var+1, n_w, b, denominator);
03963 add_octagonal_constraint(n_var, n_w+1, b, minus_den);
03964 }
03965 break;
03966 case LESS_OR_EQUAL:
03967 {
03968 PPL_DIRTY_TEMP(N, d);
03969 div_round_up(d, b, denominator);
03970
03971
03972 if (w_coeff == denominator) {
03973
03974 if (var_id < w_id)
03975 add_octagonal_constraint(n_w, n_var, d);
03976 else
03977 add_octagonal_constraint(n_var+1, n_w+1, d);
03978 }
03979 else if (w_coeff == minus_den) {
03980
03981 if (var_id < w_id)
03982 add_octagonal_constraint(n_w+1, n_var, d);
03983 else
03984 add_octagonal_constraint(n_var+1, n_w, d);
03985 }
03986 break;
03987 }
03988
03989 case GREATER_OR_EQUAL:
03990 {
03991 PPL_DIRTY_TEMP(N, d);
03992 div_round_up(d, b, minus_den);
03993
03994
03995 if (w_coeff == denominator) {
03996
03997
03998 if (var_id < w_id)
03999 add_octagonal_constraint(n_w+1, n_var+1, d);
04000 else
04001 add_octagonal_constraint(n_var, n_w, d);
04002 }
04003 else if (w_coeff == minus_den) {
04004
04005
04006 if (var_id < w_id)
04007 add_octagonal_constraint(n_w, n_var+1, d);
04008 else
04009 add_octagonal_constraint(n_var, n_w+1, d);
04010 }
04011 break;
04012 }
04013
04014 default:
04015
04016 throw std::runtime_error("PPL internal error");
04017 }
04018 }
04019 else {
04020
04021
04022 const bool is_sc = (denominator > 0);
04023 PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
04024 neg_assign(minus_b, b);
04025 const Coefficient& sc_b = is_sc ? b : minus_b;
04026 const Coefficient& minus_sc_b = is_sc ? minus_b : b;
04027 const Coefficient& sc_den = is_sc ? denominator : minus_den;
04028 const Coefficient& minus_sc_den = is_sc ? minus_den : denominator;
04029
04030
04031
04032 Linear_Expression minus_expr;
04033 if (!is_sc)
04034 minus_expr = -expr;
04035 const Linear_Expression& sc_expr = is_sc ? expr : minus_expr;
04036
04037 PPL_DIRTY_TEMP(N, sum);
04038
04039 PPL_UNINITIALIZED(dimension_type, pinf_index);
04040
04041 dimension_type pinf_count = 0;
04042
04043 switch (relsym) {
04044 case EQUAL:
04045 {
04046 PPL_DIRTY_TEMP(N, neg_sum);
04047
04048 PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
04049
04050 dimension_type neg_pinf_count = 0;
04051
04052
04053 assign_r(sum, sc_b, ROUND_UP);
04054 assign_r(neg_sum, minus_sc_b, ROUND_UP);
04055
04056
04057 PPL_DIRTY_TEMP(N, coeff_i);
04058 PPL_DIRTY_TEMP(N, half);
04059 PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
04060 PPL_DIRTY_TEMP(N, minus_coeff_i);
04061
04062
04063 for (Row_iterator m_iter = m_begin, m_iter_end = m_iter + (2*w_id) + 2;
04064 m_iter != m_iter_end; ) {
04065 const dimension_type n_i = m_iter.index();
04066 const dimension_type id = n_i/2;
04067 Row_reference m_i = *m_iter;
04068 ++m_iter;
04069 Row_reference m_ci = *m_iter;
04070 ++m_iter;
04071 const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
04072 const int sign_i = sgn(sc_i);
04073 if (sign_i > 0) {
04074 assign_r(coeff_i, sc_i, ROUND_UP);
04075
04076 if (pinf_count <= 1) {
04077 const N& double_approx_i = m_ci[n_i];
04078 if (!is_plus_infinity(double_approx_i)) {
04079
04080 div_2exp_assign_r(half, double_approx_i, 1, ROUND_UP);
04081 add_mul_assign_r(sum, coeff_i, half, ROUND_UP);
04082 }
04083 else {
04084 ++pinf_count;
04085 pinf_index = id;
04086 }
04087 }
04088
04089 if (neg_pinf_count <= 1) {
04090 const N& double_approx_minus_i = m_i[n_i+1];
04091 if (!is_plus_infinity(double_approx_minus_i)) {
04092
04093 div_2exp_assign_r(half, double_approx_minus_i, 1, ROUND_UP);
04094 add_mul_assign_r(neg_sum, coeff_i, half, ROUND_UP);
04095 }
04096 else {
04097 ++neg_pinf_count;
04098 neg_pinf_index = id;
04099 }
04100 }
04101 }
04102 else if (sign_i < 0) {
04103 neg_assign_r(minus_sc_i, sc_i, ROUND_NOT_NEEDED);
04104 assign_r(minus_coeff_i, minus_sc_i, ROUND_UP);
04105
04106 if (pinf_count <= 1) {
04107 const N& double_approx_minus_i = m_i[n_i+1];
04108 if (!is_plus_infinity(double_approx_minus_i)) {
04109
04110 div_2exp_assign_r(half, double_approx_minus_i, 1, ROUND_UP);
04111 add_mul_assign_r(sum, minus_coeff_i, half, ROUND_UP);
04112 }
04113 else {
04114 ++pinf_count;
04115 pinf_index = id;
04116 }
04117 }
04118
04119 if (neg_pinf_count <= 1) {
04120 const N& double_approx_i = m_ci[n_i];
04121 if (!is_plus_infinity(double_approx_i)) {
04122
04123 div_2exp_assign_r(half, double_approx_i, 1, ROUND_UP);
04124 add_mul_assign_r(neg_sum, minus_coeff_i, half, ROUND_UP);
04125 }
04126 else {
04127 ++neg_pinf_count;
04128 neg_pinf_index = id;
04129 }
04130 }
04131 }
04132 }
04133
04134 if (pinf_count > 1 && neg_pinf_count > 1) {
04135 PPL_ASSERT(OK());
04136 return;
04137 }
04138
04139
04140 reset_strongly_closed();
04141
04142
04143 if (pinf_count <= 1) {
04144
04145 if (sc_den != 1) {
04146
04147
04148
04149
04150
04151 PPL_DIRTY_TEMP(N, down_sc_den);
04152 assign_r(down_sc_den, minus_sc_den, ROUND_UP);
04153 neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
04154 div_assign_r(sum, sum, down_sc_den, ROUND_UP);
04155 }
04156
04157 if (pinf_count == 0) {
04158
04159 PPL_DIRTY_TEMP(N, double_sum);
04160 mul_2exp_assign_r(double_sum, sum, 1, ROUND_UP);
04161 matrix[n_var+1][n_var] = double_sum;
04162
04163 deduce_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, sum);
04164 }
04165 else
04166
04167 if (pinf_index != var_id) {
04168 const Coefficient& ppi =
04169 sc_expr.coefficient(Variable(pinf_index));
04170 if (ppi == sc_den)
04171
04172 if (var_id < pinf_index)
04173 matrix[2*pinf_index][n_var] = sum;
04174 else
04175 matrix[n_var+1][2*pinf_index+1] = sum;
04176 else
04177 if (ppi == minus_sc_den) {
04178
04179 if (var_id < pinf_index)
04180 matrix[2*pinf_index+1][n_var] = sum;
04181 else
04182 matrix[n_var+1][2*pinf_index] = sum;
04183 }
04184 }
04185 }
04186
04187
04188 if (neg_pinf_count <= 1) {
04189
04190 if (sc_den != 1) {
04191
04192
04193
04194
04195
04196 PPL_DIRTY_TEMP(N, down_sc_den);
04197 assign_r(down_sc_den, minus_sc_den, ROUND_UP);
04198 neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
04199 div_assign_r(neg_sum, neg_sum, down_sc_den, ROUND_UP);
04200 }
04201
04202 if (neg_pinf_count == 0) {
04203
04204 PPL_DIRTY_TEMP(N, double_neg_sum);
04205 mul_2exp_assign_r(double_neg_sum, neg_sum, 1, ROUND_UP);
04206 matrix[n_var][n_var+1] = double_neg_sum;
04207
04208 deduce_minus_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, neg_sum);
04209 }
04210 else
04211
04212 if (neg_pinf_index != var_id) {
04213 const Coefficient& npi =
04214 sc_expr.coefficient(Variable(neg_pinf_index));
04215 if (npi == sc_den)
04216
04217
04218 if (neg_pinf_index < var_id)
04219 matrix[n_var][2*neg_pinf_index] = neg_sum;
04220 else
04221 matrix[2*neg_pinf_index+1][n_var+1] = neg_sum;
04222 else
04223 if (npi == minus_sc_den) {
04224
04225
04226 if (neg_pinf_index < var_id)
04227 matrix[n_var][2*neg_pinf_index+1] = neg_sum;
04228 else
04229 matrix[2*neg_pinf_index][n_var+1] = neg_sum;
04230 }
04231 }
04232 }
04233 break;
04234 }
04235
04236 case LESS_OR_EQUAL:
04237 {
04238
04239
04240
04241
04242 assign_r(sum, sc_b, ROUND_UP);
04243
04244
04245 PPL_DIRTY_TEMP(N, coeff_i);
04246 PPL_DIRTY_TEMP(N, approx_i);
04247 PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
04248
04249
04250 for (Row_Iterator m_iter = m_begin, m_end = m_iter + (2*w_id) + 2;
04251 m_iter != m_end; ) {
04252 const dimension_type n_i = m_iter.index();
04253 const dimension_type id = n_i/2;
04254 Row_Reference m_i = *m_iter;
04255 ++m_iter;
04256 Row_Reference m_ci = *m_iter;
04257 ++m_iter;
04258 const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
04259 const int sign_i = sgn(sc_i);
04260 if (sign_i == 0)
04261 continue;
04262
04263 const N& double_approx_i = (sign_i > 0) ? m_ci[n_i] : m_i[n_i+1];
04264 if (is_plus_infinity(double_approx_i)) {
04265 if (++pinf_count > 1)
04266 break;
04267 pinf_index = id;
04268 continue;
04269 }
04270 if (sign_i > 0)
04271 assign_r(coeff_i, sc_i, ROUND_UP);
04272 else {
04273 neg_assign(minus_sc_i, sc_i);
04274 assign_r(coeff_i, minus_sc_i, ROUND_UP);
04275 }
04276 div_2exp_assign_r(approx_i, double_approx_i, 1, ROUND_UP);
04277 add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
04278 }
04279
04280 if (sc_den != 1) {
04281
04282
04283
04284
04285 PPL_DIRTY_TEMP(N, down_sc_den);
04286 assign_r(down_sc_den, minus_sc_den, ROUND_UP);
04287 neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
04288 div_assign_r(sum, sum, down_sc_den, ROUND_UP);
04289 }
04290
04291 if (pinf_count == 0) {
04292
04293 PPL_DIRTY_TEMP(N, double_sum);
04294 mul_2exp_assign_r(double_sum, sum, 1, ROUND_UP);
04295 add_octagonal_constraint(n_var+1, n_var, double_sum);
04296
04297 deduce_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, sum);
04298 }
04299 else if (pinf_count == 1) {
04300 dimension_type pinf_ind = 2*pinf_index;
04301 if (expr.coefficient(Variable(pinf_index)) == denominator ) {
04302
04303 if (var_id < pinf_index)
04304 add_octagonal_constraint(pinf_ind, n_var, sum);
04305 else
04306 add_octagonal_constraint(n_var+1, pinf_ind+1, sum);
04307 }
04308 else {
04309 if (expr.coefficient(Variable(pinf_index)) == minus_den) {
04310
04311 if (var_id < pinf_index)
04312 add_octagonal_constraint(pinf_ind+1, n_var, sum);
04313 else
04314 add_octagonal_constraint(n_var+1, pinf_ind, sum);
04315 }
04316 }
04317 }
04318 break;
04319 }
04320
04321 case GREATER_OR_EQUAL:
04322 {
04323
04324
04325
04326
04327
04328 assign_r(sum, minus_sc_b, ROUND_UP);
04329
04330
04331 PPL_DIRTY_TEMP(N, coeff_i);
04332 PPL_DIRTY_TEMP(N, approx_i);
04333 PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
04334 for (Row_Iterator m_iter = m_begin, m_end = m_iter + (2*w_id) + 2;
04335 m_iter != m_end; ) {
04336 const dimension_type n_i = m_iter.index();
04337 const dimension_type id = n_i/2;
04338 Row_Reference m_i = *m_iter;
04339 ++m_iter;
04340 Row_Reference m_ci = *m_iter;
04341 ++m_iter;
04342 const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
04343 const int sign_i = sgn(sc_i);
04344 if (sign_i == 0)
04345 continue;
04346
04347 const N& double_approx_i = (sign_i > 0) ? m_i[n_i+1] : m_ci[n_i];
04348 if (is_plus_infinity(double_approx_i)) {
04349 if (++pinf_count > 1)
04350 break;
04351 pinf_index = id;
04352 continue;
04353 }
04354 if (sign_i > 0)
04355 assign_r(coeff_i, sc_i, ROUND_UP);
04356 else {
04357 neg_assign(minus_sc_i, sc_i);
04358 assign_r(coeff_i, minus_sc_i, ROUND_UP);
04359 }
04360 div_2exp_assign_r(approx_i, double_approx_i, 1, ROUND_UP);
04361 add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
04362 }
04363
04364
04365 if (sc_den != 1) {
04366
04367
04368
04369
04370 PPL_DIRTY_TEMP(N, down_sc_den);
04371 assign_r(down_sc_den, minus_sc_den, ROUND_UP);
04372 neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
04373 div_assign_r(sum, sum, down_sc_den, ROUND_UP);
04374 }
04375
04376 if (pinf_count == 0) {
04377
04378 PPL_DIRTY_TEMP(N, double_sum);
04379 mul_2exp_assign_r(double_sum, sum, 1, ROUND_UP);
04380 add_octagonal_constraint(n_var, n_var+1, double_sum);
04381
04382 deduce_minus_v_pm_u_bounds(var_id, pinf_index, sc_expr, sc_den, sum);
04383 }
04384 else if (pinf_count == 1) {
04385 dimension_type pinf_ind = 2*pinf_index;
04386 if (expr.coefficient(Variable(pinf_index)) == denominator) {
04387
04388
04389 if (pinf_index < var_id)
04390 add_octagonal_constraint(n_var, pinf_ind, sum);
04391 else
04392 add_octagonal_constraint(pinf_ind+1, n_var, sum);
04393 }
04394 else {
04395 if (expr.coefficient(Variable(pinf_index)) == minus_den) {
04396
04397
04398 if (pinf_index < var_id)
04399 add_octagonal_constraint(n_var, pinf_ind+1, sum);
04400 else
04401 add_octagonal_constraint(pinf_ind, n_var+1, sum);
04402 }
04403 }
04404 }
04405 break;
04406 }
04407
04408 default:
04409
04410 throw std::runtime_error("PPL internal error");
04411 }
04412 }
04413 }
04414
04415 template <typename T>
04416 void
04417 Octagonal_Shape<T>::affine_image(const Variable var,
04418 const Linear_Expression& expr,
04419 Coefficient_traits::const_reference
04420 denominator) {
04421
04422 if (denominator == 0)
04423 throw_generic("affine_image(v, e, d)", "d == 0");
04424
04425
04426
04427
04428 const dimension_type expr_space_dim = expr.space_dimension();
04429 if (space_dim < expr_space_dim)
04430 throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
04431
04432
04433 const dimension_type var_id = var.id();
04434 if (space_dim < var_id + 1)
04435 throw_dimension_incompatible("affine_image(v, e, d)", var_id + 1);
04436
04437 strong_closure_assign();
04438
04439 if (marked_empty())
04440 return;
04441
04442
04443
04444 dimension_type t = 0;
04445
04446 dimension_type w_id = 0;
04447
04448
04449
04450 for (dimension_type i = expr_space_dim; i-- > 0; )
04451 if (expr.coefficient(Variable(i)) != 0) {
04452 if (t++ == 1)
04453 break;
04454 else
04455 w_id = i;
04456 }
04457
04458 typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
04459 typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
04460 typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
04461 typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
04462
04463 const dimension_type n_var = 2*var_id;
04464 const Coefficient& b = expr.inhomogeneous_term();
04465 PPL_DIRTY_TEMP_COEFFICIENT(minus_den);
04466 neg_assign_r(minus_den, denominator, ROUND_NOT_NEEDED);
04467
04468
04469
04470
04471
04472
04473
04474
04475
04476
04477 if (t == 0) {
04478
04479
04480 forget_all_octagonal_constraints(var_id);
04481 PPL_DIRTY_TEMP_COEFFICIENT(two_b);
04482 two_b = 2*b;
04483
04484 add_octagonal_constraint(n_var+1, n_var, two_b, denominator);
04485 add_octagonal_constraint(n_var, n_var+1, two_b, minus_den);
04486 PPL_ASSERT(OK());
04487 return;
04488 }
04489
04490 if (t == 1) {
04491
04492 const Coefficient& w_coeff = expr.coefficient(Variable(w_id));
04493 if (w_coeff == denominator || w_coeff == minus_den) {
04494
04495 if (w_id == var_id) {
04496
04497 const bool sign_symmetry = (w_coeff != denominator);
04498 if (!sign_symmetry && b == 0)
04499
04500 return;
04501
04502
04503 PPL_DIRTY_TEMP(N, d);
04504 div_round_up(d, b, denominator);
04505 PPL_DIRTY_TEMP(N, minus_d);
04506 div_round_up(minus_d, b, minus_den);
04507 if (sign_symmetry)
04508 std::swap(d, minus_d);
04509 const Row_Iterator m_begin = matrix.row_begin();
04510 const Row_Iterator m_end = matrix.row_end();
04511 Row_Iterator m_iter = m_begin + n_var;
04512 Row_Reference m_v = *m_iter;
04513 ++m_iter;
04514 Row_Reference m_cv = *m_iter;
04515 ++m_iter;
04516
04517 for (dimension_type j = n_var; j-- > 0; ) {
04518 N& m_v_j = m_v[j];
04519 add_assign_r(m_v_j, m_v_j, minus_d, ROUND_UP);
04520 N& m_cv_j = m_cv[j];
04521 add_assign_r(m_cv_j, m_cv_j, d, ROUND_UP);
04522 if (sign_symmetry)
04523 std::swap(m_v_j, m_cv_j);
04524 }
04525 for ( ; m_iter != m_end; ++m_iter) {
04526 Row_Reference m_i = *m_iter;
04527 N& m_i_v = m_i[n_var];
04528 add_assign_r(m_i_v, m_i_v, d, ROUND_UP);
04529 N& m_i_cv = m_i[n_var+1];
04530 add_assign_r(m_i_cv, m_i_cv, minus_d, ROUND_UP);
04531 if (sign_symmetry)
04532 std::swap(m_i_v, m_i_cv);
04533 }
04534
04535 mul_2exp_assign_r(d, d, 1, ROUND_UP);
04536 N& m_cv_v = m_cv[n_var];
04537 add_assign_r(m_cv_v, m_cv_v, d, ROUND_UP);
04538 mul_2exp_assign_r(minus_d, minus_d, 1, ROUND_UP);
04539 N& m_v_cv = m_v[n_var+1];
04540 add_assign_r(m_v_cv, m_v_cv, minus_d, ROUND_UP);
04541 if (sign_symmetry)
04542 std::swap(m_cv_v, m_v_cv);
04543
04544 }
04545 else {
04546
04547
04548
04549 forget_all_octagonal_constraints(var_id);
04550 const dimension_type n_w = 2*w_id;
04551
04552 if (w_coeff == denominator) {
04553 if (var_id < w_id) {
04554 add_octagonal_constraint(n_w, n_var, b, denominator);
04555 add_octagonal_constraint(n_w+1, n_var+1, b, minus_den);
04556 }
04557 else {
04558 add_octagonal_constraint(n_var+1, n_w+1, b, denominator);
04559 add_octagonal_constraint(n_var, n_w, b, minus_den);
04560 }
04561 }
04562 else {
04563
04564 if (var_id < w_id) {
04565 add_octagonal_constraint(n_w+1, n_var, b, denominator);
04566 add_octagonal_constraint(n_w, n_var+1, b, minus_den);
04567 }
04568 else {
04569 add_octagonal_constraint(n_var+1, n_w, b, denominator);
04570 add_octagonal_constraint(n_var, n_w+1, b, minus_den);
04571 }
04572 }
04573 incremental_strong_closure_assign(var);
04574 }
04575 PPL_ASSERT(OK());
04576 return;
04577 }
04578 }
04579
04580
04581
04582
04583
04584
04585
04586
04587
04588
04589
04590
04591
04592 const bool is_sc = (denominator > 0);
04593 PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
04594 neg_assign_r(minus_b, b, ROUND_NOT_NEEDED);
04595
04596 const Coefficient& sc_b = is_sc ? b : minus_b;
04597 const Coefficient& minus_sc_b = is_sc ? minus_b : b;
04598 const Coefficient& sc_den = is_sc ? denominator : minus_den;
04599 const Coefficient& minus_sc_den = is_sc ? minus_den : denominator;
04600
04601
04602
04603 Linear_Expression minus_expr;
04604 if (!is_sc)
04605 minus_expr = -expr;
04606 const Linear_Expression& sc_expr = is_sc ? expr : minus_expr;
04607
04608 PPL_DIRTY_TEMP(N, pos_sum);
04609 PPL_DIRTY_TEMP(N, neg_sum);
04610
04611 PPL_UNINITIALIZED(dimension_type, pos_pinf_index);
04612 PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
04613
04614 dimension_type pos_pinf_count = 0;
04615 dimension_type neg_pinf_count = 0;
04616
04617
04618 assign_r(pos_sum, sc_b, ROUND_UP);
04619 assign_r(neg_sum, minus_sc_b, ROUND_UP);
04620
04621
04622 PPL_DIRTY_TEMP(N, coeff_i);
04623 PPL_DIRTY_TEMP(N, minus_coeff_i);
04624 PPL_DIRTY_TEMP(N, half);
04625 PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
04626
04627
04628 const Row_Iterator m_begin = matrix.row_begin();
04629 for (Row_iterator m_iter = m_begin,
04630 m_iter_end = m_iter + (2*w_id) + 2; m_iter != m_iter_end; ) {
04631 const dimension_type n_i = m_iter.index();
04632 const dimension_type id = n_i/2;
04633 Row_reference m_i = *m_iter;
04634 ++m_iter;
04635 Row_reference m_ci = *m_iter;
04636 ++m_iter;
04637 const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
04638 const int sign_i = sgn(sc_i);
04639 if (sign_i > 0) {
04640 assign_r(coeff_i, sc_i, ROUND_UP);
04641
04642 if (pos_pinf_count <= 1) {
04643 const N& double_up_approx_i = m_ci[n_i];
04644 if (!is_plus_infinity(double_up_approx_i)) {
04645
04646 div_2exp_assign_r(half, double_up_approx_i, 1, ROUND_UP);
04647 add_mul_assign_r(pos_sum, coeff_i, half, ROUND_UP);
04648 }
04649 else {
04650 ++pos_pinf_count;
04651 pos_pinf_index = id;
04652 }
04653 }
04654
04655 if (neg_pinf_count <= 1) {
04656 const N& double_up_approx_minus_i = m_i[n_i+1];
04657 if (!is_plus_infinity(double_up_approx_minus_i)) {
04658
04659 div_2exp_assign_r(half, double_up_approx_minus_i, 1, ROUND_UP);
04660 add_mul_assign_r(neg_sum, coeff_i, half, ROUND_UP);
04661 }
04662 else {
04663 ++neg_pinf_count;
04664 neg_pinf_index = id;
04665 }
04666 }
04667 }
04668 else if (sign_i < 0) {
04669 neg_assign_r(minus_sc_i, sc_i, ROUND_NOT_NEEDED);
04670 assign_r(minus_coeff_i, minus_sc_i, ROUND_UP);
04671
04672 if (pos_pinf_count <= 1) {
04673 const N& double_up_approx_minus_i = m_i[n_i+1];
04674 if (!is_plus_infinity(double_up_approx_minus_i)) {
04675
04676 div_2exp_assign_r(half, double_up_approx_minus_i, 1, ROUND_UP);
04677 add_mul_assign_r(pos_sum, minus_coeff_i, half, ROUND_UP);
04678 }
04679 else {
04680 ++pos_pinf_count;
04681 pos_pinf_index = id;
04682 }
04683 }
04684
04685 if (neg_pinf_count <= 1) {
04686 const N& double_up_approx_i = m_ci[n_i];
04687 if (!is_plus_infinity(double_up_approx_i)) {
04688
04689 div_2exp_assign_r(half, double_up_approx_i, 1, ROUND_UP);
04690 add_mul_assign_r(neg_sum, minus_coeff_i, half, ROUND_UP);
04691 }
04692 else {
04693 ++neg_pinf_count;
04694 neg_pinf_index = id;
04695 }
04696 }
04697 }
04698 }
04699
04700
04701 forget_all_octagonal_constraints(var_id);
04702
04703 if (pos_pinf_count > 1 && neg_pinf_count > 1) {
04704 PPL_ASSERT(OK());
04705 return;
04706 }
04707
04708
04709 reset_strongly_closed();
04710
04711
04712 if (pos_pinf_count <= 1) {
04713
04714 if (sc_den != 1) {
04715
04716
04717
04718
04719 PPL_DIRTY_TEMP(N, down_sc_den);
04720 assign_r(down_sc_den, minus_sc_den, ROUND_UP);
04721 neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
04722 div_assign_r(pos_sum, pos_sum, down_sc_den, ROUND_UP);
04723 }
04724
04725 if (pos_pinf_count == 0) {
04726
04727 PPL_DIRTY_TEMP(N, double_pos_sum);
04728 mul_2exp_assign_r(double_pos_sum, pos_sum, 1, ROUND_UP);
04729 matrix[n_var+1][n_var] = double_pos_sum;
04730
04731 deduce_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, pos_sum);
04732 }
04733 else
04734
04735 if (pos_pinf_index != var_id) {
04736 const Coefficient& ppi = sc_expr.coefficient(Variable(pos_pinf_index));
04737 if (ppi == sc_den)
04738
04739 if (var_id < pos_pinf_index)
04740 matrix[2*pos_pinf_index][n_var] = pos_sum;
04741 else
04742 matrix[n_var+1][2*pos_pinf_index+1] = pos_sum;
04743 else
04744 if (ppi == minus_sc_den) {
04745
04746 if (var_id < pos_pinf_index)
04747 matrix[2*pos_pinf_index+1][n_var] = pos_sum;
04748 else
04749 matrix[n_var+1][2*pos_pinf_index] = pos_sum;
04750 }
04751 }
04752 }
04753
04754
04755 if (neg_pinf_count <= 1) {
04756
04757 if (sc_den != 1) {
04758
04759
04760
04761
04762 PPL_DIRTY_TEMP(N, down_sc_den);
04763 assign_r(down_sc_den, minus_sc_den, ROUND_UP);
04764 neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
04765 div_assign_r(neg_sum, neg_sum, down_sc_den, ROUND_UP);
04766 }
04767
04768 if (neg_pinf_count == 0) {
04769
04770 PPL_DIRTY_TEMP(N, double_neg_sum);
04771 mul_2exp_assign_r(double_neg_sum, neg_sum, 1, ROUND_UP);
04772 matrix[n_var][n_var+1] = double_neg_sum;
04773
04774 deduce_minus_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, neg_sum);
04775 }
04776 else
04777
04778 if (neg_pinf_index != var_id) {
04779 const Coefficient& npi = sc_expr.coefficient(Variable(neg_pinf_index));
04780 if (npi == sc_den)
04781
04782
04783 if (neg_pinf_index < var_id)
04784 matrix[n_var][2*neg_pinf_index] = neg_sum;
04785 else
04786 matrix[2*neg_pinf_index+1][n_var+1] = neg_sum;
04787 else
04788 if (npi == minus_sc_den) {
04789
04790
04791 if (neg_pinf_index < var_id)
04792 matrix[n_var][2*neg_pinf_index+1] = neg_sum;
04793 else
04794 matrix[2*neg_pinf_index][n_var+1] = neg_sum;
04795 }
04796 }
04797 }
04798
04799 incremental_strong_closure_assign(var);
04800 PPL_ASSERT(OK());
04801 }
04802
04803 template <typename T>
04804 void
04805 Octagonal_Shape<T>::affine_preimage(const Variable var,
04806 const Linear_Expression& expr,
04807 Coefficient_traits::const_reference
04808 denominator) {
04809
04810
04811 if (denominator == 0)
04812 throw_generic("affine_preimage(v, e, d)", "d == 0");
04813
04814
04815
04816
04817 const dimension_type expr_space_dim = expr.space_dimension();
04818 if (space_dim < expr_space_dim)
04819 throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
04820
04821
04822 dimension_type var_id = var.id();
04823 if (space_dim < var_id + 1)
04824 throw_dimension_incompatible("affine_preimage(v, e, d)", var_id + 1);
04825
04826 strong_closure_assign();
04827
04828 if (marked_empty())
04829 return;
04830
04831 const Coefficient& b = expr.inhomogeneous_term();
04832
04833
04834
04835 dimension_type t = 0;
04836
04837
04838 dimension_type w_id = 0;
04839
04840
04841 for (dimension_type i = expr_space_dim; i-- > 0; )
04842 if (expr.coefficient(Variable(i)) != 0) {
04843 if (t++ == 1)
04844 break;
04845 else
04846 w_id = i;
04847 }
04848
04849
04850
04851
04852
04853
04854
04855
04856
04857
04858 if (t == 0) {
04859
04860 forget_all_octagonal_constraints(var_id);
04861 PPL_ASSERT(OK());
04862 return;
04863 }
04864
04865 if (t == 1) {
04866
04867 const Coefficient& w_coeff = expr.coefficient(Variable(w_id));
04868 if (w_coeff == denominator || w_coeff == -denominator) {
04869
04870 if (w_id == var_id) {
04871
04872 affine_image(var, denominator*var - b, w_coeff);
04873 }
04874 else {
04875
04876
04877 forget_all_octagonal_constraints(var_id);
04878 PPL_ASSERT(OK());
04879 }
04880 return;
04881 }
04882 }
04883
04884
04885
04886
04887 const Coefficient& coeff_v = expr.coefficient(var);
04888 if (coeff_v != 0) {
04889 if (coeff_v > 0) {
04890
04891 Linear_Expression inverse = ((coeff_v + denominator)*var);
04892 inverse -= expr;
04893 affine_image(var, inverse, coeff_v);
04894 }
04895 else {
04896
04897 PPL_DIRTY_TEMP_COEFFICIENT(minus_coeff_v);
04898 neg_assign(minus_coeff_v, coeff_v);
04899 Linear_Expression inverse = ((minus_coeff_v - denominator)*var);
04900 inverse += expr;
04901 affine_image(var, inverse, minus_coeff_v);
04902 }
04903 }
04904 else {
04905
04906 forget_all_octagonal_constraints(var_id);
04907 PPL_ASSERT(OK());
04908 }
04909 }
04910
04911 template <typename T>
04912 void
04913 Octagonal_Shape<T>
04914 ::generalized_affine_image(const Variable var,
04915 const Relation_Symbol relsym,
04916 const Linear_Expression& expr ,
04917 Coefficient_traits::const_reference denominator) {
04918
04919 if (denominator == 0)
04920 throw_generic("generalized_affine_image(v, r, e, d)", "d == 0");
04921
04922
04923
04924
04925 const dimension_type expr_space_dim = expr.space_dimension();
04926 if (space_dim < expr_space_dim)
04927 throw_dimension_incompatible("generalized_affine_image(v, r, e, d)", "e",
04928 expr);
04929
04930
04931 dimension_type var_id = var.id();
04932 if (space_dim < var_id + 1)
04933 throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
04934 var_id + 1);
04935
04936
04937 if (relsym == LESS_THAN || relsym == GREATER_THAN)
04938 throw_generic("generalized_affine_image(v, r, e, d)",
04939 "r is a strict relation symbol and "
04940 "*this is an Octagonal_Shape");
04941
04942 if (relsym == EQUAL) {
04943
04944
04945 affine_image(var, expr, denominator);
04946 return;
04947 }
04948
04949 strong_closure_assign();
04950
04951 if (marked_empty())
04952 return;
04953
04954
04955
04956 dimension_type t = 0;
04957
04958 dimension_type w_id = 0;
04959
04960
04961
04962 for (dimension_type i = expr_space_dim; i-- > 0; )
04963 if (expr.coefficient(Variable(i)) != 0) {
04964 if (t++ == 1)
04965 break;
04966 else
04967 w_id = i;
04968 }
04969
04970 typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
04971 typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
04972 typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
04973 typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
04974
04975 const Row_Iterator m_begin = matrix.row_begin();
04976 const Row_Iterator m_end = matrix.row_end();
04977 const dimension_type n_var = 2*var_id;
04978 const Coefficient& b = expr.inhomogeneous_term();
04979 PPL_DIRTY_TEMP_COEFFICIENT(minus_den);
04980 neg_assign_r(minus_den, denominator, ROUND_NOT_NEEDED);
04981
04982
04983
04984
04985
04986
04987
04988
04989
04990
04991 if (t == 0) {
04992
04993 PPL_DIRTY_TEMP_COEFFICIENT(two_b);
04994 two_b = 2*b;
04995
04996 forget_all_octagonal_constraints(var_id);
04997
04998 reset_strongly_closed();
04999 switch (relsym) {
05000 case LESS_OR_EQUAL:
05001
05002 add_octagonal_constraint(n_var+1, n_var, two_b, denominator);
05003 break;
05004 case GREATER_OR_EQUAL:
05005
05006
05007 add_octagonal_constraint(n_var, n_var+1, two_b, minus_den);
05008 break;
05009 default:
05010
05011 throw std::runtime_error("PPL internal error");
05012 }
05013 PPL_ASSERT(OK());
05014 return;
05015 }
05016
05017 if (t == 1) {
05018
05019 const Coefficient& w_coeff = expr.coefficient(Variable(w_id));
05020 if (w_coeff == denominator || w_coeff == minus_den) {
05021
05022 switch (relsym) {
05023 case LESS_OR_EQUAL:
05024 {
05025 PPL_DIRTY_TEMP(N, d);
05026 div_round_up(d, b, denominator);
05027 if (w_id == var_id) {
05028
05029
05030 reset_strongly_closed();
05031 if (w_coeff == denominator) {
05032
05033
05034
05035 Row_Iterator m_iter = m_begin + n_var;
05036 Row_Reference m_v = *m_iter;
05037 N& m_v_cv = m_v[n_var+1];
05038 ++m_iter;
05039 Row_Reference m_cv = *m_iter;
05040 N& m_cv_v = m_cv[n_var];
05041 ++m_iter;
05042
05043 for ( ; m_iter != m_end; ++m_iter) {
05044 Row_Reference m_i = *m_iter;
05045 N& m_i_v = m_i[n_var];
05046 add_assign_r(m_i_v, m_i_v, d, ROUND_UP);
05047 assign_r(m_i[n_var+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
05048 }
05049 for (dimension_type k = n_var; k-- > 0; ) {
05050 assign_r(m_v[k], PLUS_INFINITY, ROUND_NOT_NEEDED);
05051 add_assign_r(m_cv[k], m_cv[k], d, ROUND_UP);
05052 }
05053 mul_2exp_assign_r(d, d, 1, ROUND_UP);
05054 add_assign_r(m_cv_v, m_cv_v, d, ROUND_UP);
05055 assign_r(m_v_cv, PLUS_INFINITY, ROUND_NOT_NEEDED);
05056 }
05057 else {
05058
05059
05060 N& m_v_cv = matrix[n_var][n_var+1];
05061 mul_2exp_assign_r(d, d, 1, ROUND_UP);
05062 add_assign_r(matrix[n_var+1][n_var], m_v_cv, d, ROUND_UP);
05063 assign_r(m_v_cv, PLUS_INFINITY, ROUND_NOT_NEEDED);
05064 forget_binary_octagonal_constraints(var_id);
05065 }
05066 }
05067 else {
05068
05069
05070
05071 forget_all_octagonal_constraints(var_id);
05072 const dimension_type n_w = 2*w_id;
05073 if (w_coeff == denominator) {
05074
05075 if (var_id < w_id)
05076 add_octagonal_constraint(n_w, n_var, b, denominator);
05077 else
05078 add_octagonal_constraint(n_var+1, n_w+1, b, denominator);
05079 }
05080 else {
05081
05082 if (var_id < w_id)
05083 add_octagonal_constraint(n_w+1, n_var, b, denominator);
05084 else
05085 add_octagonal_constraint(n_var+1, n_w, b, denominator);
05086 }
05087 }
05088 break;
05089 }
05090
05091 case GREATER_OR_EQUAL:
05092 {
05093 PPL_DIRTY_TEMP(N, d);
05094 div_round_up(d, b, minus_den);
05095 if (w_id == var_id) {
05096
05097
05098 reset_strongly_closed();
05099 if (w_coeff == denominator) {
05100
05101
05102
05103 Row_Iterator m_iter = m_begin + n_var;
05104 Row_Reference m_v = *m_iter;
05105 N& m_v_cv = m_v[n_var+1];
05106 ++m_iter;
05107 Row_Reference m_cv = *m_iter;
05108 N& m_cv_v = m_cv[n_var];
05109 ++m_iter;
05110
05111 for ( ; m_iter != m_end; ++m_iter) {
05112 Row_Reference m_i = *m_iter;
05113 assign_r(m_i[n_var], PLUS_INFINITY, ROUND_NOT_NEEDED);
05114 add_assign_r(m_i[n_var+1], m_i[n_var+1], d, ROUND_UP);
05115 }
05116 for (dimension_type k = n_var; k-- > 0; ) {
05117 add_assign_r(m_v[k], m_v[k], d, ROUND_UP);
05118 assign_r(m_cv[k], PLUS_INFINITY, ROUND_NOT_NEEDED);
05119 }
05120 mul_2exp_assign_r(d, d, 1, ROUND_UP);
05121 add_assign_r(m_v_cv, m_v_cv, d, ROUND_UP);
05122 assign_r(m_cv_v, PLUS_INFINITY, ROUND_NOT_NEEDED);
05123 }
05124 else {
05125
05126
05127 N& m_cv_v = matrix[n_var+1][n_var];
05128 mul_2exp_assign_r(d, d, 1, ROUND_UP);
05129 add_assign_r(matrix[n_var][n_var+1], m_cv_v, d, ROUND_UP);
05130 assign_r(m_cv_v, PLUS_INFINITY, ROUND_NOT_NEEDED);
05131 forget_binary_octagonal_constraints(var_id);
05132 }
05133 }
05134 else {
05135
05136
05137
05138 forget_all_octagonal_constraints(var_id);
05139 const dimension_type n_w = 2*w_id;
05140
05141
05142
05143
05144 if (w_coeff == denominator) {
05145
05146
05147 if (var_id < w_id)
05148 add_octagonal_constraint(n_w+1, n_var+1, b, minus_den);
05149 else
05150 add_octagonal_constraint(n_var, n_w, b, minus_den);
05151 }
05152 else {
05153
05154
05155 if (var_id < w_id)
05156 add_octagonal_constraint(n_w, n_var+1, b, minus_den);
05157 else
05158 add_octagonal_constraint(n_var, n_w+1, b, minus_den);
05159 }
05160 }
05161 break;
05162 }
05163
05164 default:
05165
05166 throw std::runtime_error("PPL internal error");
05167 }
05168 PPL_ASSERT(OK());
05169 return;
05170 }
05171 }
05172
05173
05174
05175
05176
05177
05178
05179
05180 const bool is_sc = (denominator > 0);
05181 PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
05182 neg_assign(minus_b, b);
05183 const Coefficient& sc_b = is_sc ? b : minus_b;
05184 const Coefficient& minus_sc_b = is_sc ? minus_b : b;
05185 const Coefficient& sc_den = is_sc ? denominator : minus_den;
05186 const Coefficient& minus_sc_den = is_sc ? minus_den : denominator;
05187
05188
05189
05190 Linear_Expression minus_expr;
05191 if (!is_sc)
05192 minus_expr = -expr;
05193 const Linear_Expression& sc_expr = is_sc ? expr : minus_expr;
05194
05195 PPL_DIRTY_TEMP(N, sum);
05196
05197 PPL_UNINITIALIZED(dimension_type, pinf_index);
05198
05199 dimension_type pinf_count = 0;
05200
05201 switch (relsym) {
05202 case LESS_OR_EQUAL:
05203 {
05204
05205
05206
05207 assign_r(sum, sc_b, ROUND_UP);
05208
05209 PPL_DIRTY_TEMP(N, coeff_i);
05210 PPL_DIRTY_TEMP(N, approx_i);
05211 PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
05212
05213
05214 for (Row_iterator m_iter = m_begin, m_iter_end = m_iter + (2*w_id) + 2;
05215 m_iter != m_iter_end; ) {
05216 const dimension_type n_i = m_iter.index();
05217 const dimension_type id = n_i/2;
05218 Row_reference m_i = *m_iter;
05219 ++m_iter;
05220 Row_reference m_ci = *m_iter;
05221 ++m_iter;
05222 const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
05223 const int sign_i = sgn(sc_i);
05224 if (sign_i == 0)
05225 continue;
05226
05227 const N& double_approx_i = (sign_i > 0) ? m_ci[n_i] : m_i[n_i+1];
05228 if (is_plus_infinity(double_approx_i)) {
05229 if (++pinf_count > 1)
05230 break;
05231 pinf_index = id;
05232 continue;
05233 }
05234 if (sign_i > 0)
05235 assign_r(coeff_i, sc_i, ROUND_UP);
05236 else {
05237 neg_assign(minus_sc_i, sc_i);
05238 assign_r(coeff_i, minus_sc_i, ROUND_UP);
05239 }
05240 div_2exp_assign_r(approx_i, double_approx_i, 1, ROUND_UP);
05241 add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
05242 }
05243
05244 forget_all_octagonal_constraints(var_id);
05245 reset_strongly_closed();
05246
05247 if (pinf_count > 1) {
05248 PPL_ASSERT(OK());
05249 return;
05250 }
05251
05252
05253 if (sc_den != 1) {
05254
05255
05256
05257
05258
05259 PPL_DIRTY_TEMP(N, down_sc_den);
05260 assign_r(down_sc_den, minus_sc_den, ROUND_UP);
05261 neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
05262 div_assign_r(sum, sum, down_sc_den, ROUND_UP);
05263 }
05264
05265 if (pinf_count == 0) {
05266
05267 PPL_DIRTY_TEMP(N, double_sum);
05268 mul_2exp_assign_r(double_sum, sum, 1, ROUND_UP);
05269 matrix[n_var+1][n_var] = double_sum;
05270
05271 deduce_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, sum);
05272 }
05273 else if (pinf_count == 1)
05274 if (pinf_index != var_id) {
05275 const Coefficient& pi = expr.coefficient(Variable(pinf_index));
05276 if (pi == denominator ) {
05277
05278 if (var_id < pinf_index)
05279 matrix[2*pinf_index][n_var] = sum;
05280 else
05281 matrix[n_var+1][2*pinf_index+1] = sum;
05282 }
05283 else {
05284 if (pi == minus_den) {
05285
05286 if (var_id < pinf_index)
05287 matrix[2*pinf_index+1][n_var] = sum;
05288 else
05289 matrix[n_var+1][2*pinf_index] = sum;
05290 }
05291 }
05292 }
05293 break;
05294 }
05295
05296 case GREATER_OR_EQUAL:
05297 {
05298
05299
05300
05301
05302
05303 assign_r(sum, minus_sc_b, ROUND_UP);
05304 PPL_DIRTY_TEMP(N, coeff_i);
05305 PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
05306 PPL_DIRTY_TEMP(N, approx_i);
05307
05308 for (Row_iterator m_iter = m_begin, m_iter_end = m_iter + (2*w_id) + 2;
05309 m_iter != m_iter_end; ) {
05310 const dimension_type n_i = m_iter.index();
05311 const dimension_type id = n_i/2;
05312 Row_reference m_i = *m_iter;
05313 ++m_iter;
05314 Row_reference m_ci = *m_iter;
05315 ++m_iter;
05316 const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
05317 const int sign_i = sgn(sc_i);
05318 if (sign_i == 0)
05319 continue;
05320
05321 const N& double_approx_i = (sign_i > 0) ? m_i[n_i+1] : m_ci[n_i];
05322 if (is_plus_infinity(double_approx_i)) {
05323 if (++pinf_count > 1)
05324 break;
05325 pinf_index = id;
05326 continue;
05327 }
05328 if (sign_i > 0)
05329 assign_r(coeff_i, sc_i, ROUND_UP);
05330 else {
05331 neg_assign(minus_sc_i, sc_i);
05332 assign_r(coeff_i, minus_sc_i, ROUND_UP);
05333 }
05334 div_2exp_assign_r(approx_i, double_approx_i, 1, ROUND_UP);
05335 add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
05336 }
05337
05338
05339 forget_all_octagonal_constraints(var_id);
05340 reset_strongly_closed();
05341
05342 if (pinf_count > 1) {
05343 PPL_ASSERT(OK());
05344 return;
05345 }
05346
05347
05348 if (sc_den != 1) {
05349
05350
05351
05352
05353
05354 PPL_DIRTY_TEMP(N, down_sc_den);
05355 assign_r(down_sc_den, minus_sc_den, ROUND_UP);
05356 neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
05357 div_assign_r(sum, sum, down_sc_den, ROUND_UP);
05358 }
05359
05360 if (pinf_count == 0) {
05361
05362 PPL_DIRTY_TEMP(N, double_sum);
05363 mul_2exp_assign_r(double_sum, sum, 1, ROUND_UP);
05364 matrix[n_var][n_var+1] = double_sum;
05365
05366 deduce_minus_v_pm_u_bounds(var_id, pinf_index, sc_expr, sc_den, sum);
05367 }
05368 else if (pinf_count == 1)
05369 if (pinf_index != var_id) {
05370 const Coefficient& pi = expr.coefficient(Variable(pinf_index));
05371 if (pi == denominator) {
05372
05373
05374 if (pinf_index < var_id)
05375 matrix[n_var][2*pinf_index] = sum;
05376 else
05377 matrix[2*pinf_index+1][n_var+1] = sum;
05378 }
05379 else {
05380 if (pi == minus_den) {
05381
05382
05383 if (pinf_index < var_id)
05384 matrix[n_var][2*pinf_index+1] = sum;
05385 else
05386 matrix[2*pinf_index][n_var+1] = sum;
05387 }
05388 }
05389 }
05390 break;
05391 }
05392
05393 default:
05394
05395 throw std::runtime_error("PPL internal error");
05396 }
05397 incremental_strong_closure_assign(var);
05398 PPL_ASSERT(OK());
05399 }
05400
05401 template <typename T>
05402 void
05403 Octagonal_Shape<T>::generalized_affine_image(const Linear_Expression& lhs,
05404 const Relation_Symbol relsym,
05405 const Linear_Expression& rhs) {
05406
05407
05408
05409 dimension_type lhs_space_dim = lhs.space_dimension();
05410 if (space_dim < lhs_space_dim)
05411 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
05412 "e1", lhs);
05413
05414
05415
05416 const dimension_type rhs_space_dim = rhs.space_dimension();
05417 if (space_dim < rhs_space_dim)
05418 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
05419 "e2", rhs);
05420
05421
05422 if (relsym == LESS_THAN || relsym == GREATER_THAN)
05423 throw_generic("generalized_affine_image(e1, r, e2)",
05424 "r is a strict relation symbol and "
05425 "*this is an Octagonal_Shape");
05426
05427 strong_closure_assign();
05428
05429 if (marked_empty())
05430 return;
05431
05432
05433
05434 dimension_type t_lhs = 0;
05435
05436 dimension_type j_lhs = 0;
05437
05438
05439 for (dimension_type i = lhs_space_dim; i-- > 0; )
05440 if (lhs.coefficient(Variable(i)) != 0) {
05441 if (t_lhs++ == 1)
05442 break;
05443 else
05444 j_lhs = i;
05445 }
05446
05447 const Coefficient& b_lhs = lhs.inhomogeneous_term();
05448
05449 if (t_lhs == 0) {
05450
05451
05452
05453
05454
05455
05456
05457
05458 switch (relsym) {
05459 case LESS_OR_EQUAL:
05460 refine_no_check(lhs <= rhs);
05461 break;
05462 case EQUAL:
05463 refine_no_check(lhs == rhs);
05464 break;
05465 case GREATER_OR_EQUAL:
05466 refine_no_check(lhs >= rhs);
05467 break;
05468 default:
05469
05470 throw std::runtime_error("PPL internal error");
05471 }
05472 }
05473
05474 else if (t_lhs == 1) {
05475
05476
05477
05478 Variable v(j_lhs);
05479
05480 const Coefficient& den = lhs.coefficient(v);
05481 Relation_Symbol new_relsym = relsym;
05482 if (den < 0) {
05483 if (relsym == LESS_OR_EQUAL)
05484 new_relsym = GREATER_OR_EQUAL;
05485 else if (relsym == GREATER_OR_EQUAL)
05486 new_relsym = LESS_OR_EQUAL;
05487 }
05488 Linear_Expression expr = rhs - b_lhs;
05489 generalized_affine_image(v, new_relsym, expr, den);
05490 }
05491 else {
05492
05493
05494 bool lhs_vars_intersects_rhs_vars = false;
05495 std::vector<Variable> lhs_vars;
05496 for (dimension_type i = lhs_space_dim; i-- > 0; )
05497 if (lhs.coefficient(Variable(i)) != 0) {
05498 lhs_vars.push_back(Variable(i));
05499 if (rhs.coefficient(Variable(i)) != 0)
05500 lhs_vars_intersects_rhs_vars = true;
05501 }
05502
05503 if (!lhs_vars_intersects_rhs_vars) {
05504
05505
05506 for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
05507 dimension_type lhs_vars_i = lhs_vars[i].id();
05508 forget_all_octagonal_constraints(lhs_vars_i);
05509 }
05510
05511
05512
05513
05514 switch (relsym) {
05515 case LESS_OR_EQUAL:
05516 refine_no_check(lhs <= rhs);
05517 break;
05518 case EQUAL:
05519 refine_no_check(lhs == rhs);
05520 break;
05521 case GREATER_OR_EQUAL:
05522 refine_no_check(lhs >= rhs);
05523 break;
05524 default:
05525
05526 throw std::runtime_error("PPL internal error");
05527 }
05528 }
05529 else {
05530
05531
05532 #if 1 // Simplified computation (see the TODO note below).
05533
05534 for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
05535 dimension_type lhs_vars_i = lhs_vars[i].id();
05536 forget_all_octagonal_constraints(lhs_vars_i);
05537 }
05538
05539 #else // Currently unnecessarily complex computation.
05540
05541
05542
05543
05544
05545 const Variable new_var = Variable(space_dim);
05546 add_space_dimensions_and_embed(1);
05547
05548
05549
05550
05551 affine_image(new_var, rhs);
05552
05553
05554 strong_closure_assign();
05555 PPL_ASSERT(!marked_empty());
05556 for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
05557 dimension_type lhs_vars_i = lhs_vars[i].id();
05558 forget_all_octagonal_constraints(lhs_vars_i);
05559 }
05560
05561
05562
05563
05564
05565
05566 switch (relsym) {
05567 case LESS_OR_EQUAL:
05568 refine_no_check(lhs <= new_var);
05569 break;
05570 case EQUAL:
05571 refine_no_check(lhs == new_var);
05572 break;
05573 case GREATER_OR_EQUAL:
05574 refine_no_check(lhs >= new_var);
05575 break;
05576 default:
05577
05578 throw std::runtime_error("PPL internal error");
05579 }
05580
05581 remove_higher_space_dimensions(space_dim-1);
05582 #endif // Currently unnecessarily complex computation.
05583 }
05584 }
05585
05586 PPL_ASSERT(OK());
05587 }
05588
05589 template <typename T>
05590 void
05591 Octagonal_Shape<T>::bounded_affine_image(const Variable var,
05592 const Linear_Expression& lb_expr,
05593 const Linear_Expression& ub_expr,
05594 Coefficient_traits::const_reference
05595 denominator) {
05596
05597 if (denominator == 0)
05598 throw_generic("bounded_affine_image(v, lb, ub, d)", "d == 0");
05599
05600
05601 const dimension_type var_id = var.id();
05602 if (space_dim < var_id + 1)
05603 throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
05604 var_id + 1);
05605
05606
05607
05608 const dimension_type lb_space_dim = lb_expr.space_dimension();
05609 if (space_dim < lb_space_dim)
05610 throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
05611 "lb", lb_expr);
05612 const dimension_type ub_space_dim = ub_expr.space_dimension();
05613 if (space_dim < ub_space_dim)
05614 throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
05615 "ub", ub_expr);
05616
05617 strong_closure_assign();
05618
05619 if (marked_empty())
05620 return;
05621
05622
05623
05624 dimension_type t = 0;
05625
05626 dimension_type w_id = 0;
05627
05628
05629
05630 for (dimension_type i = lb_space_dim; i-- > 0; )
05631 if (lb_expr.coefficient(Variable(i)) != 0) {
05632 if (t++ == 1)
05633 break;
05634 else
05635 w_id = i;
05636 }
05637
05638 typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
05639 typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
05640 typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
05641 typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
05642
05643 const Row_Iterator m_begin = matrix.row_begin();
05644 const dimension_type n_var = 2*var_id;
05645 const Coefficient& b = lb_expr.inhomogeneous_term();
05646 PPL_DIRTY_TEMP_COEFFICIENT(minus_den);
05647 neg_assign_r(minus_den, denominator, ROUND_NOT_NEEDED);
05648
05649
05650
05651
05652
05653
05654
05655
05656
05657
05658 if (t == 0) {
05659
05660 generalized_affine_image(var,
05661 LESS_OR_EQUAL,
05662 ub_expr,
05663 denominator);
05664 PPL_DIRTY_TEMP_COEFFICIENT(two_b);
05665 two_b = 2*b;
05666
05667 add_octagonal_constraint(n_var, n_var+1, two_b, minus_den);
05668 PPL_ASSERT(OK());
05669 return;
05670 }
05671
05672 if (t == 1) {
05673
05674 const Coefficient& w_coeff = lb_expr.coefficient(Variable(w_id));
05675 if (w_coeff == denominator || w_coeff == minus_den) {
05676
05677 if (w_id == var_id) {
05678
05679
05680 const Variable new_var = Variable(space_dim);
05681 add_space_dimensions_and_embed(1);
05682
05683
05684 affine_image(new_var, lb_expr, denominator);
05685
05686 strong_closure_assign();
05687 PPL_ASSERT(!marked_empty());
05688
05689 generalized_affine_image(var,
05690 LESS_OR_EQUAL,
05691 ub_expr,
05692 denominator);
05693
05694 refine_no_check(var >= new_var);
05695
05696 remove_higher_space_dimensions(space_dim-1);
05697 return;
05698 }
05699 else {
05700
05701 generalized_affine_image(var,
05702 LESS_OR_EQUAL,
05703 ub_expr,
05704 denominator);
05705
05706
05707 const dimension_type n_w = 2*w_id;
05708
05709 if (w_coeff == denominator)
05710 if (var_id < w_id)
05711 add_octagonal_constraint(n_w+1, n_var+1, b, minus_den);
05712 else
05713 add_octagonal_constraint(n_var, n_w, b, minus_den);
05714 else {
05715
05716 if (var_id < w_id)
05717 add_octagonal_constraint(n_w, n_var+1, b, minus_den);
05718 else
05719 add_octagonal_constraint(n_var, n_w+1, b, minus_den);
05720 }
05721 PPL_ASSERT(OK());
05722 return;
05723 }
05724 }
05725 }
05726
05727
05728
05729
05730
05731
05732
05733
05734
05735
05736
05737
05738
05739 const bool is_sc = (denominator > 0);
05740 PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
05741 neg_assign_r(minus_b, b, ROUND_NOT_NEEDED);
05742
05743 const Coefficient& minus_sc_b = is_sc ? minus_b : b;
05744 const Coefficient& sc_den = is_sc ? denominator : minus_den;
05745 const Coefficient& minus_sc_den = is_sc ? minus_den : denominator;
05746
05747
05748
05749 Linear_Expression minus_expr;
05750 if (!is_sc)
05751 minus_expr = -lb_expr;
05752 const Linear_Expression& sc_expr = is_sc ? lb_expr : minus_expr;
05753
05754 PPL_DIRTY_TEMP(N, neg_sum);
05755
05756 PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
05757
05758 dimension_type neg_pinf_count = 0;
05759
05760
05761 assign_r(neg_sum, minus_sc_b, ROUND_UP);
05762
05763
05764 PPL_DIRTY_TEMP(N, coeff_i);
05765 PPL_DIRTY_TEMP(N, minus_coeff_i);
05766 PPL_DIRTY_TEMP(N, half);
05767 PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
05768
05769
05770 for (Row_iterator m_iter = m_begin, m_iter_end = m_iter + (2*w_id) + 2;
05771 m_iter != m_iter_end; ) {
05772 const dimension_type n_i = m_iter.index();
05773 const dimension_type id = n_i/2;
05774 Row_reference m_i = *m_iter;
05775 ++m_iter;
05776 Row_reference m_ci = *m_iter;
05777 ++m_iter;
05778 const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
05779 const int sign_i = sgn(sc_i);
05780 if (sign_i > 0) {
05781 assign_r(coeff_i, sc_i, ROUND_UP);
05782
05783 if (neg_pinf_count <= 1) {
05784 const N& double_up_approx_minus_i = m_i[n_i+1];
05785 if (!is_plus_infinity(double_up_approx_minus_i)) {
05786
05787 div_2exp_assign_r(half, double_up_approx_minus_i, 1, ROUND_UP);
05788 add_mul_assign_r(neg_sum, coeff_i, half, ROUND_UP);
05789 }
05790 else {
05791 ++neg_pinf_count;
05792 neg_pinf_index = id;
05793 }
05794 }
05795 }
05796 else if (sign_i < 0) {
05797 neg_assign_r(minus_sc_i, sc_i, ROUND_NOT_NEEDED);
05798 assign_r(minus_coeff_i, minus_sc_i, ROUND_UP);
05799
05800 if (neg_pinf_count <= 1) {
05801 const N& double_up_approx_i = m_ci[n_i];
05802 if (!is_plus_infinity(double_up_approx_i)) {
05803
05804 div_2exp_assign_r(half, double_up_approx_i, 1, ROUND_UP);
05805 add_mul_assign_r(neg_sum, minus_coeff_i, half, ROUND_UP);
05806 }
05807 else {
05808 ++neg_pinf_count;
05809 neg_pinf_index = id;
05810 }
05811 }
05812 }
05813 }
05814
05815
05816 generalized_affine_image(var,
05817 LESS_OR_EQUAL,
05818 ub_expr,
05819 denominator);
05820
05821
05822 if (neg_pinf_count > 1) {
05823 return;
05824 }
05825
05826
05827 reset_strongly_closed();
05828
05829
05830 if (neg_pinf_count <= 1) {
05831
05832 if (sc_den != 1) {
05833
05834
05835
05836
05837 PPL_DIRTY_TEMP(N, down_sc_den);
05838 assign_r(down_sc_den, minus_sc_den, ROUND_UP);
05839 neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
05840 div_assign_r(neg_sum, neg_sum, down_sc_den, ROUND_UP);
05841 }
05842
05843 if (neg_pinf_count == 0) {
05844
05845 PPL_DIRTY_TEMP(N, double_neg_sum);
05846 mul_2exp_assign_r(double_neg_sum, neg_sum, 1, ROUND_UP);
05847 matrix[n_var][n_var+1] = double_neg_sum;
05848
05849 deduce_minus_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, neg_sum);
05850 }
05851 else
05852
05853 if (neg_pinf_index != var_id) {
05854 const Coefficient& npi = sc_expr.coefficient(Variable(neg_pinf_index));
05855 if (npi == sc_den)
05856
05857
05858 if (neg_pinf_index < var_id)
05859 matrix[n_var][2*neg_pinf_index] = neg_sum;
05860 else
05861 matrix[2*neg_pinf_index+1][n_var+1] = neg_sum;
05862 else
05863 if (npi == minus_sc_den) {
05864
05865
05866 if (neg_pinf_index < var_id)
05867 matrix[n_var][2*neg_pinf_index+1] = neg_sum;
05868 else
05869 matrix[2*neg_pinf_index][n_var+1] = neg_sum;
05870 }
05871 }
05872 }
05873
05874 PPL_ASSERT(OK());
05875 }
05876
05877
05878 template <typename T>
05879 void
05880 Octagonal_Shape<T>
05881 ::generalized_affine_preimage(const Variable var,
05882 const Relation_Symbol relsym,
05883 const Linear_Expression& expr,
05884 Coefficient_traits::const_reference
05885 denominator) {
05886
05887 if (denominator == 0)
05888 throw_generic("generalized_affine_preimage(v, r, e, d)", "d == 0");
05889
05890
05891
05892
05893 const dimension_type expr_space_dim = expr.space_dimension();
05894 if (space_dim < expr_space_dim)
05895 throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
05896 "e", expr);
05897
05898
05899 const dimension_type var_id = var.id();
05900 if (space_dim < var_id + 1)
05901 throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
05902 var_id + 1);
05903
05904
05905 if (relsym == LESS_THAN || relsym == GREATER_THAN)
05906 throw_generic("generalized_affine_preimage(v, r, e, d)",
05907 "r is a strict relation symbol and "
05908 "*this is an Octagonal_Shape");
05909
05910 if (relsym == EQUAL) {
05911
05912
05913 affine_preimage(var, expr, denominator);
05914 return;
05915 }
05916
05917
05918 strong_closure_assign();
05919 if (marked_empty())
05920 return;
05921
05922
05923
05924 const Coefficient& expr_v = expr.coefficient(var);
05925 if (expr_v != 0) {
05926 const Relation_Symbol reversed_relsym = (relsym == LESS_OR_EQUAL)
05927 ? GREATER_OR_EQUAL : LESS_OR_EQUAL;
05928 const Linear_Expression inverse
05929 = expr - (expr_v + denominator)*var;
05930 PPL_DIRTY_TEMP_COEFFICIENT(inverse_den);
05931 neg_assign(inverse_den, expr_v);
05932 const Relation_Symbol inverse_relsym
05933 = (sgn(denominator) == sgn(inverse_den)) ? relsym : reversed_relsym;
05934 generalized_affine_image(var, inverse_relsym, inverse, inverse_den);
05935 return;
05936 }
05937
05938
05939
05940
05941
05942 refine(var, relsym, expr, denominator);
05943
05944
05945 if (is_empty())
05946 return;
05947
05948
05949 forget_all_octagonal_constraints(var_id);
05950 PPL_ASSERT(OK());
05951 }
05952
05953 template <typename T>
05954 void
05955 Octagonal_Shape<T>
05956 ::generalized_affine_preimage(const Linear_Expression& lhs,
05957 const Relation_Symbol relsym,
05958 const Linear_Expression& rhs) {
05959
05960
05961
05962 dimension_type lhs_space_dim = lhs.space_dimension();
05963 if (space_dim < lhs_space_dim)
05964 throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
05965 "e1", lhs);
05966
05967
05968
05969 const dimension_type rhs_space_dim = rhs.space_dimension();
05970 if (space_dim < rhs_space_dim)
05971 throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
05972 "e2", rhs);
05973
05974
05975 if (relsym == LESS_THAN || relsym == GREATER_THAN)
05976 throw_generic("generalized_affine_preimage(e1, r, e2)",
05977 "r is a strict relation symbol and "
05978 "*this is an Octagonal_Shape");
05979
05980 strong_closure_assign();
05981
05982 if (marked_empty())
05983 return;
05984
05985
05986
05987 dimension_type t_lhs = 0;
05988
05989 dimension_type j_lhs = 0;
05990
05991
05992 for (dimension_type i = lhs_space_dim; i-- > 0; )
05993 if (lhs.coefficient(Variable(i)) != 0) {
05994 if (t_lhs++ == 1)
05995 break;
05996 else
05997 j_lhs = i;
05998 }
05999
06000 const Coefficient& b_lhs = lhs.inhomogeneous_term();
06001
06002
06003
06004 if (t_lhs == 0) {
06005 generalized_affine_image(lhs, relsym, rhs);
06006 return;
06007 }
06008
06009 else if (t_lhs == 1) {
06010
06011
06012
06013 Variable v(j_lhs);
06014
06015 const Coefficient& den = lhs.coefficient(v);
06016 Relation_Symbol new_relsym = relsym;
06017 if (den < 0) {
06018 if (relsym == LESS_OR_EQUAL)
06019 new_relsym = GREATER_OR_EQUAL;
06020 else if (relsym == GREATER_OR_EQUAL)
06021 new_relsym = LESS_OR_EQUAL;
06022 }
06023 Linear_Expression expr = rhs - b_lhs;
06024 generalized_affine_preimage(v, new_relsym, expr, den);
06025 }
06026
06027 else {
06028
06029
06030 bool lhs_vars_intersects_rhs_vars = false;
06031 std::vector<Variable> lhs_vars;
06032 for (dimension_type i = lhs_space_dim; i-- > 0; )
06033 if (lhs.coefficient(Variable(i)) != 0) {
06034 lhs_vars.push_back(Variable(i));
06035 if (rhs.coefficient(Variable(i)) != 0)
06036 lhs_vars_intersects_rhs_vars = true;
06037 }
06038
06039 if (!lhs_vars_intersects_rhs_vars) {
06040
06041
06042
06043
06044
06045 switch (relsym) {
06046 case LESS_OR_EQUAL:
06047 refine_no_check(lhs <= rhs);
06048 break;
06049 case EQUAL:
06050 refine_no_check(lhs == rhs);
06051 break;
06052 case GREATER_OR_EQUAL:
06053 refine_no_check(lhs >= rhs);
06054 break;
06055 default:
06056
06057 throw std::runtime_error("PPL internal error");
06058 }
06059
06060
06061 if (is_empty())
06062 return;
06063
06064 for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
06065 dimension_type lhs_vars_i = lhs_vars[i].id();
06066 forget_all_octagonal_constraints(lhs_vars_i);
06067 }
06068 }
06069 else {
06070
06071
06072
06073
06074
06075
06076 const Variable new_var = Variable(space_dim);
06077 add_space_dimensions_and_embed(1);
06078
06079
06080
06081
06082 affine_image(new_var, lhs);
06083
06084
06085 strong_closure_assign();
06086 PPL_ASSERT(!marked_empty());
06087 for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
06088 dimension_type lhs_vars_i = lhs_vars[i].id();
06089 forget_all_octagonal_constraints(lhs_vars_i);
06090 }
06091
06092
06093
06094
06095
06096
06097
06098 switch (relsym) {
06099 case LESS_OR_EQUAL:
06100 refine_no_check(new_var <= rhs);
06101 break;
06102 case EQUAL:
06103 refine_no_check(new_var == rhs);
06104 break;
06105 case GREATER_OR_EQUAL:
06106 refine_no_check(new_var >= rhs);
06107 break;
06108 default:
06109
06110 throw std::runtime_error("PPL internal error");
06111 }
06112
06113 remove_higher_space_dimensions(space_dim-1);
06114 }
06115 }
06116 PPL_ASSERT(OK());
06117 }
06118
06119 template <typename T>
06120 void
06121 Octagonal_Shape<T>::bounded_affine_preimage(const Variable var,
06122 const Linear_Expression& lb_expr,
06123 const Linear_Expression& ub_expr,
06124 Coefficient_traits::const_reference
06125 denominator) {
06126
06127 if (denominator == 0)
06128 throw_generic("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
06129
06130
06131 const dimension_type var_id = var.id();
06132 if (space_dim < var_id + 1)
06133 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
06134 var_id + 1);
06135
06136
06137
06138 const dimension_type lb_space_dim = lb_expr.space_dimension();
06139 if (space_dim < lb_space_dim)
06140 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
06141 "lb", lb_expr);
06142 const dimension_type ub_space_dim = ub_expr.space_dimension();
06143 if (space_dim < ub_space_dim)
06144 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
06145 "ub", ub_expr);
06146
06147 strong_closure_assign();
06148
06149 if (marked_empty())
06150 return;
06151
06152 if (ub_expr.coefficient(var) == 0) {
06153 refine(var, LESS_OR_EQUAL, ub_expr, denominator);
06154 generalized_affine_preimage(var, GREATER_OR_EQUAL,
06155 lb_expr, denominator);
06156 return;
06157 }
06158 if (lb_expr.coefficient(var) == 0) {
06159 refine(var, GREATER_OR_EQUAL, lb_expr, denominator);
06160 generalized_affine_preimage(var, LESS_OR_EQUAL,
06161 ub_expr, denominator);
06162 return;
06163 }
06164
06165 const Coefficient& expr_v = lb_expr.coefficient(var);
06166
06167
06168 const Variable new_var = Variable(space_dim);
06169 add_space_dimensions_and_embed(1);
06170 const Linear_Expression lb_inverse
06171 = lb_expr - (expr_v + denominator)*var;
06172 PPL_DIRTY_TEMP_COEFFICIENT(inverse_den);
06173 neg_assign(inverse_den, expr_v);
06174 affine_image(new_var, lb_inverse, inverse_den);
06175 strong_closure_assign();
06176 PPL_ASSERT(!marked_empty());
06177 generalized_affine_preimage(var, LESS_OR_EQUAL,
06178 ub_expr, denominator);
06179 if (sgn(denominator) == sgn(inverse_den))
06180 refine_no_check(var >= new_var) ;
06181 else
06182 refine_no_check(var <= new_var);
06183
06184 remove_higher_space_dimensions(space_dim-1);
06185 }
06186
06187 template <typename T>
06188 Constraint_System
06189 Octagonal_Shape<T>::constraints() const {
06190 Constraint_System cs;
06191 if (space_dim == 0) {
06192 if (marked_empty())
06193 cs = Constraint_System::zero_dim_empty();
06194 }
06195 else if (marked_empty())
06196 cs.insert(0*Variable(space_dim-1) <= -1);
06197 else {
06198
06199
06200 cs.insert(0*Variable(space_dim-1) <= 0);
06201
06202 typedef typename OR_Matrix<N>::const_row_iterator Row_Iterator;
06203 typedef typename OR_Matrix<N>::const_row_reference_type Row_Reference;
06204
06205 Row_Iterator m_begin = matrix.row_begin();
06206 Row_Iterator m_end = matrix.row_end();
06207
06208 PPL_DIRTY_TEMP_COEFFICIENT(a);
06209 PPL_DIRTY_TEMP_COEFFICIENT(b);
06210
06211
06212 for (Row_Iterator i_iter = m_begin; i_iter != m_end; ) {
06213 const dimension_type i = i_iter.index();
06214 const Variable x(i/2);
06215 const N& c_i_ii = (*i_iter)[i+1];
06216 ++i_iter;
06217 const N& c_ii_i = (*i_iter)[i];
06218 ++i_iter;
06219
06220 if (is_additive_inverse(c_i_ii, c_ii_i)) {
06221
06222 numer_denom(c_ii_i, b, a);
06223 a *= 2;
06224 cs.insert(a*x == b);
06225 }
06226 else {
06227
06228 if (!is_plus_infinity(c_i_ii)) {
06229 numer_denom(c_i_ii, b, a);
06230 a *= 2;
06231 cs.insert(-a*x <= b);
06232 }
06233 if (!is_plus_infinity(c_ii_i)) {
06234 numer_denom(c_ii_i, b, a);
06235 a *= 2;
06236 cs.insert(a*x <= b);
06237 }
06238 }
06239 }
06240
06241 for (Row_Iterator i_iter = m_begin; i_iter != m_end; ) {
06242 const dimension_type i = i_iter.index();
06243 Row_Reference r_i = *i_iter;
06244 ++i_iter;
06245 Row_Reference r_ii = *i_iter;
06246 ++i_iter;
06247 const Variable y(i/2);
06248 for (dimension_type j = 0; j < i; j += 2) {
06249 const N& c_i_j = r_i[j];
06250 const N& c_ii_jj = r_ii[j+1];
06251 const Variable x(j/2);
06252 if (is_additive_inverse(c_ii_jj, c_i_j)) {
06253
06254 numer_denom(c_i_j, b, a);
06255 cs.insert(a*x - a*y == b);
06256 }
06257 else {
06258
06259 if (!is_plus_infinity(c_i_j)) {
06260 numer_denom(c_i_j, b, a);
06261 cs.insert(a*x - a*y <= b);
06262 }
06263 if (!is_plus_infinity(c_ii_jj)) {
06264 numer_denom(c_ii_jj, b, a);
06265 cs.insert(a*y - a*x <= b);
06266 }
06267 }
06268
06269 const N& c_ii_j = r_ii[j];
06270 const N& c_i_jj = r_i[j+1];
06271 if (is_additive_inverse(c_i_jj, c_ii_j)) {
06272
06273 numer_denom(c_ii_j, b, a);
06274 cs.insert(a*x + a*y == b);
06275 }
06276 else {
06277
06278 if (!is_plus_infinity(c_i_jj)) {
06279 numer_denom(c_i_jj, b, a);
06280 cs.insert(-a*x - a*y <= b);
06281 }
06282 if (!is_plus_infinity(c_ii_j)) {
06283 numer_denom(c_ii_j, b, a);
06284 cs.insert(a*x + a*y <= b);
06285 }
06286 }
06287 }
06288 }
06289 }
06290 return cs;
06291 }
06292
06293 template <typename T>
06294 void
06295 Octagonal_Shape<T>::expand_space_dimension(Variable var, dimension_type m) {
06296
06297 const dimension_type var_id = var.id();
06298 if (var_id+1 > space_dim)
06299 throw_dimension_incompatible("expand_space_dimension(v, m)", var_id+1);
06300
06301
06302
06303 if (m > max_space_dimension() - space_dim)
06304 throw_generic("expand_dimension(v, m)",
06305 "adding m new space dimensions exceeds "
06306 "the maximum allowed space dimension");
06307
06308
06309 if (m == 0)
06310 return;
06311
06312
06313 const dimension_type old_num_rows = matrix.num_rows();
06314
06315
06316 add_space_dimensions_and_embed(m);
06317
06318
06319
06320
06321 typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
06322 typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
06323 typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
06324 typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
06325
06326 const Row_Iterator m_begin = matrix.row_begin();
06327 const Row_Iterator m_end = matrix.row_end();
06328 const dimension_type n_var = 2*var_id;
06329 Row_iterator v_iter = m_begin + n_var;
06330 Row_reference m_v = *v_iter;
06331 Row_reference m_cv = *(v_iter+1);
06332
06333 for (Row_Iterator i_iter = m_begin + old_num_rows; i_iter != m_end;
06334 i_iter += 2) {
06335 Row_Reference m_i = *i_iter;
06336 Row_Reference m_ci = *(i_iter+1);
06337 const dimension_type i = i_iter.index();
06338 const dimension_type ci = i+1;
06339 m_i[ci] = m_v[n_var+1];
06340 m_ci[i] = m_cv[n_var];
06341 for (dimension_type j = 0; j < n_var; ++j) {
06342 m_i[j] = m_v[j];
06343 m_ci[j] = m_cv[j];
06344 }
06345 for (dimension_type j = n_var+2; j < old_num_rows; ++j) {
06346 Row_Iterator j_iter = m_begin + j;
06347 Row_Reference m_cj = (j % 2 != 0) ? *(j_iter-1) : *(j_iter+1);
06348 m_i[j] = m_cj[n_var+1];
06349 m_ci[j] = m_cj[n_var];
06350 }
06351 }
06352
06353
06354 if (marked_strongly_closed())
06355 reset_strongly_closed();
06356 PPL_ASSERT(OK());
06357 }
06358
06359 template <typename T>
06360 void
06361 Octagonal_Shape<T>::fold_space_dimensions(const Variables_Set& vars,
06362 Variable dest) {
06363
06364 if (dest.space_dimension() > space_dim)
06365 throw_dimension_incompatible("fold_space_dimensions(vs, v)", "v", dest);
06366
06367
06368 if (vars.empty())
06369 return;
06370
06371
06372 if (vars.space_dimension() > space_dim)
06373 throw_dimension_incompatible("fold_space_dimensions(vs, v)",
06374 vars.space_dimension());
06375
06376
06377 if (vars.find(dest.id()) != vars.end())
06378 throw_generic("fold_space_dimensions(vs, v)",
06379 "v should not occur in vs");
06380
06381
06382
06383
06384
06385 typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
06386 typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
06387
06388 const Row_Iterator m_begin = matrix.row_begin();
06389
06390 strong_closure_assign();
06391 const dimension_type n_rows = matrix.num_rows();
06392 const dimension_type n_dest = 2*dest.id();
06393 Row_Iterator v_iter = m_begin + n_dest;
06394 Row_Reference m_v = *v_iter;
06395 Row_Reference m_cv = *(v_iter+1);
06396 for (Variables_Set::const_iterator i = vars.begin(),
06397 vs_end = vars.end(); i != vs_end; ++i) {
06398 const dimension_type tbf_id = *i;
06399 const dimension_type tbf_var = 2*tbf_id;
06400 Row_Iterator tbf_iter = m_begin + tbf_var;
06401 Row_Reference m_tbf = *tbf_iter;
06402 Row_Reference m_ctbf = *(tbf_iter+1);
06403 max_assign(m_v[n_dest+1], m_tbf[tbf_var+1]);
06404 max_assign(m_cv[n_dest], m_ctbf[tbf_var]);
06405
06406 const dimension_type min_id = std::min(n_dest, tbf_var);
06407 const dimension_type max_id = std::max(n_dest, tbf_var);
06408
06409 using namespace Implementation::Octagonal_Shapes;
06410 for (dimension_type j = 0; j < min_id; ++j) {
06411 const dimension_type cj = coherent_index(j);
06412 max_assign(m_v[j], m_tbf[j]);
06413 max_assign(m_cv[j], m_ctbf[j]);
06414 max_assign(m_cv[cj], m_ctbf[cj]);
06415 max_assign(m_v[cj], m_tbf[cj]);
06416 }
06417 for (dimension_type j = min_id+2; j < max_id; ++j) {
06418 const dimension_type cj = coherent_index(j);
06419 Row_Iterator j_iter = m_begin + j;
06420 Row_Reference m_j = *j_iter;
06421 Row_Reference m_cj = (j % 2 != 0) ? *(j_iter-1) : *(j_iter+1);
06422 if (n_dest == min_id) {
06423 max_assign(m_cj[n_dest+1], m_tbf[j]);
06424 max_assign(m_cj[n_dest], m_ctbf[j]);
06425 max_assign(m_j[n_dest], m_ctbf[cj]);
06426 max_assign(m_j[n_dest+1], m_tbf[cj]);
06427 }
06428 else {
06429 max_assign(m_v[j], m_cj[tbf_var+1]);
06430 max_assign(m_cv[j], m_cj[tbf_var]);
06431 max_assign(m_cv[cj], m_j[tbf_var]);
06432 max_assign(m_v[cj], m_j[tbf_var+1]);
06433 }
06434 }
06435 for (dimension_type j = max_id+2; j < n_rows; ++j) {
06436 Row_Iterator j_iter = m_begin + j;
06437 Row_Reference m_j = *j_iter;
06438 Row_Reference m_cj = (j % 2 != 0) ? *(j_iter-1) : *(j_iter+1);
06439 max_assign(m_cj[n_dest+1], m_cj[tbf_var+1]);
06440 max_assign(m_cj[n_dest], m_cj[tbf_var]);
06441 max_assign(m_j[n_dest], m_j[tbf_var]);
06442 max_assign(m_j[n_dest+1], m_j[tbf_var+1]);
06443 }
06444 }
06445 remove_space_dimensions(vars);
06446 }
06447
06448 template <typename T>
06449 bool
06450 Octagonal_Shape<T>::upper_bound_assign_if_exact(const Octagonal_Shape& y) {
06451
06452
06453
06454 const Octagonal_Shape& x = *this;
06455 const dimension_type x_space_dim = x.space_dimension();
06456
06457 if (x_space_dim != y.space_dimension())
06458 throw_dimension_incompatible("upper_bound_assign_if_exact(y)", y);
06459
06460
06461 if (x_space_dim == 0) {
06462 upper_bound_assign(y);
06463 return true;
06464 }
06465
06466 if (x.marked_empty()) {
06467 *this = y;
06468 return true;
06469 }
06470 else if (y.is_empty())
06471 return true;
06472 else if (x.is_empty()) {
06473 *this = y;
06474 return true;
06475 }
06476
06477
06478 PPL_ASSERT(x.marked_strongly_closed());
06479 PPL_ASSERT(y.marked_strongly_closed());
06480
06481 Octagonal_Shape<T> ub(x);
06482 ub.upper_bound_assign(y);
06483
06484
06485
06486 std::vector<Bit_Row> x_non_red;
06487 x.non_redundant_matrix_entries(x_non_red);
06488 std::vector<Bit_Row> y_non_red;
06489 y.non_redundant_matrix_entries(y_non_red);
06490
06491 PPL_DIRTY_TEMP(N, lhs);
06492 PPL_DIRTY_TEMP(N, lhs_copy);
06493 PPL_DIRTY_TEMP(N, rhs);
06494 PPL_DIRTY_TEMP(N, temp_zero);
06495 assign_r(temp_zero, 0, ROUND_NOT_NEEDED);
06496
06497 typedef typename OR_Matrix<N>::const_row_iterator Row_Iterator;
06498 typedef typename OR_Matrix<N>::const_row_reference_type Row_Reference;
06499 const dimension_type n_rows = x.matrix.num_rows();
06500 const Row_Iterator x_m_begin = x.matrix.row_begin();
06501 const Row_Iterator y_m_begin = y.matrix.row_begin();
06502 const Row_Iterator ub_m_begin = ub.matrix.row_begin();
06503
06504 for (dimension_type i = n_rows; i-- > 0; ) {
06505 const Bit_Row& x_non_red_i = x_non_red[i];
06506 using namespace Implementation::Octagonal_Shapes;
06507 const dimension_type ci = coherent_index(i);
06508 const dimension_type row_size_i = OR_Matrix<N>::row_size(i);
06509 Row_Reference x_i = *(x_m_begin + i);
06510 Row_Reference y_i = *(y_m_begin + i);
06511 Row_Reference ub_i = *(ub_m_begin + i);
06512 const N& ub_i_ci = ub_i[ci];
06513 for (dimension_type j = row_size_i; j-- > 0; ) {
06514
06515 if (!x_non_red_i[j])
06516 continue;
06517 const N& x_i_j = x_i[j];
06518
06519 if (x_i_j >= y_i[j])
06520 continue;
06521 const dimension_type cj = coherent_index(j);
06522 const dimension_type row_size_cj = OR_Matrix<N>::row_size(cj);
06523 Row_Reference ub_cj = *(ub_m_begin + cj);
06524 const N& ub_cj_j = ub_cj[j];
06525 for (dimension_type k = 0; k < n_rows; ++k) {
06526 const Bit_Row& y_non_red_k = y_non_red[k];
06527 const dimension_type ck = coherent_index(k);
06528 const dimension_type row_size_k = OR_Matrix<N>::row_size(k);
06529 Row_Reference x_k = *(x_m_begin + k);
06530 Row_Reference y_k = *(y_m_begin + k);
06531 Row_Reference ub_k = *(ub_m_begin + k);
06532 const N& ub_k_ck = ub_k[ck];
06533
06534
06535
06536 const N& ub_k_j = (k == j) ? temp_zero
06537 : (j < row_size_k ? ub_k[j] : ub_cj[ck]);
06538 const N& ub_i_ck = (i == ck) ? temp_zero
06539 : (ck < row_size_i ? ub_i[ck] : ub_k[ci]);
06540
06541 for (dimension_type ell = row_size_k; ell-- > 0; ) {
06542
06543 if (!y_non_red_k[ell])
06544 continue;
06545 const N& y_k_ell = y_k[ell];
06546
06547 if (y_k_ell >= x_k[ell])
06548 continue;
06549 const dimension_type cell = coherent_index(ell);
06550 Row_Reference ub_cell = *(ub_m_begin + cell);
06551 const N& ub_i_ell = (i == ell) ? temp_zero
06552 : (ell < row_size_i ? ub_i[ell] : ub_cell[ci]);
06553 const N& ub_cj_ell = (cj == ell) ? temp_zero
06554 : (ell < row_size_cj ? ub_cj[ell] : ub_cell[j]);
06555
06556 add_assign_r(lhs, x_i_j, y_k_ell, ROUND_UP);
06557 add_assign_r(rhs, ub_i_ell, ub_k_j, ROUND_UP);
06558 if (lhs >= rhs)
06559 continue;
06560
06561 add_assign_r(rhs, ub_i_ck, ub_cj_ell, ROUND_UP);
06562 if (lhs >= rhs)
06563 continue;
06564
06565 assign_r(lhs_copy, lhs, ROUND_NOT_NEEDED);
06566 add_assign_r(lhs, lhs_copy, x_i_j, ROUND_UP);
06567 add_assign_r(rhs, ub_i_ell, ub_i_ck, ROUND_UP);
06568 add_assign_r(rhs, rhs, ub_cj_j, ROUND_UP);
06569 if (lhs >= rhs)
06570 continue;
06571
06572 add_assign_r(rhs, ub_k_j, ub_cj_ell, ROUND_UP);
06573 add_assign_r(rhs, rhs, ub_i_ci, ROUND_UP);
06574 if (lhs >= rhs)
06575 continue;
06576
06577 add_assign_r(lhs, lhs_copy, y_k_ell, ROUND_UP);
06578 add_assign_r(rhs, ub_i_ell, ub_cj_ell, ROUND_UP);
06579 add_assign_r(rhs, rhs, ub_k_ck, ROUND_UP);
06580 if (lhs >= rhs)
06581 continue;
06582
06583 add_assign_r(rhs, ub_k_j, ub_i_ck, ROUND_UP);
06584 add_assign_r(rhs, rhs, ub_cell[ell], ROUND_UP);
06585 if (lhs < rhs)
06586
06587
06588 return false;
06589 }
06590 }
06591 }
06592 }
06593
06594
06595 swap(ub);
06596 PPL_ASSERT(OK());
06597 return true;
06598 }
06599
06600 template <typename T>
06601 bool
06602 Octagonal_Shape<T>
06603 ::integer_upper_bound_assign_if_exact(const Octagonal_Shape& y) {
06604 PPL_COMPILE_TIME_CHECK(std::numeric_limits<T>::is_integer,
06605 "Octagonal_Shape<T>::"
06606 "integer_upper_bound_assign_if_exact(y):"
06607 " T in not an integer datatype.");
06608
06609 const Octagonal_Shape& x = *this;
06610 const dimension_type x_space_dim = x.space_dimension();
06611
06612 if (x_space_dim != y.space_dimension())
06613 throw_dimension_incompatible("integer_upper_bound_assign_if_exact(y)", y);
06614
06615
06616 if (x_space_dim == 0) {
06617 upper_bound_assign(y);
06618 return true;
06619 }
06620
06621
06622
06623 if (x.marked_empty()) {
06624 *this = y;
06625 tight_closure_assign();
06626 return true;
06627 }
06628 else if (y.marked_empty()) {
06629 tight_closure_assign();
06630 return true;
06631 }
06632 else if (x.is_empty() || x.tight_coherence_would_make_empty()) {
06633 *this = y;
06634 tight_closure_assign();
06635 return true;
06636 }
06637 else if (y.is_empty() || y.tight_coherence_would_make_empty()) {
06638 tight_closure_assign();
06639 return true;
06640 }
06641
06642
06643 PPL_ASSERT(x.marked_strongly_closed());
06644 PPL_ASSERT(y.marked_strongly_closed());
06645
06646
06647 Octagonal_Shape<T> tx(x);
06648 tx.tight_closure_assign();
06649 Octagonal_Shape<T> ty(y);
06650 ty.tight_closure_assign();
06651 Octagonal_Shape<T> ub(tx);
06652 ub.upper_bound_assign(ty);
06653
06654
06655
06656
06657
06658 std::vector<Bit_Row> tx_non_red;
06659 tx.non_redundant_matrix_entries(tx_non_red);
06660 std::vector<Bit_Row> ty_non_red;
06661 ty.non_redundant_matrix_entries(ty_non_red);
06662
06663 PPL_DIRTY_TEMP(N, lhs_i_j);
06664 PPL_DIRTY_TEMP(N, lhs_k_ell);
06665 PPL_DIRTY_TEMP(N, lhs);
06666 PPL_DIRTY_TEMP(N, lhs_copy);
06667 PPL_DIRTY_TEMP(N, rhs);
06668 PPL_DIRTY_TEMP(N, temp_zero);
06669 assign_r(temp_zero, 0, ROUND_NOT_NEEDED);
06670 PPL_DIRTY_TEMP(N, temp_one);
06671 assign_r(temp_one, 1, ROUND_NOT_NEEDED);
06672 PPL_DIRTY_TEMP(N, temp_two);
06673 assign_r(temp_two, 2, ROUND_NOT_NEEDED);
06674
06675 typedef typename OR_Matrix<N>::const_row_iterator Row_Iterator;
06676 typedef typename OR_Matrix<N>::const_row_reference_type Row_Reference;
06677 const dimension_type n_rows = tx.matrix.num_rows();
06678 const Row_Iterator tx_m_begin = tx.matrix.row_begin();
06679 const Row_Iterator ty_m_begin = ty.matrix.row_begin();
06680 const Row_Iterator ub_m_begin = ub.matrix.row_begin();
06681
06682 for (dimension_type i = n_rows; i-- > 0; ) {
06683 const Bit_Row& tx_non_red_i = tx_non_red[i];
06684 using namespace Implementation::Octagonal_Shapes;
06685 const dimension_type ci = coherent_index(i);
06686 const dimension_type row_size_i = OR_Matrix<N>::row_size(i);
06687 Row_Reference tx_i = *(tx_m_begin + i);
06688 Row_Reference ty_i = *(ty_m_begin + i);
06689 Row_Reference ub_i = *(ub_m_begin + i);
06690 const N& ub_i_ci = ub_i[ci];
06691 for (dimension_type j = row_size_i; j-- > 0; ) {
06692
06693 if (!tx_non_red_i[j])
06694 continue;
06695 const N& tx_i_j = tx_i[j];
06696 const dimension_type cj = coherent_index(j);
06697 const N& eps_i_j = (i == cj) ? temp_two : temp_one;
06698
06699 add_assign_r(lhs_i_j, tx_i_j, eps_i_j, ROUND_NOT_NEEDED);
06700 if (lhs_i_j > ty_i[j])
06701 continue;
06702 const dimension_type row_size_cj = OR_Matrix<N>::row_size(cj);
06703 Row_Reference ub_cj = *(ub_m_begin + cj);
06704 const N& ub_cj_j = ub_cj[j];
06705 for (dimension_type k = 0; k < n_rows; ++k) {
06706 const Bit_Row& ty_non_red_k = ty_non_red[k];
06707 const dimension_type ck = coherent_index(k);
06708 const dimension_type row_size_k = OR_Matrix<N>::row_size(k);
06709 Row_Reference tx_k = *(tx_m_begin + k);
06710 Row_Reference ty_k = *(ty_m_begin + k);
06711 Row_Reference ub_k = *(ub_m_begin + k);
06712 const N& ub_k_ck = ub_k[ck];
06713
06714
06715
06716 const N& ub_k_j = (k == j) ? temp_zero
06717 : (j < row_size_k ? ub_k[j] : ub_cj[ck]);
06718 const N& ub_i_ck = (i == ck) ? temp_zero
06719 : (ck < row_size_i ? ub_i[ck] : ub_k[ci]);
06720
06721 for (dimension_type ell = row_size_k; ell-- > 0; ) {
06722
06723 if (!ty_non_red_k[ell])
06724 continue;
06725 const N& ty_k_ell = ty_k[ell];
06726 const dimension_type cell = coherent_index(ell);
06727 const N& eps_k_ell = (k == cell) ? temp_two : temp_one;
06728
06729 add_assign_r(lhs_k_ell, ty_k_ell, eps_k_ell, ROUND_NOT_NEEDED);
06730 if (lhs_k_ell > tx_k[ell])
06731 continue;
06732 Row_Reference ub_cell = *(ub_m_begin + cell);
06733 const N& ub_i_ell = (i == ell) ? temp_zero
06734 : (ell < row_size_i ? ub_i[ell] : ub_cell[ci]);
06735 const N& ub_cj_ell = (cj == ell) ? temp_zero
06736 : (ell < row_size_cj ? ub_cj[ell] : ub_cell[j]);
06737
06738 add_assign_r(lhs, lhs_i_j, lhs_k_ell, ROUND_NOT_NEEDED);
06739 add_assign_r(rhs, ub_i_ell, ub_k_j, ROUND_NOT_NEEDED);
06740 if (lhs > rhs)
06741 continue;
06742
06743 add_assign_r(rhs, ub_i_ck, ub_cj_ell, ROUND_NOT_NEEDED);
06744 if (lhs > rhs)
06745 continue;
06746
06747 assign_r(lhs_copy, lhs, ROUND_NOT_NEEDED);
06748 add_assign_r(lhs, lhs, lhs_i_j, ROUND_NOT_NEEDED);
06749 add_assign_r(rhs, ub_i_ell, ub_i_ck, ROUND_NOT_NEEDED);
06750 add_assign_r(rhs, rhs, ub_cj_j, ROUND_NOT_NEEDED);
06751 if (lhs > rhs)
06752 continue;
06753
06754 add_assign_r(rhs, ub_k_j, ub_cj_ell, ROUND_NOT_NEEDED);
06755 add_assign_r(rhs, rhs, ub_i_ci, ROUND_NOT_NEEDED);
06756 if (lhs > rhs)
06757 continue;
06758
06759 add_assign_r(lhs, lhs_copy, lhs_k_ell, ROUND_NOT_NEEDED);
06760 add_assign_r(rhs, ub_i_ell, ub_cj_ell, ROUND_NOT_NEEDED);
06761 add_assign_r(rhs, rhs, ub_k_ck, ROUND_NOT_NEEDED);
06762 if (lhs > rhs)
06763 continue;
06764
06765 add_assign_r(rhs, ub_k_j, ub_i_ck, ROUND_NOT_NEEDED);
06766 add_assign_r(rhs, rhs, ub_cell[ell], ROUND_NOT_NEEDED);
06767 if (lhs <= rhs)
06768
06769
06770 return false;
06771 }
06772 }
06773 }
06774 }
06775
06776
06777 swap(ub);
06778 PPL_ASSERT(OK());
06779 return true;
06780 }
06781
06782 template <typename T>
06783 void
06784 Octagonal_Shape<T>::drop_some_non_integer_points(Complexity_Class) {
06785 if (std::numeric_limits<T>::is_integer)
06786 return;
06787
06788 const dimension_type space_dim = space_dimension();
06789 strong_closure_assign();
06790 if (space_dim == 0 || marked_empty())
06791 return;
06792
06793 for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
06794 i_end = matrix.element_end(); i != i_end; ++i)
06795 drop_some_non_integer_points_helper(*i);
06796
06797
06798 PPL_DIRTY_TEMP(N, temp_one);
06799 assign_r(temp_one, 1, ROUND_NOT_NEEDED);
06800 for (dimension_type i = 0; i < 2*space_dim; i += 2) {
06801 const dimension_type ci = i+1;
06802 N& mat_i_ci = matrix[i][ci];
06803 if (!is_plus_infinity(mat_i_ci) && !is_even(mat_i_ci)) {
06804 sub_assign_r(mat_i_ci, mat_i_ci, temp_one, ROUND_UP);
06805 reset_strongly_closed();
06806 }
06807 N& mat_ci_i = matrix[ci][i];
06808 if (!is_plus_infinity(mat_ci_i) && !is_even(mat_ci_i)) {
06809 sub_assign_r(mat_ci_i, mat_ci_i, temp_one, ROUND_UP);
06810 reset_strongly_closed();
06811 }
06812 }
06813
06814 PPL_ASSERT(OK());
06815 }
06816
06817 template <typename T>
06818 void
06819 Octagonal_Shape<T>
06820 ::drop_some_non_integer_points(const Variables_Set& vars,
06821 Complexity_Class) {
06822
06823 const dimension_type min_space_dim = vars.space_dimension();
06824 if (space_dimension() < min_space_dim)
06825 throw_dimension_incompatible("drop_some_non_integer_points(vs, cmpl)",
06826 min_space_dim);
06827
06828 if (std::numeric_limits<T>::is_integer || min_space_dim == 0)
06829 return;
06830
06831 strong_closure_assign();
06832 if (marked_empty())
06833 return;
06834
06835 PPL_DIRTY_TEMP(N, temp_one);
06836 assign_r(temp_one, 1, ROUND_NOT_NEEDED);
06837
06838 const Variables_Set::const_iterator v_begin = vars.begin();
06839 const Variables_Set::const_iterator v_end = vars.end();
06840 PPL_ASSERT(v_begin != v_end);
06841 typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
06842 for (Variables_Set::const_iterator v_i = v_begin; v_i != v_end; ++v_i) {
06843 const dimension_type i = 2 * (*v_i);
06844 const dimension_type ci = i + 1;
06845 Row_Reference m_i = matrix[i];
06846 Row_Reference m_ci = matrix[ci];
06847
06848
06849 N& m_i_ci = m_i[ci];
06850 if (!is_plus_infinity(m_i_ci)) {
06851 drop_some_non_integer_points_helper(m_i_ci);
06852 if (!is_even(m_i_ci)) {
06853 sub_assign_r(m_i_ci, m_i_ci, temp_one, ROUND_UP);
06854 reset_strongly_closed();
06855 }
06856 }
06857 N& m_ci_i = m_ci[i];
06858 if (!is_plus_infinity(m_ci_i)) {
06859 drop_some_non_integer_points_helper(m_ci_i);
06860 if (!is_even(m_ci_i)) {
06861 sub_assign_r(m_ci_i, m_ci_i, temp_one, ROUND_UP);
06862 reset_strongly_closed();
06863 }
06864 }
06865
06866
06867 for (Variables_Set::const_iterator v_j = v_begin; v_j != v_i; ++v_j) {
06868 const dimension_type j = 2 * (*v_j);
06869 const dimension_type cj = j + 1;
06870 drop_some_non_integer_points_helper(m_i[j]);
06871 drop_some_non_integer_points_helper(m_i[cj]);
06872 drop_some_non_integer_points_helper(m_ci[j]);
06873 drop_some_non_integer_points_helper(m_ci[cj]);
06874 }
06875 }
06876 PPL_ASSERT(OK());
06877 }
06878
06880 template <typename T>
06881 std::ostream&
06882 IO_Operators::operator<<(std::ostream& s, const Octagonal_Shape<T>& x) {
06883
06884 if (x.marked_empty()) {
06885 s << "false";
06886 return s;
06887 }
06888 if (x.is_universe()) {
06889 s << "true";
06890 return s;
06891 }
06892
06893 typedef typename Octagonal_Shape<T>::coefficient_type N;
06894 typedef typename OR_Matrix<N>::const_row_iterator Row_Iterator;
06895 typedef typename OR_Matrix<N>::const_row_reference_type Row_Reference;
06896
06897
06898 bool first = true;
06899
06900 Row_Iterator m_begin = x.matrix.row_begin();
06901 Row_Iterator m_end = x.matrix.row_end();
06902
06903
06904 PPL_DIRTY_TEMP(N, negation);
06905 PPL_DIRTY_TEMP(N, half);
06906
06907
06908 for (Row_Iterator i_iter = m_begin; i_iter != m_end; ) {
06909 const dimension_type i = i_iter.index();
06910 const Variable v_i = Variable(i/2);
06911 const N& x_i_ii = (*i_iter)[i+1];
06912 ++i_iter;
06913 const N& x_ii_i = (*i_iter)[i];
06914 ++i_iter;
06915
06916 if (is_additive_inverse(x_i_ii, x_ii_i)) {
06917
06918 PPL_ASSERT(!is_plus_infinity(x_i_ii) && !is_plus_infinity(x_ii_i));
06919 if (first)
06920 first = false;
06921 else
06922 s << ", ";
06923
06924
06925 if (div_2exp_assign_r(half, x_ii_i, 1, ROUND_UP | ROUND_STRICT_RELATION) == V_EQ)
06926 s << v_i << " = " << half;
06927 else
06928 s << "2*" << v_i << " = " << x_ii_i;
06929 }
06930 else {
06931
06932 if (!is_plus_infinity(x_i_ii)) {
06933 if (first)
06934 first = false;
06935 else
06936 s << ", ";
06937 neg_assign_r(negation, x_i_ii, ROUND_NOT_NEEDED);
06938
06939
06940 if (div_2exp_assign_r(half, negation, 1, ROUND_UP | ROUND_STRICT_RELATION) == V_EQ)
06941 s << v_i << " >= " << half;
06942 else
06943 s << "2*" << v_i << " >= " << negation;
06944 }
06945 if (!is_plus_infinity(x_ii_i)) {
06946 if (first)
06947 first = false;
06948 else
06949 s << ", ";
06950
06951
06952 if (div_2exp_assign_r(half, x_ii_i, 1, ROUND_UP | ROUND_STRICT_RELATION) == V_EQ)
06953 s << v_i << " <= " << half;
06954 else
06955 s << "2*" << v_i << " <= " << x_ii_i;
06956 }
06957 }
06958 }
06959
06960
06961
06962 for (Row_Iterator i_iter = m_begin; i_iter != m_end; ) {
06963 const dimension_type i = i_iter.index();
06964 const Variable v_i = Variable(i/2);
06965 Row_Reference r_i = *i_iter;
06966 ++i_iter;
06967 Row_Reference r_ii = *i_iter;
06968 ++i_iter;
06969
06970 for (dimension_type j = 0; j < i; j += 2) {
06971 const Variable v_j = Variable(j/2);
06972
06973 const N& x_ii_jj = r_ii[j+1];
06974 const N& x_i_j = r_i[j];
06975
06976 if (is_additive_inverse(x_ii_jj, x_i_j)) {
06977
06978 PPL_ASSERT(!is_plus_infinity(x_i_j) && !is_plus_infinity(x_ii_jj));
06979 if (first)
06980 first = false;
06981 else
06982 s << ", ";
06983 if (sgn(x_i_j) >= 0)
06984 s << v_j << " - " << v_i << " = " << x_i_j;
06985 else
06986 s << v_i << " - " << v_j << " = " << x_ii_jj;
06987 }
06988 else {
06989
06990 if (!is_plus_infinity(x_i_j)) {
06991 if (first)
06992 first = false;
06993 else
06994 s << ", ";
06995 if (sgn(x_i_j) >= 0)
06996 s << v_j << " - " << v_i << " <= " << x_i_j;
06997 else {
06998 neg_assign_r(negation, x_i_j, ROUND_DOWN);
06999 s << v_i << " - " << v_j << " >= " << negation;
07000 }
07001 }
07002 if (!is_plus_infinity(x_ii_jj)) {
07003 if (first)
07004 first = false;
07005 else
07006 s << ", ";
07007 if (sgn(x_ii_jj) >= 0)
07008 s << v_i << " - " << v_j << " <= " << x_ii_jj;
07009 else {
07010 neg_assign_r(negation, x_ii_jj, ROUND_DOWN);
07011 s << v_j << " - " << v_i << " >= " << negation;
07012 }
07013 }
07014 }
07015
07016 const N& x_i_jj = r_i[j+1];
07017 const N& x_ii_j = r_ii[j];
07018
07019 if (is_additive_inverse(x_i_jj, x_ii_j)) {
07020
07021 PPL_ASSERT(!is_plus_infinity(x_i_jj) && !is_plus_infinity(x_ii_j));
07022 if (first)
07023 first = false;
07024 else
07025 s << ", ";
07026 s << v_j << " + " << v_i << " = " << x_ii_j;
07027 }
07028 else {
07029
07030 if (!is_plus_infinity(x_i_jj)) {
07031 if (first)
07032 first = false;
07033 else
07034 s << ", ";
07035 neg_assign_r(negation, x_i_jj, ROUND_DOWN);
07036 s << v_j << " + " << v_i << " >= " << negation;
07037 }
07038 if (!is_plus_infinity(x_ii_j)) {
07039 if (first)
07040 first = false;
07041 else
07042 s << ", ";
07043 s << v_j << " + " << v_i << " <= " << x_ii_j;
07044 }
07045 }
07046 }
07047 }
07048 return s;
07049 }
07050
07051 template <typename T>
07052 void
07053 Octagonal_Shape<T>::ascii_dump(std::ostream& s) const {
07054 s << "space_dim "
07055 << space_dim
07056 << "\n";
07057 status.ascii_dump(s);
07058 s << "\n";
07059 matrix.ascii_dump(s);
07060 }
07061
07062 PPL_OUTPUT_TEMPLATE_DEFINITIONS(T, Octagonal_Shape<T>)
07063
07064 template <typename T>
07065 bool
07066 Octagonal_Shape<T>::ascii_load(std::istream& s) {
07067 std::string str;
07068
07069 if (!(s >> str) || str != "space_dim")
07070 return false;
07071
07072 if (!(s >> space_dim))
07073 return false;
07074
07075 if (!status.ascii_load(s))
07076 return false;
07077
07078 if (!matrix.ascii_load(s))
07079 return false;
07080
07081 PPL_ASSERT(OK());
07082 return true;
07083 }
07084
07085 template <typename T>
07086 memory_size_type
07087 Octagonal_Shape<T>::external_memory_in_bytes() const {
07088 return matrix.external_memory_in_bytes();
07089 }
07090
07091 template <typename T>
07092 bool
07093 Octagonal_Shape<T>::OK() const {
07094
07095 if (!matrix.OK())
07096 return false;
07097
07098
07099 if (!status.OK())
07100 return false;
07101
07102
07103 if (marked_empty())
07104 return true;
07105
07106
07107 if (space_dim == 0)
07108 return true;
07109
07110
07111 for (typename OR_Matrix<N>::const_row_iterator i = matrix.row_begin(),
07112 matrix_row_end = matrix.row_end(); i != matrix_row_end; ++i) {
07113 typename OR_Matrix<N>::const_row_reference_type x_i = *i;
07114 for (dimension_type j = i.row_size(); j-- > 0; )
07115 if (is_minus_infinity(x_i[j])) {
07116 #ifndef NDEBUG
07117 using namespace Parma_Polyhedra_Library::IO_Operators;
07118 std::cerr << "Octagonal_Shape::"
07119 << "matrix[" << i.index() << "][" << j << "] = "
07120 << x_i[j] << "!"
07121 << std::endl;
07122 #endif
07123 return false;
07124 }
07125 }
07126
07127
07128 for (typename OR_Matrix<N>::const_row_iterator i = matrix.row_begin(),
07129 m_end = matrix.row_end(); i != m_end; ++i) {
07130 typename OR_Matrix<N>::const_row_reference_type r = *i;
07131 const N& m_i_i = r[i.index()];
07132 if (!is_plus_infinity(m_i_i)) {
07133 #ifndef NDEBUG
07134 const dimension_type j = i.index();
07135 using namespace Parma_Polyhedra_Library::IO_Operators;
07136 std::cerr << "Octagonal_Shape::matrix[" << j << "][" << j << "] = "
07137 << m_i_i << "! (+inf was expected.)\n";
07138 #endif
07139 return false;
07140 }
07141 }
07142
07143
07144
07145
07146 if (std::numeric_limits<coefficient_type_base>::is_exact) {
07147
07148
07149 if (marked_strongly_closed()) {
07150 Octagonal_Shape x = *this;
07151 x.reset_strongly_closed();
07152 x.strong_closure_assign();
07153 if (x.matrix != matrix) {
07154 #ifndef NDEBUG
07155 std::cerr << "Octagonal_Shape is marked as strongly closed "
07156 << "but it is not!\n";
07157 #endif
07158 return false;
07159 }
07160 }
07161
07162
07163 if (marked_strongly_closed())
07164 if (!is_strong_coherent()) {
07165 #ifndef NDEBUG
07166 std::cerr << "Octagonal_Shape is not strong-coherent!\n";
07167 #endif
07168 return false;
07169 }
07170 }
07171
07172
07173 return true;
07174 }
07175
07176
07177 template <typename T>
07178 void
07179 Octagonal_Shape<T>
07180 ::throw_dimension_incompatible(const char* method,
07181 const Octagonal_Shape& y) const {
07182 std::ostringstream s;
07183 s << "PPL::Octagonal_Shape::" << method << ":\n"
07184 << "this->space_dimension() == " << space_dimension()
07185 << ", y->space_dimension() == " << y.space_dimension() << ".";
07186 throw std::invalid_argument(s.str());
07187 }
07188
07189 template <typename T>
07190 void
07191 Octagonal_Shape<T>
07192 ::throw_dimension_incompatible(const char* method,
07193 dimension_type required_dim) const {
07194 std::ostringstream s;
07195 s << "PPL::Octagonal_Shape::" << method << ":\n"
07196 << "this->space_dimension() == " << space_dimension()
07197 << ", required dimension == " << required_dim << ".";
07198 throw std::invalid_argument(s.str());
07199 }
07200
07201 template <typename T>
07202 void
07203 Octagonal_Shape<T>::throw_dimension_incompatible(const char* method,
07204 const Constraint& c) const {
07205 std::ostringstream s;
07206 s << "PPL::Octagonal_Shape::" << method << ":\n"
07207 << "this->space_dimension() == " << space_dimension()
07208 << ", c->space_dimension == " << c.space_dimension() << ".";
07209 throw std::invalid_argument(s.str());
07210 }
07211
07212 template <typename T>
07213 void
07214 Octagonal_Shape<T>::throw_dimension_incompatible(const char* method,
07215 const Congruence& cg) const {
07216 std::ostringstream s;
07217 s << "PPL::Octagonal_Shape::" << method << ":\n"
07218 << "this->space_dimension() == " << space_dimension()
07219 << ", cg->space_dimension == " << cg.space_dimension() << ".";
07220 throw std::invalid_argument(s.str());
07221 }
07222
07223 template <typename T>
07224 void
07225 Octagonal_Shape<T>::throw_dimension_incompatible(const char* method,
07226 const Generator& g) const {
07227 std::ostringstream s;
07228 s << "PPL::Octagonal_Shape::" << method << ":\n"
07229 << "this->space_dimension() == " << space_dimension()
07230 << ", g->space_dimension == " << g.space_dimension() << ".";
07231 throw std::invalid_argument(s.str());
07232 }
07233
07234 template <typename T>
07235 void
07236 Octagonal_Shape<T>::throw_constraint_incompatible(const char* method) const {
07237 std::ostringstream s;
07238 s << "PPL::Octagonal_Shape::" << method << ":\n"
07239 << "the constraint is incompatible.";
07240 throw std::invalid_argument(s.str());
07241 }
07242
07243 template <typename T>
07244 void
07245 Octagonal_Shape<T>
07246 ::throw_expression_too_complex(const char* method,
07247 const Linear_Expression& e) const {
07248 using namespace IO_Operators;
07249 std::ostringstream s;
07250 s << "PPL::Octagonal_Shape::" << method << ":\n"
07251 << e << " is too complex.";
07252 throw std::invalid_argument(s.str());
07253 }
07254
07255 template <typename T>
07256 void
07257 Octagonal_Shape<T>
07258 ::throw_dimension_incompatible(const char* method,
07259 const char* name_row,
07260 const Linear_Expression& y) const {
07261 std::ostringstream s;
07262 s << "PPL::Octagonal_Shape::" << method << ":\n"
07263 << "this->space_dimension() == " << space_dimension()
07264 << ", " << name_row << "->space_dimension() == "
07265 << y.space_dimension() << ".";
07266 throw std::invalid_argument(s.str());
07267 }
07268
07269 template <typename T>
07270 void
07271 Octagonal_Shape<T>::throw_generic(const char* method,
07272 const char* reason) const {
07273 std::ostringstream s;
07274 s << "PPL::Octagonal_Shape::" << method << ":\n"
07275 << reason << ".";
07276 throw std::invalid_argument(s.str());
07277 }
07278
07279 }
07280
07281 #endif // !defined(PPL_Octagonal_Shape_templates_hh)