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_map_private.h> 12 1.1 mrg #include <isl_union_map_private.h> 13 1.1 mrg #include <isl_polynomial_private.h> 14 1.1 mrg #include <isl_point_private.h> 15 1.1 mrg #include <isl_space_private.h> 16 1.1 mrg #include <isl_lp_private.h> 17 1.1 mrg #include <isl_seq.h> 18 1.1 mrg #include <isl_mat_private.h> 19 1.1 mrg #include <isl_val_private.h> 20 1.1 mrg #include <isl_vec_private.h> 21 1.1 mrg #include <isl_config.h> 22 1.1 mrg 23 1.1 mrg #undef EL_BASE 24 1.1 mrg #define EL_BASE pw_qpolynomial_fold 25 1.1 mrg 26 1.1 mrg #include <isl_list_templ.c> 27 1.1 mrg 28 1.1 mrg enum isl_fold isl_fold_type_negate(enum isl_fold type) 29 1.1 mrg { 30 1.1 mrg switch (type) { 31 1.1 mrg case isl_fold_error: 32 1.1 mrg return isl_fold_error; 33 1.1 mrg case isl_fold_min: 34 1.1 mrg return isl_fold_max; 35 1.1 mrg case isl_fold_max: 36 1.1 mrg return isl_fold_min; 37 1.1 mrg case isl_fold_list: 38 1.1 mrg return isl_fold_list; 39 1.1 mrg } 40 1.1 mrg 41 1.1 mrg isl_die(NULL, isl_error_internal, "unhandled isl_fold type", abort()); 42 1.1 mrg } 43 1.1 mrg 44 1.1 mrg /* Construct a new reduction with the given type, domain space and 45 1.1 mrg * list of polynomials. 46 1.1 mrg */ 47 1.1 mrg static __isl_give isl_qpolynomial_fold *qpolynomial_fold_alloc( 48 1.1 mrg enum isl_fold type, __isl_take isl_space *space, 49 1.1 mrg __isl_take isl_qpolynomial_list *list) 50 1.1 mrg { 51 1.1 mrg isl_ctx *ctx; 52 1.1 mrg isl_qpolynomial_fold *fold; 53 1.1 mrg 54 1.1 mrg if (type < 0 || !space || !list) 55 1.1 mrg goto error; 56 1.1 mrg 57 1.1 mrg ctx = isl_space_get_ctx(space); 58 1.1 mrg fold = isl_calloc_type(ctx, struct isl_qpolynomial_fold); 59 1.1 mrg if (!fold) 60 1.1 mrg goto error; 61 1.1 mrg 62 1.1 mrg fold->ref = 1; 63 1.1 mrg fold->type = type; 64 1.1 mrg fold->dim = space; 65 1.1 mrg fold->list = list; 66 1.1 mrg 67 1.1 mrg return fold; 68 1.1 mrg error: 69 1.1 mrg isl_space_free(space); 70 1.1 mrg isl_qpolynomial_list_free(list); 71 1.1 mrg return NULL; 72 1.1 mrg } 73 1.1 mrg 74 1.1 mrg isl_ctx *isl_qpolynomial_fold_get_ctx(__isl_keep isl_qpolynomial_fold *fold) 75 1.1 mrg { 76 1.1 mrg return fold ? fold->dim->ctx : NULL; 77 1.1 mrg } 78 1.1 mrg 79 1.1 mrg /* Return the domain space of "fold". 80 1.1 mrg */ 81 1.1 mrg static __isl_keep isl_space *isl_qpolynomial_fold_peek_domain_space( 82 1.1 mrg __isl_keep isl_qpolynomial_fold *fold) 83 1.1 mrg { 84 1.1 mrg return fold ? fold->dim : NULL; 85 1.1 mrg } 86 1.1 mrg 87 1.1 mrg __isl_give isl_space *isl_qpolynomial_fold_get_domain_space( 88 1.1 mrg __isl_keep isl_qpolynomial_fold *fold) 89 1.1 mrg { 90 1.1 mrg return isl_space_copy(isl_qpolynomial_fold_peek_domain_space(fold)); 91 1.1 mrg } 92 1.1 mrg 93 1.1 mrg /* Return the space of the domain of "fold". 94 1.1 mrg * This may be either a copy or the space itself 95 1.1 mrg * if there is only one reference to "fold". 96 1.1 mrg * This allows the space to be modified inplace 97 1.1 mrg * if both the expression and its space have only a single reference. 98 1.1 mrg * The caller is not allowed to modify "fold" between this call and 99 1.1 mrg * a subsequent call to isl_qpolynomial_fold_restore_domain_space. 100 1.1 mrg * The only exception is that isl_qpolynomial_fold_free can be called instead. 101 1.1 mrg */ 102 1.1 mrg static __isl_give isl_space *isl_qpolynomial_fold_take_domain_space( 103 1.1 mrg __isl_keep isl_qpolynomial_fold *fold) 104 1.1 mrg { 105 1.1 mrg isl_space *space; 106 1.1 mrg 107 1.1 mrg if (!fold) 108 1.1 mrg return NULL; 109 1.1 mrg if (fold->ref != 1) 110 1.1 mrg return isl_qpolynomial_fold_get_domain_space(fold); 111 1.1 mrg space = fold->dim; 112 1.1 mrg fold->dim = NULL; 113 1.1 mrg return space; 114 1.1 mrg } 115 1.1 mrg 116 1.1 mrg /* Set the space of the domain of "fold" to "space", 117 1.1 mrg * where the space of "fold" may be missing 118 1.1 mrg * due to a preceding call to isl_qpolynomial_fold_take_domain_space. 119 1.1 mrg * However, in this case, "fold" only has a single reference and 120 1.1 mrg * then the call to isl_qpolynomial_fold_cow has no effect. 121 1.1 mrg */ 122 1.1 mrg static 123 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_restore_domain_space( 124 1.1 mrg __isl_keep isl_qpolynomial_fold *fold, __isl_take isl_space *space) 125 1.1 mrg { 126 1.1 mrg if (!fold || !space) 127 1.1 mrg goto error; 128 1.1 mrg 129 1.1 mrg if (fold->dim == space) { 130 1.1 mrg isl_space_free(space); 131 1.1 mrg return fold; 132 1.1 mrg } 133 1.1 mrg 134 1.1 mrg fold = isl_qpolynomial_fold_cow(fold); 135 1.1 mrg if (!fold) 136 1.1 mrg goto error; 137 1.1 mrg isl_space_free(fold->dim); 138 1.1 mrg fold->dim = space; 139 1.1 mrg 140 1.1 mrg return fold; 141 1.1 mrg error: 142 1.1 mrg isl_qpolynomial_fold_free(fold); 143 1.1 mrg isl_space_free(space); 144 1.1 mrg return NULL; 145 1.1 mrg } 146 1.1 mrg 147 1.1 mrg __isl_give isl_space *isl_qpolynomial_fold_get_space( 148 1.1 mrg __isl_keep isl_qpolynomial_fold *fold) 149 1.1 mrg { 150 1.1 mrg isl_space *space; 151 1.1 mrg if (!fold) 152 1.1 mrg return NULL; 153 1.1 mrg space = isl_space_copy(fold->dim); 154 1.1 mrg space = isl_space_from_domain(space); 155 1.1 mrg space = isl_space_add_dims(space, isl_dim_out, 1); 156 1.1 mrg return space; 157 1.1 mrg } 158 1.1 mrg 159 1.1 mrg /* Return the list of polynomials in the reduction "fold". 160 1.1 mrg */ 161 1.1 mrg __isl_keep isl_qpolynomial_list *isl_qpolynomial_fold_peek_list( 162 1.1 mrg __isl_keep isl_qpolynomial_fold *fold) 163 1.1 mrg { 164 1.1 mrg return fold ? fold->list : NULL; 165 1.1 mrg } 166 1.1 mrg 167 1.1 mrg /* Return a copy of the list of polynomials in the reduction "fold". 168 1.1 mrg */ 169 1.1 mrg static __isl_give isl_qpolynomial_list *isl_qpolynomial_fold_get_list( 170 1.1 mrg __isl_keep isl_qpolynomial_fold *fold) 171 1.1 mrg { 172 1.1 mrg return isl_qpolynomial_list_copy(isl_qpolynomial_fold_peek_list(fold)); 173 1.1 mrg } 174 1.1 mrg 175 1.1 mrg /* Return the list of polynomials of "fold". 176 1.1 mrg * This may be either a copy or the list itself 177 1.1 mrg * if there is only one reference to "fold". 178 1.1 mrg * This allows the list to be modified inplace 179 1.1 mrg * if both the expression and its list have only a single reference. 180 1.1 mrg * The caller is not allowed to modify "fold" between this call and 181 1.1 mrg * a subsequent call to isl_qpolynomial_fold_restore_list. 182 1.1 mrg * The only exception is that isl_qpolynomial_fold_free can be called instead. 183 1.1 mrg */ 184 1.1 mrg static __isl_give isl_qpolynomial_list *isl_qpolynomial_fold_take_list( 185 1.1 mrg __isl_keep isl_qpolynomial_fold *fold) 186 1.1 mrg { 187 1.1 mrg isl_qpolynomial_list *list; 188 1.1 mrg 189 1.1 mrg if (!fold) 190 1.1 mrg return NULL; 191 1.1 mrg if (fold->ref != 1) 192 1.1 mrg return isl_qpolynomial_fold_get_list(fold); 193 1.1 mrg list = fold->list; 194 1.1 mrg fold->list = NULL; 195 1.1 mrg return list; 196 1.1 mrg } 197 1.1 mrg 198 1.1 mrg /* Set the space of the list of polynomials of "fold" to "space", 199 1.1 mrg * where the list of polynomials of "fold" may be missing 200 1.1 mrg * due to a preceding call to isl_qpolynomial_fold_take_list. 201 1.1 mrg * However, in this case, "fold" only has a single reference and 202 1.1 mrg * then the call to isl_qpolynomial_fold_cow has no effect. 203 1.1 mrg */ 204 1.1 mrg static __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_restore_list( 205 1.1 mrg __isl_keep isl_qpolynomial_fold *fold, 206 1.1 mrg __isl_take isl_qpolynomial_list *list) 207 1.1 mrg { 208 1.1 mrg if (!fold || !list) 209 1.1 mrg goto error; 210 1.1 mrg 211 1.1 mrg if (fold->list == list) { 212 1.1 mrg isl_qpolynomial_list_free(list); 213 1.1 mrg return fold; 214 1.1 mrg } 215 1.1 mrg 216 1.1 mrg fold = isl_qpolynomial_fold_cow(fold); 217 1.1 mrg if (!fold) 218 1.1 mrg goto error; 219 1.1 mrg isl_qpolynomial_list_free(fold->list); 220 1.1 mrg fold->list = list; 221 1.1 mrg 222 1.1 mrg return fold; 223 1.1 mrg error: 224 1.1 mrg isl_qpolynomial_fold_free(fold); 225 1.1 mrg isl_qpolynomial_list_free(list); 226 1.1 mrg return NULL; 227 1.1 mrg } 228 1.1 mrg 229 1.1 mrg /* isl_qpolynomial_list_map callback that calls 230 1.1 mrg * isl_qpolynomial_reset_domain_space on "qp". 231 1.1 mrg */ 232 1.1 mrg static __isl_give isl_qpolynomial *reset_domain_space( 233 1.1 mrg __isl_take isl_qpolynomial *qp, void *user) 234 1.1 mrg { 235 1.1 mrg isl_space *space = user; 236 1.1 mrg 237 1.1 mrg return isl_qpolynomial_reset_domain_space(qp, isl_space_copy(space)); 238 1.1 mrg } 239 1.1 mrg 240 1.1 mrg /* Replace the domain space of "fold" by "space". 241 1.1 mrg * 242 1.1 mrg * Replace the domain space itself and that of all polynomials 243 1.1 mrg * in the list. 244 1.1 mrg */ 245 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space( 246 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space) 247 1.1 mrg { 248 1.1 mrg isl_qpolynomial_list *list; 249 1.1 mrg 250 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 251 1.1 mrg list = isl_qpolynomial_list_map(list, &reset_domain_space, space); 252 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 253 1.1 mrg 254 1.1 mrg isl_space_free(isl_qpolynomial_fold_take_domain_space(fold)); 255 1.1 mrg fold = isl_qpolynomial_fold_restore_domain_space(fold, space); 256 1.1 mrg 257 1.1 mrg return fold; 258 1.1 mrg } 259 1.1 mrg 260 1.1 mrg /* Reset the space of "fold". This function is called from isl_pw_templ.c 261 1.1 mrg * and doesn't know if the space of an element object is represented 262 1.1 mrg * directly or through its domain. It therefore passes along both. 263 1.1 mrg */ 264 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_space_and_domain( 265 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space, 266 1.1 mrg __isl_take isl_space *domain) 267 1.1 mrg { 268 1.1 mrg isl_space_free(space); 269 1.1 mrg return isl_qpolynomial_fold_reset_domain_space(fold, domain); 270 1.1 mrg } 271 1.1 mrg 272 1.1 mrg /* Internal data structure for isl_qpolynomial_fold_*_dims 273 1.1 mrg * representing their arguments. 274 1.1 mrg */ 275 1.1 mrg struct isl_fold_dims_data { 276 1.1 mrg enum isl_dim_type type; 277 1.1 mrg unsigned first; 278 1.1 mrg unsigned n; 279 1.1 mrg }; 280 1.1 mrg 281 1.1 mrg /* isl_qpolynomial_list_every callback that checks whether "qp" 282 1.1 mrg * does not involve any dimensions in the given range. 283 1.1 mrg */ 284 1.1 mrg static isl_bool not_involved(__isl_keep isl_qpolynomial *qp, void *user) 285 1.1 mrg { 286 1.1 mrg struct isl_fold_dims_data *data = user; 287 1.1 mrg isl_bool involves; 288 1.1 mrg 289 1.1 mrg involves = isl_qpolynomial_involves_dims(qp, data->type, 290 1.1 mrg data->first, data->n); 291 1.1 mrg return isl_bool_not(involves); 292 1.1 mrg } 293 1.1 mrg 294 1.1 mrg /* Does "fold" involve any dimensions in the given range. 295 1.1 mrg * 296 1.1 mrg * It involves any of those dimensions if it is not the case 297 1.1 mrg * that every polynomial in the reduction does not involve 298 1.1 mrg * any of the dimensions. 299 1.1 mrg */ 300 1.1 mrg static isl_bool isl_qpolynomial_fold_involves_dims( 301 1.1 mrg __isl_keep isl_qpolynomial_fold *fold, 302 1.1 mrg enum isl_dim_type type, unsigned first, unsigned n) 303 1.1 mrg { 304 1.1 mrg struct isl_fold_dims_data data = { type, first, n }; 305 1.1 mrg isl_qpolynomial_list *list; 306 1.1 mrg isl_bool not; 307 1.1 mrg 308 1.1 mrg if (!fold) 309 1.1 mrg return isl_bool_error; 310 1.1 mrg if (n == 0) 311 1.1 mrg return isl_bool_false; 312 1.1 mrg 313 1.1 mrg list = isl_qpolynomial_fold_peek_list(fold); 314 1.1 mrg not = isl_qpolynomial_list_every(list, ¬_involved, &data); 315 1.1 mrg return isl_bool_not(not); 316 1.1 mrg } 317 1.1 mrg 318 1.1 mrg /* Internal data structure for isl_qpolynomial_fold_set_dim_name 319 1.1 mrg * representing its arguments. 320 1.1 mrg */ 321 1.1 mrg struct isl_fold_set_dim_name_data { 322 1.1 mrg enum isl_dim_type type; 323 1.1 mrg unsigned pos; 324 1.1 mrg const char *s; 325 1.1 mrg }; 326 1.1 mrg 327 1.1 mrg /* isl_qpolynomial_list_map callback for calling 328 1.1 mrg * isl_qpolynomial_set_dim_name on "qp". 329 1.1 mrg */ 330 1.1 mrg static __isl_give isl_qpolynomial *set_dim_name(__isl_take isl_qpolynomial *qp, 331 1.1 mrg void *user) 332 1.1 mrg { 333 1.1 mrg struct isl_fold_set_dim_name_data *data = user; 334 1.1 mrg 335 1.1 mrg qp = isl_qpolynomial_set_dim_name(qp, data->type, data->pos, data->s); 336 1.1 mrg return qp; 337 1.1 mrg } 338 1.1 mrg 339 1.1 mrg /* Given a dimension type for an isl_qpolynomial_fold, 340 1.1 mrg * return the corresponding type for the domain. 341 1.1 mrg */ 342 1.1 mrg static enum isl_dim_type domain_type(enum isl_dim_type type) 343 1.1 mrg { 344 1.1 mrg if (type == isl_dim_in) 345 1.1 mrg return isl_dim_set; 346 1.1 mrg return type; 347 1.1 mrg } 348 1.1 mrg 349 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_set_dim_name( 350 1.1 mrg __isl_take isl_qpolynomial_fold *fold, 351 1.1 mrg enum isl_dim_type type, unsigned pos, const char *s) 352 1.1 mrg { 353 1.1 mrg struct isl_fold_set_dim_name_data data = { type, pos, s }; 354 1.1 mrg enum isl_dim_type set_type; 355 1.1 mrg isl_space *space; 356 1.1 mrg isl_qpolynomial_list *list; 357 1.1 mrg 358 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 359 1.1 mrg list = isl_qpolynomial_list_map(list, &set_dim_name, &data); 360 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 361 1.1 mrg 362 1.1 mrg set_type = domain_type(type); 363 1.1 mrg space = isl_qpolynomial_fold_take_domain_space(fold); 364 1.1 mrg space = isl_space_set_dim_name(space, set_type, pos, s); 365 1.1 mrg fold = isl_qpolynomial_fold_restore_domain_space(fold, space); 366 1.1 mrg 367 1.1 mrg return fold; 368 1.1 mrg } 369 1.1 mrg 370 1.1 mrg /* isl_qpolynomial_list_map callback for calling 371 1.1 mrg * isl_qpolynomial_drop_dims on "qp". 372 1.1 mrg */ 373 1.1 mrg static __isl_give isl_qpolynomial *drop_dims(__isl_take isl_qpolynomial *qp, 374 1.1 mrg void *user) 375 1.1 mrg { 376 1.1 mrg struct isl_fold_dims_data *data = user; 377 1.1 mrg 378 1.1 mrg qp = isl_qpolynomial_drop_dims(qp, data->type, data->first, data->n); 379 1.1 mrg return qp; 380 1.1 mrg } 381 1.1 mrg 382 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_drop_dims( 383 1.1 mrg __isl_take isl_qpolynomial_fold *fold, 384 1.1 mrg enum isl_dim_type type, unsigned first, unsigned n) 385 1.1 mrg { 386 1.1 mrg struct isl_fold_dims_data data = { type, first, n }; 387 1.1 mrg enum isl_dim_type set_type; 388 1.1 mrg isl_space *space; 389 1.1 mrg isl_qpolynomial_list *list; 390 1.1 mrg 391 1.1 mrg if (!fold) 392 1.1 mrg return NULL; 393 1.1 mrg if (n == 0) 394 1.1 mrg return fold; 395 1.1 mrg 396 1.1 mrg set_type = domain_type(type); 397 1.1 mrg 398 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 399 1.1 mrg list = isl_qpolynomial_list_map(list, &drop_dims, &data); 400 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 401 1.1 mrg 402 1.1 mrg space = isl_qpolynomial_fold_take_domain_space(fold); 403 1.1 mrg space = isl_space_drop_dims(space, set_type, first, n); 404 1.1 mrg fold = isl_qpolynomial_fold_restore_domain_space(fold, space); 405 1.1 mrg 406 1.1 mrg return fold; 407 1.1 mrg } 408 1.1 mrg 409 1.1 mrg /* isl_qpolynomial_list_map callback for calling 410 1.1 mrg * isl_qpolynomial_insert_dims on "qp". 411 1.1 mrg */ 412 1.1 mrg static __isl_give isl_qpolynomial *insert_dims(__isl_take isl_qpolynomial *qp, 413 1.1 mrg void *user) 414 1.1 mrg { 415 1.1 mrg struct isl_fold_dims_data *data = user; 416 1.1 mrg 417 1.1 mrg qp = isl_qpolynomial_insert_dims(qp, data->type, data->first, data->n); 418 1.1 mrg return qp; 419 1.1 mrg } 420 1.1 mrg 421 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_insert_dims( 422 1.1 mrg __isl_take isl_qpolynomial_fold *fold, 423 1.1 mrg enum isl_dim_type type, unsigned first, unsigned n) 424 1.1 mrg { 425 1.1 mrg struct isl_fold_dims_data data = { type, first, n }; 426 1.1 mrg enum isl_dim_type set_type; 427 1.1 mrg isl_space *space; 428 1.1 mrg isl_qpolynomial_list *list; 429 1.1 mrg 430 1.1 mrg if (!fold) 431 1.1 mrg return NULL; 432 1.1 mrg if (n == 0 && !isl_space_is_named_or_nested(fold->dim, type)) 433 1.1 mrg return fold; 434 1.1 mrg 435 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 436 1.1 mrg list = isl_qpolynomial_list_map(list, &insert_dims, &data); 437 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 438 1.1 mrg 439 1.1 mrg set_type = domain_type(type); 440 1.1 mrg space = isl_qpolynomial_fold_take_domain_space(fold); 441 1.1 mrg space = isl_space_insert_dims(space, set_type, first, n); 442 1.1 mrg fold = isl_qpolynomial_fold_restore_domain_space(fold, space); 443 1.1 mrg 444 1.1 mrg return fold; 445 1.1 mrg } 446 1.1 mrg 447 1.1 mrg /* Determine the sign of the constant quasipolynomial "qp". 448 1.1 mrg * 449 1.1 mrg * Return 450 1.1 mrg * -1 if qp <= 0 451 1.1 mrg * 1 if qp >= 0 452 1.1 mrg * 0 if unknown 453 1.1 mrg * 454 1.1 mrg * For qp == 0, we can return either -1 or 1. In practice, we return 1. 455 1.1 mrg * For qp == NaN, the sign is undefined, so we return 0. 456 1.1 mrg */ 457 1.1 mrg static int isl_qpolynomial_cst_sign(__isl_keep isl_qpolynomial *qp) 458 1.1 mrg { 459 1.1 mrg isl_poly_cst *cst; 460 1.1 mrg 461 1.1 mrg if (isl_qpolynomial_is_nan(qp)) 462 1.1 mrg return 0; 463 1.1 mrg 464 1.1 mrg cst = isl_poly_as_cst(qp->poly); 465 1.1 mrg if (!cst) 466 1.1 mrg return 0; 467 1.1 mrg 468 1.1 mrg return isl_int_sgn(cst->n) < 0 ? -1 : 1; 469 1.1 mrg } 470 1.1 mrg 471 1.1 mrg static int isl_qpolynomial_aff_sign(__isl_keep isl_set *set, 472 1.1 mrg __isl_keep isl_qpolynomial *qp) 473 1.1 mrg { 474 1.1 mrg enum isl_lp_result res; 475 1.1 mrg isl_vec *aff; 476 1.1 mrg isl_int opt; 477 1.1 mrg int sgn = 0; 478 1.1 mrg 479 1.1 mrg aff = isl_qpolynomial_extract_affine(qp); 480 1.1 mrg if (!aff) 481 1.1 mrg return 0; 482 1.1 mrg 483 1.1 mrg isl_int_init(opt); 484 1.1 mrg 485 1.1 mrg res = isl_set_solve_lp(set, 0, aff->el + 1, aff->el[0], 486 1.1 mrg &opt, NULL, NULL); 487 1.1 mrg if (res == isl_lp_error) 488 1.1 mrg goto done; 489 1.1 mrg if (res == isl_lp_empty || 490 1.1 mrg (res == isl_lp_ok && !isl_int_is_neg(opt))) { 491 1.1 mrg sgn = 1; 492 1.1 mrg goto done; 493 1.1 mrg } 494 1.1 mrg 495 1.1 mrg res = isl_set_solve_lp(set, 1, aff->el + 1, aff->el[0], 496 1.1 mrg &opt, NULL, NULL); 497 1.1 mrg if (res == isl_lp_ok && !isl_int_is_pos(opt)) 498 1.1 mrg sgn = -1; 499 1.1 mrg 500 1.1 mrg done: 501 1.1 mrg isl_int_clear(opt); 502 1.1 mrg isl_vec_free(aff); 503 1.1 mrg return sgn; 504 1.1 mrg } 505 1.1 mrg 506 1.1 mrg /* Determine, if possible, the sign of the quasipolynomial "qp" on 507 1.1 mrg * the domain "set". 508 1.1 mrg * 509 1.1 mrg * If qp is a constant, then the problem is trivial. 510 1.1 mrg * If qp is linear, then we check if the minimum of the corresponding 511 1.1 mrg * affine constraint is non-negative or if the maximum is non-positive. 512 1.1 mrg * 513 1.1 mrg * Otherwise, we check if the outermost variable "v" has a lower bound "l" 514 1.1 mrg * in "set". If so, we write qp(v,v') as 515 1.1 mrg * 516 1.1 mrg * q(v,v') * (v - l) + r(v') 517 1.1 mrg * 518 1.1 mrg * if q(v,v') and r(v') have the same known sign, then the original 519 1.1 mrg * quasipolynomial has the same sign as well. 520 1.1 mrg * 521 1.1 mrg * Return 522 1.1 mrg * -1 if qp <= 0 523 1.1 mrg * 1 if qp >= 0 524 1.1 mrg * 0 if unknown 525 1.1 mrg */ 526 1.1 mrg static int isl_qpolynomial_sign(__isl_keep isl_set *set, 527 1.1 mrg __isl_keep isl_qpolynomial *qp) 528 1.1 mrg { 529 1.1 mrg isl_size d; 530 1.1 mrg int i; 531 1.1 mrg isl_bool is; 532 1.1 mrg isl_poly_rec *rec; 533 1.1 mrg isl_vec *v; 534 1.1 mrg isl_int l; 535 1.1 mrg enum isl_lp_result res; 536 1.1 mrg int sgn = 0; 537 1.1 mrg 538 1.1 mrg is = isl_qpolynomial_is_cst(qp, NULL, NULL); 539 1.1 mrg if (is < 0) 540 1.1 mrg return 0; 541 1.1 mrg if (is) 542 1.1 mrg return isl_qpolynomial_cst_sign(qp); 543 1.1 mrg 544 1.1 mrg is = isl_qpolynomial_is_affine(qp); 545 1.1 mrg if (is < 0) 546 1.1 mrg return 0; 547 1.1 mrg if (is) 548 1.1 mrg return isl_qpolynomial_aff_sign(set, qp); 549 1.1 mrg 550 1.1 mrg if (qp->div->n_row > 0) 551 1.1 mrg return 0; 552 1.1 mrg 553 1.1 mrg rec = isl_poly_as_rec(qp->poly); 554 1.1 mrg if (!rec) 555 1.1 mrg return 0; 556 1.1 mrg 557 1.1 mrg d = isl_space_dim(qp->dim, isl_dim_all); 558 1.1 mrg if (d < 0) 559 1.1 mrg return 0; 560 1.1 mrg v = isl_vec_alloc(set->ctx, 2 + d); 561 1.1 mrg if (!v) 562 1.1 mrg return 0; 563 1.1 mrg 564 1.1 mrg isl_seq_clr(v->el + 1, 1 + d); 565 1.1 mrg isl_int_set_si(v->el[0], 1); 566 1.1 mrg isl_int_set_si(v->el[2 + qp->poly->var], 1); 567 1.1 mrg 568 1.1 mrg isl_int_init(l); 569 1.1 mrg 570 1.1 mrg res = isl_set_solve_lp(set, 0, v->el + 1, v->el[0], &l, NULL, NULL); 571 1.1 mrg if (res == isl_lp_ok) { 572 1.1 mrg isl_qpolynomial *min; 573 1.1 mrg isl_qpolynomial *base; 574 1.1 mrg isl_qpolynomial *r, *q; 575 1.1 mrg isl_qpolynomial *t; 576 1.1 mrg 577 1.1 mrg min = isl_qpolynomial_cst_on_domain(isl_space_copy(qp->dim), l); 578 1.1 mrg base = isl_qpolynomial_var_pow_on_domain(isl_space_copy(qp->dim), 579 1.1 mrg qp->poly->var, 1); 580 1.1 mrg 581 1.1 mrg r = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0, 582 1.1 mrg isl_poly_copy(rec->p[rec->n - 1])); 583 1.1 mrg q = isl_qpolynomial_copy(r); 584 1.1 mrg 585 1.1 mrg for (i = rec->n - 2; i >= 0; --i) { 586 1.1 mrg r = isl_qpolynomial_mul(r, isl_qpolynomial_copy(min)); 587 1.1 mrg t = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0, 588 1.1 mrg isl_poly_copy(rec->p[i])); 589 1.1 mrg r = isl_qpolynomial_add(r, t); 590 1.1 mrg if (i == 0) 591 1.1 mrg break; 592 1.1 mrg q = isl_qpolynomial_mul(q, isl_qpolynomial_copy(base)); 593 1.1 mrg q = isl_qpolynomial_add(q, isl_qpolynomial_copy(r)); 594 1.1 mrg } 595 1.1 mrg 596 1.1 mrg if (isl_qpolynomial_is_zero(q)) 597 1.1 mrg sgn = isl_qpolynomial_sign(set, r); 598 1.1 mrg else if (isl_qpolynomial_is_zero(r)) 599 1.1 mrg sgn = isl_qpolynomial_sign(set, q); 600 1.1 mrg else { 601 1.1 mrg int sgn_q, sgn_r; 602 1.1 mrg sgn_r = isl_qpolynomial_sign(set, r); 603 1.1 mrg sgn_q = isl_qpolynomial_sign(set, q); 604 1.1 mrg if (sgn_r == sgn_q) 605 1.1 mrg sgn = sgn_r; 606 1.1 mrg } 607 1.1 mrg 608 1.1 mrg isl_qpolynomial_free(min); 609 1.1 mrg isl_qpolynomial_free(base); 610 1.1 mrg isl_qpolynomial_free(q); 611 1.1 mrg isl_qpolynomial_free(r); 612 1.1 mrg } 613 1.1 mrg 614 1.1 mrg isl_int_clear(l); 615 1.1 mrg 616 1.1 mrg isl_vec_free(v); 617 1.1 mrg 618 1.1 mrg return sgn; 619 1.1 mrg } 620 1.1 mrg 621 1.1 mrg /* Check that "fold1" and "fold2" have the same type. 622 1.1 mrg */ 623 1.1 mrg static isl_stat isl_qpolynomial_fold_check_equal_type( 624 1.1 mrg __isl_keep isl_qpolynomial_fold *fold1, 625 1.1 mrg __isl_keep isl_qpolynomial_fold *fold2) 626 1.1 mrg { 627 1.1 mrg enum isl_fold type1, type2; 628 1.1 mrg 629 1.1 mrg type1 = isl_qpolynomial_fold_get_type(fold1); 630 1.1 mrg type2 = isl_qpolynomial_fold_get_type(fold2); 631 1.1 mrg if (type1 < 0 || type2 < 0) 632 1.1 mrg return isl_stat_error; 633 1.1 mrg if (type1 != type2) 634 1.1 mrg isl_die(isl_qpolynomial_fold_get_ctx(fold1), isl_error_invalid, 635 1.1 mrg "fold types don't match", return isl_stat_error); 636 1.1 mrg return isl_stat_ok; 637 1.1 mrg } 638 1.1 mrg 639 1.1 mrg /* Check that "fold1" and "fold2" have the same (domain) space. 640 1.1 mrg */ 641 1.1 mrg static isl_stat isl_qpolynomial_fold_check_equal_space( 642 1.1 mrg __isl_keep isl_qpolynomial_fold *fold1, 643 1.1 mrg __isl_keep isl_qpolynomial_fold *fold2) 644 1.1 mrg { 645 1.1 mrg isl_bool equal; 646 1.1 mrg isl_space *space1, *space2; 647 1.1 mrg 648 1.1 mrg space1 = isl_qpolynomial_fold_peek_domain_space(fold1); 649 1.1 mrg space2 = isl_qpolynomial_fold_peek_domain_space(fold2); 650 1.1 mrg equal = isl_space_is_equal(space1, space2); 651 1.1 mrg if (equal < 0) 652 1.1 mrg return isl_stat_error; 653 1.1 mrg if (!equal) 654 1.1 mrg isl_die(isl_qpolynomial_fold_get_ctx(fold1), isl_error_invalid, 655 1.1 mrg "spaces don't match", return isl_stat_error); 656 1.1 mrg return isl_stat_ok; 657 1.1 mrg } 658 1.1 mrg 659 1.1 mrg /* Combine "list1" and "list2" into a single list, eliminating 660 1.1 mrg * those elements of one list that are already covered by the other 661 1.1 mrg * list on "set". 662 1.1 mrg * 663 1.1 mrg * "better" is the sign that the difference qp1 - qp2 needs to have for qp1 664 1.1 mrg * to be covered by qp2. 665 1.1 mrg */ 666 1.1 mrg static __isl_give isl_qpolynomial_list *merge_lists(__isl_keep isl_set *set, 667 1.1 mrg __isl_take isl_qpolynomial_list *list1, 668 1.1 mrg __isl_take isl_qpolynomial_list *list2, int better) 669 1.1 mrg { 670 1.1 mrg int i, j; 671 1.1 mrg isl_size n1, n2; 672 1.1 mrg 673 1.1 mrg n1 = isl_qpolynomial_list_size(list1); 674 1.1 mrg n2 = isl_qpolynomial_list_size(list2); 675 1.1 mrg if (n1 < 0 || n2 < 0) 676 1.1 mrg goto error; 677 1.1 mrg 678 1.1 mrg for (i = n2 - 1; i >= 0; --i) { 679 1.1 mrg for (j = n1 - 1; j >= 0; --j) { 680 1.1 mrg isl_qpolynomial *qp1, *qp2, *d; 681 1.1 mrg int sgn; 682 1.1 mrg isl_bool equal; 683 1.1 mrg 684 1.1 mrg qp1 = isl_qpolynomial_list_peek(list1, j); 685 1.1 mrg qp2 = isl_qpolynomial_list_peek(list2, i); 686 1.1 mrg equal = isl_qpolynomial_plain_is_equal(qp1, qp2); 687 1.1 mrg if (equal < 0) 688 1.1 mrg goto error; 689 1.1 mrg if (equal) 690 1.1 mrg break; 691 1.1 mrg d = isl_qpolynomial_sub( 692 1.1 mrg isl_qpolynomial_copy(qp1), 693 1.1 mrg isl_qpolynomial_copy(qp2)); 694 1.1 mrg sgn = isl_qpolynomial_sign(set, d); 695 1.1 mrg isl_qpolynomial_free(d); 696 1.1 mrg if (sgn == 0) 697 1.1 mrg continue; 698 1.1 mrg if (sgn != better) 699 1.1 mrg break; 700 1.1 mrg list1 = isl_qpolynomial_list_drop(list1, j, 1); 701 1.1 mrg n1--; 702 1.1 mrg } 703 1.1 mrg if (j < 0) 704 1.1 mrg continue; 705 1.1 mrg list2 = isl_qpolynomial_list_drop(list2, i, 1); 706 1.1 mrg n2--; 707 1.1 mrg } 708 1.1 mrg 709 1.1 mrg return isl_qpolynomial_list_concat(list1, list2); 710 1.1 mrg error: 711 1.1 mrg isl_qpolynomial_list_free(list1); 712 1.1 mrg isl_qpolynomial_list_free(list2); 713 1.1 mrg return NULL; 714 1.1 mrg } 715 1.1 mrg 716 1.1 mrg /* Combine "fold1" and "fold2" into a single reduction, eliminating 717 1.1 mrg * those elements of one reduction that are already covered by the other 718 1.1 mrg * reduction on "set". 719 1.1 mrg * 720 1.1 mrg * If "fold1" or "fold2" is an empty reduction, then return 721 1.1 mrg * the other reduction. 722 1.1 mrg * If "fold1" or "fold2" is a NaN, then return this NaN. 723 1.1 mrg */ 724 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain( 725 1.1 mrg __isl_keep isl_set *set, 726 1.1 mrg __isl_take isl_qpolynomial_fold *fold1, 727 1.1 mrg __isl_take isl_qpolynomial_fold *fold2) 728 1.1 mrg { 729 1.1 mrg isl_qpolynomial_list *list1; 730 1.1 mrg isl_qpolynomial_list *list2; 731 1.1 mrg int better; 732 1.1 mrg 733 1.1 mrg if (isl_qpolynomial_fold_check_equal_type(fold1, fold2) < 0) 734 1.1 mrg goto error; 735 1.1 mrg if (isl_qpolynomial_fold_check_equal_space(fold1, fold2) < 0) 736 1.1 mrg goto error; 737 1.1 mrg 738 1.1 mrg better = fold1->type == isl_fold_max ? -1 : 1; 739 1.1 mrg 740 1.1 mrg if (isl_qpolynomial_fold_is_empty(fold1) || 741 1.1 mrg isl_qpolynomial_fold_is_nan(fold2)) { 742 1.1 mrg isl_qpolynomial_fold_free(fold1); 743 1.1 mrg return fold2; 744 1.1 mrg } 745 1.1 mrg 746 1.1 mrg if (isl_qpolynomial_fold_is_empty(fold2) || 747 1.1 mrg isl_qpolynomial_fold_is_nan(fold1)) { 748 1.1 mrg isl_qpolynomial_fold_free(fold2); 749 1.1 mrg return fold1; 750 1.1 mrg } 751 1.1 mrg 752 1.1 mrg list1 = isl_qpolynomial_fold_take_list(fold1); 753 1.1 mrg list2 = isl_qpolynomial_fold_take_list(fold2); 754 1.1 mrg 755 1.1 mrg list1 = merge_lists(set, list1, list2, better); 756 1.1 mrg 757 1.1 mrg fold1 = isl_qpolynomial_fold_restore_list(fold1, list1); 758 1.1 mrg isl_qpolynomial_fold_free(fold2); 759 1.1 mrg 760 1.1 mrg return fold1; 761 1.1 mrg error: 762 1.1 mrg isl_qpolynomial_fold_free(fold1); 763 1.1 mrg isl_qpolynomial_fold_free(fold2); 764 1.1 mrg return NULL; 765 1.1 mrg } 766 1.1 mrg 767 1.1 mrg /* isl_qpolynomial_list_map callback for adding "qp2" to "qp". 768 1.1 mrg */ 769 1.1 mrg static __isl_give isl_qpolynomial *add_qpolynomial( 770 1.1 mrg __isl_take isl_qpolynomial *qp, void *user) 771 1.1 mrg { 772 1.1 mrg isl_qpolynomial *qp2 = user; 773 1.1 mrg 774 1.1 mrg return isl_qpolynomial_add(qp, isl_qpolynomial_copy(qp2)); 775 1.1 mrg } 776 1.1 mrg 777 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_qpolynomial( 778 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_qpolynomial *qp) 779 1.1 mrg { 780 1.1 mrg isl_qpolynomial_list *list; 781 1.1 mrg 782 1.1 mrg if (!fold || !qp) 783 1.1 mrg goto error; 784 1.1 mrg 785 1.1 mrg if (isl_qpolynomial_is_zero(qp)) { 786 1.1 mrg isl_qpolynomial_free(qp); 787 1.1 mrg return fold; 788 1.1 mrg } 789 1.1 mrg 790 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 791 1.1 mrg list = isl_qpolynomial_list_map(list, &add_qpolynomial, qp); 792 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 793 1.1 mrg 794 1.1 mrg isl_qpolynomial_free(qp); 795 1.1 mrg return fold; 796 1.1 mrg error: 797 1.1 mrg isl_qpolynomial_fold_free(fold); 798 1.1 mrg isl_qpolynomial_free(qp); 799 1.1 mrg return NULL; 800 1.1 mrg } 801 1.1 mrg 802 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain( 803 1.1 mrg __isl_keep isl_set *dom, 804 1.1 mrg __isl_take isl_qpolynomial_fold *fold1, 805 1.1 mrg __isl_take isl_qpolynomial_fold *fold2) 806 1.1 mrg { 807 1.1 mrg int i; 808 1.1 mrg isl_size n1, n2; 809 1.1 mrg isl_qpolynomial_fold *res = NULL; 810 1.1 mrg isl_qpolynomial *qp; 811 1.1 mrg isl_qpolynomial_list *list1, *list2; 812 1.1 mrg 813 1.1 mrg if (!fold1 || !fold2) 814 1.1 mrg goto error; 815 1.1 mrg 816 1.1 mrg if (isl_qpolynomial_fold_is_empty(fold1)) { 817 1.1 mrg isl_qpolynomial_fold_free(fold1); 818 1.1 mrg return fold2; 819 1.1 mrg } 820 1.1 mrg 821 1.1 mrg if (isl_qpolynomial_fold_is_empty(fold2)) { 822 1.1 mrg isl_qpolynomial_fold_free(fold2); 823 1.1 mrg return fold1; 824 1.1 mrg } 825 1.1 mrg 826 1.1 mrg list1 = isl_qpolynomial_fold_peek_list(fold1); 827 1.1 mrg list2 = isl_qpolynomial_fold_peek_list(fold2); 828 1.1 mrg n1 = isl_qpolynomial_list_size(list1); 829 1.1 mrg n2 = isl_qpolynomial_list_size(list2); 830 1.1 mrg if (n1 < 0 || n2 < 0) 831 1.1 mrg goto error; 832 1.1 mrg 833 1.1 mrg if (n1 == 1 && n2 != 1) 834 1.1 mrg return isl_qpolynomial_fold_add_on_domain(dom, fold2, fold1); 835 1.1 mrg 836 1.1 mrg qp = isl_qpolynomial_list_get_at(list2, 0); 837 1.1 mrg if (n2 == 1) { 838 1.1 mrg res = isl_qpolynomial_fold_add_qpolynomial(fold1, qp); 839 1.1 mrg isl_qpolynomial_fold_free(fold2); 840 1.1 mrg return res; 841 1.1 mrg } 842 1.1 mrg 843 1.1 mrg res = isl_qpolynomial_fold_add_qpolynomial( 844 1.1 mrg isl_qpolynomial_fold_copy(fold1), qp); 845 1.1 mrg 846 1.1 mrg for (i = 1; i < n2; ++i) { 847 1.1 mrg isl_qpolynomial_fold *res_i; 848 1.1 mrg 849 1.1 mrg qp = isl_qpolynomial_list_get_at(list2, i); 850 1.1 mrg res_i = isl_qpolynomial_fold_add_qpolynomial( 851 1.1 mrg isl_qpolynomial_fold_copy(fold1), qp); 852 1.1 mrg res = isl_qpolynomial_fold_fold_on_domain(dom, res, res_i); 853 1.1 mrg } 854 1.1 mrg 855 1.1 mrg isl_qpolynomial_fold_free(fold1); 856 1.1 mrg isl_qpolynomial_fold_free(fold2); 857 1.1 mrg return res; 858 1.1 mrg error: 859 1.1 mrg isl_qpolynomial_fold_free(res); 860 1.1 mrg isl_qpolynomial_fold_free(fold1); 861 1.1 mrg isl_qpolynomial_fold_free(fold2); 862 1.1 mrg return NULL; 863 1.1 mrg } 864 1.1 mrg 865 1.1 mrg /* isl_qpolynomial_list_map callback for calling 866 1.1 mrg * isl_qpolynomial_substitute_equalities on "qp" and "eq". 867 1.1 mrg */ 868 1.1 mrg static __isl_give isl_qpolynomial *substitute_equalities( 869 1.1 mrg __isl_take isl_qpolynomial *qp, void *user) 870 1.1 mrg { 871 1.1 mrg isl_basic_set *eq = user; 872 1.1 mrg 873 1.1 mrg eq = isl_basic_set_copy(eq); 874 1.1 mrg return isl_qpolynomial_substitute_equalities(qp, eq); 875 1.1 mrg } 876 1.1 mrg 877 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities( 878 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq) 879 1.1 mrg { 880 1.1 mrg isl_qpolynomial_list *list; 881 1.1 mrg 882 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 883 1.1 mrg list = isl_qpolynomial_list_map(list, &substitute_equalities, eq); 884 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 885 1.1 mrg 886 1.1 mrg isl_basic_set_free(eq); 887 1.1 mrg return fold; 888 1.1 mrg } 889 1.1 mrg 890 1.1 mrg /* isl_qpolynomial_list_map callback for calling 891 1.1 mrg * isl_qpolynomial_substitute_equalities on "qp" and "context". 892 1.1 mrg */ 893 1.1 mrg static __isl_give isl_qpolynomial *gist(__isl_take isl_qpolynomial *qp, 894 1.1 mrg void *user) 895 1.1 mrg { 896 1.1 mrg isl_set *context = user; 897 1.1 mrg 898 1.1 mrg return isl_qpolynomial_gist(qp, isl_set_copy(context)); 899 1.1 mrg } 900 1.1 mrg 901 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist( 902 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context) 903 1.1 mrg { 904 1.1 mrg isl_qpolynomial_list *list; 905 1.1 mrg 906 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 907 1.1 mrg list = isl_qpolynomial_list_map(list, &gist, context); 908 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 909 1.1 mrg 910 1.1 mrg isl_set_free(context); 911 1.1 mrg return fold; 912 1.1 mrg } 913 1.1 mrg 914 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params( 915 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context) 916 1.1 mrg { 917 1.1 mrg isl_space *space = isl_qpolynomial_fold_get_domain_space(fold); 918 1.1 mrg isl_set *dom_context = isl_set_universe(space); 919 1.1 mrg dom_context = isl_set_intersect_params(dom_context, context); 920 1.1 mrg return isl_qpolynomial_fold_gist(fold, dom_context); 921 1.1 mrg } 922 1.1 mrg 923 1.1 mrg /* Return a zero (i.e., empty) isl_qpolynomial_fold in the given space. 924 1.1 mrg * 925 1.1 mrg * This is a helper function for isl_pw_*_as_* that ensures a uniform 926 1.1 mrg * interface over all piecewise types. 927 1.1 mrg */ 928 1.1 mrg static __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_zero_in_space( 929 1.1 mrg __isl_take isl_space *space, enum isl_fold type) 930 1.1 mrg { 931 1.1 mrg return isl_qpolynomial_fold_empty(type, isl_space_domain(space)); 932 1.1 mrg } 933 1.1 mrg 934 1.1 mrg #define isl_qpolynomial_fold_involves_nan isl_qpolynomial_fold_is_nan 935 1.1 mrg 936 1.1 mrg #define HAS_TYPE 937 1.1 mrg 938 1.1 mrg #undef PW 939 1.1 mrg #define PW isl_pw_qpolynomial_fold 940 1.1 mrg #undef BASE 941 1.1 mrg #define BASE qpolynomial_fold 942 1.1 mrg #undef EL_IS_ZERO 943 1.1 mrg #define EL_IS_ZERO is_empty 944 1.1 mrg #undef ZERO 945 1.1 mrg #define ZERO zero 946 1.1 mrg #undef IS_ZERO 947 1.1 mrg #define IS_ZERO is_zero 948 1.1 mrg #undef FIELD 949 1.1 mrg #define FIELD fold 950 1.1 mrg #undef DEFAULT_IS_ZERO 951 1.1 mrg #define DEFAULT_IS_ZERO 1 952 1.1 mrg 953 1.1 mrg #include <isl_pw_templ.c> 954 1.1 mrg #include <isl_pw_add_disjoint_templ.c> 955 1.1 mrg #include <isl_pw_eval.c> 956 1.1 mrg #include <isl_pw_fix_templ.c> 957 1.1 mrg #include <isl_pw_from_range_templ.c> 958 1.1 mrg #include <isl_pw_insert_dims_templ.c> 959 1.1 mrg #include <isl_pw_lift_templ.c> 960 1.1 mrg #include <isl_pw_morph_templ.c> 961 1.1 mrg #include <isl_pw_move_dims_templ.c> 962 1.1 mrg #include <isl_pw_opt_templ.c> 963 1.1 mrg 964 1.1 mrg #undef BASE 965 1.1 mrg #define BASE pw_qpolynomial_fold 966 1.1 mrg 967 1.1 mrg #include <isl_union_single.c> 968 1.1 mrg #include <isl_union_eval.c> 969 1.1 mrg 970 1.1 mrg /* Construct a new reduction of the given type and space 971 1.1 mrg * with an empty list of polynomials. 972 1.1 mrg */ 973 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type, 974 1.1 mrg __isl_take isl_space *space) 975 1.1 mrg { 976 1.1 mrg isl_ctx *ctx; 977 1.1 mrg isl_qpolynomial_list *list; 978 1.1 mrg 979 1.1 mrg if (!space) 980 1.1 mrg return NULL; 981 1.1 mrg ctx = isl_space_get_ctx(space); 982 1.1 mrg list = isl_qpolynomial_list_alloc(ctx, 0); 983 1.1 mrg return qpolynomial_fold_alloc(type, space, list); 984 1.1 mrg } 985 1.1 mrg 986 1.1 mrg /* Construct a new reduction of the given type and 987 1.1 mrg * a single given polynomial. 988 1.1 mrg */ 989 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_alloc( 990 1.1 mrg enum isl_fold type, __isl_take isl_qpolynomial *qp) 991 1.1 mrg { 992 1.1 mrg isl_space *space; 993 1.1 mrg isl_qpolynomial_list *list; 994 1.1 mrg 995 1.1 mrg space = isl_qpolynomial_get_domain_space(qp); 996 1.1 mrg list = isl_qpolynomial_list_from_qpolynomial(qp); 997 1.1 mrg return qpolynomial_fold_alloc(type, space, list); 998 1.1 mrg } 999 1.1 mrg 1000 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_copy( 1001 1.1 mrg __isl_keep isl_qpolynomial_fold *fold) 1002 1.1 mrg { 1003 1.1 mrg if (!fold) 1004 1.1 mrg return NULL; 1005 1.1 mrg 1006 1.1 mrg fold->ref++; 1007 1.1 mrg return fold; 1008 1.1 mrg } 1009 1.1 mrg 1010 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup( 1011 1.1 mrg __isl_keep isl_qpolynomial_fold *fold) 1012 1.1 mrg { 1013 1.1 mrg enum isl_fold type; 1014 1.1 mrg isl_space *space; 1015 1.1 mrg isl_qpolynomial_list *list; 1016 1.1 mrg 1017 1.1 mrg type = isl_qpolynomial_fold_get_type(fold); 1018 1.1 mrg space = isl_qpolynomial_fold_get_domain_space(fold); 1019 1.1 mrg list = isl_qpolynomial_fold_get_list(fold); 1020 1.1 mrg return qpolynomial_fold_alloc(type, space, list); 1021 1.1 mrg } 1022 1.1 mrg 1023 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow( 1024 1.1 mrg __isl_take isl_qpolynomial_fold *fold) 1025 1.1 mrg { 1026 1.1 mrg if (!fold) 1027 1.1 mrg return NULL; 1028 1.1 mrg 1029 1.1 mrg if (fold->ref == 1) 1030 1.1 mrg return fold; 1031 1.1 mrg fold->ref--; 1032 1.1 mrg return isl_qpolynomial_fold_dup(fold); 1033 1.1 mrg } 1034 1.1 mrg 1035 1.1 mrg __isl_null isl_qpolynomial_fold *isl_qpolynomial_fold_free( 1036 1.1 mrg __isl_take isl_qpolynomial_fold *fold) 1037 1.1 mrg { 1038 1.1 mrg if (!fold) 1039 1.1 mrg return NULL; 1040 1.1 mrg if (--fold->ref > 0) 1041 1.1 mrg return NULL; 1042 1.1 mrg 1043 1.1 mrg isl_qpolynomial_list_free(fold->list); 1044 1.1 mrg isl_space_free(fold->dim); 1045 1.1 mrg free(fold); 1046 1.1 mrg 1047 1.1 mrg return NULL; 1048 1.1 mrg } 1049 1.1 mrg 1050 1.1 mrg isl_bool isl_qpolynomial_fold_is_empty(__isl_keep isl_qpolynomial_fold *fold) 1051 1.1 mrg { 1052 1.1 mrg isl_size n; 1053 1.1 mrg isl_qpolynomial_list *list; 1054 1.1 mrg 1055 1.1 mrg list = isl_qpolynomial_fold_peek_list(fold); 1056 1.1 mrg n = isl_qpolynomial_list_size(list); 1057 1.1 mrg if (n < 0) 1058 1.1 mrg return isl_bool_error; 1059 1.1 mrg 1060 1.1 mrg return isl_bool_ok(n == 0); 1061 1.1 mrg } 1062 1.1 mrg 1063 1.1 mrg /* Does "fold" represent max(NaN) or min(NaN)? 1064 1.1 mrg */ 1065 1.1 mrg isl_bool isl_qpolynomial_fold_is_nan(__isl_keep isl_qpolynomial_fold *fold) 1066 1.1 mrg { 1067 1.1 mrg isl_size n; 1068 1.1 mrg isl_qpolynomial *qp; 1069 1.1 mrg isl_qpolynomial_list *list; 1070 1.1 mrg 1071 1.1 mrg list = isl_qpolynomial_fold_peek_list(fold); 1072 1.1 mrg n = isl_qpolynomial_list_size(list); 1073 1.1 mrg if (n < 0) 1074 1.1 mrg return isl_bool_error; 1075 1.1 mrg if (n != 1) 1076 1.1 mrg return isl_bool_false; 1077 1.1 mrg qp = isl_qpolynomial_list_peek(list, 0); 1078 1.1 mrg return isl_qpolynomial_is_nan(qp); 1079 1.1 mrg } 1080 1.1 mrg 1081 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold( 1082 1.1 mrg __isl_take isl_qpolynomial_fold *fold1, 1083 1.1 mrg __isl_take isl_qpolynomial_fold *fold2) 1084 1.1 mrg { 1085 1.1 mrg isl_qpolynomial_list *list1, *list2; 1086 1.1 mrg 1087 1.1 mrg if (isl_qpolynomial_fold_check_equal_type(fold1, fold2) < 0) 1088 1.1 mrg goto error; 1089 1.1 mrg if (isl_qpolynomial_fold_check_equal_space(fold1, fold2) < 0) 1090 1.1 mrg goto error; 1091 1.1 mrg 1092 1.1 mrg if (isl_qpolynomial_fold_is_empty(fold1)) { 1093 1.1 mrg isl_qpolynomial_fold_free(fold1); 1094 1.1 mrg return fold2; 1095 1.1 mrg } 1096 1.1 mrg 1097 1.1 mrg if (isl_qpolynomial_fold_is_empty(fold2)) { 1098 1.1 mrg isl_qpolynomial_fold_free(fold2); 1099 1.1 mrg return fold1; 1100 1.1 mrg } 1101 1.1 mrg 1102 1.1 mrg list1 = isl_qpolynomial_fold_take_list(fold1); 1103 1.1 mrg list2 = isl_qpolynomial_fold_take_list(fold2); 1104 1.1 mrg list1 = isl_qpolynomial_list_concat(list1, list2); 1105 1.1 mrg fold1 = isl_qpolynomial_fold_restore_list(fold1, list1); 1106 1.1 mrg isl_qpolynomial_fold_free(fold2); 1107 1.1 mrg 1108 1.1 mrg return fold1; 1109 1.1 mrg error: 1110 1.1 mrg isl_qpolynomial_fold_free(fold1); 1111 1.1 mrg isl_qpolynomial_fold_free(fold2); 1112 1.1 mrg return NULL; 1113 1.1 mrg } 1114 1.1 mrg 1115 1.1 mrg __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold( 1116 1.1 mrg __isl_take isl_pw_qpolynomial_fold *pw1, 1117 1.1 mrg __isl_take isl_pw_qpolynomial_fold *pw2) 1118 1.1 mrg { 1119 1.1 mrg int i, j, n; 1120 1.1 mrg struct isl_pw_qpolynomial_fold *res; 1121 1.1 mrg isl_set *set; 1122 1.1 mrg 1123 1.1 mrg if (!pw1 || !pw2) 1124 1.1 mrg goto error; 1125 1.1 mrg 1126 1.1 mrg isl_assert(pw1->dim->ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error); 1127 1.1 mrg 1128 1.1 mrg if (isl_pw_qpolynomial_fold_is_zero(pw1)) { 1129 1.1 mrg isl_pw_qpolynomial_fold_free(pw1); 1130 1.1 mrg return pw2; 1131 1.1 mrg } 1132 1.1 mrg 1133 1.1 mrg if (isl_pw_qpolynomial_fold_is_zero(pw2)) { 1134 1.1 mrg isl_pw_qpolynomial_fold_free(pw2); 1135 1.1 mrg return pw1; 1136 1.1 mrg } 1137 1.1 mrg 1138 1.1 mrg if (pw1->type != pw2->type) 1139 1.1 mrg isl_die(pw1->dim->ctx, isl_error_invalid, 1140 1.1 mrg "fold types don't match", goto error); 1141 1.1 mrg 1142 1.1 mrg n = (pw1->n + 1) * (pw2->n + 1); 1143 1.1 mrg res = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pw1->dim), 1144 1.1 mrg pw1->type, n); 1145 1.1 mrg 1146 1.1 mrg for (i = 0; i < pw1->n; ++i) { 1147 1.1 mrg set = isl_set_copy(pw1->p[i].set); 1148 1.1 mrg for (j = 0; j < pw2->n; ++j) { 1149 1.1 mrg struct isl_set *common; 1150 1.1 mrg isl_qpolynomial_fold *sum; 1151 1.1 mrg set = isl_set_subtract(set, 1152 1.1 mrg isl_set_copy(pw2->p[j].set)); 1153 1.1 mrg common = isl_set_intersect(isl_set_copy(pw1->p[i].set), 1154 1.1 mrg isl_set_copy(pw2->p[j].set)); 1155 1.1 mrg if (isl_set_plain_is_empty(common)) { 1156 1.1 mrg isl_set_free(common); 1157 1.1 mrg continue; 1158 1.1 mrg } 1159 1.1 mrg 1160 1.1 mrg sum = isl_qpolynomial_fold_fold_on_domain(common, 1161 1.1 mrg isl_qpolynomial_fold_copy(pw1->p[i].fold), 1162 1.1 mrg isl_qpolynomial_fold_copy(pw2->p[j].fold)); 1163 1.1 mrg 1164 1.1 mrg res = isl_pw_qpolynomial_fold_add_piece(res, common, sum); 1165 1.1 mrg } 1166 1.1 mrg res = isl_pw_qpolynomial_fold_add_piece(res, set, 1167 1.1 mrg isl_qpolynomial_fold_copy(pw1->p[i].fold)); 1168 1.1 mrg } 1169 1.1 mrg 1170 1.1 mrg for (j = 0; j < pw2->n; ++j) { 1171 1.1 mrg set = isl_set_copy(pw2->p[j].set); 1172 1.1 mrg for (i = 0; i < pw1->n; ++i) 1173 1.1 mrg set = isl_set_subtract(set, isl_set_copy(pw1->p[i].set)); 1174 1.1 mrg res = isl_pw_qpolynomial_fold_add_piece(res, set, 1175 1.1 mrg isl_qpolynomial_fold_copy(pw2->p[j].fold)); 1176 1.1 mrg } 1177 1.1 mrg 1178 1.1 mrg isl_pw_qpolynomial_fold_free(pw1); 1179 1.1 mrg isl_pw_qpolynomial_fold_free(pw2); 1180 1.1 mrg 1181 1.1 mrg return res; 1182 1.1 mrg error: 1183 1.1 mrg isl_pw_qpolynomial_fold_free(pw1); 1184 1.1 mrg isl_pw_qpolynomial_fold_free(pw2); 1185 1.1 mrg return NULL; 1186 1.1 mrg } 1187 1.1 mrg 1188 1.1 mrg __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold( 1189 1.1 mrg __isl_take isl_union_pw_qpolynomial_fold *u, 1190 1.1 mrg __isl_take isl_pw_qpolynomial_fold *part) 1191 1.1 mrg { 1192 1.1 mrg struct isl_hash_table_entry *entry; 1193 1.1 mrg 1194 1.1 mrg u = isl_union_pw_qpolynomial_fold_cow(u); 1195 1.1 mrg 1196 1.1 mrg if (!part || !u) 1197 1.1 mrg goto error; 1198 1.1 mrg if (isl_space_check_equal_params(part->dim, u->space) < 0) 1199 1.1 mrg goto error; 1200 1.1 mrg 1201 1.1 mrg entry = isl_union_pw_qpolynomial_fold_find_part_entry(u, part->dim, 1); 1202 1.1 mrg if (!entry) 1203 1.1 mrg goto error; 1204 1.1 mrg 1205 1.1 mrg if (!entry->data) 1206 1.1 mrg entry->data = part; 1207 1.1 mrg else { 1208 1.1 mrg entry->data = isl_pw_qpolynomial_fold_fold(entry->data, 1209 1.1 mrg isl_pw_qpolynomial_fold_copy(part)); 1210 1.1 mrg if (!entry->data) 1211 1.1 mrg goto error; 1212 1.1 mrg isl_pw_qpolynomial_fold_free(part); 1213 1.1 mrg } 1214 1.1 mrg 1215 1.1 mrg return u; 1216 1.1 mrg error: 1217 1.1 mrg isl_pw_qpolynomial_fold_free(part); 1218 1.1 mrg isl_union_pw_qpolynomial_fold_free(u); 1219 1.1 mrg return NULL; 1220 1.1 mrg } 1221 1.1 mrg 1222 1.1 mrg static isl_stat fold_part(__isl_take isl_pw_qpolynomial_fold *part, void *user) 1223 1.1 mrg { 1224 1.1 mrg isl_union_pw_qpolynomial_fold **u; 1225 1.1 mrg u = (isl_union_pw_qpolynomial_fold **)user; 1226 1.1 mrg 1227 1.1 mrg *u = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(*u, part); 1228 1.1 mrg 1229 1.1 mrg return isl_stat_ok; 1230 1.1 mrg } 1231 1.1 mrg 1232 1.1 mrg __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold( 1233 1.1 mrg __isl_take isl_union_pw_qpolynomial_fold *u1, 1234 1.1 mrg __isl_take isl_union_pw_qpolynomial_fold *u2) 1235 1.1 mrg { 1236 1.1 mrg u1 = isl_union_pw_qpolynomial_fold_cow(u1); 1237 1.1 mrg 1238 1.1 mrg if (!u1 || !u2) 1239 1.1 mrg goto error; 1240 1.1 mrg 1241 1.1 mrg if (isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(u2, 1242 1.1 mrg &fold_part, &u1) < 0) 1243 1.1 mrg goto error; 1244 1.1 mrg 1245 1.1 mrg isl_union_pw_qpolynomial_fold_free(u2); 1246 1.1 mrg 1247 1.1 mrg return u1; 1248 1.1 mrg error: 1249 1.1 mrg isl_union_pw_qpolynomial_fold_free(u1); 1250 1.1 mrg isl_union_pw_qpolynomial_fold_free(u2); 1251 1.1 mrg return NULL; 1252 1.1 mrg } 1253 1.1 mrg 1254 1.1 mrg __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial( 1255 1.1 mrg enum isl_fold type, __isl_take isl_pw_qpolynomial *pwqp) 1256 1.1 mrg { 1257 1.1 mrg int i; 1258 1.1 mrg isl_pw_qpolynomial_fold *pwf; 1259 1.1 mrg 1260 1.1 mrg if (!pwqp) 1261 1.1 mrg return NULL; 1262 1.1 mrg 1263 1.1 mrg pwf = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pwqp->dim), 1264 1.1 mrg type, pwqp->n); 1265 1.1 mrg 1266 1.1 mrg for (i = 0; i < pwqp->n; ++i) 1267 1.1 mrg pwf = isl_pw_qpolynomial_fold_add_piece(pwf, 1268 1.1 mrg isl_set_copy(pwqp->p[i].set), 1269 1.1 mrg isl_qpolynomial_fold_alloc(type, 1270 1.1 mrg isl_qpolynomial_copy(pwqp->p[i].qp))); 1271 1.1 mrg 1272 1.1 mrg isl_pw_qpolynomial_free(pwqp); 1273 1.1 mrg 1274 1.1 mrg return pwf; 1275 1.1 mrg } 1276 1.1 mrg 1277 1.1 mrg __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add( 1278 1.1 mrg __isl_take isl_pw_qpolynomial_fold *pwf1, 1279 1.1 mrg __isl_take isl_pw_qpolynomial_fold *pwf2) 1280 1.1 mrg { 1281 1.1 mrg return isl_pw_qpolynomial_fold_union_add_(pwf1, pwf2); 1282 1.1 mrg } 1283 1.1 mrg 1284 1.1 mrg /* Compare two quasi-polynomial reductions. 1285 1.1 mrg * 1286 1.1 mrg * Return -1 if "fold1" is "smaller" than "fold2", 1 if "fold1" is "greater" 1287 1.1 mrg * than "fold2" and 0 if they are equal. 1288 1.1 mrg */ 1289 1.1 mrg int isl_qpolynomial_fold_plain_cmp(__isl_keep isl_qpolynomial_fold *fold1, 1290 1.1 mrg __isl_keep isl_qpolynomial_fold *fold2) 1291 1.1 mrg { 1292 1.1 mrg int i; 1293 1.1 mrg isl_size n1, n2; 1294 1.1 mrg isl_qpolynomial_list *list1, *list2; 1295 1.1 mrg 1296 1.1 mrg if (fold1 == fold2) 1297 1.1 mrg return 0; 1298 1.1 mrg list1 = isl_qpolynomial_fold_peek_list(fold1); 1299 1.1 mrg list2 = isl_qpolynomial_fold_peek_list(fold2); 1300 1.1 mrg n1 = isl_qpolynomial_list_size(list1); 1301 1.1 mrg n2 = isl_qpolynomial_list_size(list2); 1302 1.1 mrg if (n1 < 0) 1303 1.1 mrg return -1; 1304 1.1 mrg if (n2 < 0) 1305 1.1 mrg return 1; 1306 1.1 mrg 1307 1.1 mrg if (n1 != n2) 1308 1.1 mrg return n1 - n2; 1309 1.1 mrg 1310 1.1 mrg for (i = 0; i < n1; ++i) { 1311 1.1 mrg int cmp; 1312 1.1 mrg isl_qpolynomial *qp1, *qp2; 1313 1.1 mrg 1314 1.1 mrg qp1 = isl_qpolynomial_list_peek(list1, i); 1315 1.1 mrg qp2 = isl_qpolynomial_list_peek(list2, i); 1316 1.1 mrg cmp = isl_qpolynomial_plain_cmp(qp1, qp2); 1317 1.1 mrg if (cmp != 0) 1318 1.1 mrg return cmp; 1319 1.1 mrg } 1320 1.1 mrg 1321 1.1 mrg return 0; 1322 1.1 mrg } 1323 1.1 mrg 1324 1.1 mrg /* Are the lists "list1" and "list2", both consisting of "n" elements 1325 1.1 mrg * obviously equal to each other? 1326 1.1 mrg */ 1327 1.1 mrg static isl_bool isl_qpolynomial_list_plain_is_equal(unsigned n, 1328 1.1 mrg isl_qpolynomial_list *list1, isl_qpolynomial_list *list2) 1329 1.1 mrg { 1330 1.1 mrg int i; 1331 1.1 mrg 1332 1.1 mrg for (i = 0; i < n; ++i) { 1333 1.1 mrg isl_bool eq; 1334 1.1 mrg isl_qpolynomial *qp1, *qp2; 1335 1.1 mrg 1336 1.1 mrg qp1 = isl_qpolynomial_list_peek(list1, i); 1337 1.1 mrg qp2 = isl_qpolynomial_list_peek(list2, i); 1338 1.1 mrg eq = isl_qpolynomial_plain_is_equal(qp1, qp2); 1339 1.1 mrg if (eq < 0 || !eq) 1340 1.1 mrg return eq; 1341 1.1 mrg } 1342 1.1 mrg 1343 1.1 mrg return isl_bool_true; 1344 1.1 mrg } 1345 1.1 mrg 1346 1.1 mrg /* Wrapper around isl_qpolynomial_plain_cmp for use 1347 1.1 mrg * as a isl_qpolynomial_list_sort callback. 1348 1.1 mrg */ 1349 1.1 mrg static int qpolynomial_cmp(__isl_keep isl_qpolynomial *a, 1350 1.1 mrg __isl_keep isl_qpolynomial *b, void *user) 1351 1.1 mrg { 1352 1.1 mrg return isl_qpolynomial_plain_cmp(a, b); 1353 1.1 mrg } 1354 1.1 mrg 1355 1.1 mrg isl_bool isl_qpolynomial_fold_plain_is_equal( 1356 1.1 mrg __isl_keep isl_qpolynomial_fold *fold1, 1357 1.1 mrg __isl_keep isl_qpolynomial_fold *fold2) 1358 1.1 mrg { 1359 1.1 mrg isl_bool equal; 1360 1.1 mrg isl_size n1, n2; 1361 1.1 mrg isl_qpolynomial_list *list1, *list2; 1362 1.1 mrg 1363 1.1 mrg list1 = isl_qpolynomial_fold_peek_list(fold1); 1364 1.1 mrg list2 = isl_qpolynomial_fold_peek_list(fold2); 1365 1.1 mrg n1 = isl_qpolynomial_list_size(list1); 1366 1.1 mrg n2 = isl_qpolynomial_list_size(list2); 1367 1.1 mrg if (n1 < 0 || n2 < 0) 1368 1.1 mrg return isl_bool_error; 1369 1.1 mrg 1370 1.1 mrg if (n1 != n2) 1371 1.1 mrg return isl_bool_false; 1372 1.1 mrg 1373 1.1 mrg list1 = isl_qpolynomial_list_copy(list1); 1374 1.1 mrg list1 = isl_qpolynomial_list_sort(list1, &qpolynomial_cmp, NULL); 1375 1.1 mrg list2 = isl_qpolynomial_list_copy(list2); 1376 1.1 mrg list2 = isl_qpolynomial_list_sort(list2, &qpolynomial_cmp, NULL); 1377 1.1 mrg equal = isl_qpolynomial_list_plain_is_equal(n1, list1, list2); 1378 1.1 mrg isl_qpolynomial_list_free(list1); 1379 1.1 mrg isl_qpolynomial_list_free(list2); 1380 1.1 mrg return equal; 1381 1.1 mrg } 1382 1.1 mrg 1383 1.1 mrg __isl_give isl_val *isl_qpolynomial_fold_eval( 1384 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_point *pnt) 1385 1.1 mrg { 1386 1.1 mrg isl_size n; 1387 1.1 mrg isl_ctx *ctx; 1388 1.1 mrg isl_val *v; 1389 1.1 mrg isl_qpolynomial *qp; 1390 1.1 mrg isl_qpolynomial_list *list; 1391 1.1 mrg 1392 1.1 mrg if (!fold || !pnt) 1393 1.1 mrg goto error; 1394 1.1 mrg ctx = isl_point_get_ctx(pnt); 1395 1.1 mrg isl_assert(pnt->dim->ctx, isl_space_is_equal(pnt->dim, fold->dim), goto error); 1396 1.1 mrg isl_assert(pnt->dim->ctx, 1397 1.1 mrg fold->type == isl_fold_max || fold->type == isl_fold_min, 1398 1.1 mrg goto error); 1399 1.1 mrg 1400 1.1 mrg list = isl_qpolynomial_fold_peek_list(fold); 1401 1.1 mrg n = isl_qpolynomial_list_size(list); 1402 1.1 mrg if (n < 0) 1403 1.1 mrg goto error; 1404 1.1 mrg 1405 1.1 mrg if (n == 0) 1406 1.1 mrg v = isl_val_zero(ctx); 1407 1.1 mrg else { 1408 1.1 mrg int i; 1409 1.1 mrg 1410 1.1 mrg qp = isl_qpolynomial_list_get_at(list, 0); 1411 1.1 mrg v = isl_qpolynomial_eval(qp, isl_point_copy(pnt)); 1412 1.1 mrg for (i = 1; i < n; ++i) { 1413 1.1 mrg isl_val *v_i; 1414 1.1 mrg 1415 1.1 mrg qp = isl_qpolynomial_list_get_at(list, i); 1416 1.1 mrg v_i = isl_qpolynomial_eval(qp, isl_point_copy(pnt)); 1417 1.1 mrg if (fold->type == isl_fold_max) 1418 1.1 mrg v = isl_val_max(v, v_i); 1419 1.1 mrg else 1420 1.1 mrg v = isl_val_min(v, v_i); 1421 1.1 mrg } 1422 1.1 mrg } 1423 1.1 mrg isl_qpolynomial_fold_free(fold); 1424 1.1 mrg isl_point_free(pnt); 1425 1.1 mrg 1426 1.1 mrg return v; 1427 1.1 mrg error: 1428 1.1 mrg isl_qpolynomial_fold_free(fold); 1429 1.1 mrg isl_point_free(pnt); 1430 1.1 mrg return NULL; 1431 1.1 mrg } 1432 1.1 mrg 1433 1.1 mrg size_t isl_pw_qpolynomial_fold_size(__isl_keep isl_pw_qpolynomial_fold *pwf) 1434 1.1 mrg { 1435 1.1 mrg int i; 1436 1.1 mrg size_t n = 0; 1437 1.1 mrg 1438 1.1 mrg for (i = 0; i < pwf->n; ++i) { 1439 1.1 mrg isl_size n_i; 1440 1.1 mrg isl_qpolynomial_list *list; 1441 1.1 mrg 1442 1.1 mrg list = isl_qpolynomial_fold_peek_list(pwf->p[i].fold); 1443 1.1 mrg n_i = isl_qpolynomial_list_size(list); 1444 1.1 mrg if (n_i < 0) 1445 1.1 mrg return isl_size_error; 1446 1.1 mrg 1447 1.1 mrg n += n_i; 1448 1.1 mrg } 1449 1.1 mrg 1450 1.1 mrg return n; 1451 1.1 mrg } 1452 1.1 mrg 1453 1.1 mrg __isl_give isl_val *isl_qpolynomial_fold_opt_on_domain( 1454 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *set, int max) 1455 1.1 mrg { 1456 1.1 mrg int i; 1457 1.1 mrg isl_size n; 1458 1.1 mrg isl_val *opt; 1459 1.1 mrg isl_qpolynomial *qp; 1460 1.1 mrg isl_qpolynomial_list *list; 1461 1.1 mrg 1462 1.1 mrg list = isl_qpolynomial_fold_peek_list(fold); 1463 1.1 mrg n = isl_qpolynomial_list_size(list); 1464 1.1 mrg if (!set || n < 0) 1465 1.1 mrg goto error; 1466 1.1 mrg 1467 1.1 mrg if (n == 0) { 1468 1.1 mrg opt = isl_val_zero(isl_set_get_ctx(set)); 1469 1.1 mrg isl_set_free(set); 1470 1.1 mrg isl_qpolynomial_fold_free(fold); 1471 1.1 mrg return opt; 1472 1.1 mrg } 1473 1.1 mrg 1474 1.1 mrg qp = isl_qpolynomial_list_get_at(list, 0); 1475 1.1 mrg opt = isl_qpolynomial_opt_on_domain(qp, isl_set_copy(set), max); 1476 1.1 mrg for (i = 1; i < n; ++i) { 1477 1.1 mrg isl_val *opt_i; 1478 1.1 mrg 1479 1.1 mrg qp = isl_qpolynomial_list_get_at(list, i); 1480 1.1 mrg opt_i = isl_qpolynomial_opt_on_domain(qp, 1481 1.1 mrg isl_set_copy(set), max); 1482 1.1 mrg if (max) 1483 1.1 mrg opt = isl_val_max(opt, opt_i); 1484 1.1 mrg else 1485 1.1 mrg opt = isl_val_min(opt, opt_i); 1486 1.1 mrg } 1487 1.1 mrg 1488 1.1 mrg isl_set_free(set); 1489 1.1 mrg isl_qpolynomial_fold_free(fold); 1490 1.1 mrg 1491 1.1 mrg return opt; 1492 1.1 mrg error: 1493 1.1 mrg isl_set_free(set); 1494 1.1 mrg isl_qpolynomial_fold_free(fold); 1495 1.1 mrg return NULL; 1496 1.1 mrg } 1497 1.1 mrg 1498 1.1 mrg /* Check whether for each quasi-polynomial in "fold2" there is 1499 1.1 mrg * a quasi-polynomial in "fold1" that dominates it on "set". 1500 1.1 mrg */ 1501 1.1 mrg static isl_bool qpolynomial_fold_covers_on_domain(__isl_keep isl_set *set, 1502 1.1 mrg __isl_keep isl_qpolynomial_fold *fold1, 1503 1.1 mrg __isl_keep isl_qpolynomial_fold *fold2) 1504 1.1 mrg { 1505 1.1 mrg int i, j; 1506 1.1 mrg int covers; 1507 1.1 mrg isl_size n1, n2; 1508 1.1 mrg isl_qpolynomial_list *list1, *list2; 1509 1.1 mrg 1510 1.1 mrg list1 = isl_qpolynomial_fold_peek_list(fold1); 1511 1.1 mrg list2 = isl_qpolynomial_fold_peek_list(fold2); 1512 1.1 mrg n1 = isl_qpolynomial_list_size(list1); 1513 1.1 mrg n2 = isl_qpolynomial_list_size(list2); 1514 1.1 mrg if (!set || n1 < 0 || n2 < 0) 1515 1.1 mrg return isl_bool_error; 1516 1.1 mrg 1517 1.1 mrg covers = fold1->type == isl_fold_max ? 1 : -1; 1518 1.1 mrg 1519 1.1 mrg for (i = 0; i < n2; ++i) { 1520 1.1 mrg for (j = 0; j < n1; ++j) { 1521 1.1 mrg isl_qpolynomial *qp1, *qp2, *d; 1522 1.1 mrg int sgn; 1523 1.1 mrg 1524 1.1 mrg qp1 = isl_qpolynomial_list_get_at(list1, j); 1525 1.1 mrg qp2 = isl_qpolynomial_list_get_at(list2, i); 1526 1.1 mrg d = isl_qpolynomial_sub(qp1, qp2); 1527 1.1 mrg sgn = isl_qpolynomial_sign(set, d); 1528 1.1 mrg isl_qpolynomial_free(d); 1529 1.1 mrg if (sgn == covers) 1530 1.1 mrg break; 1531 1.1 mrg } 1532 1.1 mrg if (j >= n1) 1533 1.1 mrg return isl_bool_false; 1534 1.1 mrg } 1535 1.1 mrg 1536 1.1 mrg return isl_bool_true; 1537 1.1 mrg } 1538 1.1 mrg 1539 1.1 mrg /* Check whether "pwf1" dominated "pwf2", i.e., the domain of "pwf1" contains 1540 1.1 mrg * that of "pwf2" and on each cell, the corresponding fold from pwf1 dominates 1541 1.1 mrg * that of pwf2. 1542 1.1 mrg */ 1543 1.1 mrg isl_bool isl_pw_qpolynomial_fold_covers( 1544 1.1 mrg __isl_keep isl_pw_qpolynomial_fold *pwf1, 1545 1.1 mrg __isl_keep isl_pw_qpolynomial_fold *pwf2) 1546 1.1 mrg { 1547 1.1 mrg int i, j; 1548 1.1 mrg isl_set *dom1, *dom2; 1549 1.1 mrg isl_bool is_subset; 1550 1.1 mrg 1551 1.1 mrg if (!pwf1 || !pwf2) 1552 1.1 mrg return isl_bool_error; 1553 1.1 mrg 1554 1.1 mrg if (pwf2->n == 0) 1555 1.1 mrg return isl_bool_true; 1556 1.1 mrg if (pwf1->n == 0) 1557 1.1 mrg return isl_bool_false; 1558 1.1 mrg 1559 1.1 mrg dom1 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf1)); 1560 1.1 mrg dom2 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf2)); 1561 1.1 mrg is_subset = isl_set_is_subset(dom2, dom1); 1562 1.1 mrg isl_set_free(dom1); 1563 1.1 mrg isl_set_free(dom2); 1564 1.1 mrg 1565 1.1 mrg if (is_subset < 0 || !is_subset) 1566 1.1 mrg return is_subset; 1567 1.1 mrg 1568 1.1 mrg for (i = 0; i < pwf2->n; ++i) { 1569 1.1 mrg for (j = 0; j < pwf1->n; ++j) { 1570 1.1 mrg isl_bool is_empty; 1571 1.1 mrg isl_set *common; 1572 1.1 mrg isl_bool covers; 1573 1.1 mrg 1574 1.1 mrg common = isl_set_intersect(isl_set_copy(pwf1->p[j].set), 1575 1.1 mrg isl_set_copy(pwf2->p[i].set)); 1576 1.1 mrg is_empty = isl_set_is_empty(common); 1577 1.1 mrg if (is_empty < 0 || is_empty) { 1578 1.1 mrg isl_set_free(common); 1579 1.1 mrg if (is_empty < 0) 1580 1.1 mrg return isl_bool_error; 1581 1.1 mrg continue; 1582 1.1 mrg } 1583 1.1 mrg covers = qpolynomial_fold_covers_on_domain(common, 1584 1.1 mrg pwf1->p[j].fold, pwf2->p[i].fold); 1585 1.1 mrg isl_set_free(common); 1586 1.1 mrg if (covers < 0 || !covers) 1587 1.1 mrg return covers; 1588 1.1 mrg } 1589 1.1 mrg } 1590 1.1 mrg 1591 1.1 mrg return isl_bool_true; 1592 1.1 mrg } 1593 1.1 mrg 1594 1.1 mrg /* isl_qpolynomial_list_map callback that calls 1595 1.1 mrg * isl_qpolynomial_morph_domain on "qp". 1596 1.1 mrg */ 1597 1.1 mrg static __isl_give isl_qpolynomial *morph_domain( 1598 1.1 mrg __isl_take isl_qpolynomial *qp, void *user) 1599 1.1 mrg { 1600 1.1 mrg isl_morph *morph = user; 1601 1.1 mrg 1602 1.1 mrg return isl_qpolynomial_morph_domain(qp, isl_morph_copy(morph)); 1603 1.1 mrg } 1604 1.1 mrg 1605 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain( 1606 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph) 1607 1.1 mrg { 1608 1.1 mrg isl_space *space; 1609 1.1 mrg isl_qpolynomial_list *list; 1610 1.1 mrg 1611 1.1 mrg space = isl_qpolynomial_fold_peek_domain_space(fold); 1612 1.1 mrg if (isl_morph_check_applies(morph, space) < 0) 1613 1.1 mrg goto error; 1614 1.1 mrg 1615 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 1616 1.1 mrg list = isl_qpolynomial_list_map(list, &morph_domain, morph); 1617 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 1618 1.1 mrg 1619 1.1 mrg space = isl_morph_get_ran_space(morph); 1620 1.1 mrg isl_space_free(isl_qpolynomial_fold_take_domain_space(fold)); 1621 1.1 mrg fold = isl_qpolynomial_fold_restore_domain_space(fold, space); 1622 1.1 mrg 1623 1.1 mrg isl_morph_free(morph); 1624 1.1 mrg 1625 1.1 mrg return fold; 1626 1.1 mrg error: 1627 1.1 mrg isl_qpolynomial_fold_free(fold); 1628 1.1 mrg isl_morph_free(morph); 1629 1.1 mrg return NULL; 1630 1.1 mrg } 1631 1.1 mrg 1632 1.1 mrg enum isl_fold isl_qpolynomial_fold_get_type(__isl_keep isl_qpolynomial_fold *fold) 1633 1.1 mrg { 1634 1.1 mrg if (!fold) 1635 1.1 mrg return isl_fold_error; 1636 1.1 mrg return fold->type; 1637 1.1 mrg } 1638 1.1 mrg 1639 1.1 mrg /* Return the type of this piecewise quasipolynomial reduction. 1640 1.1 mrg */ 1641 1.1 mrg enum isl_fold isl_pw_qpolynomial_fold_get_type( 1642 1.1 mrg __isl_keep isl_pw_qpolynomial_fold *pwf) 1643 1.1 mrg { 1644 1.1 mrg if (!pwf) 1645 1.1 mrg return isl_fold_error; 1646 1.1 mrg return pwf->type; 1647 1.1 mrg } 1648 1.1 mrg 1649 1.1 mrg enum isl_fold isl_union_pw_qpolynomial_fold_get_type( 1650 1.1 mrg __isl_keep isl_union_pw_qpolynomial_fold *upwf) 1651 1.1 mrg { 1652 1.1 mrg if (!upwf) 1653 1.1 mrg return isl_fold_error; 1654 1.1 mrg return upwf->type; 1655 1.1 mrg } 1656 1.1 mrg 1657 1.1 mrg /* isl_qpolynomial_list_map callback that calls 1658 1.1 mrg * isl_qpolynomial_lift on "qp". 1659 1.1 mrg */ 1660 1.1 mrg static __isl_give isl_qpolynomial *lift(__isl_take isl_qpolynomial *qp, 1661 1.1 mrg void *user) 1662 1.1 mrg { 1663 1.1 mrg isl_space *space = user; 1664 1.1 mrg 1665 1.1 mrg return isl_qpolynomial_lift(qp, isl_space_copy(space)); 1666 1.1 mrg } 1667 1.1 mrg 1668 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift( 1669 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space) 1670 1.1 mrg { 1671 1.1 mrg isl_qpolynomial_list *list; 1672 1.1 mrg 1673 1.1 mrg if (!fold || !space) 1674 1.1 mrg goto error; 1675 1.1 mrg 1676 1.1 mrg if (isl_space_is_equal(fold->dim, space)) { 1677 1.1 mrg isl_space_free(space); 1678 1.1 mrg return fold; 1679 1.1 mrg } 1680 1.1 mrg 1681 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 1682 1.1 mrg list = isl_qpolynomial_list_map(list, &lift, space); 1683 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 1684 1.1 mrg 1685 1.1 mrg isl_space_free(isl_qpolynomial_fold_take_domain_space(fold)); 1686 1.1 mrg fold = isl_qpolynomial_fold_restore_domain_space(fold, space); 1687 1.1 mrg 1688 1.1 mrg return fold; 1689 1.1 mrg error: 1690 1.1 mrg isl_qpolynomial_fold_free(fold); 1691 1.1 mrg isl_space_free(space); 1692 1.1 mrg return NULL; 1693 1.1 mrg } 1694 1.1 mrg 1695 1.1 mrg isl_stat isl_qpolynomial_fold_foreach_qpolynomial( 1696 1.1 mrg __isl_keep isl_qpolynomial_fold *fold, 1697 1.1 mrg isl_stat (*fn)(__isl_take isl_qpolynomial *qp, void *user), void *user) 1698 1.1 mrg { 1699 1.1 mrg isl_qpolynomial_list *list; 1700 1.1 mrg 1701 1.1 mrg list = isl_qpolynomial_fold_peek_list(fold); 1702 1.1 mrg return isl_qpolynomial_list_foreach(list, fn, user); 1703 1.1 mrg } 1704 1.1 mrg 1705 1.1 mrg /* Internal data structure for isl_qpolynomial_fold_move_dims 1706 1.1 mrg * representing its arguments. 1707 1.1 mrg */ 1708 1.1 mrg struct isl_fold_move_dims_data { 1709 1.1 mrg enum isl_dim_type dst_type; 1710 1.1 mrg unsigned dst_pos; 1711 1.1 mrg enum isl_dim_type src_type; 1712 1.1 mrg unsigned src_pos; 1713 1.1 mrg unsigned n; 1714 1.1 mrg }; 1715 1.1 mrg 1716 1.1 mrg /* isl_qpolynomial_list_map callback for calling 1717 1.1 mrg * isl_qpolynomial_move_dims on "qp". 1718 1.1 mrg */ 1719 1.1 mrg static __isl_give isl_qpolynomial *move_dims(__isl_take isl_qpolynomial *qp, 1720 1.1 mrg void *user) 1721 1.1 mrg { 1722 1.1 mrg struct isl_fold_move_dims_data *data = user; 1723 1.1 mrg 1724 1.1 mrg qp = isl_qpolynomial_move_dims(qp, data->dst_type, data->dst_pos, 1725 1.1 mrg data->src_type, data->src_pos, data->n); 1726 1.1 mrg return qp; 1727 1.1 mrg } 1728 1.1 mrg 1729 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims( 1730 1.1 mrg __isl_take isl_qpolynomial_fold *fold, 1731 1.1 mrg enum isl_dim_type dst_type, unsigned dst_pos, 1732 1.1 mrg enum isl_dim_type src_type, unsigned src_pos, unsigned n) 1733 1.1 mrg { 1734 1.1 mrg struct isl_fold_move_dims_data data = 1735 1.1 mrg { dst_type, dst_pos, src_type, src_pos, n }; 1736 1.1 mrg enum isl_dim_type set_src_type, set_dst_type; 1737 1.1 mrg isl_space *space; 1738 1.1 mrg isl_qpolynomial_list *list; 1739 1.1 mrg 1740 1.1 mrg if (n == 0) 1741 1.1 mrg return fold; 1742 1.1 mrg 1743 1.1 mrg fold = isl_qpolynomial_fold_cow(fold); 1744 1.1 mrg if (!fold) 1745 1.1 mrg return NULL; 1746 1.1 mrg 1747 1.1 mrg set_src_type = domain_type(src_type); 1748 1.1 mrg set_dst_type = domain_type(dst_type); 1749 1.1 mrg 1750 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 1751 1.1 mrg list = isl_qpolynomial_list_map(list, &move_dims, &data); 1752 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 1753 1.1 mrg 1754 1.1 mrg space = isl_qpolynomial_fold_take_domain_space(fold); 1755 1.1 mrg space = isl_space_move_dims(space, set_dst_type, dst_pos, 1756 1.1 mrg set_src_type, src_pos, n); 1757 1.1 mrg fold = isl_qpolynomial_fold_restore_domain_space(fold, space); 1758 1.1 mrg 1759 1.1 mrg return fold; 1760 1.1 mrg } 1761 1.1 mrg 1762 1.1 mrg /* Internal data structure for isl_qpolynomial_fold_substitute 1763 1.1 mrg * representing its arguments. 1764 1.1 mrg */ 1765 1.1 mrg struct isl_fold_substitute { 1766 1.1 mrg enum isl_dim_type type; 1767 1.1 mrg unsigned first; 1768 1.1 mrg unsigned n; 1769 1.1 mrg isl_qpolynomial **subs; 1770 1.1 mrg }; 1771 1.1 mrg 1772 1.1 mrg /* isl_qpolynomial_list_map callback for calling 1773 1.1 mrg * isl_qpolynomial_substitute on "qp". 1774 1.1 mrg */ 1775 1.1 mrg static __isl_give isl_qpolynomial *substitute(__isl_take isl_qpolynomial *qp, 1776 1.1 mrg void *user) 1777 1.1 mrg { 1778 1.1 mrg struct isl_fold_substitute *data = user; 1779 1.1 mrg 1780 1.1 mrg qp = isl_qpolynomial_substitute(qp, 1781 1.1 mrg data->type, data->first, data->n, data->subs); 1782 1.1 mrg return qp; 1783 1.1 mrg } 1784 1.1 mrg 1785 1.1 mrg /* For each 0 <= i < "n", replace variable "first" + i of type "type" 1786 1.1 mrg * in fold->qp[k] by subs[i]. 1787 1.1 mrg */ 1788 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute( 1789 1.1 mrg __isl_take isl_qpolynomial_fold *fold, 1790 1.1 mrg enum isl_dim_type type, unsigned first, unsigned n, 1791 1.1 mrg __isl_keep isl_qpolynomial **subs) 1792 1.1 mrg { 1793 1.1 mrg struct isl_fold_substitute data = { type, first, n, subs }; 1794 1.1 mrg isl_qpolynomial_list *list; 1795 1.1 mrg 1796 1.1 mrg if (n == 0) 1797 1.1 mrg return fold; 1798 1.1 mrg 1799 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 1800 1.1 mrg list = isl_qpolynomial_list_map(list, &substitute, &data); 1801 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 1802 1.1 mrg 1803 1.1 mrg return fold; 1804 1.1 mrg } 1805 1.1 mrg 1806 1.1 mrg static isl_stat add_pwqp(__isl_take isl_pw_qpolynomial *pwqp, void *user) 1807 1.1 mrg { 1808 1.1 mrg isl_pw_qpolynomial_fold *pwf; 1809 1.1 mrg isl_union_pw_qpolynomial_fold **upwf; 1810 1.1 mrg struct isl_hash_table_entry *entry; 1811 1.1 mrg 1812 1.1 mrg upwf = (isl_union_pw_qpolynomial_fold **)user; 1813 1.1 mrg 1814 1.1 mrg entry = isl_union_pw_qpolynomial_fold_find_part_entry(*upwf, 1815 1.1 mrg pwqp->dim, 1); 1816 1.1 mrg if (!entry) 1817 1.1 mrg goto error; 1818 1.1 mrg 1819 1.1 mrg pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial((*upwf)->type, pwqp); 1820 1.1 mrg if (!entry->data) 1821 1.1 mrg entry->data = pwf; 1822 1.1 mrg else { 1823 1.1 mrg entry->data = isl_pw_qpolynomial_fold_add(entry->data, pwf); 1824 1.1 mrg if (!entry->data) 1825 1.1 mrg return isl_stat_error; 1826 1.1 mrg if (isl_pw_qpolynomial_fold_is_zero(entry->data)) 1827 1.1 mrg *upwf = isl_union_pw_qpolynomial_fold_remove_part_entry( 1828 1.1 mrg *upwf, entry); 1829 1.1 mrg } 1830 1.1 mrg 1831 1.1 mrg return isl_stat_ok; 1832 1.1 mrg error: 1833 1.1 mrg isl_pw_qpolynomial_free(pwqp); 1834 1.1 mrg return isl_stat_error; 1835 1.1 mrg } 1836 1.1 mrg 1837 1.1 mrg __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial( 1838 1.1 mrg __isl_take isl_union_pw_qpolynomial_fold *upwf, 1839 1.1 mrg __isl_take isl_union_pw_qpolynomial *upwqp) 1840 1.1 mrg { 1841 1.1 mrg upwf = isl_union_pw_qpolynomial_fold_align_params(upwf, 1842 1.1 mrg isl_union_pw_qpolynomial_get_space(upwqp)); 1843 1.1 mrg upwqp = isl_union_pw_qpolynomial_align_params(upwqp, 1844 1.1 mrg isl_union_pw_qpolynomial_fold_get_space(upwf)); 1845 1.1 mrg 1846 1.1 mrg upwf = isl_union_pw_qpolynomial_fold_cow(upwf); 1847 1.1 mrg if (!upwf || !upwqp) 1848 1.1 mrg goto error; 1849 1.1 mrg 1850 1.1 mrg if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &add_pwqp, 1851 1.1 mrg &upwf) < 0) 1852 1.1 mrg goto error; 1853 1.1 mrg 1854 1.1 mrg isl_union_pw_qpolynomial_free(upwqp); 1855 1.1 mrg 1856 1.1 mrg return upwf; 1857 1.1 mrg error: 1858 1.1 mrg isl_union_pw_qpolynomial_fold_free(upwf); 1859 1.1 mrg isl_union_pw_qpolynomial_free(upwqp); 1860 1.1 mrg return NULL; 1861 1.1 mrg } 1862 1.1 mrg 1863 1.1 mrg static isl_bool join_compatible(__isl_keep isl_space *space1, 1864 1.1 mrg __isl_keep isl_space *space2) 1865 1.1 mrg { 1866 1.1 mrg isl_bool m; 1867 1.1 mrg m = isl_space_has_equal_params(space1, space2); 1868 1.1 mrg if (m < 0 || !m) 1869 1.1 mrg return m; 1870 1.1 mrg return isl_space_tuple_is_equal(space1, isl_dim_out, 1871 1.1 mrg space2, isl_dim_in); 1872 1.1 mrg } 1873 1.1 mrg 1874 1.1 mrg /* Compute the intersection of the range of the map and the domain 1875 1.1 mrg * of the piecewise quasipolynomial reduction and then compute a bound 1876 1.1 mrg * on the associated quasipolynomial reduction over all elements 1877 1.1 mrg * in this intersection. 1878 1.1 mrg * 1879 1.1 mrg * We first introduce some unconstrained dimensions in the 1880 1.1 mrg * piecewise quasipolynomial, intersect the resulting domain 1881 1.1 mrg * with the wrapped map and the compute the sum. 1882 1.1 mrg */ 1883 1.1 mrg __isl_give isl_pw_qpolynomial_fold *isl_map_apply_pw_qpolynomial_fold( 1884 1.1 mrg __isl_take isl_map *map, __isl_take isl_pw_qpolynomial_fold *pwf, 1885 1.1 mrg isl_bool *tight) 1886 1.1 mrg { 1887 1.1 mrg isl_ctx *ctx; 1888 1.1 mrg isl_set *dom; 1889 1.1 mrg isl_space *map_space; 1890 1.1 mrg isl_space *pwf_space; 1891 1.1 mrg isl_size n_in; 1892 1.1 mrg isl_bool ok; 1893 1.1 mrg 1894 1.1 mrg ctx = isl_map_get_ctx(map); 1895 1.1 mrg if (!ctx) 1896 1.1 mrg goto error; 1897 1.1 mrg 1898 1.1 mrg map_space = isl_map_get_space(map); 1899 1.1 mrg pwf_space = isl_pw_qpolynomial_fold_get_space(pwf); 1900 1.1 mrg ok = join_compatible(map_space, pwf_space); 1901 1.1 mrg isl_space_free(map_space); 1902 1.1 mrg isl_space_free(pwf_space); 1903 1.1 mrg if (ok < 0) 1904 1.1 mrg goto error; 1905 1.1 mrg if (!ok) 1906 1.1 mrg isl_die(ctx, isl_error_invalid, "incompatible dimensions", 1907 1.1 mrg goto error); 1908 1.1 mrg 1909 1.1 mrg n_in = isl_map_dim(map, isl_dim_in); 1910 1.1 mrg if (n_in < 0) 1911 1.1 mrg goto error; 1912 1.1 mrg pwf = isl_pw_qpolynomial_fold_insert_dims(pwf, isl_dim_in, 0, n_in); 1913 1.1 mrg 1914 1.1 mrg dom = isl_map_wrap(map); 1915 1.1 mrg pwf = isl_pw_qpolynomial_fold_reset_domain_space(pwf, 1916 1.1 mrg isl_set_get_space(dom)); 1917 1.1 mrg 1918 1.1 mrg pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, dom); 1919 1.1 mrg pwf = isl_pw_qpolynomial_fold_bound(pwf, tight); 1920 1.1 mrg 1921 1.1 mrg return pwf; 1922 1.1 mrg error: 1923 1.1 mrg isl_map_free(map); 1924 1.1 mrg isl_pw_qpolynomial_fold_free(pwf); 1925 1.1 mrg return NULL; 1926 1.1 mrg } 1927 1.1 mrg 1928 1.1 mrg __isl_give isl_pw_qpolynomial_fold *isl_set_apply_pw_qpolynomial_fold( 1929 1.1 mrg __isl_take isl_set *set, __isl_take isl_pw_qpolynomial_fold *pwf, 1930 1.1 mrg isl_bool *tight) 1931 1.1 mrg { 1932 1.1 mrg return isl_map_apply_pw_qpolynomial_fold(set, pwf, tight); 1933 1.1 mrg } 1934 1.1 mrg 1935 1.1 mrg struct isl_apply_fold_data { 1936 1.1 mrg isl_union_pw_qpolynomial_fold *upwf; 1937 1.1 mrg isl_union_pw_qpolynomial_fold *res; 1938 1.1 mrg isl_map *map; 1939 1.1 mrg isl_bool tight; 1940 1.1 mrg }; 1941 1.1 mrg 1942 1.1 mrg static isl_stat pw_qpolynomial_fold_apply( 1943 1.1 mrg __isl_take isl_pw_qpolynomial_fold *pwf, void *user) 1944 1.1 mrg { 1945 1.1 mrg isl_space *map_dim; 1946 1.1 mrg isl_space *pwf_dim; 1947 1.1 mrg struct isl_apply_fold_data *data = user; 1948 1.1 mrg isl_bool ok; 1949 1.1 mrg 1950 1.1 mrg map_dim = isl_map_get_space(data->map); 1951 1.1 mrg pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf); 1952 1.1 mrg ok = join_compatible(map_dim, pwf_dim); 1953 1.1 mrg isl_space_free(map_dim); 1954 1.1 mrg isl_space_free(pwf_dim); 1955 1.1 mrg 1956 1.1 mrg if (ok < 0) 1957 1.1 mrg return isl_stat_error; 1958 1.1 mrg if (ok) { 1959 1.1 mrg pwf = isl_map_apply_pw_qpolynomial_fold(isl_map_copy(data->map), 1960 1.1 mrg pwf, data->tight ? &data->tight : NULL); 1961 1.1 mrg data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold( 1962 1.1 mrg data->res, pwf); 1963 1.1 mrg } else 1964 1.1 mrg isl_pw_qpolynomial_fold_free(pwf); 1965 1.1 mrg 1966 1.1 mrg return isl_stat_ok; 1967 1.1 mrg } 1968 1.1 mrg 1969 1.1 mrg static isl_stat map_apply(__isl_take isl_map *map, void *user) 1970 1.1 mrg { 1971 1.1 mrg struct isl_apply_fold_data *data = user; 1972 1.1 mrg isl_stat r; 1973 1.1 mrg 1974 1.1 mrg data->map = map; 1975 1.1 mrg r = isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold( 1976 1.1 mrg data->upwf, &pw_qpolynomial_fold_apply, data); 1977 1.1 mrg 1978 1.1 mrg isl_map_free(map); 1979 1.1 mrg return r; 1980 1.1 mrg } 1981 1.1 mrg 1982 1.1 mrg __isl_give isl_union_pw_qpolynomial_fold *isl_union_map_apply_union_pw_qpolynomial_fold( 1983 1.1 mrg __isl_take isl_union_map *umap, 1984 1.1 mrg __isl_take isl_union_pw_qpolynomial_fold *upwf, isl_bool *tight) 1985 1.1 mrg { 1986 1.1 mrg isl_space *space; 1987 1.1 mrg enum isl_fold type; 1988 1.1 mrg struct isl_apply_fold_data data; 1989 1.1 mrg 1990 1.1 mrg upwf = isl_union_pw_qpolynomial_fold_align_params(upwf, 1991 1.1 mrg isl_union_map_get_space(umap)); 1992 1.1 mrg umap = isl_union_map_align_params(umap, 1993 1.1 mrg isl_union_pw_qpolynomial_fold_get_space(upwf)); 1994 1.1 mrg 1995 1.1 mrg data.upwf = upwf; 1996 1.1 mrg data.tight = tight ? isl_bool_true : isl_bool_false; 1997 1.1 mrg space = isl_union_pw_qpolynomial_fold_get_space(upwf); 1998 1.1 mrg type = isl_union_pw_qpolynomial_fold_get_type(upwf); 1999 1.1 mrg data.res = isl_union_pw_qpolynomial_fold_zero(space, type); 2000 1.1 mrg if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0) 2001 1.1 mrg goto error; 2002 1.1 mrg 2003 1.1 mrg isl_union_map_free(umap); 2004 1.1 mrg isl_union_pw_qpolynomial_fold_free(upwf); 2005 1.1 mrg 2006 1.1 mrg if (tight) 2007 1.1 mrg *tight = data.tight; 2008 1.1 mrg 2009 1.1 mrg return data.res; 2010 1.1 mrg error: 2011 1.1 mrg isl_union_map_free(umap); 2012 1.1 mrg isl_union_pw_qpolynomial_fold_free(upwf); 2013 1.1 mrg isl_union_pw_qpolynomial_fold_free(data.res); 2014 1.1 mrg return NULL; 2015 1.1 mrg } 2016 1.1 mrg 2017 1.1 mrg __isl_give isl_union_pw_qpolynomial_fold *isl_union_set_apply_union_pw_qpolynomial_fold( 2018 1.1 mrg __isl_take isl_union_set *uset, 2019 1.1 mrg __isl_take isl_union_pw_qpolynomial_fold *upwf, isl_bool *tight) 2020 1.1 mrg { 2021 1.1 mrg return isl_union_map_apply_union_pw_qpolynomial_fold(uset, upwf, tight); 2022 1.1 mrg } 2023 1.1 mrg 2024 1.1 mrg /* isl_qpolynomial_list_map callback for calling 2025 1.1 mrg * isl_qpolynomial_realign_domain on "qp". 2026 1.1 mrg */ 2027 1.1 mrg static __isl_give isl_qpolynomial *realign_domain( 2028 1.1 mrg __isl_take isl_qpolynomial *qp, void *user) 2029 1.1 mrg { 2030 1.1 mrg isl_reordering *r = user; 2031 1.1 mrg 2032 1.1 mrg qp = isl_qpolynomial_realign_domain(qp, isl_reordering_copy(r)); 2033 1.1 mrg return qp; 2034 1.1 mrg } 2035 1.1 mrg 2036 1.1 mrg /* Reorder the dimension of "fold" according to the given reordering. 2037 1.1 mrg */ 2038 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain( 2039 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r) 2040 1.1 mrg { 2041 1.1 mrg isl_space *space; 2042 1.1 mrg isl_qpolynomial_list *list; 2043 1.1 mrg 2044 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 2045 1.1 mrg list = isl_qpolynomial_list_map(list, &realign_domain, r); 2046 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 2047 1.1 mrg 2048 1.1 mrg space = isl_reordering_get_space(r); 2049 1.1 mrg fold = isl_qpolynomial_fold_reset_domain_space(fold, space); 2050 1.1 mrg 2051 1.1 mrg isl_reordering_free(r); 2052 1.1 mrg 2053 1.1 mrg return fold; 2054 1.1 mrg } 2055 1.1 mrg 2056 1.1 mrg /* isl_qpolynomial_list_map callback for calling 2057 1.1 mrg * isl_qpolynomial_mul_isl_int on "qp". 2058 1.1 mrg */ 2059 1.1 mrg static __isl_give isl_qpolynomial *mul_int(__isl_take isl_qpolynomial *qp, 2060 1.1 mrg void *user) 2061 1.1 mrg { 2062 1.1 mrg isl_int *v = user; 2063 1.1 mrg 2064 1.1 mrg qp = isl_qpolynomial_mul_isl_int(qp, *v); 2065 1.1 mrg return qp; 2066 1.1 mrg } 2067 1.1 mrg 2068 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int( 2069 1.1 mrg __isl_take isl_qpolynomial_fold *fold, isl_int v) 2070 1.1 mrg { 2071 1.1 mrg isl_qpolynomial_list *list; 2072 1.1 mrg 2073 1.1 mrg if (isl_int_is_one(v)) 2074 1.1 mrg return fold; 2075 1.1 mrg if (fold && isl_int_is_zero(v)) { 2076 1.1 mrg isl_qpolynomial_fold *zero; 2077 1.1 mrg isl_space *space = isl_space_copy(fold->dim); 2078 1.1 mrg zero = isl_qpolynomial_fold_empty(fold->type, space); 2079 1.1 mrg isl_qpolynomial_fold_free(fold); 2080 1.1 mrg return zero; 2081 1.1 mrg } 2082 1.1 mrg 2083 1.1 mrg fold = isl_qpolynomial_fold_cow(fold); 2084 1.1 mrg if (!fold) 2085 1.1 mrg return NULL; 2086 1.1 mrg 2087 1.1 mrg if (isl_int_is_neg(v)) 2088 1.1 mrg fold->type = isl_fold_type_negate(fold->type); 2089 1.1 mrg 2090 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 2091 1.1 mrg list = isl_qpolynomial_list_map(list, &mul_int, &v); 2092 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 2093 1.1 mrg 2094 1.1 mrg return fold; 2095 1.1 mrg } 2096 1.1 mrg 2097 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale( 2098 1.1 mrg __isl_take isl_qpolynomial_fold *fold, isl_int v) 2099 1.1 mrg { 2100 1.1 mrg return isl_qpolynomial_fold_mul_isl_int(fold, v); 2101 1.1 mrg } 2102 1.1 mrg 2103 1.1 mrg /* isl_qpolynomial_list_map callback for calling 2104 1.1 mrg * isl_qpolynomial_scale_val on "qp". 2105 1.1 mrg */ 2106 1.1 mrg static __isl_give isl_qpolynomial *scale_val(__isl_take isl_qpolynomial *qp, 2107 1.1 mrg void *user) 2108 1.1 mrg { 2109 1.1 mrg isl_val *v = user; 2110 1.1 mrg 2111 1.1 mrg qp = isl_qpolynomial_scale_val(qp, isl_val_copy(v)); 2112 1.1 mrg return qp; 2113 1.1 mrg } 2114 1.1 mrg 2115 1.1 mrg /* Multiply "fold" by "v". 2116 1.1 mrg */ 2117 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_val( 2118 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v) 2119 1.1 mrg { 2120 1.1 mrg isl_qpolynomial_list *list; 2121 1.1 mrg 2122 1.1 mrg if (!fold || !v) 2123 1.1 mrg goto error; 2124 1.1 mrg 2125 1.1 mrg if (isl_val_is_one(v)) { 2126 1.1 mrg isl_val_free(v); 2127 1.1 mrg return fold; 2128 1.1 mrg } 2129 1.1 mrg if (isl_val_is_zero(v)) { 2130 1.1 mrg isl_qpolynomial_fold *zero; 2131 1.1 mrg isl_space *space = isl_qpolynomial_fold_get_domain_space(fold); 2132 1.1 mrg zero = isl_qpolynomial_fold_empty(fold->type, space); 2133 1.1 mrg isl_qpolynomial_fold_free(fold); 2134 1.1 mrg isl_val_free(v); 2135 1.1 mrg return zero; 2136 1.1 mrg } 2137 1.1 mrg if (!isl_val_is_rat(v)) 2138 1.1 mrg isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid, 2139 1.1 mrg "expecting rational factor", goto error); 2140 1.1 mrg 2141 1.1 mrg fold = isl_qpolynomial_fold_cow(fold); 2142 1.1 mrg if (!fold) 2143 1.1 mrg goto error; 2144 1.1 mrg 2145 1.1 mrg if (isl_val_is_neg(v)) 2146 1.1 mrg fold->type = isl_fold_type_negate(fold->type); 2147 1.1 mrg 2148 1.1 mrg list = isl_qpolynomial_fold_take_list(fold); 2149 1.1 mrg list = isl_qpolynomial_list_map(list, &scale_val, v); 2150 1.1 mrg fold = isl_qpolynomial_fold_restore_list(fold, list); 2151 1.1 mrg 2152 1.1 mrg isl_val_free(v); 2153 1.1 mrg return fold; 2154 1.1 mrg error: 2155 1.1 mrg isl_val_free(v); 2156 1.1 mrg isl_qpolynomial_fold_free(fold); 2157 1.1 mrg return NULL; 2158 1.1 mrg } 2159 1.1 mrg 2160 1.1 mrg /* Divide "fold" by "v". 2161 1.1 mrg */ 2162 1.1 mrg __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_down_val( 2163 1.1 mrg __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v) 2164 1.1 mrg { 2165 1.1 mrg if (!fold || !v) 2166 1.1 mrg goto error; 2167 1.1 mrg 2168 1.1 mrg if (isl_val_is_one(v)) { 2169 1.1 mrg isl_val_free(v); 2170 1.1 mrg return fold; 2171 1.1 mrg } 2172 1.1 mrg if (!isl_val_is_rat(v)) 2173 1.1 mrg isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid, 2174 1.1 mrg "expecting rational factor", goto error); 2175 1.1 mrg if (isl_val_is_zero(v)) 2176 1.1 mrg isl_die(isl_val_get_ctx(v), isl_error_invalid, 2177 1.1 mrg "cannot scale down by zero", goto error); 2178 1.1 mrg 2179 1.1 mrg return isl_qpolynomial_fold_scale_val(fold, isl_val_inv(v)); 2180 1.1 mrg error: 2181 1.1 mrg isl_val_free(v); 2182 1.1 mrg isl_qpolynomial_fold_free(fold); 2183 1.1 mrg return NULL; 2184 1.1 mrg } 2185