isl_multi_templ.c: extract out isl_multi_product_templ.c
[isl.git] / isl_pw_templ.c
bloba828f695ee643e999d26d52a72f3fb6f0fd7f6f9
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/id.h>
15 #include <isl/aff.h>
16 #include <isl_sort.h>
17 #include <isl_val_private.h>
19 #include <isl_pw_macro.h>
21 #ifdef HAS_TYPE
22 __isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *dim,
23 enum isl_fold type, int n)
24 #else
25 __isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *dim, int n)
26 #endif
28 isl_ctx *ctx;
29 struct PW *pw;
31 if (!dim)
32 return NULL;
33 ctx = isl_space_get_ctx(dim);
34 isl_assert(ctx, n >= 0, goto error);
35 pw = isl_alloc(ctx, struct PW,
36 sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
37 if (!pw)
38 goto error;
40 pw->ref = 1;
41 #ifdef HAS_TYPE
42 pw->type = type;
43 #endif
44 pw->size = n;
45 pw->n = 0;
46 pw->dim = dim;
47 return pw;
48 error:
49 isl_space_free(dim);
50 return NULL;
53 #ifdef HAS_TYPE
54 __isl_give PW *FN(PW,ZERO)(__isl_take isl_space *dim, enum isl_fold type)
56 return FN(PW,alloc_size)(dim, type, 0);
58 #else
59 __isl_give PW *FN(PW,ZERO)(__isl_take isl_space *dim)
61 return FN(PW,alloc_size)(dim, 0);
63 #endif
65 __isl_give PW *FN(PW,add_piece)(__isl_take PW *pw,
66 __isl_take isl_set *set, __isl_take EL *el)
68 isl_ctx *ctx;
69 isl_space *el_dim = NULL;
71 if (!pw || !set || !el)
72 goto error;
74 if (isl_set_plain_is_empty(set) || FN(EL,EL_IS_ZERO)(el)) {
75 isl_set_free(set);
76 FN(EL,free)(el);
77 return pw;
80 ctx = isl_set_get_ctx(set);
81 #ifdef HAS_TYPE
82 if (pw->type != el->type)
83 isl_die(ctx, isl_error_invalid, "fold types don't match",
84 goto error);
85 #endif
86 el_dim = FN(EL,get_space(el));
87 isl_assert(ctx, isl_space_is_equal(pw->dim, el_dim), goto error);
88 isl_assert(ctx, pw->n < pw->size, goto error);
90 pw->p[pw->n].set = set;
91 pw->p[pw->n].FIELD = el;
92 pw->n++;
94 isl_space_free(el_dim);
95 return pw;
96 error:
97 isl_space_free(el_dim);
98 FN(PW,free)(pw);
99 isl_set_free(set);
100 FN(EL,free)(el);
101 return NULL;
104 /* Does the space of "set" correspond to that of the domain of "el".
106 static isl_bool FN(PW,compatible_domain)(__isl_keep EL *el,
107 __isl_keep isl_set *set)
109 isl_bool ok;
110 isl_space *el_space, *set_space;
112 if (!set || !el)
113 return isl_bool_error;
114 set_space = isl_set_get_space(set);
115 el_space = FN(EL,get_space)(el);
116 ok = isl_space_is_domain_internal(set_space, el_space);
117 isl_space_free(el_space);
118 isl_space_free(set_space);
119 return ok;
122 /* Check that the space of "set" corresponds to that of the domain of "el".
124 static isl_stat FN(PW,check_compatible_domain)(__isl_keep EL *el,
125 __isl_keep isl_set *set)
127 isl_bool ok;
129 ok = FN(PW,compatible_domain)(el, set);
130 if (ok < 0)
131 return isl_stat_error;
132 if (!ok)
133 isl_die(isl_set_get_ctx(set), isl_error_invalid,
134 "incompatible spaces", return isl_stat_error);
136 return isl_stat_ok;
139 #ifdef HAS_TYPE
140 __isl_give PW *FN(PW,alloc)(enum isl_fold type,
141 __isl_take isl_set *set, __isl_take EL *el)
142 #else
143 __isl_give PW *FN(PW,alloc)(__isl_take isl_set *set, __isl_take EL *el)
144 #endif
146 PW *pw;
148 if (FN(PW,check_compatible_domain)(el, set) < 0)
149 goto error;
151 #ifdef HAS_TYPE
152 pw = FN(PW,alloc_size)(FN(EL,get_space)(el), type, 1);
153 #else
154 pw = FN(PW,alloc_size)(FN(EL,get_space)(el), 1);
155 #endif
157 return FN(PW,add_piece)(pw, set, el);
158 error:
159 isl_set_free(set);
160 FN(EL,free)(el);
161 return NULL;
164 __isl_give PW *FN(PW,dup)(__isl_keep PW *pw)
166 int i;
167 PW *dup;
169 if (!pw)
170 return NULL;
172 #ifdef HAS_TYPE
173 dup = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, pw->n);
174 #else
175 dup = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->n);
176 #endif
177 if (!dup)
178 return NULL;
180 for (i = 0; i < pw->n; ++i)
181 dup = FN(PW,add_piece)(dup, isl_set_copy(pw->p[i].set),
182 FN(EL,copy)(pw->p[i].FIELD));
184 return dup;
187 __isl_give PW *FN(PW,cow)(__isl_take PW *pw)
189 if (!pw)
190 return NULL;
192 if (pw->ref == 1)
193 return pw;
194 pw->ref--;
195 return FN(PW,dup)(pw);
198 __isl_give PW *FN(PW,copy)(__isl_keep PW *pw)
200 if (!pw)
201 return NULL;
203 pw->ref++;
204 return pw;
207 __isl_null PW *FN(PW,free)(__isl_take PW *pw)
209 int i;
211 if (!pw)
212 return NULL;
213 if (--pw->ref > 0)
214 return NULL;
216 for (i = 0; i < pw->n; ++i) {
217 isl_set_free(pw->p[i].set);
218 FN(EL,free)(pw->p[i].FIELD);
220 isl_space_free(pw->dim);
221 free(pw);
223 return NULL;
226 const char *FN(PW,get_dim_name)(__isl_keep PW *pw, enum isl_dim_type type,
227 unsigned pos)
229 return pw ? isl_space_get_dim_name(pw->dim, type, pos) : NULL;
232 isl_bool FN(PW,has_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
233 unsigned pos)
235 return pw ? isl_space_has_dim_id(pw->dim, type, pos) : isl_bool_error;
238 __isl_give isl_id *FN(PW,get_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
239 unsigned pos)
241 return pw ? isl_space_get_dim_id(pw->dim, type, pos) : NULL;
244 isl_bool FN(PW,has_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
246 return pw ? isl_space_has_tuple_name(pw->dim, type) : isl_bool_error;
249 const char *FN(PW,get_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
251 return pw ? isl_space_get_tuple_name(pw->dim, type) : NULL;
254 isl_bool FN(PW,has_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
256 return pw ? isl_space_has_tuple_id(pw->dim, type) : isl_bool_error;
259 __isl_give isl_id *FN(PW,get_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
261 return pw ? isl_space_get_tuple_id(pw->dim, type) : NULL;
264 isl_bool FN(PW,IS_ZERO)(__isl_keep PW *pw)
266 if (!pw)
267 return isl_bool_error;
269 return pw->n == 0;
272 #ifndef NO_REALIGN
273 __isl_give PW *FN(PW,realign_domain)(__isl_take PW *pw,
274 __isl_take isl_reordering *exp)
276 int i;
278 pw = FN(PW,cow)(pw);
279 if (!pw || !exp)
280 goto error;
282 for (i = 0; i < pw->n; ++i) {
283 pw->p[i].set = isl_set_realign(pw->p[i].set,
284 isl_reordering_copy(exp));
285 if (!pw->p[i].set)
286 goto error;
287 pw->p[i].FIELD = FN(EL,realign_domain)(pw->p[i].FIELD,
288 isl_reordering_copy(exp));
289 if (!pw->p[i].FIELD)
290 goto error;
293 pw = FN(PW,reset_domain_space)(pw, isl_reordering_get_space(exp));
295 isl_reordering_free(exp);
296 return pw;
297 error:
298 isl_reordering_free(exp);
299 FN(PW,free)(pw);
300 return NULL;
303 /* Check that "pw" has only named parameters, reporting an error
304 * if it does not.
306 isl_stat FN(PW,check_named_params)(__isl_keep PW *pw)
308 return isl_space_check_named_params(FN(PW,peek_space)(pw));
311 /* Align the parameters of "pw" to those of "model".
313 __isl_give PW *FN(PW,align_params)(__isl_take PW *pw, __isl_take isl_space *model)
315 isl_ctx *ctx;
316 isl_bool equal_params;
318 if (!pw || !model)
319 goto error;
321 ctx = isl_space_get_ctx(model);
322 if (!isl_space_has_named_params(model))
323 isl_die(ctx, isl_error_invalid,
324 "model has unnamed parameters", goto error);
325 if (FN(PW,check_named_params)(pw) < 0)
326 goto error;
327 equal_params = isl_space_has_equal_params(pw->dim, model);
328 if (equal_params < 0)
329 goto error;
330 if (!equal_params) {
331 isl_reordering *exp;
333 exp = isl_parameter_alignment_reordering(pw->dim, model);
334 exp = isl_reordering_extend_space(exp,
335 FN(PW,get_domain_space)(pw));
336 pw = FN(PW,realign_domain)(pw, exp);
339 isl_space_free(model);
340 return pw;
341 error:
342 isl_space_free(model);
343 FN(PW,free)(pw);
344 return NULL;
347 static __isl_give PW *FN(PW,align_params_pw_pw_and)(__isl_take PW *pw1,
348 __isl_take PW *pw2,
349 __isl_give PW *(*fn)(__isl_take PW *pw1, __isl_take PW *pw2))
351 isl_bool equal_params;
353 if (!pw1 || !pw2)
354 goto error;
355 equal_params = isl_space_has_equal_params(pw1->dim, pw2->dim);
356 if (equal_params < 0)
357 goto error;
358 if (equal_params)
359 return fn(pw1, pw2);
360 if (FN(PW,check_named_params)(pw1) < 0 ||
361 FN(PW,check_named_params)(pw2) < 0)
362 goto error;
363 pw1 = FN(PW,align_params)(pw1, FN(PW,get_space)(pw2));
364 pw2 = FN(PW,align_params)(pw2, FN(PW,get_space)(pw1));
365 return fn(pw1, pw2);
366 error:
367 FN(PW,free)(pw1);
368 FN(PW,free)(pw2);
369 return NULL;
372 static __isl_give PW *FN(PW,align_params_pw_set_and)(__isl_take PW *pw,
373 __isl_take isl_set *set,
374 __isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_set *set))
376 isl_ctx *ctx;
377 isl_bool aligned;
379 if (!pw || !set)
380 goto error;
381 aligned = isl_set_space_has_equal_params(set, pw->dim);
382 if (aligned < 0)
383 goto error;
384 if (aligned)
385 return fn(pw, set);
386 ctx = FN(PW,get_ctx)(pw);
387 if (FN(PW,check_named_params)(pw) < 0)
388 goto error;
389 if (!isl_space_has_named_params(set->dim))
390 isl_die(ctx, isl_error_invalid,
391 "unaligned unnamed parameters", goto error);
392 pw = FN(PW,align_params)(pw, isl_set_get_space(set));
393 set = isl_set_align_params(set, FN(PW,get_space)(pw));
394 return fn(pw, set);
395 error:
396 FN(PW,free)(pw);
397 isl_set_free(set);
398 return NULL;
400 #endif
402 static __isl_give PW *FN(PW,union_add_aligned)(__isl_take PW *pw1,
403 __isl_take PW *pw2)
405 int i, j, n;
406 struct PW *res;
407 isl_ctx *ctx;
408 isl_set *set;
410 if (!pw1 || !pw2)
411 goto error;
413 ctx = isl_space_get_ctx(pw1->dim);
414 #ifdef HAS_TYPE
415 if (pw1->type != pw2->type)
416 isl_die(ctx, isl_error_invalid,
417 "fold types don't match", goto error);
418 #endif
419 isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
421 if (FN(PW,IS_ZERO)(pw1)) {
422 FN(PW,free)(pw1);
423 return pw2;
426 if (FN(PW,IS_ZERO)(pw2)) {
427 FN(PW,free)(pw2);
428 return pw1;
431 n = (pw1->n + 1) * (pw2->n + 1);
432 #ifdef HAS_TYPE
433 res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), pw1->type, n);
434 #else
435 res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), n);
436 #endif
438 for (i = 0; i < pw1->n; ++i) {
439 set = isl_set_copy(pw1->p[i].set);
440 for (j = 0; j < pw2->n; ++j) {
441 struct isl_set *common;
442 EL *sum;
443 common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
444 isl_set_copy(pw2->p[j].set));
445 if (isl_set_plain_is_empty(common)) {
446 isl_set_free(common);
447 continue;
449 set = isl_set_subtract(set,
450 isl_set_copy(pw2->p[j].set));
452 sum = FN(EL,add_on_domain)(common,
453 FN(EL,copy)(pw1->p[i].FIELD),
454 FN(EL,copy)(pw2->p[j].FIELD));
456 res = FN(PW,add_piece)(res, common, sum);
458 res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw1->p[i].FIELD));
461 for (j = 0; j < pw2->n; ++j) {
462 set = isl_set_copy(pw2->p[j].set);
463 for (i = 0; i < pw1->n; ++i)
464 set = isl_set_subtract(set,
465 isl_set_copy(pw1->p[i].set));
466 res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw2->p[j].FIELD));
469 FN(PW,free)(pw1);
470 FN(PW,free)(pw2);
472 return res;
473 error:
474 FN(PW,free)(pw1);
475 FN(PW,free)(pw2);
476 return NULL;
479 /* Private version of "union_add". For isl_pw_qpolynomial and
480 * isl_pw_qpolynomial_fold, we prefer to simply call it "add".
482 static __isl_give PW *FN(PW,union_add_)(__isl_take PW *pw1, __isl_take PW *pw2)
484 return FN(PW,align_params_pw_pw_and)(pw1, pw2,
485 &FN(PW,union_add_aligned));
488 /* Make sure "pw" has room for at least "n" more pieces.
490 * If there is only one reference to pw, we extend it in place.
491 * Otherwise, we create a new PW and copy the pieces.
493 static __isl_give PW *FN(PW,grow)(__isl_take PW *pw, int n)
495 int i;
496 isl_ctx *ctx;
497 PW *res;
499 if (!pw)
500 return NULL;
501 if (pw->n + n <= pw->size)
502 return pw;
503 ctx = FN(PW,get_ctx)(pw);
504 n += pw->n;
505 if (pw->ref == 1) {
506 res = isl_realloc(ctx, pw, struct PW,
507 sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
508 if (!res)
509 return FN(PW,free)(pw);
510 res->size = n;
511 return res;
513 #ifdef HAS_TYPE
514 res = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, n);
515 #else
516 res = FN(PW,alloc_size)(isl_space_copy(pw->dim), n);
517 #endif
518 if (!res)
519 return FN(PW,free)(pw);
520 for (i = 0; i < pw->n; ++i)
521 res = FN(PW,add_piece)(res, isl_set_copy(pw->p[i].set),
522 FN(EL,copy)(pw->p[i].FIELD));
523 FN(PW,free)(pw);
524 return res;
527 static __isl_give PW *FN(PW,add_disjoint_aligned)(__isl_take PW *pw1,
528 __isl_take PW *pw2)
530 int i;
531 isl_ctx *ctx;
533 if (!pw1 || !pw2)
534 goto error;
536 if (pw1->size < pw1->n + pw2->n && pw1->n < pw2->n)
537 return FN(PW,add_disjoint_aligned)(pw2, pw1);
539 ctx = isl_space_get_ctx(pw1->dim);
540 #ifdef HAS_TYPE
541 if (pw1->type != pw2->type)
542 isl_die(ctx, isl_error_invalid,
543 "fold types don't match", goto error);
544 #endif
545 isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
547 if (FN(PW,IS_ZERO)(pw1)) {
548 FN(PW,free)(pw1);
549 return pw2;
552 if (FN(PW,IS_ZERO)(pw2)) {
553 FN(PW,free)(pw2);
554 return pw1;
557 pw1 = FN(PW,grow)(pw1, pw2->n);
558 if (!pw1)
559 goto error;
561 for (i = 0; i < pw2->n; ++i)
562 pw1 = FN(PW,add_piece)(pw1,
563 isl_set_copy(pw2->p[i].set),
564 FN(EL,copy)(pw2->p[i].FIELD));
566 FN(PW,free)(pw2);
568 return pw1;
569 error:
570 FN(PW,free)(pw1);
571 FN(PW,free)(pw2);
572 return NULL;
575 __isl_give PW *FN(PW,add_disjoint)(__isl_take PW *pw1, __isl_take PW *pw2)
577 return FN(PW,align_params_pw_pw_and)(pw1, pw2,
578 &FN(PW,add_disjoint_aligned));
581 /* This function is currently only used from isl_aff.c
583 static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
584 __isl_take PW *pw2, __isl_take isl_space *space,
585 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
586 __attribute__ ((unused));
588 /* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
589 * The result of "fn" (and therefore also of this function) lives in "space".
591 static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
592 __isl_take PW *pw2, __isl_take isl_space *space,
593 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
595 int i, j, n;
596 PW *res = NULL;
598 if (!pw1 || !pw2)
599 goto error;
601 n = pw1->n * pw2->n;
602 #ifdef HAS_TYPE
603 res = FN(PW,alloc_size)(isl_space_copy(space), pw1->type, n);
604 #else
605 res = FN(PW,alloc_size)(isl_space_copy(space), n);
606 #endif
608 for (i = 0; i < pw1->n; ++i) {
609 for (j = 0; j < pw2->n; ++j) {
610 isl_set *common;
611 EL *res_ij;
612 int empty;
614 common = isl_set_intersect(
615 isl_set_copy(pw1->p[i].set),
616 isl_set_copy(pw2->p[j].set));
617 empty = isl_set_plain_is_empty(common);
618 if (empty < 0 || empty) {
619 isl_set_free(common);
620 if (empty < 0)
621 goto error;
622 continue;
625 res_ij = fn(FN(EL,copy)(pw1->p[i].FIELD),
626 FN(EL,copy)(pw2->p[j].FIELD));
627 res_ij = FN(EL,gist)(res_ij, isl_set_copy(common));
629 res = FN(PW,add_piece)(res, common, res_ij);
633 isl_space_free(space);
634 FN(PW,free)(pw1);
635 FN(PW,free)(pw2);
636 return res;
637 error:
638 isl_space_free(space);
639 FN(PW,free)(pw1);
640 FN(PW,free)(pw2);
641 FN(PW,free)(res);
642 return NULL;
645 /* This function is currently only used from isl_aff.c
647 static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
648 __isl_take PW *pw2,
649 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
650 __attribute__ ((unused));
652 /* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
653 * The result of "fn" is assumed to live in the same space as "pw1" and "pw2".
655 static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
656 __isl_take PW *pw2,
657 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
659 isl_space *space;
661 if (!pw1 || !pw2)
662 goto error;
664 space = isl_space_copy(pw1->dim);
665 return FN(PW,on_shared_domain_in)(pw1, pw2, space, fn);
666 error:
667 FN(PW,free)(pw1);
668 FN(PW,free)(pw2);
669 return NULL;
672 #ifndef NO_NEG
673 __isl_give PW *FN(PW,neg)(__isl_take PW *pw)
675 int i;
677 if (!pw)
678 return NULL;
680 if (FN(PW,IS_ZERO)(pw))
681 return pw;
683 pw = FN(PW,cow)(pw);
684 if (!pw)
685 return NULL;
687 for (i = 0; i < pw->n; ++i) {
688 pw->p[i].FIELD = FN(EL,neg)(pw->p[i].FIELD);
689 if (!pw->p[i].FIELD)
690 return FN(PW,free)(pw);
693 return pw;
695 #endif
697 #ifndef NO_SUB
698 __isl_give PW *FN(PW,sub)(__isl_take PW *pw1, __isl_take PW *pw2)
700 return FN(PW,add)(pw1, FN(PW,neg)(pw2));
702 #endif
704 /* Return the parameter domain of "pw".
706 __isl_give isl_set *FN(PW,params)(__isl_take PW *pw)
708 return isl_set_params(FN(PW,domain)(pw));
711 __isl_give isl_set *FN(PW,domain)(__isl_take PW *pw)
713 int i;
714 isl_set *dom;
716 if (!pw)
717 return NULL;
719 dom = isl_set_empty(FN(PW,get_domain_space)(pw));
720 for (i = 0; i < pw->n; ++i)
721 dom = isl_set_union_disjoint(dom, isl_set_copy(pw->p[i].set));
723 FN(PW,free)(pw);
725 return dom;
728 /* Exploit the equalities in the domain of piece "i" of "pw"
729 * to simplify the associated function.
730 * If the domain of piece "i" is empty, then remove it entirely,
731 * replacing it with the final piece.
733 static int FN(PW,exploit_equalities_and_remove_if_empty)(__isl_keep PW *pw,
734 int i)
736 isl_basic_set *aff;
737 int empty = isl_set_plain_is_empty(pw->p[i].set);
739 if (empty < 0)
740 return -1;
741 if (empty) {
742 isl_set_free(pw->p[i].set);
743 FN(EL,free)(pw->p[i].FIELD);
744 if (i != pw->n - 1)
745 pw->p[i] = pw->p[pw->n - 1];
746 pw->n--;
748 return 0;
751 aff = isl_set_affine_hull(isl_set_copy(pw->p[i].set));
752 pw->p[i].FIELD = FN(EL,substitute_equalities)(pw->p[i].FIELD, aff);
753 if (!pw->p[i].FIELD)
754 return -1;
756 return 0;
759 /* Convert a piecewise expression defined over a parameter domain
760 * into one that is defined over a zero-dimensional set.
762 __isl_give PW *FN(PW,from_range)(__isl_take PW *pw)
764 isl_space *space;
766 if (!pw)
767 return NULL;
768 if (!isl_space_is_set(pw->dim))
769 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
770 "not living in a set space", return FN(PW,free)(pw));
772 space = FN(PW,get_space)(pw);
773 space = isl_space_from_range(space);
774 pw = FN(PW,reset_space)(pw, space);
776 return pw;
779 /* Fix the value of the given parameter or domain dimension of "pw"
780 * to be equal to "value".
782 __isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type,
783 unsigned pos, int value)
785 int i;
787 if (!pw)
788 return NULL;
790 if (type == isl_dim_out)
791 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
792 "cannot fix output dimension", return FN(PW,free)(pw));
794 if (pw->n == 0)
795 return pw;
797 if (type == isl_dim_in)
798 type = isl_dim_set;
800 pw = FN(PW,cow)(pw);
801 if (!pw)
802 return FN(PW,free)(pw);
804 for (i = pw->n - 1; i >= 0; --i) {
805 pw->p[i].set = isl_set_fix_si(pw->p[i].set, type, pos, value);
806 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
807 return FN(PW,free)(pw);
810 return pw;
813 /* Restrict the domain of "pw" by combining each cell
814 * with "set" through a call to "fn", where "fn" may be
815 * isl_set_intersect, isl_set_intersect_params or isl_set_subtract.
817 static __isl_give PW *FN(PW,restrict_domain_aligned)(__isl_take PW *pw,
818 __isl_take isl_set *set,
819 __isl_give isl_set *(*fn)(__isl_take isl_set *set1,
820 __isl_take isl_set *set2))
822 int i;
824 if (!pw || !set)
825 goto error;
827 if (pw->n == 0) {
828 isl_set_free(set);
829 return pw;
832 pw = FN(PW,cow)(pw);
833 if (!pw)
834 goto error;
836 for (i = pw->n - 1; i >= 0; --i) {
837 pw->p[i].set = fn(pw->p[i].set, isl_set_copy(set));
838 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
839 goto error;
842 isl_set_free(set);
843 return pw;
844 error:
845 isl_set_free(set);
846 FN(PW,free)(pw);
847 return NULL;
850 static __isl_give PW *FN(PW,intersect_domain_aligned)(__isl_take PW *pw,
851 __isl_take isl_set *set)
853 return FN(PW,restrict_domain_aligned)(pw, set, &isl_set_intersect);
856 __isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw,
857 __isl_take isl_set *context)
859 return FN(PW,align_params_pw_set_and)(pw, context,
860 &FN(PW,intersect_domain_aligned));
863 static __isl_give PW *FN(PW,intersect_params_aligned)(__isl_take PW *pw,
864 __isl_take isl_set *set)
866 return FN(PW,restrict_domain_aligned)(pw, set,
867 &isl_set_intersect_params);
870 /* Intersect the domain of "pw" with the parameter domain "context".
872 __isl_give PW *FN(PW,intersect_params)(__isl_take PW *pw,
873 __isl_take isl_set *context)
875 return FN(PW,align_params_pw_set_and)(pw, context,
876 &FN(PW,intersect_params_aligned));
879 /* Subtract "domain' from the domain of "pw", assuming their
880 * parameters have been aligned.
882 static __isl_give PW *FN(PW,subtract_domain_aligned)(__isl_take PW *pw,
883 __isl_take isl_set *domain)
885 return FN(PW,restrict_domain_aligned)(pw, domain, &isl_set_subtract);
888 /* Subtract "domain' from the domain of "pw".
890 __isl_give PW *FN(PW,subtract_domain)(__isl_take PW *pw,
891 __isl_take isl_set *domain)
893 return FN(PW,align_params_pw_set_and)(pw, domain,
894 &FN(PW,subtract_domain_aligned));
897 /* Compute the gist of "pw" with respect to the domain constraints
898 * of "context" for the case where the domain of the last element
899 * of "pw" is equal to "context".
900 * Call "fn_el" to compute the gist of this element, replace
901 * its domain by the universe and drop all other elements
902 * as their domains are necessarily disjoint from "context".
904 static __isl_give PW *FN(PW,gist_last)(__isl_take PW *pw,
905 __isl_take isl_set *context,
906 __isl_give EL *(*fn_el)(__isl_take EL *el, __isl_take isl_set *set))
908 int i;
909 isl_space *space;
911 for (i = 0; i < pw->n - 1; ++i) {
912 isl_set_free(pw->p[i].set);
913 FN(EL,free)(pw->p[i].FIELD);
915 pw->p[0].FIELD = pw->p[pw->n - 1].FIELD;
916 pw->p[0].set = pw->p[pw->n - 1].set;
917 pw->n = 1;
919 space = isl_set_get_space(context);
920 pw->p[0].FIELD = fn_el(pw->p[0].FIELD, context);
921 context = isl_set_universe(space);
922 isl_set_free(pw->p[0].set);
923 pw->p[0].set = context;
925 if (!pw->p[0].FIELD || !pw->p[0].set)
926 return FN(PW,free)(pw);
928 return pw;
931 /* Compute the gist of "pw" with respect to the domain constraints
932 * of "context". Call "fn_el" to compute the gist of the elements
933 * and "fn_dom" to compute the gist of the domains.
935 * If the piecewise expression is empty or the context is the universe,
936 * then nothing can be simplified.
938 static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw,
939 __isl_take isl_set *context,
940 __isl_give EL *(*fn_el)(__isl_take EL *el,
941 __isl_take isl_set *set),
942 __isl_give isl_set *(*fn_dom)(__isl_take isl_set *set,
943 __isl_take isl_basic_set *bset))
945 int i;
946 int is_universe;
947 isl_bool aligned;
948 isl_basic_set *hull = NULL;
950 if (!pw || !context)
951 goto error;
953 if (pw->n == 0) {
954 isl_set_free(context);
955 return pw;
958 is_universe = isl_set_plain_is_universe(context);
959 if (is_universe < 0)
960 goto error;
961 if (is_universe) {
962 isl_set_free(context);
963 return pw;
966 aligned = isl_set_space_has_equal_params(context, pw->dim);
967 if (aligned < 0)
968 goto error;
969 if (!aligned) {
970 pw = FN(PW,align_params)(pw, isl_set_get_space(context));
971 context = isl_set_align_params(context, FN(PW,get_space)(pw));
974 pw = FN(PW,cow)(pw);
975 if (!pw)
976 goto error;
978 if (pw->n == 1) {
979 int equal;
981 equal = isl_set_plain_is_equal(pw->p[0].set, context);
982 if (equal < 0)
983 goto error;
984 if (equal)
985 return FN(PW,gist_last)(pw, context, fn_el);
988 context = isl_set_compute_divs(context);
989 hull = isl_set_simple_hull(isl_set_copy(context));
991 for (i = pw->n - 1; i >= 0; --i) {
992 isl_set *set_i;
993 int empty;
995 if (i == pw->n - 1) {
996 int equal;
997 equal = isl_set_plain_is_equal(pw->p[i].set, context);
998 if (equal < 0)
999 goto error;
1000 if (equal) {
1001 isl_basic_set_free(hull);
1002 return FN(PW,gist_last)(pw, context, fn_el);
1005 set_i = isl_set_intersect(isl_set_copy(pw->p[i].set),
1006 isl_set_copy(context));
1007 empty = isl_set_plain_is_empty(set_i);
1008 pw->p[i].FIELD = fn_el(pw->p[i].FIELD, set_i);
1009 pw->p[i].set = fn_dom(pw->p[i].set, isl_basic_set_copy(hull));
1010 if (empty < 0 || !pw->p[i].FIELD || !pw->p[i].set)
1011 goto error;
1012 if (empty) {
1013 isl_set_free(pw->p[i].set);
1014 FN(EL,free)(pw->p[i].FIELD);
1015 if (i != pw->n - 1)
1016 pw->p[i] = pw->p[pw->n - 1];
1017 pw->n--;
1021 isl_basic_set_free(hull);
1022 isl_set_free(context);
1024 return pw;
1025 error:
1026 FN(PW,free)(pw);
1027 isl_basic_set_free(hull);
1028 isl_set_free(context);
1029 return NULL;
1032 static __isl_give PW *FN(PW,gist_domain_aligned)(__isl_take PW *pw,
1033 __isl_take isl_set *set)
1035 return FN(PW,gist_aligned)(pw, set, &FN(EL,gist),
1036 &isl_set_gist_basic_set);
1039 __isl_give PW *FN(PW,gist)(__isl_take PW *pw, __isl_take isl_set *context)
1041 return FN(PW,align_params_pw_set_and)(pw, context,
1042 &FN(PW,gist_domain_aligned));
1045 static __isl_give PW *FN(PW,gist_params_aligned)(__isl_take PW *pw,
1046 __isl_take isl_set *set)
1048 return FN(PW,gist_aligned)(pw, set, &FN(EL,gist_params),
1049 &isl_set_gist_params_basic_set);
1052 __isl_give PW *FN(PW,gist_params)(__isl_take PW *pw,
1053 __isl_take isl_set *context)
1055 return FN(PW,align_params_pw_set_and)(pw, context,
1056 &FN(PW,gist_params_aligned));
1059 /* Return -1 if the piece "p1" should be sorted before "p2"
1060 * and 1 if it should be sorted after "p2".
1061 * Return 0 if they do not need to be sorted in a specific order.
1063 * The two pieces are compared on the basis of their function value expressions.
1065 static int FN(PW,sort_field_cmp)(const void *p1, const void *p2, void *arg)
1067 struct FN(PW,piece) const *pc1 = p1;
1068 struct FN(PW,piece) const *pc2 = p2;
1070 return FN(EL,plain_cmp)(pc1->FIELD, pc2->FIELD);
1073 /* Sort the pieces of "pw" according to their function value
1074 * expressions and then combine pairs of adjacent pieces with
1075 * the same such expression.
1077 * The sorting is performed in place because it does not
1078 * change the meaning of "pw", but care needs to be
1079 * taken not to change any possible other copies of "pw"
1080 * in case anything goes wrong.
1082 __isl_give PW *FN(PW,sort)(__isl_take PW *pw)
1084 int i, j;
1085 isl_set *set;
1087 if (!pw)
1088 return NULL;
1089 if (pw->n <= 1)
1090 return pw;
1091 if (isl_sort(pw->p, pw->n, sizeof(pw->p[0]),
1092 &FN(PW,sort_field_cmp), NULL) < 0)
1093 return FN(PW,free)(pw);
1094 for (i = pw->n - 1; i >= 1; --i) {
1095 if (!FN(EL,plain_is_equal)(pw->p[i - 1].FIELD, pw->p[i].FIELD))
1096 continue;
1097 set = isl_set_union(isl_set_copy(pw->p[i - 1].set),
1098 isl_set_copy(pw->p[i].set));
1099 if (!set)
1100 return FN(PW,free)(pw);
1101 isl_set_free(pw->p[i].set);
1102 FN(EL,free)(pw->p[i].FIELD);
1103 isl_set_free(pw->p[i - 1].set);
1104 pw->p[i - 1].set = set;
1105 for (j = i + 1; j < pw->n; ++j)
1106 pw->p[j - 1] = pw->p[j];
1107 pw->n--;
1110 return pw;
1113 /* Coalesce the domains of "pw".
1115 * Prior to the actual coalescing, first sort the pieces such that
1116 * pieces with the same function value expression are combined
1117 * into a single piece, the combined domain of which can then
1118 * be coalesced.
1120 __isl_give PW *FN(PW,coalesce)(__isl_take PW *pw)
1122 int i;
1124 pw = FN(PW,sort)(pw);
1125 if (!pw)
1126 return NULL;
1128 for (i = 0; i < pw->n; ++i) {
1129 pw->p[i].set = isl_set_coalesce(pw->p[i].set);
1130 if (!pw->p[i].set)
1131 goto error;
1134 return pw;
1135 error:
1136 FN(PW,free)(pw);
1137 return NULL;
1140 isl_ctx *FN(PW,get_ctx)(__isl_keep PW *pw)
1142 return pw ? isl_space_get_ctx(pw->dim) : NULL;
1145 isl_bool FN(PW,involves_dims)(__isl_keep PW *pw, enum isl_dim_type type,
1146 unsigned first, unsigned n)
1148 int i;
1149 enum isl_dim_type set_type;
1151 if (!pw)
1152 return isl_bool_error;
1153 if (pw->n == 0 || n == 0)
1154 return isl_bool_false;
1156 set_type = type == isl_dim_in ? isl_dim_set : type;
1158 for (i = 0; i < pw->n; ++i) {
1159 isl_bool involves = FN(EL,involves_dims)(pw->p[i].FIELD,
1160 type, first, n);
1161 if (involves < 0 || involves)
1162 return involves;
1163 involves = isl_set_involves_dims(pw->p[i].set,
1164 set_type, first, n);
1165 if (involves < 0 || involves)
1166 return involves;
1168 return isl_bool_false;
1171 __isl_give PW *FN(PW,set_dim_name)(__isl_take PW *pw,
1172 enum isl_dim_type type, unsigned pos, const char *s)
1174 int i;
1175 enum isl_dim_type set_type;
1177 pw = FN(PW,cow)(pw);
1178 if (!pw)
1179 return NULL;
1181 set_type = type == isl_dim_in ? isl_dim_set : type;
1183 pw->dim = isl_space_set_dim_name(pw->dim, type, pos, s);
1184 if (!pw->dim)
1185 goto error;
1187 for (i = 0; i < pw->n; ++i) {
1188 pw->p[i].set = isl_set_set_dim_name(pw->p[i].set,
1189 set_type, pos, s);
1190 if (!pw->p[i].set)
1191 goto error;
1192 pw->p[i].FIELD = FN(EL,set_dim_name)(pw->p[i].FIELD, type, pos, s);
1193 if (!pw->p[i].FIELD)
1194 goto error;
1197 return pw;
1198 error:
1199 FN(PW,free)(pw);
1200 return NULL;
1203 __isl_give PW *FN(PW,drop_dims)(__isl_take PW *pw,
1204 enum isl_dim_type type, unsigned first, unsigned n)
1206 int i;
1207 enum isl_dim_type set_type;
1209 if (!pw)
1210 return NULL;
1211 if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
1212 return pw;
1214 set_type = type == isl_dim_in ? isl_dim_set : type;
1216 pw = FN(PW,cow)(pw);
1217 if (!pw)
1218 return NULL;
1219 pw->dim = isl_space_drop_dims(pw->dim, type, first, n);
1220 if (!pw->dim)
1221 goto error;
1222 for (i = 0; i < pw->n; ++i) {
1223 pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n);
1224 if (!pw->p[i].FIELD)
1225 goto error;
1226 if (type == isl_dim_out)
1227 continue;
1228 pw->p[i].set = isl_set_drop(pw->p[i].set, set_type, first, n);
1229 if (!pw->p[i].set)
1230 goto error;
1233 return pw;
1234 error:
1235 FN(PW,free)(pw);
1236 return NULL;
1239 /* This function is very similar to drop_dims.
1240 * The only difference is that the cells may still involve
1241 * the specified dimensions. They are removed using
1242 * isl_set_project_out instead of isl_set_drop.
1244 __isl_give PW *FN(PW,project_out)(__isl_take PW *pw,
1245 enum isl_dim_type type, unsigned first, unsigned n)
1247 int i;
1248 enum isl_dim_type set_type;
1250 if (!pw)
1251 return NULL;
1252 if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
1253 return pw;
1255 set_type = type == isl_dim_in ? isl_dim_set : type;
1257 pw = FN(PW,cow)(pw);
1258 if (!pw)
1259 return NULL;
1260 pw->dim = isl_space_drop_dims(pw->dim, type, first, n);
1261 if (!pw->dim)
1262 goto error;
1263 for (i = 0; i < pw->n; ++i) {
1264 pw->p[i].set = isl_set_project_out(pw->p[i].set,
1265 set_type, first, n);
1266 if (!pw->p[i].set)
1267 goto error;
1268 pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n);
1269 if (!pw->p[i].FIELD)
1270 goto error;
1273 return pw;
1274 error:
1275 FN(PW,free)(pw);
1276 return NULL;
1279 /* Project the domain of pw onto its parameter space.
1281 __isl_give PW *FN(PW,project_domain_on_params)(__isl_take PW *pw)
1283 isl_space *space;
1284 unsigned n;
1286 n = FN(PW,dim)(pw, isl_dim_in);
1287 pw = FN(PW,project_out)(pw, isl_dim_in, 0, n);
1288 space = FN(PW,get_domain_space)(pw);
1289 space = isl_space_params(space);
1290 pw = FN(PW,reset_domain_space)(pw, space);
1291 return pw;
1294 /* Drop all parameters not referenced by "pw".
1296 __isl_give PW *FN(PW,drop_unused_params)(__isl_take PW *pw)
1298 int i;
1300 if (FN(PW,check_named_params)(pw) < 0)
1301 return FN(PW,free)(pw);
1303 for (i = FN(PW,dim)(pw, isl_dim_param) - 1; i >= 0; i--) {
1304 isl_bool involves;
1306 involves = FN(PW,involves_dims)(pw, isl_dim_param, i, 1);
1307 if (involves < 0)
1308 return FN(PW,free)(pw);
1309 if (!involves)
1310 pw = FN(PW,drop_dims)(pw, isl_dim_param, i, 1);
1313 return pw;
1316 #ifndef NO_INSERT_DIMS
1317 __isl_give PW *FN(PW,insert_dims)(__isl_take PW *pw, enum isl_dim_type type,
1318 unsigned first, unsigned n)
1320 int i;
1321 enum isl_dim_type set_type;
1323 if (!pw)
1324 return NULL;
1325 if (n == 0 && !isl_space_is_named_or_nested(pw->dim, type))
1326 return pw;
1328 set_type = type == isl_dim_in ? isl_dim_set : type;
1330 pw = FN(PW,cow)(pw);
1331 if (!pw)
1332 return NULL;
1334 pw->dim = isl_space_insert_dims(pw->dim, type, first, n);
1335 if (!pw->dim)
1336 goto error;
1338 for (i = 0; i < pw->n; ++i) {
1339 pw->p[i].set = isl_set_insert_dims(pw->p[i].set,
1340 set_type, first, n);
1341 if (!pw->p[i].set)
1342 goto error;
1343 pw->p[i].FIELD = FN(EL,insert_dims)(pw->p[i].FIELD,
1344 type, first, n);
1345 if (!pw->p[i].FIELD)
1346 goto error;
1349 return pw;
1350 error:
1351 FN(PW,free)(pw);
1352 return NULL;
1354 #endif
1356 __isl_give PW *FN(PW,fix_dim)(__isl_take PW *pw,
1357 enum isl_dim_type type, unsigned pos, isl_int v)
1359 int i;
1361 if (!pw)
1362 return NULL;
1364 if (type == isl_dim_in)
1365 type = isl_dim_set;
1367 pw = FN(PW,cow)(pw);
1368 if (!pw)
1369 return NULL;
1370 for (i = 0; i < pw->n; ++i) {
1371 pw->p[i].set = isl_set_fix(pw->p[i].set, type, pos, v);
1372 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
1373 return FN(PW,free)(pw);
1376 return pw;
1379 /* Fix the value of the variable at position "pos" of type "type" of "pw"
1380 * to be equal to "v".
1382 __isl_give PW *FN(PW,fix_val)(__isl_take PW *pw,
1383 enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
1385 if (!v)
1386 return FN(PW,free)(pw);
1387 if (!isl_val_is_int(v))
1388 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
1389 "expecting integer value", goto error);
1391 pw = FN(PW,fix_dim)(pw, type, pos, v->n);
1392 isl_val_free(v);
1394 return pw;
1395 error:
1396 isl_val_free(v);
1397 return FN(PW,free)(pw);
1400 unsigned FN(PW,dim)(__isl_keep PW *pw, enum isl_dim_type type)
1402 return pw ? isl_space_dim(pw->dim, type) : 0;
1405 __isl_give PW *FN(PW,split_dims)(__isl_take PW *pw,
1406 enum isl_dim_type type, unsigned first, unsigned n)
1408 int i;
1410 if (!pw)
1411 return NULL;
1412 if (n == 0)
1413 return pw;
1415 if (type == isl_dim_in)
1416 type = isl_dim_set;
1418 pw = FN(PW,cow)(pw);
1419 if (!pw)
1420 return NULL;
1421 if (!pw->dim)
1422 goto error;
1423 for (i = 0; i < pw->n; ++i) {
1424 pw->p[i].set = isl_set_split_dims(pw->p[i].set, type, first, n);
1425 if (!pw->p[i].set)
1426 goto error;
1429 return pw;
1430 error:
1431 FN(PW,free)(pw);
1432 return NULL;
1435 #ifndef NO_OPT
1436 /* Compute the maximal value attained by the piecewise quasipolynomial
1437 * on its domain or zero if the domain is empty.
1438 * In the worst case, the domain is scanned completely,
1439 * so the domain is assumed to be bounded.
1441 __isl_give isl_val *FN(PW,opt)(__isl_take PW *pw, int max)
1443 int i;
1444 isl_val *opt;
1446 if (!pw)
1447 return NULL;
1449 if (pw->n == 0) {
1450 opt = isl_val_zero(FN(PW,get_ctx)(pw));
1451 FN(PW,free)(pw);
1452 return opt;
1455 opt = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[0].FIELD),
1456 isl_set_copy(pw->p[0].set), max);
1457 for (i = 1; i < pw->n; ++i) {
1458 isl_val *opt_i;
1459 opt_i = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[i].FIELD),
1460 isl_set_copy(pw->p[i].set), max);
1461 if (max)
1462 opt = isl_val_max(opt, opt_i);
1463 else
1464 opt = isl_val_min(opt, opt_i);
1467 FN(PW,free)(pw);
1468 return opt;
1471 __isl_give isl_val *FN(PW,max)(__isl_take PW *pw)
1473 return FN(PW,opt)(pw, 1);
1476 __isl_give isl_val *FN(PW,min)(__isl_take PW *pw)
1478 return FN(PW,opt)(pw, 0);
1480 #endif
1482 /* Return the space of "pw".
1484 __isl_keep isl_space *FN(PW,peek_space)(__isl_keep PW *pw)
1486 return pw ? pw->dim : NULL;
1489 __isl_give isl_space *FN(PW,get_space)(__isl_keep PW *pw)
1491 return isl_space_copy(FN(PW,peek_space)(pw));
1494 __isl_give isl_space *FN(PW,get_domain_space)(__isl_keep PW *pw)
1496 return pw ? isl_space_domain(isl_space_copy(pw->dim)) : NULL;
1499 /* Return the position of the dimension of the given type and name
1500 * in "pw".
1501 * Return -1 if no such dimension can be found.
1503 int FN(PW,find_dim_by_name)(__isl_keep PW *pw,
1504 enum isl_dim_type type, const char *name)
1506 if (!pw)
1507 return -1;
1508 return isl_space_find_dim_by_name(pw->dim, type, name);
1511 #ifndef NO_RESET_DIM
1512 /* Reset the space of "pw". Since we don't know if the elements
1513 * represent the spaces themselves or their domains, we pass along
1514 * both when we call their reset_space_and_domain.
1516 static __isl_give PW *FN(PW,reset_space_and_domain)(__isl_take PW *pw,
1517 __isl_take isl_space *space, __isl_take isl_space *domain)
1519 int i;
1521 pw = FN(PW,cow)(pw);
1522 if (!pw || !space || !domain)
1523 goto error;
1525 for (i = 0; i < pw->n; ++i) {
1526 pw->p[i].set = isl_set_reset_space(pw->p[i].set,
1527 isl_space_copy(domain));
1528 if (!pw->p[i].set)
1529 goto error;
1530 pw->p[i].FIELD = FN(EL,reset_space_and_domain)(pw->p[i].FIELD,
1531 isl_space_copy(space), isl_space_copy(domain));
1532 if (!pw->p[i].FIELD)
1533 goto error;
1536 isl_space_free(domain);
1538 isl_space_free(pw->dim);
1539 pw->dim = space;
1541 return pw;
1542 error:
1543 isl_space_free(domain);
1544 isl_space_free(space);
1545 FN(PW,free)(pw);
1546 return NULL;
1549 __isl_give PW *FN(PW,reset_domain_space)(__isl_take PW *pw,
1550 __isl_take isl_space *domain)
1552 isl_space *space;
1554 space = isl_space_extend_domain_with_range(isl_space_copy(domain),
1555 FN(PW,get_space)(pw));
1556 return FN(PW,reset_space_and_domain)(pw, space, domain);
1559 __isl_give PW *FN(PW,reset_space)(__isl_take PW *pw, __isl_take isl_space *dim)
1561 isl_space *domain;
1563 domain = isl_space_domain(isl_space_copy(dim));
1564 return FN(PW,reset_space_and_domain)(pw, dim, domain);
1567 __isl_give PW *FN(PW,set_tuple_id)(__isl_take PW *pw, enum isl_dim_type type,
1568 __isl_take isl_id *id)
1570 isl_space *space;
1572 pw = FN(PW,cow)(pw);
1573 if (!pw)
1574 goto error;
1576 space = FN(PW,get_space)(pw);
1577 space = isl_space_set_tuple_id(space, type, id);
1579 return FN(PW,reset_space)(pw, space);
1580 error:
1581 isl_id_free(id);
1582 return FN(PW,free)(pw);
1585 /* Drop the id on the specified tuple.
1587 __isl_give PW *FN(PW,reset_tuple_id)(__isl_take PW *pw, enum isl_dim_type type)
1589 isl_space *space;
1591 if (!pw)
1592 return NULL;
1593 if (!FN(PW,has_tuple_id)(pw, type))
1594 return pw;
1596 pw = FN(PW,cow)(pw);
1597 if (!pw)
1598 return NULL;
1600 space = FN(PW,get_space)(pw);
1601 space = isl_space_reset_tuple_id(space, type);
1603 return FN(PW,reset_space)(pw, space);
1606 __isl_give PW *FN(PW,set_dim_id)(__isl_take PW *pw,
1607 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
1609 pw = FN(PW,cow)(pw);
1610 if (!pw)
1611 goto error;
1612 pw->dim = isl_space_set_dim_id(pw->dim, type, pos, id);
1613 return FN(PW,reset_space)(pw, isl_space_copy(pw->dim));
1614 error:
1615 isl_id_free(id);
1616 return FN(PW,free)(pw);
1618 #endif
1620 /* Reset the user pointer on all identifiers of parameters and tuples
1621 * of the space of "pw".
1623 __isl_give PW *FN(PW,reset_user)(__isl_take PW *pw)
1625 isl_space *space;
1627 space = FN(PW,get_space)(pw);
1628 space = isl_space_reset_user(space);
1630 return FN(PW,reset_space)(pw, space);
1633 isl_bool FN(PW,has_equal_space)(__isl_keep PW *pw1, __isl_keep PW *pw2)
1635 if (!pw1 || !pw2)
1636 return isl_bool_error;
1638 return isl_space_is_equal(pw1->dim, pw2->dim);
1641 #ifndef NO_MORPH
1642 __isl_give PW *FN(PW,morph_domain)(__isl_take PW *pw,
1643 __isl_take isl_morph *morph)
1645 int i;
1646 isl_ctx *ctx;
1648 if (!pw || !morph)
1649 goto error;
1651 ctx = isl_space_get_ctx(pw->dim);
1652 isl_assert(ctx, isl_space_is_domain_internal(morph->dom->dim, pw->dim),
1653 goto error);
1655 pw = FN(PW,cow)(pw);
1656 if (!pw)
1657 goto error;
1658 pw->dim = isl_space_extend_domain_with_range(
1659 isl_space_copy(morph->ran->dim), pw->dim);
1660 if (!pw->dim)
1661 goto error;
1663 for (i = 0; i < pw->n; ++i) {
1664 pw->p[i].set = isl_morph_set(isl_morph_copy(morph), pw->p[i].set);
1665 if (!pw->p[i].set)
1666 goto error;
1667 pw->p[i].FIELD = FN(EL,morph_domain)(pw->p[i].FIELD,
1668 isl_morph_copy(morph));
1669 if (!pw->p[i].FIELD)
1670 goto error;
1673 isl_morph_free(morph);
1675 return pw;
1676 error:
1677 FN(PW,free)(pw);
1678 isl_morph_free(morph);
1679 return NULL;
1681 #endif
1683 int FN(PW,n_piece)(__isl_keep PW *pw)
1685 return pw ? pw->n : 0;
1688 isl_stat FN(PW,foreach_piece)(__isl_keep PW *pw,
1689 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el, void *user),
1690 void *user)
1692 int i;
1694 if (!pw)
1695 return isl_stat_error;
1697 for (i = 0; i < pw->n; ++i)
1698 if (fn(isl_set_copy(pw->p[i].set),
1699 FN(EL,copy)(pw->p[i].FIELD), user) < 0)
1700 return isl_stat_error;
1702 return isl_stat_ok;
1705 #ifndef NO_LIFT
1706 static isl_bool any_divs(__isl_keep isl_set *set)
1708 int i;
1710 if (!set)
1711 return isl_bool_error;
1713 for (i = 0; i < set->n; ++i)
1714 if (set->p[i]->n_div > 0)
1715 return isl_bool_true;
1717 return isl_bool_false;
1720 static isl_stat foreach_lifted_subset(__isl_take isl_set *set,
1721 __isl_take EL *el,
1722 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el,
1723 void *user), void *user)
1725 int i;
1727 if (!set || !el)
1728 goto error;
1730 for (i = 0; i < set->n; ++i) {
1731 isl_set *lift;
1732 EL *copy;
1734 lift = isl_set_from_basic_set(isl_basic_set_copy(set->p[i]));
1735 lift = isl_set_lift(lift);
1737 copy = FN(EL,copy)(el);
1738 copy = FN(EL,lift)(copy, isl_set_get_space(lift));
1740 if (fn(lift, copy, user) < 0)
1741 goto error;
1744 isl_set_free(set);
1745 FN(EL,free)(el);
1747 return isl_stat_ok;
1748 error:
1749 isl_set_free(set);
1750 FN(EL,free)(el);
1751 return isl_stat_error;
1754 isl_stat FN(PW,foreach_lifted_piece)(__isl_keep PW *pw,
1755 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el,
1756 void *user), void *user)
1758 int i;
1760 if (!pw)
1761 return isl_stat_error;
1763 for (i = 0; i < pw->n; ++i) {
1764 isl_bool any;
1765 isl_set *set;
1766 EL *el;
1768 any = any_divs(pw->p[i].set);
1769 if (any < 0)
1770 return isl_stat_error;
1771 set = isl_set_copy(pw->p[i].set);
1772 el = FN(EL,copy)(pw->p[i].FIELD);
1773 if (!any) {
1774 if (fn(set, el, user) < 0)
1775 return isl_stat_error;
1776 continue;
1778 if (foreach_lifted_subset(set, el, fn, user) < 0)
1779 return isl_stat_error;
1782 return isl_stat_ok;
1784 #endif
1786 #ifndef NO_MOVE_DIMS
1787 __isl_give PW *FN(PW,move_dims)(__isl_take PW *pw,
1788 enum isl_dim_type dst_type, unsigned dst_pos,
1789 enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1791 int i;
1793 pw = FN(PW,cow)(pw);
1794 if (!pw)
1795 return NULL;
1797 pw->dim = isl_space_move_dims(pw->dim, dst_type, dst_pos, src_type, src_pos, n);
1798 if (!pw->dim)
1799 goto error;
1801 for (i = 0; i < pw->n; ++i) {
1802 pw->p[i].FIELD = FN(EL,move_dims)(pw->p[i].FIELD,
1803 dst_type, dst_pos, src_type, src_pos, n);
1804 if (!pw->p[i].FIELD)
1805 goto error;
1808 if (dst_type == isl_dim_in)
1809 dst_type = isl_dim_set;
1810 if (src_type == isl_dim_in)
1811 src_type = isl_dim_set;
1813 for (i = 0; i < pw->n; ++i) {
1814 pw->p[i].set = isl_set_move_dims(pw->p[i].set,
1815 dst_type, dst_pos,
1816 src_type, src_pos, n);
1817 if (!pw->p[i].set)
1818 goto error;
1821 return pw;
1822 error:
1823 FN(PW,free)(pw);
1824 return NULL;
1826 #endif
1828 __isl_give PW *FN(PW,mul_isl_int)(__isl_take PW *pw, isl_int v)
1830 int i;
1832 if (isl_int_is_one(v))
1833 return pw;
1834 if (pw && DEFAULT_IS_ZERO && isl_int_is_zero(v)) {
1835 PW *zero;
1836 isl_space *dim = FN(PW,get_space)(pw);
1837 #ifdef HAS_TYPE
1838 zero = FN(PW,ZERO)(dim, pw->type);
1839 #else
1840 zero = FN(PW,ZERO)(dim);
1841 #endif
1842 FN(PW,free)(pw);
1843 return zero;
1845 pw = FN(PW,cow)(pw);
1846 if (!pw)
1847 return NULL;
1848 if (pw->n == 0)
1849 return pw;
1851 #ifdef HAS_TYPE
1852 if (isl_int_is_neg(v))
1853 pw->type = isl_fold_type_negate(pw->type);
1854 #endif
1855 for (i = 0; i < pw->n; ++i) {
1856 pw->p[i].FIELD = FN(EL,scale)(pw->p[i].FIELD, v);
1857 if (!pw->p[i].FIELD)
1858 goto error;
1861 return pw;
1862 error:
1863 FN(PW,free)(pw);
1864 return NULL;
1867 /* Multiply the pieces of "pw" by "v" and return the result.
1869 __isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v)
1871 int i;
1873 if (!pw || !v)
1874 goto error;
1876 if (isl_val_is_one(v)) {
1877 isl_val_free(v);
1878 return pw;
1880 if (pw && DEFAULT_IS_ZERO && isl_val_is_zero(v)) {
1881 PW *zero;
1882 isl_space *space = FN(PW,get_space)(pw);
1883 #ifdef HAS_TYPE
1884 zero = FN(PW,ZERO)(space, pw->type);
1885 #else
1886 zero = FN(PW,ZERO)(space);
1887 #endif
1888 FN(PW,free)(pw);
1889 isl_val_free(v);
1890 return zero;
1892 if (pw->n == 0) {
1893 isl_val_free(v);
1894 return pw;
1896 pw = FN(PW,cow)(pw);
1897 if (!pw)
1898 goto error;
1900 #ifdef HAS_TYPE
1901 if (isl_val_is_neg(v))
1902 pw->type = isl_fold_type_negate(pw->type);
1903 #endif
1904 for (i = 0; i < pw->n; ++i) {
1905 pw->p[i].FIELD = FN(EL,scale_val)(pw->p[i].FIELD,
1906 isl_val_copy(v));
1907 if (!pw->p[i].FIELD)
1908 goto error;
1911 isl_val_free(v);
1912 return pw;
1913 error:
1914 isl_val_free(v);
1915 FN(PW,free)(pw);
1916 return NULL;
1919 /* Divide the pieces of "pw" by "v" and return the result.
1921 __isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v)
1923 int i;
1925 if (!pw || !v)
1926 goto error;
1928 if (isl_val_is_one(v)) {
1929 isl_val_free(v);
1930 return pw;
1933 if (!isl_val_is_rat(v))
1934 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1935 "expecting rational factor", goto error);
1936 if (isl_val_is_zero(v))
1937 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1938 "cannot scale down by zero", goto error);
1940 if (pw->n == 0) {
1941 isl_val_free(v);
1942 return pw;
1944 pw = FN(PW,cow)(pw);
1945 if (!pw)
1946 goto error;
1948 #ifdef HAS_TYPE
1949 if (isl_val_is_neg(v))
1950 pw->type = isl_fold_type_negate(pw->type);
1951 #endif
1952 for (i = 0; i < pw->n; ++i) {
1953 pw->p[i].FIELD = FN(EL,scale_down_val)(pw->p[i].FIELD,
1954 isl_val_copy(v));
1955 if (!pw->p[i].FIELD)
1956 goto error;
1959 isl_val_free(v);
1960 return pw;
1961 error:
1962 isl_val_free(v);
1963 FN(PW,free)(pw);
1964 return NULL;
1967 __isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v)
1969 return FN(PW,mul_isl_int)(pw, v);
1972 /* Apply some normalization to "pw".
1973 * In particular, sort the pieces according to their function value
1974 * expressions, combining pairs of adjacent pieces with
1975 * the same such expression, and then normalize the domains of the pieces.
1977 * We normalize in place, but if anything goes wrong we need
1978 * to return NULL, so we need to make sure we don't change the
1979 * meaning of any possible other copies of "pw".
1981 __isl_give PW *FN(PW,normalize)(__isl_take PW *pw)
1983 int i;
1984 isl_set *set;
1986 pw = FN(PW,sort)(pw);
1987 if (!pw)
1988 return NULL;
1989 for (i = 0; i < pw->n; ++i) {
1990 set = isl_set_normalize(isl_set_copy(pw->p[i].set));
1991 if (!set)
1992 return FN(PW,free)(pw);
1993 isl_set_free(pw->p[i].set);
1994 pw->p[i].set = set;
1997 return pw;
2000 /* Is pw1 obviously equal to pw2?
2001 * That is, do they have obviously identical cells and obviously identical
2002 * elements on each cell?
2004 * If "pw1" or "pw2" contain any NaNs, then they are considered
2005 * not to be the same. A NaN is not equal to anything, not even
2006 * to another NaN.
2008 isl_bool FN(PW,plain_is_equal)(__isl_keep PW *pw1, __isl_keep PW *pw2)
2010 int i;
2011 isl_bool equal, has_nan;
2013 if (!pw1 || !pw2)
2014 return isl_bool_error;
2016 has_nan = FN(PW,involves_nan)(pw1);
2017 if (has_nan >= 0 && !has_nan)
2018 has_nan = FN(PW,involves_nan)(pw2);
2019 if (has_nan < 0 || has_nan)
2020 return isl_bool_not(has_nan);
2022 if (pw1 == pw2)
2023 return isl_bool_true;
2024 if (!isl_space_is_equal(pw1->dim, pw2->dim))
2025 return isl_bool_false;
2027 pw1 = FN(PW,copy)(pw1);
2028 pw2 = FN(PW,copy)(pw2);
2029 pw1 = FN(PW,normalize)(pw1);
2030 pw2 = FN(PW,normalize)(pw2);
2031 if (!pw1 || !pw2)
2032 goto error;
2034 equal = pw1->n == pw2->n;
2035 for (i = 0; equal && i < pw1->n; ++i) {
2036 equal = isl_set_plain_is_equal(pw1->p[i].set, pw2->p[i].set);
2037 if (equal < 0)
2038 goto error;
2039 if (!equal)
2040 break;
2041 equal = FN(EL,plain_is_equal)(pw1->p[i].FIELD, pw2->p[i].FIELD);
2042 if (equal < 0)
2043 goto error;
2046 FN(PW,free)(pw1);
2047 FN(PW,free)(pw2);
2048 return equal;
2049 error:
2050 FN(PW,free)(pw1);
2051 FN(PW,free)(pw2);
2052 return isl_bool_error;
2055 /* Does "pw" involve any NaNs?
2057 isl_bool FN(PW,involves_nan)(__isl_keep PW *pw)
2059 int i;
2061 if (!pw)
2062 return isl_bool_error;
2063 if (pw->n == 0)
2064 return isl_bool_false;
2066 for (i = 0; i < pw->n; ++i) {
2067 isl_bool has_nan = FN(EL,involves_nan)(pw->p[i].FIELD);
2068 if (has_nan < 0 || has_nan)
2069 return has_nan;
2072 return isl_bool_false;
2075 #ifndef NO_PULLBACK
2076 static __isl_give PW *FN(PW,align_params_pw_multi_aff_and)(__isl_take PW *pw,
2077 __isl_take isl_multi_aff *ma,
2078 __isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_multi_aff *ma))
2080 isl_ctx *ctx;
2081 isl_bool equal_params;
2082 isl_space *ma_space;
2084 ma_space = isl_multi_aff_get_space(ma);
2085 if (!pw || !ma || !ma_space)
2086 goto error;
2087 equal_params = isl_space_has_equal_params(pw->dim, ma_space);
2088 if (equal_params < 0)
2089 goto error;
2090 if (equal_params) {
2091 isl_space_free(ma_space);
2092 return fn(pw, ma);
2094 ctx = FN(PW,get_ctx)(pw);
2095 if (FN(PW,check_named_params)(pw) < 0)
2096 goto error;
2097 if (!isl_space_has_named_params(ma_space))
2098 isl_die(ctx, isl_error_invalid,
2099 "unaligned unnamed parameters", goto error);
2100 pw = FN(PW,align_params)(pw, ma_space);
2101 ma = isl_multi_aff_align_params(ma, FN(PW,get_space)(pw));
2102 return fn(pw, ma);
2103 error:
2104 isl_space_free(ma_space);
2105 FN(PW,free)(pw);
2106 isl_multi_aff_free(ma);
2107 return NULL;
2110 static __isl_give PW *FN(PW,align_params_pw_pw_multi_aff_and)(__isl_take PW *pw,
2111 __isl_take isl_pw_multi_aff *pma,
2112 __isl_give PW *(*fn)(__isl_take PW *pw,
2113 __isl_take isl_pw_multi_aff *ma))
2115 isl_bool equal_params;
2116 isl_space *pma_space;
2118 pma_space = isl_pw_multi_aff_get_space(pma);
2119 if (!pw || !pma || !pma_space)
2120 goto error;
2121 equal_params = isl_space_has_equal_params(pw->dim, pma_space);
2122 if (equal_params < 0)
2123 goto error;
2124 if (equal_params) {
2125 isl_space_free(pma_space);
2126 return fn(pw, pma);
2128 if (FN(PW,check_named_params)(pw) < 0 ||
2129 isl_pw_multi_aff_check_named_params(pma) < 0)
2130 goto error;
2131 pw = FN(PW,align_params)(pw, pma_space);
2132 pma = isl_pw_multi_aff_align_params(pma, FN(PW,get_space)(pw));
2133 return fn(pw, pma);
2134 error:
2135 isl_space_free(pma_space);
2136 FN(PW,free)(pw);
2137 isl_pw_multi_aff_free(pma);
2138 return NULL;
2141 /* Compute the pullback of "pw" by the function represented by "ma".
2142 * In other words, plug in "ma" in "pw".
2144 static __isl_give PW *FN(PW,pullback_multi_aff_aligned)(__isl_take PW *pw,
2145 __isl_take isl_multi_aff *ma)
2147 int i;
2148 isl_space *space = NULL;
2150 ma = isl_multi_aff_align_divs(ma);
2151 pw = FN(PW,cow)(pw);
2152 if (!pw || !ma)
2153 goto error;
2155 space = isl_space_join(isl_multi_aff_get_space(ma),
2156 FN(PW,get_space)(pw));
2158 for (i = 0; i < pw->n; ++i) {
2159 pw->p[i].set = isl_set_preimage_multi_aff(pw->p[i].set,
2160 isl_multi_aff_copy(ma));
2161 if (!pw->p[i].set)
2162 goto error;
2163 pw->p[i].FIELD = FN(EL,pullback_multi_aff)(pw->p[i].FIELD,
2164 isl_multi_aff_copy(ma));
2165 if (!pw->p[i].FIELD)
2166 goto error;
2169 pw = FN(PW,reset_space)(pw, space);
2170 isl_multi_aff_free(ma);
2171 return pw;
2172 error:
2173 isl_space_free(space);
2174 isl_multi_aff_free(ma);
2175 FN(PW,free)(pw);
2176 return NULL;
2179 __isl_give PW *FN(PW,pullback_multi_aff)(__isl_take PW *pw,
2180 __isl_take isl_multi_aff *ma)
2182 return FN(PW,align_params_pw_multi_aff_and)(pw, ma,
2183 &FN(PW,pullback_multi_aff_aligned));
2186 /* Compute the pullback of "pw" by the function represented by "pma".
2187 * In other words, plug in "pma" in "pw".
2189 static __isl_give PW *FN(PW,pullback_pw_multi_aff_aligned)(__isl_take PW *pw,
2190 __isl_take isl_pw_multi_aff *pma)
2192 int i;
2193 PW *res;
2195 if (!pma)
2196 goto error;
2198 if (pma->n == 0) {
2199 isl_space *space;
2200 space = isl_space_join(isl_pw_multi_aff_get_space(pma),
2201 FN(PW,get_space)(pw));
2202 isl_pw_multi_aff_free(pma);
2203 res = FN(PW,empty)(space);
2204 FN(PW,free)(pw);
2205 return res;
2208 res = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
2209 isl_multi_aff_copy(pma->p[0].maff));
2210 res = FN(PW,intersect_domain)(res, isl_set_copy(pma->p[0].set));
2212 for (i = 1; i < pma->n; ++i) {
2213 PW *res_i;
2215 res_i = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
2216 isl_multi_aff_copy(pma->p[i].maff));
2217 res_i = FN(PW,intersect_domain)(res_i,
2218 isl_set_copy(pma->p[i].set));
2219 res = FN(PW,add_disjoint)(res, res_i);
2222 isl_pw_multi_aff_free(pma);
2223 FN(PW,free)(pw);
2224 return res;
2225 error:
2226 isl_pw_multi_aff_free(pma);
2227 FN(PW,free)(pw);
2228 return NULL;
2231 __isl_give PW *FN(PW,pullback_pw_multi_aff)(__isl_take PW *pw,
2232 __isl_take isl_pw_multi_aff *pma)
2234 return FN(PW,align_params_pw_pw_multi_aff_and)(pw, pma,
2235 &FN(PW,pullback_pw_multi_aff_aligned));
2237 #endif