isl_scheduler.c: extract_edge: finish conversion to isl_stat return type
[isl.git] / isl_pw_templ.c
blob124ff34da2ab8c4fe9bab1da0079754f8a458dd1
1 /*
2 * Copyright 2010-2011 INRIA Saclay
3 * Copyright 2011 Sven Verdoolaege
4 * Copyright 2012-2014 Ecole Normale Superieure
6 * Use of this software is governed by the MIT license
8 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
9 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
10 * 91893 Orsay, France
11 * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
14 #include <isl/aff.h>
15 #include <isl_sort.h>
16 #include <isl_val_private.h>
18 #include <isl_pw_macro.h>
20 #ifdef HAS_TYPE
21 __isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *dim,
22 enum isl_fold type, int n)
23 #else
24 __isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *dim, int n)
25 #endif
27 isl_ctx *ctx;
28 struct PW *pw;
30 if (!dim)
31 return NULL;
32 ctx = isl_space_get_ctx(dim);
33 isl_assert(ctx, n >= 0, goto error);
34 pw = isl_alloc(ctx, struct PW,
35 sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
36 if (!pw)
37 goto error;
39 pw->ref = 1;
40 #ifdef HAS_TYPE
41 pw->type = type;
42 #endif
43 pw->size = n;
44 pw->n = 0;
45 pw->dim = dim;
46 return pw;
47 error:
48 isl_space_free(dim);
49 return NULL;
52 #ifdef HAS_TYPE
53 __isl_give PW *FN(PW,ZERO)(__isl_take isl_space *dim, enum isl_fold type)
55 return FN(PW,alloc_size)(dim, type, 0);
57 #else
58 __isl_give PW *FN(PW,ZERO)(__isl_take isl_space *dim)
60 return FN(PW,alloc_size)(dim, 0);
62 #endif
64 __isl_give PW *FN(PW,add_piece)(__isl_take PW *pw,
65 __isl_take isl_set *set, __isl_take EL *el)
67 isl_ctx *ctx;
68 isl_space *el_dim = NULL;
70 if (!pw || !set || !el)
71 goto error;
73 if (isl_set_plain_is_empty(set) || FN(EL,EL_IS_ZERO)(el)) {
74 isl_set_free(set);
75 FN(EL,free)(el);
76 return pw;
79 ctx = isl_set_get_ctx(set);
80 #ifdef HAS_TYPE
81 if (pw->type != el->type)
82 isl_die(ctx, isl_error_invalid, "fold types don't match",
83 goto error);
84 #endif
85 el_dim = FN(EL,get_space(el));
86 isl_assert(ctx, isl_space_is_equal(pw->dim, el_dim), goto error);
87 isl_assert(ctx, pw->n < pw->size, goto error);
89 pw->p[pw->n].set = set;
90 pw->p[pw->n].FIELD = el;
91 pw->n++;
93 isl_space_free(el_dim);
94 return pw;
95 error:
96 isl_space_free(el_dim);
97 FN(PW,free)(pw);
98 isl_set_free(set);
99 FN(EL,free)(el);
100 return NULL;
103 #ifdef HAS_TYPE
104 __isl_give PW *FN(PW,alloc)(enum isl_fold type,
105 __isl_take isl_set *set, __isl_take EL *el)
106 #else
107 __isl_give PW *FN(PW,alloc)(__isl_take isl_set *set, __isl_take EL *el)
108 #endif
110 PW *pw;
112 if (!set || !el)
113 goto error;
115 #ifdef HAS_TYPE
116 pw = FN(PW,alloc_size)(FN(EL,get_space)(el), type, 1);
117 #else
118 pw = FN(PW,alloc_size)(FN(EL,get_space)(el), 1);
119 #endif
121 return FN(PW,add_piece)(pw, set, el);
122 error:
123 isl_set_free(set);
124 FN(EL,free)(el);
125 return NULL;
128 __isl_give PW *FN(PW,dup)(__isl_keep PW *pw)
130 int i;
131 PW *dup;
133 if (!pw)
134 return NULL;
136 #ifdef HAS_TYPE
137 dup = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, pw->n);
138 #else
139 dup = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->n);
140 #endif
141 if (!dup)
142 return NULL;
144 for (i = 0; i < pw->n; ++i)
145 dup = FN(PW,add_piece)(dup, isl_set_copy(pw->p[i].set),
146 FN(EL,copy)(pw->p[i].FIELD));
148 return dup;
151 __isl_give PW *FN(PW,cow)(__isl_take PW *pw)
153 if (!pw)
154 return NULL;
156 if (pw->ref == 1)
157 return pw;
158 pw->ref--;
159 return FN(PW,dup)(pw);
162 __isl_give PW *FN(PW,copy)(__isl_keep PW *pw)
164 if (!pw)
165 return NULL;
167 pw->ref++;
168 return pw;
171 __isl_null PW *FN(PW,free)(__isl_take PW *pw)
173 int i;
175 if (!pw)
176 return NULL;
177 if (--pw->ref > 0)
178 return NULL;
180 for (i = 0; i < pw->n; ++i) {
181 isl_set_free(pw->p[i].set);
182 FN(EL,free)(pw->p[i].FIELD);
184 isl_space_free(pw->dim);
185 free(pw);
187 return NULL;
190 const char *FN(PW,get_dim_name)(__isl_keep PW *pw, enum isl_dim_type type,
191 unsigned pos)
193 return pw ? isl_space_get_dim_name(pw->dim, type, pos) : NULL;
196 isl_bool FN(PW,has_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
197 unsigned pos)
199 return pw ? isl_space_has_dim_id(pw->dim, type, pos) : isl_bool_error;
202 __isl_give isl_id *FN(PW,get_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
203 unsigned pos)
205 return pw ? isl_space_get_dim_id(pw->dim, type, pos) : NULL;
208 isl_bool FN(PW,has_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
210 return pw ? isl_space_has_tuple_name(pw->dim, type) : isl_bool_error;
213 const char *FN(PW,get_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
215 return pw ? isl_space_get_tuple_name(pw->dim, type) : NULL;
218 isl_bool FN(PW,has_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
220 return pw ? isl_space_has_tuple_id(pw->dim, type) : isl_bool_error;
223 __isl_give isl_id *FN(PW,get_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
225 return pw ? isl_space_get_tuple_id(pw->dim, type) : NULL;
228 isl_bool FN(PW,IS_ZERO)(__isl_keep PW *pw)
230 if (!pw)
231 return isl_bool_error;
233 return pw->n == 0;
236 #ifndef NO_REALIGN
237 __isl_give PW *FN(PW,realign_domain)(__isl_take PW *pw,
238 __isl_take isl_reordering *exp)
240 int i;
242 pw = FN(PW,cow)(pw);
243 if (!pw || !exp)
244 goto error;
246 for (i = 0; i < pw->n; ++i) {
247 pw->p[i].set = isl_set_realign(pw->p[i].set,
248 isl_reordering_copy(exp));
249 if (!pw->p[i].set)
250 goto error;
251 pw->p[i].FIELD = FN(EL,realign_domain)(pw->p[i].FIELD,
252 isl_reordering_copy(exp));
253 if (!pw->p[i].FIELD)
254 goto error;
257 pw = FN(PW,reset_domain_space)(pw, isl_space_copy(exp->dim));
259 isl_reordering_free(exp);
260 return pw;
261 error:
262 isl_reordering_free(exp);
263 FN(PW,free)(pw);
264 return NULL;
267 /* Align the parameters of "pw" to those of "model".
269 __isl_give PW *FN(PW,align_params)(__isl_take PW *pw, __isl_take isl_space *model)
271 isl_ctx *ctx;
272 isl_bool equal_params;
274 if (!pw || !model)
275 goto error;
277 ctx = isl_space_get_ctx(model);
278 if (!isl_space_has_named_params(model))
279 isl_die(ctx, isl_error_invalid,
280 "model has unnamed parameters", goto error);
281 if (!isl_space_has_named_params(pw->dim))
282 isl_die(ctx, isl_error_invalid,
283 "input has unnamed parameters", goto error);
284 equal_params = isl_space_has_equal_params(pw->dim, model);
285 if (equal_params < 0)
286 goto error;
287 if (!equal_params) {
288 isl_reordering *exp;
290 model = isl_space_drop_dims(model, isl_dim_in,
291 0, isl_space_dim(model, isl_dim_in));
292 model = isl_space_drop_dims(model, isl_dim_out,
293 0, isl_space_dim(model, isl_dim_out));
294 exp = isl_parameter_alignment_reordering(pw->dim, model);
295 exp = isl_reordering_extend_space(exp,
296 FN(PW,get_domain_space)(pw));
297 pw = FN(PW,realign_domain)(pw, exp);
300 isl_space_free(model);
301 return pw;
302 error:
303 isl_space_free(model);
304 FN(PW,free)(pw);
305 return NULL;
308 static __isl_give PW *FN(PW,align_params_pw_pw_and)(__isl_take PW *pw1,
309 __isl_take PW *pw2,
310 __isl_give PW *(*fn)(__isl_take PW *pw1, __isl_take PW *pw2))
312 isl_ctx *ctx;
313 isl_bool equal_params;
315 if (!pw1 || !pw2)
316 goto error;
317 equal_params = isl_space_has_equal_params(pw1->dim, pw2->dim);
318 if (equal_params < 0)
319 goto error;
320 if (equal_params)
321 return fn(pw1, pw2);
322 ctx = FN(PW,get_ctx)(pw1);
323 if (!isl_space_has_named_params(pw1->dim) ||
324 !isl_space_has_named_params(pw2->dim))
325 isl_die(ctx, isl_error_invalid,
326 "unaligned unnamed parameters", goto error);
327 pw1 = FN(PW,align_params)(pw1, FN(PW,get_space)(pw2));
328 pw2 = FN(PW,align_params)(pw2, FN(PW,get_space)(pw1));
329 return fn(pw1, pw2);
330 error:
331 FN(PW,free)(pw1);
332 FN(PW,free)(pw2);
333 return NULL;
336 static __isl_give PW *FN(PW,align_params_pw_set_and)(__isl_take PW *pw,
337 __isl_take isl_set *set,
338 __isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_set *set))
340 isl_ctx *ctx;
341 isl_bool aligned;
343 if (!pw || !set)
344 goto error;
345 aligned = isl_set_space_has_equal_params(set, pw->dim);
346 if (aligned < 0)
347 goto error;
348 if (aligned)
349 return fn(pw, set);
350 ctx = FN(PW,get_ctx)(pw);
351 if (!isl_space_has_named_params(pw->dim) ||
352 !isl_space_has_named_params(set->dim))
353 isl_die(ctx, isl_error_invalid,
354 "unaligned unnamed parameters", goto error);
355 pw = FN(PW,align_params)(pw, isl_set_get_space(set));
356 set = isl_set_align_params(set, FN(PW,get_space)(pw));
357 return fn(pw, set);
358 error:
359 FN(PW,free)(pw);
360 isl_set_free(set);
361 return NULL;
363 #endif
365 static __isl_give PW *FN(PW,union_add_aligned)(__isl_take PW *pw1,
366 __isl_take PW *pw2)
368 int i, j, n;
369 struct PW *res;
370 isl_ctx *ctx;
371 isl_set *set;
373 if (!pw1 || !pw2)
374 goto error;
376 ctx = isl_space_get_ctx(pw1->dim);
377 #ifdef HAS_TYPE
378 if (pw1->type != pw2->type)
379 isl_die(ctx, isl_error_invalid,
380 "fold types don't match", goto error);
381 #endif
382 isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
384 if (FN(PW,IS_ZERO)(pw1)) {
385 FN(PW,free)(pw1);
386 return pw2;
389 if (FN(PW,IS_ZERO)(pw2)) {
390 FN(PW,free)(pw2);
391 return pw1;
394 n = (pw1->n + 1) * (pw2->n + 1);
395 #ifdef HAS_TYPE
396 res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), pw1->type, n);
397 #else
398 res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), n);
399 #endif
401 for (i = 0; i < pw1->n; ++i) {
402 set = isl_set_copy(pw1->p[i].set);
403 for (j = 0; j < pw2->n; ++j) {
404 struct isl_set *common;
405 EL *sum;
406 common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
407 isl_set_copy(pw2->p[j].set));
408 if (isl_set_plain_is_empty(common)) {
409 isl_set_free(common);
410 continue;
412 set = isl_set_subtract(set,
413 isl_set_copy(pw2->p[j].set));
415 sum = FN(EL,add_on_domain)(common,
416 FN(EL,copy)(pw1->p[i].FIELD),
417 FN(EL,copy)(pw2->p[j].FIELD));
419 res = FN(PW,add_piece)(res, common, sum);
421 res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw1->p[i].FIELD));
424 for (j = 0; j < pw2->n; ++j) {
425 set = isl_set_copy(pw2->p[j].set);
426 for (i = 0; i < pw1->n; ++i)
427 set = isl_set_subtract(set,
428 isl_set_copy(pw1->p[i].set));
429 res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw2->p[j].FIELD));
432 FN(PW,free)(pw1);
433 FN(PW,free)(pw2);
435 return res;
436 error:
437 FN(PW,free)(pw1);
438 FN(PW,free)(pw2);
439 return NULL;
442 /* Private version of "union_add". For isl_pw_qpolynomial and
443 * isl_pw_qpolynomial_fold, we prefer to simply call it "add".
445 static __isl_give PW *FN(PW,union_add_)(__isl_take PW *pw1, __isl_take PW *pw2)
447 return FN(PW,align_params_pw_pw_and)(pw1, pw2,
448 &FN(PW,union_add_aligned));
451 /* Make sure "pw" has room for at least "n" more pieces.
453 * If there is only one reference to pw, we extend it in place.
454 * Otherwise, we create a new PW and copy the pieces.
456 static __isl_give PW *FN(PW,grow)(__isl_take PW *pw, int n)
458 int i;
459 isl_ctx *ctx;
460 PW *res;
462 if (!pw)
463 return NULL;
464 if (pw->n + n <= pw->size)
465 return pw;
466 ctx = FN(PW,get_ctx)(pw);
467 n += pw->n;
468 if (pw->ref == 1) {
469 res = isl_realloc(ctx, pw, struct PW,
470 sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
471 if (!res)
472 return FN(PW,free)(pw);
473 res->size = n;
474 return res;
476 #ifdef HAS_TYPE
477 res = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, n);
478 #else
479 res = FN(PW,alloc_size)(isl_space_copy(pw->dim), n);
480 #endif
481 if (!res)
482 return FN(PW,free)(pw);
483 for (i = 0; i < pw->n; ++i)
484 res = FN(PW,add_piece)(res, isl_set_copy(pw->p[i].set),
485 FN(EL,copy)(pw->p[i].FIELD));
486 FN(PW,free)(pw);
487 return res;
490 static __isl_give PW *FN(PW,add_disjoint_aligned)(__isl_take PW *pw1,
491 __isl_take PW *pw2)
493 int i;
494 isl_ctx *ctx;
496 if (!pw1 || !pw2)
497 goto error;
499 if (pw1->size < pw1->n + pw2->n && pw1->n < pw2->n)
500 return FN(PW,add_disjoint_aligned)(pw2, pw1);
502 ctx = isl_space_get_ctx(pw1->dim);
503 #ifdef HAS_TYPE
504 if (pw1->type != pw2->type)
505 isl_die(ctx, isl_error_invalid,
506 "fold types don't match", goto error);
507 #endif
508 isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
510 if (FN(PW,IS_ZERO)(pw1)) {
511 FN(PW,free)(pw1);
512 return pw2;
515 if (FN(PW,IS_ZERO)(pw2)) {
516 FN(PW,free)(pw2);
517 return pw1;
520 pw1 = FN(PW,grow)(pw1, pw2->n);
521 if (!pw1)
522 goto error;
524 for (i = 0; i < pw2->n; ++i)
525 pw1 = FN(PW,add_piece)(pw1,
526 isl_set_copy(pw2->p[i].set),
527 FN(EL,copy)(pw2->p[i].FIELD));
529 FN(PW,free)(pw2);
531 return pw1;
532 error:
533 FN(PW,free)(pw1);
534 FN(PW,free)(pw2);
535 return NULL;
538 __isl_give PW *FN(PW,add_disjoint)(__isl_take PW *pw1, __isl_take PW *pw2)
540 return FN(PW,align_params_pw_pw_and)(pw1, pw2,
541 &FN(PW,add_disjoint_aligned));
544 /* This function is currently only used from isl_aff.c
546 static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
547 __isl_take PW *pw2, __isl_take isl_space *space,
548 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
549 __attribute__ ((unused));
551 /* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
552 * The result of "fn" (and therefore also of this function) lives in "space".
554 static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
555 __isl_take PW *pw2, __isl_take isl_space *space,
556 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
558 int i, j, n;
559 PW *res = NULL;
561 if (!pw1 || !pw2)
562 goto error;
564 n = pw1->n * pw2->n;
565 #ifdef HAS_TYPE
566 res = FN(PW,alloc_size)(isl_space_copy(space), pw1->type, n);
567 #else
568 res = FN(PW,alloc_size)(isl_space_copy(space), n);
569 #endif
571 for (i = 0; i < pw1->n; ++i) {
572 for (j = 0; j < pw2->n; ++j) {
573 isl_set *common;
574 EL *res_ij;
575 int empty;
577 common = isl_set_intersect(
578 isl_set_copy(pw1->p[i].set),
579 isl_set_copy(pw2->p[j].set));
580 empty = isl_set_plain_is_empty(common);
581 if (empty < 0 || empty) {
582 isl_set_free(common);
583 if (empty < 0)
584 goto error;
585 continue;
588 res_ij = fn(FN(EL,copy)(pw1->p[i].FIELD),
589 FN(EL,copy)(pw2->p[j].FIELD));
590 res_ij = FN(EL,gist)(res_ij, isl_set_copy(common));
592 res = FN(PW,add_piece)(res, common, res_ij);
596 isl_space_free(space);
597 FN(PW,free)(pw1);
598 FN(PW,free)(pw2);
599 return res;
600 error:
601 isl_space_free(space);
602 FN(PW,free)(pw1);
603 FN(PW,free)(pw2);
604 FN(PW,free)(res);
605 return NULL;
608 /* This function is currently only used from isl_aff.c
610 static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
611 __isl_take PW *pw2,
612 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
613 __attribute__ ((unused));
615 /* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
616 * The result of "fn" is assumed to live in the same space as "pw1" and "pw2".
618 static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
619 __isl_take PW *pw2,
620 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
622 isl_space *space;
624 if (!pw1 || !pw2)
625 goto error;
627 space = isl_space_copy(pw1->dim);
628 return FN(PW,on_shared_domain_in)(pw1, pw2, space, fn);
629 error:
630 FN(PW,free)(pw1);
631 FN(PW,free)(pw2);
632 return NULL;
635 #ifndef NO_NEG
636 __isl_give PW *FN(PW,neg)(__isl_take PW *pw)
638 int i;
640 if (!pw)
641 return NULL;
643 if (FN(PW,IS_ZERO)(pw))
644 return pw;
646 pw = FN(PW,cow)(pw);
647 if (!pw)
648 return NULL;
650 for (i = 0; i < pw->n; ++i) {
651 pw->p[i].FIELD = FN(EL,neg)(pw->p[i].FIELD);
652 if (!pw->p[i].FIELD)
653 return FN(PW,free)(pw);
656 return pw;
658 #endif
660 #ifndef NO_SUB
661 __isl_give PW *FN(PW,sub)(__isl_take PW *pw1, __isl_take PW *pw2)
663 return FN(PW,add)(pw1, FN(PW,neg)(pw2));
665 #endif
667 #ifndef NO_EVAL
668 __isl_give isl_val *FN(PW,eval)(__isl_take PW *pw, __isl_take isl_point *pnt)
670 int i;
671 int found = 0;
672 isl_ctx *ctx;
673 isl_space *pnt_dim = NULL;
674 isl_val *v;
676 if (!pw || !pnt)
677 goto error;
678 ctx = isl_point_get_ctx(pnt);
679 pnt_dim = isl_point_get_space(pnt);
680 isl_assert(ctx, isl_space_is_domain_internal(pnt_dim, pw->dim),
681 goto error);
683 for (i = 0; i < pw->n; ++i) {
684 found = isl_set_contains_point(pw->p[i].set, pnt);
685 if (found < 0)
686 goto error;
687 if (found)
688 break;
690 if (found)
691 v = FN(EL,eval)(FN(EL,copy)(pw->p[i].FIELD),
692 isl_point_copy(pnt));
693 else
694 v = isl_val_zero(ctx);
695 FN(PW,free)(pw);
696 isl_space_free(pnt_dim);
697 isl_point_free(pnt);
698 return v;
699 error:
700 FN(PW,free)(pw);
701 isl_space_free(pnt_dim);
702 isl_point_free(pnt);
703 return NULL;
705 #endif
707 /* Return the parameter domain of "pw".
709 __isl_give isl_set *FN(PW,params)(__isl_take PW *pw)
711 return isl_set_params(FN(PW,domain)(pw));
714 __isl_give isl_set *FN(PW,domain)(__isl_take PW *pw)
716 int i;
717 isl_set *dom;
719 if (!pw)
720 return NULL;
722 dom = isl_set_empty(FN(PW,get_domain_space)(pw));
723 for (i = 0; i < pw->n; ++i)
724 dom = isl_set_union_disjoint(dom, isl_set_copy(pw->p[i].set));
726 FN(PW,free)(pw);
728 return dom;
731 /* Exploit the equalities in the domain of piece "i" of "pw"
732 * to simplify the associated function.
733 * If the domain of piece "i" is empty, then remove it entirely,
734 * replacing it with the final piece.
736 static int FN(PW,exploit_equalities_and_remove_if_empty)(__isl_keep PW *pw,
737 int i)
739 isl_basic_set *aff;
740 int empty = isl_set_plain_is_empty(pw->p[i].set);
742 if (empty < 0)
743 return -1;
744 if (empty) {
745 isl_set_free(pw->p[i].set);
746 FN(EL,free)(pw->p[i].FIELD);
747 if (i != pw->n - 1)
748 pw->p[i] = pw->p[pw->n - 1];
749 pw->n--;
751 return 0;
754 aff = isl_set_affine_hull(isl_set_copy(pw->p[i].set));
755 pw->p[i].FIELD = FN(EL,substitute_equalities)(pw->p[i].FIELD, aff);
756 if (!pw->p[i].FIELD)
757 return -1;
759 return 0;
762 /* Convert a piecewise expression defined over a parameter domain
763 * into one that is defined over a zero-dimensional set.
765 __isl_give PW *FN(PW,from_range)(__isl_take PW *pw)
767 isl_space *space;
769 if (!pw)
770 return NULL;
771 if (!isl_space_is_set(pw->dim))
772 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
773 "not living in a set space", return FN(PW,free)(pw));
775 space = FN(PW,get_space)(pw);
776 space = isl_space_from_range(space);
777 pw = FN(PW,reset_space)(pw, space);
779 return pw;
782 /* Fix the value of the given parameter or domain dimension of "pw"
783 * to be equal to "value".
785 __isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type,
786 unsigned pos, int value)
788 int i;
790 if (!pw)
791 return NULL;
793 if (type == isl_dim_out)
794 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
795 "cannot fix output dimension", return FN(PW,free)(pw));
797 if (pw->n == 0)
798 return pw;
800 if (type == isl_dim_in)
801 type = isl_dim_set;
803 pw = FN(PW,cow)(pw);
804 if (!pw)
805 return FN(PW,free)(pw);
807 for (i = pw->n - 1; i >= 0; --i) {
808 pw->p[i].set = isl_set_fix_si(pw->p[i].set, type, pos, value);
809 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
810 return FN(PW,free)(pw);
813 return pw;
816 /* Restrict the domain of "pw" by combining each cell
817 * with "set" through a call to "fn", where "fn" may be
818 * isl_set_intersect, isl_set_intersect_params or isl_set_subtract.
820 static __isl_give PW *FN(PW,restrict_domain_aligned)(__isl_take PW *pw,
821 __isl_take isl_set *set,
822 __isl_give isl_set *(*fn)(__isl_take isl_set *set1,
823 __isl_take isl_set *set2))
825 int i;
827 if (!pw || !set)
828 goto error;
830 if (pw->n == 0) {
831 isl_set_free(set);
832 return pw;
835 pw = FN(PW,cow)(pw);
836 if (!pw)
837 goto error;
839 for (i = pw->n - 1; i >= 0; --i) {
840 pw->p[i].set = fn(pw->p[i].set, isl_set_copy(set));
841 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
842 goto error;
845 isl_set_free(set);
846 return pw;
847 error:
848 isl_set_free(set);
849 FN(PW,free)(pw);
850 return NULL;
853 static __isl_give PW *FN(PW,intersect_domain_aligned)(__isl_take PW *pw,
854 __isl_take isl_set *set)
856 return FN(PW,restrict_domain_aligned)(pw, set, &isl_set_intersect);
859 __isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw,
860 __isl_take isl_set *context)
862 return FN(PW,align_params_pw_set_and)(pw, context,
863 &FN(PW,intersect_domain_aligned));
866 static __isl_give PW *FN(PW,intersect_params_aligned)(__isl_take PW *pw,
867 __isl_take isl_set *set)
869 return FN(PW,restrict_domain_aligned)(pw, set,
870 &isl_set_intersect_params);
873 /* Intersect the domain of "pw" with the parameter domain "context".
875 __isl_give PW *FN(PW,intersect_params)(__isl_take PW *pw,
876 __isl_take isl_set *context)
878 return FN(PW,align_params_pw_set_and)(pw, context,
879 &FN(PW,intersect_params_aligned));
882 /* Subtract "domain' from the domain of "pw", assuming their
883 * parameters have been aligned.
885 static __isl_give PW *FN(PW,subtract_domain_aligned)(__isl_take PW *pw,
886 __isl_take isl_set *domain)
888 return FN(PW,restrict_domain_aligned)(pw, domain, &isl_set_subtract);
891 /* Subtract "domain' from the domain of "pw".
893 __isl_give PW *FN(PW,subtract_domain)(__isl_take PW *pw,
894 __isl_take isl_set *domain)
896 return FN(PW,align_params_pw_set_and)(pw, domain,
897 &FN(PW,subtract_domain_aligned));
900 /* Compute the gist of "pw" with respect to the domain constraints
901 * of "context" for the case where the domain of the last element
902 * of "pw" is equal to "context".
903 * Call "fn_el" to compute the gist of this element, replace
904 * its domain by the universe and drop all other elements
905 * as their domains are necessarily disjoint from "context".
907 static __isl_give PW *FN(PW,gist_last)(__isl_take PW *pw,
908 __isl_take isl_set *context,
909 __isl_give EL *(*fn_el)(__isl_take EL *el, __isl_take isl_set *set))
911 int i;
912 isl_space *space;
914 for (i = 0; i < pw->n - 1; ++i) {
915 isl_set_free(pw->p[i].set);
916 FN(EL,free)(pw->p[i].FIELD);
918 pw->p[0].FIELD = pw->p[pw->n - 1].FIELD;
919 pw->p[0].set = pw->p[pw->n - 1].set;
920 pw->n = 1;
922 space = isl_set_get_space(context);
923 pw->p[0].FIELD = fn_el(pw->p[0].FIELD, context);
924 context = isl_set_universe(space);
925 isl_set_free(pw->p[0].set);
926 pw->p[0].set = context;
928 if (!pw->p[0].FIELD || !pw->p[0].set)
929 return FN(PW,free)(pw);
931 return pw;
934 /* Compute the gist of "pw" with respect to the domain constraints
935 * of "context". Call "fn_el" to compute the gist of the elements
936 * and "fn_dom" to compute the gist of the domains.
938 * If the piecewise expression is empty or the context is the universe,
939 * then nothing can be simplified.
941 static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw,
942 __isl_take isl_set *context,
943 __isl_give EL *(*fn_el)(__isl_take EL *el,
944 __isl_take isl_set *set),
945 __isl_give isl_set *(*fn_dom)(__isl_take isl_set *set,
946 __isl_take isl_basic_set *bset))
948 int i;
949 int is_universe;
950 isl_bool aligned;
951 isl_basic_set *hull = NULL;
953 if (!pw || !context)
954 goto error;
956 if (pw->n == 0) {
957 isl_set_free(context);
958 return pw;
961 is_universe = isl_set_plain_is_universe(context);
962 if (is_universe < 0)
963 goto error;
964 if (is_universe) {
965 isl_set_free(context);
966 return pw;
969 aligned = isl_set_space_has_equal_params(context, pw->dim);
970 if (aligned < 0)
971 goto error;
972 if (!aligned) {
973 pw = FN(PW,align_params)(pw, isl_set_get_space(context));
974 context = isl_set_align_params(context, FN(PW,get_space)(pw));
977 pw = FN(PW,cow)(pw);
978 if (!pw)
979 goto error;
981 if (pw->n == 1) {
982 int equal;
984 equal = isl_set_plain_is_equal(pw->p[0].set, context);
985 if (equal < 0)
986 goto error;
987 if (equal)
988 return FN(PW,gist_last)(pw, context, fn_el);
991 context = isl_set_compute_divs(context);
992 hull = isl_set_simple_hull(isl_set_copy(context));
994 for (i = pw->n - 1; i >= 0; --i) {
995 isl_set *set_i;
996 int empty;
998 if (i == pw->n - 1) {
999 int equal;
1000 equal = isl_set_plain_is_equal(pw->p[i].set, context);
1001 if (equal < 0)
1002 goto error;
1003 if (equal) {
1004 isl_basic_set_free(hull);
1005 return FN(PW,gist_last)(pw, context, fn_el);
1008 set_i = isl_set_intersect(isl_set_copy(pw->p[i].set),
1009 isl_set_copy(context));
1010 empty = isl_set_plain_is_empty(set_i);
1011 pw->p[i].FIELD = fn_el(pw->p[i].FIELD, set_i);
1012 pw->p[i].set = fn_dom(pw->p[i].set, isl_basic_set_copy(hull));
1013 if (empty < 0 || !pw->p[i].FIELD || !pw->p[i].set)
1014 goto error;
1015 if (empty) {
1016 isl_set_free(pw->p[i].set);
1017 FN(EL,free)(pw->p[i].FIELD);
1018 if (i != pw->n - 1)
1019 pw->p[i] = pw->p[pw->n - 1];
1020 pw->n--;
1024 isl_basic_set_free(hull);
1025 isl_set_free(context);
1027 return pw;
1028 error:
1029 FN(PW,free)(pw);
1030 isl_basic_set_free(hull);
1031 isl_set_free(context);
1032 return NULL;
1035 static __isl_give PW *FN(PW,gist_domain_aligned)(__isl_take PW *pw,
1036 __isl_take isl_set *set)
1038 return FN(PW,gist_aligned)(pw, set, &FN(EL,gist),
1039 &isl_set_gist_basic_set);
1042 __isl_give PW *FN(PW,gist)(__isl_take PW *pw, __isl_take isl_set *context)
1044 return FN(PW,align_params_pw_set_and)(pw, context,
1045 &FN(PW,gist_domain_aligned));
1048 static __isl_give PW *FN(PW,gist_params_aligned)(__isl_take PW *pw,
1049 __isl_take isl_set *set)
1051 return FN(PW,gist_aligned)(pw, set, &FN(EL,gist_params),
1052 &isl_set_gist_params_basic_set);
1055 __isl_give PW *FN(PW,gist_params)(__isl_take PW *pw,
1056 __isl_take isl_set *context)
1058 return FN(PW,align_params_pw_set_and)(pw, context,
1059 &FN(PW,gist_params_aligned));
1062 /* Return -1 if the piece "p1" should be sorted before "p2"
1063 * and 1 if it should be sorted after "p2".
1064 * Return 0 if they do not need to be sorted in a specific order.
1066 * The two pieces are compared on the basis of their function value expressions.
1068 static int FN(PW,sort_field_cmp)(const void *p1, const void *p2, void *arg)
1070 struct FN(PW,piece) const *pc1 = p1;
1071 struct FN(PW,piece) const *pc2 = p2;
1073 return FN(EL,plain_cmp)(pc1->FIELD, pc2->FIELD);
1076 /* Sort the pieces of "pw" according to their function value
1077 * expressions and then combine pairs of adjacent pieces with
1078 * the same such expression.
1080 * The sorting is performed in place because it does not
1081 * change the meaning of "pw", but care needs to be
1082 * taken not to change any possible other copies of "pw"
1083 * in case anything goes wrong.
1085 __isl_give PW *FN(PW,sort)(__isl_take PW *pw)
1087 int i, j;
1088 isl_set *set;
1090 if (!pw)
1091 return NULL;
1092 if (pw->n <= 1)
1093 return pw;
1094 if (isl_sort(pw->p, pw->n, sizeof(pw->p[0]),
1095 &FN(PW,sort_field_cmp), NULL) < 0)
1096 return FN(PW,free)(pw);
1097 for (i = pw->n - 1; i >= 1; --i) {
1098 if (!FN(EL,plain_is_equal)(pw->p[i - 1].FIELD, pw->p[i].FIELD))
1099 continue;
1100 set = isl_set_union(isl_set_copy(pw->p[i - 1].set),
1101 isl_set_copy(pw->p[i].set));
1102 if (!set)
1103 return FN(PW,free)(pw);
1104 isl_set_free(pw->p[i].set);
1105 FN(EL,free)(pw->p[i].FIELD);
1106 isl_set_free(pw->p[i - 1].set);
1107 pw->p[i - 1].set = set;
1108 for (j = i + 1; j < pw->n; ++j)
1109 pw->p[j - 1] = pw->p[j];
1110 pw->n--;
1113 return pw;
1116 /* Coalesce the domains of "pw".
1118 * Prior to the actual coalescing, first sort the pieces such that
1119 * pieces with the same function value expression are combined
1120 * into a single piece, the combined domain of which can then
1121 * be coalesced.
1123 __isl_give PW *FN(PW,coalesce)(__isl_take PW *pw)
1125 int i;
1127 pw = FN(PW,sort)(pw);
1128 if (!pw)
1129 return NULL;
1131 for (i = 0; i < pw->n; ++i) {
1132 pw->p[i].set = isl_set_coalesce(pw->p[i].set);
1133 if (!pw->p[i].set)
1134 goto error;
1137 return pw;
1138 error:
1139 FN(PW,free)(pw);
1140 return NULL;
1143 isl_ctx *FN(PW,get_ctx)(__isl_keep PW *pw)
1145 return pw ? isl_space_get_ctx(pw->dim) : NULL;
1148 #ifndef NO_INVOLVES_DIMS
1149 isl_bool FN(PW,involves_dims)(__isl_keep PW *pw, enum isl_dim_type type,
1150 unsigned first, unsigned n)
1152 int i;
1153 enum isl_dim_type set_type;
1155 if (!pw)
1156 return isl_bool_error;
1157 if (pw->n == 0 || n == 0)
1158 return isl_bool_false;
1160 set_type = type == isl_dim_in ? isl_dim_set : type;
1162 for (i = 0; i < pw->n; ++i) {
1163 isl_bool involves = FN(EL,involves_dims)(pw->p[i].FIELD,
1164 type, first, n);
1165 if (involves < 0 || involves)
1166 return involves;
1167 involves = isl_set_involves_dims(pw->p[i].set,
1168 set_type, first, n);
1169 if (involves < 0 || involves)
1170 return involves;
1172 return isl_bool_false;
1174 #endif
1176 __isl_give PW *FN(PW,set_dim_name)(__isl_take PW *pw,
1177 enum isl_dim_type type, unsigned pos, const char *s)
1179 int i;
1180 enum isl_dim_type set_type;
1182 pw = FN(PW,cow)(pw);
1183 if (!pw)
1184 return NULL;
1186 set_type = type == isl_dim_in ? isl_dim_set : type;
1188 pw->dim = isl_space_set_dim_name(pw->dim, type, pos, s);
1189 if (!pw->dim)
1190 goto error;
1192 for (i = 0; i < pw->n; ++i) {
1193 pw->p[i].set = isl_set_set_dim_name(pw->p[i].set,
1194 set_type, pos, s);
1195 if (!pw->p[i].set)
1196 goto error;
1197 pw->p[i].FIELD = FN(EL,set_dim_name)(pw->p[i].FIELD, type, pos, s);
1198 if (!pw->p[i].FIELD)
1199 goto error;
1202 return pw;
1203 error:
1204 FN(PW,free)(pw);
1205 return NULL;
1208 #ifndef NO_DROP_DIMS
1209 __isl_give PW *FN(PW,drop_dims)(__isl_take PW *pw,
1210 enum isl_dim_type type, unsigned first, unsigned n)
1212 int i;
1213 enum isl_dim_type set_type;
1215 if (!pw)
1216 return NULL;
1217 if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
1218 return pw;
1220 set_type = type == isl_dim_in ? isl_dim_set : type;
1222 pw = FN(PW,cow)(pw);
1223 if (!pw)
1224 return NULL;
1225 pw->dim = isl_space_drop_dims(pw->dim, type, first, n);
1226 if (!pw->dim)
1227 goto error;
1228 for (i = 0; i < pw->n; ++i) {
1229 pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n);
1230 if (!pw->p[i].FIELD)
1231 goto error;
1232 if (type == isl_dim_out)
1233 continue;
1234 pw->p[i].set = isl_set_drop(pw->p[i].set, set_type, first, n);
1235 if (!pw->p[i].set)
1236 goto error;
1239 return pw;
1240 error:
1241 FN(PW,free)(pw);
1242 return NULL;
1245 /* This function is very similar to drop_dims.
1246 * The only difference is that the cells may still involve
1247 * the specified dimensions. They are removed using
1248 * isl_set_project_out instead of isl_set_drop.
1250 __isl_give PW *FN(PW,project_out)(__isl_take PW *pw,
1251 enum isl_dim_type type, unsigned first, unsigned n)
1253 int i;
1254 enum isl_dim_type set_type;
1256 if (!pw)
1257 return NULL;
1258 if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
1259 return pw;
1261 set_type = type == isl_dim_in ? isl_dim_set : type;
1263 pw = FN(PW,cow)(pw);
1264 if (!pw)
1265 return NULL;
1266 pw->dim = isl_space_drop_dims(pw->dim, type, first, n);
1267 if (!pw->dim)
1268 goto error;
1269 for (i = 0; i < pw->n; ++i) {
1270 pw->p[i].set = isl_set_project_out(pw->p[i].set,
1271 set_type, first, n);
1272 if (!pw->p[i].set)
1273 goto error;
1274 pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n);
1275 if (!pw->p[i].FIELD)
1276 goto error;
1279 return pw;
1280 error:
1281 FN(PW,free)(pw);
1282 return NULL;
1285 /* Project the domain of pw onto its parameter space.
1287 __isl_give PW *FN(PW,project_domain_on_params)(__isl_take PW *pw)
1289 isl_space *space;
1290 unsigned n;
1292 n = FN(PW,dim)(pw, isl_dim_in);
1293 pw = FN(PW,project_out)(pw, isl_dim_in, 0, n);
1294 space = FN(PW,get_domain_space)(pw);
1295 space = isl_space_params(space);
1296 pw = FN(PW,reset_domain_space)(pw, space);
1297 return pw;
1299 #endif
1301 #ifndef NO_INSERT_DIMS
1302 __isl_give PW *FN(PW,insert_dims)(__isl_take PW *pw, enum isl_dim_type type,
1303 unsigned first, unsigned n)
1305 int i;
1306 enum isl_dim_type set_type;
1308 if (!pw)
1309 return NULL;
1310 if (n == 0 && !isl_space_is_named_or_nested(pw->dim, type))
1311 return pw;
1313 set_type = type == isl_dim_in ? isl_dim_set : type;
1315 pw = FN(PW,cow)(pw);
1316 if (!pw)
1317 return NULL;
1319 pw->dim = isl_space_insert_dims(pw->dim, type, first, n);
1320 if (!pw->dim)
1321 goto error;
1323 for (i = 0; i < pw->n; ++i) {
1324 pw->p[i].set = isl_set_insert_dims(pw->p[i].set,
1325 set_type, first, n);
1326 if (!pw->p[i].set)
1327 goto error;
1328 pw->p[i].FIELD = FN(EL,insert_dims)(pw->p[i].FIELD,
1329 type, first, n);
1330 if (!pw->p[i].FIELD)
1331 goto error;
1334 return pw;
1335 error:
1336 FN(PW,free)(pw);
1337 return NULL;
1339 #endif
1341 __isl_give PW *FN(PW,fix_dim)(__isl_take PW *pw,
1342 enum isl_dim_type type, unsigned pos, isl_int v)
1344 int i;
1346 if (!pw)
1347 return NULL;
1349 if (type == isl_dim_in)
1350 type = isl_dim_set;
1352 pw = FN(PW,cow)(pw);
1353 if (!pw)
1354 return NULL;
1355 for (i = 0; i < pw->n; ++i) {
1356 pw->p[i].set = isl_set_fix(pw->p[i].set, type, pos, v);
1357 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
1358 return FN(PW,free)(pw);
1361 return pw;
1364 /* Fix the value of the variable at position "pos" of type "type" of "pw"
1365 * to be equal to "v".
1367 __isl_give PW *FN(PW,fix_val)(__isl_take PW *pw,
1368 enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
1370 if (!v)
1371 return FN(PW,free)(pw);
1372 if (!isl_val_is_int(v))
1373 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
1374 "expecting integer value", goto error);
1376 pw = FN(PW,fix_dim)(pw, type, pos, v->n);
1377 isl_val_free(v);
1379 return pw;
1380 error:
1381 isl_val_free(v);
1382 return FN(PW,free)(pw);
1385 unsigned FN(PW,dim)(__isl_keep PW *pw, enum isl_dim_type type)
1387 return pw ? isl_space_dim(pw->dim, type) : 0;
1390 __isl_give PW *FN(PW,split_dims)(__isl_take PW *pw,
1391 enum isl_dim_type type, unsigned first, unsigned n)
1393 int i;
1395 if (!pw)
1396 return NULL;
1397 if (n == 0)
1398 return pw;
1400 if (type == isl_dim_in)
1401 type = isl_dim_set;
1403 pw = FN(PW,cow)(pw);
1404 if (!pw)
1405 return NULL;
1406 if (!pw->dim)
1407 goto error;
1408 for (i = 0; i < pw->n; ++i) {
1409 pw->p[i].set = isl_set_split_dims(pw->p[i].set, type, first, n);
1410 if (!pw->p[i].set)
1411 goto error;
1414 return pw;
1415 error:
1416 FN(PW,free)(pw);
1417 return NULL;
1420 #ifndef NO_OPT
1421 /* Compute the maximal value attained by the piecewise quasipolynomial
1422 * on its domain or zero if the domain is empty.
1423 * In the worst case, the domain is scanned completely,
1424 * so the domain is assumed to be bounded.
1426 __isl_give isl_val *FN(PW,opt)(__isl_take PW *pw, int max)
1428 int i;
1429 isl_val *opt;
1431 if (!pw)
1432 return NULL;
1434 if (pw->n == 0) {
1435 opt = isl_val_zero(FN(PW,get_ctx)(pw));
1436 FN(PW,free)(pw);
1437 return opt;
1440 opt = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[0].FIELD),
1441 isl_set_copy(pw->p[0].set), max);
1442 for (i = 1; i < pw->n; ++i) {
1443 isl_val *opt_i;
1444 opt_i = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[i].FIELD),
1445 isl_set_copy(pw->p[i].set), max);
1446 if (max)
1447 opt = isl_val_max(opt, opt_i);
1448 else
1449 opt = isl_val_min(opt, opt_i);
1452 FN(PW,free)(pw);
1453 return opt;
1456 __isl_give isl_val *FN(PW,max)(__isl_take PW *pw)
1458 return FN(PW,opt)(pw, 1);
1461 __isl_give isl_val *FN(PW,min)(__isl_take PW *pw)
1463 return FN(PW,opt)(pw, 0);
1465 #endif
1467 __isl_give isl_space *FN(PW,get_space)(__isl_keep PW *pw)
1469 return pw ? isl_space_copy(pw->dim) : NULL;
1472 __isl_give isl_space *FN(PW,get_domain_space)(__isl_keep PW *pw)
1474 return pw ? isl_space_domain(isl_space_copy(pw->dim)) : NULL;
1477 /* Return the position of the dimension of the given type and name
1478 * in "pw".
1479 * Return -1 if no such dimension can be found.
1481 int FN(PW,find_dim_by_name)(__isl_keep PW *pw,
1482 enum isl_dim_type type, const char *name)
1484 if (!pw)
1485 return -1;
1486 return isl_space_find_dim_by_name(pw->dim, type, name);
1489 #ifndef NO_RESET_DIM
1490 /* Reset the space of "pw". Since we don't know if the elements
1491 * represent the spaces themselves or their domains, we pass along
1492 * both when we call their reset_space_and_domain.
1494 static __isl_give PW *FN(PW,reset_space_and_domain)(__isl_take PW *pw,
1495 __isl_take isl_space *space, __isl_take isl_space *domain)
1497 int i;
1499 pw = FN(PW,cow)(pw);
1500 if (!pw || !space || !domain)
1501 goto error;
1503 for (i = 0; i < pw->n; ++i) {
1504 pw->p[i].set = isl_set_reset_space(pw->p[i].set,
1505 isl_space_copy(domain));
1506 if (!pw->p[i].set)
1507 goto error;
1508 pw->p[i].FIELD = FN(EL,reset_space_and_domain)(pw->p[i].FIELD,
1509 isl_space_copy(space), isl_space_copy(domain));
1510 if (!pw->p[i].FIELD)
1511 goto error;
1514 isl_space_free(domain);
1516 isl_space_free(pw->dim);
1517 pw->dim = space;
1519 return pw;
1520 error:
1521 isl_space_free(domain);
1522 isl_space_free(space);
1523 FN(PW,free)(pw);
1524 return NULL;
1527 __isl_give PW *FN(PW,reset_domain_space)(__isl_take PW *pw,
1528 __isl_take isl_space *domain)
1530 isl_space *space;
1532 space = isl_space_extend_domain_with_range(isl_space_copy(domain),
1533 FN(PW,get_space)(pw));
1534 return FN(PW,reset_space_and_domain)(pw, space, domain);
1537 __isl_give PW *FN(PW,reset_space)(__isl_take PW *pw, __isl_take isl_space *dim)
1539 isl_space *domain;
1541 domain = isl_space_domain(isl_space_copy(dim));
1542 return FN(PW,reset_space_and_domain)(pw, dim, domain);
1545 __isl_give PW *FN(PW,set_tuple_id)(__isl_take PW *pw, enum isl_dim_type type,
1546 __isl_take isl_id *id)
1548 isl_space *space;
1550 pw = FN(PW,cow)(pw);
1551 if (!pw)
1552 goto error;
1554 space = FN(PW,get_space)(pw);
1555 space = isl_space_set_tuple_id(space, type, id);
1557 return FN(PW,reset_space)(pw, space);
1558 error:
1559 isl_id_free(id);
1560 return FN(PW,free)(pw);
1563 /* Drop the id on the specified tuple.
1565 __isl_give PW *FN(PW,reset_tuple_id)(__isl_take PW *pw, enum isl_dim_type type)
1567 isl_space *space;
1569 if (!pw)
1570 return NULL;
1571 if (!FN(PW,has_tuple_id)(pw, type))
1572 return pw;
1574 pw = FN(PW,cow)(pw);
1575 if (!pw)
1576 return NULL;
1578 space = FN(PW,get_space)(pw);
1579 space = isl_space_reset_tuple_id(space, type);
1581 return FN(PW,reset_space)(pw, space);
1584 __isl_give PW *FN(PW,set_dim_id)(__isl_take PW *pw,
1585 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
1587 pw = FN(PW,cow)(pw);
1588 if (!pw)
1589 goto error;
1590 pw->dim = isl_space_set_dim_id(pw->dim, type, pos, id);
1591 return FN(PW,reset_space)(pw, isl_space_copy(pw->dim));
1592 error:
1593 isl_id_free(id);
1594 return FN(PW,free)(pw);
1596 #endif
1598 /* Reset the user pointer on all identifiers of parameters and tuples
1599 * of the space of "pw".
1601 __isl_give PW *FN(PW,reset_user)(__isl_take PW *pw)
1603 isl_space *space;
1605 space = FN(PW,get_space)(pw);
1606 space = isl_space_reset_user(space);
1608 return FN(PW,reset_space)(pw, space);
1611 isl_bool FN(PW,has_equal_space)(__isl_keep PW *pw1, __isl_keep PW *pw2)
1613 if (!pw1 || !pw2)
1614 return isl_bool_error;
1616 return isl_space_is_equal(pw1->dim, pw2->dim);
1619 #ifndef NO_MORPH
1620 __isl_give PW *FN(PW,morph_domain)(__isl_take PW *pw,
1621 __isl_take isl_morph *morph)
1623 int i;
1624 isl_ctx *ctx;
1626 if (!pw || !morph)
1627 goto error;
1629 ctx = isl_space_get_ctx(pw->dim);
1630 isl_assert(ctx, isl_space_is_domain_internal(morph->dom->dim, pw->dim),
1631 goto error);
1633 pw = FN(PW,cow)(pw);
1634 if (!pw)
1635 goto error;
1636 pw->dim = isl_space_extend_domain_with_range(
1637 isl_space_copy(morph->ran->dim), pw->dim);
1638 if (!pw->dim)
1639 goto error;
1641 for (i = 0; i < pw->n; ++i) {
1642 pw->p[i].set = isl_morph_set(isl_morph_copy(morph), pw->p[i].set);
1643 if (!pw->p[i].set)
1644 goto error;
1645 pw->p[i].FIELD = FN(EL,morph_domain)(pw->p[i].FIELD,
1646 isl_morph_copy(morph));
1647 if (!pw->p[i].FIELD)
1648 goto error;
1651 isl_morph_free(morph);
1653 return pw;
1654 error:
1655 FN(PW,free)(pw);
1656 isl_morph_free(morph);
1657 return NULL;
1659 #endif
1661 int FN(PW,n_piece)(__isl_keep PW *pw)
1663 return pw ? pw->n : 0;
1666 isl_stat FN(PW,foreach_piece)(__isl_keep PW *pw,
1667 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el, void *user),
1668 void *user)
1670 int i;
1672 if (!pw)
1673 return isl_stat_error;
1675 for (i = 0; i < pw->n; ++i)
1676 if (fn(isl_set_copy(pw->p[i].set),
1677 FN(EL,copy)(pw->p[i].FIELD), user) < 0)
1678 return isl_stat_error;
1680 return isl_stat_ok;
1683 #ifndef NO_LIFT
1684 static isl_bool any_divs(__isl_keep isl_set *set)
1686 int i;
1688 if (!set)
1689 return isl_bool_error;
1691 for (i = 0; i < set->n; ++i)
1692 if (set->p[i]->n_div > 0)
1693 return isl_bool_true;
1695 return isl_bool_false;
1698 static isl_stat foreach_lifted_subset(__isl_take isl_set *set,
1699 __isl_take EL *el,
1700 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el,
1701 void *user), void *user)
1703 int i;
1705 if (!set || !el)
1706 goto error;
1708 for (i = 0; i < set->n; ++i) {
1709 isl_set *lift;
1710 EL *copy;
1712 lift = isl_set_from_basic_set(isl_basic_set_copy(set->p[i]));
1713 lift = isl_set_lift(lift);
1715 copy = FN(EL,copy)(el);
1716 copy = FN(EL,lift)(copy, isl_set_get_space(lift));
1718 if (fn(lift, copy, user) < 0)
1719 goto error;
1722 isl_set_free(set);
1723 FN(EL,free)(el);
1725 return isl_stat_ok;
1726 error:
1727 isl_set_free(set);
1728 FN(EL,free)(el);
1729 return isl_stat_error;
1732 isl_stat FN(PW,foreach_lifted_piece)(__isl_keep PW *pw,
1733 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el,
1734 void *user), void *user)
1736 int i;
1738 if (!pw)
1739 return isl_stat_error;
1741 for (i = 0; i < pw->n; ++i) {
1742 isl_bool any;
1743 isl_set *set;
1744 EL *el;
1746 any = any_divs(pw->p[i].set);
1747 if (any < 0)
1748 return isl_stat_error;
1749 set = isl_set_copy(pw->p[i].set);
1750 el = FN(EL,copy)(pw->p[i].FIELD);
1751 if (!any) {
1752 if (fn(set, el, user) < 0)
1753 return isl_stat_error;
1754 continue;
1756 if (foreach_lifted_subset(set, el, fn, user) < 0)
1757 return isl_stat_error;
1760 return isl_stat_ok;
1762 #endif
1764 #ifndef NO_MOVE_DIMS
1765 __isl_give PW *FN(PW,move_dims)(__isl_take PW *pw,
1766 enum isl_dim_type dst_type, unsigned dst_pos,
1767 enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1769 int i;
1771 pw = FN(PW,cow)(pw);
1772 if (!pw)
1773 return NULL;
1775 pw->dim = isl_space_move_dims(pw->dim, dst_type, dst_pos, src_type, src_pos, n);
1776 if (!pw->dim)
1777 goto error;
1779 for (i = 0; i < pw->n; ++i) {
1780 pw->p[i].FIELD = FN(EL,move_dims)(pw->p[i].FIELD,
1781 dst_type, dst_pos, src_type, src_pos, n);
1782 if (!pw->p[i].FIELD)
1783 goto error;
1786 if (dst_type == isl_dim_in)
1787 dst_type = isl_dim_set;
1788 if (src_type == isl_dim_in)
1789 src_type = isl_dim_set;
1791 for (i = 0; i < pw->n; ++i) {
1792 pw->p[i].set = isl_set_move_dims(pw->p[i].set,
1793 dst_type, dst_pos,
1794 src_type, src_pos, n);
1795 if (!pw->p[i].set)
1796 goto error;
1799 return pw;
1800 error:
1801 FN(PW,free)(pw);
1802 return NULL;
1804 #endif
1806 __isl_give PW *FN(PW,mul_isl_int)(__isl_take PW *pw, isl_int v)
1808 int i;
1810 if (isl_int_is_one(v))
1811 return pw;
1812 if (pw && DEFAULT_IS_ZERO && isl_int_is_zero(v)) {
1813 PW *zero;
1814 isl_space *dim = FN(PW,get_space)(pw);
1815 #ifdef HAS_TYPE
1816 zero = FN(PW,ZERO)(dim, pw->type);
1817 #else
1818 zero = FN(PW,ZERO)(dim);
1819 #endif
1820 FN(PW,free)(pw);
1821 return zero;
1823 pw = FN(PW,cow)(pw);
1824 if (!pw)
1825 return NULL;
1826 if (pw->n == 0)
1827 return pw;
1829 #ifdef HAS_TYPE
1830 if (isl_int_is_neg(v))
1831 pw->type = isl_fold_type_negate(pw->type);
1832 #endif
1833 for (i = 0; i < pw->n; ++i) {
1834 pw->p[i].FIELD = FN(EL,scale)(pw->p[i].FIELD, v);
1835 if (!pw->p[i].FIELD)
1836 goto error;
1839 return pw;
1840 error:
1841 FN(PW,free)(pw);
1842 return NULL;
1845 /* Multiply the pieces of "pw" by "v" and return the result.
1847 __isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v)
1849 int i;
1851 if (!pw || !v)
1852 goto error;
1854 if (isl_val_is_one(v)) {
1855 isl_val_free(v);
1856 return pw;
1858 if (pw && DEFAULT_IS_ZERO && isl_val_is_zero(v)) {
1859 PW *zero;
1860 isl_space *space = FN(PW,get_space)(pw);
1861 #ifdef HAS_TYPE
1862 zero = FN(PW,ZERO)(space, pw->type);
1863 #else
1864 zero = FN(PW,ZERO)(space);
1865 #endif
1866 FN(PW,free)(pw);
1867 isl_val_free(v);
1868 return zero;
1870 if (pw->n == 0) {
1871 isl_val_free(v);
1872 return pw;
1874 pw = FN(PW,cow)(pw);
1875 if (!pw)
1876 goto error;
1878 #ifdef HAS_TYPE
1879 if (isl_val_is_neg(v))
1880 pw->type = isl_fold_type_negate(pw->type);
1881 #endif
1882 for (i = 0; i < pw->n; ++i) {
1883 pw->p[i].FIELD = FN(EL,scale_val)(pw->p[i].FIELD,
1884 isl_val_copy(v));
1885 if (!pw->p[i].FIELD)
1886 goto error;
1889 isl_val_free(v);
1890 return pw;
1891 error:
1892 isl_val_free(v);
1893 FN(PW,free)(pw);
1894 return NULL;
1897 /* Divide the pieces of "pw" by "v" and return the result.
1899 __isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v)
1901 int i;
1903 if (!pw || !v)
1904 goto error;
1906 if (isl_val_is_one(v)) {
1907 isl_val_free(v);
1908 return pw;
1911 if (!isl_val_is_rat(v))
1912 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1913 "expecting rational factor", goto error);
1914 if (isl_val_is_zero(v))
1915 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1916 "cannot scale down by zero", goto error);
1918 if (pw->n == 0) {
1919 isl_val_free(v);
1920 return pw;
1922 pw = FN(PW,cow)(pw);
1923 if (!pw)
1924 goto error;
1926 #ifdef HAS_TYPE
1927 if (isl_val_is_neg(v))
1928 pw->type = isl_fold_type_negate(pw->type);
1929 #endif
1930 for (i = 0; i < pw->n; ++i) {
1931 pw->p[i].FIELD = FN(EL,scale_down_val)(pw->p[i].FIELD,
1932 isl_val_copy(v));
1933 if (!pw->p[i].FIELD)
1934 goto error;
1937 isl_val_free(v);
1938 return pw;
1939 error:
1940 isl_val_free(v);
1941 FN(PW,free)(pw);
1942 return NULL;
1945 __isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v)
1947 return FN(PW,mul_isl_int)(pw, v);
1950 /* Apply some normalization to "pw".
1951 * In particular, sort the pieces according to their function value
1952 * expressions, combining pairs of adjacent pieces with
1953 * the same such expression, and then normalize the domains of the pieces.
1955 * We normalize in place, but if anything goes wrong we need
1956 * to return NULL, so we need to make sure we don't change the
1957 * meaning of any possible other copies of "pw".
1959 __isl_give PW *FN(PW,normalize)(__isl_take PW *pw)
1961 int i;
1962 isl_set *set;
1964 pw = FN(PW,sort)(pw);
1965 if (!pw)
1966 return NULL;
1967 for (i = 0; i < pw->n; ++i) {
1968 set = isl_set_normalize(isl_set_copy(pw->p[i].set));
1969 if (!set)
1970 return FN(PW,free)(pw);
1971 isl_set_free(pw->p[i].set);
1972 pw->p[i].set = set;
1975 return pw;
1978 /* Is pw1 obviously equal to pw2?
1979 * That is, do they have obviously identical cells and obviously identical
1980 * elements on each cell?
1982 * If "pw1" or "pw2" contain any NaNs, then they are considered
1983 * not to be the same. A NaN is not equal to anything, not even
1984 * to another NaN.
1986 isl_bool FN(PW,plain_is_equal)(__isl_keep PW *pw1, __isl_keep PW *pw2)
1988 int i;
1989 isl_bool equal, has_nan;
1991 if (!pw1 || !pw2)
1992 return isl_bool_error;
1994 has_nan = FN(PW,involves_nan)(pw1);
1995 if (has_nan >= 0 && !has_nan)
1996 has_nan = FN(PW,involves_nan)(pw2);
1997 if (has_nan < 0 || has_nan)
1998 return isl_bool_not(has_nan);
2000 if (pw1 == pw2)
2001 return isl_bool_true;
2002 if (!isl_space_is_equal(pw1->dim, pw2->dim))
2003 return isl_bool_false;
2005 pw1 = FN(PW,copy)(pw1);
2006 pw2 = FN(PW,copy)(pw2);
2007 pw1 = FN(PW,normalize)(pw1);
2008 pw2 = FN(PW,normalize)(pw2);
2009 if (!pw1 || !pw2)
2010 goto error;
2012 equal = pw1->n == pw2->n;
2013 for (i = 0; equal && i < pw1->n; ++i) {
2014 equal = isl_set_plain_is_equal(pw1->p[i].set, pw2->p[i].set);
2015 if (equal < 0)
2016 goto error;
2017 if (!equal)
2018 break;
2019 equal = FN(EL,plain_is_equal)(pw1->p[i].FIELD, pw2->p[i].FIELD);
2020 if (equal < 0)
2021 goto error;
2024 FN(PW,free)(pw1);
2025 FN(PW,free)(pw2);
2026 return equal;
2027 error:
2028 FN(PW,free)(pw1);
2029 FN(PW,free)(pw2);
2030 return isl_bool_error;
2033 /* Does "pw" involve any NaNs?
2035 isl_bool FN(PW,involves_nan)(__isl_keep PW *pw)
2037 int i;
2039 if (!pw)
2040 return isl_bool_error;
2041 if (pw->n == 0)
2042 return isl_bool_false;
2044 for (i = 0; i < pw->n; ++i) {
2045 isl_bool has_nan = FN(EL,involves_nan)(pw->p[i].FIELD);
2046 if (has_nan < 0 || has_nan)
2047 return has_nan;
2050 return isl_bool_false;
2053 #ifndef NO_PULLBACK
2054 static __isl_give PW *FN(PW,align_params_pw_multi_aff_and)(__isl_take PW *pw,
2055 __isl_take isl_multi_aff *ma,
2056 __isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_multi_aff *ma))
2058 isl_ctx *ctx;
2059 isl_bool equal_params;
2060 isl_space *ma_space;
2062 ma_space = isl_multi_aff_get_space(ma);
2063 if (!pw || !ma || !ma_space)
2064 goto error;
2065 equal_params = isl_space_has_equal_params(pw->dim, ma_space);
2066 if (equal_params < 0)
2067 goto error;
2068 if (equal_params) {
2069 isl_space_free(ma_space);
2070 return fn(pw, ma);
2072 ctx = FN(PW,get_ctx)(pw);
2073 if (!isl_space_has_named_params(pw->dim) ||
2074 !isl_space_has_named_params(ma_space))
2075 isl_die(ctx, isl_error_invalid,
2076 "unaligned unnamed parameters", goto error);
2077 pw = FN(PW,align_params)(pw, ma_space);
2078 ma = isl_multi_aff_align_params(ma, FN(PW,get_space)(pw));
2079 return fn(pw, ma);
2080 error:
2081 isl_space_free(ma_space);
2082 FN(PW,free)(pw);
2083 isl_multi_aff_free(ma);
2084 return NULL;
2087 static __isl_give PW *FN(PW,align_params_pw_pw_multi_aff_and)(__isl_take PW *pw,
2088 __isl_take isl_pw_multi_aff *pma,
2089 __isl_give PW *(*fn)(__isl_take PW *pw,
2090 __isl_take isl_pw_multi_aff *ma))
2092 isl_ctx *ctx;
2093 isl_bool equal_params;
2094 isl_space *pma_space;
2096 pma_space = isl_pw_multi_aff_get_space(pma);
2097 if (!pw || !pma || !pma_space)
2098 goto error;
2099 equal_params = isl_space_has_equal_params(pw->dim, pma_space);
2100 if (equal_params < 0)
2101 goto error;
2102 if (equal_params) {
2103 isl_space_free(pma_space);
2104 return fn(pw, pma);
2106 ctx = FN(PW,get_ctx)(pw);
2107 if (!isl_space_has_named_params(pw->dim) ||
2108 !isl_space_has_named_params(pma_space))
2109 isl_die(ctx, isl_error_invalid,
2110 "unaligned unnamed parameters", goto error);
2111 pw = FN(PW,align_params)(pw, pma_space);
2112 pma = isl_pw_multi_aff_align_params(pma, FN(PW,get_space)(pw));
2113 return fn(pw, pma);
2114 error:
2115 isl_space_free(pma_space);
2116 FN(PW,free)(pw);
2117 isl_pw_multi_aff_free(pma);
2118 return NULL;
2121 /* Compute the pullback of "pw" by the function represented by "ma".
2122 * In other words, plug in "ma" in "pw".
2124 static __isl_give PW *FN(PW,pullback_multi_aff_aligned)(__isl_take PW *pw,
2125 __isl_take isl_multi_aff *ma)
2127 int i;
2128 isl_space *space = NULL;
2130 ma = isl_multi_aff_align_divs(ma);
2131 pw = FN(PW,cow)(pw);
2132 if (!pw || !ma)
2133 goto error;
2135 space = isl_space_join(isl_multi_aff_get_space(ma),
2136 FN(PW,get_space)(pw));
2138 for (i = 0; i < pw->n; ++i) {
2139 pw->p[i].set = isl_set_preimage_multi_aff(pw->p[i].set,
2140 isl_multi_aff_copy(ma));
2141 if (!pw->p[i].set)
2142 goto error;
2143 pw->p[i].FIELD = FN(EL,pullback_multi_aff)(pw->p[i].FIELD,
2144 isl_multi_aff_copy(ma));
2145 if (!pw->p[i].FIELD)
2146 goto error;
2149 pw = FN(PW,reset_space)(pw, space);
2150 isl_multi_aff_free(ma);
2151 return pw;
2152 error:
2153 isl_space_free(space);
2154 isl_multi_aff_free(ma);
2155 FN(PW,free)(pw);
2156 return NULL;
2159 __isl_give PW *FN(PW,pullback_multi_aff)(__isl_take PW *pw,
2160 __isl_take isl_multi_aff *ma)
2162 return FN(PW,align_params_pw_multi_aff_and)(pw, ma,
2163 &FN(PW,pullback_multi_aff_aligned));
2166 /* Compute the pullback of "pw" by the function represented by "pma".
2167 * In other words, plug in "pma" in "pw".
2169 static __isl_give PW *FN(PW,pullback_pw_multi_aff_aligned)(__isl_take PW *pw,
2170 __isl_take isl_pw_multi_aff *pma)
2172 int i;
2173 PW *res;
2175 if (!pma)
2176 goto error;
2178 if (pma->n == 0) {
2179 isl_space *space;
2180 space = isl_space_join(isl_pw_multi_aff_get_space(pma),
2181 FN(PW,get_space)(pw));
2182 isl_pw_multi_aff_free(pma);
2183 res = FN(PW,empty)(space);
2184 FN(PW,free)(pw);
2185 return res;
2188 res = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
2189 isl_multi_aff_copy(pma->p[0].maff));
2190 res = FN(PW,intersect_domain)(res, isl_set_copy(pma->p[0].set));
2192 for (i = 1; i < pma->n; ++i) {
2193 PW *res_i;
2195 res_i = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
2196 isl_multi_aff_copy(pma->p[i].maff));
2197 res_i = FN(PW,intersect_domain)(res_i,
2198 isl_set_copy(pma->p[i].set));
2199 res = FN(PW,add_disjoint)(res, res_i);
2202 isl_pw_multi_aff_free(pma);
2203 FN(PW,free)(pw);
2204 return res;
2205 error:
2206 isl_pw_multi_aff_free(pma);
2207 FN(PW,free)(pw);
2208 return NULL;
2211 __isl_give PW *FN(PW,pullback_pw_multi_aff)(__isl_take PW *pw,
2212 __isl_take isl_pw_multi_aff *pma)
2214 return FN(PW,align_params_pw_pw_multi_aff_and)(pw, pma,
2215 &FN(PW,pullback_pw_multi_aff_aligned));
2217 #endif