Line data Source code
1 : /*
2 : * Copyright 2010 INRIA Saclay
3 : *
4 : * Use of this software is governed by the MIT license
5 : *
6 : * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
7 : * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
8 : * 91893 Orsay, France
9 : */
10 :
11 : #include <isl_map_private.h>
12 : #include <isl_union_map_private.h>
13 : #include <isl_polynomial_private.h>
14 : #include <isl_point_private.h>
15 : #include <isl_space_private.h>
16 : #include <isl_lp_private.h>
17 : #include <isl_seq.h>
18 : #include <isl_mat_private.h>
19 : #include <isl_val_private.h>
20 : #include <isl_vec_private.h>
21 : #include <isl_config.h>
22 :
23 : #undef BASE
24 : #define BASE pw_qpolynomial_fold
25 :
26 : #include <isl_list_templ.c>
27 :
28 0 : enum isl_fold isl_fold_type_negate(enum isl_fold type)
29 : {
30 0 : switch (type) {
31 : case isl_fold_min:
32 0 : return isl_fold_max;
33 : case isl_fold_max:
34 0 : return isl_fold_min;
35 : case isl_fold_list:
36 0 : return isl_fold_list;
37 : }
38 :
39 0 : isl_die(NULL, isl_error_internal, "unhandled isl_fold type", abort());
40 : }
41 :
42 0 : static __isl_give isl_qpolynomial_fold *qpolynomial_fold_alloc(
43 : enum isl_fold type, __isl_take isl_space *dim, int n)
44 : {
45 : isl_qpolynomial_fold *fold;
46 :
47 0 : if (!dim)
48 0 : goto error;
49 :
50 0 : isl_assert(dim->ctx, n >= 0, goto error);
51 0 : fold = isl_calloc(dim->ctx, struct isl_qpolynomial_fold,
52 : sizeof(struct isl_qpolynomial_fold) +
53 : (n - 1) * sizeof(struct isl_qpolynomial *));
54 0 : if (!fold)
55 0 : goto error;
56 :
57 0 : fold->ref = 1;
58 0 : fold->size = n;
59 0 : fold->n = 0;
60 0 : fold->type = type;
61 0 : fold->dim = dim;
62 :
63 0 : return fold;
64 : error:
65 0 : isl_space_free(dim);
66 0 : return NULL;
67 : }
68 :
69 0 : isl_ctx *isl_qpolynomial_fold_get_ctx(__isl_keep isl_qpolynomial_fold *fold)
70 : {
71 0 : return fold ? fold->dim->ctx : NULL;
72 : }
73 :
74 0 : __isl_give isl_space *isl_qpolynomial_fold_get_domain_space(
75 : __isl_keep isl_qpolynomial_fold *fold)
76 : {
77 0 : return fold ? isl_space_copy(fold->dim) : NULL;
78 : }
79 :
80 0 : __isl_give isl_space *isl_qpolynomial_fold_get_space(
81 : __isl_keep isl_qpolynomial_fold *fold)
82 : {
83 : isl_space *space;
84 0 : if (!fold)
85 0 : return NULL;
86 0 : space = isl_space_copy(fold->dim);
87 0 : space = isl_space_from_domain(space);
88 0 : space = isl_space_add_dims(space, isl_dim_out, 1);
89 0 : return space;
90 : }
91 :
92 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space(
93 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim)
94 : {
95 : int i;
96 :
97 0 : fold = isl_qpolynomial_fold_cow(fold);
98 0 : if (!fold || !dim)
99 : goto error;
100 :
101 0 : for (i = 0; i < fold->n; ++i) {
102 0 : fold->qp[i] = isl_qpolynomial_reset_domain_space(fold->qp[i],
103 : isl_space_copy(dim));
104 0 : if (!fold->qp[i])
105 0 : goto error;
106 : }
107 :
108 0 : isl_space_free(fold->dim);
109 0 : fold->dim = dim;
110 :
111 0 : return fold;
112 : error:
113 0 : isl_qpolynomial_fold_free(fold);
114 0 : isl_space_free(dim);
115 0 : return NULL;
116 : }
117 :
118 : /* Reset the space of "fold". This function is called from isl_pw_templ.c
119 : * and doesn't know if the space of an element object is represented
120 : * directly or through its domain. It therefore passes along both.
121 : */
122 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_space_and_domain(
123 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space,
124 : __isl_take isl_space *domain)
125 : {
126 0 : isl_space_free(space);
127 0 : return isl_qpolynomial_fold_reset_domain_space(fold, domain);
128 : }
129 :
130 0 : int isl_qpolynomial_fold_involves_dims(__isl_keep isl_qpolynomial_fold *fold,
131 : enum isl_dim_type type, unsigned first, unsigned n)
132 : {
133 : int i;
134 :
135 0 : if (!fold)
136 0 : return -1;
137 0 : if (fold->n == 0 || n == 0)
138 0 : return 0;
139 :
140 0 : for (i = 0; i < fold->n; ++i) {
141 0 : int involves = isl_qpolynomial_involves_dims(fold->qp[i],
142 : type, first, n);
143 0 : if (involves < 0 || involves)
144 0 : return involves;
145 : }
146 0 : return 0;
147 : }
148 :
149 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_set_dim_name(
150 : __isl_take isl_qpolynomial_fold *fold,
151 : enum isl_dim_type type, unsigned pos, const char *s)
152 : {
153 : int i;
154 :
155 0 : fold = isl_qpolynomial_fold_cow(fold);
156 0 : if (!fold)
157 0 : return NULL;
158 0 : fold->dim = isl_space_set_dim_name(fold->dim, type, pos, s);
159 0 : if (!fold->dim)
160 0 : goto error;
161 :
162 0 : for (i = 0; i < fold->n; ++i) {
163 0 : fold->qp[i] = isl_qpolynomial_set_dim_name(fold->qp[i],
164 : type, pos, s);
165 0 : if (!fold->qp[i])
166 0 : goto error;
167 : }
168 :
169 0 : return fold;
170 : error:
171 0 : isl_qpolynomial_fold_free(fold);
172 0 : return NULL;
173 : }
174 :
175 : /* Given a dimension type for an isl_qpolynomial_fold,
176 : * return the corresponding type for the domain.
177 : */
178 0 : static enum isl_dim_type domain_type(enum isl_dim_type type)
179 : {
180 0 : if (type == isl_dim_in)
181 0 : return isl_dim_set;
182 0 : return type;
183 : }
184 :
185 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_drop_dims(
186 : __isl_take isl_qpolynomial_fold *fold,
187 : enum isl_dim_type type, unsigned first, unsigned n)
188 : {
189 : int i;
190 : enum isl_dim_type set_type;
191 :
192 0 : if (!fold)
193 0 : return NULL;
194 0 : if (n == 0)
195 0 : return fold;
196 :
197 0 : set_type = domain_type(type);
198 :
199 0 : fold = isl_qpolynomial_fold_cow(fold);
200 0 : if (!fold)
201 0 : return NULL;
202 0 : fold->dim = isl_space_drop_dims(fold->dim, set_type, first, n);
203 0 : if (!fold->dim)
204 0 : goto error;
205 :
206 0 : for (i = 0; i < fold->n; ++i) {
207 0 : fold->qp[i] = isl_qpolynomial_drop_dims(fold->qp[i],
208 : type, first, n);
209 0 : if (!fold->qp[i])
210 0 : goto error;
211 : }
212 :
213 0 : return fold;
214 : error:
215 0 : isl_qpolynomial_fold_free(fold);
216 0 : return NULL;
217 : }
218 :
219 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_insert_dims(
220 : __isl_take isl_qpolynomial_fold *fold,
221 : enum isl_dim_type type, unsigned first, unsigned n)
222 : {
223 : int i;
224 :
225 0 : if (!fold)
226 0 : return NULL;
227 0 : if (n == 0 && !isl_space_is_named_or_nested(fold->dim, type))
228 0 : return fold;
229 :
230 0 : fold = isl_qpolynomial_fold_cow(fold);
231 0 : if (!fold)
232 0 : return NULL;
233 0 : fold->dim = isl_space_insert_dims(fold->dim, type, first, n);
234 0 : if (!fold->dim)
235 0 : goto error;
236 :
237 0 : for (i = 0; i < fold->n; ++i) {
238 0 : fold->qp[i] = isl_qpolynomial_insert_dims(fold->qp[i],
239 : type, first, n);
240 0 : if (!fold->qp[i])
241 0 : goto error;
242 : }
243 :
244 0 : return fold;
245 : error:
246 0 : isl_qpolynomial_fold_free(fold);
247 0 : return NULL;
248 : }
249 :
250 : /* Determine the sign of the constant quasipolynomial "qp".
251 : *
252 : * Return
253 : * -1 if qp <= 0
254 : * 1 if qp >= 0
255 : * 0 if unknown
256 : *
257 : * For qp == 0, we can return either -1 or 1. In practice, we return 1.
258 : * For qp == NaN, the sign is undefined, so we return 0.
259 : */
260 0 : static int isl_qpolynomial_cst_sign(__isl_keep isl_qpolynomial *qp)
261 : {
262 : struct isl_upoly_cst *cst;
263 :
264 0 : if (isl_qpolynomial_is_nan(qp))
265 0 : return 0;
266 :
267 0 : cst = isl_upoly_as_cst(qp->upoly);
268 0 : if (!cst)
269 0 : return 0;
270 :
271 0 : return isl_int_sgn(cst->n) < 0 ? -1 : 1;
272 : }
273 :
274 0 : static int isl_qpolynomial_aff_sign(__isl_keep isl_set *set,
275 : __isl_keep isl_qpolynomial *qp)
276 : {
277 : enum isl_lp_result res;
278 : isl_vec *aff;
279 : isl_int opt;
280 0 : int sgn = 0;
281 :
282 0 : aff = isl_qpolynomial_extract_affine(qp);
283 0 : if (!aff)
284 0 : return 0;
285 :
286 0 : isl_int_init(opt);
287 :
288 0 : res = isl_set_solve_lp(set, 0, aff->el + 1, aff->el[0],
289 : &opt, NULL, NULL);
290 0 : if (res == isl_lp_error)
291 0 : goto done;
292 0 : if (res == isl_lp_empty ||
293 0 : (res == isl_lp_ok && !isl_int_is_neg(opt))) {
294 0 : sgn = 1;
295 0 : goto done;
296 : }
297 :
298 0 : res = isl_set_solve_lp(set, 1, aff->el + 1, aff->el[0],
299 : &opt, NULL, NULL);
300 0 : if (res == isl_lp_ok && !isl_int_is_pos(opt))
301 0 : sgn = -1;
302 :
303 : done:
304 0 : isl_int_clear(opt);
305 0 : isl_vec_free(aff);
306 0 : return sgn;
307 : }
308 :
309 : /* Determine, if possible, the sign of the quasipolynomial "qp" on
310 : * the domain "set".
311 : *
312 : * If qp is a constant, then the problem is trivial.
313 : * If qp is linear, then we check if the minimum of the corresponding
314 : * affine constraint is non-negative or if the maximum is non-positive.
315 : *
316 : * Otherwise, we check if the outermost variable "v" has a lower bound "l"
317 : * in "set". If so, we write qp(v,v') as
318 : *
319 : * q(v,v') * (v - l) + r(v')
320 : *
321 : * if q(v,v') and r(v') have the same known sign, then the original
322 : * quasipolynomial has the same sign as well.
323 : *
324 : * Return
325 : * -1 if qp <= 0
326 : * 1 if qp >= 0
327 : * 0 if unknown
328 : */
329 0 : static int isl_qpolynomial_sign(__isl_keep isl_set *set,
330 : __isl_keep isl_qpolynomial *qp)
331 : {
332 : int d;
333 : int i;
334 : int is;
335 : struct isl_upoly_rec *rec;
336 : isl_vec *v;
337 : isl_int l;
338 : enum isl_lp_result res;
339 0 : int sgn = 0;
340 :
341 0 : is = isl_qpolynomial_is_cst(qp, NULL, NULL);
342 0 : if (is < 0)
343 0 : return 0;
344 0 : if (is)
345 0 : return isl_qpolynomial_cst_sign(qp);
346 :
347 0 : is = isl_qpolynomial_is_affine(qp);
348 0 : if (is < 0)
349 0 : return 0;
350 0 : if (is)
351 0 : return isl_qpolynomial_aff_sign(set, qp);
352 :
353 0 : if (qp->div->n_row > 0)
354 0 : return 0;
355 :
356 0 : rec = isl_upoly_as_rec(qp->upoly);
357 0 : if (!rec)
358 0 : return 0;
359 :
360 0 : d = isl_space_dim(qp->dim, isl_dim_all);
361 0 : v = isl_vec_alloc(set->ctx, 2 + d);
362 0 : if (!v)
363 0 : return 0;
364 :
365 0 : isl_seq_clr(v->el + 1, 1 + d);
366 0 : isl_int_set_si(v->el[0], 1);
367 0 : isl_int_set_si(v->el[2 + qp->upoly->var], 1);
368 :
369 0 : isl_int_init(l);
370 :
371 0 : res = isl_set_solve_lp(set, 0, v->el + 1, v->el[0], &l, NULL, NULL);
372 0 : if (res == isl_lp_ok) {
373 : isl_qpolynomial *min;
374 : isl_qpolynomial *base;
375 : isl_qpolynomial *r, *q;
376 : isl_qpolynomial *t;
377 :
378 0 : min = isl_qpolynomial_cst_on_domain(isl_space_copy(qp->dim), l);
379 0 : base = isl_qpolynomial_var_pow_on_domain(isl_space_copy(qp->dim),
380 0 : qp->upoly->var, 1);
381 :
382 0 : r = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0,
383 0 : isl_upoly_copy(rec->p[rec->n - 1]));
384 0 : q = isl_qpolynomial_copy(r);
385 :
386 0 : for (i = rec->n - 2; i >= 0; --i) {
387 0 : r = isl_qpolynomial_mul(r, isl_qpolynomial_copy(min));
388 0 : t = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0,
389 : isl_upoly_copy(rec->p[i]));
390 0 : r = isl_qpolynomial_add(r, t);
391 0 : if (i == 0)
392 0 : break;
393 0 : q = isl_qpolynomial_mul(q, isl_qpolynomial_copy(base));
394 0 : q = isl_qpolynomial_add(q, isl_qpolynomial_copy(r));
395 : }
396 :
397 0 : if (isl_qpolynomial_is_zero(q))
398 0 : sgn = isl_qpolynomial_sign(set, r);
399 0 : else if (isl_qpolynomial_is_zero(r))
400 0 : sgn = isl_qpolynomial_sign(set, q);
401 : else {
402 : int sgn_q, sgn_r;
403 0 : sgn_r = isl_qpolynomial_sign(set, r);
404 0 : sgn_q = isl_qpolynomial_sign(set, q);
405 0 : if (sgn_r == sgn_q)
406 0 : sgn = sgn_r;
407 : }
408 :
409 0 : isl_qpolynomial_free(min);
410 0 : isl_qpolynomial_free(base);
411 0 : isl_qpolynomial_free(q);
412 0 : isl_qpolynomial_free(r);
413 : }
414 :
415 0 : isl_int_clear(l);
416 :
417 0 : isl_vec_free(v);
418 :
419 0 : return sgn;
420 : }
421 :
422 : /* Combine "fold1" and "fold2" into a single reduction, eliminating
423 : * those elements of one reduction that are already covered by the other
424 : * reduction on "set".
425 : *
426 : * If "fold1" or "fold2" is an empty reduction, then return
427 : * the other reduction.
428 : * If "fold1" or "fold2" is a NaN, then return this NaN.
429 : */
430 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain(
431 : __isl_keep isl_set *set,
432 : __isl_take isl_qpolynomial_fold *fold1,
433 : __isl_take isl_qpolynomial_fold *fold2)
434 : {
435 : int i, j;
436 : int n1;
437 0 : struct isl_qpolynomial_fold *res = NULL;
438 : int better;
439 :
440 0 : if (!fold1 || !fold2)
441 : goto error;
442 :
443 0 : isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error);
444 0 : isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim),
445 : goto error);
446 :
447 0 : better = fold1->type == isl_fold_max ? -1 : 1;
448 :
449 0 : if (isl_qpolynomial_fold_is_empty(fold1) ||
450 0 : isl_qpolynomial_fold_is_nan(fold2)) {
451 0 : isl_qpolynomial_fold_free(fold1);
452 0 : return fold2;
453 : }
454 :
455 0 : if (isl_qpolynomial_fold_is_empty(fold2) ||
456 0 : isl_qpolynomial_fold_is_nan(fold1)) {
457 0 : isl_qpolynomial_fold_free(fold2);
458 0 : return fold1;
459 : }
460 :
461 0 : res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim),
462 0 : fold1->n + fold2->n);
463 0 : if (!res)
464 0 : goto error;
465 :
466 0 : for (i = 0; i < fold1->n; ++i) {
467 0 : res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]);
468 0 : if (!res->qp[res->n])
469 0 : goto error;
470 0 : res->n++;
471 : }
472 0 : n1 = res->n;
473 :
474 0 : for (i = 0; i < fold2->n; ++i) {
475 0 : for (j = n1 - 1; j >= 0; --j) {
476 : isl_qpolynomial *d;
477 : int sgn, equal;
478 0 : equal = isl_qpolynomial_plain_is_equal(res->qp[j],
479 0 : fold2->qp[i]);
480 0 : if (equal < 0)
481 0 : goto error;
482 0 : if (equal)
483 0 : break;
484 0 : d = isl_qpolynomial_sub(
485 0 : isl_qpolynomial_copy(res->qp[j]),
486 0 : isl_qpolynomial_copy(fold2->qp[i]));
487 0 : sgn = isl_qpolynomial_sign(set, d);
488 0 : isl_qpolynomial_free(d);
489 0 : if (sgn == 0)
490 0 : continue;
491 0 : if (sgn != better)
492 0 : break;
493 0 : isl_qpolynomial_free(res->qp[j]);
494 0 : if (j != n1 - 1)
495 0 : res->qp[j] = res->qp[n1 - 1];
496 0 : n1--;
497 0 : if (n1 != res->n - 1)
498 0 : res->qp[n1] = res->qp[res->n - 1];
499 0 : res->n--;
500 : }
501 0 : if (j >= 0)
502 0 : continue;
503 0 : res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]);
504 0 : if (!res->qp[res->n])
505 0 : goto error;
506 0 : res->n++;
507 : }
508 :
509 0 : isl_qpolynomial_fold_free(fold1);
510 0 : isl_qpolynomial_fold_free(fold2);
511 :
512 0 : return res;
513 : error:
514 0 : isl_qpolynomial_fold_free(res);
515 0 : isl_qpolynomial_fold_free(fold1);
516 0 : isl_qpolynomial_fold_free(fold2);
517 0 : return NULL;
518 : }
519 :
520 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_qpolynomial(
521 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_qpolynomial *qp)
522 : {
523 : int i;
524 :
525 0 : if (!fold || !qp)
526 : goto error;
527 :
528 0 : if (isl_qpolynomial_is_zero(qp)) {
529 0 : isl_qpolynomial_free(qp);
530 0 : return fold;
531 : }
532 :
533 0 : fold = isl_qpolynomial_fold_cow(fold);
534 0 : if (!fold)
535 0 : goto error;
536 :
537 0 : for (i = 0; i < fold->n; ++i) {
538 0 : fold->qp[i] = isl_qpolynomial_add(fold->qp[i],
539 : isl_qpolynomial_copy(qp));
540 0 : if (!fold->qp[i])
541 0 : goto error;
542 : }
543 :
544 0 : isl_qpolynomial_free(qp);
545 0 : return fold;
546 : error:
547 0 : isl_qpolynomial_fold_free(fold);
548 0 : isl_qpolynomial_free(qp);
549 0 : return NULL;
550 : }
551 :
552 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain(
553 : __isl_keep isl_set *dom,
554 : __isl_take isl_qpolynomial_fold *fold1,
555 : __isl_take isl_qpolynomial_fold *fold2)
556 : {
557 : int i;
558 0 : isl_qpolynomial_fold *res = NULL;
559 :
560 0 : if (!fold1 || !fold2)
561 : goto error;
562 :
563 0 : if (isl_qpolynomial_fold_is_empty(fold1)) {
564 0 : isl_qpolynomial_fold_free(fold1);
565 0 : return fold2;
566 : }
567 :
568 0 : if (isl_qpolynomial_fold_is_empty(fold2)) {
569 0 : isl_qpolynomial_fold_free(fold2);
570 0 : return fold1;
571 : }
572 :
573 0 : if (fold1->n == 1 && fold2->n != 1)
574 0 : return isl_qpolynomial_fold_add_on_domain(dom, fold2, fold1);
575 :
576 0 : if (fold2->n == 1) {
577 0 : res = isl_qpolynomial_fold_add_qpolynomial(fold1,
578 0 : isl_qpolynomial_copy(fold2->qp[0]));
579 0 : isl_qpolynomial_fold_free(fold2);
580 0 : return res;
581 : }
582 :
583 0 : res = isl_qpolynomial_fold_add_qpolynomial(
584 : isl_qpolynomial_fold_copy(fold1),
585 0 : isl_qpolynomial_copy(fold2->qp[0]));
586 :
587 0 : for (i = 1; i < fold2->n; ++i) {
588 : isl_qpolynomial_fold *res_i;
589 0 : res_i = isl_qpolynomial_fold_add_qpolynomial(
590 : isl_qpolynomial_fold_copy(fold1),
591 0 : isl_qpolynomial_copy(fold2->qp[i]));
592 0 : res = isl_qpolynomial_fold_fold_on_domain(dom, res, res_i);
593 : }
594 :
595 0 : isl_qpolynomial_fold_free(fold1);
596 0 : isl_qpolynomial_fold_free(fold2);
597 0 : return res;
598 : error:
599 0 : isl_qpolynomial_fold_free(res);
600 0 : isl_qpolynomial_fold_free(fold1);
601 0 : isl_qpolynomial_fold_free(fold2);
602 0 : return NULL;
603 : }
604 :
605 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities(
606 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq)
607 : {
608 : int i;
609 :
610 0 : if (!fold || !eq)
611 : goto error;
612 :
613 0 : fold = isl_qpolynomial_fold_cow(fold);
614 0 : if (!fold)
615 0 : return NULL;
616 :
617 0 : for (i = 0; i < fold->n; ++i) {
618 0 : fold->qp[i] = isl_qpolynomial_substitute_equalities(fold->qp[i],
619 : isl_basic_set_copy(eq));
620 0 : if (!fold->qp[i])
621 0 : goto error;
622 : }
623 :
624 0 : isl_basic_set_free(eq);
625 0 : return fold;
626 : error:
627 0 : isl_basic_set_free(eq);
628 0 : isl_qpolynomial_fold_free(fold);
629 0 : return NULL;
630 : }
631 :
632 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
633 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
634 : {
635 : int i;
636 :
637 0 : if (!fold || !context)
638 : goto error;
639 :
640 0 : fold = isl_qpolynomial_fold_cow(fold);
641 0 : if (!fold)
642 0 : return NULL;
643 :
644 0 : for (i = 0; i < fold->n; ++i) {
645 0 : fold->qp[i] = isl_qpolynomial_gist(fold->qp[i],
646 : isl_set_copy(context));
647 0 : if (!fold->qp[i])
648 0 : goto error;
649 : }
650 :
651 0 : isl_set_free(context);
652 0 : return fold;
653 : error:
654 0 : isl_set_free(context);
655 0 : isl_qpolynomial_fold_free(fold);
656 0 : return NULL;
657 : }
658 :
659 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params(
660 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
661 : {
662 0 : isl_space *space = isl_qpolynomial_fold_get_domain_space(fold);
663 0 : isl_set *dom_context = isl_set_universe(space);
664 0 : dom_context = isl_set_intersect_params(dom_context, context);
665 0 : return isl_qpolynomial_fold_gist(fold, dom_context);
666 : }
667 :
668 : #define isl_qpolynomial_fold_involves_nan isl_qpolynomial_fold_is_nan
669 :
670 : #define HAS_TYPE
671 :
672 : #undef PW
673 : #define PW isl_pw_qpolynomial_fold
674 : #undef EL
675 : #define EL isl_qpolynomial_fold
676 : #undef EL_IS_ZERO
677 : #define EL_IS_ZERO is_empty
678 : #undef ZERO
679 : #define ZERO zero
680 : #undef IS_ZERO
681 : #define IS_ZERO is_zero
682 : #undef FIELD
683 : #define FIELD fold
684 : #undef DEFAULT_IS_ZERO
685 : #define DEFAULT_IS_ZERO 1
686 :
687 : #define NO_NEG
688 : #define NO_SUB
689 : #define NO_PULLBACK
690 :
691 : #include <isl_pw_templ.c>
692 : #include <isl_pw_eval.c>
693 :
694 : #undef BASE
695 : #define BASE pw_qpolynomial_fold
696 :
697 : #define NO_SUB
698 :
699 : #include <isl_union_single.c>
700 : #include <isl_union_eval.c>
701 :
702 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type,
703 : __isl_take isl_space *dim)
704 : {
705 0 : return qpolynomial_fold_alloc(type, dim, 0);
706 : }
707 :
708 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_alloc(
709 : enum isl_fold type, __isl_take isl_qpolynomial *qp)
710 : {
711 : isl_qpolynomial_fold *fold;
712 :
713 0 : if (!qp)
714 0 : return NULL;
715 :
716 0 : fold = qpolynomial_fold_alloc(type, isl_space_copy(qp->dim), 1);
717 0 : if (!fold)
718 0 : goto error;
719 :
720 0 : fold->qp[0] = qp;
721 0 : fold->n++;
722 :
723 0 : return fold;
724 : error:
725 0 : isl_qpolynomial_fold_free(fold);
726 0 : isl_qpolynomial_free(qp);
727 0 : return NULL;
728 : }
729 :
730 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_copy(
731 : __isl_keep isl_qpolynomial_fold *fold)
732 : {
733 0 : if (!fold)
734 0 : return NULL;
735 :
736 0 : fold->ref++;
737 0 : return fold;
738 : }
739 :
740 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup(
741 : __isl_keep isl_qpolynomial_fold *fold)
742 : {
743 : int i;
744 : isl_qpolynomial_fold *dup;
745 :
746 0 : if (!fold)
747 0 : return NULL;
748 0 : dup = qpolynomial_fold_alloc(fold->type,
749 : isl_space_copy(fold->dim), fold->n);
750 0 : if (!dup)
751 0 : return NULL;
752 :
753 0 : dup->n = fold->n;
754 0 : for (i = 0; i < fold->n; ++i) {
755 0 : dup->qp[i] = isl_qpolynomial_copy(fold->qp[i]);
756 0 : if (!dup->qp[i])
757 0 : goto error;
758 : }
759 :
760 0 : return dup;
761 : error:
762 0 : isl_qpolynomial_fold_free(dup);
763 0 : return NULL;
764 : }
765 :
766 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow(
767 : __isl_take isl_qpolynomial_fold *fold)
768 : {
769 0 : if (!fold)
770 0 : return NULL;
771 :
772 0 : if (fold->ref == 1)
773 0 : return fold;
774 0 : fold->ref--;
775 0 : return isl_qpolynomial_fold_dup(fold);
776 : }
777 :
778 0 : void isl_qpolynomial_fold_free(__isl_take isl_qpolynomial_fold *fold)
779 : {
780 : int i;
781 :
782 0 : if (!fold)
783 0 : return;
784 0 : if (--fold->ref > 0)
785 0 : return;
786 :
787 0 : for (i = 0; i < fold->n; ++i)
788 0 : isl_qpolynomial_free(fold->qp[i]);
789 0 : isl_space_free(fold->dim);
790 0 : free(fold);
791 : }
792 :
793 0 : int isl_qpolynomial_fold_is_empty(__isl_keep isl_qpolynomial_fold *fold)
794 : {
795 0 : if (!fold)
796 0 : return -1;
797 :
798 0 : return fold->n == 0;
799 : }
800 :
801 : /* Does "fold" represent max(NaN) or min(NaN)?
802 : */
803 0 : isl_bool isl_qpolynomial_fold_is_nan(__isl_keep isl_qpolynomial_fold *fold)
804 : {
805 0 : if (!fold)
806 0 : return isl_bool_error;
807 0 : if (fold->n != 1)
808 0 : return isl_bool_false;
809 0 : return isl_qpolynomial_is_nan(fold->qp[0]);
810 : }
811 :
812 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold(
813 : __isl_take isl_qpolynomial_fold *fold1,
814 : __isl_take isl_qpolynomial_fold *fold2)
815 : {
816 : int i;
817 0 : struct isl_qpolynomial_fold *res = NULL;
818 :
819 0 : if (!fold1 || !fold2)
820 : goto error;
821 :
822 0 : isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error);
823 0 : isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim),
824 : goto error);
825 :
826 0 : if (isl_qpolynomial_fold_is_empty(fold1)) {
827 0 : isl_qpolynomial_fold_free(fold1);
828 0 : return fold2;
829 : }
830 :
831 0 : if (isl_qpolynomial_fold_is_empty(fold2)) {
832 0 : isl_qpolynomial_fold_free(fold2);
833 0 : return fold1;
834 : }
835 :
836 0 : res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim),
837 0 : fold1->n + fold2->n);
838 0 : if (!res)
839 0 : goto error;
840 :
841 0 : for (i = 0; i < fold1->n; ++i) {
842 0 : res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]);
843 0 : if (!res->qp[res->n])
844 0 : goto error;
845 0 : res->n++;
846 : }
847 :
848 0 : for (i = 0; i < fold2->n; ++i) {
849 0 : res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]);
850 0 : if (!res->qp[res->n])
851 0 : goto error;
852 0 : res->n++;
853 : }
854 :
855 0 : isl_qpolynomial_fold_free(fold1);
856 0 : isl_qpolynomial_fold_free(fold2);
857 :
858 0 : return res;
859 : error:
860 0 : isl_qpolynomial_fold_free(res);
861 0 : isl_qpolynomial_fold_free(fold1);
862 0 : isl_qpolynomial_fold_free(fold2);
863 0 : return NULL;
864 : }
865 :
866 0 : __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold(
867 : __isl_take isl_pw_qpolynomial_fold *pw1,
868 : __isl_take isl_pw_qpolynomial_fold *pw2)
869 : {
870 : int i, j, n;
871 : struct isl_pw_qpolynomial_fold *res;
872 : isl_set *set;
873 :
874 0 : if (!pw1 || !pw2)
875 : goto error;
876 :
877 0 : isl_assert(pw1->dim->ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
878 :
879 0 : if (isl_pw_qpolynomial_fold_is_zero(pw1)) {
880 0 : isl_pw_qpolynomial_fold_free(pw1);
881 0 : return pw2;
882 : }
883 :
884 0 : if (isl_pw_qpolynomial_fold_is_zero(pw2)) {
885 0 : isl_pw_qpolynomial_fold_free(pw2);
886 0 : return pw1;
887 : }
888 :
889 0 : if (pw1->type != pw2->type)
890 0 : isl_die(pw1->dim->ctx, isl_error_invalid,
891 : "fold types don't match", goto error);
892 :
893 0 : n = (pw1->n + 1) * (pw2->n + 1);
894 0 : res = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pw1->dim),
895 : pw1->type, n);
896 :
897 0 : for (i = 0; i < pw1->n; ++i) {
898 0 : set = isl_set_copy(pw1->p[i].set);
899 0 : for (j = 0; j < pw2->n; ++j) {
900 : struct isl_set *common;
901 : isl_qpolynomial_fold *sum;
902 0 : set = isl_set_subtract(set,
903 0 : isl_set_copy(pw2->p[j].set));
904 0 : common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
905 0 : isl_set_copy(pw2->p[j].set));
906 0 : if (isl_set_plain_is_empty(common)) {
907 0 : isl_set_free(common);
908 0 : continue;
909 : }
910 :
911 0 : sum = isl_qpolynomial_fold_fold_on_domain(common,
912 0 : isl_qpolynomial_fold_copy(pw1->p[i].fold),
913 0 : isl_qpolynomial_fold_copy(pw2->p[j].fold));
914 :
915 0 : res = isl_pw_qpolynomial_fold_add_piece(res, common, sum);
916 : }
917 0 : res = isl_pw_qpolynomial_fold_add_piece(res, set,
918 0 : isl_qpolynomial_fold_copy(pw1->p[i].fold));
919 : }
920 :
921 0 : for (j = 0; j < pw2->n; ++j) {
922 0 : set = isl_set_copy(pw2->p[j].set);
923 0 : for (i = 0; i < pw1->n; ++i)
924 0 : set = isl_set_subtract(set, isl_set_copy(pw1->p[i].set));
925 0 : res = isl_pw_qpolynomial_fold_add_piece(res, set,
926 0 : isl_qpolynomial_fold_copy(pw2->p[j].fold));
927 : }
928 :
929 0 : isl_pw_qpolynomial_fold_free(pw1);
930 0 : isl_pw_qpolynomial_fold_free(pw2);
931 :
932 0 : return res;
933 : error:
934 0 : isl_pw_qpolynomial_fold_free(pw1);
935 0 : isl_pw_qpolynomial_fold_free(pw2);
936 0 : return NULL;
937 : }
938 :
939 0 : __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
940 : __isl_take isl_union_pw_qpolynomial_fold *u,
941 : __isl_take isl_pw_qpolynomial_fold *part)
942 : {
943 : struct isl_hash_table_entry *entry;
944 :
945 0 : u = isl_union_pw_qpolynomial_fold_cow(u);
946 :
947 0 : if (!part || !u)
948 : goto error;
949 0 : if (isl_space_check_equal_params(part->dim, u->space) < 0)
950 0 : goto error;
951 :
952 0 : entry = isl_union_pw_qpolynomial_fold_find_part_entry(u, part->dim, 1);
953 0 : if (!entry)
954 0 : goto error;
955 :
956 0 : if (!entry->data)
957 0 : entry->data = part;
958 : else {
959 0 : entry->data = isl_pw_qpolynomial_fold_fold(entry->data,
960 : isl_pw_qpolynomial_fold_copy(part));
961 0 : if (!entry->data)
962 0 : goto error;
963 0 : isl_pw_qpolynomial_fold_free(part);
964 : }
965 :
966 0 : return u;
967 : error:
968 0 : isl_pw_qpolynomial_fold_free(part);
969 0 : isl_union_pw_qpolynomial_fold_free(u);
970 0 : return NULL;
971 : }
972 :
973 0 : static isl_stat fold_part(__isl_take isl_pw_qpolynomial_fold *part, void *user)
974 : {
975 : isl_union_pw_qpolynomial_fold **u;
976 0 : u = (isl_union_pw_qpolynomial_fold **)user;
977 :
978 0 : *u = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(*u, part);
979 :
980 0 : return isl_stat_ok;
981 : }
982 :
983 0 : __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold(
984 : __isl_take isl_union_pw_qpolynomial_fold *u1,
985 : __isl_take isl_union_pw_qpolynomial_fold *u2)
986 : {
987 0 : u1 = isl_union_pw_qpolynomial_fold_cow(u1);
988 :
989 0 : if (!u1 || !u2)
990 : goto error;
991 :
992 0 : if (isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(u2,
993 : &fold_part, &u1) < 0)
994 0 : goto error;
995 :
996 0 : isl_union_pw_qpolynomial_fold_free(u2);
997 :
998 0 : return u1;
999 : error:
1000 0 : isl_union_pw_qpolynomial_fold_free(u1);
1001 0 : isl_union_pw_qpolynomial_fold_free(u2);
1002 0 : return NULL;
1003 : }
1004 :
1005 0 : __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial(
1006 : enum isl_fold type, __isl_take isl_pw_qpolynomial *pwqp)
1007 : {
1008 : int i;
1009 : isl_pw_qpolynomial_fold *pwf;
1010 :
1011 0 : if (!pwqp)
1012 0 : return NULL;
1013 :
1014 0 : pwf = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pwqp->dim),
1015 : type, pwqp->n);
1016 :
1017 0 : for (i = 0; i < pwqp->n; ++i)
1018 0 : pwf = isl_pw_qpolynomial_fold_add_piece(pwf,
1019 0 : isl_set_copy(pwqp->p[i].set),
1020 : isl_qpolynomial_fold_alloc(type,
1021 0 : isl_qpolynomial_copy(pwqp->p[i].qp)));
1022 :
1023 0 : isl_pw_qpolynomial_free(pwqp);
1024 :
1025 0 : return pwf;
1026 : }
1027 :
1028 0 : __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add(
1029 : __isl_take isl_pw_qpolynomial_fold *pwf1,
1030 : __isl_take isl_pw_qpolynomial_fold *pwf2)
1031 : {
1032 0 : return isl_pw_qpolynomial_fold_union_add_(pwf1, pwf2);
1033 : }
1034 :
1035 : /* Compare two quasi-polynomial reductions.
1036 : *
1037 : * Return -1 if "fold1" is "smaller" than "fold2", 1 if "fold1" is "greater"
1038 : * than "fold2" and 0 if they are equal.
1039 : */
1040 0 : int isl_qpolynomial_fold_plain_cmp(__isl_keep isl_qpolynomial_fold *fold1,
1041 : __isl_keep isl_qpolynomial_fold *fold2)
1042 : {
1043 : int i;
1044 :
1045 0 : if (fold1 == fold2)
1046 0 : return 0;
1047 0 : if (!fold1)
1048 0 : return -1;
1049 0 : if (!fold2)
1050 0 : return 1;
1051 :
1052 0 : if (fold1->n != fold2->n)
1053 0 : return fold1->n - fold2->n;
1054 :
1055 0 : for (i = 0; i < fold1->n; ++i) {
1056 : int cmp;
1057 :
1058 0 : cmp = isl_qpolynomial_plain_cmp(fold1->qp[i], fold2->qp[i]);
1059 0 : if (cmp != 0)
1060 0 : return cmp;
1061 : }
1062 :
1063 0 : return 0;
1064 : }
1065 :
1066 0 : int isl_qpolynomial_fold_plain_is_equal(__isl_keep isl_qpolynomial_fold *fold1,
1067 : __isl_keep isl_qpolynomial_fold *fold2)
1068 : {
1069 : int i;
1070 :
1071 0 : if (!fold1 || !fold2)
1072 0 : return -1;
1073 :
1074 0 : if (fold1->n != fold2->n)
1075 0 : return 0;
1076 :
1077 : /* We probably want to sort the qps first... */
1078 0 : for (i = 0; i < fold1->n; ++i) {
1079 0 : int eq = isl_qpolynomial_plain_is_equal(fold1->qp[i], fold2->qp[i]);
1080 0 : if (eq < 0 || !eq)
1081 0 : return eq;
1082 : }
1083 :
1084 0 : return 1;
1085 : }
1086 :
1087 0 : __isl_give isl_val *isl_qpolynomial_fold_eval(
1088 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_point *pnt)
1089 : {
1090 : isl_ctx *ctx;
1091 : isl_val *v;
1092 :
1093 0 : if (!fold || !pnt)
1094 : goto error;
1095 0 : ctx = isl_point_get_ctx(pnt);
1096 0 : isl_assert(pnt->dim->ctx, isl_space_is_equal(pnt->dim, fold->dim), goto error);
1097 0 : isl_assert(pnt->dim->ctx,
1098 : fold->type == isl_fold_max || fold->type == isl_fold_min,
1099 : goto error);
1100 :
1101 0 : if (fold->n == 0)
1102 0 : v = isl_val_zero(ctx);
1103 : else {
1104 : int i;
1105 0 : v = isl_qpolynomial_eval(isl_qpolynomial_copy(fold->qp[0]),
1106 : isl_point_copy(pnt));
1107 0 : for (i = 1; i < fold->n; ++i) {
1108 : isl_val *v_i;
1109 0 : v_i = isl_qpolynomial_eval(
1110 0 : isl_qpolynomial_copy(fold->qp[i]),
1111 : isl_point_copy(pnt));
1112 0 : if (fold->type == isl_fold_max)
1113 0 : v = isl_val_max(v, v_i);
1114 : else
1115 0 : v = isl_val_min(v, v_i);
1116 : }
1117 : }
1118 0 : isl_qpolynomial_fold_free(fold);
1119 0 : isl_point_free(pnt);
1120 :
1121 0 : return v;
1122 : error:
1123 0 : isl_qpolynomial_fold_free(fold);
1124 0 : isl_point_free(pnt);
1125 0 : return NULL;
1126 : }
1127 :
1128 0 : size_t isl_pw_qpolynomial_fold_size(__isl_keep isl_pw_qpolynomial_fold *pwf)
1129 : {
1130 : int i;
1131 0 : size_t n = 0;
1132 :
1133 0 : for (i = 0; i < pwf->n; ++i)
1134 0 : n += pwf->p[i].fold->n;
1135 :
1136 0 : return n;
1137 : }
1138 :
1139 0 : __isl_give isl_val *isl_qpolynomial_fold_opt_on_domain(
1140 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *set, int max)
1141 : {
1142 : int i;
1143 : isl_val *opt;
1144 :
1145 0 : if (!set || !fold)
1146 : goto error;
1147 :
1148 0 : if (fold->n == 0) {
1149 0 : opt = isl_val_zero(isl_set_get_ctx(set));
1150 0 : isl_set_free(set);
1151 0 : isl_qpolynomial_fold_free(fold);
1152 0 : return opt;
1153 : }
1154 :
1155 0 : opt = isl_qpolynomial_opt_on_domain(isl_qpolynomial_copy(fold->qp[0]),
1156 : isl_set_copy(set), max);
1157 0 : for (i = 1; i < fold->n; ++i) {
1158 : isl_val *opt_i;
1159 0 : opt_i = isl_qpolynomial_opt_on_domain(
1160 0 : isl_qpolynomial_copy(fold->qp[i]),
1161 : isl_set_copy(set), max);
1162 0 : if (max)
1163 0 : opt = isl_val_max(opt, opt_i);
1164 : else
1165 0 : opt = isl_val_min(opt, opt_i);
1166 : }
1167 :
1168 0 : isl_set_free(set);
1169 0 : isl_qpolynomial_fold_free(fold);
1170 :
1171 0 : return opt;
1172 : error:
1173 0 : isl_set_free(set);
1174 0 : isl_qpolynomial_fold_free(fold);
1175 0 : return NULL;
1176 : }
1177 :
1178 : /* Check whether for each quasi-polynomial in "fold2" there is
1179 : * a quasi-polynomial in "fold1" that dominates it on "set".
1180 : */
1181 0 : static int qpolynomial_fold_covers_on_domain(__isl_keep isl_set *set,
1182 : __isl_keep isl_qpolynomial_fold *fold1,
1183 : __isl_keep isl_qpolynomial_fold *fold2)
1184 : {
1185 : int i, j;
1186 : int covers;
1187 :
1188 0 : if (!set || !fold1 || !fold2)
1189 0 : return -1;
1190 :
1191 0 : covers = fold1->type == isl_fold_max ? 1 : -1;
1192 :
1193 0 : for (i = 0; i < fold2->n; ++i) {
1194 0 : for (j = 0; j < fold1->n; ++j) {
1195 : isl_qpolynomial *d;
1196 : int sgn;
1197 :
1198 0 : d = isl_qpolynomial_sub(
1199 0 : isl_qpolynomial_copy(fold1->qp[j]),
1200 0 : isl_qpolynomial_copy(fold2->qp[i]));
1201 0 : sgn = isl_qpolynomial_sign(set, d);
1202 0 : isl_qpolynomial_free(d);
1203 0 : if (sgn == covers)
1204 0 : break;
1205 : }
1206 0 : if (j >= fold1->n)
1207 0 : return 0;
1208 : }
1209 :
1210 0 : return 1;
1211 : }
1212 :
1213 : /* Check whether "pwf1" dominated "pwf2", i.e., the domain of "pwf1" contains
1214 : * that of "pwf2" and on each cell, the corresponding fold from pwf1 dominates
1215 : * that of pwf2.
1216 : */
1217 0 : int isl_pw_qpolynomial_fold_covers(__isl_keep isl_pw_qpolynomial_fold *pwf1,
1218 : __isl_keep isl_pw_qpolynomial_fold *pwf2)
1219 : {
1220 : int i, j;
1221 : isl_set *dom1, *dom2;
1222 : int is_subset;
1223 :
1224 0 : if (!pwf1 || !pwf2)
1225 0 : return -1;
1226 :
1227 0 : if (pwf2->n == 0)
1228 0 : return 1;
1229 0 : if (pwf1->n == 0)
1230 0 : return 0;
1231 :
1232 0 : dom1 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf1));
1233 0 : dom2 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf2));
1234 0 : is_subset = isl_set_is_subset(dom2, dom1);
1235 0 : isl_set_free(dom1);
1236 0 : isl_set_free(dom2);
1237 :
1238 0 : if (is_subset < 0 || !is_subset)
1239 0 : return is_subset;
1240 :
1241 0 : for (i = 0; i < pwf2->n; ++i) {
1242 0 : for (j = 0; j < pwf1->n; ++j) {
1243 : int is_empty;
1244 : isl_set *common;
1245 : int covers;
1246 :
1247 0 : common = isl_set_intersect(isl_set_copy(pwf1->p[j].set),
1248 0 : isl_set_copy(pwf2->p[i].set));
1249 0 : is_empty = isl_set_is_empty(common);
1250 0 : if (is_empty < 0 || is_empty) {
1251 0 : isl_set_free(common);
1252 0 : if (is_empty < 0)
1253 0 : return -1;
1254 0 : continue;
1255 : }
1256 0 : covers = qpolynomial_fold_covers_on_domain(common,
1257 0 : pwf1->p[j].fold, pwf2->p[i].fold);
1258 0 : isl_set_free(common);
1259 0 : if (covers < 0 || !covers)
1260 0 : return covers;
1261 : }
1262 : }
1263 :
1264 0 : return 1;
1265 : }
1266 :
1267 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain(
1268 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph)
1269 : {
1270 : int i;
1271 : isl_ctx *ctx;
1272 :
1273 0 : if (!fold || !morph)
1274 : goto error;
1275 :
1276 0 : ctx = fold->dim->ctx;
1277 0 : isl_assert(ctx, isl_space_is_equal(fold->dim, morph->dom->dim), goto error);
1278 :
1279 0 : fold = isl_qpolynomial_fold_cow(fold);
1280 0 : if (!fold)
1281 0 : goto error;
1282 :
1283 0 : isl_space_free(fold->dim);
1284 0 : fold->dim = isl_space_copy(morph->ran->dim);
1285 0 : if (!fold->dim)
1286 0 : goto error;
1287 :
1288 0 : for (i = 0; i < fold->n; ++i) {
1289 0 : fold->qp[i] = isl_qpolynomial_morph_domain(fold->qp[i],
1290 : isl_morph_copy(morph));
1291 0 : if (!fold->qp[i])
1292 0 : goto error;
1293 : }
1294 :
1295 0 : isl_morph_free(morph);
1296 :
1297 0 : return fold;
1298 : error:
1299 0 : isl_qpolynomial_fold_free(fold);
1300 0 : isl_morph_free(morph);
1301 0 : return NULL;
1302 : }
1303 :
1304 0 : enum isl_fold isl_qpolynomial_fold_get_type(__isl_keep isl_qpolynomial_fold *fold)
1305 : {
1306 0 : if (!fold)
1307 0 : return isl_fold_list;
1308 0 : return fold->type;
1309 : }
1310 :
1311 0 : enum isl_fold isl_union_pw_qpolynomial_fold_get_type(
1312 : __isl_keep isl_union_pw_qpolynomial_fold *upwf)
1313 : {
1314 0 : if (!upwf)
1315 0 : return isl_fold_list;
1316 0 : return upwf->type;
1317 : }
1318 :
1319 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift(
1320 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim)
1321 : {
1322 : int i;
1323 :
1324 0 : if (!fold || !dim)
1325 : goto error;
1326 :
1327 0 : if (isl_space_is_equal(fold->dim, dim)) {
1328 0 : isl_space_free(dim);
1329 0 : return fold;
1330 : }
1331 :
1332 0 : fold = isl_qpolynomial_fold_cow(fold);
1333 0 : if (!fold)
1334 0 : goto error;
1335 :
1336 0 : isl_space_free(fold->dim);
1337 0 : fold->dim = isl_space_copy(dim);
1338 0 : if (!fold->dim)
1339 0 : goto error;
1340 :
1341 0 : for (i = 0; i < fold->n; ++i) {
1342 0 : fold->qp[i] = isl_qpolynomial_lift(fold->qp[i],
1343 : isl_space_copy(dim));
1344 0 : if (!fold->qp[i])
1345 0 : goto error;
1346 : }
1347 :
1348 0 : isl_space_free(dim);
1349 :
1350 0 : return fold;
1351 : error:
1352 0 : isl_qpolynomial_fold_free(fold);
1353 0 : isl_space_free(dim);
1354 0 : return NULL;
1355 : }
1356 :
1357 0 : isl_stat isl_qpolynomial_fold_foreach_qpolynomial(
1358 : __isl_keep isl_qpolynomial_fold *fold,
1359 : isl_stat (*fn)(__isl_take isl_qpolynomial *qp, void *user), void *user)
1360 : {
1361 : int i;
1362 :
1363 0 : if (!fold)
1364 0 : return isl_stat_error;
1365 :
1366 0 : for (i = 0; i < fold->n; ++i)
1367 0 : if (fn(isl_qpolynomial_copy(fold->qp[i]), user) < 0)
1368 0 : return isl_stat_error;
1369 :
1370 0 : return isl_stat_ok;
1371 : }
1372 :
1373 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims(
1374 : __isl_take isl_qpolynomial_fold *fold,
1375 : enum isl_dim_type dst_type, unsigned dst_pos,
1376 : enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1377 : {
1378 : int i;
1379 : enum isl_dim_type set_src_type, set_dst_type;
1380 :
1381 0 : if (n == 0)
1382 0 : return fold;
1383 :
1384 0 : fold = isl_qpolynomial_fold_cow(fold);
1385 0 : if (!fold)
1386 0 : return NULL;
1387 :
1388 0 : set_src_type = domain_type(src_type);
1389 0 : set_dst_type = domain_type(dst_type);
1390 :
1391 0 : fold->dim = isl_space_move_dims(fold->dim, set_dst_type, dst_pos,
1392 : set_src_type, src_pos, n);
1393 0 : if (!fold->dim)
1394 0 : goto error;
1395 :
1396 0 : for (i = 0; i < fold->n; ++i) {
1397 0 : fold->qp[i] = isl_qpolynomial_move_dims(fold->qp[i],
1398 : dst_type, dst_pos, src_type, src_pos, n);
1399 0 : if (!fold->qp[i])
1400 0 : goto error;
1401 : }
1402 :
1403 0 : return fold;
1404 : error:
1405 0 : isl_qpolynomial_fold_free(fold);
1406 0 : return NULL;
1407 : }
1408 :
1409 : /* For each 0 <= i < "n", replace variable "first" + i of type "type"
1410 : * in fold->qp[k] by subs[i].
1411 : */
1412 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute(
1413 : __isl_take isl_qpolynomial_fold *fold,
1414 : enum isl_dim_type type, unsigned first, unsigned n,
1415 : __isl_keep isl_qpolynomial **subs)
1416 : {
1417 : int i;
1418 :
1419 0 : if (n == 0)
1420 0 : return fold;
1421 :
1422 0 : fold = isl_qpolynomial_fold_cow(fold);
1423 0 : if (!fold)
1424 0 : return NULL;
1425 :
1426 0 : for (i = 0; i < fold->n; ++i) {
1427 0 : fold->qp[i] = isl_qpolynomial_substitute(fold->qp[i],
1428 : type, first, n, subs);
1429 0 : if (!fold->qp[i])
1430 0 : goto error;
1431 : }
1432 :
1433 0 : return fold;
1434 : error:
1435 0 : isl_qpolynomial_fold_free(fold);
1436 0 : return NULL;
1437 : }
1438 :
1439 0 : static isl_stat add_pwqp(__isl_take isl_pw_qpolynomial *pwqp, void *user)
1440 : {
1441 : isl_pw_qpolynomial_fold *pwf;
1442 : isl_union_pw_qpolynomial_fold **upwf;
1443 : struct isl_hash_table_entry *entry;
1444 :
1445 0 : upwf = (isl_union_pw_qpolynomial_fold **)user;
1446 :
1447 0 : entry = isl_union_pw_qpolynomial_fold_find_part_entry(*upwf,
1448 : pwqp->dim, 1);
1449 0 : if (!entry)
1450 0 : goto error;
1451 :
1452 0 : pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial((*upwf)->type, pwqp);
1453 0 : if (!entry->data)
1454 0 : entry->data = pwf;
1455 : else {
1456 0 : entry->data = isl_pw_qpolynomial_fold_add(entry->data, pwf);
1457 0 : if (!entry->data)
1458 0 : return isl_stat_error;
1459 0 : if (isl_pw_qpolynomial_fold_is_zero(entry->data))
1460 0 : *upwf = isl_union_pw_qpolynomial_fold_remove_part_entry(
1461 : *upwf, entry);
1462 : }
1463 :
1464 0 : return isl_stat_ok;
1465 : error:
1466 0 : isl_pw_qpolynomial_free(pwqp);
1467 0 : return isl_stat_error;
1468 : }
1469 :
1470 0 : __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial(
1471 : __isl_take isl_union_pw_qpolynomial_fold *upwf,
1472 : __isl_take isl_union_pw_qpolynomial *upwqp)
1473 : {
1474 0 : upwf = isl_union_pw_qpolynomial_fold_align_params(upwf,
1475 : isl_union_pw_qpolynomial_get_space(upwqp));
1476 0 : upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1477 : isl_union_pw_qpolynomial_fold_get_space(upwf));
1478 :
1479 0 : upwf = isl_union_pw_qpolynomial_fold_cow(upwf);
1480 0 : if (!upwf || !upwqp)
1481 : goto error;
1482 :
1483 0 : if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &add_pwqp,
1484 : &upwf) < 0)
1485 0 : goto error;
1486 :
1487 0 : isl_union_pw_qpolynomial_free(upwqp);
1488 :
1489 0 : return upwf;
1490 : error:
1491 0 : isl_union_pw_qpolynomial_fold_free(upwf);
1492 0 : isl_union_pw_qpolynomial_free(upwqp);
1493 0 : return NULL;
1494 : }
1495 :
1496 0 : static isl_bool join_compatible(__isl_keep isl_space *space1,
1497 : __isl_keep isl_space *space2)
1498 : {
1499 : isl_bool m;
1500 0 : m = isl_space_has_equal_params(space1, space2);
1501 0 : if (m < 0 || !m)
1502 0 : return m;
1503 0 : return isl_space_tuple_is_equal(space1, isl_dim_out,
1504 : space2, isl_dim_in);
1505 : }
1506 :
1507 : /* Compute the intersection of the range of the map and the domain
1508 : * of the piecewise quasipolynomial reduction and then compute a bound
1509 : * on the associated quasipolynomial reduction over all elements
1510 : * in this intersection.
1511 : *
1512 : * We first introduce some unconstrained dimensions in the
1513 : * piecewise quasipolynomial, intersect the resulting domain
1514 : * with the wrapped map and the compute the sum.
1515 : */
1516 0 : __isl_give isl_pw_qpolynomial_fold *isl_map_apply_pw_qpolynomial_fold(
1517 : __isl_take isl_map *map, __isl_take isl_pw_qpolynomial_fold *pwf,
1518 : int *tight)
1519 : {
1520 : isl_ctx *ctx;
1521 : isl_set *dom;
1522 : isl_space *map_dim;
1523 : isl_space *pwf_dim;
1524 : unsigned n_in;
1525 : isl_bool ok;
1526 :
1527 0 : ctx = isl_map_get_ctx(map);
1528 0 : if (!ctx)
1529 0 : goto error;
1530 :
1531 0 : map_dim = isl_map_get_space(map);
1532 0 : pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf);
1533 0 : ok = join_compatible(map_dim, pwf_dim);
1534 0 : isl_space_free(map_dim);
1535 0 : isl_space_free(pwf_dim);
1536 0 : if (ok < 0)
1537 0 : goto error;
1538 0 : if (!ok)
1539 0 : isl_die(ctx, isl_error_invalid, "incompatible dimensions",
1540 : goto error);
1541 :
1542 0 : n_in = isl_map_dim(map, isl_dim_in);
1543 0 : pwf = isl_pw_qpolynomial_fold_insert_dims(pwf, isl_dim_in, 0, n_in);
1544 :
1545 0 : dom = isl_map_wrap(map);
1546 0 : pwf = isl_pw_qpolynomial_fold_reset_domain_space(pwf,
1547 : isl_set_get_space(dom));
1548 :
1549 0 : pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, dom);
1550 0 : pwf = isl_pw_qpolynomial_fold_bound(pwf, tight);
1551 :
1552 0 : return pwf;
1553 : error:
1554 0 : isl_map_free(map);
1555 0 : isl_pw_qpolynomial_fold_free(pwf);
1556 0 : return NULL;
1557 : }
1558 :
1559 0 : __isl_give isl_pw_qpolynomial_fold *isl_set_apply_pw_qpolynomial_fold(
1560 : __isl_take isl_set *set, __isl_take isl_pw_qpolynomial_fold *pwf,
1561 : int *tight)
1562 : {
1563 0 : return isl_map_apply_pw_qpolynomial_fold(set, pwf, tight);
1564 : }
1565 :
1566 : struct isl_apply_fold_data {
1567 : isl_union_pw_qpolynomial_fold *upwf;
1568 : isl_union_pw_qpolynomial_fold *res;
1569 : isl_map *map;
1570 : int tight;
1571 : };
1572 :
1573 0 : static isl_stat pw_qpolynomial_fold_apply(
1574 : __isl_take isl_pw_qpolynomial_fold *pwf, void *user)
1575 : {
1576 : isl_space *map_dim;
1577 : isl_space *pwf_dim;
1578 0 : struct isl_apply_fold_data *data = user;
1579 : isl_bool ok;
1580 :
1581 0 : map_dim = isl_map_get_space(data->map);
1582 0 : pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf);
1583 0 : ok = join_compatible(map_dim, pwf_dim);
1584 0 : isl_space_free(map_dim);
1585 0 : isl_space_free(pwf_dim);
1586 :
1587 0 : if (ok < 0)
1588 0 : return isl_stat_error;
1589 0 : if (ok) {
1590 0 : pwf = isl_map_apply_pw_qpolynomial_fold(isl_map_copy(data->map),
1591 0 : pwf, data->tight ? &data->tight : NULL);
1592 0 : data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
1593 : data->res, pwf);
1594 : } else
1595 0 : isl_pw_qpolynomial_fold_free(pwf);
1596 :
1597 0 : return isl_stat_ok;
1598 : }
1599 :
1600 0 : static isl_stat map_apply(__isl_take isl_map *map, void *user)
1601 : {
1602 0 : struct isl_apply_fold_data *data = user;
1603 : isl_stat r;
1604 :
1605 0 : data->map = map;
1606 0 : r = isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(
1607 : data->upwf, &pw_qpolynomial_fold_apply, data);
1608 :
1609 0 : isl_map_free(map);
1610 0 : return r;
1611 : }
1612 :
1613 0 : __isl_give isl_union_pw_qpolynomial_fold *isl_union_map_apply_union_pw_qpolynomial_fold(
1614 : __isl_take isl_union_map *umap,
1615 : __isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight)
1616 : {
1617 : isl_space *dim;
1618 : enum isl_fold type;
1619 : struct isl_apply_fold_data data;
1620 :
1621 0 : upwf = isl_union_pw_qpolynomial_fold_align_params(upwf,
1622 : isl_union_map_get_space(umap));
1623 0 : umap = isl_union_map_align_params(umap,
1624 : isl_union_pw_qpolynomial_fold_get_space(upwf));
1625 :
1626 0 : data.upwf = upwf;
1627 0 : data.tight = tight ? 1 : 0;
1628 0 : dim = isl_union_pw_qpolynomial_fold_get_space(upwf);
1629 0 : type = isl_union_pw_qpolynomial_fold_get_type(upwf);
1630 0 : data.res = isl_union_pw_qpolynomial_fold_zero(dim, type);
1631 0 : if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
1632 0 : goto error;
1633 :
1634 0 : isl_union_map_free(umap);
1635 0 : isl_union_pw_qpolynomial_fold_free(upwf);
1636 :
1637 0 : if (tight)
1638 0 : *tight = data.tight;
1639 :
1640 0 : return data.res;
1641 : error:
1642 0 : isl_union_map_free(umap);
1643 0 : isl_union_pw_qpolynomial_fold_free(upwf);
1644 0 : isl_union_pw_qpolynomial_fold_free(data.res);
1645 0 : return NULL;
1646 : }
1647 :
1648 0 : __isl_give isl_union_pw_qpolynomial_fold *isl_union_set_apply_union_pw_qpolynomial_fold(
1649 : __isl_take isl_union_set *uset,
1650 : __isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight)
1651 : {
1652 0 : return isl_union_map_apply_union_pw_qpolynomial_fold(uset, upwf, tight);
1653 : }
1654 :
1655 : /* Reorder the dimension of "fold" according to the given reordering.
1656 : */
1657 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain(
1658 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r)
1659 : {
1660 : int i;
1661 : isl_space *space;
1662 :
1663 0 : fold = isl_qpolynomial_fold_cow(fold);
1664 0 : if (!fold || !r)
1665 : goto error;
1666 :
1667 0 : for (i = 0; i < fold->n; ++i) {
1668 0 : fold->qp[i] = isl_qpolynomial_realign_domain(fold->qp[i],
1669 : isl_reordering_copy(r));
1670 0 : if (!fold->qp[i])
1671 0 : goto error;
1672 : }
1673 :
1674 0 : space = isl_reordering_get_space(r);
1675 0 : fold = isl_qpolynomial_fold_reset_domain_space(fold, space);
1676 :
1677 0 : isl_reordering_free(r);
1678 :
1679 0 : return fold;
1680 : error:
1681 0 : isl_qpolynomial_fold_free(fold);
1682 0 : isl_reordering_free(r);
1683 0 : return NULL;
1684 : }
1685 :
1686 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int(
1687 : __isl_take isl_qpolynomial_fold *fold, isl_int v)
1688 : {
1689 : int i;
1690 :
1691 0 : if (isl_int_is_one(v))
1692 0 : return fold;
1693 0 : if (fold && isl_int_is_zero(v)) {
1694 : isl_qpolynomial_fold *zero;
1695 0 : isl_space *dim = isl_space_copy(fold->dim);
1696 0 : zero = isl_qpolynomial_fold_empty(fold->type, dim);
1697 0 : isl_qpolynomial_fold_free(fold);
1698 0 : return zero;
1699 : }
1700 :
1701 0 : fold = isl_qpolynomial_fold_cow(fold);
1702 0 : if (!fold)
1703 0 : return NULL;
1704 :
1705 0 : if (isl_int_is_neg(v))
1706 0 : fold->type = isl_fold_type_negate(fold->type);
1707 0 : for (i = 0; i < fold->n; ++i) {
1708 0 : fold->qp[i] = isl_qpolynomial_mul_isl_int(fold->qp[i], v);
1709 0 : if (!fold->qp[i])
1710 0 : goto error;
1711 : }
1712 :
1713 0 : return fold;
1714 : error:
1715 0 : isl_qpolynomial_fold_free(fold);
1716 0 : return NULL;
1717 : }
1718 :
1719 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale(
1720 : __isl_take isl_qpolynomial_fold *fold, isl_int v)
1721 : {
1722 0 : return isl_qpolynomial_fold_mul_isl_int(fold, v);
1723 : }
1724 :
1725 : /* Multiply "fold" by "v".
1726 : */
1727 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_val(
1728 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
1729 : {
1730 : int i;
1731 :
1732 0 : if (!fold || !v)
1733 : goto error;
1734 :
1735 0 : if (isl_val_is_one(v)) {
1736 0 : isl_val_free(v);
1737 0 : return fold;
1738 : }
1739 0 : if (isl_val_is_zero(v)) {
1740 : isl_qpolynomial_fold *zero;
1741 0 : isl_space *space = isl_qpolynomial_fold_get_domain_space(fold);
1742 0 : zero = isl_qpolynomial_fold_empty(fold->type, space);
1743 0 : isl_qpolynomial_fold_free(fold);
1744 0 : isl_val_free(v);
1745 0 : return zero;
1746 : }
1747 0 : if (!isl_val_is_rat(v))
1748 0 : isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid,
1749 : "expecting rational factor", goto error);
1750 :
1751 0 : fold = isl_qpolynomial_fold_cow(fold);
1752 0 : if (!fold)
1753 0 : goto error;
1754 :
1755 0 : if (isl_val_is_neg(v))
1756 0 : fold->type = isl_fold_type_negate(fold->type);
1757 0 : for (i = 0; i < fold->n; ++i) {
1758 0 : fold->qp[i] = isl_qpolynomial_scale_val(fold->qp[i],
1759 : isl_val_copy(v));
1760 0 : if (!fold->qp[i])
1761 0 : goto error;
1762 : }
1763 :
1764 0 : isl_val_free(v);
1765 0 : return fold;
1766 : error:
1767 0 : isl_val_free(v);
1768 0 : isl_qpolynomial_fold_free(fold);
1769 0 : return NULL;
1770 : }
1771 :
1772 : /* Divide "fold" by "v".
1773 : */
1774 0 : __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_down_val(
1775 : __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
1776 : {
1777 0 : if (!fold || !v)
1778 : goto error;
1779 :
1780 0 : if (isl_val_is_one(v)) {
1781 0 : isl_val_free(v);
1782 0 : return fold;
1783 : }
1784 0 : if (!isl_val_is_rat(v))
1785 0 : isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid,
1786 : "expecting rational factor", goto error);
1787 0 : if (isl_val_is_zero(v))
1788 0 : isl_die(isl_val_get_ctx(v), isl_error_invalid,
1789 : "cannot scale down by zero", goto error);
1790 :
1791 0 : return isl_qpolynomial_fold_scale_val(fold, isl_val_inv(v));
1792 : error:
1793 0 : isl_val_free(v);
1794 0 : isl_qpolynomial_fold_free(fold);
1795 0 : return NULL;
1796 : }
|