add isl_aff_from_range
[isl.git] / isl_multi_templ.c
blobd785030ef64adab510d7cf64080d837de82dfbd1
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 unsigned FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi,
133 enum isl_dim_type type)
135 return multi ? isl_space_dim(multi->space, type) : 0;
138 /* Return the position of the first dimension of "type" with id "id".
139 * Return -1 if there is no such dimension.
141 int FN(MULTI(BASE),find_dim_by_id)(__isl_keep MULTI(BASE) *multi,
142 enum isl_dim_type type, __isl_keep isl_id *id)
144 if (!multi)
145 return -1;
146 return isl_space_find_dim_by_id(multi->space, type, id);
149 /* Return the id of the given dimension.
151 __isl_give isl_id *FN(MULTI(BASE),get_dim_id)(__isl_keep MULTI(BASE) *multi,
152 enum isl_dim_type type, unsigned pos)
154 return multi ? isl_space_get_dim_id(multi->space, type, pos) : NULL;
157 __isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_name)(
158 __isl_take MULTI(BASE) *multi,
159 enum isl_dim_type type, unsigned pos, const char *s)
161 int i;
163 multi = FN(MULTI(BASE),cow)(multi);
164 if (!multi)
165 return NULL;
167 multi->space = isl_space_set_dim_name(multi->space, type, pos, s);
168 if (!multi->space)
169 return FN(MULTI(BASE),free)(multi);
171 if (type == isl_dim_out)
172 return multi;
173 for (i = 0; i < multi->n; ++i) {
174 multi->p[i] = FN(EL,set_dim_name)(multi->p[i], type, pos, s);
175 if (!multi->p[i])
176 return FN(MULTI(BASE),free)(multi);
179 return multi;
182 const char *FN(MULTI(BASE),get_tuple_name)(__isl_keep MULTI(BASE) *multi,
183 enum isl_dim_type type)
185 return multi ? isl_space_get_tuple_name(multi->space, type) : NULL;
188 /* Does the specified tuple have an id?
190 isl_bool FN(MULTI(BASE),has_tuple_id)(__isl_keep MULTI(BASE) *multi,
191 enum isl_dim_type type)
193 if (!multi)
194 return isl_bool_error;
195 return isl_space_has_tuple_id(multi->space, type);
198 /* Return the id of the specified tuple.
200 __isl_give isl_id *FN(MULTI(BASE),get_tuple_id)(__isl_keep MULTI(BASE) *multi,
201 enum isl_dim_type type)
203 return multi ? isl_space_get_tuple_id(multi->space, type) : NULL;
206 __isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi,
207 int pos)
209 isl_ctx *ctx;
211 if (!multi)
212 return NULL;
213 ctx = FN(MULTI(BASE),get_ctx)(multi);
214 if (pos < 0 || pos >= multi->n)
215 isl_die(ctx, isl_error_invalid,
216 "index out of bounds", return NULL);
217 return FN(EL,copy)(multi->p[pos]);
220 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)(
221 __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
223 isl_space *multi_space = NULL;
224 isl_space *el_space = NULL;
225 isl_bool match;
227 multi = FN(MULTI(BASE),cow)(multi);
228 if (!multi || !el)
229 goto error;
231 multi_space = FN(MULTI(BASE),get_space)(multi);
232 match = FN(EL,matching_params)(el, multi_space);
233 if (match < 0)
234 goto error;
235 if (!match) {
236 multi = FN(MULTI(BASE),align_params)(multi,
237 FN(EL,get_space)(el));
238 isl_space_free(multi_space);
239 multi_space = FN(MULTI(BASE),get_space)(multi);
240 el = FN(EL,align_params)(el, isl_space_copy(multi_space));
242 if (FN(EL,check_match_domain_space)(el, multi_space) < 0)
243 goto error;
245 if (pos < 0 || pos >= multi->n)
246 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
247 "index out of bounds", goto error);
249 FN(EL,free)(multi->p[pos]);
250 multi->p[pos] = el;
252 isl_space_free(multi_space);
253 isl_space_free(el_space);
255 return multi;
256 error:
257 FN(MULTI(BASE),free)(multi);
258 FN(EL,free)(el);
259 isl_space_free(multi_space);
260 isl_space_free(el_space);
261 return NULL;
264 /* Reset the space of "multi". This function is called from isl_pw_templ.c
265 * and doesn't know if the space of an element object is represented
266 * directly or through its domain. It therefore passes along both,
267 * which we pass along to the element function since we don't know how
268 * that is represented either.
270 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space_and_domain)(
271 __isl_take MULTI(BASE) *multi, __isl_take isl_space *space,
272 __isl_take isl_space *domain)
274 int i;
276 multi = FN(MULTI(BASE),cow)(multi);
277 if (!multi || !space || !domain)
278 goto error;
280 for (i = 0; i < multi->n; ++i) {
281 multi->p[i] = FN(EL,reset_domain_space)(multi->p[i],
282 isl_space_copy(domain));
283 if (!multi->p[i])
284 goto error;
286 isl_space_free(domain);
287 isl_space_free(multi->space);
288 multi->space = space;
290 return multi;
291 error:
292 isl_space_free(domain);
293 isl_space_free(space);
294 FN(MULTI(BASE),free)(multi);
295 return NULL;
298 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_domain_space)(
299 __isl_take MULTI(BASE) *multi, __isl_take isl_space *domain)
301 isl_space *space;
303 space = isl_space_extend_domain_with_range(isl_space_copy(domain),
304 isl_space_copy(multi->space));
305 return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
308 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space)(
309 __isl_take MULTI(BASE) *multi, __isl_take isl_space *space)
311 isl_space *domain;
313 domain = isl_space_domain(isl_space_copy(space));
314 return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
317 /* Set the id of the given dimension of "multi" to "id".
319 __isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_id)(
320 __isl_take MULTI(BASE) *multi,
321 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
323 isl_space *space;
325 multi = FN(MULTI(BASE),cow)(multi);
326 if (!multi || !id)
327 goto error;
329 space = FN(MULTI(BASE),get_space)(multi);
330 space = isl_space_set_dim_id(space, type, pos, id);
332 return FN(MULTI(BASE),reset_space)(multi, space);
333 error:
334 isl_id_free(id);
335 FN(MULTI(BASE),free)(multi);
336 return NULL;
339 __isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_name)(
340 __isl_keep MULTI(BASE) *multi, enum isl_dim_type type,
341 const char *s)
343 isl_space *space;
345 multi = FN(MULTI(BASE),cow)(multi);
346 if (!multi)
347 return NULL;
349 space = FN(MULTI(BASE),get_space)(multi);
350 space = isl_space_set_tuple_name(space, type, s);
352 return FN(MULTI(BASE),reset_space)(multi, space);
355 __isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_id)(
356 __isl_take MULTI(BASE) *multi, enum isl_dim_type type,
357 __isl_take isl_id *id)
359 isl_space *space;
361 multi = FN(MULTI(BASE),cow)(multi);
362 if (!multi)
363 goto error;
365 space = FN(MULTI(BASE),get_space)(multi);
366 space = isl_space_set_tuple_id(space, type, id);
368 return FN(MULTI(BASE),reset_space)(multi, space);
369 error:
370 isl_id_free(id);
371 return NULL;
374 /* Drop the id on the specified tuple.
376 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_tuple_id)(
377 __isl_take MULTI(BASE) *multi, enum isl_dim_type type)
379 isl_space *space;
381 if (!multi)
382 return NULL;
383 if (!FN(MULTI(BASE),has_tuple_id)(multi, type))
384 return multi;
386 multi = FN(MULTI(BASE),cow)(multi);
387 if (!multi)
388 return NULL;
390 space = FN(MULTI(BASE),get_space)(multi);
391 space = isl_space_reset_tuple_id(space, type);
393 return FN(MULTI(BASE),reset_space)(multi, space);
396 /* Reset the user pointer on all identifiers of parameters and tuples
397 * of the space of "multi".
399 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_user)(
400 __isl_take MULTI(BASE) *multi)
402 isl_space *space;
404 space = FN(MULTI(BASE),get_space)(multi);
405 space = isl_space_reset_user(space);
407 return FN(MULTI(BASE),reset_space)(multi, space);
410 __isl_give MULTI(BASE) *FN(MULTI(BASE),realign_domain)(
411 __isl_take MULTI(BASE) *multi, __isl_take isl_reordering *exp)
413 int i;
415 multi = FN(MULTI(BASE),cow)(multi);
416 if (!multi || !exp)
417 goto error;
419 for (i = 0; i < multi->n; ++i) {
420 multi->p[i] = FN(EL,realign_domain)(multi->p[i],
421 isl_reordering_copy(exp));
422 if (!multi->p[i])
423 goto error;
426 multi = FN(MULTI(BASE),reset_domain_space)(multi,
427 isl_space_copy(exp->dim));
429 isl_reordering_free(exp);
430 return multi;
431 error:
432 isl_reordering_free(exp);
433 FN(MULTI(BASE),free)(multi);
434 return NULL;
437 /* Align the parameters of "multi" to those of "model".
439 __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)(
440 __isl_take MULTI(BASE) *multi, __isl_take isl_space *model)
442 isl_ctx *ctx;
443 isl_bool equal_params;
444 isl_reordering *exp;
446 if (!multi || !model)
447 goto error;
449 equal_params = isl_space_has_equal_params(multi->space, model);
450 if (equal_params < 0)
451 goto error;
452 if (equal_params) {
453 isl_space_free(model);
454 return multi;
457 ctx = isl_space_get_ctx(model);
458 if (!isl_space_has_named_params(model))
459 isl_die(ctx, isl_error_invalid,
460 "model has unnamed parameters", goto error);
461 if (!isl_space_has_named_params(multi->space))
462 isl_die(ctx, isl_error_invalid,
463 "input has unnamed parameters", goto error);
465 model = isl_space_params(model);
466 exp = isl_parameter_alignment_reordering(multi->space, model);
467 exp = isl_reordering_extend_space(exp,
468 FN(MULTI(BASE),get_domain_space)(multi));
469 multi = FN(MULTI(BASE),realign_domain)(multi, exp);
471 isl_space_free(model);
472 return multi;
473 error:
474 isl_space_free(model);
475 FN(MULTI(BASE),free)(multi);
476 return NULL;
479 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))(
480 __isl_take isl_space *space, __isl_take LIST(EL) *list)
482 int i;
483 int n;
484 isl_ctx *ctx;
485 MULTI(BASE) *multi;
487 if (!space || !list)
488 goto error;
490 ctx = isl_space_get_ctx(space);
491 n = FN(FN(LIST(EL),n),BASE)(list);
492 if (n != isl_space_dim(space, isl_dim_out))
493 isl_die(ctx, isl_error_invalid,
494 "invalid number of elements in list", goto error);
496 multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
497 for (i = 0; i < n; ++i) {
498 multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
499 FN(FN(LIST(EL),get),BASE)(list, i));
502 isl_space_free(space);
503 FN(LIST(EL),free)(list);
504 return multi;
505 error:
506 isl_space_free(space);
507 FN(LIST(EL),free)(list);
508 return NULL;
511 #ifndef NO_IDENTITY
512 /* Create a multi expression in the given space that maps each
513 * input dimension to the corresponding output dimension.
515 __isl_give MULTI(BASE) *FN(MULTI(BASE),identity)(__isl_take isl_space *space)
517 int i, n;
518 isl_local_space *ls;
519 MULTI(BASE) *multi;
521 if (!space)
522 return NULL;
524 if (isl_space_is_set(space))
525 isl_die(isl_space_get_ctx(space), isl_error_invalid,
526 "expecting map space", goto error);
528 n = isl_space_dim(space, isl_dim_out);
529 if (n != isl_space_dim(space, isl_dim_in))
530 isl_die(isl_space_get_ctx(space), isl_error_invalid,
531 "number of input and output dimensions needs to be "
532 "the same", goto error);
534 multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
536 if (!n) {
537 isl_space_free(space);
538 return multi;
541 space = isl_space_domain(space);
542 ls = isl_local_space_from_space(space);
544 for (i = 0; i < n; ++i) {
545 EL *el;
546 el = FN(EL,var_on_domain)(isl_local_space_copy(ls),
547 isl_dim_set, i);
548 multi = FN(FN(MULTI(BASE),set),BASE)(multi, i, el);
551 isl_local_space_free(ls);
553 return multi;
554 error:
555 isl_space_free(space);
556 return NULL;
558 #endif
560 #ifndef NO_ZERO
561 /* Construct a multi expression in the given space with value zero in
562 * each of the output dimensions.
564 __isl_give MULTI(BASE) *FN(MULTI(BASE),zero)(__isl_take isl_space *space)
566 int n;
567 MULTI(BASE) *multi;
569 if (!space)
570 return NULL;
572 n = isl_space_dim(space , isl_dim_out);
573 multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
575 if (!n)
576 isl_space_free(space);
577 else {
578 int i;
579 isl_local_space *ls;
580 EL *el;
582 space = isl_space_domain(space);
583 ls = isl_local_space_from_space(space);
584 el = FN(EL,zero_on_domain)(ls);
586 for (i = 0; i < n; ++i)
587 multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
588 FN(EL,copy)(el));
590 FN(EL,free)(el);
593 return multi;
595 #endif
597 #ifndef NO_FROM_BASE
598 /* Create a multiple expression with a single output/set dimension
599 * equal to "el".
600 * For most multiple expression types, the base type has a single
601 * output/set dimension and the space of the result is therefore
602 * the same as the space of the input.
603 * In the case of isl_multi_union_pw_aff, however, the base type
604 * lives in a parameter space and we therefore need to add
605 * a single set dimension.
607 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),BASE)(__isl_take EL *el)
609 isl_space *space;
610 MULTI(BASE) *multi;
612 space = FN(EL,get_space(el));
613 if (isl_space_is_params(space)) {
614 space = isl_space_set_from_params(space);
615 space = isl_space_add_dims(space, isl_dim_set, 1);
617 multi = FN(MULTI(BASE),alloc)(space);
618 multi = FN(FN(MULTI(BASE),set),BASE)(multi, 0, el);
620 return multi;
622 #endif
624 __isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)(
625 __isl_take MULTI(BASE) *multi,
626 enum isl_dim_type type, unsigned first, unsigned n)
628 int i;
629 unsigned dim;
631 multi = FN(MULTI(BASE),cow)(multi);
632 if (!multi)
633 return NULL;
635 dim = FN(MULTI(BASE),dim)(multi, type);
636 if (first + n > dim || first + n < first)
637 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
638 "index out of bounds",
639 return FN(MULTI(BASE),free)(multi));
641 multi->space = isl_space_drop_dims(multi->space, type, first, n);
642 if (!multi->space)
643 return FN(MULTI(BASE),free)(multi);
645 if (type == isl_dim_out) {
646 for (i = 0; i < n; ++i)
647 FN(EL,free)(multi->p[first + i]);
648 for (i = first; i + n < multi->n; ++i)
649 multi->p[i] = multi->p[i + n];
650 multi->n -= n;
652 return multi;
655 for (i = 0; i < multi->n; ++i) {
656 multi->p[i] = FN(EL,drop_dims)(multi->p[i], type, first, n);
657 if (!multi->p[i])
658 return FN(MULTI(BASE),free)(multi);
661 return multi;
664 /* Align the parameters of "multi1" and "multi2" (if needed) and call "fn".
666 static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_multi_and)(
667 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
668 __isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi1,
669 __isl_take MULTI(BASE) *multi2))
671 isl_ctx *ctx;
672 isl_bool equal_params;
674 if (!multi1 || !multi2)
675 goto error;
676 equal_params = isl_space_has_equal_params(multi1->space, multi2->space);
677 if (equal_params < 0)
678 goto error;
679 if (equal_params)
680 return fn(multi1, multi2);
681 ctx = FN(MULTI(BASE),get_ctx)(multi1);
682 if (!isl_space_has_named_params(multi1->space) ||
683 !isl_space_has_named_params(multi2->space))
684 isl_die(ctx, isl_error_invalid,
685 "unaligned unnamed parameters", goto error);
686 multi1 = FN(MULTI(BASE),align_params)(multi1,
687 FN(MULTI(BASE),get_space)(multi2));
688 multi2 = FN(MULTI(BASE),align_params)(multi2,
689 FN(MULTI(BASE),get_space)(multi1));
690 return fn(multi1, multi2);
691 error:
692 FN(MULTI(BASE),free)(multi1);
693 FN(MULTI(BASE),free)(multi2);
694 return NULL;
697 /* Given two MULTI(BASE)s A -> B and C -> D,
698 * construct a MULTI(BASE) (A * C) -> [B -> D].
700 * The parameters are assumed to have been aligned.
702 static __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product_aligned)(
703 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
705 int i, n1, n2;
706 EL *el;
707 isl_space *space;
708 MULTI(BASE) *res;
710 if (!multi1 || !multi2)
711 goto error;
713 space = isl_space_range_product(FN(MULTI(BASE),get_space)(multi1),
714 FN(MULTI(BASE),get_space)(multi2));
715 res = FN(MULTI(BASE),alloc)(space);
717 n1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
718 n2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
720 for (i = 0; i < n1; ++i) {
721 el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
722 res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
725 for (i = 0; i < n2; ++i) {
726 el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
727 res = FN(FN(MULTI(BASE),set),BASE)(res, n1 + i, el);
730 FN(MULTI(BASE),free)(multi1);
731 FN(MULTI(BASE),free)(multi2);
732 return res;
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 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)(
743 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
745 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
746 &FN(MULTI(BASE),range_product_aligned));
749 /* Is the range of "multi" a wrapped relation?
751 isl_bool FN(MULTI(BASE),range_is_wrapping)(__isl_keep MULTI(BASE) *multi)
753 if (!multi)
754 return isl_bool_error;
755 return isl_space_range_is_wrapping(multi->space);
758 /* Given a function A -> [B -> C], extract the function A -> B.
760 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_domain)(
761 __isl_take MULTI(BASE) *multi)
763 isl_space *space;
764 int total, keep;
766 if (!multi)
767 return NULL;
768 if (!isl_space_range_is_wrapping(multi->space))
769 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
770 "range is not a product",
771 return FN(MULTI(BASE),free)(multi));
773 space = FN(MULTI(BASE),get_space)(multi);
774 total = isl_space_dim(space, isl_dim_out);
775 space = isl_space_range_factor_domain(space);
776 keep = isl_space_dim(space, isl_dim_out);
777 multi = FN(MULTI(BASE),drop_dims)(multi,
778 isl_dim_out, keep, total - keep);
779 multi = FN(MULTI(BASE),reset_space)(multi, space);
781 return multi;
784 /* Given a function A -> [B -> C], extract the function A -> C.
786 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_range)(
787 __isl_take MULTI(BASE) *multi)
789 isl_space *space;
790 int total, keep;
792 if (!multi)
793 return NULL;
794 if (!isl_space_range_is_wrapping(multi->space))
795 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
796 "range is not a product",
797 return FN(MULTI(BASE),free)(multi));
799 space = FN(MULTI(BASE),get_space)(multi);
800 total = isl_space_dim(space, isl_dim_out);
801 space = isl_space_range_factor_range(space);
802 keep = isl_space_dim(space, isl_dim_out);
803 multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
804 multi = FN(MULTI(BASE),reset_space)(multi, space);
806 return multi;
809 /* Given a function [B -> C], extract the function C.
811 __isl_give MULTI(BASE) *FN(MULTI(BASE),factor_range)(
812 __isl_take MULTI(BASE) *multi)
814 isl_space *space;
815 int total, keep;
817 if (!multi)
818 return NULL;
819 if (!isl_space_is_wrapping(multi->space))
820 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
821 "not a product", return FN(MULTI(BASE),free)(multi));
823 space = FN(MULTI(BASE),get_space)(multi);
824 total = isl_space_dim(space, isl_dim_out);
825 space = isl_space_factor_range(space);
826 keep = isl_space_dim(space, isl_dim_out);
827 multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
828 multi = FN(MULTI(BASE),reset_space)(multi, space);
830 return multi;
833 #ifndef NO_PRODUCT
834 /* Given two MULTI(BASE)s A -> B and C -> D,
835 * construct a MULTI(BASE) [A -> C] -> [B -> D].
837 * The parameters are assumed to have been aligned.
839 __isl_give MULTI(BASE) *FN(MULTI(BASE),product_aligned)(
840 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
842 int i;
843 EL *el;
844 isl_space *space;
845 MULTI(BASE) *res;
846 int in1, in2, out1, out2;
848 in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in);
849 in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in);
850 out1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
851 out2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
852 space = isl_space_product(FN(MULTI(BASE),get_space)(multi1),
853 FN(MULTI(BASE),get_space)(multi2));
854 res = FN(MULTI(BASE),alloc)(isl_space_copy(space));
855 space = isl_space_domain(space);
857 for (i = 0; i < out1; ++i) {
858 el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
859 el = FN(EL,insert_dims)(el, isl_dim_in, in1, in2);
860 el = FN(EL,reset_domain_space)(el, isl_space_copy(space));
861 res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
864 for (i = 0; i < out2; ++i) {
865 el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
866 el = FN(EL,insert_dims)(el, isl_dim_in, 0, in1);
867 el = FN(EL,reset_domain_space)(el, isl_space_copy(space));
868 res = FN(FN(MULTI(BASE),set),BASE)(res, out1 + i, el);
871 isl_space_free(space);
872 FN(MULTI(BASE),free)(multi1);
873 FN(MULTI(BASE),free)(multi2);
874 return res;
877 /* Given two MULTI(BASE)s A -> B and C -> D,
878 * construct a MULTI(BASE) [A -> C] -> [B -> D].
880 __isl_give MULTI(BASE) *FN(MULTI(BASE),product)(
881 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
883 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
884 &FN(MULTI(BASE),product_aligned));
886 #endif
888 __isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)(
889 __isl_take MULTI(BASE) *multi)
891 if (!multi)
892 return NULL;
894 if (!multi->space->nested[1])
895 return multi;
897 multi = FN(MULTI(BASE),cow)(multi);
898 if (!multi)
899 return NULL;
901 multi->space = isl_space_flatten_range(multi->space);
902 if (!multi->space)
903 return FN(MULTI(BASE),free)(multi);
905 return multi;
908 /* Given two MULTI(BASE)s A -> B and C -> D,
909 * construct a MULTI(BASE) (A * C) -> (B, D).
911 __isl_give MULTI(BASE) *FN(MULTI(BASE),flat_range_product)(
912 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
914 MULTI(BASE) *multi;
916 multi = FN(MULTI(BASE),range_product)(multi1, multi2);
917 multi = FN(MULTI(BASE),flatten_range)(multi);
918 return multi;
921 /* Given two multi expressions, "multi1"
923 * [A] -> [B1 B2]
925 * where B2 starts at position "pos", and "multi2"
927 * [A] -> [D]
929 * return the multi expression
931 * [A] -> [B1 D B2]
933 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_splice)(
934 __isl_take MULTI(BASE) *multi1, unsigned pos,
935 __isl_take MULTI(BASE) *multi2)
937 MULTI(BASE) *res;
938 unsigned dim;
940 if (!multi1 || !multi2)
941 goto error;
943 dim = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
944 if (pos > dim)
945 isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
946 "index out of bounds", goto error);
948 res = FN(MULTI(BASE),copy)(multi1);
949 res = FN(MULTI(BASE),drop_dims)(res, isl_dim_out, pos, dim - pos);
950 multi1 = FN(MULTI(BASE),drop_dims)(multi1, isl_dim_out, 0, pos);
952 res = FN(MULTI(BASE),flat_range_product)(res, multi2);
953 res = FN(MULTI(BASE),flat_range_product)(res, multi1);
955 return res;
956 error:
957 FN(MULTI(BASE),free)(multi1);
958 FN(MULTI(BASE),free)(multi2);
959 return NULL;
962 #ifndef NO_SPLICE
963 /* Given two multi expressions, "multi1"
965 * [A1 A2] -> [B1 B2]
967 * where A2 starts at position "in_pos" and B2 starts at position "out_pos",
968 * and "multi2"
970 * [C] -> [D]
972 * return the multi expression
974 * [A1 C A2] -> [B1 D B2]
976 * We first insert input dimensions to obtain
978 * [A1 C A2] -> [B1 B2]
980 * and
982 * [A1 C A2] -> [D]
984 * and then apply range_splice.
986 __isl_give MULTI(BASE) *FN(MULTI(BASE),splice)(
987 __isl_take MULTI(BASE) *multi1, unsigned in_pos, unsigned out_pos,
988 __isl_take MULTI(BASE) *multi2)
990 unsigned n_in1;
991 unsigned n_in2;
993 if (!multi1 || !multi2)
994 goto error;
996 n_in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in);
997 if (in_pos > n_in1)
998 isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
999 "index out of bounds", goto error);
1001 n_in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in);
1003 multi1 = FN(MULTI(BASE),insert_dims)(multi1, isl_dim_in, in_pos, n_in2);
1004 multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, n_in2,
1005 n_in1 - in_pos);
1006 multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, 0, in_pos);
1008 return FN(MULTI(BASE),range_splice)(multi1, out_pos, multi2);
1009 error:
1010 FN(MULTI(BASE),free)(multi1);
1011 FN(MULTI(BASE),free)(multi2);
1012 return NULL;
1014 #endif
1016 /* This function is currently only used from isl_aff.c
1018 static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
1019 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
1020 __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
1021 __attribute__ ((unused));
1023 /* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
1024 * return the result.
1026 static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
1027 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
1028 __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
1030 int i;
1031 isl_ctx *ctx;
1033 multi1 = FN(MULTI(BASE),cow)(multi1);
1034 if (!multi1 || !multi2)
1035 goto error;
1037 ctx = FN(MULTI(BASE),get_ctx)(multi1);
1038 if (!isl_space_is_equal(multi1->space, multi2->space))
1039 isl_die(ctx, isl_error_invalid,
1040 "spaces don't match", goto error);
1042 for (i = 0; i < multi1->n; ++i) {
1043 multi1->p[i] = fn(multi1->p[i], FN(EL,copy)(multi2->p[i]));
1044 if (!multi1->p[i])
1045 goto error;
1048 FN(MULTI(BASE),free)(multi2);
1049 return multi1;
1050 error:
1051 FN(MULTI(BASE),free)(multi1);
1052 FN(MULTI(BASE),free)(multi2);
1053 return NULL;
1056 /* Add "multi2" from "multi1" and return the result.
1058 * The parameters of "multi1" and "multi2" are assumed to have been aligned.
1060 static __isl_give MULTI(BASE) *FN(MULTI(BASE),add_aligned)(
1061 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
1063 return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,add));
1066 /* Add "multi2" from "multi1" and return the result.
1068 __isl_give MULTI(BASE) *FN(MULTI(BASE),add)(__isl_take MULTI(BASE) *multi1,
1069 __isl_take MULTI(BASE) *multi2)
1071 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
1072 &FN(MULTI(BASE),add_aligned));
1075 /* Subtract "multi2" from "multi1" and return the result.
1077 * The parameters of "multi1" and "multi2" are assumed to have been aligned.
1079 static __isl_give MULTI(BASE) *FN(MULTI(BASE),sub_aligned)(
1080 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
1082 return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,sub));
1085 /* Subtract "multi2" from "multi1" and return the result.
1087 __isl_give MULTI(BASE) *FN(MULTI(BASE),sub)(__isl_take MULTI(BASE) *multi1,
1088 __isl_take MULTI(BASE) *multi2)
1090 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
1091 &FN(MULTI(BASE),sub_aligned));
1094 /* Multiply the elements of "multi" by "v" and return the result.
1096 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val)(__isl_take MULTI(BASE) *multi,
1097 __isl_take isl_val *v)
1099 int i;
1101 if (!multi || !v)
1102 goto error;
1104 if (isl_val_is_one(v)) {
1105 isl_val_free(v);
1106 return multi;
1109 if (!isl_val_is_rat(v))
1110 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1111 "expecting rational factor", goto error);
1113 multi = FN(MULTI(BASE),cow)(multi);
1114 if (!multi)
1115 return NULL;
1117 for (i = 0; i < multi->n; ++i) {
1118 multi->p[i] = FN(EL,scale_val)(multi->p[i], isl_val_copy(v));
1119 if (!multi->p[i])
1120 goto error;
1123 isl_val_free(v);
1124 return multi;
1125 error:
1126 isl_val_free(v);
1127 return FN(MULTI(BASE),free)(multi);
1130 /* Divide the elements of "multi" by "v" and return the result.
1132 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_val)(
1133 __isl_take MULTI(BASE) *multi, __isl_take isl_val *v)
1135 int i;
1137 if (!multi || !v)
1138 goto error;
1140 if (isl_val_is_one(v)) {
1141 isl_val_free(v);
1142 return multi;
1145 if (!isl_val_is_rat(v))
1146 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1147 "expecting rational factor", goto error);
1148 if (isl_val_is_zero(v))
1149 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1150 "cannot scale down by zero", goto error);
1152 multi = FN(MULTI(BASE),cow)(multi);
1153 if (!multi)
1154 return NULL;
1156 for (i = 0; i < multi->n; ++i) {
1157 multi->p[i] = FN(EL,scale_down_val)(multi->p[i],
1158 isl_val_copy(v));
1159 if (!multi->p[i])
1160 goto error;
1163 isl_val_free(v);
1164 return multi;
1165 error:
1166 isl_val_free(v);
1167 return FN(MULTI(BASE),free)(multi);
1170 /* Multiply the elements of "multi" by the corresponding element of "mv"
1171 * and return the result.
1173 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_multi_val)(
1174 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1176 int i;
1178 if (!multi || !mv)
1179 goto error;
1181 if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1182 mv->space, isl_dim_set))
1183 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1184 "spaces don't match", goto error);
1186 multi = FN(MULTI(BASE),cow)(multi);
1187 if (!multi)
1188 goto error;
1190 for (i = 0; i < multi->n; ++i) {
1191 isl_val *v;
1193 v = isl_multi_val_get_val(mv, i);
1194 multi->p[i] = FN(EL,scale_val)(multi->p[i], v);
1195 if (!multi->p[i])
1196 goto error;
1199 isl_multi_val_free(mv);
1200 return multi;
1201 error:
1202 isl_multi_val_free(mv);
1203 return FN(MULTI(BASE),free)(multi);
1206 /* Divide the elements of "multi" by the corresponding element of "mv"
1207 * and return the result.
1209 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_multi_val)(
1210 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1212 int i;
1214 if (!multi || !mv)
1215 goto error;
1217 if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1218 mv->space, isl_dim_set))
1219 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1220 "spaces don't match", goto error);
1222 multi = FN(MULTI(BASE),cow)(multi);
1223 if (!multi)
1224 return NULL;
1226 for (i = 0; i < multi->n; ++i) {
1227 isl_val *v;
1229 v = isl_multi_val_get_val(mv, i);
1230 multi->p[i] = FN(EL,scale_down_val)(multi->p[i], v);
1231 if (!multi->p[i])
1232 goto error;
1235 isl_multi_val_free(mv);
1236 return multi;
1237 error:
1238 isl_multi_val_free(mv);
1239 return FN(MULTI(BASE),free)(multi);
1242 /* Compute the residues of the elements of "multi" modulo
1243 * the corresponding element of "mv" and return the result.
1245 __isl_give MULTI(BASE) *FN(MULTI(BASE),mod_multi_val)(
1246 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1248 int i;
1250 if (!multi || !mv)
1251 goto error;
1253 if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1254 mv->space, isl_dim_set))
1255 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1256 "spaces don't match", goto error);
1258 multi = FN(MULTI(BASE),cow)(multi);
1259 if (!multi)
1260 goto error;
1262 for (i = 0; i < multi->n; ++i) {
1263 isl_val *v;
1265 v = isl_multi_val_get_val(mv, i);
1266 multi->p[i] = FN(EL,mod_val)(multi->p[i], v);
1267 if (!multi->p[i])
1268 goto error;
1271 isl_multi_val_free(mv);
1272 return multi;
1273 error:
1274 isl_multi_val_free(mv);
1275 return FN(MULTI(BASE),free)(multi);
1278 #ifndef NO_MOVE_DIMS
1279 /* Move the "n" dimensions of "src_type" starting at "src_pos" of "multi"
1280 * to dimensions of "dst_type" at "dst_pos".
1282 * We only support moving input dimensions to parameters and vice versa.
1284 __isl_give MULTI(BASE) *FN(MULTI(BASE),move_dims)(__isl_take MULTI(BASE) *multi,
1285 enum isl_dim_type dst_type, unsigned dst_pos,
1286 enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1288 int i;
1290 if (!multi)
1291 return NULL;
1293 if (n == 0 &&
1294 !isl_space_is_named_or_nested(multi->space, src_type) &&
1295 !isl_space_is_named_or_nested(multi->space, dst_type))
1296 return multi;
1298 if (dst_type == isl_dim_out || src_type == isl_dim_out)
1299 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1300 "cannot move output/set dimension",
1301 return FN(MULTI(BASE),free)(multi));
1302 if (dst_type == isl_dim_div || src_type == isl_dim_div)
1303 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1304 "cannot move divs",
1305 return FN(MULTI(BASE),free)(multi));
1306 if (src_pos + n > isl_space_dim(multi->space, src_type))
1307 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1308 "range out of bounds",
1309 return FN(MULTI(BASE),free)(multi));
1310 if (dst_type == src_type)
1311 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_unsupported,
1312 "moving dims within the same type not supported",
1313 return FN(MULTI(BASE),free)(multi));
1315 multi = FN(MULTI(BASE),cow)(multi);
1316 if (!multi)
1317 return NULL;
1319 multi->space = isl_space_move_dims(multi->space, dst_type, dst_pos,
1320 src_type, src_pos, n);
1321 if (!multi->space)
1322 return FN(MULTI(BASE),free)(multi);
1324 for (i = 0; i < multi->n; ++i) {
1325 multi->p[i] = FN(EL,move_dims)(multi->p[i], dst_type, dst_pos,
1326 src_type, src_pos, n);
1327 if (!multi->p[i])
1328 return FN(MULTI(BASE),free)(multi);
1331 return multi;
1333 #endif
1335 /* Convert a multiple expression defined over a parameter domain
1336 * into one that is defined over a zero-dimensional set.
1338 __isl_give MULTI(BASE) *FN(MULTI(BASE),from_range)(
1339 __isl_take MULTI(BASE) *multi)
1341 isl_space *space;
1343 if (!multi)
1344 return NULL;
1345 if (!isl_space_is_set(multi->space))
1346 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1347 "not living in a set space",
1348 return FN(MULTI(BASE),free)(multi));
1350 space = FN(MULTI(BASE),get_space)(multi);
1351 space = isl_space_from_range(space);
1352 multi = FN(MULTI(BASE),reset_space)(multi, space);
1354 return multi;
1357 /* Are "multi1" and "multi2" obviously equal?
1359 isl_bool FN(MULTI(BASE),plain_is_equal)(__isl_keep MULTI(BASE) *multi1,
1360 __isl_keep MULTI(BASE) *multi2)
1362 int i;
1363 isl_bool equal;
1365 if (!multi1 || !multi2)
1366 return isl_bool_error;
1367 if (multi1->n != multi2->n)
1368 return isl_bool_false;
1369 equal = isl_space_is_equal(multi1->space, multi2->space);
1370 if (equal < 0 || !equal)
1371 return equal;
1373 for (i = 0; i < multi1->n; ++i) {
1374 equal = FN(EL,plain_is_equal)(multi1->p[i], multi2->p[i]);
1375 if (equal < 0 || !equal)
1376 return equal;
1379 return isl_bool_true;
1382 /* Does "multi" involve any NaNs?
1384 isl_bool FN(MULTI(BASE),involves_nan)(__isl_keep MULTI(BASE) *multi)
1386 int i;
1388 if (!multi)
1389 return isl_bool_error;
1390 if (multi->n == 0)
1391 return isl_bool_false;
1393 for (i = 0; i < multi->n; ++i) {
1394 isl_bool has_nan = FN(EL,involves_nan)(multi->p[i]);
1395 if (has_nan < 0 || has_nan)
1396 return has_nan;
1399 return isl_bool_false;
1402 #ifndef NO_DOMAIN
1403 /* Return the shared domain of the elements of "multi".
1405 __isl_give isl_set *FN(MULTI(BASE),domain)(__isl_take MULTI(BASE) *multi)
1407 int i;
1408 isl_set *dom;
1410 if (!multi)
1411 return NULL;
1413 dom = isl_set_universe(FN(MULTI(BASE),get_domain_space)(multi));
1414 for (i = 0; i < multi->n; ++i) {
1415 isl_set *dom_i;
1417 dom_i = FN(EL,domain)(FN(FN(MULTI(BASE),get),BASE)(multi, i));
1418 dom = isl_set_intersect(dom, dom_i);
1421 FN(MULTI(BASE),free)(multi);
1422 return dom;
1424 #endif
1426 #ifndef NO_NEG
1427 /* Return the opposite of "multi".
1429 __isl_give MULTI(BASE) *FN(MULTI(BASE),neg)(__isl_take MULTI(BASE) *multi)
1431 int i;
1433 multi = FN(MULTI(BASE),cow)(multi);
1434 if (!multi)
1435 return NULL;
1437 for (i = 0; i < multi->n; ++i) {
1438 multi->p[i] = FN(EL,neg)(multi->p[i]);
1439 if (!multi->p[i])
1440 return FN(MULTI(BASE),free)(multi);
1443 return multi;
1445 #endif