1 1.1 mrg /* 2 1.1 mrg * Copyright 2010 INRIA Saclay 3 1.1 mrg * 4 1.1 mrg * Use of this software is governed by the MIT license 5 1.1 mrg * 6 1.1 mrg * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, 7 1.1 mrg * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, 8 1.1 mrg * 91893 Orsay, France 9 1.1 mrg */ 10 1.1 mrg 11 1.1 mrg #include <isl_ctx_private.h> 12 1.1 mrg #include <isl_map_private.h> 13 1.1 mrg #include <isl_bound.h> 14 1.1 mrg #include <isl_bernstein.h> 15 1.1 mrg #include <isl_range.h> 16 1.1 mrg #include <isl_polynomial_private.h> 17 1.1 mrg #include <isl_options_private.h> 18 1.1 mrg 19 1.1 mrg /* Given a polynomial "poly" that is constant in terms 20 1.1 mrg * of the domain variables, construct a polynomial reduction 21 1.1 mrg * of type "type" that is equal to "poly" on "bset", 22 1.1 mrg * with the domain projected onto the parameters. 23 1.1 mrg */ 24 1.1 mrg __isl_give isl_pw_qpolynomial_fold *isl_qpolynomial_cst_bound( 25 1.1 mrg __isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *poly, 26 1.1 mrg enum isl_fold type, isl_bool *tight) 27 1.1 mrg { 28 1.1 mrg isl_set *dom; 29 1.1 mrg isl_qpolynomial_fold *fold; 30 1.1 mrg isl_pw_qpolynomial_fold *pwf; 31 1.1 mrg 32 1.1 mrg fold = isl_qpolynomial_fold_alloc(type, poly); 33 1.1 mrg dom = isl_set_from_basic_set(bset); 34 1.1 mrg if (tight) 35 1.1 mrg *tight = isl_bool_true; 36 1.1 mrg pwf = isl_pw_qpolynomial_fold_alloc(type, dom, fold); 37 1.1 mrg return isl_pw_qpolynomial_fold_project_domain_on_params(pwf); 38 1.1 mrg } 39 1.1 mrg 40 1.1 mrg /* Add the bound "pwf", which is not known to be tight, 41 1.1 mrg * to the output of "bound". 42 1.1 mrg */ 43 1.1 mrg isl_stat isl_bound_add(struct isl_bound *bound, 44 1.1 mrg __isl_take isl_pw_qpolynomial_fold *pwf) 45 1.1 mrg { 46 1.1 mrg bound->pwf = isl_pw_qpolynomial_fold_fold(bound->pwf, pwf); 47 1.1 mrg return isl_stat_non_null(bound->pwf); 48 1.1 mrg } 49 1.1 mrg 50 1.1 mrg /* Add the bound "pwf", which is known to be tight, 51 1.1 mrg * to the output of "bound". 52 1.1 mrg */ 53 1.1 mrg isl_stat isl_bound_add_tight(struct isl_bound *bound, 54 1.1 mrg __isl_take isl_pw_qpolynomial_fold *pwf) 55 1.1 mrg { 56 1.1 mrg bound->pwf_tight = isl_pw_qpolynomial_fold_fold(bound->pwf_tight, pwf); 57 1.1 mrg return isl_stat_non_null(bound->pwf); 58 1.1 mrg } 59 1.1 mrg 60 1.1 mrg /* Given a polynomial "poly" that is constant in terms 61 1.1 mrg * of the domain variables and the domain "bset", 62 1.1 mrg * construct the corresponding polynomial reduction and 63 1.1 mrg * add it to the tight bounds of "bound". 64 1.1 mrg */ 65 1.1 mrg static isl_stat add_constant_poly(__isl_take isl_basic_set *bset, 66 1.1 mrg __isl_take isl_qpolynomial *poly, struct isl_bound *bound) 67 1.1 mrg { 68 1.1 mrg isl_pw_qpolynomial_fold *pwf; 69 1.1 mrg 70 1.1 mrg pwf = isl_qpolynomial_cst_bound(bset, poly, bound->type, NULL); 71 1.1 mrg return isl_bound_add_tight(bound, pwf); 72 1.1 mrg } 73 1.1 mrg 74 1.1 mrg /* Compute a bound on the polynomial defined over the parametric polytope 75 1.1 mrg * using either range propagation or bernstein expansion and 76 1.1 mrg * store the result in bound->pwf and bound->pwf_tight. 77 1.1 mrg * Since bernstein expansion requires bounded domains, we apply 78 1.1 mrg * range propagation on unbounded domains. Otherwise, we respect the choice 79 1.1 mrg * of the user. 80 1.1 mrg * 81 1.1 mrg * If the polynomial does not depend on the set variables 82 1.1 mrg * then the bound is equal to the polynomial and 83 1.1 mrg * it can be added to "bound" directly. 84 1.1 mrg */ 85 1.1 mrg static isl_stat compressed_guarded_poly_bound(__isl_take isl_basic_set *bset, 86 1.1 mrg __isl_take isl_qpolynomial *poly, void *user) 87 1.1 mrg { 88 1.1 mrg struct isl_bound *bound = (struct isl_bound *)user; 89 1.1 mrg isl_ctx *ctx; 90 1.1 mrg int bounded; 91 1.1 mrg int degree; 92 1.1 mrg 93 1.1 mrg if (!bset || !poly) 94 1.1 mrg goto error; 95 1.1 mrg 96 1.1 mrg degree = isl_qpolynomial_degree(poly); 97 1.1 mrg if (degree < -1) 98 1.1 mrg goto error; 99 1.1 mrg if (degree <= 0) 100 1.1 mrg return add_constant_poly(bset, poly, bound); 101 1.1 mrg 102 1.1 mrg ctx = isl_basic_set_get_ctx(bset); 103 1.1 mrg if (ctx->opt->bound == ISL_BOUND_RANGE) 104 1.1 mrg return isl_qpolynomial_bound_on_domain_range(bset, poly, bound); 105 1.1 mrg 106 1.1 mrg bounded = isl_basic_set_is_bounded(bset); 107 1.1 mrg if (bounded < 0) 108 1.1 mrg goto error; 109 1.1 mrg if (bounded) 110 1.1 mrg return isl_qpolynomial_bound_on_domain_bernstein(bset, poly, bound); 111 1.1 mrg else 112 1.1 mrg return isl_qpolynomial_bound_on_domain_range(bset, poly, bound); 113 1.1 mrg error: 114 1.1 mrg isl_basic_set_free(bset); 115 1.1 mrg isl_qpolynomial_free(poly); 116 1.1 mrg return isl_stat_error; 117 1.1 mrg } 118 1.1 mrg 119 1.1 mrg static isl_stat unwrapped_guarded_poly_bound(__isl_take isl_basic_set *bset, 120 1.1 mrg __isl_take isl_qpolynomial *poly, void *user) 121 1.1 mrg { 122 1.1 mrg struct isl_bound *bound = (struct isl_bound *)user; 123 1.1 mrg isl_pw_qpolynomial_fold *top_pwf; 124 1.1 mrg isl_pw_qpolynomial_fold *top_pwf_tight; 125 1.1 mrg isl_space *space; 126 1.1 mrg isl_morph *morph; 127 1.1 mrg isl_stat r; 128 1.1 mrg 129 1.1 mrg bset = isl_basic_set_detect_equalities(bset); 130 1.1 mrg 131 1.1 mrg if (!bset) 132 1.1 mrg goto error; 133 1.1 mrg 134 1.1 mrg if (bset->n_eq == 0) 135 1.1 mrg return compressed_guarded_poly_bound(bset, poly, user); 136 1.1 mrg 137 1.1 mrg morph = isl_basic_set_full_compression(bset); 138 1.1 mrg 139 1.1 mrg bset = isl_morph_basic_set(isl_morph_copy(morph), bset); 140 1.1 mrg poly = isl_qpolynomial_morph_domain(poly, isl_morph_copy(morph)); 141 1.1 mrg 142 1.1 mrg space = isl_morph_get_ran_space(morph); 143 1.1 mrg space = isl_space_params(space); 144 1.1 mrg 145 1.1 mrg top_pwf = bound->pwf; 146 1.1 mrg top_pwf_tight = bound->pwf_tight; 147 1.1 mrg 148 1.1 mrg space = isl_space_from_domain(space); 149 1.1 mrg space = isl_space_add_dims(space, isl_dim_out, 1); 150 1.1 mrg bound->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(space), 151 1.1 mrg bound->type); 152 1.1 mrg bound->pwf_tight = isl_pw_qpolynomial_fold_zero(space, bound->type); 153 1.1 mrg 154 1.1 mrg r = compressed_guarded_poly_bound(bset, poly, user); 155 1.1 mrg 156 1.1 mrg morph = isl_morph_dom_params(morph); 157 1.1 mrg morph = isl_morph_ran_params(morph); 158 1.1 mrg morph = isl_morph_inverse(morph); 159 1.1 mrg 160 1.1 mrg bound->pwf = isl_pw_qpolynomial_fold_morph_domain(bound->pwf, 161 1.1 mrg isl_morph_copy(morph)); 162 1.1 mrg bound->pwf_tight = isl_pw_qpolynomial_fold_morph_domain( 163 1.1 mrg bound->pwf_tight, morph); 164 1.1 mrg 165 1.1 mrg isl_bound_add(bound, top_pwf); 166 1.1 mrg isl_bound_add_tight(bound, top_pwf_tight); 167 1.1 mrg 168 1.1 mrg return r; 169 1.1 mrg error: 170 1.1 mrg isl_basic_set_free(bset); 171 1.1 mrg isl_qpolynomial_free(poly); 172 1.1 mrg return isl_stat_error; 173 1.1 mrg } 174 1.1 mrg 175 1.1 mrg /* Update bound->pwf and bound->pwf_tight with a bound 176 1.1 mrg * of type bound->type on the polynomial "poly" over the domain "bset". 177 1.1 mrg * 178 1.1 mrg * If the original problem had a wrapped relation in the domain, 179 1.1 mrg * meaning that the bound should be computed over the range 180 1.1 mrg * of this relation, then temporarily treat the domain dimensions 181 1.1 mrg * of this wrapped relation as parameters, compute a bound 182 1.1 mrg * in terms of these and the original parameters, 183 1.1 mrg * turn the parameters back into set dimensions and 184 1.1 mrg * add the results to bound->pwf and bound->pwf_tight. 185 1.1 mrg * 186 1.1 mrg * Note that even though "bset" is known to live in the same space 187 1.1 mrg * as the domain of "poly", the names of the set dimensions 188 1.1 mrg * may be different (or missing). Make sure the naming is exactly 189 1.1 mrg * the same before turning these dimensions into parameters 190 1.1 mrg * to ensure that the spaces are still the same after 191 1.1 mrg * this operation. 192 1.1 mrg */ 193 1.1 mrg static isl_stat guarded_poly_bound(__isl_take isl_basic_set *bset, 194 1.1 mrg __isl_take isl_qpolynomial *poly, void *user) 195 1.1 mrg { 196 1.1 mrg struct isl_bound *bound = (struct isl_bound *)user; 197 1.1 mrg isl_space *space; 198 1.1 mrg isl_pw_qpolynomial_fold *top_pwf; 199 1.1 mrg isl_pw_qpolynomial_fold *top_pwf_tight; 200 1.1 mrg isl_size nparam; 201 1.1 mrg isl_size n_in; 202 1.1 mrg isl_stat r; 203 1.1 mrg 204 1.1 mrg if (!bound->wrapping) 205 1.1 mrg return unwrapped_guarded_poly_bound(bset, poly, user); 206 1.1 mrg 207 1.1 mrg nparam = isl_space_dim(bound->dim, isl_dim_param); 208 1.1 mrg n_in = isl_space_dim(bound->dim, isl_dim_in); 209 1.1 mrg if (nparam < 0 || n_in < 0) 210 1.1 mrg goto error; 211 1.1 mrg 212 1.1 mrg space = isl_qpolynomial_get_domain_space(poly); 213 1.1 mrg bset = isl_basic_set_reset_space(bset, space); 214 1.1 mrg 215 1.1 mrg bset = isl_basic_set_move_dims(bset, isl_dim_param, nparam, 216 1.1 mrg isl_dim_set, 0, n_in); 217 1.1 mrg poly = isl_qpolynomial_move_dims(poly, isl_dim_param, nparam, 218 1.1 mrg isl_dim_in, 0, n_in); 219 1.1 mrg 220 1.1 mrg space = isl_basic_set_get_space(bset); 221 1.1 mrg space = isl_space_params(space); 222 1.1 mrg 223 1.1 mrg top_pwf = bound->pwf; 224 1.1 mrg top_pwf_tight = bound->pwf_tight; 225 1.1 mrg 226 1.1 mrg space = isl_space_from_domain(space); 227 1.1 mrg space = isl_space_add_dims(space, isl_dim_out, 1); 228 1.1 mrg bound->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(space), 229 1.1 mrg bound->type); 230 1.1 mrg bound->pwf_tight = isl_pw_qpolynomial_fold_zero(space, bound->type); 231 1.1 mrg 232 1.1 mrg r = unwrapped_guarded_poly_bound(bset, poly, user); 233 1.1 mrg 234 1.1 mrg bound->pwf = isl_pw_qpolynomial_fold_reset_space(bound->pwf, 235 1.1 mrg isl_space_copy(bound->dim)); 236 1.1 mrg bound->pwf_tight = isl_pw_qpolynomial_fold_reset_space(bound->pwf_tight, 237 1.1 mrg isl_space_copy(bound->dim)); 238 1.1 mrg 239 1.1 mrg isl_bound_add(bound, top_pwf); 240 1.1 mrg isl_bound_add_tight(bound, top_pwf_tight); 241 1.1 mrg 242 1.1 mrg return r; 243 1.1 mrg error: 244 1.1 mrg isl_basic_set_free(bset); 245 1.1 mrg isl_qpolynomial_free(poly); 246 1.1 mrg return isl_stat_error; 247 1.1 mrg } 248 1.1 mrg 249 1.1 mrg static isl_stat guarded_qp(__isl_take isl_qpolynomial *qp, void *user) 250 1.1 mrg { 251 1.1 mrg struct isl_bound *bound = (struct isl_bound *)user; 252 1.1 mrg isl_stat r; 253 1.1 mrg 254 1.1 mrg r = isl_qpolynomial_as_polynomial_on_domain(qp, bound->bset, 255 1.1 mrg &guarded_poly_bound, user); 256 1.1 mrg isl_qpolynomial_free(qp); 257 1.1 mrg return r; 258 1.1 mrg } 259 1.1 mrg 260 1.1 mrg static isl_stat basic_guarded_fold(__isl_take isl_basic_set *bset, void *user) 261 1.1 mrg { 262 1.1 mrg struct isl_bound *bound = (struct isl_bound *)user; 263 1.1 mrg isl_stat r; 264 1.1 mrg 265 1.1 mrg bound->bset = bset; 266 1.1 mrg r = isl_qpolynomial_fold_foreach_qpolynomial(bound->fold, 267 1.1 mrg &guarded_qp, user); 268 1.1 mrg isl_basic_set_free(bset); 269 1.1 mrg return r; 270 1.1 mrg } 271 1.1 mrg 272 1.1 mrg static isl_stat guarded_fold(__isl_take isl_set *set, 273 1.1 mrg __isl_take isl_qpolynomial_fold *fold, void *user) 274 1.1 mrg { 275 1.1 mrg struct isl_bound *bound = (struct isl_bound *)user; 276 1.1 mrg 277 1.1 mrg if (!set || !fold) 278 1.1 mrg goto error; 279 1.1 mrg 280 1.1 mrg set = isl_set_make_disjoint(set); 281 1.1 mrg 282 1.1 mrg bound->fold = fold; 283 1.1 mrg bound->type = isl_qpolynomial_fold_get_type(fold); 284 1.1 mrg 285 1.1 mrg if (isl_set_foreach_basic_set(set, &basic_guarded_fold, bound) < 0) 286 1.1 mrg goto error; 287 1.1 mrg 288 1.1 mrg isl_set_free(set); 289 1.1 mrg isl_qpolynomial_fold_free(fold); 290 1.1 mrg 291 1.1 mrg return isl_stat_ok; 292 1.1 mrg error: 293 1.1 mrg isl_set_free(set); 294 1.1 mrg isl_qpolynomial_fold_free(fold); 295 1.1 mrg return isl_stat_error; 296 1.1 mrg } 297 1.1 mrg 298 1.1 mrg __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_bound( 299 1.1 mrg __isl_take isl_pw_qpolynomial_fold *pwf, isl_bool *tight) 300 1.1 mrg { 301 1.1 mrg isl_size nvar; 302 1.1 mrg struct isl_bound bound; 303 1.1 mrg isl_bool covers; 304 1.1 mrg 305 1.1 mrg if (!pwf) 306 1.1 mrg return NULL; 307 1.1 mrg 308 1.1 mrg bound.dim = isl_pw_qpolynomial_fold_get_domain_space(pwf); 309 1.1 mrg 310 1.1 mrg bound.wrapping = isl_space_is_wrapping(bound.dim); 311 1.1 mrg if (bound.wrapping) 312 1.1 mrg bound.dim = isl_space_unwrap(bound.dim); 313 1.1 mrg nvar = isl_space_dim(bound.dim, isl_dim_out); 314 1.1 mrg if (nvar < 0) 315 1.1 mrg bound.dim = isl_space_free(bound.dim); 316 1.1 mrg bound.dim = isl_space_domain(bound.dim); 317 1.1 mrg bound.dim = isl_space_from_domain(bound.dim); 318 1.1 mrg bound.dim = isl_space_add_dims(bound.dim, isl_dim_out, 1); 319 1.1 mrg 320 1.1 mrg if (nvar == 0) { 321 1.1 mrg if (tight) 322 1.1 mrg *tight = isl_bool_true; 323 1.1 mrg return isl_pw_qpolynomial_fold_reset_space(pwf, bound.dim); 324 1.1 mrg } 325 1.1 mrg 326 1.1 mrg if (isl_pw_qpolynomial_fold_is_zero(pwf)) { 327 1.1 mrg enum isl_fold type = pwf->type; 328 1.1 mrg isl_pw_qpolynomial_fold_free(pwf); 329 1.1 mrg if (tight) 330 1.1 mrg *tight = isl_bool_true; 331 1.1 mrg return isl_pw_qpolynomial_fold_zero(bound.dim, type); 332 1.1 mrg } 333 1.1 mrg 334 1.1 mrg bound.pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(bound.dim), 335 1.1 mrg pwf->type); 336 1.1 mrg bound.pwf_tight = isl_pw_qpolynomial_fold_zero(isl_space_copy(bound.dim), 337 1.1 mrg pwf->type); 338 1.1 mrg bound.check_tight = !!tight; 339 1.1 mrg 340 1.1 mrg if (isl_pw_qpolynomial_fold_foreach_lifted_piece(pwf, 341 1.1 mrg guarded_fold, &bound) < 0) 342 1.1 mrg goto error; 343 1.1 mrg 344 1.1 mrg covers = isl_pw_qpolynomial_fold_covers(bound.pwf_tight, bound.pwf); 345 1.1 mrg if (covers < 0) 346 1.1 mrg goto error; 347 1.1 mrg 348 1.1 mrg if (tight) 349 1.1 mrg *tight = covers; 350 1.1 mrg 351 1.1 mrg isl_space_free(bound.dim); 352 1.1 mrg isl_pw_qpolynomial_fold_free(pwf); 353 1.1 mrg 354 1.1 mrg if (covers) { 355 1.1 mrg isl_pw_qpolynomial_fold_free(bound.pwf); 356 1.1 mrg return bound.pwf_tight; 357 1.1 mrg } 358 1.1 mrg 359 1.1 mrg bound.pwf = isl_pw_qpolynomial_fold_fold(bound.pwf, bound.pwf_tight); 360 1.1 mrg 361 1.1 mrg return bound.pwf; 362 1.1 mrg error: 363 1.1 mrg isl_pw_qpolynomial_fold_free(bound.pwf_tight); 364 1.1 mrg isl_pw_qpolynomial_fold_free(bound.pwf); 365 1.1 mrg isl_pw_qpolynomial_fold_free(pwf); 366 1.1 mrg isl_space_free(bound.dim); 367 1.1 mrg return NULL; 368 1.1 mrg } 369 1.1 mrg 370 1.1 mrg __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_bound( 371 1.1 mrg __isl_take isl_pw_qpolynomial *pwqp, enum isl_fold type, 372 1.1 mrg isl_bool *tight) 373 1.1 mrg { 374 1.1 mrg isl_pw_qpolynomial_fold *pwf; 375 1.1 mrg 376 1.1 mrg pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(type, pwqp); 377 1.1 mrg return isl_pw_qpolynomial_fold_bound(pwf, tight); 378 1.1 mrg } 379 1.1 mrg 380 1.1 mrg struct isl_union_bound_data { 381 1.1 mrg enum isl_fold type; 382 1.1 mrg isl_bool tight; 383 1.1 mrg isl_union_pw_qpolynomial_fold *res; 384 1.1 mrg }; 385 1.1 mrg 386 1.1 mrg static isl_stat bound_pw(__isl_take isl_pw_qpolynomial *pwqp, void *user) 387 1.1 mrg { 388 1.1 mrg struct isl_union_bound_data *data = user; 389 1.1 mrg isl_pw_qpolynomial_fold *pwf; 390 1.1 mrg 391 1.1 mrg pwf = isl_pw_qpolynomial_bound(pwqp, data->type, 392 1.1 mrg data->tight ? &data->tight : NULL); 393 1.1 mrg data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold( 394 1.1 mrg data->res, pwf); 395 1.1 mrg 396 1.1 mrg return isl_stat_ok; 397 1.1 mrg } 398 1.1 mrg 399 1.1 mrg __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_bound( 400 1.1 mrg __isl_take isl_union_pw_qpolynomial *upwqp, 401 1.1 mrg enum isl_fold type, isl_bool *tight) 402 1.1 mrg { 403 1.1 mrg isl_space *space; 404 1.1 mrg struct isl_union_bound_data data = { type, 1, NULL }; 405 1.1 mrg 406 1.1 mrg if (!upwqp) 407 1.1 mrg return NULL; 408 1.1 mrg 409 1.1 mrg if (!tight) 410 1.1 mrg data.tight = isl_bool_false; 411 1.1 mrg 412 1.1 mrg space = isl_union_pw_qpolynomial_get_space(upwqp); 413 1.1 mrg data.res = isl_union_pw_qpolynomial_fold_zero(space, type); 414 1.1 mrg if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, 415 1.1 mrg &bound_pw, &data) < 0) 416 1.1 mrg goto error; 417 1.1 mrg 418 1.1 mrg isl_union_pw_qpolynomial_free(upwqp); 419 1.1 mrg if (tight) 420 1.1 mrg *tight = data.tight; 421 1.1 mrg 422 1.1 mrg return data.res; 423 1.1 mrg error: 424 1.1 mrg isl_union_pw_qpolynomial_free(upwqp); 425 1.1 mrg isl_union_pw_qpolynomial_fold_free(data.res); 426 1.1 mrg return NULL; 427 1.1 mrg } 428