extract out shared isl_reordering_get_space
[isl.git] / isl_pw_templ.c
blob1d023c81a5d17475cacbc1c68fda09afa7dd48ac
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 model = isl_space_drop_dims(model, isl_dim_in,
334 0, isl_space_dim(model, isl_dim_in));
335 model = isl_space_drop_dims(model, isl_dim_out,
336 0, isl_space_dim(model, isl_dim_out));
337 exp = isl_parameter_alignment_reordering(pw->dim, model);
338 exp = isl_reordering_extend_space(exp,
339 FN(PW,get_domain_space)(pw));
340 pw = FN(PW,realign_domain)(pw, exp);
343 isl_space_free(model);
344 return pw;
345 error:
346 isl_space_free(model);
347 FN(PW,free)(pw);
348 return NULL;
351 static __isl_give PW *FN(PW,align_params_pw_pw_and)(__isl_take PW *pw1,
352 __isl_take PW *pw2,
353 __isl_give PW *(*fn)(__isl_take PW *pw1, __isl_take PW *pw2))
355 isl_ctx *ctx;
356 isl_bool equal_params;
358 if (!pw1 || !pw2)
359 goto error;
360 equal_params = isl_space_has_equal_params(pw1->dim, pw2->dim);
361 if (equal_params < 0)
362 goto error;
363 if (equal_params)
364 return fn(pw1, pw2);
365 ctx = FN(PW,get_ctx)(pw1);
366 if (FN(PW,check_named_params)(pw1) < 0 ||
367 FN(PW,check_named_params)(pw2) < 0)
368 goto error;
369 pw1 = FN(PW,align_params)(pw1, FN(PW,get_space)(pw2));
370 pw2 = FN(PW,align_params)(pw2, FN(PW,get_space)(pw1));
371 return fn(pw1, pw2);
372 error:
373 FN(PW,free)(pw1);
374 FN(PW,free)(pw2);
375 return NULL;
378 static __isl_give PW *FN(PW,align_params_pw_set_and)(__isl_take PW *pw,
379 __isl_take isl_set *set,
380 __isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_set *set))
382 isl_ctx *ctx;
383 isl_bool aligned;
385 if (!pw || !set)
386 goto error;
387 aligned = isl_set_space_has_equal_params(set, pw->dim);
388 if (aligned < 0)
389 goto error;
390 if (aligned)
391 return fn(pw, set);
392 ctx = FN(PW,get_ctx)(pw);
393 if (FN(PW,check_named_params)(pw) < 0)
394 goto error;
395 if (!isl_space_has_named_params(set->dim))
396 isl_die(ctx, isl_error_invalid,
397 "unaligned unnamed parameters", goto error);
398 pw = FN(PW,align_params)(pw, isl_set_get_space(set));
399 set = isl_set_align_params(set, FN(PW,get_space)(pw));
400 return fn(pw, set);
401 error:
402 FN(PW,free)(pw);
403 isl_set_free(set);
404 return NULL;
406 #endif
408 static __isl_give PW *FN(PW,union_add_aligned)(__isl_take PW *pw1,
409 __isl_take PW *pw2)
411 int i, j, n;
412 struct PW *res;
413 isl_ctx *ctx;
414 isl_set *set;
416 if (!pw1 || !pw2)
417 goto error;
419 ctx = isl_space_get_ctx(pw1->dim);
420 #ifdef HAS_TYPE
421 if (pw1->type != pw2->type)
422 isl_die(ctx, isl_error_invalid,
423 "fold types don't match", goto error);
424 #endif
425 isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
427 if (FN(PW,IS_ZERO)(pw1)) {
428 FN(PW,free)(pw1);
429 return pw2;
432 if (FN(PW,IS_ZERO)(pw2)) {
433 FN(PW,free)(pw2);
434 return pw1;
437 n = (pw1->n + 1) * (pw2->n + 1);
438 #ifdef HAS_TYPE
439 res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), pw1->type, n);
440 #else
441 res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), n);
442 #endif
444 for (i = 0; i < pw1->n; ++i) {
445 set = isl_set_copy(pw1->p[i].set);
446 for (j = 0; j < pw2->n; ++j) {
447 struct isl_set *common;
448 EL *sum;
449 common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
450 isl_set_copy(pw2->p[j].set));
451 if (isl_set_plain_is_empty(common)) {
452 isl_set_free(common);
453 continue;
455 set = isl_set_subtract(set,
456 isl_set_copy(pw2->p[j].set));
458 sum = FN(EL,add_on_domain)(common,
459 FN(EL,copy)(pw1->p[i].FIELD),
460 FN(EL,copy)(pw2->p[j].FIELD));
462 res = FN(PW,add_piece)(res, common, sum);
464 res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw1->p[i].FIELD));
467 for (j = 0; j < pw2->n; ++j) {
468 set = isl_set_copy(pw2->p[j].set);
469 for (i = 0; i < pw1->n; ++i)
470 set = isl_set_subtract(set,
471 isl_set_copy(pw1->p[i].set));
472 res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw2->p[j].FIELD));
475 FN(PW,free)(pw1);
476 FN(PW,free)(pw2);
478 return res;
479 error:
480 FN(PW,free)(pw1);
481 FN(PW,free)(pw2);
482 return NULL;
485 /* Private version of "union_add". For isl_pw_qpolynomial and
486 * isl_pw_qpolynomial_fold, we prefer to simply call it "add".
488 static __isl_give PW *FN(PW,union_add_)(__isl_take PW *pw1, __isl_take PW *pw2)
490 return FN(PW,align_params_pw_pw_and)(pw1, pw2,
491 &FN(PW,union_add_aligned));
494 /* Make sure "pw" has room for at least "n" more pieces.
496 * If there is only one reference to pw, we extend it in place.
497 * Otherwise, we create a new PW and copy the pieces.
499 static __isl_give PW *FN(PW,grow)(__isl_take PW *pw, int n)
501 int i;
502 isl_ctx *ctx;
503 PW *res;
505 if (!pw)
506 return NULL;
507 if (pw->n + n <= pw->size)
508 return pw;
509 ctx = FN(PW,get_ctx)(pw);
510 n += pw->n;
511 if (pw->ref == 1) {
512 res = isl_realloc(ctx, pw, struct PW,
513 sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
514 if (!res)
515 return FN(PW,free)(pw);
516 res->size = n;
517 return res;
519 #ifdef HAS_TYPE
520 res = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, n);
521 #else
522 res = FN(PW,alloc_size)(isl_space_copy(pw->dim), n);
523 #endif
524 if (!res)
525 return FN(PW,free)(pw);
526 for (i = 0; i < pw->n; ++i)
527 res = FN(PW,add_piece)(res, isl_set_copy(pw->p[i].set),
528 FN(EL,copy)(pw->p[i].FIELD));
529 FN(PW,free)(pw);
530 return res;
533 static __isl_give PW *FN(PW,add_disjoint_aligned)(__isl_take PW *pw1,
534 __isl_take PW *pw2)
536 int i;
537 isl_ctx *ctx;
539 if (!pw1 || !pw2)
540 goto error;
542 if (pw1->size < pw1->n + pw2->n && pw1->n < pw2->n)
543 return FN(PW,add_disjoint_aligned)(pw2, pw1);
545 ctx = isl_space_get_ctx(pw1->dim);
546 #ifdef HAS_TYPE
547 if (pw1->type != pw2->type)
548 isl_die(ctx, isl_error_invalid,
549 "fold types don't match", goto error);
550 #endif
551 isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
553 if (FN(PW,IS_ZERO)(pw1)) {
554 FN(PW,free)(pw1);
555 return pw2;
558 if (FN(PW,IS_ZERO)(pw2)) {
559 FN(PW,free)(pw2);
560 return pw1;
563 pw1 = FN(PW,grow)(pw1, pw2->n);
564 if (!pw1)
565 goto error;
567 for (i = 0; i < pw2->n; ++i)
568 pw1 = FN(PW,add_piece)(pw1,
569 isl_set_copy(pw2->p[i].set),
570 FN(EL,copy)(pw2->p[i].FIELD));
572 FN(PW,free)(pw2);
574 return pw1;
575 error:
576 FN(PW,free)(pw1);
577 FN(PW,free)(pw2);
578 return NULL;
581 __isl_give PW *FN(PW,add_disjoint)(__isl_take PW *pw1, __isl_take PW *pw2)
583 return FN(PW,align_params_pw_pw_and)(pw1, pw2,
584 &FN(PW,add_disjoint_aligned));
587 /* This function is currently only used from isl_aff.c
589 static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
590 __isl_take PW *pw2, __isl_take isl_space *space,
591 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
592 __attribute__ ((unused));
594 /* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
595 * The result of "fn" (and therefore also of this function) lives in "space".
597 static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
598 __isl_take PW *pw2, __isl_take isl_space *space,
599 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
601 int i, j, n;
602 PW *res = NULL;
604 if (!pw1 || !pw2)
605 goto error;
607 n = pw1->n * pw2->n;
608 #ifdef HAS_TYPE
609 res = FN(PW,alloc_size)(isl_space_copy(space), pw1->type, n);
610 #else
611 res = FN(PW,alloc_size)(isl_space_copy(space), n);
612 #endif
614 for (i = 0; i < pw1->n; ++i) {
615 for (j = 0; j < pw2->n; ++j) {
616 isl_set *common;
617 EL *res_ij;
618 int empty;
620 common = isl_set_intersect(
621 isl_set_copy(pw1->p[i].set),
622 isl_set_copy(pw2->p[j].set));
623 empty = isl_set_plain_is_empty(common);
624 if (empty < 0 || empty) {
625 isl_set_free(common);
626 if (empty < 0)
627 goto error;
628 continue;
631 res_ij = fn(FN(EL,copy)(pw1->p[i].FIELD),
632 FN(EL,copy)(pw2->p[j].FIELD));
633 res_ij = FN(EL,gist)(res_ij, isl_set_copy(common));
635 res = FN(PW,add_piece)(res, common, res_ij);
639 isl_space_free(space);
640 FN(PW,free)(pw1);
641 FN(PW,free)(pw2);
642 return res;
643 error:
644 isl_space_free(space);
645 FN(PW,free)(pw1);
646 FN(PW,free)(pw2);
647 FN(PW,free)(res);
648 return NULL;
651 /* This function is currently only used from isl_aff.c
653 static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
654 __isl_take PW *pw2,
655 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
656 __attribute__ ((unused));
658 /* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
659 * The result of "fn" is assumed to live in the same space as "pw1" and "pw2".
661 static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
662 __isl_take PW *pw2,
663 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
665 isl_space *space;
667 if (!pw1 || !pw2)
668 goto error;
670 space = isl_space_copy(pw1->dim);
671 return FN(PW,on_shared_domain_in)(pw1, pw2, space, fn);
672 error:
673 FN(PW,free)(pw1);
674 FN(PW,free)(pw2);
675 return NULL;
678 #ifndef NO_NEG
679 __isl_give PW *FN(PW,neg)(__isl_take PW *pw)
681 int i;
683 if (!pw)
684 return NULL;
686 if (FN(PW,IS_ZERO)(pw))
687 return pw;
689 pw = FN(PW,cow)(pw);
690 if (!pw)
691 return NULL;
693 for (i = 0; i < pw->n; ++i) {
694 pw->p[i].FIELD = FN(EL,neg)(pw->p[i].FIELD);
695 if (!pw->p[i].FIELD)
696 return FN(PW,free)(pw);
699 return pw;
701 #endif
703 #ifndef NO_SUB
704 __isl_give PW *FN(PW,sub)(__isl_take PW *pw1, __isl_take PW *pw2)
706 return FN(PW,add)(pw1, FN(PW,neg)(pw2));
708 #endif
710 /* Return the parameter domain of "pw".
712 __isl_give isl_set *FN(PW,params)(__isl_take PW *pw)
714 return isl_set_params(FN(PW,domain)(pw));
717 __isl_give isl_set *FN(PW,domain)(__isl_take PW *pw)
719 int i;
720 isl_set *dom;
722 if (!pw)
723 return NULL;
725 dom = isl_set_empty(FN(PW,get_domain_space)(pw));
726 for (i = 0; i < pw->n; ++i)
727 dom = isl_set_union_disjoint(dom, isl_set_copy(pw->p[i].set));
729 FN(PW,free)(pw);
731 return dom;
734 /* Exploit the equalities in the domain of piece "i" of "pw"
735 * to simplify the associated function.
736 * If the domain of piece "i" is empty, then remove it entirely,
737 * replacing it with the final piece.
739 static int FN(PW,exploit_equalities_and_remove_if_empty)(__isl_keep PW *pw,
740 int i)
742 isl_basic_set *aff;
743 int empty = isl_set_plain_is_empty(pw->p[i].set);
745 if (empty < 0)
746 return -1;
747 if (empty) {
748 isl_set_free(pw->p[i].set);
749 FN(EL,free)(pw->p[i].FIELD);
750 if (i != pw->n - 1)
751 pw->p[i] = pw->p[pw->n - 1];
752 pw->n--;
754 return 0;
757 aff = isl_set_affine_hull(isl_set_copy(pw->p[i].set));
758 pw->p[i].FIELD = FN(EL,substitute_equalities)(pw->p[i].FIELD, aff);
759 if (!pw->p[i].FIELD)
760 return -1;
762 return 0;
765 /* Convert a piecewise expression defined over a parameter domain
766 * into one that is defined over a zero-dimensional set.
768 __isl_give PW *FN(PW,from_range)(__isl_take PW *pw)
770 isl_space *space;
772 if (!pw)
773 return NULL;
774 if (!isl_space_is_set(pw->dim))
775 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
776 "not living in a set space", return FN(PW,free)(pw));
778 space = FN(PW,get_space)(pw);
779 space = isl_space_from_range(space);
780 pw = FN(PW,reset_space)(pw, space);
782 return pw;
785 /* Fix the value of the given parameter or domain dimension of "pw"
786 * to be equal to "value".
788 __isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type,
789 unsigned pos, int value)
791 int i;
793 if (!pw)
794 return NULL;
796 if (type == isl_dim_out)
797 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
798 "cannot fix output dimension", return FN(PW,free)(pw));
800 if (pw->n == 0)
801 return pw;
803 if (type == isl_dim_in)
804 type = isl_dim_set;
806 pw = FN(PW,cow)(pw);
807 if (!pw)
808 return FN(PW,free)(pw);
810 for (i = pw->n - 1; i >= 0; --i) {
811 pw->p[i].set = isl_set_fix_si(pw->p[i].set, type, pos, value);
812 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
813 return FN(PW,free)(pw);
816 return pw;
819 /* Restrict the domain of "pw" by combining each cell
820 * with "set" through a call to "fn", where "fn" may be
821 * isl_set_intersect, isl_set_intersect_params or isl_set_subtract.
823 static __isl_give PW *FN(PW,restrict_domain_aligned)(__isl_take PW *pw,
824 __isl_take isl_set *set,
825 __isl_give isl_set *(*fn)(__isl_take isl_set *set1,
826 __isl_take isl_set *set2))
828 int i;
830 if (!pw || !set)
831 goto error;
833 if (pw->n == 0) {
834 isl_set_free(set);
835 return pw;
838 pw = FN(PW,cow)(pw);
839 if (!pw)
840 goto error;
842 for (i = pw->n - 1; i >= 0; --i) {
843 pw->p[i].set = fn(pw->p[i].set, isl_set_copy(set));
844 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
845 goto error;
848 isl_set_free(set);
849 return pw;
850 error:
851 isl_set_free(set);
852 FN(PW,free)(pw);
853 return NULL;
856 static __isl_give PW *FN(PW,intersect_domain_aligned)(__isl_take PW *pw,
857 __isl_take isl_set *set)
859 return FN(PW,restrict_domain_aligned)(pw, set, &isl_set_intersect);
862 __isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw,
863 __isl_take isl_set *context)
865 return FN(PW,align_params_pw_set_and)(pw, context,
866 &FN(PW,intersect_domain_aligned));
869 static __isl_give PW *FN(PW,intersect_params_aligned)(__isl_take PW *pw,
870 __isl_take isl_set *set)
872 return FN(PW,restrict_domain_aligned)(pw, set,
873 &isl_set_intersect_params);
876 /* Intersect the domain of "pw" with the parameter domain "context".
878 __isl_give PW *FN(PW,intersect_params)(__isl_take PW *pw,
879 __isl_take isl_set *context)
881 return FN(PW,align_params_pw_set_and)(pw, context,
882 &FN(PW,intersect_params_aligned));
885 /* Subtract "domain' from the domain of "pw", assuming their
886 * parameters have been aligned.
888 static __isl_give PW *FN(PW,subtract_domain_aligned)(__isl_take PW *pw,
889 __isl_take isl_set *domain)
891 return FN(PW,restrict_domain_aligned)(pw, domain, &isl_set_subtract);
894 /* Subtract "domain' from the domain of "pw".
896 __isl_give PW *FN(PW,subtract_domain)(__isl_take PW *pw,
897 __isl_take isl_set *domain)
899 return FN(PW,align_params_pw_set_and)(pw, domain,
900 &FN(PW,subtract_domain_aligned));
903 /* Compute the gist of "pw" with respect to the domain constraints
904 * of "context" for the case where the domain of the last element
905 * of "pw" is equal to "context".
906 * Call "fn_el" to compute the gist of this element, replace
907 * its domain by the universe and drop all other elements
908 * as their domains are necessarily disjoint from "context".
910 static __isl_give PW *FN(PW,gist_last)(__isl_take PW *pw,
911 __isl_take isl_set *context,
912 __isl_give EL *(*fn_el)(__isl_take EL *el, __isl_take isl_set *set))
914 int i;
915 isl_space *space;
917 for (i = 0; i < pw->n - 1; ++i) {
918 isl_set_free(pw->p[i].set);
919 FN(EL,free)(pw->p[i].FIELD);
921 pw->p[0].FIELD = pw->p[pw->n - 1].FIELD;
922 pw->p[0].set = pw->p[pw->n - 1].set;
923 pw->n = 1;
925 space = isl_set_get_space(context);
926 pw->p[0].FIELD = fn_el(pw->p[0].FIELD, context);
927 context = isl_set_universe(space);
928 isl_set_free(pw->p[0].set);
929 pw->p[0].set = context;
931 if (!pw->p[0].FIELD || !pw->p[0].set)
932 return FN(PW,free)(pw);
934 return pw;
937 /* Compute the gist of "pw" with respect to the domain constraints
938 * of "context". Call "fn_el" to compute the gist of the elements
939 * and "fn_dom" to compute the gist of the domains.
941 * If the piecewise expression is empty or the context is the universe,
942 * then nothing can be simplified.
944 static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw,
945 __isl_take isl_set *context,
946 __isl_give EL *(*fn_el)(__isl_take EL *el,
947 __isl_take isl_set *set),
948 __isl_give isl_set *(*fn_dom)(__isl_take isl_set *set,
949 __isl_take isl_basic_set *bset))
951 int i;
952 int is_universe;
953 isl_bool aligned;
954 isl_basic_set *hull = NULL;
956 if (!pw || !context)
957 goto error;
959 if (pw->n == 0) {
960 isl_set_free(context);
961 return pw;
964 is_universe = isl_set_plain_is_universe(context);
965 if (is_universe < 0)
966 goto error;
967 if (is_universe) {
968 isl_set_free(context);
969 return pw;
972 aligned = isl_set_space_has_equal_params(context, pw->dim);
973 if (aligned < 0)
974 goto error;
975 if (!aligned) {
976 pw = FN(PW,align_params)(pw, isl_set_get_space(context));
977 context = isl_set_align_params(context, FN(PW,get_space)(pw));
980 pw = FN(PW,cow)(pw);
981 if (!pw)
982 goto error;
984 if (pw->n == 1) {
985 int equal;
987 equal = isl_set_plain_is_equal(pw->p[0].set, context);
988 if (equal < 0)
989 goto error;
990 if (equal)
991 return FN(PW,gist_last)(pw, context, fn_el);
994 context = isl_set_compute_divs(context);
995 hull = isl_set_simple_hull(isl_set_copy(context));
997 for (i = pw->n - 1; i >= 0; --i) {
998 isl_set *set_i;
999 int empty;
1001 if (i == pw->n - 1) {
1002 int equal;
1003 equal = isl_set_plain_is_equal(pw->p[i].set, context);
1004 if (equal < 0)
1005 goto error;
1006 if (equal) {
1007 isl_basic_set_free(hull);
1008 return FN(PW,gist_last)(pw, context, fn_el);
1011 set_i = isl_set_intersect(isl_set_copy(pw->p[i].set),
1012 isl_set_copy(context));
1013 empty = isl_set_plain_is_empty(set_i);
1014 pw->p[i].FIELD = fn_el(pw->p[i].FIELD, set_i);
1015 pw->p[i].set = fn_dom(pw->p[i].set, isl_basic_set_copy(hull));
1016 if (empty < 0 || !pw->p[i].FIELD || !pw->p[i].set)
1017 goto error;
1018 if (empty) {
1019 isl_set_free(pw->p[i].set);
1020 FN(EL,free)(pw->p[i].FIELD);
1021 if (i != pw->n - 1)
1022 pw->p[i] = pw->p[pw->n - 1];
1023 pw->n--;
1027 isl_basic_set_free(hull);
1028 isl_set_free(context);
1030 return pw;
1031 error:
1032 FN(PW,free)(pw);
1033 isl_basic_set_free(hull);
1034 isl_set_free(context);
1035 return NULL;
1038 static __isl_give PW *FN(PW,gist_domain_aligned)(__isl_take PW *pw,
1039 __isl_take isl_set *set)
1041 return FN(PW,gist_aligned)(pw, set, &FN(EL,gist),
1042 &isl_set_gist_basic_set);
1045 __isl_give PW *FN(PW,gist)(__isl_take PW *pw, __isl_take isl_set *context)
1047 return FN(PW,align_params_pw_set_and)(pw, context,
1048 &FN(PW,gist_domain_aligned));
1051 static __isl_give PW *FN(PW,gist_params_aligned)(__isl_take PW *pw,
1052 __isl_take isl_set *set)
1054 return FN(PW,gist_aligned)(pw, set, &FN(EL,gist_params),
1055 &isl_set_gist_params_basic_set);
1058 __isl_give PW *FN(PW,gist_params)(__isl_take PW *pw,
1059 __isl_take isl_set *context)
1061 return FN(PW,align_params_pw_set_and)(pw, context,
1062 &FN(PW,gist_params_aligned));
1065 /* Return -1 if the piece "p1" should be sorted before "p2"
1066 * and 1 if it should be sorted after "p2".
1067 * Return 0 if they do not need to be sorted in a specific order.
1069 * The two pieces are compared on the basis of their function value expressions.
1071 static int FN(PW,sort_field_cmp)(const void *p1, const void *p2, void *arg)
1073 struct FN(PW,piece) const *pc1 = p1;
1074 struct FN(PW,piece) const *pc2 = p2;
1076 return FN(EL,plain_cmp)(pc1->FIELD, pc2->FIELD);
1079 /* Sort the pieces of "pw" according to their function value
1080 * expressions and then combine pairs of adjacent pieces with
1081 * the same such expression.
1083 * The sorting is performed in place because it does not
1084 * change the meaning of "pw", but care needs to be
1085 * taken not to change any possible other copies of "pw"
1086 * in case anything goes wrong.
1088 __isl_give PW *FN(PW,sort)(__isl_take PW *pw)
1090 int i, j;
1091 isl_set *set;
1093 if (!pw)
1094 return NULL;
1095 if (pw->n <= 1)
1096 return pw;
1097 if (isl_sort(pw->p, pw->n, sizeof(pw->p[0]),
1098 &FN(PW,sort_field_cmp), NULL) < 0)
1099 return FN(PW,free)(pw);
1100 for (i = pw->n - 1; i >= 1; --i) {
1101 if (!FN(EL,plain_is_equal)(pw->p[i - 1].FIELD, pw->p[i].FIELD))
1102 continue;
1103 set = isl_set_union(isl_set_copy(pw->p[i - 1].set),
1104 isl_set_copy(pw->p[i].set));
1105 if (!set)
1106 return FN(PW,free)(pw);
1107 isl_set_free(pw->p[i].set);
1108 FN(EL,free)(pw->p[i].FIELD);
1109 isl_set_free(pw->p[i - 1].set);
1110 pw->p[i - 1].set = set;
1111 for (j = i + 1; j < pw->n; ++j)
1112 pw->p[j - 1] = pw->p[j];
1113 pw->n--;
1116 return pw;
1119 /* Coalesce the domains of "pw".
1121 * Prior to the actual coalescing, first sort the pieces such that
1122 * pieces with the same function value expression are combined
1123 * into a single piece, the combined domain of which can then
1124 * be coalesced.
1126 __isl_give PW *FN(PW,coalesce)(__isl_take PW *pw)
1128 int i;
1130 pw = FN(PW,sort)(pw);
1131 if (!pw)
1132 return NULL;
1134 for (i = 0; i < pw->n; ++i) {
1135 pw->p[i].set = isl_set_coalesce(pw->p[i].set);
1136 if (!pw->p[i].set)
1137 goto error;
1140 return pw;
1141 error:
1142 FN(PW,free)(pw);
1143 return NULL;
1146 isl_ctx *FN(PW,get_ctx)(__isl_keep PW *pw)
1148 return pw ? isl_space_get_ctx(pw->dim) : NULL;
1151 isl_bool FN(PW,involves_dims)(__isl_keep PW *pw, enum isl_dim_type type,
1152 unsigned first, unsigned n)
1154 int i;
1155 enum isl_dim_type set_type;
1157 if (!pw)
1158 return isl_bool_error;
1159 if (pw->n == 0 || n == 0)
1160 return isl_bool_false;
1162 set_type = type == isl_dim_in ? isl_dim_set : type;
1164 for (i = 0; i < pw->n; ++i) {
1165 isl_bool involves = FN(EL,involves_dims)(pw->p[i].FIELD,
1166 type, first, n);
1167 if (involves < 0 || involves)
1168 return involves;
1169 involves = isl_set_involves_dims(pw->p[i].set,
1170 set_type, first, n);
1171 if (involves < 0 || involves)
1172 return involves;
1174 return isl_bool_false;
1177 __isl_give PW *FN(PW,set_dim_name)(__isl_take PW *pw,
1178 enum isl_dim_type type, unsigned pos, const char *s)
1180 int i;
1181 enum isl_dim_type set_type;
1183 pw = FN(PW,cow)(pw);
1184 if (!pw)
1185 return NULL;
1187 set_type = type == isl_dim_in ? isl_dim_set : type;
1189 pw->dim = isl_space_set_dim_name(pw->dim, type, pos, s);
1190 if (!pw->dim)
1191 goto error;
1193 for (i = 0; i < pw->n; ++i) {
1194 pw->p[i].set = isl_set_set_dim_name(pw->p[i].set,
1195 set_type, pos, s);
1196 if (!pw->p[i].set)
1197 goto error;
1198 pw->p[i].FIELD = FN(EL,set_dim_name)(pw->p[i].FIELD, type, pos, s);
1199 if (!pw->p[i].FIELD)
1200 goto error;
1203 return pw;
1204 error:
1205 FN(PW,free)(pw);
1206 return NULL;
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;
1300 /* Drop all parameters not referenced by "pw".
1302 __isl_give PW *FN(PW,drop_unused_params)(__isl_take PW *pw)
1304 int i;
1306 if (FN(PW,check_named_params)(pw) < 0)
1307 return FN(PW,free)(pw);
1309 for (i = FN(PW,dim)(pw, isl_dim_param) - 1; i >= 0; i--) {
1310 isl_bool involves;
1312 involves = FN(PW,involves_dims)(pw, isl_dim_param, i, 1);
1313 if (involves < 0)
1314 return FN(PW,free)(pw);
1315 if (!involves)
1316 pw = FN(PW,drop_dims)(pw, isl_dim_param, i, 1);
1319 return pw;
1322 #ifndef NO_INSERT_DIMS
1323 __isl_give PW *FN(PW,insert_dims)(__isl_take PW *pw, enum isl_dim_type type,
1324 unsigned first, unsigned n)
1326 int i;
1327 enum isl_dim_type set_type;
1329 if (!pw)
1330 return NULL;
1331 if (n == 0 && !isl_space_is_named_or_nested(pw->dim, type))
1332 return pw;
1334 set_type = type == isl_dim_in ? isl_dim_set : type;
1336 pw = FN(PW,cow)(pw);
1337 if (!pw)
1338 return NULL;
1340 pw->dim = isl_space_insert_dims(pw->dim, type, first, n);
1341 if (!pw->dim)
1342 goto error;
1344 for (i = 0; i < pw->n; ++i) {
1345 pw->p[i].set = isl_set_insert_dims(pw->p[i].set,
1346 set_type, first, n);
1347 if (!pw->p[i].set)
1348 goto error;
1349 pw->p[i].FIELD = FN(EL,insert_dims)(pw->p[i].FIELD,
1350 type, first, n);
1351 if (!pw->p[i].FIELD)
1352 goto error;
1355 return pw;
1356 error:
1357 FN(PW,free)(pw);
1358 return NULL;
1360 #endif
1362 __isl_give PW *FN(PW,fix_dim)(__isl_take PW *pw,
1363 enum isl_dim_type type, unsigned pos, isl_int v)
1365 int i;
1367 if (!pw)
1368 return NULL;
1370 if (type == isl_dim_in)
1371 type = isl_dim_set;
1373 pw = FN(PW,cow)(pw);
1374 if (!pw)
1375 return NULL;
1376 for (i = 0; i < pw->n; ++i) {
1377 pw->p[i].set = isl_set_fix(pw->p[i].set, type, pos, v);
1378 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
1379 return FN(PW,free)(pw);
1382 return pw;
1385 /* Fix the value of the variable at position "pos" of type "type" of "pw"
1386 * to be equal to "v".
1388 __isl_give PW *FN(PW,fix_val)(__isl_take PW *pw,
1389 enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
1391 if (!v)
1392 return FN(PW,free)(pw);
1393 if (!isl_val_is_int(v))
1394 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
1395 "expecting integer value", goto error);
1397 pw = FN(PW,fix_dim)(pw, type, pos, v->n);
1398 isl_val_free(v);
1400 return pw;
1401 error:
1402 isl_val_free(v);
1403 return FN(PW,free)(pw);
1406 unsigned FN(PW,dim)(__isl_keep PW *pw, enum isl_dim_type type)
1408 return pw ? isl_space_dim(pw->dim, type) : 0;
1411 __isl_give PW *FN(PW,split_dims)(__isl_take PW *pw,
1412 enum isl_dim_type type, unsigned first, unsigned n)
1414 int i;
1416 if (!pw)
1417 return NULL;
1418 if (n == 0)
1419 return pw;
1421 if (type == isl_dim_in)
1422 type = isl_dim_set;
1424 pw = FN(PW,cow)(pw);
1425 if (!pw)
1426 return NULL;
1427 if (!pw->dim)
1428 goto error;
1429 for (i = 0; i < pw->n; ++i) {
1430 pw->p[i].set = isl_set_split_dims(pw->p[i].set, type, first, n);
1431 if (!pw->p[i].set)
1432 goto error;
1435 return pw;
1436 error:
1437 FN(PW,free)(pw);
1438 return NULL;
1441 #ifndef NO_OPT
1442 /* Compute the maximal value attained by the piecewise quasipolynomial
1443 * on its domain or zero if the domain is empty.
1444 * In the worst case, the domain is scanned completely,
1445 * so the domain is assumed to be bounded.
1447 __isl_give isl_val *FN(PW,opt)(__isl_take PW *pw, int max)
1449 int i;
1450 isl_val *opt;
1452 if (!pw)
1453 return NULL;
1455 if (pw->n == 0) {
1456 opt = isl_val_zero(FN(PW,get_ctx)(pw));
1457 FN(PW,free)(pw);
1458 return opt;
1461 opt = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[0].FIELD),
1462 isl_set_copy(pw->p[0].set), max);
1463 for (i = 1; i < pw->n; ++i) {
1464 isl_val *opt_i;
1465 opt_i = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[i].FIELD),
1466 isl_set_copy(pw->p[i].set), max);
1467 if (max)
1468 opt = isl_val_max(opt, opt_i);
1469 else
1470 opt = isl_val_min(opt, opt_i);
1473 FN(PW,free)(pw);
1474 return opt;
1477 __isl_give isl_val *FN(PW,max)(__isl_take PW *pw)
1479 return FN(PW,opt)(pw, 1);
1482 __isl_give isl_val *FN(PW,min)(__isl_take PW *pw)
1484 return FN(PW,opt)(pw, 0);
1486 #endif
1488 /* Return the space of "pw".
1490 __isl_keep isl_space *FN(PW,peek_space)(__isl_keep PW *pw)
1492 return pw ? pw->dim : NULL;
1495 __isl_give isl_space *FN(PW,get_space)(__isl_keep PW *pw)
1497 return isl_space_copy(FN(PW,peek_space)(pw));
1500 __isl_give isl_space *FN(PW,get_domain_space)(__isl_keep PW *pw)
1502 return pw ? isl_space_domain(isl_space_copy(pw->dim)) : NULL;
1505 /* Return the position of the dimension of the given type and name
1506 * in "pw".
1507 * Return -1 if no such dimension can be found.
1509 int FN(PW,find_dim_by_name)(__isl_keep PW *pw,
1510 enum isl_dim_type type, const char *name)
1512 if (!pw)
1513 return -1;
1514 return isl_space_find_dim_by_name(pw->dim, type, name);
1517 #ifndef NO_RESET_DIM
1518 /* Reset the space of "pw". Since we don't know if the elements
1519 * represent the spaces themselves or their domains, we pass along
1520 * both when we call their reset_space_and_domain.
1522 static __isl_give PW *FN(PW,reset_space_and_domain)(__isl_take PW *pw,
1523 __isl_take isl_space *space, __isl_take isl_space *domain)
1525 int i;
1527 pw = FN(PW,cow)(pw);
1528 if (!pw || !space || !domain)
1529 goto error;
1531 for (i = 0; i < pw->n; ++i) {
1532 pw->p[i].set = isl_set_reset_space(pw->p[i].set,
1533 isl_space_copy(domain));
1534 if (!pw->p[i].set)
1535 goto error;
1536 pw->p[i].FIELD = FN(EL,reset_space_and_domain)(pw->p[i].FIELD,
1537 isl_space_copy(space), isl_space_copy(domain));
1538 if (!pw->p[i].FIELD)
1539 goto error;
1542 isl_space_free(domain);
1544 isl_space_free(pw->dim);
1545 pw->dim = space;
1547 return pw;
1548 error:
1549 isl_space_free(domain);
1550 isl_space_free(space);
1551 FN(PW,free)(pw);
1552 return NULL;
1555 __isl_give PW *FN(PW,reset_domain_space)(__isl_take PW *pw,
1556 __isl_take isl_space *domain)
1558 isl_space *space;
1560 space = isl_space_extend_domain_with_range(isl_space_copy(domain),
1561 FN(PW,get_space)(pw));
1562 return FN(PW,reset_space_and_domain)(pw, space, domain);
1565 __isl_give PW *FN(PW,reset_space)(__isl_take PW *pw, __isl_take isl_space *dim)
1567 isl_space *domain;
1569 domain = isl_space_domain(isl_space_copy(dim));
1570 return FN(PW,reset_space_and_domain)(pw, dim, domain);
1573 __isl_give PW *FN(PW,set_tuple_id)(__isl_take PW *pw, enum isl_dim_type type,
1574 __isl_take isl_id *id)
1576 isl_space *space;
1578 pw = FN(PW,cow)(pw);
1579 if (!pw)
1580 goto error;
1582 space = FN(PW,get_space)(pw);
1583 space = isl_space_set_tuple_id(space, type, id);
1585 return FN(PW,reset_space)(pw, space);
1586 error:
1587 isl_id_free(id);
1588 return FN(PW,free)(pw);
1591 /* Drop the id on the specified tuple.
1593 __isl_give PW *FN(PW,reset_tuple_id)(__isl_take PW *pw, enum isl_dim_type type)
1595 isl_space *space;
1597 if (!pw)
1598 return NULL;
1599 if (!FN(PW,has_tuple_id)(pw, type))
1600 return pw;
1602 pw = FN(PW,cow)(pw);
1603 if (!pw)
1604 return NULL;
1606 space = FN(PW,get_space)(pw);
1607 space = isl_space_reset_tuple_id(space, type);
1609 return FN(PW,reset_space)(pw, space);
1612 __isl_give PW *FN(PW,set_dim_id)(__isl_take PW *pw,
1613 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
1615 pw = FN(PW,cow)(pw);
1616 if (!pw)
1617 goto error;
1618 pw->dim = isl_space_set_dim_id(pw->dim, type, pos, id);
1619 return FN(PW,reset_space)(pw, isl_space_copy(pw->dim));
1620 error:
1621 isl_id_free(id);
1622 return FN(PW,free)(pw);
1624 #endif
1626 /* Reset the user pointer on all identifiers of parameters and tuples
1627 * of the space of "pw".
1629 __isl_give PW *FN(PW,reset_user)(__isl_take PW *pw)
1631 isl_space *space;
1633 space = FN(PW,get_space)(pw);
1634 space = isl_space_reset_user(space);
1636 return FN(PW,reset_space)(pw, space);
1639 isl_bool FN(PW,has_equal_space)(__isl_keep PW *pw1, __isl_keep PW *pw2)
1641 if (!pw1 || !pw2)
1642 return isl_bool_error;
1644 return isl_space_is_equal(pw1->dim, pw2->dim);
1647 #ifndef NO_MORPH
1648 __isl_give PW *FN(PW,morph_domain)(__isl_take PW *pw,
1649 __isl_take isl_morph *morph)
1651 int i;
1652 isl_ctx *ctx;
1654 if (!pw || !morph)
1655 goto error;
1657 ctx = isl_space_get_ctx(pw->dim);
1658 isl_assert(ctx, isl_space_is_domain_internal(morph->dom->dim, pw->dim),
1659 goto error);
1661 pw = FN(PW,cow)(pw);
1662 if (!pw)
1663 goto error;
1664 pw->dim = isl_space_extend_domain_with_range(
1665 isl_space_copy(morph->ran->dim), pw->dim);
1666 if (!pw->dim)
1667 goto error;
1669 for (i = 0; i < pw->n; ++i) {
1670 pw->p[i].set = isl_morph_set(isl_morph_copy(morph), pw->p[i].set);
1671 if (!pw->p[i].set)
1672 goto error;
1673 pw->p[i].FIELD = FN(EL,morph_domain)(pw->p[i].FIELD,
1674 isl_morph_copy(morph));
1675 if (!pw->p[i].FIELD)
1676 goto error;
1679 isl_morph_free(morph);
1681 return pw;
1682 error:
1683 FN(PW,free)(pw);
1684 isl_morph_free(morph);
1685 return NULL;
1687 #endif
1689 int FN(PW,n_piece)(__isl_keep PW *pw)
1691 return pw ? pw->n : 0;
1694 isl_stat FN(PW,foreach_piece)(__isl_keep PW *pw,
1695 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el, void *user),
1696 void *user)
1698 int i;
1700 if (!pw)
1701 return isl_stat_error;
1703 for (i = 0; i < pw->n; ++i)
1704 if (fn(isl_set_copy(pw->p[i].set),
1705 FN(EL,copy)(pw->p[i].FIELD), user) < 0)
1706 return isl_stat_error;
1708 return isl_stat_ok;
1711 #ifndef NO_LIFT
1712 static isl_bool any_divs(__isl_keep isl_set *set)
1714 int i;
1716 if (!set)
1717 return isl_bool_error;
1719 for (i = 0; i < set->n; ++i)
1720 if (set->p[i]->n_div > 0)
1721 return isl_bool_true;
1723 return isl_bool_false;
1726 static isl_stat foreach_lifted_subset(__isl_take isl_set *set,
1727 __isl_take EL *el,
1728 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el,
1729 void *user), void *user)
1731 int i;
1733 if (!set || !el)
1734 goto error;
1736 for (i = 0; i < set->n; ++i) {
1737 isl_set *lift;
1738 EL *copy;
1740 lift = isl_set_from_basic_set(isl_basic_set_copy(set->p[i]));
1741 lift = isl_set_lift(lift);
1743 copy = FN(EL,copy)(el);
1744 copy = FN(EL,lift)(copy, isl_set_get_space(lift));
1746 if (fn(lift, copy, user) < 0)
1747 goto error;
1750 isl_set_free(set);
1751 FN(EL,free)(el);
1753 return isl_stat_ok;
1754 error:
1755 isl_set_free(set);
1756 FN(EL,free)(el);
1757 return isl_stat_error;
1760 isl_stat FN(PW,foreach_lifted_piece)(__isl_keep PW *pw,
1761 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el,
1762 void *user), void *user)
1764 int i;
1766 if (!pw)
1767 return isl_stat_error;
1769 for (i = 0; i < pw->n; ++i) {
1770 isl_bool any;
1771 isl_set *set;
1772 EL *el;
1774 any = any_divs(pw->p[i].set);
1775 if (any < 0)
1776 return isl_stat_error;
1777 set = isl_set_copy(pw->p[i].set);
1778 el = FN(EL,copy)(pw->p[i].FIELD);
1779 if (!any) {
1780 if (fn(set, el, user) < 0)
1781 return isl_stat_error;
1782 continue;
1784 if (foreach_lifted_subset(set, el, fn, user) < 0)
1785 return isl_stat_error;
1788 return isl_stat_ok;
1790 #endif
1792 #ifndef NO_MOVE_DIMS
1793 __isl_give PW *FN(PW,move_dims)(__isl_take PW *pw,
1794 enum isl_dim_type dst_type, unsigned dst_pos,
1795 enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1797 int i;
1799 pw = FN(PW,cow)(pw);
1800 if (!pw)
1801 return NULL;
1803 pw->dim = isl_space_move_dims(pw->dim, dst_type, dst_pos, src_type, src_pos, n);
1804 if (!pw->dim)
1805 goto error;
1807 for (i = 0; i < pw->n; ++i) {
1808 pw->p[i].FIELD = FN(EL,move_dims)(pw->p[i].FIELD,
1809 dst_type, dst_pos, src_type, src_pos, n);
1810 if (!pw->p[i].FIELD)
1811 goto error;
1814 if (dst_type == isl_dim_in)
1815 dst_type = isl_dim_set;
1816 if (src_type == isl_dim_in)
1817 src_type = isl_dim_set;
1819 for (i = 0; i < pw->n; ++i) {
1820 pw->p[i].set = isl_set_move_dims(pw->p[i].set,
1821 dst_type, dst_pos,
1822 src_type, src_pos, n);
1823 if (!pw->p[i].set)
1824 goto error;
1827 return pw;
1828 error:
1829 FN(PW,free)(pw);
1830 return NULL;
1832 #endif
1834 __isl_give PW *FN(PW,mul_isl_int)(__isl_take PW *pw, isl_int v)
1836 int i;
1838 if (isl_int_is_one(v))
1839 return pw;
1840 if (pw && DEFAULT_IS_ZERO && isl_int_is_zero(v)) {
1841 PW *zero;
1842 isl_space *dim = FN(PW,get_space)(pw);
1843 #ifdef HAS_TYPE
1844 zero = FN(PW,ZERO)(dim, pw->type);
1845 #else
1846 zero = FN(PW,ZERO)(dim);
1847 #endif
1848 FN(PW,free)(pw);
1849 return zero;
1851 pw = FN(PW,cow)(pw);
1852 if (!pw)
1853 return NULL;
1854 if (pw->n == 0)
1855 return pw;
1857 #ifdef HAS_TYPE
1858 if (isl_int_is_neg(v))
1859 pw->type = isl_fold_type_negate(pw->type);
1860 #endif
1861 for (i = 0; i < pw->n; ++i) {
1862 pw->p[i].FIELD = FN(EL,scale)(pw->p[i].FIELD, v);
1863 if (!pw->p[i].FIELD)
1864 goto error;
1867 return pw;
1868 error:
1869 FN(PW,free)(pw);
1870 return NULL;
1873 /* Multiply the pieces of "pw" by "v" and return the result.
1875 __isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v)
1877 int i;
1879 if (!pw || !v)
1880 goto error;
1882 if (isl_val_is_one(v)) {
1883 isl_val_free(v);
1884 return pw;
1886 if (pw && DEFAULT_IS_ZERO && isl_val_is_zero(v)) {
1887 PW *zero;
1888 isl_space *space = FN(PW,get_space)(pw);
1889 #ifdef HAS_TYPE
1890 zero = FN(PW,ZERO)(space, pw->type);
1891 #else
1892 zero = FN(PW,ZERO)(space);
1893 #endif
1894 FN(PW,free)(pw);
1895 isl_val_free(v);
1896 return zero;
1898 if (pw->n == 0) {
1899 isl_val_free(v);
1900 return pw;
1902 pw = FN(PW,cow)(pw);
1903 if (!pw)
1904 goto error;
1906 #ifdef HAS_TYPE
1907 if (isl_val_is_neg(v))
1908 pw->type = isl_fold_type_negate(pw->type);
1909 #endif
1910 for (i = 0; i < pw->n; ++i) {
1911 pw->p[i].FIELD = FN(EL,scale_val)(pw->p[i].FIELD,
1912 isl_val_copy(v));
1913 if (!pw->p[i].FIELD)
1914 goto error;
1917 isl_val_free(v);
1918 return pw;
1919 error:
1920 isl_val_free(v);
1921 FN(PW,free)(pw);
1922 return NULL;
1925 /* Divide the pieces of "pw" by "v" and return the result.
1927 __isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v)
1929 int i;
1931 if (!pw || !v)
1932 goto error;
1934 if (isl_val_is_one(v)) {
1935 isl_val_free(v);
1936 return pw;
1939 if (!isl_val_is_rat(v))
1940 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1941 "expecting rational factor", goto error);
1942 if (isl_val_is_zero(v))
1943 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1944 "cannot scale down by zero", goto error);
1946 if (pw->n == 0) {
1947 isl_val_free(v);
1948 return pw;
1950 pw = FN(PW,cow)(pw);
1951 if (!pw)
1952 goto error;
1954 #ifdef HAS_TYPE
1955 if (isl_val_is_neg(v))
1956 pw->type = isl_fold_type_negate(pw->type);
1957 #endif
1958 for (i = 0; i < pw->n; ++i) {
1959 pw->p[i].FIELD = FN(EL,scale_down_val)(pw->p[i].FIELD,
1960 isl_val_copy(v));
1961 if (!pw->p[i].FIELD)
1962 goto error;
1965 isl_val_free(v);
1966 return pw;
1967 error:
1968 isl_val_free(v);
1969 FN(PW,free)(pw);
1970 return NULL;
1973 __isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v)
1975 return FN(PW,mul_isl_int)(pw, v);
1978 /* Apply some normalization to "pw".
1979 * In particular, sort the pieces according to their function value
1980 * expressions, combining pairs of adjacent pieces with
1981 * the same such expression, and then normalize the domains of the pieces.
1983 * We normalize in place, but if anything goes wrong we need
1984 * to return NULL, so we need to make sure we don't change the
1985 * meaning of any possible other copies of "pw".
1987 __isl_give PW *FN(PW,normalize)(__isl_take PW *pw)
1989 int i;
1990 isl_set *set;
1992 pw = FN(PW,sort)(pw);
1993 if (!pw)
1994 return NULL;
1995 for (i = 0; i < pw->n; ++i) {
1996 set = isl_set_normalize(isl_set_copy(pw->p[i].set));
1997 if (!set)
1998 return FN(PW,free)(pw);
1999 isl_set_free(pw->p[i].set);
2000 pw->p[i].set = set;
2003 return pw;
2006 /* Is pw1 obviously equal to pw2?
2007 * That is, do they have obviously identical cells and obviously identical
2008 * elements on each cell?
2010 * If "pw1" or "pw2" contain any NaNs, then they are considered
2011 * not to be the same. A NaN is not equal to anything, not even
2012 * to another NaN.
2014 isl_bool FN(PW,plain_is_equal)(__isl_keep PW *pw1, __isl_keep PW *pw2)
2016 int i;
2017 isl_bool equal, has_nan;
2019 if (!pw1 || !pw2)
2020 return isl_bool_error;
2022 has_nan = FN(PW,involves_nan)(pw1);
2023 if (has_nan >= 0 && !has_nan)
2024 has_nan = FN(PW,involves_nan)(pw2);
2025 if (has_nan < 0 || has_nan)
2026 return isl_bool_not(has_nan);
2028 if (pw1 == pw2)
2029 return isl_bool_true;
2030 if (!isl_space_is_equal(pw1->dim, pw2->dim))
2031 return isl_bool_false;
2033 pw1 = FN(PW,copy)(pw1);
2034 pw2 = FN(PW,copy)(pw2);
2035 pw1 = FN(PW,normalize)(pw1);
2036 pw2 = FN(PW,normalize)(pw2);
2037 if (!pw1 || !pw2)
2038 goto error;
2040 equal = pw1->n == pw2->n;
2041 for (i = 0; equal && i < pw1->n; ++i) {
2042 equal = isl_set_plain_is_equal(pw1->p[i].set, pw2->p[i].set);
2043 if (equal < 0)
2044 goto error;
2045 if (!equal)
2046 break;
2047 equal = FN(EL,plain_is_equal)(pw1->p[i].FIELD, pw2->p[i].FIELD);
2048 if (equal < 0)
2049 goto error;
2052 FN(PW,free)(pw1);
2053 FN(PW,free)(pw2);
2054 return equal;
2055 error:
2056 FN(PW,free)(pw1);
2057 FN(PW,free)(pw2);
2058 return isl_bool_error;
2061 /* Does "pw" involve any NaNs?
2063 isl_bool FN(PW,involves_nan)(__isl_keep PW *pw)
2065 int i;
2067 if (!pw)
2068 return isl_bool_error;
2069 if (pw->n == 0)
2070 return isl_bool_false;
2072 for (i = 0; i < pw->n; ++i) {
2073 isl_bool has_nan = FN(EL,involves_nan)(pw->p[i].FIELD);
2074 if (has_nan < 0 || has_nan)
2075 return has_nan;
2078 return isl_bool_false;
2081 #ifndef NO_PULLBACK
2082 static __isl_give PW *FN(PW,align_params_pw_multi_aff_and)(__isl_take PW *pw,
2083 __isl_take isl_multi_aff *ma,
2084 __isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_multi_aff *ma))
2086 isl_ctx *ctx;
2087 isl_bool equal_params;
2088 isl_space *ma_space;
2090 ma_space = isl_multi_aff_get_space(ma);
2091 if (!pw || !ma || !ma_space)
2092 goto error;
2093 equal_params = isl_space_has_equal_params(pw->dim, ma_space);
2094 if (equal_params < 0)
2095 goto error;
2096 if (equal_params) {
2097 isl_space_free(ma_space);
2098 return fn(pw, ma);
2100 ctx = FN(PW,get_ctx)(pw);
2101 if (FN(PW,check_named_params)(pw) < 0)
2102 goto error;
2103 if (!isl_space_has_named_params(ma_space))
2104 isl_die(ctx, isl_error_invalid,
2105 "unaligned unnamed parameters", goto error);
2106 pw = FN(PW,align_params)(pw, ma_space);
2107 ma = isl_multi_aff_align_params(ma, FN(PW,get_space)(pw));
2108 return fn(pw, ma);
2109 error:
2110 isl_space_free(ma_space);
2111 FN(PW,free)(pw);
2112 isl_multi_aff_free(ma);
2113 return NULL;
2116 static __isl_give PW *FN(PW,align_params_pw_pw_multi_aff_and)(__isl_take PW *pw,
2117 __isl_take isl_pw_multi_aff *pma,
2118 __isl_give PW *(*fn)(__isl_take PW *pw,
2119 __isl_take isl_pw_multi_aff *ma))
2121 isl_ctx *ctx;
2122 isl_bool equal_params;
2123 isl_space *pma_space;
2125 pma_space = isl_pw_multi_aff_get_space(pma);
2126 if (!pw || !pma || !pma_space)
2127 goto error;
2128 equal_params = isl_space_has_equal_params(pw->dim, pma_space);
2129 if (equal_params < 0)
2130 goto error;
2131 if (equal_params) {
2132 isl_space_free(pma_space);
2133 return fn(pw, pma);
2135 ctx = FN(PW,get_ctx)(pw);
2136 if (FN(PW,check_named_params)(pw) < 0 ||
2137 isl_pw_multi_aff_check_named_params(pma) < 0)
2138 goto error;
2139 pw = FN(PW,align_params)(pw, pma_space);
2140 pma = isl_pw_multi_aff_align_params(pma, FN(PW,get_space)(pw));
2141 return fn(pw, pma);
2142 error:
2143 isl_space_free(pma_space);
2144 FN(PW,free)(pw);
2145 isl_pw_multi_aff_free(pma);
2146 return NULL;
2149 /* Compute the pullback of "pw" by the function represented by "ma".
2150 * In other words, plug in "ma" in "pw".
2152 static __isl_give PW *FN(PW,pullback_multi_aff_aligned)(__isl_take PW *pw,
2153 __isl_take isl_multi_aff *ma)
2155 int i;
2156 isl_space *space = NULL;
2158 ma = isl_multi_aff_align_divs(ma);
2159 pw = FN(PW,cow)(pw);
2160 if (!pw || !ma)
2161 goto error;
2163 space = isl_space_join(isl_multi_aff_get_space(ma),
2164 FN(PW,get_space)(pw));
2166 for (i = 0; i < pw->n; ++i) {
2167 pw->p[i].set = isl_set_preimage_multi_aff(pw->p[i].set,
2168 isl_multi_aff_copy(ma));
2169 if (!pw->p[i].set)
2170 goto error;
2171 pw->p[i].FIELD = FN(EL,pullback_multi_aff)(pw->p[i].FIELD,
2172 isl_multi_aff_copy(ma));
2173 if (!pw->p[i].FIELD)
2174 goto error;
2177 pw = FN(PW,reset_space)(pw, space);
2178 isl_multi_aff_free(ma);
2179 return pw;
2180 error:
2181 isl_space_free(space);
2182 isl_multi_aff_free(ma);
2183 FN(PW,free)(pw);
2184 return NULL;
2187 __isl_give PW *FN(PW,pullback_multi_aff)(__isl_take PW *pw,
2188 __isl_take isl_multi_aff *ma)
2190 return FN(PW,align_params_pw_multi_aff_and)(pw, ma,
2191 &FN(PW,pullback_multi_aff_aligned));
2194 /* Compute the pullback of "pw" by the function represented by "pma".
2195 * In other words, plug in "pma" in "pw".
2197 static __isl_give PW *FN(PW,pullback_pw_multi_aff_aligned)(__isl_take PW *pw,
2198 __isl_take isl_pw_multi_aff *pma)
2200 int i;
2201 PW *res;
2203 if (!pma)
2204 goto error;
2206 if (pma->n == 0) {
2207 isl_space *space;
2208 space = isl_space_join(isl_pw_multi_aff_get_space(pma),
2209 FN(PW,get_space)(pw));
2210 isl_pw_multi_aff_free(pma);
2211 res = FN(PW,empty)(space);
2212 FN(PW,free)(pw);
2213 return res;
2216 res = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
2217 isl_multi_aff_copy(pma->p[0].maff));
2218 res = FN(PW,intersect_domain)(res, isl_set_copy(pma->p[0].set));
2220 for (i = 1; i < pma->n; ++i) {
2221 PW *res_i;
2223 res_i = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
2224 isl_multi_aff_copy(pma->p[i].maff));
2225 res_i = FN(PW,intersect_domain)(res_i,
2226 isl_set_copy(pma->p[i].set));
2227 res = FN(PW,add_disjoint)(res, res_i);
2230 isl_pw_multi_aff_free(pma);
2231 FN(PW,free)(pw);
2232 return res;
2233 error:
2234 isl_pw_multi_aff_free(pma);
2235 FN(PW,free)(pw);
2236 return NULL;
2239 __isl_give PW *FN(PW,pullback_pw_multi_aff)(__isl_take PW *pw,
2240 __isl_take isl_pw_multi_aff *pma)
2242 return FN(PW,align_params_pw_pw_multi_aff_and)(pw, pma,
2243 &FN(PW,pullback_pw_multi_aff_aligned));
2245 #endif