2 * Copyright 2011 Sven Verdoolaege
3 * Copyright 2012-2013 Ecole Normale Superieure
5 * Use of this software is governed by the MIT license
7 * Written by Sven Verdoolaege,
8 * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
11 #include <isl_space_private.h>
13 #include <isl_reordering.h>
15 #include <isl_multi_macro.h>
17 #define MULTI_NAME(BASE) "isl_multi_" #BASE
18 #define xLIST(EL) EL ## _list
19 #define LIST(EL) xLIST(EL)
21 isl_ctx
*FN(MULTI(BASE
),get_ctx
)(__isl_keep
MULTI(BASE
) *multi
)
23 return multi
? isl_space_get_ctx(multi
->space
) : NULL
;
26 __isl_give isl_space
*FN(MULTI(BASE
),get_space
)(__isl_keep
MULTI(BASE
) *multi
)
28 return multi
? isl_space_copy(multi
->space
) : NULL
;
31 /* Return the position of the dimension of the given type and name
33 * Return -1 if no such dimension can be found.
35 int FN(MULTI(BASE
),find_dim_by_name
)(__isl_keep
MULTI(BASE
) *multi
,
36 enum isl_dim_type type
, const char *name
)
40 return isl_space_find_dim_by_name(multi
->space
, type
, name
);
43 __isl_give isl_space
*FN(MULTI(BASE
),get_domain_space
)(
44 __isl_keep
MULTI(BASE
) *multi
)
46 return multi
? isl_space_domain(isl_space_copy(multi
->space
)) : NULL
;
49 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),alloc
)(__isl_take isl_space
*space
)
58 ctx
= isl_space_get_ctx(space
);
59 n
= isl_space_dim(space
, isl_dim_out
);
60 multi
= isl_calloc(ctx
, MULTI(BASE
),
61 sizeof(MULTI(BASE
)) + (n
- 1) * sizeof(struct EL
*));
70 isl_space_free(space
);
74 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),dup
)(__isl_keep
MULTI(BASE
) *multi
)
82 dup
= FN(MULTI(BASE
),alloc
)(isl_space_copy(multi
->space
));
86 for (i
= 0; i
< multi
->n
; ++i
)
87 dup
= FN(FN(MULTI(BASE
),set
),BASE
)(dup
, i
,
88 FN(EL
,copy
)(multi
->p
[i
]));
93 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),cow
)(__isl_take
MULTI(BASE
) *multi
)
102 return FN(MULTI(BASE
),dup
)(multi
);
105 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),copy
)(__isl_keep
MULTI(BASE
) *multi
)
114 __isl_null
MULTI(BASE
) *FN(MULTI(BASE
),free
)(__isl_take
MULTI(BASE
) *multi
)
121 if (--multi
->ref
> 0)
124 isl_space_free(multi
->space
);
125 for (i
= 0; i
< multi
->n
; ++i
)
126 FN(EL
,free
)(multi
->p
[i
]);
132 /* Check whether "multi" has non-zero coefficients for any dimension
133 * in the given range or if any of these dimensions appear
134 * with non-zero coefficients in any of the integer divisions involved.
136 int FN(MULTI(BASE
),involves_dims
)(__isl_keep
MULTI(BASE
) *multi
,
137 enum isl_dim_type type
, unsigned first
, unsigned n
)
143 if (multi
->n
== 0 || n
== 0)
146 for (i
= 0; i
< multi
->n
; ++i
) {
149 involves
= FN(EL
,involves_dims
)(multi
->p
[i
], type
, first
, n
);
150 if (involves
< 0 || involves
)
157 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),insert_dims
)(
158 __isl_take
MULTI(BASE
) *multi
,
159 enum isl_dim_type type
, unsigned first
, unsigned n
)
165 if (type
== isl_dim_out
)
166 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
167 "cannot insert output/set dimensions",
168 return FN(MULTI(BASE
),free
)(multi
));
169 if (n
== 0 && !isl_space_is_named_or_nested(multi
->space
, type
))
172 multi
= FN(MULTI(BASE
),cow
)(multi
);
176 multi
->space
= isl_space_insert_dims(multi
->space
, type
, first
, n
);
178 return FN(MULTI(BASE
),free
)(multi
);
180 for (i
= 0; i
< multi
->n
; ++i
) {
181 multi
->p
[i
] = FN(EL
,insert_dims
)(multi
->p
[i
], type
, first
, n
);
183 return FN(MULTI(BASE
),free
)(multi
);
189 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),add_dims
)(__isl_take
MULTI(BASE
) *multi
,
190 enum isl_dim_type type
, unsigned n
)
194 pos
= FN(MULTI(BASE
),dim
)(multi
, type
);
196 return FN(MULTI(BASE
),insert_dims
)(multi
, type
, pos
, n
);
199 unsigned FN(MULTI(BASE
),dim
)(__isl_keep
MULTI(BASE
) *multi
,
200 enum isl_dim_type type
)
202 return multi
? isl_space_dim(multi
->space
, type
) : 0;
205 /* Return the position of the first dimension of "type" with id "id".
206 * Return -1 if there is no such dimension.
208 int FN(MULTI(BASE
),find_dim_by_id
)(__isl_keep
MULTI(BASE
) *multi
,
209 enum isl_dim_type type
, __isl_keep isl_id
*id
)
213 return isl_space_find_dim_by_id(multi
->space
, type
, id
);
216 /* Return the id of the given dimension.
218 __isl_give isl_id
*FN(MULTI(BASE
),get_dim_id
)(__isl_keep
MULTI(BASE
) *multi
,
219 enum isl_dim_type type
, unsigned pos
)
221 return multi
? isl_space_get_dim_id(multi
->space
, type
, pos
) : NULL
;
224 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),set_dim_name
)(
225 __isl_take
MULTI(BASE
) *multi
,
226 enum isl_dim_type type
, unsigned pos
, const char *s
)
230 multi
= FN(MULTI(BASE
),cow
)(multi
);
234 multi
->space
= isl_space_set_dim_name(multi
->space
, type
, pos
, s
);
236 return FN(MULTI(BASE
),free
)(multi
);
238 if (type
== isl_dim_out
)
240 for (i
= 0; i
< multi
->n
; ++i
) {
241 multi
->p
[i
] = FN(EL
,set_dim_name
)(multi
->p
[i
], type
, pos
, s
);
243 return FN(MULTI(BASE
),free
)(multi
);
249 const char *FN(MULTI(BASE
),get_tuple_name
)(__isl_keep
MULTI(BASE
) *multi
,
250 enum isl_dim_type type
)
252 return multi
? isl_space_get_tuple_name(multi
->space
, type
) : NULL
;
255 /* Does the specified tuple have an id?
257 int FN(MULTI(BASE
),has_tuple_id
)(__isl_keep
MULTI(BASE
) *multi
,
258 enum isl_dim_type type
)
260 return multi
? isl_space_has_tuple_id(multi
->space
, type
) : -1;
263 /* Return the id of the specified tuple.
265 __isl_give isl_id
*FN(MULTI(BASE
),get_tuple_id
)(__isl_keep
MULTI(BASE
) *multi
,
266 enum isl_dim_type type
)
268 return multi
? isl_space_get_tuple_id(multi
->space
, type
) : NULL
;
271 __isl_give EL
*FN(FN(MULTI(BASE
),get
),BASE
)(__isl_keep
MULTI(BASE
) *multi
,
278 ctx
= FN(MULTI(BASE
),get_ctx
)(multi
);
279 if (pos
< 0 || pos
>= multi
->n
)
280 isl_die(ctx
, isl_error_invalid
,
281 "index out of bounds", return NULL
);
282 return FN(EL
,copy
)(multi
->p
[pos
]);
285 __isl_give
MULTI(BASE
) *FN(FN(MULTI(BASE
),set
),BASE
)(
286 __isl_take
MULTI(BASE
) *multi
, int pos
, __isl_take EL
*el
)
288 isl_space
*multi_space
= NULL
;
289 isl_space
*el_space
= NULL
;
292 multi
= FN(MULTI(BASE
),cow
)(multi
);
296 multi_space
= FN(MULTI(BASE
),get_space
)(multi
);
297 match
= FN(EL
,matching_params
)(el
, multi_space
);
301 multi
= FN(MULTI(BASE
),align_params
)(multi
,
302 FN(EL
,get_space
)(el
));
303 isl_space_free(multi_space
);
304 multi_space
= FN(MULTI(BASE
),get_space
)(multi
);
305 el
= FN(EL
,align_params
)(el
, isl_space_copy(multi_space
));
307 if (FN(EL
,check_match_domain_space
)(el
, multi_space
) < 0)
310 if (pos
< 0 || pos
>= multi
->n
)
311 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
312 "index out of bounds", goto error
);
314 FN(EL
,free
)(multi
->p
[pos
]);
317 isl_space_free(multi_space
);
318 isl_space_free(el_space
);
322 FN(MULTI(BASE
),free
)(multi
);
324 isl_space_free(multi_space
);
325 isl_space_free(el_space
);
329 /* Reset the space of "multi". This function is called from isl_pw_templ.c
330 * and doesn't know if the space of an element object is represented
331 * directly or through its domain. It therefore passes along both,
332 * which we pass along to the element function since we don't how
333 * that is represented either.
335 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_space_and_domain
)(
336 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_space
*space
,
337 __isl_take isl_space
*domain
)
341 multi
= FN(MULTI(BASE
),cow
)(multi
);
342 if (!multi
|| !space
|| !domain
)
345 for (i
= 0; i
< multi
->n
; ++i
) {
346 multi
->p
[i
] = FN(EL
,reset_domain_space
)(multi
->p
[i
],
347 isl_space_copy(domain
));
351 isl_space_free(domain
);
352 isl_space_free(multi
->space
);
353 multi
->space
= space
;
357 isl_space_free(domain
);
358 isl_space_free(space
);
359 FN(MULTI(BASE
),free
)(multi
);
363 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_domain_space
)(
364 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_space
*domain
)
368 space
= isl_space_extend_domain_with_range(isl_space_copy(domain
),
369 isl_space_copy(multi
->space
));
370 return FN(MULTI(BASE
),reset_space_and_domain
)(multi
, space
, domain
);
373 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_space
)(
374 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_space
*space
)
378 domain
= isl_space_domain(isl_space_copy(space
));
379 return FN(MULTI(BASE
),reset_space_and_domain
)(multi
, space
, domain
);
382 /* Set the id of the given dimension of "multi" to "id".
384 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),set_dim_id
)(
385 __isl_take
MULTI(BASE
) *multi
,
386 enum isl_dim_type type
, unsigned pos
, __isl_take isl_id
*id
)
390 multi
= FN(MULTI(BASE
),cow
)(multi
);
394 space
= FN(MULTI(BASE
),get_space
)(multi
);
395 space
= isl_space_set_dim_id(space
, type
, pos
, id
);
397 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
400 FN(MULTI(BASE
),free
)(multi
);
404 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),set_tuple_name
)(
405 __isl_keep
MULTI(BASE
) *multi
, enum isl_dim_type type
,
410 multi
= FN(MULTI(BASE
),cow
)(multi
);
414 space
= FN(MULTI(BASE
),get_space
)(multi
);
415 space
= isl_space_set_tuple_name(space
, type
, s
);
417 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
420 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),set_tuple_id
)(
421 __isl_take
MULTI(BASE
) *multi
, enum isl_dim_type type
,
422 __isl_take isl_id
*id
)
426 multi
= FN(MULTI(BASE
),cow
)(multi
);
430 space
= FN(MULTI(BASE
),get_space
)(multi
);
431 space
= isl_space_set_tuple_id(space
, type
, id
);
433 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
439 /* Drop the id on the specified tuple.
441 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_tuple_id
)(
442 __isl_take
MULTI(BASE
) *multi
, enum isl_dim_type type
)
448 if (!FN(MULTI(BASE
),has_tuple_id
)(multi
, type
))
451 multi
= FN(MULTI(BASE
),cow
)(multi
);
455 space
= FN(MULTI(BASE
),get_space
)(multi
);
456 space
= isl_space_reset_tuple_id(space
, type
);
458 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
461 /* Reset the user pointer on all identifiers of parameters and tuples
462 * of the space of "multi".
464 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_user
)(
465 __isl_take
MULTI(BASE
) *multi
)
469 space
= FN(MULTI(BASE
),get_space
)(multi
);
470 space
= isl_space_reset_user(space
);
472 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
475 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),realign_domain
)(
476 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_reordering
*exp
)
480 multi
= FN(MULTI(BASE
),cow
)(multi
);
484 for (i
= 0; i
< multi
->n
; ++i
) {
485 multi
->p
[i
] = FN(EL
,realign_domain
)(multi
->p
[i
],
486 isl_reordering_copy(exp
));
491 multi
= FN(MULTI(BASE
),reset_domain_space
)(multi
,
492 isl_space_copy(exp
->dim
));
494 isl_reordering_free(exp
);
497 isl_reordering_free(exp
);
498 FN(MULTI(BASE
),free
)(multi
);
502 /* Align the parameters of "multi" to those of "model".
504 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),align_params
)(
505 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_space
*model
)
510 if (!multi
|| !model
)
513 if (isl_space_match(multi
->space
, isl_dim_param
,
514 model
, isl_dim_param
)) {
515 isl_space_free(model
);
519 ctx
= isl_space_get_ctx(model
);
520 if (!isl_space_has_named_params(model
))
521 isl_die(ctx
, isl_error_invalid
,
522 "model has unnamed parameters", goto error
);
523 if (!isl_space_has_named_params(multi
->space
))
524 isl_die(ctx
, isl_error_invalid
,
525 "input has unnamed parameters", goto error
);
527 model
= isl_space_params(model
);
528 exp
= isl_parameter_alignment_reordering(multi
->space
, model
);
529 exp
= isl_reordering_extend_space(exp
,
530 FN(MULTI(BASE
),get_domain_space
)(multi
));
531 multi
= FN(MULTI(BASE
),realign_domain
)(multi
, exp
);
533 isl_space_free(model
);
536 isl_space_free(model
);
537 FN(MULTI(BASE
),free
)(multi
);
541 #if !defined(NO_GIST) || !defined(NO_INTERSECT_DOMAIN)
542 /* Transform the elements of "multi" by applying "fn" to them
543 * with extra argument "set".
545 * The parameters of "multi" and "set" are assumed to have been aligned.
547 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),apply_set_aligned
)(
548 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_set
*set
,
549 __isl_give EL
*(*fn
)(EL
*el
, __isl_take isl_set
*set
))
561 multi
= FN(MULTI(BASE
),cow
)(multi
);
565 for (i
= 0; i
< multi
->n
; ++i
) {
566 multi
->p
[i
] = fn(multi
->p
[i
], isl_set_copy(set
));
575 FN(MULTI(BASE
),free
)(multi
);
579 /* Transform the elements of "multi" by applying "fn" to them
580 * with extra argument "set".
582 * Align the parameters if needed and call apply_set_aligned.
584 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),apply_set
)(
585 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_set
*set
,
586 __isl_give EL
*(*fn
)(EL
*el
, __isl_take isl_set
*set
))
593 if (isl_space_match(multi
->space
, isl_dim_param
,
594 set
->dim
, isl_dim_param
))
595 return FN(MULTI(BASE
),apply_set_aligned
)(multi
, set
, fn
);
596 ctx
= FN(MULTI(BASE
),get_ctx
)(multi
);
597 if (!isl_space_has_named_params(multi
->space
) ||
598 !isl_space_has_named_params(set
->dim
))
599 isl_die(ctx
, isl_error_invalid
,
600 "unaligned unnamed parameters", goto error
);
601 multi
= FN(MULTI(BASE
),align_params
)(multi
, isl_set_get_space(set
));
602 set
= isl_set_align_params(set
, FN(MULTI(BASE
),get_space
)(multi
));
603 return FN(MULTI(BASE
),apply_set_aligned
)(multi
, set
, fn
);
605 FN(MULTI(BASE
),free
)(multi
);
612 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),gist
)(__isl_take
MULTI(BASE
) *multi
,
613 __isl_take isl_set
*context
)
615 return FN(MULTI(BASE
),apply_set
)(multi
, context
, &FN(EL
,gist
));
618 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),gist_params
)(
619 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_set
*context
)
621 return FN(MULTI(BASE
),apply_set
)(multi
, context
, &FN(EL
,gist_params
));
625 #ifndef NO_INTERSECT_DOMAIN
626 /* Intersect the domain of "multi" with "domain".
628 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),intersect_domain
)(
629 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_set
*domain
)
631 return FN(MULTI(BASE
),apply_set
)(multi
, domain
,
632 &FN(EL
,intersect_domain
));
635 /* Intersect the parameter domain of "multi" with "domain".
637 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),intersect_params
)(
638 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_set
*domain
)
640 return FN(MULTI(BASE
),apply_set
)(multi
, domain
,
641 &FN(EL
,intersect_params
));
645 __isl_give
MULTI(BASE
) *FN(FN(MULTI(BASE
),from
),LIST(BASE
))(
646 __isl_take isl_space
*space
, __isl_take
LIST(EL
) *list
)
656 ctx
= isl_space_get_ctx(space
);
657 n
= FN(FN(LIST(EL
),n
),BASE
)(list
);
658 if (n
!= isl_space_dim(space
, isl_dim_out
))
659 isl_die(ctx
, isl_error_invalid
,
660 "invalid number of elements in list", goto error
);
662 multi
= FN(MULTI(BASE
),alloc
)(isl_space_copy(space
));
663 for (i
= 0; i
< n
; ++i
) {
664 multi
= FN(FN(MULTI(BASE
),set
),BASE
)(multi
, i
,
665 FN(FN(LIST(EL
),get
),BASE
)(list
, i
));
668 isl_space_free(space
);
669 FN(LIST(EL
),free
)(list
);
672 isl_space_free(space
);
673 FN(LIST(EL
),free
)(list
);
678 /* Create a multi expression in the given space that maps each
679 * input dimension to the corresponding output dimension.
681 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),identity
)(__isl_take isl_space
*space
)
690 if (isl_space_is_set(space
))
691 isl_die(isl_space_get_ctx(space
), isl_error_invalid
,
692 "expecting map space", goto error
);
694 n
= isl_space_dim(space
, isl_dim_out
);
695 if (n
!= isl_space_dim(space
, isl_dim_in
))
696 isl_die(isl_space_get_ctx(space
), isl_error_invalid
,
697 "number of input and output dimensions needs to be "
698 "the same", goto error
);
700 multi
= FN(MULTI(BASE
),alloc
)(isl_space_copy(space
));
703 isl_space_free(space
);
707 space
= isl_space_domain(space
);
708 ls
= isl_local_space_from_space(space
);
710 for (i
= 0; i
< n
; ++i
) {
712 el
= FN(EL
,var_on_domain
)(isl_local_space_copy(ls
),
714 multi
= FN(FN(MULTI(BASE
),set
),BASE
)(multi
, i
, el
);
717 isl_local_space_free(ls
);
721 isl_space_free(space
);
726 /* Construct a multi expression in the given space with value zero in
727 * each of the output dimensions.
729 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),zero
)(__isl_take isl_space
*space
)
737 n
= isl_space_dim(space
, isl_dim_out
);
738 multi
= FN(MULTI(BASE
),alloc
)(isl_space_copy(space
));
741 isl_space_free(space
);
747 space
= isl_space_domain(space
);
748 ls
= isl_local_space_from_space(space
);
749 el
= FN(EL
,zero_on_domain
)(ls
);
751 for (i
= 0; i
< n
; ++i
)
752 multi
= FN(FN(MULTI(BASE
),set
),BASE
)(multi
, i
,
762 __isl_give
MULTI(BASE
) *FN(FN(MULTI(BASE
),from
),BASE
)(__isl_take EL
*el
)
766 multi
= FN(MULTI(BASE
),alloc
)(FN(EL
,get_space
)(el
));
767 multi
= FN(FN(MULTI(BASE
),set
),BASE
)(multi
, 0, el
);
773 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),drop_dims
)(
774 __isl_take
MULTI(BASE
) *multi
,
775 enum isl_dim_type type
, unsigned first
, unsigned n
)
780 multi
= FN(MULTI(BASE
),cow
)(multi
);
784 dim
= FN(MULTI(BASE
),dim
)(multi
, type
);
785 if (first
+ n
> dim
|| first
+ n
< first
)
786 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
787 "index out of bounds",
788 return FN(MULTI(BASE
),cow
)(multi
));
790 multi
->space
= isl_space_drop_dims(multi
->space
, type
, first
, n
);
792 return FN(MULTI(BASE
),cow
)(multi
);
794 if (type
== isl_dim_out
) {
795 for (i
= 0; i
< n
; ++i
)
796 FN(EL
,free
)(multi
->p
[first
+ i
]);
797 for (i
= first
; i
+ n
< multi
->n
; ++i
)
798 multi
->p
[i
] = multi
->p
[i
+ n
];
804 for (i
= 0; i
< multi
->n
; ++i
) {
805 multi
->p
[i
] = FN(EL
,drop_dims
)(multi
->p
[i
], type
, first
, n
);
807 return FN(MULTI(BASE
),cow
)(multi
);
813 /* Align the parameters of "multi1" and "multi2" (if needed) and call "fn".
815 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),align_params_multi_multi_and
)(
816 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
,
817 __isl_give
MULTI(BASE
) *(*fn
)(__isl_take
MULTI(BASE
) *multi1
,
818 __isl_take
MULTI(BASE
) *multi2
))
822 if (!multi1
|| !multi2
)
824 if (isl_space_match(multi1
->space
, isl_dim_param
,
825 multi2
->space
, isl_dim_param
))
826 return fn(multi1
, multi2
);
827 ctx
= FN(MULTI(BASE
),get_ctx
)(multi1
);
828 if (!isl_space_has_named_params(multi1
->space
) ||
829 !isl_space_has_named_params(multi2
->space
))
830 isl_die(ctx
, isl_error_invalid
,
831 "unaligned unnamed parameters", goto error
);
832 multi1
= FN(MULTI(BASE
),align_params
)(multi1
,
833 FN(MULTI(BASE
),get_space
)(multi2
));
834 multi2
= FN(MULTI(BASE
),align_params
)(multi2
,
835 FN(MULTI(BASE
),get_space
)(multi1
));
836 return fn(multi1
, multi2
);
838 FN(MULTI(BASE
),free
)(multi1
);
839 FN(MULTI(BASE
),free
)(multi2
);
843 /* Given two MULTI(BASE)s A -> B and C -> D,
844 * construct a MULTI(BASE) (A * C) -> [B -> D].
846 * The parameters are assumed to have been aligned.
848 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_product_aligned
)(
849 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
856 if (!multi1
|| !multi2
)
859 space
= isl_space_range_product(FN(MULTI(BASE
),get_space
)(multi1
),
860 FN(MULTI(BASE
),get_space
)(multi2
));
861 res
= FN(MULTI(BASE
),alloc
)(space
);
863 n1
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_out
);
864 n2
= FN(MULTI(BASE
),dim
)(multi2
, isl_dim_out
);
866 for (i
= 0; i
< n1
; ++i
) {
867 el
= FN(FN(MULTI(BASE
),get
),BASE
)(multi1
, i
);
868 res
= FN(FN(MULTI(BASE
),set
),BASE
)(res
, i
, el
);
871 for (i
= 0; i
< n2
; ++i
) {
872 el
= FN(FN(MULTI(BASE
),get
),BASE
)(multi2
, i
);
873 res
= FN(FN(MULTI(BASE
),set
),BASE
)(res
, n1
+ i
, el
);
876 FN(MULTI(BASE
),free
)(multi1
);
877 FN(MULTI(BASE
),free
)(multi2
);
880 FN(MULTI(BASE
),free
)(multi1
);
881 FN(MULTI(BASE
),free
)(multi2
);
885 /* Given two MULTI(BASE)s A -> B and C -> D,
886 * construct a MULTI(BASE) (A * C) -> [B -> D].
888 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_product
)(
889 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
891 return FN(MULTI(BASE
),align_params_multi_multi_and
)(multi1
, multi2
,
892 &FN(MULTI(BASE
),range_product_aligned
));
895 /* Is the range of "multi" a wrapped relation?
897 int FN(MULTI(BASE
),range_is_wrapping
)(__isl_keep
MULTI(BASE
) *multi
)
901 return isl_space_range_is_wrapping(multi
->space
);
904 /* Given a function A -> [B -> C], extract the function A -> B.
906 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_factor_domain
)(
907 __isl_take
MULTI(BASE
) *multi
)
914 if (!isl_space_range_is_wrapping(multi
->space
))
915 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
916 "range is not a product",
917 return FN(MULTI(BASE
),free
)(multi
));
919 space
= FN(MULTI(BASE
),get_space
)(multi
);
920 total
= isl_space_dim(space
, isl_dim_out
);
921 space
= isl_space_range_factor_domain(space
);
922 keep
= isl_space_dim(space
, isl_dim_out
);
923 multi
= FN(MULTI(BASE
),drop_dims
)(multi
,
924 isl_dim_out
, keep
, total
- keep
);
925 multi
= FN(MULTI(BASE
),reset_space
)(multi
, space
);
930 /* Given a function A -> [B -> C], extract the function A -> C.
932 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_factor_range
)(
933 __isl_take
MULTI(BASE
) *multi
)
940 if (!isl_space_range_is_wrapping(multi
->space
))
941 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
942 "range is not a product",
943 return FN(MULTI(BASE
),free
)(multi
));
945 space
= FN(MULTI(BASE
),get_space
)(multi
);
946 total
= isl_space_dim(space
, isl_dim_out
);
947 space
= isl_space_range_factor_range(space
);
948 keep
= isl_space_dim(space
, isl_dim_out
);
949 multi
= FN(MULTI(BASE
),drop_dims
)(multi
, isl_dim_out
, 0, total
- keep
);
950 multi
= FN(MULTI(BASE
),reset_space
)(multi
, space
);
955 /* Given two MULTI(BASE)s A -> B and C -> D,
956 * construct a MULTI(BASE) [A -> C] -> [B -> D].
958 * The parameters are assumed to have been aligned.
960 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),product_aligned
)(
961 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
967 int in1
, in2
, out1
, out2
;
969 in1
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_in
);
970 in2
= FN(MULTI(BASE
),dim
)(multi2
, isl_dim_in
);
971 out1
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_out
);
972 out2
= FN(MULTI(BASE
),dim
)(multi2
, isl_dim_out
);
973 space
= isl_space_product(FN(MULTI(BASE
),get_space
)(multi1
),
974 FN(MULTI(BASE
),get_space
)(multi2
));
975 res
= FN(MULTI(BASE
),alloc
)(isl_space_copy(space
));
976 space
= isl_space_domain(space
);
978 for (i
= 0; i
< out1
; ++i
) {
979 el
= FN(FN(MULTI(BASE
),get
),BASE
)(multi1
, i
);
980 el
= FN(EL
,insert_dims
)(el
, isl_dim_in
, in1
, in2
);
981 el
= FN(EL
,reset_domain_space
)(el
, isl_space_copy(space
));
982 res
= FN(FN(MULTI(BASE
),set
),BASE
)(res
, i
, el
);
985 for (i
= 0; i
< out2
; ++i
) {
986 el
= FN(FN(MULTI(BASE
),get
),BASE
)(multi2
, i
);
987 el
= FN(EL
,insert_dims
)(el
, isl_dim_in
, 0, in1
);
988 el
= FN(EL
,reset_domain_space
)(el
, isl_space_copy(space
));
989 res
= FN(FN(MULTI(BASE
),set
),BASE
)(res
, out1
+ i
, el
);
992 isl_space_free(space
);
993 FN(MULTI(BASE
),free
)(multi1
);
994 FN(MULTI(BASE
),free
)(multi2
);
998 /* Given two MULTI(BASE)s A -> B and C -> D,
999 * construct a MULTI(BASE) [A -> C] -> [B -> D].
1001 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),product
)(
1002 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
1004 return FN(MULTI(BASE
),align_params_multi_multi_and
)(multi1
, multi2
,
1005 &FN(MULTI(BASE
),product_aligned
));
1008 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),flatten_range
)(
1009 __isl_take
MULTI(BASE
) *multi
)
1014 if (!multi
->space
->nested
[1])
1017 multi
= FN(MULTI(BASE
),cow
)(multi
);
1021 multi
->space
= isl_space_flatten_range(multi
->space
);
1023 return FN(MULTI(BASE
),free
)(multi
);
1028 /* Given two MULTI(BASE)s A -> B and C -> D,
1029 * construct a MULTI(BASE) (A * C) -> (B, D).
1031 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),flat_range_product
)(
1032 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
1036 multi
= FN(MULTI(BASE
),range_product
)(multi1
, multi2
);
1037 multi
= FN(MULTI(BASE
),flatten_range
)(multi
);
1041 /* Given two multi expressions, "multi1"
1045 * where B2 starts at position "pos", and "multi2"
1049 * return the multi expression
1053 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_splice
)(
1054 __isl_take
MULTI(BASE
) *multi1
, unsigned pos
,
1055 __isl_take
MULTI(BASE
) *multi2
)
1060 if (!multi1
|| !multi2
)
1063 dim
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_out
);
1065 isl_die(FN(MULTI(BASE
),get_ctx
)(multi1
), isl_error_invalid
,
1066 "index out of bounds", goto error
);
1068 res
= FN(MULTI(BASE
),copy
)(multi1
);
1069 res
= FN(MULTI(BASE
),drop_dims
)(res
, isl_dim_out
, pos
, dim
- pos
);
1070 multi1
= FN(MULTI(BASE
),drop_dims
)(multi1
, isl_dim_out
, 0, pos
);
1072 res
= FN(MULTI(BASE
),flat_range_product
)(res
, multi2
);
1073 res
= FN(MULTI(BASE
),flat_range_product
)(res
, multi1
);
1077 FN(MULTI(BASE
),free
)(multi1
);
1078 FN(MULTI(BASE
),free
)(multi2
);
1082 /* Given two multi expressions, "multi1"
1084 * [A1 A2] -> [B1 B2]
1086 * where A2 starts at position "in_pos" and B2 starts at position "out_pos",
1091 * return the multi expression
1093 * [A1 C A2] -> [B1 D B2]
1095 * We first insert input dimensions to obtain
1097 * [A1 C A2] -> [B1 B2]
1103 * and then apply range_splice.
1105 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),splice
)(
1106 __isl_take
MULTI(BASE
) *multi1
, unsigned in_pos
, unsigned out_pos
,
1107 __isl_take
MULTI(BASE
) *multi2
)
1112 if (!multi1
|| !multi2
)
1115 n_in1
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_in
);
1117 isl_die(FN(MULTI(BASE
),get_ctx
)(multi1
), isl_error_invalid
,
1118 "index out of bounds", goto error
);
1120 n_in2
= FN(MULTI(BASE
),dim
)(multi2
, isl_dim_in
);
1122 multi1
= FN(MULTI(BASE
),insert_dims
)(multi1
, isl_dim_in
, in_pos
, n_in2
);
1123 multi2
= FN(MULTI(BASE
),insert_dims
)(multi2
, isl_dim_in
, n_in2
,
1125 multi2
= FN(MULTI(BASE
),insert_dims
)(multi2
, isl_dim_in
, 0, in_pos
);
1127 return FN(MULTI(BASE
),range_splice
)(multi1
, out_pos
, multi2
);
1129 FN(MULTI(BASE
),free
)(multi1
);
1130 FN(MULTI(BASE
),free
)(multi2
);
1134 /* This function is currently only used from isl_aff.c
1136 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),bin_op
)(
1137 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
,
1138 __isl_give EL
*(*fn
)(__isl_take EL
*, __isl_take EL
*))
1139 __attribute__ ((unused
));
1141 /* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
1142 * return the result.
1144 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),bin_op
)(
1145 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
,
1146 __isl_give EL
*(*fn
)(__isl_take EL
*, __isl_take EL
*))
1151 multi1
= FN(MULTI(BASE
),cow
)(multi1
);
1152 if (!multi1
|| !multi2
)
1155 ctx
= FN(MULTI(BASE
),get_ctx
)(multi1
);
1156 if (!isl_space_is_equal(multi1
->space
, multi2
->space
))
1157 isl_die(ctx
, isl_error_invalid
,
1158 "spaces don't match", goto error
);
1160 for (i
= 0; i
< multi1
->n
; ++i
) {
1161 multi1
->p
[i
] = fn(multi1
->p
[i
], FN(EL
,copy
)(multi2
->p
[i
]));
1166 FN(MULTI(BASE
),free
)(multi2
);
1169 FN(MULTI(BASE
),free
)(multi1
);
1170 FN(MULTI(BASE
),free
)(multi2
);
1174 /* Subtract "multi2" from "multi1" and return the result.
1176 * The parameters of "multi1" and "multi2" are assumed to have been aligned.
1178 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),sub_aligned
)(
1179 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
1181 return FN(MULTI(BASE
),bin_op
)(multi1
, multi2
, &FN(EL
,sub
));
1184 /* Subtract "multi2" from "multi1" and return the result.
1186 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),sub
)(__isl_take
MULTI(BASE
) *multi1
,
1187 __isl_take
MULTI(BASE
) *multi2
)
1189 return FN(MULTI(BASE
),align_params_multi_multi_and
)(multi1
, multi2
,
1190 &FN(MULTI(BASE
),sub_aligned
));
1193 /* Multiply the elements of "multi" by "v" and return the result.
1195 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),scale_val
)(__isl_take
MULTI(BASE
) *multi
,
1196 __isl_take isl_val
*v
)
1203 if (isl_val_is_one(v
)) {
1208 if (!isl_val_is_rat(v
))
1209 isl_die(isl_val_get_ctx(v
), isl_error_invalid
,
1210 "expecting rational factor", goto error
);
1212 multi
= FN(MULTI(BASE
),cow
)(multi
);
1216 for (i
= 0; i
< multi
->n
; ++i
) {
1217 multi
->p
[i
] = FN(EL
,scale_val
)(multi
->p
[i
], isl_val_copy(v
));
1226 return FN(MULTI(BASE
),free
)(multi
);
1229 /* Divide the elements of "multi" by "v" and return the result.
1231 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),scale_down_val
)(
1232 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_val
*v
)
1239 if (isl_val_is_one(v
)) {
1244 if (!isl_val_is_rat(v
))
1245 isl_die(isl_val_get_ctx(v
), isl_error_invalid
,
1246 "expecting rational factor", goto error
);
1247 if (isl_val_is_zero(v
))
1248 isl_die(isl_val_get_ctx(v
), isl_error_invalid
,
1249 "cannot scale down by zero", goto error
);
1251 multi
= FN(MULTI(BASE
),cow
)(multi
);
1255 for (i
= 0; i
< multi
->n
; ++i
) {
1256 multi
->p
[i
] = FN(EL
,scale_down_val
)(multi
->p
[i
],
1266 return FN(MULTI(BASE
),free
)(multi
);
1269 /* Multiply the elements of "multi" by the corresponding element of "mv"
1270 * and return the result.
1272 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),scale_multi_val
)(
1273 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_multi_val
*mv
)
1280 if (!isl_space_tuple_is_equal(multi
->space
, isl_dim_out
,
1281 mv
->space
, isl_dim_set
))
1282 isl_die(isl_multi_val_get_ctx(mv
), isl_error_invalid
,
1283 "spaces don't match", goto error
);
1285 multi
= FN(MULTI(BASE
),cow
)(multi
);
1289 for (i
= 0; i
< multi
->n
; ++i
) {
1292 v
= isl_multi_val_get_val(mv
, i
);
1293 multi
->p
[i
] = FN(EL
,scale_val
)(multi
->p
[i
], v
);
1298 isl_multi_val_free(mv
);
1301 isl_multi_val_free(mv
);
1302 return FN(MULTI(BASE
),free
)(multi
);
1305 /* Divide the elements of "multi" by the corresponding element of "mv"
1306 * and return the result.
1308 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),scale_down_multi_val
)(
1309 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_multi_val
*mv
)
1316 if (!isl_space_tuple_is_equal(multi
->space
, isl_dim_out
,
1317 mv
->space
, isl_dim_set
))
1318 isl_die(isl_multi_val_get_ctx(mv
), isl_error_invalid
,
1319 "spaces don't match", goto error
);
1321 multi
= FN(MULTI(BASE
),cow
)(multi
);
1325 for (i
= 0; i
< multi
->n
; ++i
) {
1328 v
= isl_multi_val_get_val(mv
, i
);
1329 multi
->p
[i
] = FN(EL
,scale_down_val
)(multi
->p
[i
], v
);
1334 isl_multi_val_free(mv
);
1337 isl_multi_val_free(mv
);
1338 return FN(MULTI(BASE
),free
)(multi
);
1341 /* Compute the residues of the elements of "multi" modulo
1342 * the corresponding element of "mv" and return the result.
1344 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),mod_multi_val
)(
1345 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_multi_val
*mv
)
1352 if (!isl_space_tuple_is_equal(multi
->space
, isl_dim_out
,
1353 mv
->space
, isl_dim_set
))
1354 isl_die(isl_multi_val_get_ctx(mv
), isl_error_invalid
,
1355 "spaces don't match", goto error
);
1357 multi
= FN(MULTI(BASE
),cow
)(multi
);
1361 for (i
= 0; i
< multi
->n
; ++i
) {
1364 v
= isl_multi_val_get_val(mv
, i
);
1365 multi
->p
[i
] = FN(EL
,mod_val
)(multi
->p
[i
], v
);
1370 isl_multi_val_free(mv
);
1373 isl_multi_val_free(mv
);
1374 return FN(MULTI(BASE
),free
)(multi
);
1377 #ifndef NO_MOVE_DIMS
1378 /* Move the "n" dimensions of "src_type" starting at "src_pos" of "multi"
1379 * to dimensions of "dst_type" at "dst_pos".
1381 * We only support moving input dimensions to parameters and vice versa.
1383 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),move_dims
)(__isl_take
MULTI(BASE
) *multi
,
1384 enum isl_dim_type dst_type
, unsigned dst_pos
,
1385 enum isl_dim_type src_type
, unsigned src_pos
, unsigned n
)
1393 !isl_space_is_named_or_nested(multi
->space
, src_type
) &&
1394 !isl_space_is_named_or_nested(multi
->space
, dst_type
))
1397 if (dst_type
== isl_dim_out
|| src_type
== isl_dim_out
)
1398 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
1399 "cannot move output/set dimension",
1400 return FN(MULTI(BASE
),free
)(multi
));
1401 if (dst_type
== isl_dim_div
|| src_type
== isl_dim_div
)
1402 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
1404 return FN(MULTI(BASE
),free
)(multi
));
1405 if (src_pos
+ n
> isl_space_dim(multi
->space
, src_type
))
1406 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
1407 "range out of bounds",
1408 return FN(MULTI(BASE
),free
)(multi
));
1409 if (dst_type
== src_type
)
1410 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_unsupported
,
1411 "moving dims within the same type not supported",
1412 return FN(MULTI(BASE
),free
)(multi
));
1414 multi
= FN(MULTI(BASE
),cow
)(multi
);
1418 multi
->space
= isl_space_move_dims(multi
->space
, dst_type
, dst_pos
,
1419 src_type
, src_pos
, n
);
1421 return FN(MULTI(BASE
),free
)(multi
);
1423 for (i
= 0; i
< multi
->n
; ++i
) {
1424 multi
->p
[i
] = FN(EL
,move_dims
)(multi
->p
[i
], dst_type
, dst_pos
,
1425 src_type
, src_pos
, n
);
1427 return FN(MULTI(BASE
),free
)(multi
);
1434 /* Convert a multiple expression defined over a parameter domain
1435 * into one that is defined over a zero-dimensional set.
1437 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),from_range
)(
1438 __isl_take
MULTI(BASE
) *multi
)
1444 if (!isl_space_is_set(multi
->space
))
1445 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
1446 "not living in a set space",
1447 return FN(MULTI(BASE
),free
)(multi
));
1449 space
= FN(MULTI(BASE
),get_space
)(multi
);
1450 space
= isl_space_from_range(space
);
1451 multi
= FN(MULTI(BASE
),reset_space
)(multi
, space
);
1456 /* Are "multi1" and "multi2" obviously equal?
1458 int FN(MULTI(BASE
),plain_is_equal
)(__isl_keep
MULTI(BASE
) *multi1
,
1459 __isl_keep
MULTI(BASE
) *multi2
)
1464 if (!multi1
|| !multi2
)
1466 if (multi1
->n
!= multi2
->n
)
1468 equal
= isl_space_is_equal(multi1
->space
, multi2
->space
);
1469 if (equal
< 0 || !equal
)
1472 for (i
= 0; i
< multi1
->n
; ++i
) {
1473 equal
= FN(EL
,plain_is_equal
)(multi1
->p
[i
], multi2
->p
[i
]);
1474 if (equal
< 0 || !equal
)
1482 /* Return the shared domain of the elements of "multi".
1484 __isl_give isl_set
*FN(MULTI(BASE
),domain
)(__isl_take
MULTI(BASE
) *multi
)
1492 dom
= isl_set_universe(FN(MULTI(BASE
),get_domain_space
)(multi
));
1493 for (i
= 0; i
< multi
->n
; ++i
) {
1496 dom_i
= FN(EL
,domain
)(FN(FN(MULTI(BASE
),get
),BASE
)(multi
, i
));
1497 dom
= isl_set_intersect(dom
, dom_i
);
1500 FN(MULTI(BASE
),free
)(multi
);
1506 /* Return the opposite of "multi".
1508 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),neg
)(__isl_take
MULTI(BASE
) *multi
)
1512 multi
= FN(MULTI(BASE
),cow
)(multi
);
1516 for (i
= 0; i
< multi
->n
; ++i
) {
1517 multi
->p
[i
] = FN(EL
,neg
)(multi
->p
[i
]);
1519 return FN(MULTI(BASE
),free
)(multi
);