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_Grid_templates_hh
00025 #define PPL_Grid_templates_hh 1
00026
00027 #include "Grid_Generator.defs.hh"
00028 #include "Grid_Generator_System.defs.hh"
00029 #include "Grid_Generator_System.inlines.hh"
00030 #include <algorithm>
00031 #include <deque>
00032
00033 namespace Parma_Polyhedra_Library {
00034
00035 template <typename Interval>
00036 Grid::Grid(const Box<Interval>& box,
00037 Complexity_Class)
00038 : con_sys(),
00039 gen_sys() {
00040 if (box.space_dimension() > max_space_dimension())
00041 throw_space_dimension_overflow("Grid(box, from_bounding_box)",
00042 "the space dimension of box "
00043 "exceeds the maximum allowed "
00044 "space dimension");
00045
00046 space_dim = box.space_dimension();
00047
00048 if (box.is_empty()) {
00049
00050 set_empty();
00051 PPL_ASSERT(OK());
00052 return;
00053 }
00054
00055 if (space_dim == 0)
00056 set_zero_dim_univ();
00057 else {
00058
00059 con_sys.increase_space_dimension(space_dim);
00060
00061 PPL_DIRTY_TEMP_COEFFICIENT(l_n);
00062 PPL_DIRTY_TEMP_COEFFICIENT(l_d);
00063 PPL_DIRTY_TEMP_COEFFICIENT(u_n);
00064 PPL_DIRTY_TEMP_COEFFICIENT(u_d);
00065 gen_sys.insert(grid_point(0*Variable(space_dim-1)));
00066 for (dimension_type k = space_dim; k-- > 0; ) {
00067
00068
00069 Grid_Generator& point = gen_sys[0];
00070 bool closed = false;
00071
00072 if (box.get_lower_bound(k, closed, l_n, l_d)) {
00073 if (box.get_upper_bound(k, closed, u_n, u_d))
00074 if (l_n * u_d == u_n * l_d) {
00075
00076
00077 con_sys.insert(l_d * Variable(k) == l_n);
00078
00079
00080
00081 const Coefficient& point_divisor = point.divisor();
00082 gcd_assign(u_n, l_d, point_divisor);
00083
00084 exact_div_assign(u_n, point_divisor, u_n);
00085 if (l_d < 0)
00086 neg_assign(u_n);
00087
00088 point.scale_to_divisor(l_d * u_n);
00089
00090 if (l_d < 0)
00091 neg_assign(u_n);
00092
00093 point[k + 1] = l_n * u_n;
00094
00095 continue;
00096 }
00097 }
00098
00099 gen_sys.insert(grid_line(Variable(k)));
00100 }
00101 set_congruences_up_to_date();
00102 set_generators_up_to_date();
00103 gen_sys.unset_pending_rows();
00104 gen_sys.set_sorted(false);
00105 }
00106
00107 PPL_ASSERT(OK());
00108 }
00109
00110 template <typename Partial_Function>
00111 void
00112 Grid::map_space_dimensions(const Partial_Function& pfunc) {
00113 if (space_dim == 0)
00114 return;
00115
00116 if (pfunc.has_empty_codomain()) {
00117
00118 if (marked_empty()
00119 || (!generators_are_up_to_date() && !update_generators())) {
00120
00121 space_dim = 0;
00122 set_empty();
00123 }
00124 else
00125
00126 set_zero_dim_univ();
00127
00128 PPL_ASSERT(OK());
00129 return;
00130 }
00131
00132 dimension_type new_space_dimension = pfunc.max_in_codomain() + 1;
00133
00134 if (new_space_dimension == space_dim) {
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 std::vector<dimension_type> cycles;
00151 cycles.reserve(space_dim + space_dim/2);
00152
00153
00154 std::deque<bool> visited(space_dim);
00155
00156 for (dimension_type i = space_dim; i-- > 0; ) {
00157 if (!visited[i]) {
00158 dimension_type j = i;
00159 do {
00160 visited[j] = true;
00161
00162 dimension_type k = 0;
00163 if (!pfunc.maps(j, k))
00164 throw_invalid_argument("map_space_dimensions(pfunc)",
00165 " pfunc is inconsistent");
00166 if (k == j)
00167
00168 goto skip;
00169
00170 cycles.push_back(j+1);
00171
00172 j = k;
00173 } while (!visited[j]);
00174
00175 cycles.push_back(0);
00176 skip:
00177 ;
00178 }
00179 }
00180
00181
00182 if (cycles.empty())
00183 return;
00184
00185
00186 if (congruences_are_up_to_date()) {
00187 con_sys.permute_columns(cycles);
00188 clear_congruences_minimized();
00189 }
00190
00191 if (generators_are_up_to_date()) {
00192 gen_sys.permute_columns(cycles);
00193 clear_generators_minimized();
00194 }
00195
00196 PPL_ASSERT(OK());
00197 return;
00198 }
00199
00200
00201
00202
00203 const Grid_Generator_System& old_gensys = grid_generators();
00204
00205 if (old_gensys.has_no_rows()) {
00206
00207 Grid new_grid(new_space_dimension, EMPTY);
00208 std::swap(*this, new_grid);
00209 PPL_ASSERT(OK());
00210 return;
00211 }
00212
00213
00214 std::vector<dimension_type> pfunc_maps(space_dim, not_a_dimension());
00215 for (dimension_type j = space_dim; j-- > 0; ) {
00216 dimension_type pfunc_j;
00217 if (pfunc.maps(j, pfunc_j))
00218 pfunc_maps[j] = pfunc_j;
00219 }
00220
00221 Grid_Generator_System new_gensys;
00222
00223 new_gensys.set_sorted(false);
00224
00225 Grid_Generator_System::const_iterator i;
00226 Grid_Generator_System::const_iterator old_gensys_end = old_gensys.end();
00227 for (i = old_gensys.begin(); i != old_gensys_end; ++i)
00228 if (i->is_point())
00229 break;
00230 PPL_ASSERT(i != old_gensys_end);
00231 const Coefficient& system_divisor = i->divisor();
00232 for (i = old_gensys.begin(); i != old_gensys_end; ++i) {
00233 const Grid_Generator& old_g = *i;
00234 Linear_Expression e(0 * Variable(new_space_dimension-1));
00235 bool all_zeroes = true;
00236 for (dimension_type j = space_dim; j-- > 0; ) {
00237 if (old_g.coefficient(Variable(j)) != 0
00238 && pfunc_maps[j] != not_a_dimension()) {
00239 e += Variable(pfunc_maps[j]) * old_g.coefficient(Variable(j));
00240 all_zeroes = false;
00241 }
00242 }
00243 switch (old_g.type()) {
00244 case Grid_Generator::LINE:
00245 if (!all_zeroes)
00246 new_gensys.insert(grid_line(e));
00247 break;
00248 case Grid_Generator::PARAMETER:
00249 if (!all_zeroes)
00250 new_gensys.insert(parameter(e, system_divisor));
00251 break;
00252 case Grid_Generator::POINT:
00253 new_gensys.insert(grid_point(e, old_g.divisor()));
00254 break;
00255 default:
00256 PPL_ASSERT(0);
00257 }
00258 }
00259
00260 Grid new_grid(new_gensys);
00261 std::swap(*this, new_grid);
00262
00263 PPL_ASSERT(OK(true));
00264 }
00265
00266
00267
00268 template <typename M, typename R>
00269 void
00270 Grid::reduce_reduced(M& sys,
00271 const dimension_type dim,
00272 const dimension_type pivot_index,
00273 const dimension_type start,
00274 const dimension_type end,
00275 const Dimension_Kinds& dim_kinds,
00276 const bool generators) {
00277 R& pivot = sys[pivot_index];
00278
00279 const Coefficient& pivot_dim = pivot[dim];
00280
00281 if (pivot_dim == 0)
00282 return;
00283
00284 PPL_DIRTY_TEMP_COEFFICIENT(pivot_dim_half);
00285 pivot_dim_half = (pivot_dim + 1) / 2;
00286 Dimension_Kind row_kind = dim_kinds[dim];
00287 Dimension_Kind line_or_equality, virtual_kind;
00288 int jump;
00289 if (generators) {
00290 line_or_equality = LINE;
00291 virtual_kind = GEN_VIRTUAL;
00292 jump = -1;
00293 }
00294 else {
00295 line_or_equality = EQUALITY;
00296 virtual_kind = CON_VIRTUAL;
00297 jump = 1;
00298 }
00299
00300 PPL_DIRTY_TEMP_COEFFICIENT(num_rows_to_subtract);
00301 PPL_DIRTY_TEMP_COEFFICIENT(row_dim_remainder);
00302 for (dimension_type row_index = pivot_index, kinds_index = dim + jump;
00303 row_index-- > 0;
00304 kinds_index += jump) {
00305
00306 while (dim_kinds[kinds_index] == virtual_kind)
00307 kinds_index += jump;
00308
00309
00310 if (row_kind == line_or_equality
00311 || (row_kind == PARAMETER
00312 && dim_kinds[kinds_index] == PARAMETER)) {
00313 R& row = sys[row_index];
00314
00315 const Coefficient& row_dim = row[dim];
00316
00317 num_rows_to_subtract = row_dim / pivot_dim;
00318
00319
00320
00321
00322
00323 row_dim_remainder = row_dim % pivot_dim;
00324 if (row_dim_remainder < 0) {
00325 if (row_dim_remainder <= -pivot_dim_half)
00326 --num_rows_to_subtract;
00327 }
00328 else if (row_dim_remainder > 0 && row_dim_remainder > pivot_dim_half)
00329 ++num_rows_to_subtract;
00330
00331
00332
00333
00334
00335
00336 if (num_rows_to_subtract != 0)
00337 for (dimension_type col = start; col <= end; ++col)
00338 sub_mul_assign(row[col], num_rows_to_subtract, pivot[col]);
00339 }
00340 }
00341 }
00342
00343 }
00344
00345 #endif // !defined(PPL_Grid_templates_hh)