clean up isl_basic_set_variable_compression_with_id
[isl.git] / isl_multi_templ.c
blob81e6d1c89fa54e7d16f6925e0832cc6fc56fa153
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 isl_size n, dim;
565 isl_ctx *ctx;
566 MULTI(BASE) *multi;
568 dim = isl_space_dim(space, isl_dim_out);
569 n = FN(FN(LIST(EL),n),BASE)(list);
570 if (dim < 0 || n < 0)
571 goto error;
573 ctx = isl_space_get_ctx(space);
574 if (n != dim)
575 isl_die(ctx, isl_error_invalid,
576 "invalid number of elements in list", goto error);
578 for (i = 0; i < n; ++i) {
579 EL *el = FN(LIST(EL),peek)(list, i);
580 space = isl_space_align_params(space, FN(EL,get_space)(el));
582 multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
583 for (i = 0; i < n; ++i) {
584 EL *el = FN(FN(LIST(EL),get),BASE)(list, i);
585 el = FN(EL,align_params)(el, isl_space_copy(space));
586 multi = FN(MULTI(BASE),restore_check_space)(multi, i, el);
589 isl_space_free(space);
590 FN(LIST(EL),free)(list);
591 return multi;
592 error:
593 isl_space_free(space);
594 FN(LIST(EL),free)(list);
595 return NULL;
598 __isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)(
599 __isl_take MULTI(BASE) *multi,
600 enum isl_dim_type type, unsigned first, unsigned n)
602 int i;
604 multi = FN(MULTI(BASE),cow)(multi);
605 if (FN(MULTI(BASE),check_range)(multi, type, first, n) < 0)
606 return FN(MULTI(BASE),free)(multi);
608 multi->space = isl_space_drop_dims(multi->space, type, first, n);
609 if (!multi->space)
610 return FN(MULTI(BASE),free)(multi);
612 if (type == isl_dim_out) {
613 for (i = 0; i < n; ++i)
614 FN(EL,free)(multi->u.p[first + i]);
615 for (i = first; i + n < multi->n; ++i)
616 multi->u.p[i] = multi->u.p[i + n];
617 multi->n -= n;
618 if (n > 0 && FN(MULTI(BASE),has_explicit_domain)(multi))
619 multi = FN(MULTI(BASE),init_explicit_domain)(multi);
621 return multi;
624 if (FN(MULTI(BASE),has_explicit_domain)(multi))
625 multi = FN(MULTI(BASE),drop_explicit_domain_dims)(multi,
626 type, first, n);
627 if (!multi)
628 return NULL;
630 for (i = 0; i < multi->n; ++i) {
631 multi->u.p[i] = FN(EL,drop_dims)(multi->u.p[i], type, first, n);
632 if (!multi->u.p[i])
633 return FN(MULTI(BASE),free)(multi);
636 return multi;
639 /* Align the parameters of "multi1" and "multi2" (if needed) and call "fn".
641 static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_multi_and)(
642 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
643 __isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi1,
644 __isl_take MULTI(BASE) *multi2))
646 isl_ctx *ctx;
647 isl_bool equal_params;
649 if (!multi1 || !multi2)
650 goto error;
651 equal_params = isl_space_has_equal_params(multi1->space, multi2->space);
652 if (equal_params < 0)
653 goto error;
654 if (equal_params)
655 return fn(multi1, multi2);
656 ctx = FN(MULTI(BASE),get_ctx)(multi1);
657 if (!isl_space_has_named_params(multi1->space) ||
658 !isl_space_has_named_params(multi2->space))
659 isl_die(ctx, isl_error_invalid,
660 "unaligned unnamed parameters", goto error);
661 multi1 = FN(MULTI(BASE),align_params)(multi1,
662 FN(MULTI(BASE),get_space)(multi2));
663 multi2 = FN(MULTI(BASE),align_params)(multi2,
664 FN(MULTI(BASE),get_space)(multi1));
665 return fn(multi1, multi2);
666 error:
667 FN(MULTI(BASE),free)(multi1);
668 FN(MULTI(BASE),free)(multi2);
669 return NULL;
672 /* Given two MULTI(BASE)s A -> B and C -> D,
673 * construct a MULTI(BASE) (A * C) -> [B -> D].
675 * The parameters are assumed to have been aligned.
677 * If "multi1" and/or "multi2" has an explicit domain, then
678 * intersect the domain of the result with these explicit domains.
680 static __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product_aligned)(
681 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
683 int i;
684 isl_size n1, n2;
685 EL *el;
686 isl_space *space;
687 MULTI(BASE) *res;
689 n1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
690 n2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
691 if (n1 < 0 || n2 < 0)
692 goto error;
694 space = isl_space_range_product(FN(MULTI(BASE),get_space)(multi1),
695 FN(MULTI(BASE),get_space)(multi2));
696 res = FN(MULTI(BASE),alloc)(space);
698 for (i = 0; i < n1; ++i) {
699 el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
700 res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
703 for (i = 0; i < n2; ++i) {
704 el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
705 res = FN(FN(MULTI(BASE),set),BASE)(res, n1 + i, el);
708 if (FN(MULTI(BASE),has_explicit_domain)(multi1))
709 res = FN(MULTI(BASE),intersect_explicit_domain)(res, multi1);
710 if (FN(MULTI(BASE),has_explicit_domain)(multi2))
711 res = FN(MULTI(BASE),intersect_explicit_domain)(res, multi2);
713 FN(MULTI(BASE),free)(multi1);
714 FN(MULTI(BASE),free)(multi2);
715 return res;
716 error:
717 FN(MULTI(BASE),free)(multi1);
718 FN(MULTI(BASE),free)(multi2);
719 return NULL;
722 /* Given two MULTI(BASE)s A -> B and C -> D,
723 * construct a MULTI(BASE) (A * C) -> [B -> D].
725 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)(
726 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
728 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
729 &FN(MULTI(BASE),range_product_aligned));
732 /* Is the range of "multi" a wrapped relation?
734 isl_bool FN(MULTI(BASE),range_is_wrapping)(__isl_keep MULTI(BASE) *multi)
736 if (!multi)
737 return isl_bool_error;
738 return isl_space_range_is_wrapping(multi->space);
741 /* Given a function A -> [B -> C], extract the function A -> B.
743 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_domain)(
744 __isl_take MULTI(BASE) *multi)
746 isl_space *space;
747 isl_size total, keep;
749 total = FN(MULTI(BASE),dim)(multi, isl_dim_out);
750 if (total < 0)
751 return FN(MULTI(BASE),free)(multi);
752 if (!isl_space_range_is_wrapping(multi->space))
753 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
754 "range is not a product",
755 return FN(MULTI(BASE),free)(multi));
757 space = FN(MULTI(BASE),get_space)(multi);
758 space = isl_space_range_factor_domain(space);
759 keep = isl_space_dim(space, isl_dim_out);
760 if (keep < 0)
761 multi = FN(MULTI(BASE),free)(multi);
762 multi = FN(MULTI(BASE),drop_dims)(multi,
763 isl_dim_out, keep, total - keep);
764 multi = FN(MULTI(BASE),reset_space)(multi, space);
766 return multi;
769 /* Given a function A -> [B -> C], extract the function A -> C.
771 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_range)(
772 __isl_take MULTI(BASE) *multi)
774 isl_space *space;
775 isl_size total, keep;
777 total = FN(MULTI(BASE),dim)(multi, isl_dim_out);
778 if (total < 0)
779 return FN(MULTI(BASE),free)(multi);
780 if (!isl_space_range_is_wrapping(multi->space))
781 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
782 "range is not a product",
783 return FN(MULTI(BASE),free)(multi));
785 space = FN(MULTI(BASE),get_space)(multi);
786 space = isl_space_range_factor_range(space);
787 keep = isl_space_dim(space, isl_dim_out);
788 if (keep < 0)
789 multi = FN(MULTI(BASE),free)(multi);
790 multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
791 multi = FN(MULTI(BASE),reset_space)(multi, space);
793 return multi;
796 /* Given a function [B -> C], extract the function C.
798 __isl_give MULTI(BASE) *FN(MULTI(BASE),factor_range)(
799 __isl_take MULTI(BASE) *multi)
801 isl_space *space;
802 isl_size total, keep;
804 total = FN(MULTI(BASE),dim)(multi, isl_dim_set);
805 if (total < 0)
806 return FN(MULTI(BASE),free)(multi);
807 if (!isl_space_is_wrapping(multi->space))
808 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
809 "not a product", return FN(MULTI(BASE),free)(multi));
811 space = FN(MULTI(BASE),get_space)(multi);
812 space = isl_space_factor_range(space);
813 keep = isl_space_dim(space, isl_dim_set);
814 if (keep < 0)
815 multi = FN(MULTI(BASE),free)(multi);
816 multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_set, 0, total - keep);
817 multi = FN(MULTI(BASE),reset_space)(multi, space);
819 return multi;
822 __isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)(
823 __isl_take MULTI(BASE) *multi)
825 if (!multi)
826 return NULL;
828 if (!multi->space->nested[1])
829 return multi;
831 multi = FN(MULTI(BASE),cow)(multi);
832 if (!multi)
833 return NULL;
835 multi->space = isl_space_flatten_range(multi->space);
836 if (!multi->space)
837 return FN(MULTI(BASE),free)(multi);
839 return multi;
842 /* Given two MULTI(BASE)s A -> B and C -> D,
843 * construct a MULTI(BASE) (A * C) -> (B, D).
845 __isl_give MULTI(BASE) *FN(MULTI(BASE),flat_range_product)(
846 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
848 MULTI(BASE) *multi;
850 multi = FN(MULTI(BASE),range_product)(multi1, multi2);
851 multi = FN(MULTI(BASE),flatten_range)(multi);
852 return multi;
855 /* Given two multi expressions, "multi1"
857 * [A] -> [B1 B2]
859 * where B2 starts at position "pos", and "multi2"
861 * [A] -> [D]
863 * return the multi expression
865 * [A] -> [B1 D B2]
867 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_splice)(
868 __isl_take MULTI(BASE) *multi1, unsigned pos,
869 __isl_take MULTI(BASE) *multi2)
871 MULTI(BASE) *res;
872 isl_size dim;
874 dim = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
875 if (dim < 0 || !multi2)
876 goto error;
878 if (FN(MULTI(BASE),check_range)(multi1, isl_dim_out, pos, 0) < 0)
879 goto error;
881 res = FN(MULTI(BASE),copy)(multi1);
882 res = FN(MULTI(BASE),drop_dims)(res, isl_dim_out, pos, dim - pos);
883 multi1 = FN(MULTI(BASE),drop_dims)(multi1, isl_dim_out, 0, pos);
885 res = FN(MULTI(BASE),flat_range_product)(res, multi2);
886 res = FN(MULTI(BASE),flat_range_product)(res, multi1);
888 return res;
889 error:
890 FN(MULTI(BASE),free)(multi1);
891 FN(MULTI(BASE),free)(multi2);
892 return NULL;
895 /* Check that "multi1" and "multi2" live in the same space,
896 * reporting an error if they do not.
898 static isl_stat FN(MULTI(BASE),check_equal_space)(
899 __isl_keep MULTI(BASE) *multi1, __isl_keep MULTI(BASE) *multi2)
901 isl_bool equal;
903 if (!multi1 || !multi2)
904 return isl_stat_error;
906 equal = isl_space_is_equal(multi1->space, multi2->space);
907 if (equal < 0)
908 return isl_stat_error;
909 if (!equal)
910 isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
911 "spaces don't match", return isl_stat_error);
913 return isl_stat_ok;
916 /* This function is currently only used from isl_aff.c
918 static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
919 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
920 __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
921 __attribute__ ((unused));
923 /* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
924 * return the result.
926 * If "multi2" has an explicit domain, then
927 * intersect the domain of the result with this explicit domain.
929 static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
930 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
931 __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
933 int i;
935 multi1 = FN(MULTI(BASE),cow)(multi1);
936 if (FN(MULTI(BASE),check_equal_space)(multi1, multi2) < 0)
937 goto error;
939 for (i = 0; i < multi1->n; ++i) {
940 multi1->u.p[i] = fn(multi1->u.p[i],
941 FN(EL,copy)(multi2->u.p[i]));
942 if (!multi1->u.p[i])
943 goto error;
946 if (FN(MULTI(BASE),has_explicit_domain)(multi2))
947 multi1 = FN(MULTI(BASE),intersect_explicit_domain)(multi1,
948 multi2);
950 FN(MULTI(BASE),free)(multi2);
951 return multi1;
952 error:
953 FN(MULTI(BASE),free)(multi1);
954 FN(MULTI(BASE),free)(multi2);
955 return NULL;
958 /* Add "multi2" to "multi1" and return the result.
960 * The parameters of "multi1" and "multi2" are assumed to have been aligned.
962 static __isl_give MULTI(BASE) *FN(MULTI(BASE),add_aligned)(
963 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
965 return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,add));
968 /* Add "multi2" to "multi1" and return the result.
970 __isl_give MULTI(BASE) *FN(MULTI(BASE),add)(__isl_take MULTI(BASE) *multi1,
971 __isl_take MULTI(BASE) *multi2)
973 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
974 &FN(MULTI(BASE),add_aligned));
977 /* Subtract "multi2" from "multi1" and return the result.
979 * The parameters of "multi1" and "multi2" are assumed to have been aligned.
981 static __isl_give MULTI(BASE) *FN(MULTI(BASE),sub_aligned)(
982 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
984 return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,sub));
987 /* Subtract "multi2" from "multi1" and return the result.
989 __isl_give MULTI(BASE) *FN(MULTI(BASE),sub)(__isl_take MULTI(BASE) *multi1,
990 __isl_take MULTI(BASE) *multi2)
992 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
993 &FN(MULTI(BASE),sub_aligned));
996 /* Multiply the elements of "multi" by "v" and return the result.
998 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val)(__isl_take MULTI(BASE) *multi,
999 __isl_take isl_val *v)
1001 int i;
1003 if (!multi || !v)
1004 goto error;
1006 if (isl_val_is_one(v)) {
1007 isl_val_free(v);
1008 return multi;
1011 if (!isl_val_is_rat(v))
1012 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1013 "expecting rational factor", goto error);
1015 multi = FN(MULTI(BASE),cow)(multi);
1016 if (!multi)
1017 return NULL;
1019 for (i = 0; i < multi->n; ++i) {
1020 multi->u.p[i] = FN(EL,scale_val)(multi->u.p[i],
1021 isl_val_copy(v));
1022 if (!multi->u.p[i])
1023 goto error;
1026 isl_val_free(v);
1027 return multi;
1028 error:
1029 isl_val_free(v);
1030 return FN(MULTI(BASE),free)(multi);
1033 /* Divide the elements of "multi" by "v" and return the result.
1035 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_val)(
1036 __isl_take MULTI(BASE) *multi, __isl_take isl_val *v)
1038 int i;
1040 if (!multi || !v)
1041 goto error;
1043 if (isl_val_is_one(v)) {
1044 isl_val_free(v);
1045 return multi;
1048 if (!isl_val_is_rat(v))
1049 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1050 "expecting rational factor", goto error);
1051 if (isl_val_is_zero(v))
1052 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1053 "cannot scale down by zero", goto error);
1055 multi = FN(MULTI(BASE),cow)(multi);
1056 if (!multi)
1057 return NULL;
1059 for (i = 0; i < multi->n; ++i) {
1060 multi->u.p[i] = FN(EL,scale_down_val)(multi->u.p[i],
1061 isl_val_copy(v));
1062 if (!multi->u.p[i])
1063 goto error;
1066 isl_val_free(v);
1067 return multi;
1068 error:
1069 isl_val_free(v);
1070 return FN(MULTI(BASE),free)(multi);
1073 /* Multiply the elements of "multi" by the corresponding element of "mv"
1074 * and return the result.
1076 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_multi_val)(
1077 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1079 int i;
1081 if (!multi || !mv)
1082 goto error;
1084 if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1085 mv->space, isl_dim_set))
1086 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1087 "spaces don't match", goto error);
1089 multi = FN(MULTI(BASE),cow)(multi);
1090 if (!multi)
1091 goto error;
1093 for (i = 0; i < multi->n; ++i) {
1094 isl_val *v;
1096 v = isl_multi_val_get_val(mv, i);
1097 multi->u.p[i] = FN(EL,scale_val)(multi->u.p[i], v);
1098 if (!multi->u.p[i])
1099 goto error;
1102 isl_multi_val_free(mv);
1103 return multi;
1104 error:
1105 isl_multi_val_free(mv);
1106 return FN(MULTI(BASE),free)(multi);
1109 /* Divide the elements of "multi" by the corresponding element of "mv"
1110 * and return the result.
1112 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_multi_val)(
1113 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1115 int i;
1117 if (!multi || !mv)
1118 goto error;
1120 if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1121 mv->space, isl_dim_set))
1122 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1123 "spaces don't match", goto error);
1125 multi = FN(MULTI(BASE),cow)(multi);
1126 if (!multi)
1127 return NULL;
1129 for (i = 0; i < multi->n; ++i) {
1130 isl_val *v;
1132 v = isl_multi_val_get_val(mv, i);
1133 multi->u.p[i] = FN(EL,scale_down_val)(multi->u.p[i], v);
1134 if (!multi->u.p[i])
1135 goto error;
1138 isl_multi_val_free(mv);
1139 return multi;
1140 error:
1141 isl_multi_val_free(mv);
1142 return FN(MULTI(BASE),free)(multi);
1145 /* Compute the residues of the elements of "multi" modulo
1146 * the corresponding element of "mv" and return the result.
1148 __isl_give MULTI(BASE) *FN(MULTI(BASE),mod_multi_val)(
1149 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1151 int i;
1153 if (!multi || !mv)
1154 goto error;
1156 if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1157 mv->space, isl_dim_set))
1158 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1159 "spaces don't match", goto error);
1161 multi = FN(MULTI(BASE),cow)(multi);
1162 if (!multi)
1163 goto error;
1165 for (i = 0; i < multi->n; ++i) {
1166 isl_val *v;
1168 v = isl_multi_val_get_val(mv, i);
1169 multi->u.p[i] = FN(EL,mod_val)(multi->u.p[i], v);
1170 if (!multi->u.p[i])
1171 goto error;
1174 isl_multi_val_free(mv);
1175 return multi;
1176 error:
1177 isl_multi_val_free(mv);
1178 return FN(MULTI(BASE),free)(multi);
1181 /* Convert a multiple expression defined over a parameter domain
1182 * into one that is defined over a zero-dimensional set.
1184 __isl_give MULTI(BASE) *FN(MULTI(BASE),from_range)(
1185 __isl_take MULTI(BASE) *multi)
1187 isl_space *space;
1189 if (!multi)
1190 return NULL;
1191 if (!isl_space_is_set(multi->space))
1192 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1193 "not living in a set space",
1194 return FN(MULTI(BASE),free)(multi));
1196 space = FN(MULTI(BASE),get_space)(multi);
1197 space = isl_space_from_range(space);
1198 multi = FN(MULTI(BASE),reset_space)(multi, space);
1200 return multi;
1203 /* Are "multi1" and "multi2" obviously equal?
1205 isl_bool FN(MULTI(BASE),plain_is_equal)(__isl_keep MULTI(BASE) *multi1,
1206 __isl_keep MULTI(BASE) *multi2)
1208 int i;
1209 isl_bool equal;
1211 if (!multi1 || !multi2)
1212 return isl_bool_error;
1213 if (multi1->n != multi2->n)
1214 return isl_bool_false;
1215 equal = isl_space_is_equal(multi1->space, multi2->space);
1216 if (equal < 0 || !equal)
1217 return equal;
1219 for (i = 0; i < multi1->n; ++i) {
1220 equal = FN(EL,plain_is_equal)(multi1->u.p[i], multi2->u.p[i]);
1221 if (equal < 0 || !equal)
1222 return equal;
1225 if (FN(MULTI(BASE),has_explicit_domain)(multi1) ||
1226 FN(MULTI(BASE),has_explicit_domain)(multi2)) {
1227 equal = FN(MULTI(BASE),equal_explicit_domain)(multi1, multi2);
1228 if (equal < 0 || !equal)
1229 return equal;
1232 return isl_bool_true;
1235 /* Does "multi" involve any NaNs?
1237 isl_bool FN(MULTI(BASE),involves_nan)(__isl_keep MULTI(BASE) *multi)
1239 int i;
1241 if (!multi)
1242 return isl_bool_error;
1243 if (multi->n == 0)
1244 return isl_bool_false;
1246 for (i = 0; i < multi->n; ++i) {
1247 isl_bool has_nan = FN(EL,involves_nan)(multi->u.p[i]);
1248 if (has_nan < 0 || has_nan)
1249 return has_nan;
1252 return isl_bool_false;
1255 /* Return the opposite of "multi".
1257 __isl_give MULTI(BASE) *FN(MULTI(BASE),neg)(__isl_take MULTI(BASE) *multi)
1259 int i;
1261 multi = FN(MULTI(BASE),cow)(multi);
1262 if (!multi)
1263 return NULL;
1265 for (i = 0; i < multi->n; ++i) {
1266 multi->u.p[i] = FN(EL,neg)(multi->u.p[i]);
1267 if (!multi->u.p[i])
1268 return FN(MULTI(BASE),free)(multi);
1271 return multi;