isl_{map,set}_n_basic_{map,set}: return isl_size
[isl.git] / isl_multi_templ.c
blob1baaf4af17d8851699de7e9d2f6db3ccd709a08a
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/id.h>
12 #include <isl_space_private.h>
13 #include <isl_val_private.h>
14 #include <isl/set.h>
15 #include <isl_reordering.h>
17 #include <isl_multi_macro.h>
19 #define MULTI_NAME(BASE) "isl_multi_" #BASE
20 #define xLIST(EL) EL ## _list
21 #define LIST(EL) xLIST(EL)
23 isl_ctx *FN(MULTI(BASE),get_ctx)(__isl_keep MULTI(BASE) *multi)
25 return multi ? isl_space_get_ctx(multi->space) : NULL;
28 /* Return the space of "multi".
30 __isl_keep isl_space *FN(MULTI(BASE),peek_space)(__isl_keep MULTI(BASE) *multi)
32 return multi ? multi->space : NULL;
35 __isl_give isl_space *FN(MULTI(BASE),get_space)(__isl_keep MULTI(BASE) *multi)
37 return isl_space_copy(FN(MULTI(BASE),peek_space)(multi));
40 /* Return the position of the dimension of the given type and name
41 * in "multi".
42 * Return -1 if no such dimension can be found.
44 int FN(MULTI(BASE),find_dim_by_name)(__isl_keep MULTI(BASE) *multi,
45 enum isl_dim_type type, const char *name)
47 if (!multi)
48 return -1;
49 return isl_space_find_dim_by_name(multi->space, type, name);
52 __isl_give isl_space *FN(MULTI(BASE),get_domain_space)(
53 __isl_keep MULTI(BASE) *multi)
55 return multi ? isl_space_domain(isl_space_copy(multi->space)) : NULL;
58 /* Allocate a multi expression living in "space".
60 * If the number of base expressions is zero, then make sure
61 * there is enough room in the structure for the explicit domain,
62 * in case the type supports such an explicit domain.
64 __isl_give MULTI(BASE) *FN(MULTI(BASE),alloc)(__isl_take isl_space *space)
66 isl_ctx *ctx;
67 isl_size n;
68 MULTI(BASE) *multi;
70 n = isl_space_dim(space, isl_dim_out);
71 if (n < 0)
72 goto error;
74 ctx = isl_space_get_ctx(space);
75 if (n > 0)
76 multi = isl_calloc(ctx, MULTI(BASE),
77 sizeof(MULTI(BASE)) + (n - 1) * sizeof(struct EL *));
78 else
79 multi = isl_calloc(ctx, MULTI(BASE), sizeof(MULTI(BASE)));
80 if (!multi)
81 goto error;
83 multi->space = space;
84 multi->n = n;
85 multi->ref = 1;
86 if (FN(MULTI(BASE),has_explicit_domain)(multi))
87 multi = FN(MULTI(BASE),init_explicit_domain)(multi);
88 return multi;
89 error:
90 isl_space_free(space);
91 return NULL;
94 __isl_give MULTI(BASE) *FN(MULTI(BASE),dup)(__isl_keep MULTI(BASE) *multi)
96 int i;
97 MULTI(BASE) *dup;
99 if (!multi)
100 return NULL;
102 dup = FN(MULTI(BASE),alloc)(isl_space_copy(multi->space));
103 if (!dup)
104 return NULL;
106 for (i = 0; i < multi->n; ++i)
107 dup = FN(FN(MULTI(BASE),set),BASE)(dup, i,
108 FN(EL,copy)(multi->u.p[i]));
109 if (FN(MULTI(BASE),has_explicit_domain)(multi))
110 dup = FN(MULTI(BASE),copy_explicit_domain)(dup, multi);
112 return dup;
115 __isl_give MULTI(BASE) *FN(MULTI(BASE),cow)(__isl_take MULTI(BASE) *multi)
117 if (!multi)
118 return NULL;
120 if (multi->ref == 1)
121 return multi;
123 multi->ref--;
124 return FN(MULTI(BASE),dup)(multi);
127 __isl_give MULTI(BASE) *FN(MULTI(BASE),copy)(__isl_keep MULTI(BASE) *multi)
129 if (!multi)
130 return NULL;
132 multi->ref++;
133 return multi;
136 __isl_null MULTI(BASE) *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi)
138 int i;
140 if (!multi)
141 return NULL;
143 if (--multi->ref > 0)
144 return NULL;
146 isl_space_free(multi->space);
147 for (i = 0; i < multi->n; ++i)
148 FN(EL,free)(multi->u.p[i]);
149 if (FN(MULTI(BASE),has_explicit_domain)(multi))
150 FN(MULTI(BASE),free_explicit_domain)(multi);
151 free(multi);
153 return NULL;
156 isl_size FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi,
157 enum isl_dim_type type)
159 return isl_space_dim(FN(MULTI(BASE),peek_space)(multi), type);
162 /* Return the position of the first dimension of "type" with id "id".
163 * Return -1 if there is no such dimension.
165 int FN(MULTI(BASE),find_dim_by_id)(__isl_keep MULTI(BASE) *multi,
166 enum isl_dim_type type, __isl_keep isl_id *id)
168 if (!multi)
169 return -1;
170 return isl_space_find_dim_by_id(multi->space, type, id);
173 /* Return the id of the given dimension.
175 __isl_give isl_id *FN(MULTI(BASE),get_dim_id)(__isl_keep MULTI(BASE) *multi,
176 enum isl_dim_type type, unsigned pos)
178 return multi ? isl_space_get_dim_id(multi->space, type, pos) : NULL;
181 __isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_name)(
182 __isl_take MULTI(BASE) *multi,
183 enum isl_dim_type type, unsigned pos, const char *s)
185 int i;
187 multi = FN(MULTI(BASE),cow)(multi);
188 if (!multi)
189 return NULL;
191 multi->space = isl_space_set_dim_name(multi->space, type, pos, s);
192 if (!multi->space)
193 return FN(MULTI(BASE),free)(multi);
195 if (type == isl_dim_out)
196 return multi;
197 for (i = 0; i < multi->n; ++i) {
198 multi->u.p[i] = FN(EL,set_dim_name)(multi->u.p[i],
199 type, pos, s);
200 if (!multi->u.p[i])
201 return FN(MULTI(BASE),free)(multi);
204 return multi;
207 const char *FN(MULTI(BASE),get_tuple_name)(__isl_keep MULTI(BASE) *multi,
208 enum isl_dim_type type)
210 return multi ? isl_space_get_tuple_name(multi->space, type) : NULL;
213 /* Does the specified tuple have an id?
215 isl_bool FN(MULTI(BASE),has_tuple_id)(__isl_keep MULTI(BASE) *multi,
216 enum isl_dim_type type)
218 if (!multi)
219 return isl_bool_error;
220 return isl_space_has_tuple_id(multi->space, type);
223 /* Return the id of the specified tuple.
225 __isl_give isl_id *FN(MULTI(BASE),get_tuple_id)(__isl_keep MULTI(BASE) *multi,
226 enum isl_dim_type type)
228 return multi ? isl_space_get_tuple_id(multi->space, type) : NULL;
231 #undef TYPE
232 #define TYPE MULTI(BASE)
233 static
234 #include "check_type_range_templ.c"
236 __isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi,
237 int pos)
239 isl_ctx *ctx;
241 if (FN(MULTI(BASE),check_range)(multi, isl_dim_out, pos, 1) < 0)
242 return NULL;
243 ctx = FN(MULTI(BASE),get_ctx)(multi);
244 return FN(EL,copy)(multi->u.p[pos]);
247 /* Set the element at position "pos" of "multi" to "el",
248 * where the position may be empty if "multi" has only a single reference.
250 static __isl_give MULTI(BASE) *FN(MULTI(BASE),restore)(
251 __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
253 multi = FN(MULTI(BASE),cow)(multi);
254 if (!multi || !el)
255 goto error;
257 if (FN(MULTI(BASE),check_range)(multi, isl_dim_out, pos, 1) < 0)
258 goto error;
260 FN(EL,free)(multi->u.p[pos]);
261 multi->u.p[pos] = el;
263 return multi;
264 error:
265 FN(MULTI(BASE),free)(multi);
266 FN(EL,free)(el);
267 return NULL;
270 /* Set the element at position "pos" of "multi" to "el",
271 * where the position may be empty if "multi" has only a single reference.
272 * However, the space of "multi" is available and is checked
273 * for compatibility with "el".
275 static __isl_give MULTI(BASE) *FN(MULTI(BASE),restore_check_space)(
276 __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
278 isl_space *space;
280 space = FN(MULTI(BASE),peek_space)(multi);
281 if (FN(EL,check_match_domain_space)(el, space) < 0)
282 multi = FN(MULTI(BASE),free)(multi);
283 return FN(MULTI(BASE),restore)(multi, pos, el);
286 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)(
287 __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
289 isl_space *multi_space = NULL;
290 isl_space *el_space = NULL;
291 isl_bool match;
293 multi_space = FN(MULTI(BASE),get_space)(multi);
294 match = FN(EL,matching_params)(el, multi_space);
295 if (match < 0)
296 goto error;
297 if (!match) {
298 multi = FN(MULTI(BASE),align_params)(multi,
299 FN(EL,get_space)(el));
300 isl_space_free(multi_space);
301 multi_space = FN(MULTI(BASE),get_space)(multi);
302 el = FN(EL,align_params)(el, isl_space_copy(multi_space));
305 multi = FN(MULTI(BASE),restore_check_space)(multi, pos, el);
307 isl_space_free(multi_space);
308 isl_space_free(el_space);
310 return multi;
311 error:
312 FN(MULTI(BASE),free)(multi);
313 FN(EL,free)(el);
314 isl_space_free(multi_space);
315 isl_space_free(el_space);
316 return NULL;
319 /* Reset the space of "multi". This function is called from isl_pw_templ.c
320 * and doesn't know if the space of an element object is represented
321 * directly or through its domain. It therefore passes along both,
322 * which we pass along to the element function since we don't know how
323 * that is represented either.
325 * If "multi" has an explicit domain, then the caller is expected
326 * to make sure that any modification that would change the dimensions
327 * of the explicit domain has bee applied before this function is called.
329 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space_and_domain)(
330 __isl_take MULTI(BASE) *multi, __isl_take isl_space *space,
331 __isl_take isl_space *domain)
333 int i;
335 multi = FN(MULTI(BASE),cow)(multi);
336 if (!multi || !space || !domain)
337 goto error;
339 for (i = 0; i < multi->n; ++i) {
340 multi->u.p[i] = FN(EL,reset_domain_space)(multi->u.p[i],
341 isl_space_copy(domain));
342 if (!multi->u.p[i])
343 goto error;
345 if (FN(MULTI(BASE),has_explicit_domain)(multi)) {
346 multi = FN(MULTI(BASE),reset_explicit_domain_space)(multi,
347 isl_space_copy(domain));
348 if (!multi)
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;
479 isl_space *space;
481 multi = FN(MULTI(BASE),cow)(multi);
482 if (!multi || !exp)
483 goto error;
485 for (i = 0; i < multi->n; ++i) {
486 multi->u.p[i] = FN(EL,realign_domain)(multi->u.p[i],
487 isl_reordering_copy(exp));
488 if (!multi->u.p[i])
489 goto error;
492 space = isl_reordering_get_space(exp);
493 multi = FN(MULTI(BASE),reset_domain_space)(multi, space);
495 isl_reordering_free(exp);
496 return multi;
497 error:
498 isl_reordering_free(exp);
499 FN(MULTI(BASE),free)(multi);
500 return NULL;
503 /* Align the parameters of "multi" to those of "model".
505 * If "multi" has an explicit domain, then align the parameters
506 * of the domain first.
508 __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)(
509 __isl_take MULTI(BASE) *multi, __isl_take isl_space *model)
511 isl_ctx *ctx;
512 isl_bool equal_params;
513 isl_reordering *exp;
515 if (!multi || !model)
516 goto error;
518 equal_params = isl_space_has_equal_params(multi->space, model);
519 if (equal_params < 0)
520 goto error;
521 if (equal_params) {
522 isl_space_free(model);
523 return multi;
526 ctx = isl_space_get_ctx(model);
527 if (!isl_space_has_named_params(model))
528 isl_die(ctx, isl_error_invalid,
529 "model has unnamed parameters", goto error);
530 if (!isl_space_has_named_params(multi->space))
531 isl_die(ctx, isl_error_invalid,
532 "input has unnamed parameters", goto error);
534 if (FN(MULTI(BASE),has_explicit_domain)(multi)) {
535 multi = FN(MULTI(BASE),align_explicit_domain_params)(multi,
536 isl_space_copy(model));
537 if (!multi)
538 goto error;
540 exp = isl_parameter_alignment_reordering(multi->space, model);
541 exp = isl_reordering_extend_space(exp,
542 FN(MULTI(BASE),get_domain_space)(multi));
543 multi = FN(MULTI(BASE),realign_domain)(multi, exp);
545 isl_space_free(model);
546 return multi;
547 error:
548 isl_space_free(model);
549 FN(MULTI(BASE),free)(multi);
550 return NULL;
553 /* Create a multi expression in the given space with the elements of "list"
554 * as base expressions.
556 * Since isl_multi_*_restore_* assumes that the element and
557 * the multi expression have matching spaces, the alignment
558 * (if any) needs to be performed beforehand.
560 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))(
561 __isl_take isl_space *space, __isl_take LIST(EL) *list)
563 int i;
564 int n;
565 isl_size dim;
566 isl_ctx *ctx;
567 MULTI(BASE) *multi;
569 dim = isl_space_dim(space, isl_dim_out);
570 if (dim < 0 || !list)
571 goto error;
573 ctx = isl_space_get_ctx(space);
574 n = FN(FN(LIST(EL),n),BASE)(list);
575 if (n != dim)
576 isl_die(ctx, isl_error_invalid,
577 "invalid number of elements in list", goto error);
579 for (i = 0; i < n; ++i) {
580 EL *el = FN(LIST(EL),peek)(list, i);
581 space = isl_space_align_params(space, FN(EL,get_space)(el));
583 multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
584 for (i = 0; i < n; ++i) {
585 EL *el = FN(FN(LIST(EL),get),BASE)(list, i);
586 el = FN(EL,align_params)(el, isl_space_copy(space));
587 multi = FN(MULTI(BASE),restore_check_space)(multi, i, el);
590 isl_space_free(space);
591 FN(LIST(EL),free)(list);
592 return multi;
593 error:
594 isl_space_free(space);
595 FN(LIST(EL),free)(list);
596 return NULL;
599 __isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)(
600 __isl_take MULTI(BASE) *multi,
601 enum isl_dim_type type, unsigned first, unsigned n)
603 int i;
605 multi = FN(MULTI(BASE),cow)(multi);
606 if (FN(MULTI(BASE),check_range)(multi, type, first, n) < 0)
607 return FN(MULTI(BASE),free)(multi);
609 multi->space = isl_space_drop_dims(multi->space, type, first, n);
610 if (!multi->space)
611 return FN(MULTI(BASE),free)(multi);
613 if (type == isl_dim_out) {
614 for (i = 0; i < n; ++i)
615 FN(EL,free)(multi->u.p[first + i]);
616 for (i = first; i + n < multi->n; ++i)
617 multi->u.p[i] = multi->u.p[i + n];
618 multi->n -= n;
619 if (n > 0 && FN(MULTI(BASE),has_explicit_domain)(multi))
620 multi = FN(MULTI(BASE),init_explicit_domain)(multi);
622 return multi;
625 if (FN(MULTI(BASE),has_explicit_domain)(multi))
626 multi = FN(MULTI(BASE),drop_explicit_domain_dims)(multi,
627 type, first, n);
628 if (!multi)
629 return NULL;
631 for (i = 0; i < multi->n; ++i) {
632 multi->u.p[i] = FN(EL,drop_dims)(multi->u.p[i], type, first, n);
633 if (!multi->u.p[i])
634 return FN(MULTI(BASE),free)(multi);
637 return multi;
640 /* Align the parameters of "multi1" and "multi2" (if needed) and call "fn".
642 static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_multi_and)(
643 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
644 __isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi1,
645 __isl_take MULTI(BASE) *multi2))
647 isl_ctx *ctx;
648 isl_bool equal_params;
650 if (!multi1 || !multi2)
651 goto error;
652 equal_params = isl_space_has_equal_params(multi1->space, multi2->space);
653 if (equal_params < 0)
654 goto error;
655 if (equal_params)
656 return fn(multi1, multi2);
657 ctx = FN(MULTI(BASE),get_ctx)(multi1);
658 if (!isl_space_has_named_params(multi1->space) ||
659 !isl_space_has_named_params(multi2->space))
660 isl_die(ctx, isl_error_invalid,
661 "unaligned unnamed parameters", goto error);
662 multi1 = FN(MULTI(BASE),align_params)(multi1,
663 FN(MULTI(BASE),get_space)(multi2));
664 multi2 = FN(MULTI(BASE),align_params)(multi2,
665 FN(MULTI(BASE),get_space)(multi1));
666 return fn(multi1, multi2);
667 error:
668 FN(MULTI(BASE),free)(multi1);
669 FN(MULTI(BASE),free)(multi2);
670 return NULL;
673 /* Given two MULTI(BASE)s A -> B and C -> D,
674 * construct a MULTI(BASE) (A * C) -> [B -> D].
676 * The parameters are assumed to have been aligned.
678 * If "multi1" and/or "multi2" has an explicit domain, then
679 * intersect the domain of the result with these explicit domains.
681 static __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product_aligned)(
682 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
684 int i;
685 isl_size n1, n2;
686 EL *el;
687 isl_space *space;
688 MULTI(BASE) *res;
690 n1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
691 n2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
692 if (n1 < 0 || n2 < 0)
693 goto error;
695 space = isl_space_range_product(FN(MULTI(BASE),get_space)(multi1),
696 FN(MULTI(BASE),get_space)(multi2));
697 res = FN(MULTI(BASE),alloc)(space);
699 for (i = 0; i < n1; ++i) {
700 el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
701 res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
704 for (i = 0; i < n2; ++i) {
705 el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
706 res = FN(FN(MULTI(BASE),set),BASE)(res, n1 + i, el);
709 if (FN(MULTI(BASE),has_explicit_domain)(multi1))
710 res = FN(MULTI(BASE),intersect_explicit_domain)(res, multi1);
711 if (FN(MULTI(BASE),has_explicit_domain)(multi2))
712 res = FN(MULTI(BASE),intersect_explicit_domain)(res, multi2);
714 FN(MULTI(BASE),free)(multi1);
715 FN(MULTI(BASE),free)(multi2);
716 return res;
717 error:
718 FN(MULTI(BASE),free)(multi1);
719 FN(MULTI(BASE),free)(multi2);
720 return NULL;
723 /* Given two MULTI(BASE)s A -> B and C -> D,
724 * construct a MULTI(BASE) (A * C) -> [B -> D].
726 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)(
727 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
729 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
730 &FN(MULTI(BASE),range_product_aligned));
733 /* Is the range of "multi" a wrapped relation?
735 isl_bool FN(MULTI(BASE),range_is_wrapping)(__isl_keep MULTI(BASE) *multi)
737 if (!multi)
738 return isl_bool_error;
739 return isl_space_range_is_wrapping(multi->space);
742 /* Given a function A -> [B -> C], extract the function A -> B.
744 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_domain)(
745 __isl_take MULTI(BASE) *multi)
747 isl_space *space;
748 isl_size total, keep;
750 total = FN(MULTI(BASE),dim)(multi, isl_dim_out);
751 if (total < 0)
752 return FN(MULTI(BASE),free)(multi);
753 if (!isl_space_range_is_wrapping(multi->space))
754 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
755 "range is not a product",
756 return FN(MULTI(BASE),free)(multi));
758 space = FN(MULTI(BASE),get_space)(multi);
759 space = isl_space_range_factor_domain(space);
760 keep = isl_space_dim(space, isl_dim_out);
761 if (keep < 0)
762 multi = FN(MULTI(BASE),free)(multi);
763 multi = FN(MULTI(BASE),drop_dims)(multi,
764 isl_dim_out, keep, total - keep);
765 multi = FN(MULTI(BASE),reset_space)(multi, space);
767 return multi;
770 /* Given a function A -> [B -> C], extract the function A -> C.
772 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_range)(
773 __isl_take MULTI(BASE) *multi)
775 isl_space *space;
776 isl_size total, keep;
778 total = FN(MULTI(BASE),dim)(multi, isl_dim_out);
779 if (total < 0)
780 return FN(MULTI(BASE),free)(multi);
781 if (!isl_space_range_is_wrapping(multi->space))
782 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
783 "range is not a product",
784 return FN(MULTI(BASE),free)(multi));
786 space = FN(MULTI(BASE),get_space)(multi);
787 space = isl_space_range_factor_range(space);
788 keep = isl_space_dim(space, isl_dim_out);
789 if (keep < 0)
790 multi = FN(MULTI(BASE),free)(multi);
791 multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
792 multi = FN(MULTI(BASE),reset_space)(multi, space);
794 return multi;
797 /* Given a function [B -> C], extract the function C.
799 __isl_give MULTI(BASE) *FN(MULTI(BASE),factor_range)(
800 __isl_take MULTI(BASE) *multi)
802 isl_space *space;
803 isl_size total, keep;
805 total = FN(MULTI(BASE),dim)(multi, isl_dim_set);
806 if (total < 0)
807 return FN(MULTI(BASE),free)(multi);
808 if (!isl_space_is_wrapping(multi->space))
809 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
810 "not a product", return FN(MULTI(BASE),free)(multi));
812 space = FN(MULTI(BASE),get_space)(multi);
813 space = isl_space_factor_range(space);
814 keep = isl_space_dim(space, isl_dim_set);
815 if (keep < 0)
816 multi = FN(MULTI(BASE),free)(multi);
817 multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_set, 0, total - keep);
818 multi = FN(MULTI(BASE),reset_space)(multi, space);
820 return multi;
823 __isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)(
824 __isl_take MULTI(BASE) *multi)
826 if (!multi)
827 return NULL;
829 if (!multi->space->nested[1])
830 return multi;
832 multi = FN(MULTI(BASE),cow)(multi);
833 if (!multi)
834 return NULL;
836 multi->space = isl_space_flatten_range(multi->space);
837 if (!multi->space)
838 return FN(MULTI(BASE),free)(multi);
840 return multi;
843 /* Given two MULTI(BASE)s A -> B and C -> D,
844 * construct a MULTI(BASE) (A * C) -> (B, D).
846 __isl_give MULTI(BASE) *FN(MULTI(BASE),flat_range_product)(
847 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
849 MULTI(BASE) *multi;
851 multi = FN(MULTI(BASE),range_product)(multi1, multi2);
852 multi = FN(MULTI(BASE),flatten_range)(multi);
853 return multi;
856 /* Given two multi expressions, "multi1"
858 * [A] -> [B1 B2]
860 * where B2 starts at position "pos", and "multi2"
862 * [A] -> [D]
864 * return the multi expression
866 * [A] -> [B1 D B2]
868 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_splice)(
869 __isl_take MULTI(BASE) *multi1, unsigned pos,
870 __isl_take MULTI(BASE) *multi2)
872 MULTI(BASE) *res;
873 isl_size dim;
875 dim = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
876 if (dim < 0 || !multi2)
877 goto error;
879 if (FN(MULTI(BASE),check_range)(multi1, isl_dim_out, pos, 0) < 0)
880 goto error;
882 res = FN(MULTI(BASE),copy)(multi1);
883 res = FN(MULTI(BASE),drop_dims)(res, isl_dim_out, pos, dim - pos);
884 multi1 = FN(MULTI(BASE),drop_dims)(multi1, isl_dim_out, 0, pos);
886 res = FN(MULTI(BASE),flat_range_product)(res, multi2);
887 res = FN(MULTI(BASE),flat_range_product)(res, multi1);
889 return res;
890 error:
891 FN(MULTI(BASE),free)(multi1);
892 FN(MULTI(BASE),free)(multi2);
893 return NULL;
896 /* Check that "multi1" and "multi2" live in the same space,
897 * reporting an error if they do not.
899 static isl_stat FN(MULTI(BASE),check_equal_space)(
900 __isl_keep MULTI(BASE) *multi1, __isl_keep MULTI(BASE) *multi2)
902 isl_bool equal;
904 if (!multi1 || !multi2)
905 return isl_stat_error;
907 equal = isl_space_is_equal(multi1->space, multi2->space);
908 if (equal < 0)
909 return isl_stat_error;
910 if (!equal)
911 isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
912 "spaces don't match", return isl_stat_error);
914 return isl_stat_ok;
917 /* This function is currently only used from isl_aff.c
919 static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
920 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
921 __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
922 __attribute__ ((unused));
924 /* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
925 * return the result.
927 * If "multi2" has an explicit domain, then
928 * intersect the domain of the result with this explicit domain.
930 static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
931 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
932 __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
934 int i;
936 multi1 = FN(MULTI(BASE),cow)(multi1);
937 if (FN(MULTI(BASE),check_equal_space)(multi1, multi2) < 0)
938 goto error;
940 for (i = 0; i < multi1->n; ++i) {
941 multi1->u.p[i] = fn(multi1->u.p[i],
942 FN(EL,copy)(multi2->u.p[i]));
943 if (!multi1->u.p[i])
944 goto error;
947 if (FN(MULTI(BASE),has_explicit_domain)(multi2))
948 multi1 = FN(MULTI(BASE),intersect_explicit_domain)(multi1,
949 multi2);
951 FN(MULTI(BASE),free)(multi2);
952 return multi1;
953 error:
954 FN(MULTI(BASE),free)(multi1);
955 FN(MULTI(BASE),free)(multi2);
956 return NULL;
959 /* Add "multi2" to "multi1" and return the result.
961 * The parameters of "multi1" and "multi2" are assumed to have been aligned.
963 static __isl_give MULTI(BASE) *FN(MULTI(BASE),add_aligned)(
964 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
966 return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,add));
969 /* Add "multi2" to "multi1" and return the result.
971 __isl_give MULTI(BASE) *FN(MULTI(BASE),add)(__isl_take MULTI(BASE) *multi1,
972 __isl_take MULTI(BASE) *multi2)
974 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
975 &FN(MULTI(BASE),add_aligned));
978 /* Subtract "multi2" from "multi1" and return the result.
980 * The parameters of "multi1" and "multi2" are assumed to have been aligned.
982 static __isl_give MULTI(BASE) *FN(MULTI(BASE),sub_aligned)(
983 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
985 return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,sub));
988 /* Subtract "multi2" from "multi1" and return the result.
990 __isl_give MULTI(BASE) *FN(MULTI(BASE),sub)(__isl_take MULTI(BASE) *multi1,
991 __isl_take MULTI(BASE) *multi2)
993 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
994 &FN(MULTI(BASE),sub_aligned));
997 /* Multiply the elements of "multi" by "v" and return the result.
999 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val)(__isl_take MULTI(BASE) *multi,
1000 __isl_take isl_val *v)
1002 int i;
1004 if (!multi || !v)
1005 goto error;
1007 if (isl_val_is_one(v)) {
1008 isl_val_free(v);
1009 return multi;
1012 if (!isl_val_is_rat(v))
1013 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1014 "expecting rational factor", goto error);
1016 multi = FN(MULTI(BASE),cow)(multi);
1017 if (!multi)
1018 return NULL;
1020 for (i = 0; i < multi->n; ++i) {
1021 multi->u.p[i] = FN(EL,scale_val)(multi->u.p[i],
1022 isl_val_copy(v));
1023 if (!multi->u.p[i])
1024 goto error;
1027 isl_val_free(v);
1028 return multi;
1029 error:
1030 isl_val_free(v);
1031 return FN(MULTI(BASE),free)(multi);
1034 /* Divide the elements of "multi" by "v" and return the result.
1036 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_val)(
1037 __isl_take MULTI(BASE) *multi, __isl_take isl_val *v)
1039 int i;
1041 if (!multi || !v)
1042 goto error;
1044 if (isl_val_is_one(v)) {
1045 isl_val_free(v);
1046 return multi;
1049 if (!isl_val_is_rat(v))
1050 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1051 "expecting rational factor", goto error);
1052 if (isl_val_is_zero(v))
1053 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1054 "cannot scale down by zero", goto error);
1056 multi = FN(MULTI(BASE),cow)(multi);
1057 if (!multi)
1058 return NULL;
1060 for (i = 0; i < multi->n; ++i) {
1061 multi->u.p[i] = FN(EL,scale_down_val)(multi->u.p[i],
1062 isl_val_copy(v));
1063 if (!multi->u.p[i])
1064 goto error;
1067 isl_val_free(v);
1068 return multi;
1069 error:
1070 isl_val_free(v);
1071 return FN(MULTI(BASE),free)(multi);
1074 /* Multiply the elements of "multi" by the corresponding element of "mv"
1075 * and return the result.
1077 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_multi_val)(
1078 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1080 int i;
1082 if (!multi || !mv)
1083 goto error;
1085 if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1086 mv->space, isl_dim_set))
1087 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1088 "spaces don't match", goto error);
1090 multi = FN(MULTI(BASE),cow)(multi);
1091 if (!multi)
1092 goto error;
1094 for (i = 0; i < multi->n; ++i) {
1095 isl_val *v;
1097 v = isl_multi_val_get_val(mv, i);
1098 multi->u.p[i] = FN(EL,scale_val)(multi->u.p[i], v);
1099 if (!multi->u.p[i])
1100 goto error;
1103 isl_multi_val_free(mv);
1104 return multi;
1105 error:
1106 isl_multi_val_free(mv);
1107 return FN(MULTI(BASE),free)(multi);
1110 /* Divide the elements of "multi" by the corresponding element of "mv"
1111 * and return the result.
1113 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_multi_val)(
1114 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1116 int i;
1118 if (!multi || !mv)
1119 goto error;
1121 if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1122 mv->space, isl_dim_set))
1123 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1124 "spaces don't match", goto error);
1126 multi = FN(MULTI(BASE),cow)(multi);
1127 if (!multi)
1128 return NULL;
1130 for (i = 0; i < multi->n; ++i) {
1131 isl_val *v;
1133 v = isl_multi_val_get_val(mv, i);
1134 multi->u.p[i] = FN(EL,scale_down_val)(multi->u.p[i], v);
1135 if (!multi->u.p[i])
1136 goto error;
1139 isl_multi_val_free(mv);
1140 return multi;
1141 error:
1142 isl_multi_val_free(mv);
1143 return FN(MULTI(BASE),free)(multi);
1146 /* Compute the residues of the elements of "multi" modulo
1147 * the corresponding element of "mv" and return the result.
1149 __isl_give MULTI(BASE) *FN(MULTI(BASE),mod_multi_val)(
1150 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1152 int i;
1154 if (!multi || !mv)
1155 goto error;
1157 if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1158 mv->space, isl_dim_set))
1159 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1160 "spaces don't match", goto error);
1162 multi = FN(MULTI(BASE),cow)(multi);
1163 if (!multi)
1164 goto error;
1166 for (i = 0; i < multi->n; ++i) {
1167 isl_val *v;
1169 v = isl_multi_val_get_val(mv, i);
1170 multi->u.p[i] = FN(EL,mod_val)(multi->u.p[i], v);
1171 if (!multi->u.p[i])
1172 goto error;
1175 isl_multi_val_free(mv);
1176 return multi;
1177 error:
1178 isl_multi_val_free(mv);
1179 return FN(MULTI(BASE),free)(multi);
1182 /* Convert a multiple expression defined over a parameter domain
1183 * into one that is defined over a zero-dimensional set.
1185 __isl_give MULTI(BASE) *FN(MULTI(BASE),from_range)(
1186 __isl_take MULTI(BASE) *multi)
1188 isl_space *space;
1190 if (!multi)
1191 return NULL;
1192 if (!isl_space_is_set(multi->space))
1193 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1194 "not living in a set space",
1195 return FN(MULTI(BASE),free)(multi));
1197 space = FN(MULTI(BASE),get_space)(multi);
1198 space = isl_space_from_range(space);
1199 multi = FN(MULTI(BASE),reset_space)(multi, space);
1201 return multi;
1204 /* Are "multi1" and "multi2" obviously equal?
1206 isl_bool FN(MULTI(BASE),plain_is_equal)(__isl_keep MULTI(BASE) *multi1,
1207 __isl_keep MULTI(BASE) *multi2)
1209 int i;
1210 isl_bool equal;
1212 if (!multi1 || !multi2)
1213 return isl_bool_error;
1214 if (multi1->n != multi2->n)
1215 return isl_bool_false;
1216 equal = isl_space_is_equal(multi1->space, multi2->space);
1217 if (equal < 0 || !equal)
1218 return equal;
1220 for (i = 0; i < multi1->n; ++i) {
1221 equal = FN(EL,plain_is_equal)(multi1->u.p[i], multi2->u.p[i]);
1222 if (equal < 0 || !equal)
1223 return equal;
1226 if (FN(MULTI(BASE),has_explicit_domain)(multi1) ||
1227 FN(MULTI(BASE),has_explicit_domain)(multi2)) {
1228 equal = FN(MULTI(BASE),equal_explicit_domain)(multi1, multi2);
1229 if (equal < 0 || !equal)
1230 return equal;
1233 return isl_bool_true;
1236 /* Does "multi" involve any NaNs?
1238 isl_bool FN(MULTI(BASE),involves_nan)(__isl_keep MULTI(BASE) *multi)
1240 int i;
1242 if (!multi)
1243 return isl_bool_error;
1244 if (multi->n == 0)
1245 return isl_bool_false;
1247 for (i = 0; i < multi->n; ++i) {
1248 isl_bool has_nan = FN(EL,involves_nan)(multi->u.p[i]);
1249 if (has_nan < 0 || has_nan)
1250 return has_nan;
1253 return isl_bool_false;
1256 /* Return the opposite of "multi".
1258 __isl_give MULTI(BASE) *FN(MULTI(BASE),neg)(__isl_take MULTI(BASE) *multi)
1260 int i;
1262 multi = FN(MULTI(BASE),cow)(multi);
1263 if (!multi)
1264 return NULL;
1266 for (i = 0; i < multi->n; ++i) {
1267 multi->u.p[i] = FN(EL,neg)(multi->u.p[i]);
1268 if (!multi->u.p[i])
1269 return FN(MULTI(BASE),free)(multi);
1272 return multi;