isl_map_coalesce: avoid ignoring constraints redundant wrt implicit equalities
[isl.git] / isl_space.c
blobf7d882d2b9f16d7c12b07a7094818f102eb0986f
1 /*
2 * Copyright 2008-2009 Katholieke Universiteit Leuven
3 * Copyright 2010 INRIA Saclay
4 * Copyright 2013-2014 Ecole Normale Superieure
5 * Copyright 2018-2019 Cerebras Systems
7 * Use of this software is governed by the MIT license
9 * Written by Sven Verdoolaege, K.U.Leuven, Departement
10 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
11 * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
12 * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
13 * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
14 * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA
17 #include <stdlib.h>
18 #include <string.h>
19 #include <isl_space_private.h>
20 #include <isl_id_private.h>
21 #include <isl_reordering.h>
23 isl_ctx *isl_space_get_ctx(__isl_keep isl_space *space)
25 return space ? space->ctx : NULL;
28 __isl_give isl_space *isl_space_alloc(isl_ctx *ctx,
29 unsigned nparam, unsigned n_in, unsigned n_out)
31 isl_space *space;
33 space = isl_alloc_type(ctx, struct isl_space);
34 if (!space)
35 return NULL;
37 space->ctx = ctx;
38 isl_ctx_ref(ctx);
39 space->ref = 1;
40 space->nparam = nparam;
41 space->n_in = n_in;
42 space->n_out = n_out;
44 space->tuple_id[0] = NULL;
45 space->tuple_id[1] = NULL;
47 space->nested[0] = NULL;
48 space->nested[1] = NULL;
50 space->n_id = 0;
51 space->ids = NULL;
53 return space;
56 /* Mark the space as being that of a set, by setting the domain tuple
57 * to isl_id_none.
59 static __isl_give isl_space *mark_as_set(__isl_take isl_space *space)
61 space = isl_space_cow(space);
62 if (!space)
63 return NULL;
64 space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none);
65 return space;
68 /* Is the space that of a set?
70 isl_bool isl_space_is_set(__isl_keep isl_space *space)
72 if (!space)
73 return isl_bool_error;
74 if (space->n_in != 0 || space->nested[0])
75 return isl_bool_false;
76 if (space->tuple_id[0] != &isl_id_none)
77 return isl_bool_false;
78 return isl_bool_true;
81 /* Check that "space" is a set space.
83 isl_stat isl_space_check_is_set(__isl_keep isl_space *space)
85 isl_bool is_set;
87 is_set = isl_space_is_set(space);
88 if (is_set < 0)
89 return isl_stat_error;
90 if (!is_set)
91 isl_die(isl_space_get_ctx(space), isl_error_invalid,
92 "space is not a set", return isl_stat_error);
93 return isl_stat_ok;
96 /* Is the given space that of a map?
98 isl_bool isl_space_is_map(__isl_keep isl_space *space)
100 int r;
102 if (!space)
103 return isl_bool_error;
104 r = space->tuple_id[0] != &isl_id_none &&
105 space->tuple_id[1] != &isl_id_none;
106 return isl_bool_ok(r);
109 /* Check that "space" is the space of a map.
111 static isl_stat isl_space_check_is_map(__isl_keep isl_space *space)
113 isl_bool is_space;
115 is_space = isl_space_is_map(space);
116 if (is_space < 0)
117 return isl_stat_error;
118 if (!is_space)
119 isl_die(isl_space_get_ctx(space), isl_error_invalid,
120 "expecting map space", return isl_stat_error);
121 return isl_stat_ok;
124 /* Check that "space" is the space of a set wrapping a map space.
126 isl_stat isl_space_check_is_wrapping(__isl_keep isl_space *space)
128 isl_bool wrapping;
130 wrapping = isl_space_is_wrapping(space);
131 if (wrapping < 0)
132 return isl_stat_error;
133 if (!wrapping)
134 isl_die(isl_space_get_ctx(space), isl_error_invalid,
135 "not a product", return isl_stat_error);
136 return isl_stat_ok;
139 /* Check that "space" is the space of a map
140 * where the domain is a wrapped map space.
142 isl_stat isl_space_check_domain_is_wrapping(__isl_keep isl_space *space)
144 isl_bool wrapping;
146 wrapping = isl_space_domain_is_wrapping(space);
147 if (wrapping < 0)
148 return isl_stat_error;
149 if (!wrapping)
150 isl_die(isl_space_get_ctx(space), isl_error_invalid,
151 "domain not a product", return isl_stat_error);
152 return isl_stat_ok;
155 /* Check that "space" is the space of a map
156 * where the range is a wrapped map space.
158 isl_stat isl_space_check_range_is_wrapping(__isl_keep isl_space *space)
160 isl_bool wrapping;
162 wrapping = isl_space_range_is_wrapping(space);
163 if (wrapping < 0)
164 return isl_stat_error;
165 if (!wrapping)
166 isl_die(isl_space_get_ctx(space), isl_error_invalid,
167 "range not a product", return isl_stat_error);
168 return isl_stat_ok;
171 __isl_give isl_space *isl_space_set_alloc(isl_ctx *ctx,
172 unsigned nparam, unsigned dim)
174 isl_space *space;
175 space = isl_space_alloc(ctx, nparam, 0, dim);
176 space = mark_as_set(space);
177 return space;
180 /* Mark the space as being that of a parameter domain, by setting
181 * both tuples to isl_id_none.
183 static __isl_give isl_space *mark_as_params(isl_space *space)
185 if (!space)
186 return NULL;
187 space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none);
188 space = isl_space_set_tuple_id(space, isl_dim_out, &isl_id_none);
189 return space;
192 /* Is the space that of a parameter domain?
194 isl_bool isl_space_is_params(__isl_keep isl_space *space)
196 if (!space)
197 return isl_bool_error;
198 if (space->n_in != 0 || space->nested[0] ||
199 space->n_out != 0 || space->nested[1])
200 return isl_bool_false;
201 if (space->tuple_id[0] != &isl_id_none)
202 return isl_bool_false;
203 if (space->tuple_id[1] != &isl_id_none)
204 return isl_bool_false;
205 return isl_bool_true;
208 /* Create a space for a parameter domain.
210 __isl_give isl_space *isl_space_params_alloc(isl_ctx *ctx, unsigned nparam)
212 isl_space *space;
213 space = isl_space_alloc(ctx, nparam, 0, 0);
214 space = mark_as_params(space);
215 return space;
218 /* Create a space for a parameter domain, without any parameters.
220 __isl_give isl_space *isl_space_unit(isl_ctx *ctx)
222 return isl_space_params_alloc(ctx, 0);
225 static isl_size global_pos(__isl_keep isl_space *space,
226 enum isl_dim_type type, unsigned pos)
228 if (isl_space_check_range(space, type, pos, 1) < 0)
229 return isl_size_error;
231 switch (type) {
232 case isl_dim_param:
233 return pos;
234 case isl_dim_in:
235 return pos + space->nparam;
236 case isl_dim_out:
237 return pos + space->nparam + space->n_in;
238 default:
239 isl_assert(isl_space_get_ctx(space), 0, return isl_size_error);
241 return isl_size_error;
244 /* Extend length of ids array to the total number of dimensions.
246 static __isl_give isl_space *extend_ids(__isl_take isl_space *space)
248 isl_id **ids;
249 int i;
250 isl_size dim;
252 dim = isl_space_dim(space, isl_dim_all);
253 if (dim < 0)
254 return isl_space_free(space);
255 if (dim <= space->n_id)
256 return space;
258 if (!space->ids) {
259 space->ids = isl_calloc_array(space->ctx, isl_id *, dim);
260 if (!space->ids)
261 goto error;
262 } else {
263 ids = isl_realloc_array(space->ctx, space->ids, isl_id *, dim);
264 if (!ids)
265 goto error;
266 space->ids = ids;
267 for (i = space->n_id; i < dim; ++i)
268 space->ids[i] = NULL;
271 space->n_id = dim;
273 return space;
274 error:
275 isl_space_free(space);
276 return NULL;
279 static __isl_give isl_space *set_id(__isl_take isl_space *space,
280 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
282 isl_size gpos;
284 space = isl_space_cow(space);
286 gpos = global_pos(space, type, pos);
287 if (gpos < 0)
288 goto error;
290 if (gpos >= space->n_id) {
291 if (!id)
292 return space;
293 space = extend_ids(space);
294 if (!space)
295 goto error;
298 space->ids[gpos] = id;
300 return space;
301 error:
302 isl_id_free(id);
303 isl_space_free(space);
304 return NULL;
307 static __isl_keep isl_id *get_id(__isl_keep isl_space *space,
308 enum isl_dim_type type, unsigned pos)
310 isl_size gpos;
312 gpos = global_pos(space, type, pos);
313 if (gpos < 0)
314 return NULL;
315 if (gpos >= space->n_id)
316 return NULL;
317 return space->ids[gpos];
320 /* Return the nested space at the given position.
322 static __isl_keep isl_space *isl_space_peek_nested(__isl_keep isl_space *space,
323 int pos)
325 if (!space)
326 return NULL;
327 if (!space->nested[pos])
328 isl_die(isl_space_get_ctx(space), isl_error_invalid,
329 "no nested space", return NULL);
330 return space->nested[pos];
333 static unsigned offset(__isl_keep isl_space *space, enum isl_dim_type type)
335 switch (type) {
336 case isl_dim_param: return 0;
337 case isl_dim_in: return space->nparam;
338 case isl_dim_out: return space->nparam + space->n_in;
339 default: return 0;
343 static unsigned n(__isl_keep isl_space *space, enum isl_dim_type type)
345 switch (type) {
346 case isl_dim_param: return space->nparam;
347 case isl_dim_in: return space->n_in;
348 case isl_dim_out: return space->n_out;
349 case isl_dim_all:
350 return space->nparam + space->n_in + space->n_out;
351 default: return 0;
355 isl_size isl_space_dim(__isl_keep isl_space *space, enum isl_dim_type type)
357 if (!space)
358 return isl_size_error;
359 return n(space, type);
362 /* Return the dimensionality of tuple "inner" within the wrapped relation
363 * inside tuple "outer".
365 isl_size isl_space_wrapped_dim(__isl_keep isl_space *space,
366 enum isl_dim_type outer, enum isl_dim_type inner)
368 int pos;
370 if (!space)
371 return isl_size_error;
372 if (outer != isl_dim_in && outer != isl_dim_out)
373 isl_die(isl_space_get_ctx(space), isl_error_invalid,
374 "only input, output and set tuples "
375 "can have nested relations", return isl_size_error);
376 pos = outer - isl_dim_in;
377 return isl_space_dim(isl_space_peek_nested(space, pos), inner);
380 isl_size isl_space_offset(__isl_keep isl_space *space, enum isl_dim_type type)
382 if (!space)
383 return isl_size_error;
384 return offset(space, type);
387 static __isl_give isl_space *copy_ids(__isl_take isl_space *dst,
388 enum isl_dim_type dst_type, unsigned offset, __isl_keep isl_space *src,
389 enum isl_dim_type src_type)
391 int i;
392 isl_id *id;
394 if (!dst)
395 return NULL;
397 for (i = 0; i < n(src, src_type); ++i) {
398 id = get_id(src, src_type, i);
399 if (!id)
400 continue;
401 isl_id_free(get_id(dst, dst_type, offset + i));
402 dst = set_id(dst, dst_type, offset + i, isl_id_copy(id));
403 if (!dst)
404 return NULL;
406 return dst;
409 __isl_give isl_space *isl_space_dup(__isl_keep isl_space *space)
411 isl_space *dup;
412 if (!space)
413 return NULL;
414 dup = isl_space_alloc(space->ctx,
415 space->nparam, space->n_in, space->n_out);
416 if (!dup)
417 return NULL;
418 if (space->tuple_id[0] &&
419 !(dup->tuple_id[0] = isl_id_copy(space->tuple_id[0])))
420 goto error;
421 if (space->tuple_id[1] &&
422 !(dup->tuple_id[1] = isl_id_copy(space->tuple_id[1])))
423 goto error;
424 if (space->nested[0] &&
425 !(dup->nested[0] = isl_space_copy(space->nested[0])))
426 goto error;
427 if (space->nested[1] &&
428 !(dup->nested[1] = isl_space_copy(space->nested[1])))
429 goto error;
430 if (!space->ids)
431 return dup;
432 dup = copy_ids(dup, isl_dim_param, 0, space, isl_dim_param);
433 dup = copy_ids(dup, isl_dim_in, 0, space, isl_dim_in);
434 dup = copy_ids(dup, isl_dim_out, 0, space, isl_dim_out);
435 return dup;
436 error:
437 isl_space_free(dup);
438 return NULL;
441 __isl_give isl_space *isl_space_cow(__isl_take isl_space *space)
443 if (!space)
444 return NULL;
446 if (space->ref == 1)
447 return space;
448 space->ref--;
449 return isl_space_dup(space);
452 __isl_give isl_space *isl_space_copy(__isl_keep isl_space *space)
454 if (!space)
455 return NULL;
457 space->ref++;
458 return space;
461 __isl_null isl_space *isl_space_free(__isl_take isl_space *space)
463 int i;
465 if (!space)
466 return NULL;
468 if (--space->ref > 0)
469 return NULL;
471 isl_id_free(space->tuple_id[0]);
472 isl_id_free(space->tuple_id[1]);
474 isl_space_free(space->nested[0]);
475 isl_space_free(space->nested[1]);
477 for (i = 0; i < space->n_id; ++i)
478 isl_id_free(space->ids[i]);
479 free(space->ids);
480 isl_ctx_deref(space->ctx);
482 free(space);
484 return NULL;
487 /* Check if "s" is a valid dimension or tuple name.
488 * We currently only forbid names that look like a number.
490 * s is assumed to be non-NULL.
492 static int name_ok(isl_ctx *ctx, const char *s)
494 char *p;
496 strtol(s, &p, 0);
497 if (p != s)
498 isl_die(ctx, isl_error_invalid, "name looks like a number",
499 return 0);
501 return 1;
504 /* Return a copy of the nested space at the given position.
506 static __isl_keep isl_space *isl_space_get_nested(__isl_keep isl_space *space,
507 int pos)
509 return isl_space_copy(isl_space_peek_nested(space, pos));
512 /* Return the nested space at the given position.
513 * This may be either a copy or the nested space itself
514 * if there is only one reference to "space".
515 * This allows the nested space to be modified inplace
516 * if both "space" and the nested space have only a single reference.
517 * The caller is not allowed to modify "space" between this call and
518 * a subsequent call to isl_space_restore_nested.
519 * The only exception is that isl_space_free can be called instead.
521 static __isl_give isl_space *isl_space_take_nested(__isl_keep isl_space *space,
522 int pos)
524 isl_space *nested;
526 if (!space)
527 return NULL;
528 if (space->ref != 1)
529 return isl_space_get_nested(space, pos);
530 nested = space->nested[pos];
531 space->nested[pos] = NULL;
532 return nested;
535 /* Replace the nested space at the given position by "nested",
536 * where this nested space of "space" may be missing
537 * due to a preceding call to isl_space_take_nested.
538 * However, in this case, "space" only has a single reference and
539 * then the call to isl_space_cow has no effect.
541 static __isl_give isl_space *isl_space_restore_nested(
542 __isl_take isl_space *space, int pos, __isl_take isl_space *nested)
544 if (!space || !nested)
545 goto error;
547 if (space->nested[pos] == nested) {
548 isl_space_free(nested);
549 return space;
552 space = isl_space_cow(space);
553 if (!space)
554 goto error;
555 isl_space_free(space->nested[pos]);
556 space->nested[pos] = nested;
558 return space;
559 error:
560 isl_space_free(space);
561 isl_space_free(nested);
562 return NULL;
565 /* Is it possible for the given dimension type to have a tuple id?
567 static int space_can_have_id(__isl_keep isl_space *space,
568 enum isl_dim_type type)
570 if (!space)
571 return 0;
572 if (isl_space_is_params(space))
573 isl_die(space->ctx, isl_error_invalid,
574 "parameter spaces don't have tuple ids", return 0);
575 if (isl_space_is_set(space) && type != isl_dim_set)
576 isl_die(space->ctx, isl_error_invalid,
577 "set spaces can only have a set id", return 0);
578 if (type != isl_dim_in && type != isl_dim_out)
579 isl_die(space->ctx, isl_error_invalid,
580 "only input, output and set tuples can have ids",
581 return 0);
583 return 1;
586 /* Does the tuple have an id?
588 isl_bool isl_space_has_tuple_id(__isl_keep isl_space *space,
589 enum isl_dim_type type)
591 if (!space_can_have_id(space, type))
592 return isl_bool_error;
593 return isl_bool_ok(space->tuple_id[type - isl_dim_in] != NULL);
596 /* Does the domain tuple of the map space "space" have an identifier?
598 isl_bool isl_space_has_domain_tuple_id(__isl_keep isl_space *space)
600 if (isl_space_check_is_map(space) < 0)
601 return isl_bool_error;
602 return isl_space_has_tuple_id(space, isl_dim_in);
605 /* Does the range tuple of the map space "space" have an identifier?
607 isl_bool isl_space_has_range_tuple_id(__isl_keep isl_space *space)
609 if (isl_space_check_is_map(space) < 0)
610 return isl_bool_error;
611 return isl_space_has_tuple_id(space, isl_dim_out);
614 __isl_give isl_id *isl_space_get_tuple_id(__isl_keep isl_space *space,
615 enum isl_dim_type type)
617 int has_id;
619 if (!space)
620 return NULL;
621 has_id = isl_space_has_tuple_id(space, type);
622 if (has_id < 0)
623 return NULL;
624 if (!has_id)
625 isl_die(space->ctx, isl_error_invalid,
626 "tuple has no id", return NULL);
627 return isl_id_copy(space->tuple_id[type - isl_dim_in]);
630 /* Return the identifier of the domain tuple of the map space "space",
631 * assuming it has one.
633 __isl_give isl_id *isl_space_get_domain_tuple_id(
634 __isl_keep isl_space *space)
636 if (isl_space_check_is_map(space) < 0)
637 return NULL;
638 return isl_space_get_tuple_id(space, isl_dim_in);
641 /* Return the identifier of the range tuple of the map space "space",
642 * assuming it has one.
644 __isl_give isl_id *isl_space_get_range_tuple_id(
645 __isl_keep isl_space *space)
647 if (isl_space_check_is_map(space) < 0)
648 return NULL;
649 return isl_space_get_tuple_id(space, isl_dim_out);
652 __isl_give isl_space *isl_space_set_tuple_id(__isl_take isl_space *space,
653 enum isl_dim_type type, __isl_take isl_id *id)
655 space = isl_space_cow(space);
656 if (!space || !id)
657 goto error;
658 if (type != isl_dim_in && type != isl_dim_out)
659 isl_die(space->ctx, isl_error_invalid,
660 "only input, output and set tuples can have names",
661 goto error);
663 isl_id_free(space->tuple_id[type - isl_dim_in]);
664 space->tuple_id[type - isl_dim_in] = id;
666 return space;
667 error:
668 isl_id_free(id);
669 isl_space_free(space);
670 return NULL;
673 /* Replace the identifier of the domain tuple of the map space "space"
674 * by "id".
676 __isl_give isl_space *isl_space_set_domain_tuple_id(
677 __isl_take isl_space *space, __isl_take isl_id *id)
679 if (isl_space_check_is_map(space) < 0)
680 space = isl_space_free(space);
681 return isl_space_set_tuple_id(space, isl_dim_in, id);
684 /* Replace the identifier of the range tuple of the map space "space"
685 * by "id".
687 __isl_give isl_space *isl_space_set_range_tuple_id(
688 __isl_take isl_space *space, __isl_take isl_id *id)
690 if (isl_space_check_is_map(space) < 0)
691 space = isl_space_free(space);
692 return isl_space_set_tuple_id(space, isl_dim_out, id);
695 __isl_give isl_space *isl_space_reset_tuple_id(__isl_take isl_space *space,
696 enum isl_dim_type type)
698 space = isl_space_cow(space);
699 if (!space)
700 return NULL;
701 if (type != isl_dim_in && type != isl_dim_out)
702 isl_die(space->ctx, isl_error_invalid,
703 "only input, output and set tuples can have names",
704 goto error);
706 isl_id_free(space->tuple_id[type - isl_dim_in]);
707 space->tuple_id[type - isl_dim_in] = NULL;
709 return space;
710 error:
711 isl_space_free(space);
712 return NULL;
715 /* Set the id of the given dimension of "space" to "id".
716 * If the dimension already has an id, then it is replaced.
717 * If the dimension is a parameter, then we need to change it
718 * in the nested spaces (if any) as well.
720 __isl_give isl_space *isl_space_set_dim_id(__isl_take isl_space *space,
721 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
723 space = isl_space_cow(space);
724 if (!space || !id)
725 goto error;
727 if (type == isl_dim_param) {
728 int i;
730 for (i = 0; i < 2; ++i) {
731 if (!space->nested[i])
732 continue;
733 space->nested[i] =
734 isl_space_set_dim_id(space->nested[i],
735 type, pos, isl_id_copy(id));
736 if (!space->nested[i])
737 goto error;
741 isl_id_free(get_id(space, type, pos));
742 return set_id(space, type, pos, id);
743 error:
744 isl_id_free(id);
745 isl_space_free(space);
746 return NULL;
749 /* Reset the id of the given dimension of "space".
750 * If the dimension already has an id, then it is removed.
751 * If the dimension is a parameter, then we need to reset it
752 * in the nested spaces (if any) as well.
754 __isl_give isl_space *isl_space_reset_dim_id(__isl_take isl_space *space,
755 enum isl_dim_type type, unsigned pos)
757 space = isl_space_cow(space);
758 if (!space)
759 goto error;
761 if (type == isl_dim_param) {
762 int i;
764 for (i = 0; i < 2; ++i) {
765 if (!space->nested[i])
766 continue;
767 space->nested[i] =
768 isl_space_reset_dim_id(space->nested[i],
769 type, pos);
770 if (!space->nested[i])
771 goto error;
775 isl_id_free(get_id(space, type, pos));
776 return set_id(space, type, pos, NULL);
777 error:
778 isl_space_free(space);
779 return NULL;
782 isl_bool isl_space_has_dim_id(__isl_keep isl_space *space,
783 enum isl_dim_type type, unsigned pos)
785 if (!space)
786 return isl_bool_error;
787 return isl_bool_ok(get_id(space, type, pos) != NULL);
790 __isl_give isl_id *isl_space_get_dim_id(__isl_keep isl_space *space,
791 enum isl_dim_type type, unsigned pos)
793 if (!space)
794 return NULL;
795 if (!get_id(space, type, pos))
796 isl_die(space->ctx, isl_error_invalid,
797 "dim has no id", return NULL);
798 return isl_id_copy(get_id(space, type, pos));
801 __isl_give isl_space *isl_space_set_tuple_name(__isl_take isl_space *space,
802 enum isl_dim_type type, const char *s)
804 isl_id *id;
806 if (!space)
807 return NULL;
809 if (!s)
810 return isl_space_reset_tuple_id(space, type);
812 if (!name_ok(space->ctx, s))
813 goto error;
815 id = isl_id_alloc(space->ctx, s, NULL);
816 return isl_space_set_tuple_id(space, type, id);
817 error:
818 isl_space_free(space);
819 return NULL;
822 /* Does the tuple have a name?
824 isl_bool isl_space_has_tuple_name(__isl_keep isl_space *space,
825 enum isl_dim_type type)
827 isl_id *id;
829 if (!space_can_have_id(space, type))
830 return isl_bool_error;
831 id = space->tuple_id[type - isl_dim_in];
832 return isl_bool_ok(id && id->name);
835 __isl_keep const char *isl_space_get_tuple_name(__isl_keep isl_space *space,
836 enum isl_dim_type type)
838 isl_id *id;
839 if (!space)
840 return NULL;
841 if (type != isl_dim_in && type != isl_dim_out)
842 return NULL;
843 id = space->tuple_id[type - isl_dim_in];
844 return id ? id->name : NULL;
847 __isl_give isl_space *isl_space_set_dim_name(__isl_take isl_space *space,
848 enum isl_dim_type type, unsigned pos,
849 const char *s)
851 isl_id *id;
853 if (!space)
854 return NULL;
855 if (!s)
856 return isl_space_reset_dim_id(space, type, pos);
857 if (!name_ok(space->ctx, s))
858 goto error;
859 id = isl_id_alloc(space->ctx, s, NULL);
860 return isl_space_set_dim_id(space, type, pos, id);
861 error:
862 isl_space_free(space);
863 return NULL;
866 /* Does the given dimension have a name?
868 isl_bool isl_space_has_dim_name(__isl_keep isl_space *space,
869 enum isl_dim_type type, unsigned pos)
871 isl_id *id;
873 if (!space)
874 return isl_bool_error;
875 id = get_id(space, type, pos);
876 return isl_bool_ok(id && id->name);
879 __isl_keep const char *isl_space_get_dim_name(__isl_keep isl_space *space,
880 enum isl_dim_type type, unsigned pos)
882 isl_id *id = get_id(space, type, pos);
883 return id ? id->name : NULL;
886 int isl_space_find_dim_by_id(__isl_keep isl_space *space,
887 enum isl_dim_type type, __isl_keep isl_id *id)
889 int i;
890 isl_size offset;
891 isl_size n;
893 n = isl_space_dim(space, type);
894 offset = isl_space_offset(space, type);
895 if (n < 0 || offset < 0 || !id)
896 return -1;
898 for (i = 0; i < n && offset + i < space->n_id; ++i)
899 if (space->ids[offset + i] == id)
900 return i;
902 return -1;
905 int isl_space_find_dim_by_name(__isl_keep isl_space *space,
906 enum isl_dim_type type, const char *name)
908 int i;
909 isl_size offset;
910 isl_size n;
912 n = isl_space_dim(space, type);
913 offset = isl_space_offset(space, type);
914 if (n < 0 || offset < 0 || !name)
915 return -1;
917 for (i = 0; i < n && offset + i < space->n_id; ++i) {
918 isl_id *id = get_id(space, type, i);
919 if (id && id->name && !strcmp(id->name, name))
920 return i;
923 return -1;
926 /* Reset the user pointer on all identifiers of parameters and tuples
927 * of "space".
929 __isl_give isl_space *isl_space_reset_user(__isl_take isl_space *space)
931 int i;
932 isl_ctx *ctx;
933 isl_id *id;
934 const char *name;
936 if (!space)
937 return NULL;
939 ctx = isl_space_get_ctx(space);
941 for (i = 0; i < space->nparam && i < space->n_id; ++i) {
942 if (!isl_id_get_user(space->ids[i]))
943 continue;
944 space = isl_space_cow(space);
945 if (!space)
946 return NULL;
947 name = isl_id_get_name(space->ids[i]);
948 id = isl_id_alloc(ctx, name, NULL);
949 isl_id_free(space->ids[i]);
950 space->ids[i] = id;
951 if (!id)
952 return isl_space_free(space);
955 for (i = 0; i < 2; ++i) {
956 if (!space->tuple_id[i])
957 continue;
958 if (!isl_id_get_user(space->tuple_id[i]))
959 continue;
960 space = isl_space_cow(space);
961 if (!space)
962 return NULL;
963 name = isl_id_get_name(space->tuple_id[i]);
964 id = isl_id_alloc(ctx, name, NULL);
965 isl_id_free(space->tuple_id[i]);
966 space->tuple_id[i] = id;
967 if (!id)
968 return isl_space_free(space);
971 for (i = 0; i < 2; ++i) {
972 isl_space *nested;
974 if (!space->nested[i])
975 continue;
976 nested = isl_space_take_nested(space, i);
977 nested = isl_space_reset_user(nested);
978 space = isl_space_restore_nested(space, i, nested);
979 if (!space)
980 return NULL;
983 return space;
986 static __isl_keep isl_id *tuple_id(__isl_keep isl_space *space,
987 enum isl_dim_type type)
989 if (!space)
990 return NULL;
991 if (type == isl_dim_in)
992 return space->tuple_id[0];
993 if (type == isl_dim_out)
994 return space->tuple_id[1];
995 return NULL;
998 static __isl_keep isl_space *nested(__isl_keep isl_space *space,
999 enum isl_dim_type type)
1001 if (!space)
1002 return NULL;
1003 if (type == isl_dim_in)
1004 return space->nested[0];
1005 if (type == isl_dim_out)
1006 return space->nested[1];
1007 return NULL;
1010 /* Are the two spaces the same, apart from positions and names of parameters?
1012 isl_bool isl_space_has_equal_tuples(__isl_keep isl_space *space1,
1013 __isl_keep isl_space *space2)
1015 if (!space1 || !space2)
1016 return isl_bool_error;
1017 if (space1 == space2)
1018 return isl_bool_true;
1019 return isl_space_tuple_is_equal(space1, isl_dim_in,
1020 space2, isl_dim_in) &&
1021 isl_space_tuple_is_equal(space1, isl_dim_out,
1022 space2, isl_dim_out);
1025 /* Check that a match involving "space" was successful.
1026 * That is, check that "match" is equal to isl_bool_true.
1028 static isl_stat check_match(__isl_keep isl_space *space, isl_bool match)
1030 if (match < 0)
1031 return isl_stat_error;
1032 if (!match)
1033 isl_die(isl_space_get_ctx(space), isl_error_invalid,
1034 "incompatible spaces", return isl_stat_error);
1036 return isl_stat_ok;
1039 /* Check that the two spaces are the same,
1040 * apart from positions and names of parameters.
1042 isl_stat isl_space_check_equal_tuples(__isl_keep isl_space *space1,
1043 __isl_keep isl_space *space2)
1045 isl_bool is_equal;
1047 is_equal = isl_space_has_equal_tuples(space1, space2);
1048 return check_match(space1, is_equal);
1051 /* Check if the tuple of type "type1" of "space1" is the same as
1052 * the tuple of type "type2" of "space2".
1054 * That is, check if the tuples have the same identifier, the same dimension
1055 * and the same internal structure.
1056 * The identifiers of the dimensions inside the tuples do not affect the result.
1058 * Note that this function only checks the tuples themselves.
1059 * If nested tuples are involved, then we need to be careful not
1060 * to have result affected by possibly differing parameters
1061 * in those nested tuples.
1063 isl_bool isl_space_tuple_is_equal(__isl_keep isl_space *space1,
1064 enum isl_dim_type type1, __isl_keep isl_space *space2,
1065 enum isl_dim_type type2)
1067 isl_id *id1, *id2;
1068 isl_space *nested1, *nested2;
1070 if (!space1 || !space2)
1071 return isl_bool_error;
1073 if (space1 == space2 && type1 == type2)
1074 return isl_bool_true;
1076 if (n(space1, type1) != n(space2, type2))
1077 return isl_bool_false;
1078 id1 = tuple_id(space1, type1);
1079 id2 = tuple_id(space2, type2);
1080 if (!id1 ^ !id2)
1081 return isl_bool_false;
1082 if (id1 && id1 != id2)
1083 return isl_bool_false;
1084 nested1 = nested(space1, type1);
1085 nested2 = nested(space2, type2);
1086 if (!nested1 ^ !nested2)
1087 return isl_bool_false;
1088 if (nested1 && !isl_space_has_equal_tuples(nested1, nested2))
1089 return isl_bool_false;
1090 return isl_bool_true;
1093 /* Is the tuple "inner" within the wrapped relation inside tuple "outer"
1094 * of "space1" equal to tuple "type2" of "space2"?
1096 isl_bool isl_space_wrapped_tuple_is_equal(__isl_keep isl_space *space1,
1097 enum isl_dim_type outer, enum isl_dim_type inner,
1098 __isl_keep isl_space *space2, enum isl_dim_type type2)
1100 int pos;
1101 isl_space *nested;
1103 if (!space1)
1104 return isl_bool_error;
1105 if (outer != isl_dim_in && outer != isl_dim_out)
1106 isl_die(isl_space_get_ctx(space1), isl_error_invalid,
1107 "only input, output and set tuples "
1108 "can have nested relations", return isl_bool_error);
1109 pos = outer - isl_dim_in;
1110 nested = isl_space_peek_nested(space1, pos);
1111 return isl_space_tuple_is_equal(nested, inner, space2, type2);
1114 /* Check that the tuple "inner" within the wrapped relation inside tuple "outer"
1115 * of "space1" is equal to tuple "type2" of "space2".
1117 isl_stat isl_space_check_wrapped_tuple_is_equal(__isl_keep isl_space *space1,
1118 enum isl_dim_type outer, enum isl_dim_type inner,
1119 __isl_keep isl_space *space2, enum isl_dim_type type2)
1121 isl_bool is_equal;
1123 is_equal = isl_space_wrapped_tuple_is_equal(space1, outer, inner,
1124 space2, type2);
1125 return check_match(space1, is_equal);
1128 static isl_bool match(__isl_keep isl_space *space1, enum isl_dim_type type1,
1129 __isl_keep isl_space *space2, enum isl_dim_type type2)
1131 int i;
1132 isl_bool equal;
1134 if (!space1 || !space2)
1135 return isl_bool_error;
1137 if (space1 == space2 && type1 == type2)
1138 return isl_bool_true;
1140 equal = isl_space_tuple_is_equal(space1, type1, space2, type2);
1141 if (equal < 0 || !equal)
1142 return equal;
1144 if (!space1->ids && !space2->ids)
1145 return isl_bool_true;
1147 for (i = 0; i < n(space1, type1); ++i) {
1148 if (get_id(space1, type1, i) != get_id(space2, type2, i))
1149 return isl_bool_false;
1151 return isl_bool_true;
1154 /* Do "space1" and "space2" have the same parameters?
1156 isl_bool isl_space_has_equal_params(__isl_keep isl_space *space1,
1157 __isl_keep isl_space *space2)
1159 return match(space1, isl_dim_param, space2, isl_dim_param);
1162 /* Do "space1" and "space2" have the same identifiers for all
1163 * the tuple variables?
1165 isl_bool isl_space_has_equal_ids(__isl_keep isl_space *space1,
1166 __isl_keep isl_space *space2)
1168 isl_bool equal;
1170 equal = match(space1, isl_dim_in, space2, isl_dim_in);
1171 if (equal < 0 || !equal)
1172 return equal;
1173 return match(space1, isl_dim_out, space2, isl_dim_out);
1176 isl_bool isl_space_match(__isl_keep isl_space *space1, enum isl_dim_type type1,
1177 __isl_keep isl_space *space2, enum isl_dim_type type2)
1179 return match(space1, type1, space2, type2);
1182 static void get_ids(__isl_keep isl_space *space, enum isl_dim_type type,
1183 unsigned first, unsigned n, __isl_keep isl_id **ids)
1185 int i;
1187 for (i = 0; i < n ; ++i)
1188 ids[i] = get_id(space, type, first + i);
1191 static __isl_give isl_space *space_extend(__isl_take isl_space *space,
1192 unsigned nparam, unsigned n_in, unsigned n_out)
1194 isl_id **ids = NULL;
1196 if (!space)
1197 return NULL;
1198 if (space->nparam == nparam &&
1199 space->n_in == n_in && space->n_out == n_out)
1200 return space;
1202 isl_assert(space->ctx, space->nparam <= nparam, goto error);
1203 isl_assert(space->ctx, space->n_in <= n_in, goto error);
1204 isl_assert(space->ctx, space->n_out <= n_out, goto error);
1206 space = isl_space_cow(space);
1207 if (!space)
1208 goto error;
1210 if (space->ids) {
1211 unsigned n;
1212 n = nparam + n_in + n_out;
1213 if (n < nparam || n < n_in || n < n_out)
1214 isl_die(isl_space_get_ctx(space), isl_error_invalid,
1215 "overflow in total number of dimensions",
1216 goto error);
1217 ids = isl_calloc_array(space->ctx, isl_id *, n);
1218 if (!ids)
1219 goto error;
1220 get_ids(space, isl_dim_param, 0, space->nparam, ids);
1221 get_ids(space, isl_dim_in, 0, space->n_in, ids + nparam);
1222 get_ids(space, isl_dim_out, 0, space->n_out,
1223 ids + nparam + n_in);
1224 free(space->ids);
1225 space->ids = ids;
1226 space->n_id = nparam + n_in + n_out;
1228 space->nparam = nparam;
1229 space->n_in = n_in;
1230 space->n_out = n_out;
1232 return space;
1233 error:
1234 free(ids);
1235 isl_space_free(space);
1236 return NULL;
1239 __isl_give isl_space *isl_space_extend(__isl_take isl_space *space,
1240 unsigned nparam, unsigned n_in, unsigned n_out)
1242 return space_extend(space, nparam, n_in, n_out);
1245 __isl_give isl_space *isl_space_add_dims(__isl_take isl_space *space,
1246 enum isl_dim_type type, unsigned n)
1248 space = isl_space_reset(space, type);
1249 if (!space)
1250 return NULL;
1251 switch (type) {
1252 case isl_dim_param:
1253 space = space_extend(space,
1254 space->nparam + n, space->n_in, space->n_out);
1255 if (space && space->nested[0] &&
1256 !(space->nested[0] = isl_space_add_dims(space->nested[0],
1257 isl_dim_param, n)))
1258 goto error;
1259 if (space && space->nested[1] &&
1260 !(space->nested[1] = isl_space_add_dims(space->nested[1],
1261 isl_dim_param, n)))
1262 goto error;
1263 return space;
1264 case isl_dim_in:
1265 return space_extend(space,
1266 space->nparam, space->n_in + n, space->n_out);
1267 case isl_dim_out:
1268 return space_extend(space,
1269 space->nparam, space->n_in, space->n_out + n);
1270 default:
1271 isl_die(space->ctx, isl_error_invalid,
1272 "cannot add dimensions of specified type", goto error);
1274 error:
1275 isl_space_free(space);
1276 return NULL;
1279 /* Add a parameter with identifier "id" to "space", provided
1280 * it does not already appear in "space".
1282 __isl_give isl_space *isl_space_add_param_id(__isl_take isl_space *space,
1283 __isl_take isl_id *id)
1285 isl_size pos;
1287 if (!space || !id)
1288 goto error;
1290 if (isl_space_find_dim_by_id(space, isl_dim_param, id) >= 0) {
1291 isl_id_free(id);
1292 return space;
1295 pos = isl_space_dim(space, isl_dim_param);
1296 if (pos < 0)
1297 goto error;
1298 space = isl_space_add_dims(space, isl_dim_param, 1);
1299 space = isl_space_set_dim_id(space, isl_dim_param, pos, id);
1301 return space;
1302 error:
1303 isl_space_free(space);
1304 isl_id_free(id);
1305 return NULL;
1308 static int valid_dim_type(enum isl_dim_type type)
1310 switch (type) {
1311 case isl_dim_param:
1312 case isl_dim_in:
1313 case isl_dim_out:
1314 return 1;
1315 default:
1316 return 0;
1320 #undef TYPE
1321 #define TYPE isl_space
1322 #include "check_type_range_templ.c"
1324 /* Insert "n" dimensions of type "type" at position "pos".
1325 * If we are inserting parameters, then they are also inserted in
1326 * any nested spaces.
1328 __isl_give isl_space *isl_space_insert_dims(__isl_take isl_space *space,
1329 enum isl_dim_type type, unsigned pos, unsigned n)
1331 isl_ctx *ctx;
1332 isl_id **ids = NULL;
1334 if (!space)
1335 return NULL;
1336 if (n == 0)
1337 return isl_space_reset(space, type);
1339 ctx = isl_space_get_ctx(space);
1340 if (!valid_dim_type(type))
1341 isl_die(ctx, isl_error_invalid,
1342 "cannot insert dimensions of specified type",
1343 goto error);
1345 if (isl_space_check_range(space, type, pos, 0) < 0)
1346 return isl_space_free(space);
1348 space = isl_space_cow(space);
1349 if (!space)
1350 return NULL;
1352 if (space->ids) {
1353 enum isl_dim_type t, o = isl_dim_param;
1354 int off;
1355 int s[3];
1356 ids = isl_calloc_array(ctx, isl_id *,
1357 space->nparam + space->n_in + space->n_out + n);
1358 if (!ids)
1359 goto error;
1360 off = 0;
1361 s[isl_dim_param - o] = space->nparam;
1362 s[isl_dim_in - o] = space->n_in;
1363 s[isl_dim_out - o] = space->n_out;
1364 for (t = isl_dim_param; t <= isl_dim_out; ++t) {
1365 if (t != type) {
1366 get_ids(space, t, 0, s[t - o], ids + off);
1367 off += s[t - o];
1368 } else {
1369 get_ids(space, t, 0, pos, ids + off);
1370 off += pos + n;
1371 get_ids(space, t, pos, s[t - o] - pos,
1372 ids + off);
1373 off += s[t - o] - pos;
1376 free(space->ids);
1377 space->ids = ids;
1378 space->n_id = space->nparam + space->n_in + space->n_out + n;
1380 switch (type) {
1381 case isl_dim_param: space->nparam += n; break;
1382 case isl_dim_in: space->n_in += n; break;
1383 case isl_dim_out: space->n_out += n; break;
1384 default: ;
1386 space = isl_space_reset(space, type);
1388 if (type == isl_dim_param) {
1389 if (space && space->nested[0] &&
1390 !(space->nested[0] = isl_space_insert_dims(space->nested[0],
1391 isl_dim_param, pos, n)))
1392 goto error;
1393 if (space && space->nested[1] &&
1394 !(space->nested[1] = isl_space_insert_dims(space->nested[1],
1395 isl_dim_param, pos, n)))
1396 goto error;
1399 return space;
1400 error:
1401 isl_space_free(space);
1402 return NULL;
1405 __isl_give isl_space *isl_space_move_dims(__isl_take isl_space *space,
1406 enum isl_dim_type dst_type, unsigned dst_pos,
1407 enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1409 int i;
1411 space = isl_space_reset(space, src_type);
1412 space = isl_space_reset(space, dst_type);
1413 if (!space)
1414 return NULL;
1415 if (n == 0)
1416 return space;
1418 if (isl_space_check_range(space, src_type, src_pos, n) < 0)
1419 return isl_space_free(space);
1421 if (dst_type == src_type && dst_pos == src_pos)
1422 return space;
1424 isl_assert(space->ctx, dst_type != src_type, goto error);
1426 space = isl_space_cow(space);
1427 if (!space)
1428 return NULL;
1430 if (space->ids) {
1431 isl_id **ids;
1432 enum isl_dim_type t, o = isl_dim_param;
1433 int off;
1434 int s[3];
1435 ids = isl_calloc_array(space->ctx, isl_id *,
1436 space->nparam + space->n_in + space->n_out);
1437 if (!ids)
1438 goto error;
1439 off = 0;
1440 s[isl_dim_param - o] = space->nparam;
1441 s[isl_dim_in - o] = space->n_in;
1442 s[isl_dim_out - o] = space->n_out;
1443 for (t = isl_dim_param; t <= isl_dim_out; ++t) {
1444 if (t == dst_type) {
1445 get_ids(space, t, 0, dst_pos, ids + off);
1446 off += dst_pos;
1447 get_ids(space, src_type, src_pos, n, ids + off);
1448 off += n;
1449 get_ids(space, t, dst_pos, s[t - o] - dst_pos,
1450 ids + off);
1451 off += s[t - o] - dst_pos;
1452 } else if (t == src_type) {
1453 get_ids(space, t, 0, src_pos, ids + off);
1454 off += src_pos;
1455 get_ids(space, t, src_pos + n,
1456 s[t - o] - src_pos - n, ids + off);
1457 off += s[t - o] - src_pos - n;
1458 } else {
1459 get_ids(space, t, 0, s[t - o], ids + off);
1460 off += s[t - o];
1463 free(space->ids);
1464 space->ids = ids;
1465 space->n_id = space->nparam + space->n_in + space->n_out;
1468 switch (dst_type) {
1469 case isl_dim_param: space->nparam += n; break;
1470 case isl_dim_in: space->n_in += n; break;
1471 case isl_dim_out: space->n_out += n; break;
1472 default: ;
1475 switch (src_type) {
1476 case isl_dim_param: space->nparam -= n; break;
1477 case isl_dim_in: space->n_in -= n; break;
1478 case isl_dim_out: space->n_out -= n; break;
1479 default: ;
1482 if (dst_type != isl_dim_param && src_type != isl_dim_param)
1483 return space;
1485 for (i = 0; i < 2; ++i) {
1486 isl_space *nested;
1488 if (!space->nested[i])
1489 continue;
1490 nested = isl_space_take_nested(space, i);
1491 nested = isl_space_replace_params(nested, space);
1492 space = isl_space_restore_nested(space, i, nested);
1493 if (!space)
1494 return NULL;
1497 return space;
1498 error:
1499 isl_space_free(space);
1500 return NULL;
1503 /* Check that "space1" and "space2" have the same parameters,
1504 * reporting an error if they do not.
1506 isl_stat isl_space_check_equal_params(__isl_keep isl_space *space1,
1507 __isl_keep isl_space *space2)
1509 isl_bool equal;
1511 equal = isl_space_has_equal_params(space1, space2);
1512 if (equal < 0)
1513 return isl_stat_error;
1514 if (!equal)
1515 isl_die(isl_space_get_ctx(space1), isl_error_invalid,
1516 "parameters need to match", return isl_stat_error);
1517 return isl_stat_ok;
1520 __isl_give isl_space *isl_space_join(__isl_take isl_space *left,
1521 __isl_take isl_space *right)
1523 isl_space *space;
1525 if (isl_space_check_equal_params(left, right) < 0)
1526 goto error;
1528 isl_assert(left->ctx,
1529 isl_space_tuple_is_equal(left, isl_dim_out, right, isl_dim_in),
1530 goto error);
1532 space = isl_space_alloc(left->ctx,
1533 left->nparam, left->n_in, right->n_out);
1534 if (!space)
1535 goto error;
1537 space = copy_ids(space, isl_dim_param, 0, left, isl_dim_param);
1538 space = copy_ids(space, isl_dim_in, 0, left, isl_dim_in);
1539 space = copy_ids(space, isl_dim_out, 0, right, isl_dim_out);
1541 if (space && left->tuple_id[0] &&
1542 !(space->tuple_id[0] = isl_id_copy(left->tuple_id[0])))
1543 goto error;
1544 if (space && right->tuple_id[1] &&
1545 !(space->tuple_id[1] = isl_id_copy(right->tuple_id[1])))
1546 goto error;
1547 if (space && left->nested[0] &&
1548 !(space->nested[0] = isl_space_copy(left->nested[0])))
1549 goto error;
1550 if (space && right->nested[1] &&
1551 !(space->nested[1] = isl_space_copy(right->nested[1])))
1552 goto error;
1554 isl_space_free(left);
1555 isl_space_free(right);
1557 return space;
1558 error:
1559 isl_space_free(left);
1560 isl_space_free(right);
1561 return NULL;
1564 /* Given two map spaces { A -> C } and { B -> D }, construct the space
1565 * { [A -> B] -> [C -> D] }.
1566 * Given two set spaces { A } and { B }, construct the space { [A -> B] }.
1568 __isl_give isl_space *isl_space_product(__isl_take isl_space *left,
1569 __isl_take isl_space *right)
1571 isl_space *dom1, *dom2, *nest1, *nest2;
1572 int is_set;
1574 if (!left || !right)
1575 goto error;
1577 is_set = isl_space_is_set(left);
1578 if (is_set != isl_space_is_set(right))
1579 isl_die(isl_space_get_ctx(left), isl_error_invalid,
1580 "expecting either two set spaces or two map spaces",
1581 goto error);
1582 if (is_set)
1583 return isl_space_range_product(left, right);
1585 if (isl_space_check_equal_params(left, right) < 0)
1586 goto error;
1588 dom1 = isl_space_domain(isl_space_copy(left));
1589 dom2 = isl_space_domain(isl_space_copy(right));
1590 nest1 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
1592 dom1 = isl_space_range(left);
1593 dom2 = isl_space_range(right);
1594 nest2 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
1596 return isl_space_join(isl_space_reverse(nest1), nest2);
1597 error:
1598 isl_space_free(left);
1599 isl_space_free(right);
1600 return NULL;
1603 /* Given two spaces { A -> C } and { B -> C }, construct the space
1604 * { [A -> B] -> C }
1606 __isl_give isl_space *isl_space_domain_product(__isl_take isl_space *left,
1607 __isl_take isl_space *right)
1609 isl_space *ran, *dom1, *dom2, *nest;
1611 if (isl_space_check_equal_params(left, right) < 0)
1612 goto error;
1614 if (!isl_space_tuple_is_equal(left, isl_dim_out, right, isl_dim_out))
1615 isl_die(left->ctx, isl_error_invalid,
1616 "ranges need to match", goto error);
1618 ran = isl_space_range(isl_space_copy(left));
1620 dom1 = isl_space_domain(left);
1621 dom2 = isl_space_domain(right);
1622 nest = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
1624 return isl_space_join(isl_space_reverse(nest), ran);
1625 error:
1626 isl_space_free(left);
1627 isl_space_free(right);
1628 return NULL;
1631 __isl_give isl_space *isl_space_range_product(__isl_take isl_space *left,
1632 __isl_take isl_space *right)
1634 isl_space *dom, *ran1, *ran2, *nest;
1636 if (isl_space_check_equal_params(left, right) < 0)
1637 goto error;
1639 if (!isl_space_tuple_is_equal(left, isl_dim_in, right, isl_dim_in))
1640 isl_die(left->ctx, isl_error_invalid,
1641 "domains need to match", goto error);
1643 dom = isl_space_domain(isl_space_copy(left));
1645 ran1 = isl_space_range(left);
1646 ran2 = isl_space_range(right);
1647 nest = isl_space_wrap(isl_space_join(isl_space_reverse(ran1), ran2));
1649 return isl_space_join(isl_space_reverse(dom), nest);
1650 error:
1651 isl_space_free(left);
1652 isl_space_free(right);
1653 return NULL;
1656 /* Given a space of the form [A -> B] -> C, return the space A -> C.
1658 __isl_give isl_space *isl_space_domain_factor_domain(
1659 __isl_take isl_space *space)
1661 isl_space *nested;
1662 isl_space *domain;
1664 if (isl_space_check_domain_is_wrapping(space) < 0)
1665 return isl_space_free(space);
1667 nested = space->nested[0];
1668 domain = isl_space_copy(space);
1669 domain = isl_space_drop_dims(domain, isl_dim_in,
1670 nested->n_in, nested->n_out);
1671 if (!domain)
1672 return isl_space_free(space);
1673 if (nested->tuple_id[0]) {
1674 domain->tuple_id[0] = isl_id_copy(nested->tuple_id[0]);
1675 if (!domain->tuple_id[0])
1676 goto error;
1678 if (nested->nested[0]) {
1679 domain->nested[0] = isl_space_copy(nested->nested[0]);
1680 if (!domain->nested[0])
1681 goto error;
1684 isl_space_free(space);
1685 return domain;
1686 error:
1687 isl_space_free(space);
1688 isl_space_free(domain);
1689 return NULL;
1692 /* Given a space of the form [A -> B] -> C, return the space B -> C.
1694 __isl_give isl_space *isl_space_domain_factor_range(
1695 __isl_take isl_space *space)
1697 isl_space *nested;
1698 isl_space *range;
1700 if (isl_space_check_domain_is_wrapping(space) < 0)
1701 return isl_space_free(space);
1703 nested = space->nested[0];
1704 range = isl_space_copy(space);
1705 range = isl_space_drop_dims(range, isl_dim_in, 0, nested->n_in);
1706 if (!range)
1707 return isl_space_free(space);
1708 if (nested->tuple_id[1]) {
1709 range->tuple_id[0] = isl_id_copy(nested->tuple_id[1]);
1710 if (!range->tuple_id[0])
1711 goto error;
1713 if (nested->nested[1]) {
1714 range->nested[0] = isl_space_copy(nested->nested[1]);
1715 if (!range->nested[0])
1716 goto error;
1719 isl_space_free(space);
1720 return range;
1721 error:
1722 isl_space_free(space);
1723 isl_space_free(range);
1724 return NULL;
1727 /* Internal function that selects the domain of the map that is
1728 * embedded in either a set space or the range of a map space.
1729 * In particular, given a space of the form [A -> B], return the space A.
1730 * Given a space of the form A -> [B -> C], return the space A -> B.
1732 static __isl_give isl_space *range_factor_domain(__isl_take isl_space *space)
1734 isl_space *nested;
1735 isl_space *domain;
1737 if (!space)
1738 return NULL;
1740 nested = space->nested[1];
1741 domain = isl_space_copy(space);
1742 domain = isl_space_drop_dims(domain, isl_dim_out,
1743 nested->n_in, nested->n_out);
1744 if (!domain)
1745 return isl_space_free(space);
1746 if (nested->tuple_id[0]) {
1747 domain->tuple_id[1] = isl_id_copy(nested->tuple_id[0]);
1748 if (!domain->tuple_id[1])
1749 goto error;
1751 if (nested->nested[0]) {
1752 domain->nested[1] = isl_space_copy(nested->nested[0]);
1753 if (!domain->nested[1])
1754 goto error;
1757 isl_space_free(space);
1758 return domain;
1759 error:
1760 isl_space_free(space);
1761 isl_space_free(domain);
1762 return NULL;
1765 /* Given a space of the form A -> [B -> C], return the space A -> B.
1767 __isl_give isl_space *isl_space_range_factor_domain(
1768 __isl_take isl_space *space)
1770 if (isl_space_check_range_is_wrapping(space) < 0)
1771 return isl_space_free(space);
1773 return range_factor_domain(space);
1776 /* Given a space of the form [A -> B], return the space A.
1778 static __isl_give isl_space *set_factor_domain(__isl_take isl_space *space)
1780 if (!space)
1781 return NULL;
1782 if (!isl_space_is_wrapping(space))
1783 isl_die(isl_space_get_ctx(space), isl_error_invalid,
1784 "not a product", return isl_space_free(space));
1786 return range_factor_domain(space);
1789 /* Given a space of the form [A -> B] -> [C -> D], return the space A -> C.
1790 * Given a space of the form [A -> B], return the space A.
1792 __isl_give isl_space *isl_space_factor_domain(__isl_take isl_space *space)
1794 if (!space)
1795 return NULL;
1796 if (isl_space_is_set(space))
1797 return set_factor_domain(space);
1798 space = isl_space_domain_factor_domain(space);
1799 space = isl_space_range_factor_domain(space);
1800 return space;
1803 /* Internal function that selects the range of the map that is
1804 * embedded in either a set space or the range of a map space.
1805 * In particular, given a space of the form [A -> B], return the space B.
1806 * Given a space of the form A -> [B -> C], return the space A -> C.
1808 static __isl_give isl_space *range_factor_range(__isl_take isl_space *space)
1810 isl_space *nested;
1811 isl_space *range;
1813 if (!space)
1814 return NULL;
1816 nested = space->nested[1];
1817 range = isl_space_copy(space);
1818 range = isl_space_drop_dims(range, isl_dim_out, 0, nested->n_in);
1819 if (!range)
1820 return isl_space_free(space);
1821 if (nested->tuple_id[1]) {
1822 range->tuple_id[1] = isl_id_copy(nested->tuple_id[1]);
1823 if (!range->tuple_id[1])
1824 goto error;
1826 if (nested->nested[1]) {
1827 range->nested[1] = isl_space_copy(nested->nested[1]);
1828 if (!range->nested[1])
1829 goto error;
1832 isl_space_free(space);
1833 return range;
1834 error:
1835 isl_space_free(space);
1836 isl_space_free(range);
1837 return NULL;
1840 /* Given a space of the form A -> [B -> C], return the space A -> C.
1842 __isl_give isl_space *isl_space_range_factor_range(
1843 __isl_take isl_space *space)
1845 if (isl_space_check_range_is_wrapping(space) < 0)
1846 return isl_space_free(space);
1848 return range_factor_range(space);
1851 /* Given a space of the form [A -> B], return the space B.
1853 static __isl_give isl_space *set_factor_range(__isl_take isl_space *space)
1855 if (!space)
1856 return NULL;
1857 if (!isl_space_is_wrapping(space))
1858 isl_die(isl_space_get_ctx(space), isl_error_invalid,
1859 "not a product", return isl_space_free(space));
1861 return range_factor_range(space);
1864 /* Given a space of the form [A -> B] -> [C -> D], return the space B -> D.
1865 * Given a space of the form [A -> B], return the space B.
1867 __isl_give isl_space *isl_space_factor_range(__isl_take isl_space *space)
1869 if (!space)
1870 return NULL;
1871 if (isl_space_is_set(space))
1872 return set_factor_range(space);
1873 space = isl_space_domain_factor_range(space);
1874 space = isl_space_range_factor_range(space);
1875 return space;
1878 /* Given a space of the form [A -> B] -> C, return the space A.
1880 __isl_give isl_space *isl_space_domain_wrapped_domain(
1881 __isl_take isl_space *space)
1883 return isl_space_factor_domain(isl_space_domain(space));
1886 /* Given a space of the form [A -> B] -> C, return the space B.
1888 __isl_give isl_space *isl_space_domain_wrapped_range(
1889 __isl_take isl_space *space)
1891 return isl_space_factor_range(isl_space_domain(space));
1894 /* Given a space of the form A -> [B -> C], return the space B.
1896 __isl_give isl_space *isl_space_range_wrapped_domain(
1897 __isl_take isl_space *space)
1899 return isl_space_factor_domain(isl_space_range(space));
1902 /* Given a space of the form A -> [B -> C], return the space C.
1904 __isl_give isl_space *isl_space_range_wrapped_range(
1905 __isl_take isl_space *space)
1907 return isl_space_factor_range(isl_space_range(space));
1910 __isl_give isl_space *isl_space_map_from_set(__isl_take isl_space *space)
1912 isl_ctx *ctx;
1913 isl_id **ids = NULL;
1914 int n_id;
1916 if (!space)
1917 return NULL;
1918 ctx = isl_space_get_ctx(space);
1919 if (!isl_space_is_set(space))
1920 isl_die(ctx, isl_error_invalid, "not a set space", goto error);
1921 space = isl_space_cow(space);
1922 if (!space)
1923 return NULL;
1924 n_id = space->nparam + space->n_out + space->n_out;
1925 if (n_id > 0 && space->ids) {
1926 ids = isl_calloc_array(space->ctx, isl_id *, n_id);
1927 if (!ids)
1928 goto error;
1929 get_ids(space, isl_dim_param, 0, space->nparam, ids);
1930 get_ids(space, isl_dim_out, 0, space->n_out,
1931 ids + space->nparam);
1933 space->n_in = space->n_out;
1934 if (ids) {
1935 free(space->ids);
1936 space->ids = ids;
1937 space->n_id = n_id;
1938 space = copy_ids(space, isl_dim_out, 0, space, isl_dim_in);
1940 isl_id_free(space->tuple_id[0]);
1941 space->tuple_id[0] = isl_id_copy(space->tuple_id[1]);
1942 isl_space_free(space->nested[0]);
1943 space->nested[0] = isl_space_copy(space->nested[1]);
1944 return space;
1945 error:
1946 isl_space_free(space);
1947 return NULL;
1950 __isl_give isl_space *isl_space_map_from_domain_and_range(
1951 __isl_take isl_space *domain, __isl_take isl_space *range)
1953 if (!domain || !range)
1954 goto error;
1955 if (!isl_space_is_set(domain))
1956 isl_die(isl_space_get_ctx(domain), isl_error_invalid,
1957 "domain is not a set space", goto error);
1958 if (!isl_space_is_set(range))
1959 isl_die(isl_space_get_ctx(range), isl_error_invalid,
1960 "range is not a set space", goto error);
1961 return isl_space_join(isl_space_reverse(domain), range);
1962 error:
1963 isl_space_free(domain);
1964 isl_space_free(range);
1965 return NULL;
1968 static __isl_give isl_space *set_ids(__isl_take isl_space *space,
1969 enum isl_dim_type type,
1970 unsigned first, unsigned n, __isl_take isl_id **ids)
1972 int i;
1974 for (i = 0; i < n ; ++i)
1975 space = set_id(space, type, first + i, ids[i]);
1977 return space;
1980 __isl_give isl_space *isl_space_reverse(__isl_take isl_space *space)
1982 unsigned t;
1983 isl_bool equal;
1984 isl_space *nested;
1985 isl_id **ids = NULL;
1986 isl_id *id;
1988 equal = match(space, isl_dim_in, space, isl_dim_out);
1989 if (equal < 0)
1990 return isl_space_free(space);
1991 if (equal)
1992 return space;
1994 space = isl_space_cow(space);
1995 if (!space)
1996 return NULL;
1998 id = space->tuple_id[0];
1999 space->tuple_id[0] = space->tuple_id[1];
2000 space->tuple_id[1] = id;
2002 nested = space->nested[0];
2003 space->nested[0] = space->nested[1];
2004 space->nested[1] = nested;
2006 if (space->ids) {
2007 int n_id = space->n_in + space->n_out;
2008 ids = isl_alloc_array(space->ctx, isl_id *, n_id);
2009 if (n_id && !ids)
2010 goto error;
2011 get_ids(space, isl_dim_in, 0, space->n_in, ids);
2012 get_ids(space, isl_dim_out, 0, space->n_out, ids + space->n_in);
2015 t = space->n_in;
2016 space->n_in = space->n_out;
2017 space->n_out = t;
2019 if (space->ids) {
2020 space = set_ids(space, isl_dim_out, 0, space->n_out, ids);
2021 space = set_ids(space, isl_dim_in, 0, space->n_in,
2022 ids + space->n_out);
2023 free(ids);
2026 return space;
2027 error:
2028 free(ids);
2029 isl_space_free(space);
2030 return NULL;
2033 /* Given a space where the tuple of type "type" is a wrapped map space,
2034 * swap domain and range of that wrapped space.
2036 * If the tuple is named, then the name is only preserved
2037 * if the nested tuples are equal, in which case the output
2038 * of this function is identical to the input, except possibly
2039 * for the dimension identifiers.
2041 * Make a reasonable attempt at moving the dimension identifiers
2042 * along with the tuples.
2044 __isl_give isl_space *isl_space_reverse_wrapped(__isl_take isl_space *space,
2045 enum isl_dim_type type)
2047 int pos = type - isl_dim_in;
2048 isl_space *nested;
2049 isl_bool equal;
2050 isl_size n_in;
2052 nested = isl_space_peek_nested(space, pos);
2053 equal = isl_space_tuple_is_equal(nested, isl_dim_in,
2054 nested, isl_dim_out);
2055 if (equal < 0)
2056 return isl_space_free(space);
2058 nested = isl_space_take_nested(space, pos);
2059 nested = isl_space_reverse(nested);
2060 space = isl_space_restore_nested(space, pos, nested);
2061 if (!equal)
2062 space = isl_space_reset_tuple_id(space, type);
2063 nested = isl_space_peek_nested(space, pos);
2064 n_in = isl_space_dim(nested, isl_dim_in);
2065 if (n_in < 0)
2066 return isl_space_free(space);
2067 space = copy_ids(space, type, 0, nested, isl_dim_in);
2068 space = copy_ids(space, type, n_in, nested, isl_dim_out);
2070 return space;
2073 /* Given a space (A -> B), return the corresponding space
2074 * (B -> A).
2076 * If the domain tuple is named, then the name is only preserved
2077 * if A and B are equal tuples, in which case the output
2078 * of this function is identical to the input, except possibly
2079 * for the dimension identifiers.
2081 __isl_give isl_space *isl_space_wrapped_reverse(__isl_take isl_space *space)
2083 if (isl_space_check_is_wrapping(space) < 0)
2084 return isl_space_free(space);
2085 space = isl_space_reverse_wrapped(space, isl_dim_set);
2087 return space;
2090 /* Given a space (A -> B) -> C, return the corresponding space
2091 * (B -> A) -> C.
2093 * If the domain tuple is named, then the name is only preserved
2094 * if A and B are equal tuples, in which case the output
2095 * of this function is identical to the input, except possibly
2096 * for the dimension identifiers.
2098 __isl_give isl_space *isl_space_domain_reverse(__isl_take isl_space *space)
2100 if (isl_space_check_domain_is_wrapping(space) < 0)
2101 return isl_space_free(space);
2102 space = isl_space_reverse_wrapped(space, isl_dim_in);
2104 return space;
2107 /* Given a space A -> (B -> C), return the corresponding space
2108 * A -> (C -> B).
2110 * If the range tuple is named, then the name is only preserved
2111 * if B and C are equal tuples, in which case the output
2112 * of this function is identical to the input, except possibly
2113 * for the dimension identifiers.
2115 __isl_give isl_space *isl_space_range_reverse(__isl_take isl_space *space)
2117 if (isl_space_check_range_is_wrapping(space) < 0)
2118 return isl_space_free(space);
2119 space = isl_space_reverse_wrapped(space, isl_dim_out);
2121 return space;
2124 __isl_give isl_space *isl_space_drop_dims(__isl_take isl_space *space,
2125 enum isl_dim_type type, unsigned first, unsigned num)
2127 int i;
2129 if (!space)
2130 return NULL;
2132 if (num == 0)
2133 return isl_space_reset(space, type);
2135 if (!valid_dim_type(type))
2136 isl_die(space->ctx, isl_error_invalid,
2137 "cannot drop dimensions of specified type", goto error);
2139 if (isl_space_check_range(space, type, first, num) < 0)
2140 return isl_space_free(space);
2141 space = isl_space_cow(space);
2142 if (!space)
2143 goto error;
2144 if (space->ids) {
2145 space = extend_ids(space);
2146 if (!space)
2147 goto error;
2148 for (i = 0; i < num; ++i)
2149 isl_id_free(get_id(space, type, first + i));
2150 for (i = first+num; i < n(space, type); ++i)
2151 set_id(space, type, i - num, get_id(space, type, i));
2152 switch (type) {
2153 case isl_dim_param:
2154 get_ids(space, isl_dim_in, 0, space->n_in,
2155 space->ids + offset(space, isl_dim_in) - num);
2156 case isl_dim_in:
2157 get_ids(space, isl_dim_out, 0, space->n_out,
2158 space->ids + offset(space, isl_dim_out) - num);
2159 default:
2162 space->n_id -= num;
2164 switch (type) {
2165 case isl_dim_param: space->nparam -= num; break;
2166 case isl_dim_in: space->n_in -= num; break;
2167 case isl_dim_out: space->n_out -= num; break;
2168 default: ;
2170 space = isl_space_reset(space, type);
2171 if (type == isl_dim_param) {
2172 if (space && space->nested[0] &&
2173 !(space->nested[0] = isl_space_drop_dims(space->nested[0],
2174 isl_dim_param, first, num)))
2175 goto error;
2176 if (space && space->nested[1] &&
2177 !(space->nested[1] = isl_space_drop_dims(space->nested[1],
2178 isl_dim_param, first, num)))
2179 goto error;
2181 return space;
2182 error:
2183 isl_space_free(space);
2184 return NULL;
2187 __isl_give isl_space *isl_space_drop_inputs(__isl_take isl_space *space,
2188 unsigned first, unsigned n)
2190 if (!space)
2191 return NULL;
2192 return isl_space_drop_dims(space, isl_dim_in, first, n);
2195 __isl_give isl_space *isl_space_drop_outputs(__isl_take isl_space *space,
2196 unsigned first, unsigned n)
2198 if (!space)
2199 return NULL;
2200 return isl_space_drop_dims(space, isl_dim_out, first, n);
2203 /* Remove all parameters from "space".
2205 __isl_give isl_space *isl_space_drop_all_params(__isl_take isl_space *space)
2207 isl_size nparam;
2209 nparam = isl_space_dim(space, isl_dim_param);
2210 if (nparam < 0)
2211 return isl_space_free(space);
2212 return isl_space_drop_dims(space, isl_dim_param, 0, nparam);
2215 __isl_give isl_space *isl_space_domain(__isl_take isl_space *space)
2217 if (!space)
2218 return NULL;
2219 space = isl_space_drop_dims(space, isl_dim_out, 0, space->n_out);
2220 space = isl_space_reverse(space);
2221 space = mark_as_set(space);
2222 return space;
2225 __isl_give isl_space *isl_space_from_domain(__isl_take isl_space *space)
2227 if (!space)
2228 return NULL;
2229 if (!isl_space_is_set(space))
2230 isl_die(isl_space_get_ctx(space), isl_error_invalid,
2231 "not a set space", goto error);
2232 space = isl_space_reverse(space);
2233 space = isl_space_reset(space, isl_dim_out);
2234 return space;
2235 error:
2236 isl_space_free(space);
2237 return NULL;
2240 __isl_give isl_space *isl_space_range(__isl_take isl_space *space)
2242 if (!space)
2243 return NULL;
2244 space = isl_space_drop_dims(space, isl_dim_in, 0, space->n_in);
2245 space = mark_as_set(space);
2246 return space;
2249 __isl_give isl_space *isl_space_from_range(__isl_take isl_space *space)
2251 if (!space)
2252 return NULL;
2253 if (!isl_space_is_set(space))
2254 isl_die(isl_space_get_ctx(space), isl_error_invalid,
2255 "not a set space", goto error);
2256 return isl_space_reset(space, isl_dim_in);
2257 error:
2258 isl_space_free(space);
2259 return NULL;
2262 /* Given a map space A -> B, return the map space [A -> B] -> A.
2264 __isl_give isl_space *isl_space_domain_map(__isl_take isl_space *space)
2266 isl_space *domain;
2268 domain = isl_space_from_range(isl_space_domain(isl_space_copy(space)));
2269 space = isl_space_from_domain(isl_space_wrap(space));
2270 space = isl_space_join(space, domain);
2272 return space;
2275 /* Given a map space A -> B, return the map space [A -> B] -> B.
2277 __isl_give isl_space *isl_space_range_map(__isl_take isl_space *space)
2279 isl_space *range;
2281 range = isl_space_from_range(isl_space_range(isl_space_copy(space)));
2282 space = isl_space_from_domain(isl_space_wrap(space));
2283 space = isl_space_join(space, range);
2285 return space;
2288 __isl_give isl_space *isl_space_params(__isl_take isl_space *space)
2290 isl_size n_in, n_out;
2292 if (isl_space_is_params(space))
2293 return space;
2294 n_in = isl_space_dim(space, isl_dim_in);
2295 n_out = isl_space_dim(space, isl_dim_out);
2296 if (n_in < 0 || n_out < 0)
2297 return isl_space_free(space);
2298 space = isl_space_drop_dims(space, isl_dim_in, 0, n_in);
2299 space = isl_space_drop_dims(space, isl_dim_out, 0, n_out);
2300 space = mark_as_params(space);
2301 return space;
2304 __isl_give isl_space *isl_space_set_from_params(__isl_take isl_space *space)
2306 if (!space)
2307 return NULL;
2308 if (!isl_space_is_params(space))
2309 isl_die(isl_space_get_ctx(space), isl_error_invalid,
2310 "not a parameter space", goto error);
2311 return isl_space_reset(space, isl_dim_set);
2312 error:
2313 isl_space_free(space);
2314 return NULL;
2317 /* Add an unnamed tuple of dimension "dim" to "space".
2318 * This requires "space" to be a parameter or set space.
2320 * In particular, if "space" is a parameter space, then return
2321 * a set space with the given dimension.
2322 * If "space" is a set space, then return a map space
2323 * with "space" as domain and a range of the given dimension.
2325 __isl_give isl_space *isl_space_add_unnamed_tuple_ui(
2326 __isl_take isl_space *space, unsigned dim)
2328 isl_bool is_params, is_set;
2330 is_params = isl_space_is_params(space);
2331 is_set = isl_space_is_set(space);
2332 if (is_params < 0 || is_set < 0)
2333 return isl_space_free(space);
2334 if (!is_params && !is_set)
2335 isl_die(isl_space_get_ctx(space), isl_error_invalid,
2336 "cannot add tuple to map space",
2337 return isl_space_free(space));
2338 if (is_params)
2339 space = isl_space_set_from_params(space);
2340 else
2341 space = isl_space_from_domain(space);
2342 space = isl_space_add_dims(space, isl_dim_out, dim);
2343 return space;
2346 /* Add a tuple of dimension "dim" and with tuple identifier "tuple_id"
2347 * to "space".
2348 * This requires "space" to be a parameter or set space.
2350 __isl_give isl_space *isl_space_add_named_tuple_id_ui(
2351 __isl_take isl_space *space, __isl_take isl_id *tuple_id, unsigned dim)
2353 space = isl_space_add_unnamed_tuple_ui(space, dim);
2354 space = isl_space_set_tuple_id(space, isl_dim_out, tuple_id);
2355 return space;
2358 /* Check that the identifiers in "tuple" do not appear as parameters
2359 * in "space".
2361 static isl_stat check_fresh_params(__isl_keep isl_space *space,
2362 __isl_keep isl_multi_id *tuple)
2364 int i;
2365 isl_size n;
2367 n = isl_multi_id_size(tuple);
2368 if (n < 0)
2369 return isl_stat_error;
2370 for (i = 0; i < n; ++i) {
2371 isl_id *id;
2372 int pos;
2374 id = isl_multi_id_get_at(tuple, i);
2375 if (!id)
2376 return isl_stat_error;
2377 pos = isl_space_find_dim_by_id(space, isl_dim_param, id);
2378 isl_id_free(id);
2379 if (pos >= 0)
2380 isl_die(isl_space_get_ctx(space), isl_error_invalid,
2381 "parameters not unique", return isl_stat_error);
2384 return isl_stat_ok;
2387 /* Add the identifiers in "tuple" as parameters of "space"
2388 * that are known to be fresh.
2390 static __isl_give isl_space *add_bind_params(__isl_take isl_space *space,
2391 __isl_keep isl_multi_id *tuple)
2393 int i;
2394 isl_size first, n;
2396 first = isl_space_dim(space, isl_dim_param);
2397 n = isl_multi_id_size(tuple);
2398 if (first < 0 || n < 0)
2399 return isl_space_free(space);
2400 space = isl_space_add_dims(space, isl_dim_param, n);
2401 for (i = 0; i < n; ++i) {
2402 isl_id *id;
2404 id = isl_multi_id_get_at(tuple, i);
2405 space = isl_space_set_dim_id(space,
2406 isl_dim_param, first + i, id);
2409 return space;
2412 /* Internal function that removes the set tuple of "space",
2413 * which is assumed to correspond to the range space of "tuple", and
2414 * adds the identifiers in "tuple" as fresh parameters.
2415 * In other words, the set dimensions of "space" are reinterpreted
2416 * as parameters, but stay in the same global positions.
2418 __isl_give isl_space *isl_space_bind_set(__isl_take isl_space *space,
2419 __isl_keep isl_multi_id *tuple)
2421 isl_space *tuple_space;
2423 if (isl_space_check_is_set(space) < 0)
2424 return isl_space_free(space);
2425 tuple_space = isl_multi_id_peek_space(tuple);
2426 if (isl_space_check_equal_tuples(tuple_space, space) < 0)
2427 return isl_space_free(space);
2428 if (check_fresh_params(space, tuple) < 0)
2429 return isl_space_free(space);
2430 space = isl_space_params(space);
2431 space = add_bind_params(space, tuple);
2432 return space;
2435 /* Internal function that removes the domain tuple of the map space "space",
2436 * which is assumed to correspond to the range space of "tuple", and
2437 * adds the identifiers in "tuple" as fresh parameters.
2438 * In other words, the domain dimensions of "space" are reinterpreted
2439 * as parameters, but stay in the same global positions.
2441 __isl_give isl_space *isl_space_bind_map_domain(__isl_take isl_space *space,
2442 __isl_keep isl_multi_id *tuple)
2444 isl_space *tuple_space;
2446 if (isl_space_check_is_map(space) < 0)
2447 return isl_space_free(space);
2448 tuple_space = isl_multi_id_peek_space(tuple);
2449 if (isl_space_check_domain_tuples(tuple_space, space) < 0)
2450 return isl_space_free(space);
2451 if (check_fresh_params(space, tuple) < 0)
2452 return isl_space_free(space);
2453 space = isl_space_range(space);
2454 space = add_bind_params(space, tuple);
2455 return space;
2458 /* Internal function that, given a space of the form [A -> B] -> C and
2459 * a tuple of identifiers in A, returns a space B -> C with
2460 * the identifiers in "tuple" added as fresh parameters.
2461 * In other words, the domain dimensions of the wrapped relation
2462 * in the domain of "space" are reinterpreted
2463 * as parameters, but stay in the same global positions.
2465 __isl_give isl_space *isl_space_bind_domain_wrapped_domain(
2466 __isl_take isl_space *space, __isl_keep isl_multi_id *tuple)
2468 isl_space *tuple_space;
2470 if (isl_space_check_is_map(space) < 0)
2471 return isl_space_free(space);
2472 tuple_space = isl_multi_id_peek_space(tuple);
2473 if (isl_space_check_domain_wrapped_domain_tuples(tuple_space,
2474 space) < 0)
2475 return isl_space_free(space);
2476 if (check_fresh_params(space, tuple) < 0)
2477 return isl_space_free(space);
2478 space = isl_space_domain_factor_range(space);
2479 space = add_bind_params(space, tuple);
2480 return space;
2483 /* Insert a domain tuple in "space" corresponding to the set space "domain".
2484 * In particular, if "space" is a parameter space, then the result
2485 * is the set space "domain" combined with the parameters of "space".
2486 * If "space" is a set space, then the result
2487 * is a map space with "domain" as domain and the original space as range.
2489 static __isl_give isl_space *isl_space_insert_domain(
2490 __isl_take isl_space *space, __isl_take isl_space *domain)
2492 isl_bool is_params;
2494 domain = isl_space_replace_params(domain, space);
2496 is_params = isl_space_is_params(space);
2497 if (is_params < 0) {
2498 isl_space_free(domain);
2499 space = isl_space_free(space);
2500 } else if (is_params) {
2501 isl_space_free(space);
2502 space = domain;
2503 } else {
2504 space = isl_space_map_from_domain_and_range(domain, space);
2506 return space;
2509 /* Internal function that introduces a domain in "space"
2510 * corresponding to the range space of "tuple".
2511 * In particular, if "space" is a parameter space, then the result
2512 * is a set space. If "space" is a set space, then the result
2513 * is a map space with the original space as range.
2514 * Parameters that correspond to the identifiers in "tuple" are removed.
2516 * The parameters are removed in reverse order (under the assumption
2517 * that they appear in the same order in "multi") because
2518 * it is slightly more efficient to remove parameters at the end.
2520 * For pretty-printing purposes, the identifiers of the set dimensions
2521 * of the introduced domain are set to the identifiers in "tuple".
2523 __isl_give isl_space *isl_space_unbind_params_insert_domain(
2524 __isl_take isl_space *space, __isl_keep isl_multi_id *tuple)
2526 int i;
2527 isl_size n;
2528 isl_space *tuple_space;
2530 n = isl_multi_id_size(tuple);
2531 if (!space || n < 0)
2532 return isl_space_free(space);
2533 for (i = n - 1; i >= 0; --i) {
2534 isl_id *id;
2535 int pos;
2537 id = isl_multi_id_get_id(tuple, i);
2538 if (!id)
2539 return isl_space_free(space);
2540 pos = isl_space_find_dim_by_id(space, isl_dim_param, id);
2541 isl_id_free(id);
2542 if (pos < 0)
2543 continue;
2544 space = isl_space_drop_dims(space, isl_dim_param, pos, 1);
2546 tuple_space = isl_multi_id_get_space(tuple);
2547 for (i = 0; i < n; ++i) {
2548 isl_id *id;
2550 id = isl_multi_id_get_id(tuple, i);
2551 tuple_space = isl_space_set_dim_id(tuple_space,
2552 isl_dim_set, i, id);
2554 return isl_space_insert_domain(space, tuple_space);
2557 __isl_give isl_space *isl_space_underlying(__isl_take isl_space *space,
2558 unsigned n_div)
2560 int i;
2561 isl_bool is_set;
2563 is_set = isl_space_is_set(space);
2564 if (is_set < 0)
2565 return isl_space_free(space);
2566 if (n_div == 0 && is_set &&
2567 space->nparam == 0 && space->n_in == 0 && space->n_id == 0)
2568 return isl_space_reset(space, isl_dim_out);
2569 space = isl_space_cow(space);
2570 if (!space)
2571 return NULL;
2572 space->n_out += space->nparam + space->n_in + n_div;
2573 space->nparam = 0;
2574 space->n_in = 0;
2576 for (i = 0; i < space->n_id; ++i)
2577 isl_id_free(get_id(space, isl_dim_out, i));
2578 space->n_id = 0;
2579 space = isl_space_reset(space, isl_dim_in);
2580 space = isl_space_reset(space, isl_dim_out);
2581 space = mark_as_set(space);
2583 return space;
2586 /* Are the two spaces the same, including positions and names of parameters?
2588 isl_bool isl_space_is_equal(__isl_keep isl_space *space1,
2589 __isl_keep isl_space *space2)
2591 isl_bool equal;
2593 if (!space1 || !space2)
2594 return isl_bool_error;
2595 if (space1 == space2)
2596 return isl_bool_true;
2597 equal = isl_space_has_equal_params(space1, space2);
2598 if (equal < 0 || !equal)
2599 return equal;
2600 return isl_space_has_equal_tuples(space1, space2);
2603 /* Do the tuples of "space1" correspond to those of the domain of "space2"?
2604 * That is, is "space1" equal to the domain of "space2", ignoring parameters.
2606 * "space2" is allowed to be a set space, in which case "space1"
2607 * should be a parameter space.
2609 isl_bool isl_space_has_domain_tuples(__isl_keep isl_space *space1,
2610 __isl_keep isl_space *space2)
2612 isl_bool is_set;
2614 is_set = isl_space_is_set(space1);
2615 if (is_set < 0 || !is_set)
2616 return is_set;
2617 return isl_space_tuple_is_equal(space1, isl_dim_set,
2618 space2, isl_dim_in);
2621 /* Do the tuples of "space1" correspond to those of the range of "space2"?
2622 * That is, is "space1" equal to the range of "space2", ignoring parameters.
2624 * "space2" is allowed to be the space of a set,
2625 * in which case it should be equal to "space1", ignoring parameters.
2627 isl_bool isl_space_has_range_tuples(__isl_keep isl_space *space1,
2628 __isl_keep isl_space *space2)
2630 isl_bool is_set;
2632 is_set = isl_space_is_set(space1);
2633 if (is_set < 0 || !is_set)
2634 return is_set;
2635 return isl_space_tuple_is_equal(space1, isl_dim_set,
2636 space2, isl_dim_out);
2639 /* Check that the tuples of "space1" correspond to those
2640 * of the domain of "space2".
2641 * That is, check that "space1" is equal to the domain of "space2",
2642 * ignoring parameters.
2644 isl_stat isl_space_check_domain_tuples(__isl_keep isl_space *space1,
2645 __isl_keep isl_space *space2)
2647 isl_bool is_equal;
2649 is_equal = isl_space_has_domain_tuples(space1, space2);
2650 return check_match(space1, is_equal);
2653 /* Check that the tuples of "space1" correspond to those
2654 * of the domain of the wrapped relation in the domain of "space2".
2655 * That is, check that "space1" is equal to this domain,
2656 * ignoring parameters.
2658 isl_stat isl_space_check_domain_wrapped_domain_tuples(
2659 __isl_keep isl_space *space1, __isl_keep isl_space *space2)
2661 isl_space *domain;
2662 isl_stat r;
2664 domain = isl_space_unwrap(isl_space_domain(isl_space_copy(space2)));
2665 r = isl_space_check_domain_tuples(space1, domain);
2666 isl_space_free(domain);
2668 return r;
2671 /* Is space1 equal to the domain of space2?
2673 * In the internal version we also allow space2 to be the space of a set,
2674 * provided space1 is a parameter space.
2676 isl_bool isl_space_is_domain_internal(__isl_keep isl_space *space1,
2677 __isl_keep isl_space *space2)
2679 isl_bool equal_params;
2681 if (!space1 || !space2)
2682 return isl_bool_error;
2683 equal_params = isl_space_has_equal_params(space1, space2);
2684 if (equal_params < 0 || !equal_params)
2685 return equal_params;
2686 return isl_space_has_domain_tuples(space1, space2);
2689 /* Is space1 equal to the domain of space2?
2691 isl_bool isl_space_is_domain(__isl_keep isl_space *space1,
2692 __isl_keep isl_space *space2)
2694 if (!space2)
2695 return isl_bool_error;
2696 if (!isl_space_is_map(space2))
2697 return isl_bool_false;
2698 return isl_space_is_domain_internal(space1, space2);
2701 /* Is space1 equal to the range of space2?
2703 * In the internal version, space2 is allowed to be the space of a set,
2704 * in which case it should be equal to space1.
2706 isl_bool isl_space_is_range_internal(__isl_keep isl_space *space1,
2707 __isl_keep isl_space *space2)
2709 isl_bool equal_params;
2711 if (!space1 || !space2)
2712 return isl_bool_error;
2713 equal_params = isl_space_has_equal_params(space1, space2);
2714 if (equal_params < 0 || !equal_params)
2715 return equal_params;
2716 return isl_space_has_range_tuples(space1, space2);
2719 /* Is space1 equal to the range of space2?
2721 isl_bool isl_space_is_range(__isl_keep isl_space *space1,
2722 __isl_keep isl_space *space2)
2724 if (!space2)
2725 return isl_bool_error;
2726 if (!isl_space_is_map(space2))
2727 return isl_bool_false;
2728 return isl_space_is_range_internal(space1, space2);
2731 /* Update "hash" by hashing in the parameters of "space".
2733 static uint32_t isl_hash_params(uint32_t hash, __isl_keep isl_space *space)
2735 int i;
2736 isl_id *id;
2738 if (!space)
2739 return hash;
2741 isl_hash_byte(hash, space->nparam % 256);
2743 for (i = 0; i < space->nparam; ++i) {
2744 id = get_id(space, isl_dim_param, i);
2745 hash = isl_hash_id(hash, id);
2748 return hash;
2751 /* Update "hash" by hashing in the tuples of "space".
2752 * Changes in this function should be reflected in isl_hash_tuples_domain.
2754 static uint32_t isl_hash_tuples(uint32_t hash, __isl_keep isl_space *space)
2756 isl_id *id;
2758 if (!space)
2759 return hash;
2761 isl_hash_byte(hash, space->n_in % 256);
2762 isl_hash_byte(hash, space->n_out % 256);
2764 id = tuple_id(space, isl_dim_in);
2765 hash = isl_hash_id(hash, id);
2766 id = tuple_id(space, isl_dim_out);
2767 hash = isl_hash_id(hash, id);
2769 hash = isl_hash_tuples(hash, space->nested[0]);
2770 hash = isl_hash_tuples(hash, space->nested[1]);
2772 return hash;
2775 /* Update "hash" by hashing in the domain tuple of "space".
2776 * The result of this function is equal to the result of applying
2777 * isl_hash_tuples to the domain of "space".
2779 static uint32_t isl_hash_tuples_domain(uint32_t hash,
2780 __isl_keep isl_space *space)
2782 isl_id *id;
2784 if (!space)
2785 return hash;
2787 isl_hash_byte(hash, 0);
2788 isl_hash_byte(hash, space->n_in % 256);
2790 hash = isl_hash_id(hash, &isl_id_none);
2791 id = tuple_id(space, isl_dim_in);
2792 hash = isl_hash_id(hash, id);
2794 hash = isl_hash_tuples(hash, space->nested[0]);
2796 return hash;
2799 /* Return a hash value that digests the tuples of "space",
2800 * i.e., that ignores the parameters.
2801 * Changes in this function should be reflected
2802 * in isl_space_get_tuple_domain_hash.
2804 uint32_t isl_space_get_tuple_hash(__isl_keep isl_space *space)
2806 uint32_t hash;
2808 if (!space)
2809 return 0;
2811 hash = isl_hash_init();
2812 hash = isl_hash_tuples(hash, space);
2814 return hash;
2817 /* Return the hash value of "space".
2819 uint32_t isl_space_get_full_hash(__isl_keep isl_space *space)
2821 uint32_t hash;
2823 if (!space)
2824 return 0;
2826 hash = isl_hash_init();
2827 hash = isl_hash_params(hash, space);
2828 hash = isl_hash_tuples(hash, space);
2830 return hash;
2833 /* Return the hash value of the domain tuple of "space".
2834 * That is, isl_space_get_tuple_domain_hash(space) is equal to
2835 * isl_space_get_tuple_hash(isl_space_domain(space)).
2837 uint32_t isl_space_get_tuple_domain_hash(__isl_keep isl_space *space)
2839 uint32_t hash;
2841 if (!space)
2842 return 0;
2844 hash = isl_hash_init();
2845 hash = isl_hash_tuples_domain(hash, space);
2847 return hash;
2850 /* Is "space" the space of a set wrapping a map space?
2852 isl_bool isl_space_is_wrapping(__isl_keep isl_space *space)
2854 if (!space)
2855 return isl_bool_error;
2857 if (!isl_space_is_set(space))
2858 return isl_bool_false;
2860 return isl_bool_ok(space->nested[1] != NULL);
2863 /* Is "space" the space of a map where the domain is a wrapped map space?
2865 isl_bool isl_space_domain_is_wrapping(__isl_keep isl_space *space)
2867 if (!space)
2868 return isl_bool_error;
2870 if (isl_space_is_set(space))
2871 return isl_bool_false;
2873 return isl_bool_ok(space->nested[0] != NULL);
2876 /* Is "space" the space of a map where the range is a wrapped map space?
2878 isl_bool isl_space_range_is_wrapping(__isl_keep isl_space *space)
2880 if (!space)
2881 return isl_bool_error;
2883 if (isl_space_is_set(space))
2884 return isl_bool_false;
2886 return isl_bool_ok(space->nested[1] != NULL);
2889 /* Is "space" a product of two spaces?
2890 * That is, is it a wrapping set space or a map space
2891 * with wrapping domain and range?
2893 isl_bool isl_space_is_product(__isl_keep isl_space *space)
2895 isl_bool is_set;
2896 isl_bool is_product;
2898 is_set = isl_space_is_set(space);
2899 if (is_set < 0)
2900 return isl_bool_error;
2901 if (is_set)
2902 return isl_space_is_wrapping(space);
2903 is_product = isl_space_domain_is_wrapping(space);
2904 if (is_product < 0 || !is_product)
2905 return is_product;
2906 return isl_space_range_is_wrapping(space);
2909 __isl_give isl_space *isl_space_wrap(__isl_take isl_space *space)
2911 isl_space *wrap;
2913 if (!space)
2914 return NULL;
2916 wrap = isl_space_set_alloc(space->ctx,
2917 space->nparam, space->n_in + space->n_out);
2919 wrap = copy_ids(wrap, isl_dim_param, 0, space, isl_dim_param);
2920 wrap = copy_ids(wrap, isl_dim_set, 0, space, isl_dim_in);
2921 wrap = copy_ids(wrap, isl_dim_set, space->n_in, space, isl_dim_out);
2923 if (!wrap)
2924 goto error;
2926 wrap->nested[1] = space;
2928 return wrap;
2929 error:
2930 isl_space_free(space);
2931 return NULL;
2934 __isl_give isl_space *isl_space_unwrap(__isl_take isl_space *space)
2936 isl_space *unwrap;
2938 if (!space)
2939 return NULL;
2941 if (!isl_space_is_wrapping(space))
2942 isl_die(space->ctx, isl_error_invalid, "not a wrapping space",
2943 goto error);
2945 unwrap = isl_space_copy(space->nested[1]);
2946 isl_space_free(space);
2948 return unwrap;
2949 error:
2950 isl_space_free(space);
2951 return NULL;
2954 isl_bool isl_space_is_named_or_nested(__isl_keep isl_space *space,
2955 enum isl_dim_type type)
2957 if (type != isl_dim_in && type != isl_dim_out)
2958 return isl_bool_false;
2959 if (!space)
2960 return isl_bool_error;
2961 if (space->tuple_id[type - isl_dim_in])
2962 return isl_bool_true;
2963 if (space->nested[type - isl_dim_in])
2964 return isl_bool_true;
2965 return isl_bool_false;
2968 isl_bool isl_space_may_be_set(__isl_keep isl_space *space)
2970 isl_bool nested;
2971 isl_size n_in;
2973 if (!space)
2974 return isl_bool_error;
2975 if (isl_space_is_set(space))
2976 return isl_bool_true;
2977 n_in = isl_space_dim(space, isl_dim_in);
2978 if (n_in < 0)
2979 return isl_bool_error;
2980 if (n_in != 0)
2981 return isl_bool_false;
2982 nested = isl_space_is_named_or_nested(space, isl_dim_in);
2983 if (nested < 0 || nested)
2984 return isl_bool_not(nested);
2985 return isl_bool_true;
2988 __isl_give isl_space *isl_space_reset(__isl_take isl_space *space,
2989 enum isl_dim_type type)
2991 if (!isl_space_is_named_or_nested(space, type))
2992 return space;
2994 space = isl_space_cow(space);
2995 if (!space)
2996 return NULL;
2998 isl_id_free(space->tuple_id[type - isl_dim_in]);
2999 space->tuple_id[type - isl_dim_in] = NULL;
3000 isl_space_free(space->nested[type - isl_dim_in]);
3001 space->nested[type - isl_dim_in] = NULL;
3003 return space;
3006 __isl_give isl_space *isl_space_flatten(__isl_take isl_space *space)
3008 if (!space)
3009 return NULL;
3010 if (!space->nested[0] && !space->nested[1])
3011 return space;
3013 if (space->nested[0])
3014 space = isl_space_reset(space, isl_dim_in);
3015 if (space && space->nested[1])
3016 space = isl_space_reset(space, isl_dim_out);
3018 return space;
3021 __isl_give isl_space *isl_space_flatten_domain(__isl_take isl_space *space)
3023 if (!space)
3024 return NULL;
3025 if (!space->nested[0])
3026 return space;
3028 return isl_space_reset(space, isl_dim_in);
3031 __isl_give isl_space *isl_space_flatten_range(__isl_take isl_space *space)
3033 if (!space)
3034 return NULL;
3035 if (!space->nested[1])
3036 return space;
3038 return isl_space_reset(space, isl_dim_out);
3041 /* Replace the parameters of dst by those of src.
3043 __isl_give isl_space *isl_space_replace_params(__isl_take isl_space *dst,
3044 __isl_keep isl_space *src)
3046 isl_size dst_dim, src_dim;
3047 isl_bool equal_params;
3048 enum isl_dim_type type = isl_dim_param;
3050 equal_params = isl_space_has_equal_params(dst, src);
3051 if (equal_params < 0)
3052 return isl_space_free(dst);
3053 if (equal_params)
3054 return dst;
3056 dst = isl_space_cow(dst);
3058 dst_dim = isl_space_dim(dst, type);
3059 src_dim = isl_space_dim(src, type);
3060 if (dst_dim < 0 || src_dim < 0)
3061 goto error;
3063 dst = isl_space_drop_dims(dst, type, 0, dst_dim);
3064 dst = isl_space_add_dims(dst, type, src_dim);
3065 dst = copy_ids(dst, type, 0, src, type);
3067 if (dst) {
3068 int i;
3069 for (i = 0; i <= 1; ++i) {
3070 isl_space *nested;
3072 if (!dst->nested[i])
3073 continue;
3074 nested = isl_space_take_nested(dst, i);
3075 nested = isl_space_replace_params(nested, src);
3076 dst = isl_space_restore_nested(dst, i, nested);
3077 if (!dst)
3078 return NULL;
3082 return dst;
3083 error:
3084 isl_space_free(dst);
3085 return NULL;
3088 /* Given two tuples ("dst_type" in "dst" and "src_type" in "src")
3089 * of the same size, check if any of the dimensions in the "dst" tuple
3090 * have no identifier, while the corresponding dimensions in "src"
3091 * does have an identifier,
3092 * If so, copy the identifier over to "dst".
3094 __isl_give isl_space *isl_space_copy_ids_if_unset(__isl_take isl_space *dst,
3095 enum isl_dim_type dst_type, __isl_keep isl_space *src,
3096 enum isl_dim_type src_type)
3098 int i;
3099 isl_size n;
3101 n = isl_space_dim(dst, dst_type);
3102 if (n < 0)
3103 return isl_space_free(dst);
3104 for (i = 0; i < n; ++i) {
3105 isl_bool set;
3106 isl_id *id;
3108 set = isl_space_has_dim_id(dst, dst_type, i);
3109 if (set < 0)
3110 return isl_space_free(dst);
3111 if (set)
3112 continue;
3114 set = isl_space_has_dim_id(src, src_type, i);
3115 if (set < 0)
3116 return isl_space_free(dst);
3117 if (!set)
3118 continue;
3120 id = isl_space_get_dim_id(src, src_type, i);
3121 dst = isl_space_set_dim_id(dst, dst_type, i, id);
3124 return dst;
3127 /* Given a space "space" of a set, create a space
3128 * for the lift of the set. In particular, the result
3129 * is of the form lifted[space -> local[..]], with n_local variables in the
3130 * range of the wrapped map.
3132 __isl_give isl_space *isl_space_lift(__isl_take isl_space *space,
3133 unsigned n_local)
3135 isl_space *local_space;
3137 if (!space)
3138 return NULL;
3140 local_space = isl_space_dup(space);
3141 local_space = isl_space_drop_dims(local_space, isl_dim_set, 0,
3142 space->n_out);
3143 local_space = isl_space_add_dims(local_space, isl_dim_set, n_local);
3144 local_space = isl_space_set_tuple_name(local_space,
3145 isl_dim_set, "local");
3146 space = isl_space_join(isl_space_from_domain(space),
3147 isl_space_from_range(local_space));
3148 space = isl_space_wrap(space);
3149 space = isl_space_set_tuple_name(space, isl_dim_set, "lifted");
3151 return space;
3154 isl_bool isl_space_can_zip(__isl_keep isl_space *space)
3156 isl_bool is_set;
3158 is_set = isl_space_is_set(space);
3159 if (is_set < 0)
3160 return isl_bool_error;
3161 if (is_set)
3162 return isl_bool_false;
3163 return isl_space_is_product(space);
3166 __isl_give isl_space *isl_space_zip(__isl_take isl_space *space)
3168 isl_space *dom, *ran;
3169 isl_space *dom_dom, *dom_ran, *ran_dom, *ran_ran;
3171 if (!isl_space_can_zip(space))
3172 isl_die(space->ctx, isl_error_invalid, "space cannot be zipped",
3173 goto error);
3175 if (!space)
3176 return NULL;
3177 dom = isl_space_unwrap(isl_space_domain(isl_space_copy(space)));
3178 ran = isl_space_unwrap(isl_space_range(space));
3179 dom_dom = isl_space_domain(isl_space_copy(dom));
3180 dom_ran = isl_space_range(dom);
3181 ran_dom = isl_space_domain(isl_space_copy(ran));
3182 ran_ran = isl_space_range(ran);
3183 dom = isl_space_join(isl_space_from_domain(dom_dom),
3184 isl_space_from_range(ran_dom));
3185 ran = isl_space_join(isl_space_from_domain(dom_ran),
3186 isl_space_from_range(ran_ran));
3187 return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)),
3188 isl_space_from_range(isl_space_wrap(ran)));
3189 error:
3190 isl_space_free(space);
3191 return NULL;
3194 /* Can we apply isl_space_curry to "space"?
3195 * That is, does is it have a map space with a nested relation in its domain?
3197 isl_bool isl_space_can_curry(__isl_keep isl_space *space)
3199 return isl_space_domain_is_wrapping(space);
3202 /* Given a space (A -> B) -> C, return the corresponding space
3203 * A -> (B -> C).
3205 __isl_give isl_space *isl_space_curry(__isl_take isl_space *space)
3207 isl_space *dom, *ran;
3208 isl_space *dom_dom, *dom_ran;
3210 if (!space)
3211 return NULL;
3213 if (!isl_space_can_curry(space))
3214 isl_die(space->ctx, isl_error_invalid,
3215 "space cannot be curried", goto error);
3217 dom = isl_space_unwrap(isl_space_domain(isl_space_copy(space)));
3218 ran = isl_space_range(space);
3219 dom_dom = isl_space_domain(isl_space_copy(dom));
3220 dom_ran = isl_space_range(dom);
3221 ran = isl_space_join(isl_space_from_domain(dom_ran),
3222 isl_space_from_range(ran));
3223 return isl_space_join(isl_space_from_domain(dom_dom),
3224 isl_space_from_range(isl_space_wrap(ran)));
3225 error:
3226 isl_space_free(space);
3227 return NULL;
3230 /* Can isl_space_range_curry be applied to "space"?
3231 * That is, does it have a nested relation in its range,
3232 * the domain of which is itself a nested relation?
3234 isl_bool isl_space_can_range_curry(__isl_keep isl_space *space)
3236 isl_bool can;
3238 if (!space)
3239 return isl_bool_error;
3240 can = isl_space_range_is_wrapping(space);
3241 if (can < 0 || !can)
3242 return can;
3243 return isl_space_can_curry(space->nested[1]);
3246 /* Given a space A -> ((B -> C) -> D), return the corresponding space
3247 * A -> (B -> (C -> D)).
3249 __isl_give isl_space *isl_space_range_curry(__isl_take isl_space *space)
3251 isl_space *nested;
3253 if (!space)
3254 return NULL;
3256 if (!isl_space_can_range_curry(space))
3257 isl_die(isl_space_get_ctx(space), isl_error_invalid,
3258 "space range cannot be curried",
3259 return isl_space_free(space));
3261 nested = isl_space_take_nested(space, 1);
3262 nested = isl_space_curry(nested);
3263 space = isl_space_restore_nested(space, 1, nested);
3265 return space;
3268 /* Can we apply isl_space_uncurry to "space"?
3269 * That is, does it have a map space with a nested relation in its range?
3271 isl_bool isl_space_can_uncurry(__isl_keep isl_space *space)
3273 return isl_space_range_is_wrapping(space);
3276 /* Given a space A -> (B -> C), return the corresponding space
3277 * (A -> B) -> C.
3279 __isl_give isl_space *isl_space_uncurry(__isl_take isl_space *space)
3281 isl_space *dom, *ran;
3282 isl_space *ran_dom, *ran_ran;
3284 if (!space)
3285 return NULL;
3287 if (!isl_space_can_uncurry(space))
3288 isl_die(space->ctx, isl_error_invalid,
3289 "space cannot be uncurried",
3290 return isl_space_free(space));
3292 dom = isl_space_domain(isl_space_copy(space));
3293 ran = isl_space_unwrap(isl_space_range(space));
3294 ran_dom = isl_space_domain(isl_space_copy(ran));
3295 ran_ran = isl_space_range(ran);
3296 dom = isl_space_join(isl_space_from_domain(dom),
3297 isl_space_from_range(ran_dom));
3298 return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)),
3299 isl_space_from_range(ran_ran));
3302 isl_bool isl_space_has_named_params(__isl_keep isl_space *space)
3304 int i;
3305 isl_size off;
3307 if (!space)
3308 return isl_bool_error;
3309 if (space->nparam == 0)
3310 return isl_bool_true;
3311 off = isl_space_offset(space, isl_dim_param);
3312 if (off < 0)
3313 return isl_bool_error;
3314 if (off + space->nparam > space->n_id)
3315 return isl_bool_false;
3316 for (i = 0; i < space->nparam; ++i)
3317 if (!space->ids[off + i])
3318 return isl_bool_false;
3319 return isl_bool_true;
3322 /* Check that "space" has only named parameters, reporting an error
3323 * if it does not.
3325 isl_stat isl_space_check_named_params(__isl_keep isl_space *space)
3327 isl_bool named;
3329 named = isl_space_has_named_params(space);
3330 if (named < 0)
3331 return isl_stat_error;
3332 if (!named)
3333 isl_die(isl_space_get_ctx(space), isl_error_invalid,
3334 "unexpected unnamed parameters", return isl_stat_error);
3336 return isl_stat_ok;
3339 /* Align the initial parameters of space1 to match the order in space2.
3341 __isl_give isl_space *isl_space_align_params(__isl_take isl_space *space1,
3342 __isl_take isl_space *space2)
3344 isl_reordering *exp;
3346 if (isl_space_check_named_params(space1) < 0 ||
3347 isl_space_check_named_params(space2) < 0)
3348 goto error;
3350 exp = isl_parameter_alignment_reordering(space1, space2);
3351 isl_space_free(space1);
3352 isl_space_free(space2);
3353 space1 = isl_reordering_get_space(exp);
3354 isl_reordering_free(exp);
3355 return space1;
3356 error:
3357 isl_space_free(space1);
3358 isl_space_free(space2);
3359 return NULL;
3362 /* Given the space of set (domain), construct a space for a map
3363 * with as domain the given space and as range the range of "model".
3365 __isl_give isl_space *isl_space_extend_domain_with_range(
3366 __isl_take isl_space *space, __isl_take isl_space *model)
3368 isl_size n_out;
3370 if (!model)
3371 goto error;
3373 space = isl_space_from_domain(space);
3374 n_out = isl_space_dim(model, isl_dim_out);
3375 if (n_out < 0)
3376 goto error;
3377 space = isl_space_add_dims(space, isl_dim_out, n_out);
3378 if (isl_space_has_tuple_id(model, isl_dim_out))
3379 space = isl_space_set_tuple_id(space, isl_dim_out,
3380 isl_space_get_tuple_id(model, isl_dim_out));
3381 if (!space)
3382 goto error;
3383 if (model->nested[1]) {
3384 isl_space *nested = isl_space_copy(model->nested[1]);
3385 isl_size n_nested, n_space;
3386 nested = isl_space_align_params(nested, isl_space_copy(space));
3387 n_nested = isl_space_dim(nested, isl_dim_param);
3388 n_space = isl_space_dim(space, isl_dim_param);
3389 if (n_nested < 0 || n_space < 0)
3390 goto error;
3391 if (n_nested > n_space)
3392 nested = isl_space_drop_dims(nested, isl_dim_param,
3393 n_space, n_nested - n_space);
3394 if (!nested)
3395 goto error;
3396 space->nested[1] = nested;
3398 isl_space_free(model);
3399 return space;
3400 error:
3401 isl_space_free(model);
3402 isl_space_free(space);
3403 return NULL;
3406 /* Compare the "type" dimensions of two isl_spaces.
3408 * The order is fairly arbitrary.
3410 static int isl_space_cmp_type(__isl_keep isl_space *space1,
3411 __isl_keep isl_space *space2, enum isl_dim_type type)
3413 int cmp;
3414 isl_size dim1, dim2;
3415 isl_space *nested1, *nested2;
3417 dim1 = isl_space_dim(space1, type);
3418 dim2 = isl_space_dim(space2, type);
3419 if (dim1 < 0 || dim2 < 0)
3420 return 0;
3421 if (dim1 != dim2)
3422 return dim1 - dim2;
3424 cmp = isl_id_cmp(tuple_id(space1, type), tuple_id(space2, type));
3425 if (cmp != 0)
3426 return cmp;
3428 nested1 = nested(space1, type);
3429 nested2 = nested(space2, type);
3430 if (!nested1 != !nested2)
3431 return !nested1 - !nested2;
3433 if (nested1)
3434 return isl_space_cmp(nested1, nested2);
3436 return 0;
3439 /* Compare two isl_spaces.
3441 * The order is fairly arbitrary.
3443 int isl_space_cmp(__isl_keep isl_space *space1, __isl_keep isl_space *space2)
3445 int i;
3446 int cmp;
3448 if (space1 == space2)
3449 return 0;
3450 if (!space1)
3451 return -1;
3452 if (!space2)
3453 return 1;
3455 cmp = isl_space_cmp_type(space1, space2, isl_dim_param);
3456 if (cmp != 0)
3457 return cmp;
3458 cmp = isl_space_cmp_type(space1, space2, isl_dim_in);
3459 if (cmp != 0)
3460 return cmp;
3461 cmp = isl_space_cmp_type(space1, space2, isl_dim_out);
3462 if (cmp != 0)
3463 return cmp;
3465 if (!space1->ids && !space2->ids)
3466 return 0;
3468 for (i = 0; i < n(space1, isl_dim_param); ++i) {
3469 cmp = isl_id_cmp(get_id(space1, isl_dim_param, i),
3470 get_id(space2, isl_dim_param, i));
3471 if (cmp != 0)
3472 return cmp;
3475 return 0;