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,
11 * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
17 #include <isl_val_private.h>
19 #include <isl_pw_macro.h>
23 __isl_give PW
*FN(PW
,alloc_size
)(__isl_take isl_space
*space
24 OPT_TYPE_PARAM
, int n
)
31 ctx
= isl_space_get_ctx(space
);
32 isl_assert(ctx
, n
>= 0, goto error
);
33 pw
= isl_alloc(ctx
, struct PW
,
34 sizeof(struct PW
) + (n
- 1) * sizeof(S(PW
,piece
)));
39 OPT_SET_TYPE(pw
->, type
);
45 isl_space_free(space
);
49 __isl_give PW
*FN(PW
,ZERO
)(__isl_take isl_space
*space OPT_TYPE_PARAM
)
51 return FN(PW
,alloc_size
)(space
OPT_TYPE_ARG(NO_LOC
), 0);
54 __isl_give PW
*FN(PW
,add_piece
)(__isl_take PW
*pw
,
55 __isl_take isl_set
*set
, __isl_take EL
*el
)
58 isl_space
*el_dim
= NULL
;
60 if (!pw
|| !set
|| !el
)
63 if (isl_set_plain_is_empty(set
) || FN(EL
,EL_IS_ZERO
)(el
)) {
69 ctx
= isl_set_get_ctx(set
);
70 if (!OPT_EQUAL_TYPES(pw
->, el
->))
71 isl_die(ctx
, isl_error_invalid
, "fold types don't match",
73 el_dim
= FN(EL
,get_space(el
));
74 isl_assert(ctx
, isl_space_is_equal(pw
->dim
, el_dim
), goto error
);
75 isl_assert(ctx
, pw
->n
< pw
->size
, goto error
);
77 pw
->p
[pw
->n
].set
= set
;
78 pw
->p
[pw
->n
].FIELD
= el
;
81 isl_space_free(el_dim
);
84 isl_space_free(el_dim
);
91 /* Does the space of "set" correspond to that of the domain of "el".
93 static isl_bool
FN(PW
,compatible_domain
)(__isl_keep EL
*el
,
94 __isl_keep isl_set
*set
)
97 isl_space
*el_space
, *set_space
;
100 return isl_bool_error
;
101 set_space
= isl_set_get_space(set
);
102 el_space
= FN(EL
,get_space
)(el
);
103 ok
= isl_space_is_domain_internal(set_space
, el_space
);
104 isl_space_free(el_space
);
105 isl_space_free(set_space
);
109 /* Check that the space of "set" corresponds to that of the domain of "el".
111 static isl_stat
FN(PW
,check_compatible_domain
)(__isl_keep EL
*el
,
112 __isl_keep isl_set
*set
)
116 ok
= FN(PW
,compatible_domain
)(el
, set
);
118 return isl_stat_error
;
120 isl_die(isl_set_get_ctx(set
), isl_error_invalid
,
121 "incompatible spaces", return isl_stat_error
);
126 __isl_give PW
*FN(PW
,alloc
)(OPT_TYPE_PARAM_FIRST
127 __isl_take isl_set
*set
, __isl_take EL
*el
)
131 if (FN(PW
,check_compatible_domain
)(el
, set
) < 0)
134 pw
= FN(PW
,alloc_size
)(FN(EL
,get_space
)(el
) OPT_TYPE_ARG(NO_LOC
), 1);
136 return FN(PW
,add_piece
)(pw
, set
, el
);
143 __isl_give PW
*FN(PW
,dup
)(__isl_keep PW
*pw
)
151 dup
= FN(PW
,alloc_size
)(isl_space_copy(pw
->dim
)
152 OPT_TYPE_ARG(pw
->), pw
->n
);
156 for (i
= 0; i
< pw
->n
; ++i
)
157 dup
= FN(PW
,add_piece
)(dup
, isl_set_copy(pw
->p
[i
].set
),
158 FN(EL
,copy
)(pw
->p
[i
].FIELD
));
163 __isl_give PW
*FN(PW
,cow
)(__isl_take PW
*pw
)
171 return FN(PW
,dup
)(pw
);
174 __isl_give PW
*FN(PW
,copy
)(__isl_keep PW
*pw
)
183 __isl_null PW
*FN(PW
,free
)(__isl_take PW
*pw
)
192 for (i
= 0; i
< pw
->n
; ++i
) {
193 isl_set_free(pw
->p
[i
].set
);
194 FN(EL
,free
)(pw
->p
[i
].FIELD
);
196 isl_space_free(pw
->dim
);
202 /* Create a piecewise expression with the given base expression on a universe
205 static __isl_give PW
*FN(FN(FN(PW
,from
),BASE
),type_base
)(__isl_take EL
*el
208 isl_set
*dom
= isl_set_universe(FN(EL
,get_domain_space
)(el
));
209 return FN(PW
,alloc
)(OPT_TYPE_ARG_FIRST(NO_LOC
) dom
, el
);
212 /* Create a piecewise expression with the given base expression on a universe
215 * If the default value of this piecewise type is zero and
216 * if "el" is effectively zero, then create an empty piecewise expression
219 static __isl_give PW
*FN(FN(FN(PW
,from
),BASE
),type
)(__isl_take EL
*el
225 if (!DEFAULT_IS_ZERO
)
226 return FN(FN(FN(PW
,from
),BASE
),type_base
)(el
227 OPT_TYPE_ARG(NO_LOC
));
228 is_zero
= FN(EL
,EL_IS_ZERO
)(el
);
232 return FN(FN(FN(PW
,from
),BASE
),type_base
)(el
233 OPT_TYPE_ARG(NO_LOC
));
234 space
= FN(EL
,get_space
)(el
);
236 return FN(PW
,ZERO
)(space
OPT_TYPE_ARG(NO_LOC
));
243 /* Create a piecewise expression with the given base expression on a universe
246 * Pass along the type as an extra argument for improved uniformity
247 * with piecewise types that do not have a fold type.
249 __isl_give PW
*FN(FN(PW
,from
),BASE
)(__isl_take EL
*el
)
251 enum isl_fold type
= FN(EL
,get_type
)(el
);
252 return FN(FN(FN(PW
,from
),BASE
),type
)(el
, type
);
255 __isl_give PW
*FN(FN(PW
,from
),BASE
)(__isl_take EL
*el
)
257 return FN(FN(FN(PW
,from
),BASE
),type
)(el
);
261 const char *FN(PW
,get_dim_name
)(__isl_keep PW
*pw
, enum isl_dim_type type
,
264 return pw
? isl_space_get_dim_name(pw
->dim
, type
, pos
) : NULL
;
267 isl_bool
FN(PW
,has_dim_id
)(__isl_keep PW
*pw
, enum isl_dim_type type
,
270 return pw
? isl_space_has_dim_id(pw
->dim
, type
, pos
) : isl_bool_error
;
273 __isl_give isl_id
*FN(PW
,get_dim_id
)(__isl_keep PW
*pw
, enum isl_dim_type type
,
276 return pw
? isl_space_get_dim_id(pw
->dim
, type
, pos
) : NULL
;
279 isl_bool
FN(PW
,has_tuple_name
)(__isl_keep PW
*pw
, enum isl_dim_type type
)
281 return pw
? isl_space_has_tuple_name(pw
->dim
, type
) : isl_bool_error
;
284 const char *FN(PW
,get_tuple_name
)(__isl_keep PW
*pw
, enum isl_dim_type type
)
286 return pw
? isl_space_get_tuple_name(pw
->dim
, type
) : NULL
;
289 isl_bool
FN(PW
,has_tuple_id
)(__isl_keep PW
*pw
, enum isl_dim_type type
)
291 return pw
? isl_space_has_tuple_id(pw
->dim
, type
) : isl_bool_error
;
294 __isl_give isl_id
*FN(PW
,get_tuple_id
)(__isl_keep PW
*pw
, enum isl_dim_type type
)
296 return pw
? isl_space_get_tuple_id(pw
->dim
, type
) : NULL
;
299 isl_bool
FN(PW
,IS_ZERO
)(__isl_keep PW
*pw
)
302 return isl_bool_error
;
304 return isl_bool_ok(pw
->n
== 0);
308 __isl_give PW
*FN(PW
,realign_domain
)(__isl_take PW
*pw
,
309 __isl_take isl_reordering
*exp
)
317 for (i
= 0; i
< pw
->n
; ++i
) {
318 pw
->p
[i
].set
= isl_set_realign(pw
->p
[i
].set
,
319 isl_reordering_copy(exp
));
322 pw
->p
[i
].FIELD
= FN(EL
,realign_domain
)(pw
->p
[i
].FIELD
,
323 isl_reordering_copy(exp
));
328 pw
= FN(PW
,reset_domain_space
)(pw
, isl_reordering_get_space(exp
));
330 isl_reordering_free(exp
);
333 isl_reordering_free(exp
);
338 /* Check that "pw" has only named parameters, reporting an error
341 isl_stat
FN(PW
,check_named_params
)(__isl_keep PW
*pw
)
343 return isl_space_check_named_params(FN(PW
,peek_space
)(pw
));
346 /* Align the parameters of "pw" to those of "model".
348 __isl_give PW
*FN(PW
,align_params
)(__isl_take PW
*pw
, __isl_take isl_space
*model
)
351 isl_bool equal_params
;
356 ctx
= isl_space_get_ctx(model
);
357 if (!isl_space_has_named_params(model
))
358 isl_die(ctx
, isl_error_invalid
,
359 "model has unnamed parameters", goto error
);
360 if (FN(PW
,check_named_params
)(pw
) < 0)
362 equal_params
= isl_space_has_equal_params(pw
->dim
, model
);
363 if (equal_params
< 0)
368 exp
= isl_parameter_alignment_reordering(pw
->dim
, model
);
369 exp
= isl_reordering_extend_space(exp
,
370 FN(PW
,get_domain_space
)(pw
));
371 pw
= FN(PW
,realign_domain
)(pw
, exp
);
374 isl_space_free(model
);
377 isl_space_free(model
);
382 static __isl_give PW
*FN(PW
,align_params_pw_pw_and
)(__isl_take PW
*pw1
,
384 __isl_give PW
*(*fn
)(__isl_take PW
*pw1
, __isl_take PW
*pw2
))
386 isl_bool equal_params
;
390 equal_params
= isl_space_has_equal_params(pw1
->dim
, pw2
->dim
);
391 if (equal_params
< 0)
395 if (FN(PW
,check_named_params
)(pw1
) < 0 ||
396 FN(PW
,check_named_params
)(pw2
) < 0)
398 pw1
= FN(PW
,align_params
)(pw1
, FN(PW
,get_space
)(pw2
));
399 pw2
= FN(PW
,align_params
)(pw2
, FN(PW
,get_space
)(pw1
));
407 static __isl_give PW
*FN(PW
,align_params_pw_set_and
)(__isl_take PW
*pw
,
408 __isl_take isl_set
*set
,
409 __isl_give PW
*(*fn
)(__isl_take PW
*pw
, __isl_take isl_set
*set
))
416 aligned
= isl_set_space_has_equal_params(set
, pw
->dim
);
421 ctx
= FN(PW
,get_ctx
)(pw
);
422 if (FN(PW
,check_named_params
)(pw
) < 0)
424 if (!isl_space_has_named_params(set
->dim
))
425 isl_die(ctx
, isl_error_invalid
,
426 "unaligned unnamed parameters", goto error
);
427 pw
= FN(PW
,align_params
)(pw
, isl_set_get_space(set
));
428 set
= isl_set_align_params(set
, FN(PW
,get_space
)(pw
));
437 static __isl_give PW
*FN(PW
,union_add_aligned
)(__isl_take PW
*pw1
,
448 ctx
= isl_space_get_ctx(pw1
->dim
);
449 if (!OPT_EQUAL_TYPES(pw1
->, pw2
->))
450 isl_die(ctx
, isl_error_invalid
,
451 "fold types don't match", goto error
);
452 isl_assert(ctx
, isl_space_is_equal(pw1
->dim
, pw2
->dim
), goto error
);
454 if (FN(PW
,IS_ZERO
)(pw1
)) {
459 if (FN(PW
,IS_ZERO
)(pw2
)) {
464 n
= (pw1
->n
+ 1) * (pw2
->n
+ 1);
465 res
= FN(PW
,alloc_size
)(isl_space_copy(pw1
->dim
)
466 OPT_TYPE_ARG(pw1
->), n
);
468 for (i
= 0; i
< pw1
->n
; ++i
) {
469 set
= isl_set_copy(pw1
->p
[i
].set
);
470 for (j
= 0; j
< pw2
->n
; ++j
) {
471 struct isl_set
*common
;
473 common
= isl_set_intersect(isl_set_copy(pw1
->p
[i
].set
),
474 isl_set_copy(pw2
->p
[j
].set
));
475 if (isl_set_plain_is_empty(common
)) {
476 isl_set_free(common
);
479 set
= isl_set_subtract(set
,
480 isl_set_copy(pw2
->p
[j
].set
));
482 sum
= FN(EL
,add_on_domain
)(common
,
483 FN(EL
,copy
)(pw1
->p
[i
].FIELD
),
484 FN(EL
,copy
)(pw2
->p
[j
].FIELD
));
486 res
= FN(PW
,add_piece
)(res
, common
, sum
);
488 res
= FN(PW
,add_piece
)(res
, set
, FN(EL
,copy
)(pw1
->p
[i
].FIELD
));
491 for (j
= 0; j
< pw2
->n
; ++j
) {
492 set
= isl_set_copy(pw2
->p
[j
].set
);
493 for (i
= 0; i
< pw1
->n
; ++i
)
494 set
= isl_set_subtract(set
,
495 isl_set_copy(pw1
->p
[i
].set
));
496 res
= FN(PW
,add_piece
)(res
, set
, FN(EL
,copy
)(pw2
->p
[j
].FIELD
));
509 /* Private version of "union_add". For isl_pw_qpolynomial and
510 * isl_pw_qpolynomial_fold, we prefer to simply call it "add".
512 static __isl_give PW
*FN(PW
,union_add_
)(__isl_take PW
*pw1
, __isl_take PW
*pw2
)
514 return FN(PW
,align_params_pw_pw_and
)(pw1
, pw2
,
515 &FN(PW
,union_add_aligned
));
518 /* Make sure "pw" has room for at least "n" more pieces.
520 * If there is only one reference to pw, we extend it in place.
521 * Otherwise, we create a new PW and copy the pieces.
523 static __isl_give PW
*FN(PW
,grow
)(__isl_take PW
*pw
, int n
)
531 if (pw
->n
+ n
<= pw
->size
)
533 ctx
= FN(PW
,get_ctx
)(pw
);
536 res
= isl_realloc(ctx
, pw
, struct PW
,
537 sizeof(struct PW
) + (n
- 1) * sizeof(S(PW
,piece
)));
539 return FN(PW
,free
)(pw
);
543 res
= FN(PW
,alloc_size
)(isl_space_copy(pw
->dim
) OPT_TYPE_ARG(pw
->), n
);
545 return FN(PW
,free
)(pw
);
546 for (i
= 0; i
< pw
->n
; ++i
)
547 res
= FN(PW
,add_piece
)(res
, isl_set_copy(pw
->p
[i
].set
),
548 FN(EL
,copy
)(pw
->p
[i
].FIELD
));
553 static __isl_give PW
*FN(PW
,add_disjoint_aligned
)(__isl_take PW
*pw1
,
562 if (pw1
->size
< pw1
->n
+ pw2
->n
&& pw1
->n
< pw2
->n
)
563 return FN(PW
,add_disjoint_aligned
)(pw2
, pw1
);
565 ctx
= isl_space_get_ctx(pw1
->dim
);
566 if (!OPT_EQUAL_TYPES(pw1
->, pw2
->))
567 isl_die(ctx
, isl_error_invalid
,
568 "fold types don't match", goto error
);
569 isl_assert(ctx
, isl_space_is_equal(pw1
->dim
, pw2
->dim
), goto error
);
571 if (FN(PW
,IS_ZERO
)(pw1
)) {
576 if (FN(PW
,IS_ZERO
)(pw2
)) {
581 pw1
= FN(PW
,grow
)(pw1
, pw2
->n
);
585 for (i
= 0; i
< pw2
->n
; ++i
)
586 pw1
= FN(PW
,add_piece
)(pw1
,
587 isl_set_copy(pw2
->p
[i
].set
),
588 FN(EL
,copy
)(pw2
->p
[i
].FIELD
));
599 __isl_give PW
*FN(PW
,add_disjoint
)(__isl_take PW
*pw1
, __isl_take PW
*pw2
)
601 return FN(PW
,align_params_pw_pw_and
)(pw1
, pw2
,
602 &FN(PW
,add_disjoint_aligned
));
605 /* This function is currently only used from isl_aff.c
607 static __isl_give PW
*FN(PW
,on_shared_domain_in
)(__isl_take PW
*pw1
,
608 __isl_take PW
*pw2
, __isl_take isl_space
*space
,
609 __isl_give EL
*(*fn
)(__isl_take EL
*el1
, __isl_take EL
*el2
))
610 __attribute__ ((unused
));
612 /* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
613 * The result of "fn" (and therefore also of this function) lives in "space".
615 static __isl_give PW
*FN(PW
,on_shared_domain_in
)(__isl_take PW
*pw1
,
616 __isl_take PW
*pw2
, __isl_take isl_space
*space
,
617 __isl_give EL
*(*fn
)(__isl_take EL
*el1
, __isl_take EL
*el2
))
626 res
= FN(PW
,alloc_size
)(isl_space_copy(space
) OPT_TYPE_ARG(pw1
->), n
);
628 for (i
= 0; i
< pw1
->n
; ++i
) {
629 for (j
= 0; j
< pw2
->n
; ++j
) {
634 common
= isl_set_intersect(
635 isl_set_copy(pw1
->p
[i
].set
),
636 isl_set_copy(pw2
->p
[j
].set
));
637 empty
= isl_set_plain_is_empty(common
);
638 if (empty
< 0 || empty
) {
639 isl_set_free(common
);
645 res_ij
= fn(FN(EL
,copy
)(pw1
->p
[i
].FIELD
),
646 FN(EL
,copy
)(pw2
->p
[j
].FIELD
));
647 res_ij
= FN(EL
,gist
)(res_ij
, isl_set_copy(common
));
649 res
= FN(PW
,add_piece
)(res
, common
, res_ij
);
653 isl_space_free(space
);
658 isl_space_free(space
);
665 /* This function is currently only used from isl_aff.c
667 static __isl_give PW
*FN(PW
,on_shared_domain
)(__isl_take PW
*pw1
,
669 __isl_give EL
*(*fn
)(__isl_take EL
*el1
, __isl_take EL
*el2
))
670 __attribute__ ((unused
));
672 /* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
673 * The result of "fn" is assumed to live in the same space as "pw1" and "pw2".
675 static __isl_give PW
*FN(PW
,on_shared_domain
)(__isl_take PW
*pw1
,
677 __isl_give EL
*(*fn
)(__isl_take EL
*el1
, __isl_take EL
*el2
))
684 space
= isl_space_copy(pw1
->dim
);
685 return FN(PW
,on_shared_domain_in
)(pw1
, pw2
, space
, fn
);
693 __isl_give PW
*FN(PW
,neg
)(__isl_take PW
*pw
)
700 if (FN(PW
,IS_ZERO
)(pw
))
707 for (i
= 0; i
< pw
->n
; ++i
) {
708 pw
->p
[i
].FIELD
= FN(EL
,neg
)(pw
->p
[i
].FIELD
);
710 return FN(PW
,free
)(pw
);
718 __isl_give PW
*FN(PW
,sub
)(__isl_take PW
*pw1
, __isl_take PW
*pw2
)
720 return FN(PW
,add
)(pw1
, FN(PW
,neg
)(pw2
));
724 /* Return the parameter domain of "pw".
726 __isl_give isl_set
*FN(PW
,params
)(__isl_take PW
*pw
)
728 return isl_set_params(FN(PW
,domain
)(pw
));
731 __isl_give isl_set
*FN(PW
,domain
)(__isl_take PW
*pw
)
739 dom
= isl_set_empty(FN(PW
,get_domain_space
)(pw
));
740 for (i
= 0; i
< pw
->n
; ++i
)
741 dom
= isl_set_union_disjoint(dom
, isl_set_copy(pw
->p
[i
].set
));
748 /* Exploit the equalities in the domain of piece "i" of "pw"
749 * to simplify the associated function.
750 * If the domain of piece "i" is empty, then remove it entirely,
751 * replacing it with the final piece.
753 static int FN(PW
,exploit_equalities_and_remove_if_empty
)(__isl_keep PW
*pw
,
757 int empty
= isl_set_plain_is_empty(pw
->p
[i
].set
);
762 isl_set_free(pw
->p
[i
].set
);
763 FN(EL
,free
)(pw
->p
[i
].FIELD
);
765 pw
->p
[i
] = pw
->p
[pw
->n
- 1];
771 aff
= isl_set_affine_hull(isl_set_copy(pw
->p
[i
].set
));
772 pw
->p
[i
].FIELD
= FN(EL
,substitute_equalities
)(pw
->p
[i
].FIELD
, aff
);
779 /* Convert a piecewise expression defined over a parameter domain
780 * into one that is defined over a zero-dimensional set.
782 __isl_give PW
*FN(PW
,from_range
)(__isl_take PW
*pw
)
788 if (!isl_space_is_set(pw
->dim
))
789 isl_die(FN(PW
,get_ctx
)(pw
), isl_error_invalid
,
790 "not living in a set space", return FN(PW
,free
)(pw
));
792 space
= FN(PW
,get_space
)(pw
);
793 space
= isl_space_from_range(space
);
794 pw
= FN(PW
,reset_space
)(pw
, space
);
799 /* Fix the value of the given parameter or domain dimension of "pw"
800 * to be equal to "value".
802 __isl_give PW
*FN(PW
,fix_si
)(__isl_take PW
*pw
, enum isl_dim_type type
,
803 unsigned pos
, int value
)
810 if (type
== isl_dim_out
)
811 isl_die(FN(PW
,get_ctx
)(pw
), isl_error_invalid
,
812 "cannot fix output dimension", return FN(PW
,free
)(pw
));
817 if (type
== isl_dim_in
)
822 return FN(PW
,free
)(pw
);
824 for (i
= pw
->n
- 1; i
>= 0; --i
) {
825 pw
->p
[i
].set
= isl_set_fix_si(pw
->p
[i
].set
, type
, pos
, value
);
826 if (FN(PW
,exploit_equalities_and_remove_if_empty
)(pw
, i
) < 0)
827 return FN(PW
,free
)(pw
);
833 /* Restrict the domain of "pw" by combining each cell
834 * with "set" through a call to "fn", where "fn" may be
835 * isl_set_intersect, isl_set_intersect_params, isl_set_intersect_factor_domain,
836 * isl_set_intersect_factor_range or isl_set_subtract.
838 static __isl_give PW
*FN(PW
,restrict_domain_aligned
)(__isl_take PW
*pw
,
839 __isl_take isl_set
*set
,
840 __isl_give isl_set
*(*fn
)(__isl_take isl_set
*set1
,
841 __isl_take isl_set
*set2
))
857 for (i
= pw
->n
- 1; i
>= 0; --i
) {
858 pw
->p
[i
].set
= fn(pw
->p
[i
].set
, isl_set_copy(set
));
859 if (FN(PW
,exploit_equalities_and_remove_if_empty
)(pw
, i
) < 0)
871 static __isl_give PW
*FN(PW
,intersect_domain_aligned
)(__isl_take PW
*pw
,
872 __isl_take isl_set
*set
)
874 return FN(PW
,restrict_domain_aligned
)(pw
, set
, &isl_set_intersect
);
877 __isl_give PW
*FN(PW
,intersect_domain
)(__isl_take PW
*pw
,
878 __isl_take isl_set
*context
)
880 return FN(PW
,align_params_pw_set_and
)(pw
, context
,
881 &FN(PW
,intersect_domain_aligned
));
884 static __isl_give PW
*FN(PW
,intersect_params_aligned
)(__isl_take PW
*pw
,
885 __isl_take isl_set
*set
)
887 return FN(PW
,restrict_domain_aligned
)(pw
, set
,
888 &isl_set_intersect_params
);
891 /* Intersect the domain of "pw" with the parameter domain "context".
893 __isl_give PW
*FN(PW
,intersect_params
)(__isl_take PW
*pw
,
894 __isl_take isl_set
*context
)
896 return FN(PW
,align_params_pw_set_and
)(pw
, context
,
897 &FN(PW
,intersect_params_aligned
));
900 /* Given a piecewise expression "pw" with domain in a space [A -> B] and
901 * a set in the space A, intersect the domain with the set,
902 * assuming the parameters have been aligned.
904 static __isl_give PW
*FN(PW
,intersect_domain_wrapped_domain_aligned
)(
905 __isl_take PW
*pw
, __isl_take isl_set
*set
)
907 return FN(PW
,restrict_domain_aligned
)(pw
, set
,
908 &isl_set_intersect_factor_domain
);
911 /* Given a piecewise expression "pw" with domain in a space [A -> B] and
912 * a set in the space A, intersect the domain with the set.
914 __isl_give PW
*FN(PW
,intersect_domain_wrapped_domain
)(__isl_take PW
*pw
,
915 __isl_take isl_set
*set
)
917 return FN(PW
,align_params_pw_set_and
)(pw
, set
,
918 &FN(PW
,intersect_domain_wrapped_domain_aligned
));
921 /* Given a piecewise expression "pw" with domain in a space [A -> B] and
922 * a set in the space B, intersect the domain with the set,
923 * assuming the parameters have been aligned.
925 static __isl_give PW
*FN(PW
,intersect_domain_wrapped_range_aligned
)(
926 __isl_take PW
*pw
, __isl_take isl_set
*set
)
928 return FN(PW
,restrict_domain_aligned
)(pw
, set
,
929 &isl_set_intersect_factor_range
);
932 /* Given a piecewise expression "pw" with domain in a space [A -> B] and
933 * a set in the space B, intersect the domain with the set.
935 __isl_give PW
*FN(PW
,intersect_domain_wrapped_range
)(__isl_take PW
*pw
,
936 __isl_take isl_set
*set
)
938 return FN(PW
,align_params_pw_set_and
)(pw
, set
,
939 &FN(PW
,intersect_domain_wrapped_range_aligned
));
942 /* Subtract "domain' from the domain of "pw", assuming their
943 * parameters have been aligned.
945 static __isl_give PW
*FN(PW
,subtract_domain_aligned
)(__isl_take PW
*pw
,
946 __isl_take isl_set
*domain
)
948 return FN(PW
,restrict_domain_aligned
)(pw
, domain
, &isl_set_subtract
);
951 /* Subtract "domain' from the domain of "pw".
953 __isl_give PW
*FN(PW
,subtract_domain
)(__isl_take PW
*pw
,
954 __isl_take isl_set
*domain
)
956 return FN(PW
,align_params_pw_set_and
)(pw
, domain
,
957 &FN(PW
,subtract_domain_aligned
));
960 /* Compute the gist of "pw" with respect to the domain constraints
961 * of "context" for the case where the domain of the last element
962 * of "pw" is equal to "context".
963 * Call "fn_el" to compute the gist of this element, replace
964 * its domain by the universe and drop all other elements
965 * as their domains are necessarily disjoint from "context".
967 static __isl_give PW
*FN(PW
,gist_last
)(__isl_take PW
*pw
,
968 __isl_take isl_set
*context
,
969 __isl_give EL
*(*fn_el
)(__isl_take EL
*el
, __isl_take isl_set
*set
))
974 for (i
= 0; i
< pw
->n
- 1; ++i
) {
975 isl_set_free(pw
->p
[i
].set
);
976 FN(EL
,free
)(pw
->p
[i
].FIELD
);
978 pw
->p
[0].FIELD
= pw
->p
[pw
->n
- 1].FIELD
;
979 pw
->p
[0].set
= pw
->p
[pw
->n
- 1].set
;
982 space
= isl_set_get_space(context
);
983 pw
->p
[0].FIELD
= fn_el(pw
->p
[0].FIELD
, context
);
984 context
= isl_set_universe(space
);
985 isl_set_free(pw
->p
[0].set
);
986 pw
->p
[0].set
= context
;
988 if (!pw
->p
[0].FIELD
|| !pw
->p
[0].set
)
989 return FN(PW
,free
)(pw
);
994 /* Compute the gist of "pw" with respect to the domain constraints
995 * of "context". Call "fn_el" to compute the gist of the elements
996 * and "fn_dom" to compute the gist of the domains.
998 * If the piecewise expression is empty or the context is the universe,
999 * then nothing can be simplified.
1001 static __isl_give PW
*FN(PW
,gist_aligned
)(__isl_take PW
*pw
,
1002 __isl_take isl_set
*context
,
1003 __isl_give EL
*(*fn_el
)(__isl_take EL
*el
,
1004 __isl_take isl_set
*set
),
1005 __isl_give isl_set
*(*fn_dom
)(__isl_take isl_set
*set
,
1006 __isl_take isl_basic_set
*bset
))
1011 isl_basic_set
*hull
= NULL
;
1013 if (!pw
|| !context
)
1017 isl_set_free(context
);
1021 is_universe
= isl_set_plain_is_universe(context
);
1022 if (is_universe
< 0)
1025 isl_set_free(context
);
1029 aligned
= isl_set_space_has_equal_params(context
, pw
->dim
);
1033 pw
= FN(PW
,align_params
)(pw
, isl_set_get_space(context
));
1034 context
= isl_set_align_params(context
, FN(PW
,get_space
)(pw
));
1037 pw
= FN(PW
,cow
)(pw
);
1044 equal
= isl_set_plain_is_equal(pw
->p
[0].set
, context
);
1048 return FN(PW
,gist_last
)(pw
, context
, fn_el
);
1051 context
= isl_set_compute_divs(context
);
1052 hull
= isl_set_simple_hull(isl_set_copy(context
));
1054 for (i
= pw
->n
- 1; i
>= 0; --i
) {
1058 if (i
== pw
->n
- 1) {
1060 equal
= isl_set_plain_is_equal(pw
->p
[i
].set
, context
);
1064 isl_basic_set_free(hull
);
1065 return FN(PW
,gist_last
)(pw
, context
, fn_el
);
1068 set_i
= isl_set_intersect(isl_set_copy(pw
->p
[i
].set
),
1069 isl_set_copy(context
));
1070 empty
= isl_set_plain_is_empty(set_i
);
1071 pw
->p
[i
].FIELD
= fn_el(pw
->p
[i
].FIELD
, set_i
);
1072 pw
->p
[i
].set
= fn_dom(pw
->p
[i
].set
, isl_basic_set_copy(hull
));
1073 if (empty
< 0 || !pw
->p
[i
].FIELD
|| !pw
->p
[i
].set
)
1076 isl_set_free(pw
->p
[i
].set
);
1077 FN(EL
,free
)(pw
->p
[i
].FIELD
);
1079 pw
->p
[i
] = pw
->p
[pw
->n
- 1];
1084 isl_basic_set_free(hull
);
1085 isl_set_free(context
);
1090 isl_basic_set_free(hull
);
1091 isl_set_free(context
);
1095 static __isl_give PW
*FN(PW
,gist_domain_aligned
)(__isl_take PW
*pw
,
1096 __isl_take isl_set
*set
)
1098 return FN(PW
,gist_aligned
)(pw
, set
, &FN(EL
,gist
),
1099 &isl_set_gist_basic_set
);
1102 __isl_give PW
*FN(PW
,gist
)(__isl_take PW
*pw
, __isl_take isl_set
*context
)
1104 return FN(PW
,align_params_pw_set_and
)(pw
, context
,
1105 &FN(PW
,gist_domain_aligned
));
1108 static __isl_give PW
*FN(PW
,gist_params_aligned
)(__isl_take PW
*pw
,
1109 __isl_take isl_set
*set
)
1111 return FN(PW
,gist_aligned
)(pw
, set
, &FN(EL
,gist_params
),
1112 &isl_set_gist_params_basic_set
);
1115 __isl_give PW
*FN(PW
,gist_params
)(__isl_take PW
*pw
,
1116 __isl_take isl_set
*context
)
1118 return FN(PW
,align_params_pw_set_and
)(pw
, context
,
1119 &FN(PW
,gist_params_aligned
));
1122 /* Return -1 if the piece "p1" should be sorted before "p2"
1123 * and 1 if it should be sorted after "p2".
1124 * Return 0 if they do not need to be sorted in a specific order.
1126 * The two pieces are compared on the basis of their function value expressions.
1128 static int FN(PW
,sort_field_cmp
)(const void *p1
, const void *p2
, void *arg
)
1130 struct FN(PW
,piece
) const *pc1
= p1
;
1131 struct FN(PW
,piece
) const *pc2
= p2
;
1133 return FN(EL
,plain_cmp
)(pc1
->FIELD
, pc2
->FIELD
);
1136 /* Sort the pieces of "pw" according to their function value
1137 * expressions and then combine pairs of adjacent pieces with
1138 * the same such expression.
1140 * The sorting is performed in place because it does not
1141 * change the meaning of "pw", but care needs to be
1142 * taken not to change any possible other copies of "pw"
1143 * in case anything goes wrong.
1145 __isl_give PW
*FN(PW
,sort
)(__isl_take PW
*pw
)
1154 if (isl_sort(pw
->p
, pw
->n
, sizeof(pw
->p
[0]),
1155 &FN(PW
,sort_field_cmp
), NULL
) < 0)
1156 return FN(PW
,free
)(pw
);
1157 for (i
= pw
->n
- 1; i
>= 1; --i
) {
1158 if (!FN(EL
,plain_is_equal
)(pw
->p
[i
- 1].FIELD
, pw
->p
[i
].FIELD
))
1160 set
= isl_set_union(isl_set_copy(pw
->p
[i
- 1].set
),
1161 isl_set_copy(pw
->p
[i
].set
));
1163 return FN(PW
,free
)(pw
);
1164 isl_set_free(pw
->p
[i
].set
);
1165 FN(EL
,free
)(pw
->p
[i
].FIELD
);
1166 isl_set_free(pw
->p
[i
- 1].set
);
1167 pw
->p
[i
- 1].set
= set
;
1168 for (j
= i
+ 1; j
< pw
->n
; ++j
)
1169 pw
->p
[j
- 1] = pw
->p
[j
];
1176 /* Coalesce the domains of "pw".
1178 * Prior to the actual coalescing, first sort the pieces such that
1179 * pieces with the same function value expression are combined
1180 * into a single piece, the combined domain of which can then
1183 __isl_give PW
*FN(PW
,coalesce
)(__isl_take PW
*pw
)
1187 pw
= FN(PW
,sort
)(pw
);
1191 for (i
= 0; i
< pw
->n
; ++i
) {
1192 pw
->p
[i
].set
= isl_set_coalesce(pw
->p
[i
].set
);
1203 isl_ctx
*FN(PW
,get_ctx
)(__isl_keep PW
*pw
)
1205 return pw
? isl_space_get_ctx(pw
->dim
) : NULL
;
1208 isl_bool
FN(PW
,involves_dims
)(__isl_keep PW
*pw
, enum isl_dim_type type
,
1209 unsigned first
, unsigned n
)
1212 enum isl_dim_type set_type
;
1215 return isl_bool_error
;
1216 if (pw
->n
== 0 || n
== 0)
1217 return isl_bool_false
;
1219 set_type
= type
== isl_dim_in
? isl_dim_set
: type
;
1221 for (i
= 0; i
< pw
->n
; ++i
) {
1222 isl_bool involves
= FN(EL
,involves_dims
)(pw
->p
[i
].FIELD
,
1224 if (involves
< 0 || involves
)
1226 involves
= isl_set_involves_dims(pw
->p
[i
].set
,
1227 set_type
, first
, n
);
1228 if (involves
< 0 || involves
)
1231 return isl_bool_false
;
1234 __isl_give PW
*FN(PW
,set_dim_name
)(__isl_take PW
*pw
,
1235 enum isl_dim_type type
, unsigned pos
, const char *s
)
1238 enum isl_dim_type set_type
;
1240 pw
= FN(PW
,cow
)(pw
);
1244 set_type
= type
== isl_dim_in
? isl_dim_set
: type
;
1246 pw
->dim
= isl_space_set_dim_name(pw
->dim
, type
, pos
, s
);
1250 for (i
= 0; i
< pw
->n
; ++i
) {
1251 pw
->p
[i
].set
= isl_set_set_dim_name(pw
->p
[i
].set
,
1255 pw
->p
[i
].FIELD
= FN(EL
,set_dim_name
)(pw
->p
[i
].FIELD
, type
, pos
, s
);
1256 if (!pw
->p
[i
].FIELD
)
1266 __isl_give PW
*FN(PW
,drop_dims
)(__isl_take PW
*pw
,
1267 enum isl_dim_type type
, unsigned first
, unsigned n
)
1270 enum isl_dim_type set_type
;
1274 if (n
== 0 && !isl_space_get_tuple_name(pw
->dim
, type
))
1277 set_type
= type
== isl_dim_in
? isl_dim_set
: type
;
1279 pw
= FN(PW
,cow
)(pw
);
1282 pw
->dim
= isl_space_drop_dims(pw
->dim
, type
, first
, n
);
1285 for (i
= 0; i
< pw
->n
; ++i
) {
1286 pw
->p
[i
].FIELD
= FN(EL
,drop_dims
)(pw
->p
[i
].FIELD
, type
, first
, n
);
1287 if (!pw
->p
[i
].FIELD
)
1289 if (type
== isl_dim_out
)
1291 pw
->p
[i
].set
= isl_set_drop(pw
->p
[i
].set
, set_type
, first
, n
);
1302 /* This function is very similar to drop_dims.
1303 * The only difference is that the cells may still involve
1304 * the specified dimensions. They are removed using
1305 * isl_set_project_out instead of isl_set_drop.
1307 __isl_give PW
*FN(PW
,project_out
)(__isl_take PW
*pw
,
1308 enum isl_dim_type type
, unsigned first
, unsigned n
)
1311 enum isl_dim_type set_type
;
1315 if (n
== 0 && !isl_space_get_tuple_name(pw
->dim
, type
))
1318 set_type
= type
== isl_dim_in
? isl_dim_set
: type
;
1320 pw
= FN(PW
,cow
)(pw
);
1323 pw
->dim
= isl_space_drop_dims(pw
->dim
, type
, first
, n
);
1326 for (i
= 0; i
< pw
->n
; ++i
) {
1327 pw
->p
[i
].set
= isl_set_project_out(pw
->p
[i
].set
,
1328 set_type
, first
, n
);
1331 pw
->p
[i
].FIELD
= FN(EL
,drop_dims
)(pw
->p
[i
].FIELD
, type
, first
, n
);
1332 if (!pw
->p
[i
].FIELD
)
1342 /* Project the domain of pw onto its parameter space.
1344 __isl_give PW
*FN(PW
,project_domain_on_params
)(__isl_take PW
*pw
)
1349 n
= FN(PW
,dim
)(pw
, isl_dim_in
);
1351 return FN(PW
,free
)(pw
);
1352 pw
= FN(PW
,project_out
)(pw
, isl_dim_in
, 0, n
);
1353 space
= FN(PW
,get_domain_space
)(pw
);
1354 space
= isl_space_params(space
);
1355 pw
= FN(PW
,reset_domain_space
)(pw
, space
);
1359 /* Drop all parameters not referenced by "pw".
1361 __isl_give PW
*FN(PW
,drop_unused_params
)(__isl_take PW
*pw
)
1366 if (FN(PW
,check_named_params
)(pw
) < 0)
1367 return FN(PW
,free
)(pw
);
1369 n
= FN(PW
,dim
)(pw
, isl_dim_param
);
1371 return FN(PW
,free
)(pw
);
1372 for (i
= n
- 1; i
>= 0; i
--) {
1375 involves
= FN(PW
,involves_dims
)(pw
, isl_dim_param
, i
, 1);
1377 return FN(PW
,free
)(pw
);
1379 pw
= FN(PW
,drop_dims
)(pw
, isl_dim_param
, i
, 1);
1385 #ifndef NO_INSERT_DIMS
1386 __isl_give PW
*FN(PW
,insert_dims
)(__isl_take PW
*pw
, enum isl_dim_type type
,
1387 unsigned first
, unsigned n
)
1390 enum isl_dim_type set_type
;
1394 if (n
== 0 && !isl_space_is_named_or_nested(pw
->dim
, type
))
1397 set_type
= type
== isl_dim_in
? isl_dim_set
: type
;
1399 pw
= FN(PW
,cow
)(pw
);
1403 pw
->dim
= isl_space_insert_dims(pw
->dim
, type
, first
, n
);
1407 for (i
= 0; i
< pw
->n
; ++i
) {
1408 pw
->p
[i
].set
= isl_set_insert_dims(pw
->p
[i
].set
,
1409 set_type
, first
, n
);
1412 pw
->p
[i
].FIELD
= FN(EL
,insert_dims
)(pw
->p
[i
].FIELD
,
1414 if (!pw
->p
[i
].FIELD
)
1425 __isl_give PW
*FN(PW
,fix_dim
)(__isl_take PW
*pw
,
1426 enum isl_dim_type type
, unsigned pos
, isl_int v
)
1433 if (type
== isl_dim_in
)
1436 pw
= FN(PW
,cow
)(pw
);
1439 for (i
= 0; i
< pw
->n
; ++i
) {
1440 pw
->p
[i
].set
= isl_set_fix(pw
->p
[i
].set
, type
, pos
, v
);
1441 if (FN(PW
,exploit_equalities_and_remove_if_empty
)(pw
, i
) < 0)
1442 return FN(PW
,free
)(pw
);
1448 /* Fix the value of the variable at position "pos" of type "type" of "pw"
1449 * to be equal to "v".
1451 __isl_give PW
*FN(PW
,fix_val
)(__isl_take PW
*pw
,
1452 enum isl_dim_type type
, unsigned pos
, __isl_take isl_val
*v
)
1455 return FN(PW
,free
)(pw
);
1456 if (!isl_val_is_int(v
))
1457 isl_die(FN(PW
,get_ctx
)(pw
), isl_error_invalid
,
1458 "expecting integer value", goto error
);
1460 pw
= FN(PW
,fix_dim
)(pw
, type
, pos
, v
->n
);
1466 return FN(PW
,free
)(pw
);
1469 isl_size
FN(PW
,dim
)(__isl_keep PW
*pw
, enum isl_dim_type type
)
1471 return isl_space_dim(FN(PW
,peek_space
)(pw
), type
);
1474 __isl_give PW
*FN(PW
,split_dims
)(__isl_take PW
*pw
,
1475 enum isl_dim_type type
, unsigned first
, unsigned n
)
1484 if (type
== isl_dim_in
)
1487 pw
= FN(PW
,cow
)(pw
);
1492 for (i
= 0; i
< pw
->n
; ++i
) {
1493 pw
->p
[i
].set
= isl_set_split_dims(pw
->p
[i
].set
, type
, first
, n
);
1505 /* Compute the maximal value attained by the piecewise quasipolynomial
1506 * on its domain or zero if the domain is empty.
1507 * In the worst case, the domain is scanned completely,
1508 * so the domain is assumed to be bounded.
1510 __isl_give isl_val
*FN(PW
,opt
)(__isl_take PW
*pw
, int max
)
1519 opt
= isl_val_zero(FN(PW
,get_ctx
)(pw
));
1524 opt
= FN(EL
,opt_on_domain
)(FN(EL
,copy
)(pw
->p
[0].FIELD
),
1525 isl_set_copy(pw
->p
[0].set
), max
);
1526 for (i
= 1; i
< pw
->n
; ++i
) {
1528 opt_i
= FN(EL
,opt_on_domain
)(FN(EL
,copy
)(pw
->p
[i
].FIELD
),
1529 isl_set_copy(pw
->p
[i
].set
), max
);
1531 opt
= isl_val_max(opt
, opt_i
);
1533 opt
= isl_val_min(opt
, opt_i
);
1540 __isl_give isl_val
*FN(PW
,max
)(__isl_take PW
*pw
)
1542 return FN(PW
,opt
)(pw
, 1);
1545 __isl_give isl_val
*FN(PW
,min
)(__isl_take PW
*pw
)
1547 return FN(PW
,opt
)(pw
, 0);
1551 /* Return the space of "pw".
1553 __isl_keep isl_space
*FN(PW
,peek_space
)(__isl_keep PW
*pw
)
1555 return pw
? pw
->dim
: NULL
;
1558 __isl_give isl_space
*FN(PW
,get_space
)(__isl_keep PW
*pw
)
1560 return isl_space_copy(FN(PW
,peek_space
)(pw
));
1563 /* Return the space of "pw".
1564 * This may be either a copy or the space itself
1565 * if there is only one reference to "pw".
1566 * This allows the space to be modified inplace
1567 * if both the piecewise expression and its space have only a single reference.
1568 * The caller is not allowed to modify "pw" between this call and
1569 * a subsequent call to isl_pw_*_restore_*.
1570 * The only exception is that isl_pw_*_free can be called instead.
1572 __isl_give isl_space
*FN(PW
,take_space
)(__isl_keep PW
*pw
)
1579 return FN(PW
,get_space
)(pw
);
1585 /* Set the space of "pw" to "space", where the space of "pw" may be missing
1586 * due to a preceding call to isl_pw_*_take_space.
1587 * However, in this case, "pw" only has a single reference and
1588 * then the call to isl_pw_*_cow has no effect.
1590 __isl_give PW
*FN(PW
,restore_space
)(__isl_take PW
*pw
,
1591 __isl_take isl_space
*space
)
1596 if (pw
->dim
== space
) {
1597 isl_space_free(space
);
1601 pw
= FN(PW
,cow
)(pw
);
1604 isl_space_free(pw
->dim
);
1610 isl_space_free(space
);
1614 /* Check that "pos" is a valid position for a cell in "pw".
1616 static isl_stat
FN(PW
,check_pos
)(__isl_keep PW
*pw
, int pos
)
1619 return isl_stat_error
;
1620 if (pos
< 0 || pos
>= pw
->n
)
1621 isl_die(FN(PW
,get_ctx
)(pw
), isl_error_internal
,
1622 "position out of bounds", return isl_stat_error
);
1626 /* Return the cell at position "pos" in "pw".
1628 static __isl_keep isl_set
*FN(PW
,peek_domain_at
)(__isl_keep PW
*pw
, int pos
)
1630 if (FN(PW
,check_pos
)(pw
, pos
) < 0)
1632 return pw
->p
[pos
].set
;
1635 /* Return a copy of the base expression associated to
1636 * the cell at position "pos" in "pw".
1638 __isl_give EL
*FN(PW
,get_base_at
)(__isl_keep PW
*pw
, int pos
)
1640 if (FN(PW
,check_pos
)(pw
, pos
) < 0)
1642 return FN(EL
,copy
)(pw
->p
[pos
].FIELD
);
1645 /* Return the base expression associated to
1646 * the cell at position "pos" in "pw".
1647 * This may be either a copy or the base expression itself
1648 * if there is only one reference to "pw".
1649 * This allows the base expression to be modified inplace
1650 * if both the piecewise expression and this base expression
1651 * have only a single reference.
1652 * The caller is not allowed to modify "pw" between this call and
1653 * a subsequent call to isl_pw_*_restore_*.
1654 * The only exception is that isl_pw_*_free can be called instead.
1656 __isl_give EL
*FN(PW
,take_base_at
)(__isl_keep PW
*pw
, int pos
)
1663 return FN(PW
,get_base_at
)(pw
, pos
);
1664 if (FN(PW
,check_pos
)(pw
, pos
) < 0)
1666 el
= pw
->p
[pos
].FIELD
;
1667 pw
->p
[pos
].FIELD
= NULL
;
1671 /* Set the base expression associated to
1672 * the cell at position "pos" in "pw" to "el",
1673 * where this base expression may be missing
1674 * due to a preceding call to isl_pw_*_take_base_at.
1675 * However, in this case, "pw" only has a single reference and
1676 * then the call to isl_pw_*_cow has no effect.
1678 __isl_give PW
*FN(PW
,restore_base_at
)(__isl_take PW
*pw
, int pos
,
1681 if (FN(PW
,check_pos
)(pw
, pos
) < 0 || !el
)
1684 if (pw
->p
[pos
].FIELD
== el
) {
1689 pw
= FN(PW
,cow
)(pw
);
1692 FN(EL
,free
)(pw
->p
[pos
].FIELD
);
1693 pw
->p
[pos
].FIELD
= el
;
1702 __isl_give isl_space
*FN(PW
,get_domain_space
)(__isl_keep PW
*pw
)
1704 return pw
? isl_space_domain(isl_space_copy(pw
->dim
)) : NULL
;
1707 /* Return the position of the dimension of the given type and name
1709 * Return -1 if no such dimension can be found.
1711 int FN(PW
,find_dim_by_name
)(__isl_keep PW
*pw
,
1712 enum isl_dim_type type
, const char *name
)
1716 return isl_space_find_dim_by_name(pw
->dim
, type
, name
);
1719 /* Return the position of the dimension of the given type and identifier
1721 * Return -1 if no such dimension can be found.
1723 static int FN(PW
,find_dim_by_id
)(__isl_keep PW
*pw
,
1724 enum isl_dim_type type
, __isl_keep isl_id
*id
)
1728 space
= FN(PW
,peek_space
)(pw
);
1729 return isl_space_find_dim_by_id(space
, type
, id
);
1732 /* Does the piecewise expression "pw" depend in any way
1733 * on the parameter with identifier "id"?
1735 isl_bool
FN(PW
,involves_param_id
)(__isl_keep PW
*pw
, __isl_keep isl_id
*id
)
1740 return isl_bool_error
;
1742 return isl_bool_false
;
1744 pos
= FN(PW
,find_dim_by_id
)(pw
, isl_dim_param
, id
);
1746 return isl_bool_false
;
1747 return FN(PW
,involves_dims
)(pw
, isl_dim_param
, pos
, 1);
1750 #ifndef NO_RESET_DIM
1751 /* Reset the space of "pw". Since we don't know if the elements
1752 * represent the spaces themselves or their domains, we pass along
1753 * both when we call their reset_space_and_domain.
1755 static __isl_give PW
*FN(PW
,reset_space_and_domain
)(__isl_take PW
*pw
,
1756 __isl_take isl_space
*space
, __isl_take isl_space
*domain
)
1760 pw
= FN(PW
,cow
)(pw
);
1761 if (!pw
|| !space
|| !domain
)
1764 for (i
= 0; i
< pw
->n
; ++i
) {
1765 pw
->p
[i
].set
= isl_set_reset_space(pw
->p
[i
].set
,
1766 isl_space_copy(domain
));
1769 pw
->p
[i
].FIELD
= FN(EL
,reset_space_and_domain
)(pw
->p
[i
].FIELD
,
1770 isl_space_copy(space
), isl_space_copy(domain
));
1771 if (!pw
->p
[i
].FIELD
)
1775 isl_space_free(domain
);
1777 isl_space_free(pw
->dim
);
1782 isl_space_free(domain
);
1783 isl_space_free(space
);
1788 __isl_give PW
*FN(PW
,reset_domain_space
)(__isl_take PW
*pw
,
1789 __isl_take isl_space
*domain
)
1793 space
= isl_space_extend_domain_with_range(isl_space_copy(domain
),
1794 FN(PW
,get_space
)(pw
));
1795 return FN(PW
,reset_space_and_domain
)(pw
, space
, domain
);
1798 __isl_give PW
*FN(PW
,reset_space
)(__isl_take PW
*pw
, __isl_take isl_space
*dim
)
1802 domain
= isl_space_domain(isl_space_copy(dim
));
1803 return FN(PW
,reset_space_and_domain
)(pw
, dim
, domain
);
1806 __isl_give PW
*FN(PW
,set_tuple_id
)(__isl_take PW
*pw
, enum isl_dim_type type
,
1807 __isl_take isl_id
*id
)
1811 pw
= FN(PW
,cow
)(pw
);
1815 space
= FN(PW
,get_space
)(pw
);
1816 space
= isl_space_set_tuple_id(space
, type
, id
);
1818 return FN(PW
,reset_space
)(pw
, space
);
1821 return FN(PW
,free
)(pw
);
1824 /* Drop the id on the specified tuple.
1826 __isl_give PW
*FN(PW
,reset_tuple_id
)(__isl_take PW
*pw
, enum isl_dim_type type
)
1832 if (!FN(PW
,has_tuple_id
)(pw
, type
))
1835 pw
= FN(PW
,cow
)(pw
);
1839 space
= FN(PW
,get_space
)(pw
);
1840 space
= isl_space_reset_tuple_id(space
, type
);
1842 return FN(PW
,reset_space
)(pw
, space
);
1845 __isl_give PW
*FN(PW
,set_dim_id
)(__isl_take PW
*pw
,
1846 enum isl_dim_type type
, unsigned pos
, __isl_take isl_id
*id
)
1848 pw
= FN(PW
,cow
)(pw
);
1851 pw
->dim
= isl_space_set_dim_id(pw
->dim
, type
, pos
, id
);
1852 return FN(PW
,reset_space
)(pw
, isl_space_copy(pw
->dim
));
1855 return FN(PW
,free
)(pw
);
1859 /* Reset the user pointer on all identifiers of parameters and tuples
1860 * of the space of "pw".
1862 __isl_give PW
*FN(PW
,reset_user
)(__isl_take PW
*pw
)
1866 space
= FN(PW
,get_space
)(pw
);
1867 space
= isl_space_reset_user(space
);
1869 return FN(PW
,reset_space
)(pw
, space
);
1872 isl_bool
FN(PW
,has_equal_space
)(__isl_keep PW
*pw1
, __isl_keep PW
*pw2
)
1875 return isl_bool_error
;
1877 return isl_space_is_equal(pw1
->dim
, pw2
->dim
);
1880 isl_size
FN(PW
,n_piece
)(__isl_keep PW
*pw
)
1882 return pw
? pw
->n
: isl_size_error
;
1885 isl_stat
FN(PW
,foreach_piece
)(__isl_keep PW
*pw
,
1886 isl_stat (*fn
)(__isl_take isl_set
*set
, __isl_take EL
*el
, void *user
),
1892 return isl_stat_error
;
1894 for (i
= 0; i
< pw
->n
; ++i
)
1895 if (fn(isl_set_copy(pw
->p
[i
].set
),
1896 FN(EL
,copy
)(pw
->p
[i
].FIELD
), user
) < 0)
1897 return isl_stat_error
;
1902 /* Is "pw" defined over a single universe domain?
1904 * If the default value of this piecewise type is zero,
1905 * then a "pw" with a zero number of cells is also accepted
1906 * as it represents the default zero value.
1908 isl_bool
FN(FN(PW
,isa
),BASE
)(__isl_keep PW
*pw
)
1912 n
= FN(PW
,n_piece
)(pw
);
1914 return isl_bool_error
;
1915 if (DEFAULT_IS_ZERO
&& n
== 0)
1916 return isl_bool_true
;
1918 return isl_bool_false
;
1919 return isl_set_plain_is_universe(FN(PW
,peek_domain_at
)(pw
, 0));
1922 /* Return a zero base expression in the same space (and of the same type)
1925 static __isl_give EL
*FN(EL
,zero_like_type
)(__isl_take PW
*pw OPT_TYPE_PARAM
)
1929 space
= FN(PW
,get_space
)(pw
);
1931 return FN(EL
,zero_in_space
)(space
OPT_TYPE_ARG(NO_LOC
));
1935 /* Return a zero base expression in the same space as "pw".
1937 static __isl_give EL
*FN(EL
,zero_like
)(__isl_take PW
*pw
)
1939 return FN(EL
,zero_like_type
)(pw
);
1942 /* Return a zero base expression in the same space and of the same type
1945 * Pass along the type as an explicit argument for uniform handling
1946 * in isl_*_zero_like_type.
1948 static __isl_give EL
*FN(EL
,zero_like
)(__isl_take PW
*pw
)
1952 type
= FN(PW
,get_type
)(pw
);
1955 return FN(EL
,zero_like_type
)(pw
, type
);
1962 /* Given that "pw" is defined over a single universe domain,
1963 * return the base expression associated to this domain.
1965 * If the number of cells is zero, then "pw" is of a piecewise type
1966 * with a default zero value and effectively represents zero.
1967 * In this case, create a zero base expression in the same space
1968 * (and with the same type).
1969 * Otherwise, simply extract the associated base expression.
1971 __isl_give EL
*FN(FN(PW
,as
),BASE
)(__isl_take PW
*pw
)
1977 is_total
= FN(FN(PW
,isa
),BASE
)(pw
);
1981 isl_die(FN(PW
,get_ctx
)(pw
), isl_error_invalid
,
1982 "expecting single total function", goto error
);
1983 n
= FN(PW
,n_piece
)(pw
);
1987 return FN(EL
,zero_like
)(pw
);
1988 el
= FN(PW
,take_base_at
)(pw
, 0);
1997 static isl_bool
any_divs(__isl_keep isl_set
*set
)
2002 return isl_bool_error
;
2004 for (i
= 0; i
< set
->n
; ++i
)
2005 if (set
->p
[i
]->n_div
> 0)
2006 return isl_bool_true
;
2008 return isl_bool_false
;
2011 static isl_stat
foreach_lifted_subset(__isl_take isl_set
*set
,
2013 isl_stat (*fn
)(__isl_take isl_set
*set
, __isl_take EL
*el
,
2014 void *user
), void *user
)
2021 for (i
= 0; i
< set
->n
; ++i
) {
2025 lift
= isl_set_from_basic_set(isl_basic_set_copy(set
->p
[i
]));
2026 lift
= isl_set_lift(lift
);
2028 copy
= FN(EL
,copy
)(el
);
2029 copy
= FN(EL
,lift
)(copy
, isl_set_get_space(lift
));
2031 if (fn(lift
, copy
, user
) < 0)
2042 return isl_stat_error
;
2045 isl_stat
FN(PW
,foreach_lifted_piece
)(__isl_keep PW
*pw
,
2046 isl_stat (*fn
)(__isl_take isl_set
*set
, __isl_take EL
*el
,
2047 void *user
), void *user
)
2052 return isl_stat_error
;
2054 for (i
= 0; i
< pw
->n
; ++i
) {
2059 any
= any_divs(pw
->p
[i
].set
);
2061 return isl_stat_error
;
2062 set
= isl_set_copy(pw
->p
[i
].set
);
2063 el
= FN(EL
,copy
)(pw
->p
[i
].FIELD
);
2065 if (fn(set
, el
, user
) < 0)
2066 return isl_stat_error
;
2069 if (foreach_lifted_subset(set
, el
, fn
, user
) < 0)
2070 return isl_stat_error
;
2077 #ifndef NO_MOVE_DIMS
2078 __isl_give PW
*FN(PW
,move_dims
)(__isl_take PW
*pw
,
2079 enum isl_dim_type dst_type
, unsigned dst_pos
,
2080 enum isl_dim_type src_type
, unsigned src_pos
, unsigned n
)
2084 pw
= FN(PW
,cow
)(pw
);
2088 pw
->dim
= isl_space_move_dims(pw
->dim
, dst_type
, dst_pos
, src_type
, src_pos
, n
);
2092 for (i
= 0; i
< pw
->n
; ++i
) {
2093 pw
->p
[i
].FIELD
= FN(EL
,move_dims
)(pw
->p
[i
].FIELD
,
2094 dst_type
, dst_pos
, src_type
, src_pos
, n
);
2095 if (!pw
->p
[i
].FIELD
)
2099 if (dst_type
== isl_dim_in
)
2100 dst_type
= isl_dim_set
;
2101 if (src_type
== isl_dim_in
)
2102 src_type
= isl_dim_set
;
2104 for (i
= 0; i
< pw
->n
; ++i
) {
2105 pw
->p
[i
].set
= isl_set_move_dims(pw
->p
[i
].set
,
2107 src_type
, src_pos
, n
);
2120 /* Negate the type of "pw".
2122 static __isl_give PW
*FN(PW
,negate_type
)(__isl_take PW
*pw
)
2124 pw
= FN(PW
,cow
)(pw
);
2127 pw
->type
= isl_fold_type_negate(pw
->type
);
2131 /* Negate the type of "pw".
2132 * Since "pw" does not have a type, do nothing.
2134 static __isl_give PW
*FN(PW
,negate_type
)(__isl_take PW
*pw
)
2140 __isl_give PW
*FN(PW
,mul_isl_int
)(__isl_take PW
*pw
, isl_int v
)
2144 if (isl_int_is_one(v
))
2146 if (pw
&& DEFAULT_IS_ZERO
&& isl_int_is_zero(v
)) {
2148 isl_space
*dim
= FN(PW
,get_space
)(pw
);
2149 zero
= FN(PW
,ZERO
)(dim
OPT_TYPE_ARG(pw
->));
2153 pw
= FN(PW
,cow
)(pw
);
2154 if (isl_int_is_neg(v
))
2155 pw
= FN(PW
,negate_type
)(pw
);
2161 for (i
= 0; i
< pw
->n
; ++i
) {
2162 pw
->p
[i
].FIELD
= FN(EL
,scale
)(pw
->p
[i
].FIELD
, v
);
2163 if (!pw
->p
[i
].FIELD
)
2173 /* Multiply the pieces of "pw" by "v" and return the result.
2175 __isl_give PW
*FN(PW
,scale_val
)(__isl_take PW
*pw
, __isl_take isl_val
*v
)
2182 if (isl_val_is_one(v
)) {
2186 if (pw
&& DEFAULT_IS_ZERO
&& isl_val_is_zero(v
)) {
2188 isl_space
*space
= FN(PW
,get_space
)(pw
);
2189 zero
= FN(PW
,ZERO
)(space
OPT_TYPE_ARG(pw
->));
2198 pw
= FN(PW
,cow
)(pw
);
2199 if (isl_val_is_neg(v
))
2200 pw
= FN(PW
,negate_type
)(pw
);
2204 for (i
= 0; i
< pw
->n
; ++i
) {
2205 pw
->p
[i
].FIELD
= FN(EL
,scale_val
)(pw
->p
[i
].FIELD
,
2207 if (!pw
->p
[i
].FIELD
)
2219 /* Divide the pieces of "pw" by "v" and return the result.
2221 __isl_give PW
*FN(PW
,scale_down_val
)(__isl_take PW
*pw
, __isl_take isl_val
*v
)
2228 if (isl_val_is_one(v
)) {
2233 if (!isl_val_is_rat(v
))
2234 isl_die(isl_val_get_ctx(v
), isl_error_invalid
,
2235 "expecting rational factor", goto error
);
2236 if (isl_val_is_zero(v
))
2237 isl_die(isl_val_get_ctx(v
), isl_error_invalid
,
2238 "cannot scale down by zero", goto error
);
2244 pw
= FN(PW
,cow
)(pw
);
2245 if (isl_val_is_neg(v
))
2246 pw
= FN(PW
,negate_type
)(pw
);
2250 for (i
= 0; i
< pw
->n
; ++i
) {
2251 pw
->p
[i
].FIELD
= FN(EL
,scale_down_val
)(pw
->p
[i
].FIELD
,
2253 if (!pw
->p
[i
].FIELD
)
2265 __isl_give PW
*FN(PW
,scale
)(__isl_take PW
*pw
, isl_int v
)
2267 return FN(PW
,mul_isl_int
)(pw
, v
);
2270 /* Apply some normalization to "pw".
2271 * In particular, sort the pieces according to their function value
2272 * expressions, combining pairs of adjacent pieces with
2273 * the same such expression, and then normalize the domains of the pieces.
2275 * We normalize in place, but if anything goes wrong we need
2276 * to return NULL, so we need to make sure we don't change the
2277 * meaning of any possible other copies of "pw".
2279 __isl_give PW
*FN(PW
,normalize
)(__isl_take PW
*pw
)
2284 pw
= FN(PW
,sort
)(pw
);
2287 for (i
= 0; i
< pw
->n
; ++i
) {
2288 set
= isl_set_normalize(isl_set_copy(pw
->p
[i
].set
));
2290 return FN(PW
,free
)(pw
);
2291 isl_set_free(pw
->p
[i
].set
);
2298 /* Is pw1 obviously equal to pw2?
2299 * That is, do they have obviously identical cells and obviously identical
2300 * elements on each cell?
2302 * If "pw1" or "pw2" contain any NaNs, then they are considered
2303 * not to be the same. A NaN is not equal to anything, not even
2306 isl_bool
FN(PW
,plain_is_equal
)(__isl_keep PW
*pw1
, __isl_keep PW
*pw2
)
2309 isl_bool equal
, has_nan
;
2312 return isl_bool_error
;
2314 has_nan
= FN(PW
,involves_nan
)(pw1
);
2315 if (has_nan
>= 0 && !has_nan
)
2316 has_nan
= FN(PW
,involves_nan
)(pw2
);
2317 if (has_nan
< 0 || has_nan
)
2318 return isl_bool_not(has_nan
);
2321 return isl_bool_true
;
2322 if (!isl_space_is_equal(pw1
->dim
, pw2
->dim
))
2323 return isl_bool_false
;
2325 pw1
= FN(PW
,copy
)(pw1
);
2326 pw2
= FN(PW
,copy
)(pw2
);
2327 pw1
= FN(PW
,normalize
)(pw1
);
2328 pw2
= FN(PW
,normalize
)(pw2
);
2332 equal
= isl_bool_ok(pw1
->n
== pw2
->n
);
2333 for (i
= 0; equal
&& i
< pw1
->n
; ++i
) {
2334 equal
= isl_set_plain_is_equal(pw1
->p
[i
].set
, pw2
->p
[i
].set
);
2339 equal
= FN(EL
,plain_is_equal
)(pw1
->p
[i
].FIELD
, pw2
->p
[i
].FIELD
);
2350 return isl_bool_error
;
2353 /* Does "pw" involve any NaNs?
2355 isl_bool
FN(PW
,involves_nan
)(__isl_keep PW
*pw
)
2360 return isl_bool_error
;
2362 return isl_bool_false
;
2364 for (i
= 0; i
< pw
->n
; ++i
) {
2365 isl_bool has_nan
= FN(EL
,involves_nan
)(pw
->p
[i
].FIELD
);
2366 if (has_nan
< 0 || has_nan
)
2370 return isl_bool_false
;
2374 static __isl_give PW
*FN(PW
,align_params_pw_multi_aff_and
)(__isl_take PW
*pw
,
2375 __isl_take isl_multi_aff
*ma
,
2376 __isl_give PW
*(*fn
)(__isl_take PW
*pw
, __isl_take isl_multi_aff
*ma
))
2379 isl_bool equal_params
;
2380 isl_space
*ma_space
;
2382 ma_space
= isl_multi_aff_get_space(ma
);
2383 if (!pw
|| !ma
|| !ma_space
)
2385 equal_params
= isl_space_has_equal_params(pw
->dim
, ma_space
);
2386 if (equal_params
< 0)
2389 isl_space_free(ma_space
);
2392 ctx
= FN(PW
,get_ctx
)(pw
);
2393 if (FN(PW
,check_named_params
)(pw
) < 0)
2395 if (!isl_space_has_named_params(ma_space
))
2396 isl_die(ctx
, isl_error_invalid
,
2397 "unaligned unnamed parameters", goto error
);
2398 pw
= FN(PW
,align_params
)(pw
, ma_space
);
2399 ma
= isl_multi_aff_align_params(ma
, FN(PW
,get_space
)(pw
));
2402 isl_space_free(ma_space
);
2404 isl_multi_aff_free(ma
);
2408 static __isl_give PW
*FN(PW
,align_params_pw_pw_multi_aff_and
)(__isl_take PW
*pw
,
2409 __isl_take isl_pw_multi_aff
*pma
,
2410 __isl_give PW
*(*fn
)(__isl_take PW
*pw
,
2411 __isl_take isl_pw_multi_aff
*ma
))
2413 isl_bool equal_params
;
2414 isl_space
*pma_space
;
2416 pma_space
= isl_pw_multi_aff_get_space(pma
);
2417 if (!pw
|| !pma
|| !pma_space
)
2419 equal_params
= isl_space_has_equal_params(pw
->dim
, pma_space
);
2420 if (equal_params
< 0)
2423 isl_space_free(pma_space
);
2426 if (FN(PW
,check_named_params
)(pw
) < 0 ||
2427 isl_pw_multi_aff_check_named_params(pma
) < 0)
2429 pw
= FN(PW
,align_params
)(pw
, pma_space
);
2430 pma
= isl_pw_multi_aff_align_params(pma
, FN(PW
,get_space
)(pw
));
2433 isl_space_free(pma_space
);
2435 isl_pw_multi_aff_free(pma
);
2439 /* Compute the pullback of "pw" by the function represented by "ma".
2440 * In other words, plug in "ma" in "pw".
2442 static __isl_give PW
*FN(PW
,pullback_multi_aff_aligned
)(__isl_take PW
*pw
,
2443 __isl_take isl_multi_aff
*ma
)
2446 isl_space
*space
= NULL
;
2448 ma
= isl_multi_aff_align_divs(ma
);
2449 pw
= FN(PW
,cow
)(pw
);
2453 space
= isl_space_join(isl_multi_aff_get_space(ma
),
2454 FN(PW
,get_space
)(pw
));
2456 for (i
= 0; i
< pw
->n
; ++i
) {
2457 pw
->p
[i
].set
= isl_set_preimage_multi_aff(pw
->p
[i
].set
,
2458 isl_multi_aff_copy(ma
));
2461 pw
->p
[i
].FIELD
= FN(EL
,pullback_multi_aff
)(pw
->p
[i
].FIELD
,
2462 isl_multi_aff_copy(ma
));
2463 if (!pw
->p
[i
].FIELD
)
2467 pw
= FN(PW
,reset_space
)(pw
, space
);
2468 isl_multi_aff_free(ma
);
2471 isl_space_free(space
);
2472 isl_multi_aff_free(ma
);
2477 __isl_give PW
*FN(PW
,pullback_multi_aff
)(__isl_take PW
*pw
,
2478 __isl_take isl_multi_aff
*ma
)
2480 return FN(PW
,align_params_pw_multi_aff_and
)(pw
, ma
,
2481 &FN(PW
,pullback_multi_aff_aligned
));
2484 /* Compute the pullback of "pw" by the function represented by "pma".
2485 * In other words, plug in "pma" in "pw".
2487 static __isl_give PW
*FN(PW
,pullback_pw_multi_aff_aligned
)(__isl_take PW
*pw
,
2488 __isl_take isl_pw_multi_aff
*pma
)
2498 space
= isl_space_join(isl_pw_multi_aff_get_space(pma
),
2499 FN(PW
,get_space
)(pw
));
2500 isl_pw_multi_aff_free(pma
);
2501 res
= FN(PW
,empty
)(space
);
2506 res
= FN(PW
,pullback_multi_aff
)(FN(PW
,copy
)(pw
),
2507 isl_multi_aff_copy(pma
->p
[0].maff
));
2508 res
= FN(PW
,intersect_domain
)(res
, isl_set_copy(pma
->p
[0].set
));
2510 for (i
= 1; i
< pma
->n
; ++i
) {
2513 res_i
= FN(PW
,pullback_multi_aff
)(FN(PW
,copy
)(pw
),
2514 isl_multi_aff_copy(pma
->p
[i
].maff
));
2515 res_i
= FN(PW
,intersect_domain
)(res_i
,
2516 isl_set_copy(pma
->p
[i
].set
));
2517 res
= FN(PW
,add_disjoint
)(res
, res_i
);
2520 isl_pw_multi_aff_free(pma
);
2524 isl_pw_multi_aff_free(pma
);
2529 __isl_give PW
*FN(PW
,pullback_pw_multi_aff
)(__isl_take PW
*pw
,
2530 __isl_take isl_pw_multi_aff
*pma
)
2532 return FN(PW
,align_params_pw_pw_multi_aff_and
)(pw
, pma
,
2533 &FN(PW
,pullback_pw_multi_aff_aligned
));