generalize isl_multi_*_gist and isl_multi_*_intersect_domain
[isl.git] / isl_multi_templ.c
blobb889d5a66a6123a23f7b2c4a57b5d09994fcad31
1 /*
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
9 */
11 #include <isl_space_private.h>
12 #include <isl/set.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
32 * in "multi".
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)
38 if (!multi)
39 return -1;
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)
51 isl_ctx *ctx;
52 int n;
53 MULTI(BASE) *multi;
55 if (!space)
56 return NULL;
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 *));
62 if (!multi)
63 goto error;
65 multi->space = space;
66 multi->n = n;
67 multi->ref = 1;
68 return multi;
69 error:
70 isl_space_free(space);
71 return NULL;
74 __isl_give MULTI(BASE) *FN(MULTI(BASE),dup)(__isl_keep MULTI(BASE) *multi)
76 int i;
77 MULTI(BASE) *dup;
79 if (!multi)
80 return NULL;
82 dup = FN(MULTI(BASE),alloc)(isl_space_copy(multi->space));
83 if (!dup)
84 return NULL;
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]));
90 return dup;
93 __isl_give MULTI(BASE) *FN(MULTI(BASE),cow)(__isl_take MULTI(BASE) *multi)
95 if (!multi)
96 return NULL;
98 if (multi->ref == 1)
99 return multi;
101 multi->ref--;
102 return FN(MULTI(BASE),dup)(multi);
105 __isl_give MULTI(BASE) *FN(MULTI(BASE),copy)(__isl_keep MULTI(BASE) *multi)
107 if (!multi)
108 return NULL;
110 multi->ref++;
111 return multi;
114 __isl_null MULTI(BASE) *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi)
116 int i;
118 if (!multi)
119 return NULL;
121 if (--multi->ref > 0)
122 return NULL;
124 isl_space_free(multi->space);
125 for (i = 0; i < multi->n; ++i)
126 FN(EL,free)(multi->p[i]);
127 free(multi);
129 return NULL;
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)
139 int i;
141 if (!multi)
142 return -1;
143 if (multi->n == 0 || n == 0)
144 return 0;
146 for (i = 0; i < multi->n; ++i) {
147 int involves;
149 involves = FN(EL,involves_dims)(multi->p[i], type, first, n);
150 if (involves < 0 || involves)
151 return involves;
154 return 0;
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)
161 int i;
163 if (!multi)
164 return NULL;
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))
170 return multi;
172 multi = FN(MULTI(BASE),cow)(multi);
173 if (!multi)
174 return NULL;
176 multi->space = isl_space_insert_dims(multi->space, type, first, n);
177 if (!multi->space)
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);
182 if (!multi->p[i])
183 return FN(MULTI(BASE),free)(multi);
186 return multi;
189 __isl_give MULTI(BASE) *FN(MULTI(BASE),add_dims)(__isl_take MULTI(BASE) *multi,
190 enum isl_dim_type type, unsigned n)
192 unsigned pos;
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)
211 if (!multi)
212 return -1;
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)
228 int i;
230 multi = FN(MULTI(BASE),cow)(multi);
231 if (!multi)
232 return NULL;
234 multi->space = isl_space_set_dim_name(multi->space, type, pos, s);
235 if (!multi->space)
236 return FN(MULTI(BASE),free)(multi);
238 if (type == isl_dim_out)
239 return multi;
240 for (i = 0; i < multi->n; ++i) {
241 multi->p[i] = FN(EL,set_dim_name)(multi->p[i], type, pos, s);
242 if (!multi->p[i])
243 return FN(MULTI(BASE),free)(multi);
246 return 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,
272 int pos)
274 isl_ctx *ctx;
276 if (!multi)
277 return NULL;
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;
290 int match;
292 multi = FN(MULTI(BASE),cow)(multi);
293 if (!multi || !el)
294 goto error;
296 multi_space = FN(MULTI(BASE),get_space)(multi);
297 match = FN(EL,matching_params)(el, multi_space);
298 if (match < 0)
299 goto error;
300 if (!match) {
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)
308 goto error;
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]);
315 multi->p[pos] = el;
317 isl_space_free(multi_space);
318 isl_space_free(el_space);
320 return multi;
321 error:
322 FN(MULTI(BASE),free)(multi);
323 FN(EL,free)(el);
324 isl_space_free(multi_space);
325 isl_space_free(el_space);
326 return NULL;
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)
339 int i;
341 multi = FN(MULTI(BASE),cow)(multi);
342 if (!multi || !space || !domain)
343 goto error;
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));
348 if (!multi->p[i])
349 goto error;
351 isl_space_free(domain);
352 isl_space_free(multi->space);
353 multi->space = space;
355 return multi;
356 error:
357 isl_space_free(domain);
358 isl_space_free(space);
359 FN(MULTI(BASE),free)(multi);
360 return NULL;
363 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_domain_space)(
364 __isl_take MULTI(BASE) *multi, __isl_take isl_space *domain)
366 isl_space *space;
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)
376 isl_space *domain;
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)
388 isl_space *space;
390 multi = FN(MULTI(BASE),cow)(multi);
391 if (!multi || !id)
392 goto error;
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);
398 error:
399 isl_id_free(id);
400 FN(MULTI(BASE),free)(multi);
401 return NULL;
404 __isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_name)(
405 __isl_keep MULTI(BASE) *multi, enum isl_dim_type type,
406 const char *s)
408 isl_space *space;
410 multi = FN(MULTI(BASE),cow)(multi);
411 if (!multi)
412 return NULL;
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)
424 isl_space *space;
426 multi = FN(MULTI(BASE),cow)(multi);
427 if (!multi)
428 goto error;
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);
434 error:
435 isl_id_free(id);
436 return NULL;
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)
444 isl_space *space;
446 if (!multi)
447 return NULL;
448 if (!FN(MULTI(BASE),has_tuple_id)(multi, type))
449 return multi;
451 multi = FN(MULTI(BASE),cow)(multi);
452 if (!multi)
453 return NULL;
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)
467 isl_space *space;
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)
478 int i;
480 multi = FN(MULTI(BASE),cow)(multi);
481 if (!multi || !exp)
482 goto error;
484 for (i = 0; i < multi->n; ++i) {
485 multi->p[i] = FN(EL,realign_domain)(multi->p[i],
486 isl_reordering_copy(exp));
487 if (!multi->p[i])
488 goto error;
491 multi = FN(MULTI(BASE),reset_domain_space)(multi,
492 isl_space_copy(exp->dim));
494 isl_reordering_free(exp);
495 return multi;
496 error:
497 isl_reordering_free(exp);
498 FN(MULTI(BASE),free)(multi);
499 return NULL;
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)
507 isl_ctx *ctx;
508 isl_reordering *exp;
510 if (!multi || !model)
511 goto error;
513 if (isl_space_match(multi->space, isl_dim_param,
514 model, isl_dim_param)) {
515 isl_space_free(model);
516 return multi;
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);
534 return multi;
535 error:
536 isl_space_free(model);
537 FN(MULTI(BASE),free)(multi);
538 return NULL;
541 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))(
542 __isl_take isl_space *space, __isl_take LIST(EL) *list)
544 int i;
545 int n;
546 isl_ctx *ctx;
547 MULTI(BASE) *multi;
549 if (!space || !list)
550 goto error;
552 ctx = isl_space_get_ctx(space);
553 n = FN(FN(LIST(EL),n),BASE)(list);
554 if (n != isl_space_dim(space, isl_dim_out))
555 isl_die(ctx, isl_error_invalid,
556 "invalid number of elements in list", goto error);
558 multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
559 for (i = 0; i < n; ++i) {
560 multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
561 FN(FN(LIST(EL),get),BASE)(list, i));
564 isl_space_free(space);
565 FN(LIST(EL),free)(list);
566 return multi;
567 error:
568 isl_space_free(space);
569 FN(LIST(EL),free)(list);
570 return NULL;
573 #ifndef NO_IDENTITY
574 /* Create a multi expression in the given space that maps each
575 * input dimension to the corresponding output dimension.
577 __isl_give MULTI(BASE) *FN(MULTI(BASE),identity)(__isl_take isl_space *space)
579 int i, n;
580 isl_local_space *ls;
581 MULTI(BASE) *multi;
583 if (!space)
584 return NULL;
586 if (isl_space_is_set(space))
587 isl_die(isl_space_get_ctx(space), isl_error_invalid,
588 "expecting map space", goto error);
590 n = isl_space_dim(space, isl_dim_out);
591 if (n != isl_space_dim(space, isl_dim_in))
592 isl_die(isl_space_get_ctx(space), isl_error_invalid,
593 "number of input and output dimensions needs to be "
594 "the same", goto error);
596 multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
598 if (!n) {
599 isl_space_free(space);
600 return multi;
603 space = isl_space_domain(space);
604 ls = isl_local_space_from_space(space);
606 for (i = 0; i < n; ++i) {
607 EL *el;
608 el = FN(EL,var_on_domain)(isl_local_space_copy(ls),
609 isl_dim_set, i);
610 multi = FN(FN(MULTI(BASE),set),BASE)(multi, i, el);
613 isl_local_space_free(ls);
615 return multi;
616 error:
617 isl_space_free(space);
618 return NULL;
620 #endif
622 /* Construct a multi expression in the given space with value zero in
623 * each of the output dimensions.
625 __isl_give MULTI(BASE) *FN(MULTI(BASE),zero)(__isl_take isl_space *space)
627 int n;
628 MULTI(BASE) *multi;
630 if (!space)
631 return NULL;
633 n = isl_space_dim(space , isl_dim_out);
634 multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
636 if (!n)
637 isl_space_free(space);
638 else {
639 int i;
640 isl_local_space *ls;
641 EL *el;
643 space = isl_space_domain(space);
644 ls = isl_local_space_from_space(space);
645 el = FN(EL,zero_on_domain)(ls);
647 for (i = 0; i < n; ++i)
648 multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
649 FN(EL,copy)(el));
651 FN(EL,free)(el);
654 return multi;
657 #ifndef NO_FROM_BASE
658 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),BASE)(__isl_take EL *el)
660 MULTI(BASE) *multi;
662 multi = FN(MULTI(BASE),alloc)(FN(EL,get_space)(el));
663 multi = FN(FN(MULTI(BASE),set),BASE)(multi, 0, el);
665 return multi;
667 #endif
669 __isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)(
670 __isl_take MULTI(BASE) *multi,
671 enum isl_dim_type type, unsigned first, unsigned n)
673 int i;
674 unsigned dim;
676 multi = FN(MULTI(BASE),cow)(multi);
677 if (!multi)
678 return NULL;
680 dim = FN(MULTI(BASE),dim)(multi, type);
681 if (first + n > dim || first + n < first)
682 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
683 "index out of bounds",
684 return FN(MULTI(BASE),cow)(multi));
686 multi->space = isl_space_drop_dims(multi->space, type, first, n);
687 if (!multi->space)
688 return FN(MULTI(BASE),cow)(multi);
690 if (type == isl_dim_out) {
691 for (i = 0; i < n; ++i)
692 FN(EL,free)(multi->p[first + i]);
693 for (i = first; i + n < multi->n; ++i)
694 multi->p[i] = multi->p[i + n];
695 multi->n -= n;
697 return multi;
700 for (i = 0; i < multi->n; ++i) {
701 multi->p[i] = FN(EL,drop_dims)(multi->p[i], type, first, n);
702 if (!multi->p[i])
703 return FN(MULTI(BASE),cow)(multi);
706 return multi;
709 /* Align the parameters of "multi1" and "multi2" (if needed) and call "fn".
711 static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_multi_and)(
712 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
713 __isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi1,
714 __isl_take MULTI(BASE) *multi2))
716 isl_ctx *ctx;
718 if (!multi1 || !multi2)
719 goto error;
720 if (isl_space_match(multi1->space, isl_dim_param,
721 multi2->space, isl_dim_param))
722 return fn(multi1, multi2);
723 ctx = FN(MULTI(BASE),get_ctx)(multi1);
724 if (!isl_space_has_named_params(multi1->space) ||
725 !isl_space_has_named_params(multi2->space))
726 isl_die(ctx, isl_error_invalid,
727 "unaligned unnamed parameters", goto error);
728 multi1 = FN(MULTI(BASE),align_params)(multi1,
729 FN(MULTI(BASE),get_space)(multi2));
730 multi2 = FN(MULTI(BASE),align_params)(multi2,
731 FN(MULTI(BASE),get_space)(multi1));
732 return fn(multi1, multi2);
733 error:
734 FN(MULTI(BASE),free)(multi1);
735 FN(MULTI(BASE),free)(multi2);
736 return NULL;
739 /* Given two MULTI(BASE)s A -> B and C -> D,
740 * construct a MULTI(BASE) (A * C) -> [B -> D].
742 * The parameters are assumed to have been aligned.
744 static __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product_aligned)(
745 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
747 int i, n1, n2;
748 EL *el;
749 isl_space *space;
750 MULTI(BASE) *res;
752 if (!multi1 || !multi2)
753 goto error;
755 space = isl_space_range_product(FN(MULTI(BASE),get_space)(multi1),
756 FN(MULTI(BASE),get_space)(multi2));
757 res = FN(MULTI(BASE),alloc)(space);
759 n1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
760 n2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
762 for (i = 0; i < n1; ++i) {
763 el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
764 res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
767 for (i = 0; i < n2; ++i) {
768 el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
769 res = FN(FN(MULTI(BASE),set),BASE)(res, n1 + i, el);
772 FN(MULTI(BASE),free)(multi1);
773 FN(MULTI(BASE),free)(multi2);
774 return res;
775 error:
776 FN(MULTI(BASE),free)(multi1);
777 FN(MULTI(BASE),free)(multi2);
778 return NULL;
781 /* Given two MULTI(BASE)s A -> B and C -> D,
782 * construct a MULTI(BASE) (A * C) -> [B -> D].
784 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)(
785 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
787 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
788 &FN(MULTI(BASE),range_product_aligned));
791 /* Is the range of "multi" a wrapped relation?
793 int FN(MULTI(BASE),range_is_wrapping)(__isl_keep MULTI(BASE) *multi)
795 if (!multi)
796 return -1;
797 return isl_space_range_is_wrapping(multi->space);
800 /* Given a function A -> [B -> C], extract the function A -> B.
802 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_domain)(
803 __isl_take MULTI(BASE) *multi)
805 isl_space *space;
806 int total, keep;
808 if (!multi)
809 return NULL;
810 if (!isl_space_range_is_wrapping(multi->space))
811 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
812 "range is not a product",
813 return FN(MULTI(BASE),free)(multi));
815 space = FN(MULTI(BASE),get_space)(multi);
816 total = isl_space_dim(space, isl_dim_out);
817 space = isl_space_range_factor_domain(space);
818 keep = isl_space_dim(space, isl_dim_out);
819 multi = FN(MULTI(BASE),drop_dims)(multi,
820 isl_dim_out, keep, total - keep);
821 multi = FN(MULTI(BASE),reset_space)(multi, space);
823 return multi;
826 /* Given a function A -> [B -> C], extract the function A -> C.
828 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_range)(
829 __isl_take MULTI(BASE) *multi)
831 isl_space *space;
832 int total, keep;
834 if (!multi)
835 return NULL;
836 if (!isl_space_range_is_wrapping(multi->space))
837 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
838 "range is not a product",
839 return FN(MULTI(BASE),free)(multi));
841 space = FN(MULTI(BASE),get_space)(multi);
842 total = isl_space_dim(space, isl_dim_out);
843 space = isl_space_range_factor_range(space);
844 keep = isl_space_dim(space, isl_dim_out);
845 multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
846 multi = FN(MULTI(BASE),reset_space)(multi, space);
848 return multi;
851 /* Given two MULTI(BASE)s A -> B and C -> D,
852 * construct a MULTI(BASE) [A -> C] -> [B -> D].
854 * The parameters are assumed to have been aligned.
856 __isl_give MULTI(BASE) *FN(MULTI(BASE),product_aligned)(
857 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
859 int i;
860 EL *el;
861 isl_space *space;
862 MULTI(BASE) *res;
863 int in1, in2, out1, out2;
865 in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in);
866 in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in);
867 out1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
868 out2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
869 space = isl_space_product(FN(MULTI(BASE),get_space)(multi1),
870 FN(MULTI(BASE),get_space)(multi2));
871 res = FN(MULTI(BASE),alloc)(isl_space_copy(space));
872 space = isl_space_domain(space);
874 for (i = 0; i < out1; ++i) {
875 el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
876 el = FN(EL,insert_dims)(el, isl_dim_in, in1, in2);
877 el = FN(EL,reset_domain_space)(el, isl_space_copy(space));
878 res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
881 for (i = 0; i < out2; ++i) {
882 el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
883 el = FN(EL,insert_dims)(el, isl_dim_in, 0, in1);
884 el = FN(EL,reset_domain_space)(el, isl_space_copy(space));
885 res = FN(FN(MULTI(BASE),set),BASE)(res, out1 + i, el);
888 isl_space_free(space);
889 FN(MULTI(BASE),free)(multi1);
890 FN(MULTI(BASE),free)(multi2);
891 return res;
894 /* Given two MULTI(BASE)s A -> B and C -> D,
895 * construct a MULTI(BASE) [A -> C] -> [B -> D].
897 __isl_give MULTI(BASE) *FN(MULTI(BASE),product)(
898 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
900 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
901 &FN(MULTI(BASE),product_aligned));
904 __isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)(
905 __isl_take MULTI(BASE) *multi)
907 if (!multi)
908 return NULL;
910 if (!multi->space->nested[1])
911 return multi;
913 multi = FN(MULTI(BASE),cow)(multi);
914 if (!multi)
915 return NULL;
917 multi->space = isl_space_flatten_range(multi->space);
918 if (!multi->space)
919 return FN(MULTI(BASE),free)(multi);
921 return multi;
924 /* Given two MULTI(BASE)s A -> B and C -> D,
925 * construct a MULTI(BASE) (A * C) -> (B, D).
927 __isl_give MULTI(BASE) *FN(MULTI(BASE),flat_range_product)(
928 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
930 MULTI(BASE) *multi;
932 multi = FN(MULTI(BASE),range_product)(multi1, multi2);
933 multi = FN(MULTI(BASE),flatten_range)(multi);
934 return multi;
937 /* Given two multi expressions, "multi1"
939 * [A] -> [B1 B2]
941 * where B2 starts at position "pos", and "multi2"
943 * [A] -> [D]
945 * return the multi expression
947 * [A] -> [B1 D B2]
949 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_splice)(
950 __isl_take MULTI(BASE) *multi1, unsigned pos,
951 __isl_take MULTI(BASE) *multi2)
953 MULTI(BASE) *res;
954 unsigned dim;
956 if (!multi1 || !multi2)
957 goto error;
959 dim = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
960 if (pos > dim)
961 isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
962 "index out of bounds", goto error);
964 res = FN(MULTI(BASE),copy)(multi1);
965 res = FN(MULTI(BASE),drop_dims)(res, isl_dim_out, pos, dim - pos);
966 multi1 = FN(MULTI(BASE),drop_dims)(multi1, isl_dim_out, 0, pos);
968 res = FN(MULTI(BASE),flat_range_product)(res, multi2);
969 res = FN(MULTI(BASE),flat_range_product)(res, multi1);
971 return res;
972 error:
973 FN(MULTI(BASE),free)(multi1);
974 FN(MULTI(BASE),free)(multi2);
975 return NULL;
978 /* Given two multi expressions, "multi1"
980 * [A1 A2] -> [B1 B2]
982 * where A2 starts at position "in_pos" and B2 starts at position "out_pos",
983 * and "multi2"
985 * [C] -> [D]
987 * return the multi expression
989 * [A1 C A2] -> [B1 D B2]
991 * We first insert input dimensions to obtain
993 * [A1 C A2] -> [B1 B2]
995 * and
997 * [A1 C A2] -> [D]
999 * and then apply range_splice.
1001 __isl_give MULTI(BASE) *FN(MULTI(BASE),splice)(
1002 __isl_take MULTI(BASE) *multi1, unsigned in_pos, unsigned out_pos,
1003 __isl_take MULTI(BASE) *multi2)
1005 unsigned n_in1;
1006 unsigned n_in2;
1008 if (!multi1 || !multi2)
1009 goto error;
1011 n_in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in);
1012 if (in_pos > n_in1)
1013 isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
1014 "index out of bounds", goto error);
1016 n_in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in);
1018 multi1 = FN(MULTI(BASE),insert_dims)(multi1, isl_dim_in, in_pos, n_in2);
1019 multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, n_in2,
1020 n_in1 - in_pos);
1021 multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, 0, in_pos);
1023 return FN(MULTI(BASE),range_splice)(multi1, out_pos, multi2);
1024 error:
1025 FN(MULTI(BASE),free)(multi1);
1026 FN(MULTI(BASE),free)(multi2);
1027 return NULL;
1030 /* This function is currently only used from isl_aff.c
1032 static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
1033 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
1034 __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
1035 __attribute__ ((unused));
1037 /* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
1038 * return the result.
1040 static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
1041 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
1042 __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
1044 int i;
1045 isl_ctx *ctx;
1047 multi1 = FN(MULTI(BASE),cow)(multi1);
1048 if (!multi1 || !multi2)
1049 goto error;
1051 ctx = FN(MULTI(BASE),get_ctx)(multi1);
1052 if (!isl_space_is_equal(multi1->space, multi2->space))
1053 isl_die(ctx, isl_error_invalid,
1054 "spaces don't match", goto error);
1056 for (i = 0; i < multi1->n; ++i) {
1057 multi1->p[i] = fn(multi1->p[i], FN(EL,copy)(multi2->p[i]));
1058 if (!multi1->p[i])
1059 goto error;
1062 FN(MULTI(BASE),free)(multi2);
1063 return multi1;
1064 error:
1065 FN(MULTI(BASE),free)(multi1);
1066 FN(MULTI(BASE),free)(multi2);
1067 return NULL;
1070 /* Subtract "multi2" from "multi1" and return the result.
1072 * The parameters of "multi1" and "multi2" are assumed to have been aligned.
1074 static __isl_give MULTI(BASE) *FN(MULTI(BASE),sub_aligned)(
1075 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
1077 return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,sub));
1080 /* Subtract "multi2" from "multi1" and return the result.
1082 __isl_give MULTI(BASE) *FN(MULTI(BASE),sub)(__isl_take MULTI(BASE) *multi1,
1083 __isl_take MULTI(BASE) *multi2)
1085 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
1086 &FN(MULTI(BASE),sub_aligned));
1089 /* Multiply the elements of "multi" by "v" and return the result.
1091 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val)(__isl_take MULTI(BASE) *multi,
1092 __isl_take isl_val *v)
1094 int i;
1096 if (!multi || !v)
1097 goto error;
1099 if (isl_val_is_one(v)) {
1100 isl_val_free(v);
1101 return multi;
1104 if (!isl_val_is_rat(v))
1105 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1106 "expecting rational factor", goto error);
1108 multi = FN(MULTI(BASE),cow)(multi);
1109 if (!multi)
1110 return NULL;
1112 for (i = 0; i < multi->n; ++i) {
1113 multi->p[i] = FN(EL,scale_val)(multi->p[i], isl_val_copy(v));
1114 if (!multi->p[i])
1115 goto error;
1118 isl_val_free(v);
1119 return multi;
1120 error:
1121 isl_val_free(v);
1122 return FN(MULTI(BASE),free)(multi);
1125 /* Divide the elements of "multi" by "v" and return the result.
1127 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_val)(
1128 __isl_take MULTI(BASE) *multi, __isl_take isl_val *v)
1130 int i;
1132 if (!multi || !v)
1133 goto error;
1135 if (isl_val_is_one(v)) {
1136 isl_val_free(v);
1137 return multi;
1140 if (!isl_val_is_rat(v))
1141 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1142 "expecting rational factor", goto error);
1143 if (isl_val_is_zero(v))
1144 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1145 "cannot scale down by zero", goto error);
1147 multi = FN(MULTI(BASE),cow)(multi);
1148 if (!multi)
1149 return NULL;
1151 for (i = 0; i < multi->n; ++i) {
1152 multi->p[i] = FN(EL,scale_down_val)(multi->p[i],
1153 isl_val_copy(v));
1154 if (!multi->p[i])
1155 goto error;
1158 isl_val_free(v);
1159 return multi;
1160 error:
1161 isl_val_free(v);
1162 return FN(MULTI(BASE),free)(multi);
1165 /* Multiply the elements of "multi" by the corresponding element of "mv"
1166 * and return the result.
1168 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_multi_val)(
1169 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1171 int i;
1173 if (!multi || !mv)
1174 goto error;
1176 if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1177 mv->space, isl_dim_set))
1178 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1179 "spaces don't match", goto error);
1181 multi = FN(MULTI(BASE),cow)(multi);
1182 if (!multi)
1183 return NULL;
1185 for (i = 0; i < multi->n; ++i) {
1186 isl_val *v;
1188 v = isl_multi_val_get_val(mv, i);
1189 multi->p[i] = FN(EL,scale_val)(multi->p[i], v);
1190 if (!multi->p[i])
1191 goto error;
1194 isl_multi_val_free(mv);
1195 return multi;
1196 error:
1197 isl_multi_val_free(mv);
1198 return FN(MULTI(BASE),free)(multi);
1201 /* Divide the elements of "multi" by the corresponding element of "mv"
1202 * and return the result.
1204 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_multi_val)(
1205 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1207 int i;
1209 if (!multi || !mv)
1210 goto error;
1212 if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1213 mv->space, isl_dim_set))
1214 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1215 "spaces don't match", goto error);
1217 multi = FN(MULTI(BASE),cow)(multi);
1218 if (!multi)
1219 return NULL;
1221 for (i = 0; i < multi->n; ++i) {
1222 isl_val *v;
1224 v = isl_multi_val_get_val(mv, i);
1225 multi->p[i] = FN(EL,scale_down_val)(multi->p[i], v);
1226 if (!multi->p[i])
1227 goto error;
1230 isl_multi_val_free(mv);
1231 return multi;
1232 error:
1233 isl_multi_val_free(mv);
1234 return FN(MULTI(BASE),free)(multi);
1237 /* Compute the residues of the elements of "multi" modulo
1238 * the corresponding element of "mv" and return the result.
1240 __isl_give MULTI(BASE) *FN(MULTI(BASE),mod_multi_val)(
1241 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1243 int i;
1245 if (!multi || !mv)
1246 goto error;
1248 if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1249 mv->space, isl_dim_set))
1250 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1251 "spaces don't match", goto error);
1253 multi = FN(MULTI(BASE),cow)(multi);
1254 if (!multi)
1255 return NULL;
1257 for (i = 0; i < multi->n; ++i) {
1258 isl_val *v;
1260 v = isl_multi_val_get_val(mv, i);
1261 multi->p[i] = FN(EL,mod_val)(multi->p[i], v);
1262 if (!multi->p[i])
1263 goto error;
1266 isl_multi_val_free(mv);
1267 return multi;
1268 error:
1269 isl_multi_val_free(mv);
1270 return FN(MULTI(BASE),free)(multi);
1273 #ifndef NO_MOVE_DIMS
1274 /* Move the "n" dimensions of "src_type" starting at "src_pos" of "multi"
1275 * to dimensions of "dst_type" at "dst_pos".
1277 * We only support moving input dimensions to parameters and vice versa.
1279 __isl_give MULTI(BASE) *FN(MULTI(BASE),move_dims)(__isl_take MULTI(BASE) *multi,
1280 enum isl_dim_type dst_type, unsigned dst_pos,
1281 enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1283 int i;
1285 if (!multi)
1286 return NULL;
1288 if (n == 0 &&
1289 !isl_space_is_named_or_nested(multi->space, src_type) &&
1290 !isl_space_is_named_or_nested(multi->space, dst_type))
1291 return multi;
1293 if (dst_type == isl_dim_out || src_type == isl_dim_out)
1294 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1295 "cannot move output/set dimension",
1296 return FN(MULTI(BASE),free)(multi));
1297 if (dst_type == isl_dim_div || src_type == isl_dim_div)
1298 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1299 "cannot move divs",
1300 return FN(MULTI(BASE),free)(multi));
1301 if (src_pos + n > isl_space_dim(multi->space, src_type))
1302 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1303 "range out of bounds",
1304 return FN(MULTI(BASE),free)(multi));
1305 if (dst_type == src_type)
1306 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_unsupported,
1307 "moving dims within the same type not supported",
1308 return FN(MULTI(BASE),free)(multi));
1310 multi = FN(MULTI(BASE),cow)(multi);
1311 if (!multi)
1312 return NULL;
1314 multi->space = isl_space_move_dims(multi->space, dst_type, dst_pos,
1315 src_type, src_pos, n);
1316 if (!multi->space)
1317 return FN(MULTI(BASE),free)(multi);
1319 for (i = 0; i < multi->n; ++i) {
1320 multi->p[i] = FN(EL,move_dims)(multi->p[i], dst_type, dst_pos,
1321 src_type, src_pos, n);
1322 if (!multi->p[i])
1323 return FN(MULTI(BASE),free)(multi);
1326 return multi;
1328 #endif
1330 /* Convert a multiple expression defined over a parameter domain
1331 * into one that is defined over a zero-dimensional set.
1333 __isl_give MULTI(BASE) *FN(MULTI(BASE),from_range)(
1334 __isl_take MULTI(BASE) *multi)
1336 isl_space *space;
1338 if (!multi)
1339 return NULL;
1340 if (!isl_space_is_set(multi->space))
1341 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1342 "not living in a set space",
1343 return FN(MULTI(BASE),free)(multi));
1345 space = FN(MULTI(BASE),get_space)(multi);
1346 space = isl_space_from_range(space);
1347 multi = FN(MULTI(BASE),reset_space)(multi, space);
1349 return multi;
1352 /* Are "multi1" and "multi2" obviously equal?
1354 int FN(MULTI(BASE),plain_is_equal)(__isl_keep MULTI(BASE) *multi1,
1355 __isl_keep MULTI(BASE) *multi2)
1357 int i;
1358 int equal;
1360 if (!multi1 || !multi2)
1361 return -1;
1362 if (multi1->n != multi2->n)
1363 return 0;
1364 equal = isl_space_is_equal(multi1->space, multi2->space);
1365 if (equal < 0 || !equal)
1366 return equal;
1368 for (i = 0; i < multi1->n; ++i) {
1369 equal = FN(EL,plain_is_equal)(multi1->p[i], multi2->p[i]);
1370 if (equal < 0 || !equal)
1371 return equal;
1374 return 1;
1377 #ifndef NO_DOMAIN
1378 /* Return the shared domain of the elements of "multi".
1380 __isl_give isl_set *FN(MULTI(BASE),domain)(__isl_take MULTI(BASE) *multi)
1382 int i;
1383 isl_set *dom;
1385 if (!multi)
1386 return NULL;
1388 dom = isl_set_universe(FN(MULTI(BASE),get_domain_space)(multi));
1389 for (i = 0; i < multi->n; ++i) {
1390 isl_set *dom_i;
1392 dom_i = FN(EL,domain)(FN(FN(MULTI(BASE),get),BASE)(multi, i));
1393 dom = isl_set_intersect(dom, dom_i);
1396 FN(MULTI(BASE),free)(multi);
1397 return dom;
1399 #endif
1401 #ifndef NO_NEG
1402 /* Return the opposite of "multi".
1404 __isl_give MULTI(BASE) *FN(MULTI(BASE),neg)(__isl_take MULTI(BASE) *multi)
1406 int i;
1408 multi = FN(MULTI(BASE),cow)(multi);
1409 if (!multi)
1410 return NULL;
1412 for (i = 0; i < multi->n; ++i) {
1413 multi->p[i] = FN(EL,neg)(multi->p[i]);
1414 if (!multi->p[i])
1415 return FN(MULTI(BASE),free)(multi);
1418 return multi;
1420 #endif