isl_basic_map_align_params: extract out isl_basic_map_check_space
[isl.git] / isl_pw_templ.c
blobcce47025f2d2bd8a9b48d0c41a84db89af33938e
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_space_copy(exp->dim));
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 #ifndef NO_INSERT_DIMS
1301 __isl_give PW *FN(PW,insert_dims)(__isl_take PW *pw, enum isl_dim_type type,
1302 unsigned first, unsigned n)
1304 int i;
1305 enum isl_dim_type set_type;
1307 if (!pw)
1308 return NULL;
1309 if (n == 0 && !isl_space_is_named_or_nested(pw->dim, type))
1310 return pw;
1312 set_type = type == isl_dim_in ? isl_dim_set : type;
1314 pw = FN(PW,cow)(pw);
1315 if (!pw)
1316 return NULL;
1318 pw->dim = isl_space_insert_dims(pw->dim, type, first, n);
1319 if (!pw->dim)
1320 goto error;
1322 for (i = 0; i < pw->n; ++i) {
1323 pw->p[i].set = isl_set_insert_dims(pw->p[i].set,
1324 set_type, first, n);
1325 if (!pw->p[i].set)
1326 goto error;
1327 pw->p[i].FIELD = FN(EL,insert_dims)(pw->p[i].FIELD,
1328 type, first, n);
1329 if (!pw->p[i].FIELD)
1330 goto error;
1333 return pw;
1334 error:
1335 FN(PW,free)(pw);
1336 return NULL;
1338 #endif
1340 __isl_give PW *FN(PW,fix_dim)(__isl_take PW *pw,
1341 enum isl_dim_type type, unsigned pos, isl_int v)
1343 int i;
1345 if (!pw)
1346 return NULL;
1348 if (type == isl_dim_in)
1349 type = isl_dim_set;
1351 pw = FN(PW,cow)(pw);
1352 if (!pw)
1353 return NULL;
1354 for (i = 0; i < pw->n; ++i) {
1355 pw->p[i].set = isl_set_fix(pw->p[i].set, type, pos, v);
1356 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
1357 return FN(PW,free)(pw);
1360 return pw;
1363 /* Fix the value of the variable at position "pos" of type "type" of "pw"
1364 * to be equal to "v".
1366 __isl_give PW *FN(PW,fix_val)(__isl_take PW *pw,
1367 enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
1369 if (!v)
1370 return FN(PW,free)(pw);
1371 if (!isl_val_is_int(v))
1372 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
1373 "expecting integer value", goto error);
1375 pw = FN(PW,fix_dim)(pw, type, pos, v->n);
1376 isl_val_free(v);
1378 return pw;
1379 error:
1380 isl_val_free(v);
1381 return FN(PW,free)(pw);
1384 unsigned FN(PW,dim)(__isl_keep PW *pw, enum isl_dim_type type)
1386 return pw ? isl_space_dim(pw->dim, type) : 0;
1389 __isl_give PW *FN(PW,split_dims)(__isl_take PW *pw,
1390 enum isl_dim_type type, unsigned first, unsigned n)
1392 int i;
1394 if (!pw)
1395 return NULL;
1396 if (n == 0)
1397 return pw;
1399 if (type == isl_dim_in)
1400 type = isl_dim_set;
1402 pw = FN(PW,cow)(pw);
1403 if (!pw)
1404 return NULL;
1405 if (!pw->dim)
1406 goto error;
1407 for (i = 0; i < pw->n; ++i) {
1408 pw->p[i].set = isl_set_split_dims(pw->p[i].set, type, first, n);
1409 if (!pw->p[i].set)
1410 goto error;
1413 return pw;
1414 error:
1415 FN(PW,free)(pw);
1416 return NULL;
1419 #ifndef NO_OPT
1420 /* Compute the maximal value attained by the piecewise quasipolynomial
1421 * on its domain or zero if the domain is empty.
1422 * In the worst case, the domain is scanned completely,
1423 * so the domain is assumed to be bounded.
1425 __isl_give isl_val *FN(PW,opt)(__isl_take PW *pw, int max)
1427 int i;
1428 isl_val *opt;
1430 if (!pw)
1431 return NULL;
1433 if (pw->n == 0) {
1434 opt = isl_val_zero(FN(PW,get_ctx)(pw));
1435 FN(PW,free)(pw);
1436 return opt;
1439 opt = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[0].FIELD),
1440 isl_set_copy(pw->p[0].set), max);
1441 for (i = 1; i < pw->n; ++i) {
1442 isl_val *opt_i;
1443 opt_i = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[i].FIELD),
1444 isl_set_copy(pw->p[i].set), max);
1445 if (max)
1446 opt = isl_val_max(opt, opt_i);
1447 else
1448 opt = isl_val_min(opt, opt_i);
1451 FN(PW,free)(pw);
1452 return opt;
1455 __isl_give isl_val *FN(PW,max)(__isl_take PW *pw)
1457 return FN(PW,opt)(pw, 1);
1460 __isl_give isl_val *FN(PW,min)(__isl_take PW *pw)
1462 return FN(PW,opt)(pw, 0);
1464 #endif
1466 /* Return the space of "pw".
1468 __isl_keep isl_space *FN(PW,peek_space)(__isl_keep PW *pw)
1470 return pw ? pw->dim : NULL;
1473 __isl_give isl_space *FN(PW,get_space)(__isl_keep PW *pw)
1475 return isl_space_copy(FN(PW,peek_space)(pw));
1478 __isl_give isl_space *FN(PW,get_domain_space)(__isl_keep PW *pw)
1480 return pw ? isl_space_domain(isl_space_copy(pw->dim)) : NULL;
1483 /* Return the position of the dimension of the given type and name
1484 * in "pw".
1485 * Return -1 if no such dimension can be found.
1487 int FN(PW,find_dim_by_name)(__isl_keep PW *pw,
1488 enum isl_dim_type type, const char *name)
1490 if (!pw)
1491 return -1;
1492 return isl_space_find_dim_by_name(pw->dim, type, name);
1495 #ifndef NO_RESET_DIM
1496 /* Reset the space of "pw". Since we don't know if the elements
1497 * represent the spaces themselves or their domains, we pass along
1498 * both when we call their reset_space_and_domain.
1500 static __isl_give PW *FN(PW,reset_space_and_domain)(__isl_take PW *pw,
1501 __isl_take isl_space *space, __isl_take isl_space *domain)
1503 int i;
1505 pw = FN(PW,cow)(pw);
1506 if (!pw || !space || !domain)
1507 goto error;
1509 for (i = 0; i < pw->n; ++i) {
1510 pw->p[i].set = isl_set_reset_space(pw->p[i].set,
1511 isl_space_copy(domain));
1512 if (!pw->p[i].set)
1513 goto error;
1514 pw->p[i].FIELD = FN(EL,reset_space_and_domain)(pw->p[i].FIELD,
1515 isl_space_copy(space), isl_space_copy(domain));
1516 if (!pw->p[i].FIELD)
1517 goto error;
1520 isl_space_free(domain);
1522 isl_space_free(pw->dim);
1523 pw->dim = space;
1525 return pw;
1526 error:
1527 isl_space_free(domain);
1528 isl_space_free(space);
1529 FN(PW,free)(pw);
1530 return NULL;
1533 __isl_give PW *FN(PW,reset_domain_space)(__isl_take PW *pw,
1534 __isl_take isl_space *domain)
1536 isl_space *space;
1538 space = isl_space_extend_domain_with_range(isl_space_copy(domain),
1539 FN(PW,get_space)(pw));
1540 return FN(PW,reset_space_and_domain)(pw, space, domain);
1543 __isl_give PW *FN(PW,reset_space)(__isl_take PW *pw, __isl_take isl_space *dim)
1545 isl_space *domain;
1547 domain = isl_space_domain(isl_space_copy(dim));
1548 return FN(PW,reset_space_and_domain)(pw, dim, domain);
1551 __isl_give PW *FN(PW,set_tuple_id)(__isl_take PW *pw, enum isl_dim_type type,
1552 __isl_take isl_id *id)
1554 isl_space *space;
1556 pw = FN(PW,cow)(pw);
1557 if (!pw)
1558 goto error;
1560 space = FN(PW,get_space)(pw);
1561 space = isl_space_set_tuple_id(space, type, id);
1563 return FN(PW,reset_space)(pw, space);
1564 error:
1565 isl_id_free(id);
1566 return FN(PW,free)(pw);
1569 /* Drop the id on the specified tuple.
1571 __isl_give PW *FN(PW,reset_tuple_id)(__isl_take PW *pw, enum isl_dim_type type)
1573 isl_space *space;
1575 if (!pw)
1576 return NULL;
1577 if (!FN(PW,has_tuple_id)(pw, type))
1578 return pw;
1580 pw = FN(PW,cow)(pw);
1581 if (!pw)
1582 return NULL;
1584 space = FN(PW,get_space)(pw);
1585 space = isl_space_reset_tuple_id(space, type);
1587 return FN(PW,reset_space)(pw, space);
1590 __isl_give PW *FN(PW,set_dim_id)(__isl_take PW *pw,
1591 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
1593 pw = FN(PW,cow)(pw);
1594 if (!pw)
1595 goto error;
1596 pw->dim = isl_space_set_dim_id(pw->dim, type, pos, id);
1597 return FN(PW,reset_space)(pw, isl_space_copy(pw->dim));
1598 error:
1599 isl_id_free(id);
1600 return FN(PW,free)(pw);
1602 #endif
1604 /* Reset the user pointer on all identifiers of parameters and tuples
1605 * of the space of "pw".
1607 __isl_give PW *FN(PW,reset_user)(__isl_take PW *pw)
1609 isl_space *space;
1611 space = FN(PW,get_space)(pw);
1612 space = isl_space_reset_user(space);
1614 return FN(PW,reset_space)(pw, space);
1617 isl_bool FN(PW,has_equal_space)(__isl_keep PW *pw1, __isl_keep PW *pw2)
1619 if (!pw1 || !pw2)
1620 return isl_bool_error;
1622 return isl_space_is_equal(pw1->dim, pw2->dim);
1625 #ifndef NO_MORPH
1626 __isl_give PW *FN(PW,morph_domain)(__isl_take PW *pw,
1627 __isl_take isl_morph *morph)
1629 int i;
1630 isl_ctx *ctx;
1632 if (!pw || !morph)
1633 goto error;
1635 ctx = isl_space_get_ctx(pw->dim);
1636 isl_assert(ctx, isl_space_is_domain_internal(morph->dom->dim, pw->dim),
1637 goto error);
1639 pw = FN(PW,cow)(pw);
1640 if (!pw)
1641 goto error;
1642 pw->dim = isl_space_extend_domain_with_range(
1643 isl_space_copy(morph->ran->dim), pw->dim);
1644 if (!pw->dim)
1645 goto error;
1647 for (i = 0; i < pw->n; ++i) {
1648 pw->p[i].set = isl_morph_set(isl_morph_copy(morph), pw->p[i].set);
1649 if (!pw->p[i].set)
1650 goto error;
1651 pw->p[i].FIELD = FN(EL,morph_domain)(pw->p[i].FIELD,
1652 isl_morph_copy(morph));
1653 if (!pw->p[i].FIELD)
1654 goto error;
1657 isl_morph_free(morph);
1659 return pw;
1660 error:
1661 FN(PW,free)(pw);
1662 isl_morph_free(morph);
1663 return NULL;
1665 #endif
1667 int FN(PW,n_piece)(__isl_keep PW *pw)
1669 return pw ? pw->n : 0;
1672 isl_stat FN(PW,foreach_piece)(__isl_keep PW *pw,
1673 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el, void *user),
1674 void *user)
1676 int i;
1678 if (!pw)
1679 return isl_stat_error;
1681 for (i = 0; i < pw->n; ++i)
1682 if (fn(isl_set_copy(pw->p[i].set),
1683 FN(EL,copy)(pw->p[i].FIELD), user) < 0)
1684 return isl_stat_error;
1686 return isl_stat_ok;
1689 #ifndef NO_LIFT
1690 static isl_bool any_divs(__isl_keep isl_set *set)
1692 int i;
1694 if (!set)
1695 return isl_bool_error;
1697 for (i = 0; i < set->n; ++i)
1698 if (set->p[i]->n_div > 0)
1699 return isl_bool_true;
1701 return isl_bool_false;
1704 static isl_stat foreach_lifted_subset(__isl_take isl_set *set,
1705 __isl_take EL *el,
1706 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el,
1707 void *user), void *user)
1709 int i;
1711 if (!set || !el)
1712 goto error;
1714 for (i = 0; i < set->n; ++i) {
1715 isl_set *lift;
1716 EL *copy;
1718 lift = isl_set_from_basic_set(isl_basic_set_copy(set->p[i]));
1719 lift = isl_set_lift(lift);
1721 copy = FN(EL,copy)(el);
1722 copy = FN(EL,lift)(copy, isl_set_get_space(lift));
1724 if (fn(lift, copy, user) < 0)
1725 goto error;
1728 isl_set_free(set);
1729 FN(EL,free)(el);
1731 return isl_stat_ok;
1732 error:
1733 isl_set_free(set);
1734 FN(EL,free)(el);
1735 return isl_stat_error;
1738 isl_stat FN(PW,foreach_lifted_piece)(__isl_keep PW *pw,
1739 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el,
1740 void *user), void *user)
1742 int i;
1744 if (!pw)
1745 return isl_stat_error;
1747 for (i = 0; i < pw->n; ++i) {
1748 isl_bool any;
1749 isl_set *set;
1750 EL *el;
1752 any = any_divs(pw->p[i].set);
1753 if (any < 0)
1754 return isl_stat_error;
1755 set = isl_set_copy(pw->p[i].set);
1756 el = FN(EL,copy)(pw->p[i].FIELD);
1757 if (!any) {
1758 if (fn(set, el, user) < 0)
1759 return isl_stat_error;
1760 continue;
1762 if (foreach_lifted_subset(set, el, fn, user) < 0)
1763 return isl_stat_error;
1766 return isl_stat_ok;
1768 #endif
1770 #ifndef NO_MOVE_DIMS
1771 __isl_give PW *FN(PW,move_dims)(__isl_take PW *pw,
1772 enum isl_dim_type dst_type, unsigned dst_pos,
1773 enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1775 int i;
1777 pw = FN(PW,cow)(pw);
1778 if (!pw)
1779 return NULL;
1781 pw->dim = isl_space_move_dims(pw->dim, dst_type, dst_pos, src_type, src_pos, n);
1782 if (!pw->dim)
1783 goto error;
1785 for (i = 0; i < pw->n; ++i) {
1786 pw->p[i].FIELD = FN(EL,move_dims)(pw->p[i].FIELD,
1787 dst_type, dst_pos, src_type, src_pos, n);
1788 if (!pw->p[i].FIELD)
1789 goto error;
1792 if (dst_type == isl_dim_in)
1793 dst_type = isl_dim_set;
1794 if (src_type == isl_dim_in)
1795 src_type = isl_dim_set;
1797 for (i = 0; i < pw->n; ++i) {
1798 pw->p[i].set = isl_set_move_dims(pw->p[i].set,
1799 dst_type, dst_pos,
1800 src_type, src_pos, n);
1801 if (!pw->p[i].set)
1802 goto error;
1805 return pw;
1806 error:
1807 FN(PW,free)(pw);
1808 return NULL;
1810 #endif
1812 __isl_give PW *FN(PW,mul_isl_int)(__isl_take PW *pw, isl_int v)
1814 int i;
1816 if (isl_int_is_one(v))
1817 return pw;
1818 if (pw && DEFAULT_IS_ZERO && isl_int_is_zero(v)) {
1819 PW *zero;
1820 isl_space *dim = FN(PW,get_space)(pw);
1821 #ifdef HAS_TYPE
1822 zero = FN(PW,ZERO)(dim, pw->type);
1823 #else
1824 zero = FN(PW,ZERO)(dim);
1825 #endif
1826 FN(PW,free)(pw);
1827 return zero;
1829 pw = FN(PW,cow)(pw);
1830 if (!pw)
1831 return NULL;
1832 if (pw->n == 0)
1833 return pw;
1835 #ifdef HAS_TYPE
1836 if (isl_int_is_neg(v))
1837 pw->type = isl_fold_type_negate(pw->type);
1838 #endif
1839 for (i = 0; i < pw->n; ++i) {
1840 pw->p[i].FIELD = FN(EL,scale)(pw->p[i].FIELD, v);
1841 if (!pw->p[i].FIELD)
1842 goto error;
1845 return pw;
1846 error:
1847 FN(PW,free)(pw);
1848 return NULL;
1851 /* Multiply the pieces of "pw" by "v" and return the result.
1853 __isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v)
1855 int i;
1857 if (!pw || !v)
1858 goto error;
1860 if (isl_val_is_one(v)) {
1861 isl_val_free(v);
1862 return pw;
1864 if (pw && DEFAULT_IS_ZERO && isl_val_is_zero(v)) {
1865 PW *zero;
1866 isl_space *space = FN(PW,get_space)(pw);
1867 #ifdef HAS_TYPE
1868 zero = FN(PW,ZERO)(space, pw->type);
1869 #else
1870 zero = FN(PW,ZERO)(space);
1871 #endif
1872 FN(PW,free)(pw);
1873 isl_val_free(v);
1874 return zero;
1876 if (pw->n == 0) {
1877 isl_val_free(v);
1878 return pw;
1880 pw = FN(PW,cow)(pw);
1881 if (!pw)
1882 goto error;
1884 #ifdef HAS_TYPE
1885 if (isl_val_is_neg(v))
1886 pw->type = isl_fold_type_negate(pw->type);
1887 #endif
1888 for (i = 0; i < pw->n; ++i) {
1889 pw->p[i].FIELD = FN(EL,scale_val)(pw->p[i].FIELD,
1890 isl_val_copy(v));
1891 if (!pw->p[i].FIELD)
1892 goto error;
1895 isl_val_free(v);
1896 return pw;
1897 error:
1898 isl_val_free(v);
1899 FN(PW,free)(pw);
1900 return NULL;
1903 /* Divide the pieces of "pw" by "v" and return the result.
1905 __isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v)
1907 int i;
1909 if (!pw || !v)
1910 goto error;
1912 if (isl_val_is_one(v)) {
1913 isl_val_free(v);
1914 return pw;
1917 if (!isl_val_is_rat(v))
1918 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1919 "expecting rational factor", goto error);
1920 if (isl_val_is_zero(v))
1921 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1922 "cannot scale down by zero", goto error);
1924 if (pw->n == 0) {
1925 isl_val_free(v);
1926 return pw;
1928 pw = FN(PW,cow)(pw);
1929 if (!pw)
1930 goto error;
1932 #ifdef HAS_TYPE
1933 if (isl_val_is_neg(v))
1934 pw->type = isl_fold_type_negate(pw->type);
1935 #endif
1936 for (i = 0; i < pw->n; ++i) {
1937 pw->p[i].FIELD = FN(EL,scale_down_val)(pw->p[i].FIELD,
1938 isl_val_copy(v));
1939 if (!pw->p[i].FIELD)
1940 goto error;
1943 isl_val_free(v);
1944 return pw;
1945 error:
1946 isl_val_free(v);
1947 FN(PW,free)(pw);
1948 return NULL;
1951 __isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v)
1953 return FN(PW,mul_isl_int)(pw, v);
1956 /* Apply some normalization to "pw".
1957 * In particular, sort the pieces according to their function value
1958 * expressions, combining pairs of adjacent pieces with
1959 * the same such expression, and then normalize the domains of the pieces.
1961 * We normalize in place, but if anything goes wrong we need
1962 * to return NULL, so we need to make sure we don't change the
1963 * meaning of any possible other copies of "pw".
1965 __isl_give PW *FN(PW,normalize)(__isl_take PW *pw)
1967 int i;
1968 isl_set *set;
1970 pw = FN(PW,sort)(pw);
1971 if (!pw)
1972 return NULL;
1973 for (i = 0; i < pw->n; ++i) {
1974 set = isl_set_normalize(isl_set_copy(pw->p[i].set));
1975 if (!set)
1976 return FN(PW,free)(pw);
1977 isl_set_free(pw->p[i].set);
1978 pw->p[i].set = set;
1981 return pw;
1984 /* Is pw1 obviously equal to pw2?
1985 * That is, do they have obviously identical cells and obviously identical
1986 * elements on each cell?
1988 * If "pw1" or "pw2" contain any NaNs, then they are considered
1989 * not to be the same. A NaN is not equal to anything, not even
1990 * to another NaN.
1992 isl_bool FN(PW,plain_is_equal)(__isl_keep PW *pw1, __isl_keep PW *pw2)
1994 int i;
1995 isl_bool equal, has_nan;
1997 if (!pw1 || !pw2)
1998 return isl_bool_error;
2000 has_nan = FN(PW,involves_nan)(pw1);
2001 if (has_nan >= 0 && !has_nan)
2002 has_nan = FN(PW,involves_nan)(pw2);
2003 if (has_nan < 0 || has_nan)
2004 return isl_bool_not(has_nan);
2006 if (pw1 == pw2)
2007 return isl_bool_true;
2008 if (!isl_space_is_equal(pw1->dim, pw2->dim))
2009 return isl_bool_false;
2011 pw1 = FN(PW,copy)(pw1);
2012 pw2 = FN(PW,copy)(pw2);
2013 pw1 = FN(PW,normalize)(pw1);
2014 pw2 = FN(PW,normalize)(pw2);
2015 if (!pw1 || !pw2)
2016 goto error;
2018 equal = pw1->n == pw2->n;
2019 for (i = 0; equal && i < pw1->n; ++i) {
2020 equal = isl_set_plain_is_equal(pw1->p[i].set, pw2->p[i].set);
2021 if (equal < 0)
2022 goto error;
2023 if (!equal)
2024 break;
2025 equal = FN(EL,plain_is_equal)(pw1->p[i].FIELD, pw2->p[i].FIELD);
2026 if (equal < 0)
2027 goto error;
2030 FN(PW,free)(pw1);
2031 FN(PW,free)(pw2);
2032 return equal;
2033 error:
2034 FN(PW,free)(pw1);
2035 FN(PW,free)(pw2);
2036 return isl_bool_error;
2039 /* Does "pw" involve any NaNs?
2041 isl_bool FN(PW,involves_nan)(__isl_keep PW *pw)
2043 int i;
2045 if (!pw)
2046 return isl_bool_error;
2047 if (pw->n == 0)
2048 return isl_bool_false;
2050 for (i = 0; i < pw->n; ++i) {
2051 isl_bool has_nan = FN(EL,involves_nan)(pw->p[i].FIELD);
2052 if (has_nan < 0 || has_nan)
2053 return has_nan;
2056 return isl_bool_false;
2059 #ifndef NO_PULLBACK
2060 static __isl_give PW *FN(PW,align_params_pw_multi_aff_and)(__isl_take PW *pw,
2061 __isl_take isl_multi_aff *ma,
2062 __isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_multi_aff *ma))
2064 isl_ctx *ctx;
2065 isl_bool equal_params;
2066 isl_space *ma_space;
2068 ma_space = isl_multi_aff_get_space(ma);
2069 if (!pw || !ma || !ma_space)
2070 goto error;
2071 equal_params = isl_space_has_equal_params(pw->dim, ma_space);
2072 if (equal_params < 0)
2073 goto error;
2074 if (equal_params) {
2075 isl_space_free(ma_space);
2076 return fn(pw, ma);
2078 ctx = FN(PW,get_ctx)(pw);
2079 if (FN(PW,check_named_params)(pw) < 0)
2080 goto error;
2081 if (!isl_space_has_named_params(ma_space))
2082 isl_die(ctx, isl_error_invalid,
2083 "unaligned unnamed parameters", goto error);
2084 pw = FN(PW,align_params)(pw, ma_space);
2085 ma = isl_multi_aff_align_params(ma, FN(PW,get_space)(pw));
2086 return fn(pw, ma);
2087 error:
2088 isl_space_free(ma_space);
2089 FN(PW,free)(pw);
2090 isl_multi_aff_free(ma);
2091 return NULL;
2094 static __isl_give PW *FN(PW,align_params_pw_pw_multi_aff_and)(__isl_take PW *pw,
2095 __isl_take isl_pw_multi_aff *pma,
2096 __isl_give PW *(*fn)(__isl_take PW *pw,
2097 __isl_take isl_pw_multi_aff *ma))
2099 isl_ctx *ctx;
2100 isl_bool equal_params;
2101 isl_space *pma_space;
2103 pma_space = isl_pw_multi_aff_get_space(pma);
2104 if (!pw || !pma || !pma_space)
2105 goto error;
2106 equal_params = isl_space_has_equal_params(pw->dim, pma_space);
2107 if (equal_params < 0)
2108 goto error;
2109 if (equal_params) {
2110 isl_space_free(pma_space);
2111 return fn(pw, pma);
2113 ctx = FN(PW,get_ctx)(pw);
2114 if (FN(PW,check_named_params)(pw) < 0 ||
2115 isl_pw_multi_aff_check_named_params(pma) < 0)
2116 goto error;
2117 pw = FN(PW,align_params)(pw, pma_space);
2118 pma = isl_pw_multi_aff_align_params(pma, FN(PW,get_space)(pw));
2119 return fn(pw, pma);
2120 error:
2121 isl_space_free(pma_space);
2122 FN(PW,free)(pw);
2123 isl_pw_multi_aff_free(pma);
2124 return NULL;
2127 /* Compute the pullback of "pw" by the function represented by "ma".
2128 * In other words, plug in "ma" in "pw".
2130 static __isl_give PW *FN(PW,pullback_multi_aff_aligned)(__isl_take PW *pw,
2131 __isl_take isl_multi_aff *ma)
2133 int i;
2134 isl_space *space = NULL;
2136 ma = isl_multi_aff_align_divs(ma);
2137 pw = FN(PW,cow)(pw);
2138 if (!pw || !ma)
2139 goto error;
2141 space = isl_space_join(isl_multi_aff_get_space(ma),
2142 FN(PW,get_space)(pw));
2144 for (i = 0; i < pw->n; ++i) {
2145 pw->p[i].set = isl_set_preimage_multi_aff(pw->p[i].set,
2146 isl_multi_aff_copy(ma));
2147 if (!pw->p[i].set)
2148 goto error;
2149 pw->p[i].FIELD = FN(EL,pullback_multi_aff)(pw->p[i].FIELD,
2150 isl_multi_aff_copy(ma));
2151 if (!pw->p[i].FIELD)
2152 goto error;
2155 pw = FN(PW,reset_space)(pw, space);
2156 isl_multi_aff_free(ma);
2157 return pw;
2158 error:
2159 isl_space_free(space);
2160 isl_multi_aff_free(ma);
2161 FN(PW,free)(pw);
2162 return NULL;
2165 __isl_give PW *FN(PW,pullback_multi_aff)(__isl_take PW *pw,
2166 __isl_take isl_multi_aff *ma)
2168 return FN(PW,align_params_pw_multi_aff_and)(pw, ma,
2169 &FN(PW,pullback_multi_aff_aligned));
2172 /* Compute the pullback of "pw" by the function represented by "pma".
2173 * In other words, plug in "pma" in "pw".
2175 static __isl_give PW *FN(PW,pullback_pw_multi_aff_aligned)(__isl_take PW *pw,
2176 __isl_take isl_pw_multi_aff *pma)
2178 int i;
2179 PW *res;
2181 if (!pma)
2182 goto error;
2184 if (pma->n == 0) {
2185 isl_space *space;
2186 space = isl_space_join(isl_pw_multi_aff_get_space(pma),
2187 FN(PW,get_space)(pw));
2188 isl_pw_multi_aff_free(pma);
2189 res = FN(PW,empty)(space);
2190 FN(PW,free)(pw);
2191 return res;
2194 res = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
2195 isl_multi_aff_copy(pma->p[0].maff));
2196 res = FN(PW,intersect_domain)(res, isl_set_copy(pma->p[0].set));
2198 for (i = 1; i < pma->n; ++i) {
2199 PW *res_i;
2201 res_i = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
2202 isl_multi_aff_copy(pma->p[i].maff));
2203 res_i = FN(PW,intersect_domain)(res_i,
2204 isl_set_copy(pma->p[i].set));
2205 res = FN(PW,add_disjoint)(res, res_i);
2208 isl_pw_multi_aff_free(pma);
2209 FN(PW,free)(pw);
2210 return res;
2211 error:
2212 isl_pw_multi_aff_free(pma);
2213 FN(PW,free)(pw);
2214 return NULL;
2217 __isl_give PW *FN(PW,pullback_pw_multi_aff)(__isl_take PW *pw,
2218 __isl_take isl_pw_multi_aff *pma)
2220 return FN(PW,align_params_pw_pw_multi_aff_and)(pw, pma,
2221 &FN(PW,pullback_pw_multi_aff_aligned));
2223 #endif