add basic unary isl_multi_pw_aff tests
[isl.git] / isl_local_space.c
blobbc5861f36c90a505263b095cd12c9dcdbf5ec400
1 /*
2 * Copyright 2011 INRIA Saclay
3 * Copyright 2012-2014 Ecole Normale Superieure
5 * Use of this software is governed by the MIT license
7 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
8 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
9 * 91893 Orsay, France
10 * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
13 #include <isl_ctx_private.h>
14 #include <isl_map_private.h>
15 #include <isl_local_space_private.h>
16 #include <isl_space_private.h>
17 #include <isl_mat_private.h>
18 #include <isl_aff_private.h>
19 #include <isl_vec_private.h>
20 #include <isl_seq.h>
21 #include <isl_local.h>
23 isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls)
25 return ls ? ls->dim->ctx : NULL;
28 /* Return a hash value that digests "ls".
30 uint32_t isl_local_space_get_hash(__isl_keep isl_local_space *ls)
32 uint32_t hash, space_hash, div_hash;
34 if (!ls)
35 return 0;
37 hash = isl_hash_init();
38 space_hash = isl_space_get_hash(ls->dim);
39 isl_hash_hash(hash, space_hash);
40 div_hash = isl_mat_get_hash(ls->div);
41 isl_hash_hash(hash, div_hash);
43 return hash;
46 __isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim,
47 __isl_take isl_mat *div)
49 isl_ctx *ctx;
50 isl_local_space *ls = NULL;
52 if (!dim || !div)
53 goto error;
55 ctx = isl_space_get_ctx(dim);
56 ls = isl_calloc_type(ctx, struct isl_local_space);
57 if (!ls)
58 goto error;
60 ls->ref = 1;
61 ls->dim = dim;
62 ls->div = div;
64 return ls;
65 error:
66 isl_mat_free(div);
67 isl_space_free(dim);
68 isl_local_space_free(ls);
69 return NULL;
72 __isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim,
73 unsigned n_div)
75 isl_ctx *ctx;
76 isl_mat *div;
77 unsigned total;
79 if (!dim)
80 return NULL;
82 total = isl_space_dim(dim, isl_dim_all);
84 ctx = isl_space_get_ctx(dim);
85 div = isl_mat_alloc(ctx, n_div, 1 + 1 + total + n_div);
86 return isl_local_space_alloc_div(dim, div);
89 __isl_give isl_local_space *isl_local_space_from_space(__isl_take isl_space *dim)
91 return isl_local_space_alloc(dim, 0);
94 __isl_give isl_local_space *isl_local_space_copy(__isl_keep isl_local_space *ls)
96 if (!ls)
97 return NULL;
99 ls->ref++;
100 return ls;
103 __isl_give isl_local_space *isl_local_space_dup(__isl_keep isl_local_space *ls)
105 if (!ls)
106 return NULL;
108 return isl_local_space_alloc_div(isl_space_copy(ls->dim),
109 isl_mat_copy(ls->div));
113 __isl_give isl_local_space *isl_local_space_cow(__isl_take isl_local_space *ls)
115 if (!ls)
116 return NULL;
118 if (ls->ref == 1)
119 return ls;
120 ls->ref--;
121 return isl_local_space_dup(ls);
124 __isl_null isl_local_space *isl_local_space_free(
125 __isl_take isl_local_space *ls)
127 if (!ls)
128 return NULL;
130 if (--ls->ref > 0)
131 return NULL;
133 isl_space_free(ls->dim);
134 isl_mat_free(ls->div);
136 free(ls);
138 return NULL;
141 /* Is the local space that of a parameter domain?
143 isl_bool isl_local_space_is_params(__isl_keep isl_local_space *ls)
145 if (!ls)
146 return isl_bool_error;
147 return isl_space_is_params(ls->dim);
150 /* Is the local space that of a set?
152 isl_bool isl_local_space_is_set(__isl_keep isl_local_space *ls)
154 return ls ? isl_space_is_set(ls->dim) : isl_bool_error;
157 /* Do "ls1" and "ls2" have the same space?
159 isl_bool isl_local_space_has_equal_space(__isl_keep isl_local_space *ls1,
160 __isl_keep isl_local_space *ls2)
162 if (!ls1 || !ls2)
163 return isl_bool_error;
165 return isl_space_is_equal(ls1->dim, ls2->dim);
168 /* Return true if the two local spaces are identical, with identical
169 * expressions for the integer divisions.
171 isl_bool isl_local_space_is_equal(__isl_keep isl_local_space *ls1,
172 __isl_keep isl_local_space *ls2)
174 isl_bool equal;
176 equal = isl_local_space_has_equal_space(ls1, ls2);
177 if (equal < 0 || !equal)
178 return equal;
180 if (!isl_local_space_divs_known(ls1))
181 return isl_bool_false;
182 if (!isl_local_space_divs_known(ls2))
183 return isl_bool_false;
185 return isl_mat_is_equal(ls1->div, ls2->div);
188 /* Compare two isl_local_spaces.
190 * Return -1 if "ls1" is "smaller" than "ls2", 1 if "ls1" is "greater"
191 * than "ls2" and 0 if they are equal.
193 int isl_local_space_cmp(__isl_keep isl_local_space *ls1,
194 __isl_keep isl_local_space *ls2)
196 int cmp;
198 if (ls1 == ls2)
199 return 0;
200 if (!ls1)
201 return -1;
202 if (!ls2)
203 return 1;
205 cmp = isl_space_cmp(ls1->dim, ls2->dim);
206 if (cmp != 0)
207 return cmp;
209 return isl_local_cmp(ls1->div, ls2->div);
212 int isl_local_space_dim(__isl_keep isl_local_space *ls,
213 enum isl_dim_type type)
215 if (!ls)
216 return 0;
217 if (type == isl_dim_div)
218 return ls->div->n_row;
219 if (type == isl_dim_all)
220 return isl_space_dim(ls->dim, isl_dim_all) + ls->div->n_row;
221 return isl_space_dim(ls->dim, type);
224 unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
225 enum isl_dim_type type)
227 isl_space *dim;
229 if (!ls)
230 return 0;
232 dim = ls->dim;
233 switch (type) {
234 case isl_dim_cst: return 0;
235 case isl_dim_param: return 1;
236 case isl_dim_in: return 1 + dim->nparam;
237 case isl_dim_out: return 1 + dim->nparam + dim->n_in;
238 case isl_dim_div: return 1 + dim->nparam + dim->n_in + dim->n_out;
239 default: return 0;
243 /* Return the position of the dimension of the given type and name
244 * in "ls".
245 * Return -1 if no such dimension can be found.
247 int isl_local_space_find_dim_by_name(__isl_keep isl_local_space *ls,
248 enum isl_dim_type type, const char *name)
250 if (!ls)
251 return -1;
252 if (type == isl_dim_div)
253 return -1;
254 return isl_space_find_dim_by_name(ls->dim, type, name);
257 /* Does the given dimension have a name?
259 isl_bool isl_local_space_has_dim_name(__isl_keep isl_local_space *ls,
260 enum isl_dim_type type, unsigned pos)
262 return ls ? isl_space_has_dim_name(ls->dim, type, pos) : isl_bool_error;
265 const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
266 enum isl_dim_type type, unsigned pos)
268 return ls ? isl_space_get_dim_name(ls->dim, type, pos) : NULL;
271 isl_bool isl_local_space_has_dim_id(__isl_keep isl_local_space *ls,
272 enum isl_dim_type type, unsigned pos)
274 return ls ? isl_space_has_dim_id(ls->dim, type, pos) : isl_bool_error;
277 __isl_give isl_id *isl_local_space_get_dim_id(__isl_keep isl_local_space *ls,
278 enum isl_dim_type type, unsigned pos)
280 return ls ? isl_space_get_dim_id(ls->dim, type, pos) : NULL;
283 /* Return the argument of the integer division at position "pos" in "ls".
284 * All local variables in "ls" are known to have a (complete) explicit
285 * representation.
287 static __isl_give isl_aff *extract_div(__isl_keep isl_local_space *ls, int pos)
289 isl_aff *aff;
291 aff = isl_aff_alloc(isl_local_space_copy(ls));
292 if (!aff)
293 return NULL;
294 isl_seq_cpy(aff->v->el, ls->div->row[pos], aff->v->size);
295 return aff;
298 /* Return the argument of the integer division at position "pos" in "ls".
299 * The integer division at that position is known to have a complete
300 * explicit representation, but some of the others do not.
301 * Remove them first because the domain of an isl_aff
302 * is not allowed to have unknown local variables.
304 static __isl_give isl_aff *drop_unknown_divs_and_extract_div(
305 __isl_keep isl_local_space *ls, int pos)
307 int i, n;
308 isl_bool unknown;
309 isl_aff *aff;
311 ls = isl_local_space_copy(ls);
312 n = isl_local_space_dim(ls, isl_dim_div);
313 for (i = n - 1; i >= 0; --i) {
314 unknown = isl_local_space_div_is_marked_unknown(ls, i);
315 if (unknown < 0)
316 ls = isl_local_space_free(ls);
317 else if (!unknown)
318 continue;
319 ls = isl_local_space_drop_dims(ls, isl_dim_div, i, 1);
320 if (pos > i)
321 --pos;
323 aff = extract_div(ls, pos);
324 isl_local_space_free(ls);
325 return aff;
328 /* Return the argument of the integer division at position "pos" in "ls".
329 * The integer division is assumed to have a complete explicit
330 * representation. If some of the other integer divisions
331 * do not have an explicit representation, then they need
332 * to be removed first because the domain of an isl_aff
333 * is not allowed to have unknown local variables.
335 __isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls,
336 int pos)
338 isl_bool known;
340 if (!ls)
341 return NULL;
343 if (pos < 0 || pos >= ls->div->n_row)
344 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
345 "index out of bounds", return NULL);
347 known = isl_local_space_div_is_known(ls, pos);
348 if (known < 0)
349 return NULL;
350 if (!known)
351 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
352 "expression of div unknown", return NULL);
353 if (!isl_local_space_is_set(ls))
354 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
355 "cannot represent divs of map spaces", return NULL);
357 known = isl_local_space_divs_known(ls);
358 if (known < 0)
359 return NULL;
360 if (known)
361 return extract_div(ls, pos);
362 else
363 return drop_unknown_divs_and_extract_div(ls, pos);
366 __isl_give isl_space *isl_local_space_get_space(__isl_keep isl_local_space *ls)
368 if (!ls)
369 return NULL;
371 return isl_space_copy(ls->dim);
374 /* Return the space of "ls".
375 * This may be either a copy or the space itself
376 * if there is only one reference to "ls".
377 * This allows the space to be modified inplace
378 * if both the local space and its space have only a single reference.
379 * The caller is not allowed to modify "ls" between this call and
380 * a subsequent call to isl_local_space_restore_space.
381 * The only exception is that isl_local_space_free can be called instead.
383 __isl_give isl_space *isl_local_space_take_space(__isl_keep isl_local_space *ls)
385 isl_space *space;
387 if (!ls)
388 return NULL;
389 if (ls->ref != 1)
390 return isl_local_space_get_space(ls);
391 space = ls->dim;
392 ls->dim = NULL;
393 return space;
396 /* Set the space of "ls" to "space", where the space of "ls" may be missing
397 * due to a preceding call to isl_local_space_take_space.
398 * However, in this case, "ls" only has a single reference and
399 * then the call to isl_local_space_cow has no effect.
401 __isl_give isl_local_space *isl_local_space_restore_space(
402 __isl_take isl_local_space *ls, __isl_take isl_space *space)
404 if (!ls || !space)
405 goto error;
407 if (ls->dim == space) {
408 isl_space_free(space);
409 return ls;
412 ls = isl_local_space_cow(ls);
413 if (!ls)
414 goto error;
415 isl_space_free(ls->dim);
416 ls->dim = space;
418 return ls;
419 error:
420 isl_local_space_free(ls);
421 isl_space_free(space);
422 return NULL;
425 /* Replace the identifier of the tuple of type "type" by "id".
427 __isl_give isl_local_space *isl_local_space_set_tuple_id(
428 __isl_take isl_local_space *ls,
429 enum isl_dim_type type, __isl_take isl_id *id)
431 ls = isl_local_space_cow(ls);
432 if (!ls)
433 goto error;
434 ls->dim = isl_space_set_tuple_id(ls->dim, type, id);
435 if (!ls->dim)
436 return isl_local_space_free(ls);
437 return ls;
438 error:
439 isl_id_free(id);
440 return NULL;
443 __isl_give isl_local_space *isl_local_space_set_dim_name(
444 __isl_take isl_local_space *ls,
445 enum isl_dim_type type, unsigned pos, const char *s)
447 ls = isl_local_space_cow(ls);
448 if (!ls)
449 return NULL;
450 ls->dim = isl_space_set_dim_name(ls->dim, type, pos, s);
451 if (!ls->dim)
452 return isl_local_space_free(ls);
454 return ls;
457 __isl_give isl_local_space *isl_local_space_set_dim_id(
458 __isl_take isl_local_space *ls,
459 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
461 ls = isl_local_space_cow(ls);
462 if (!ls)
463 goto error;
464 ls->dim = isl_space_set_dim_id(ls->dim, type, pos, id);
465 if (!ls->dim)
466 return isl_local_space_free(ls);
468 return ls;
469 error:
470 isl_id_free(id);
471 return NULL;
474 /* Construct a zero-dimensional local space with the given parameter domain.
476 __isl_give isl_local_space *isl_local_space_set_from_params(
477 __isl_take isl_local_space *ls)
479 isl_space *space;
481 space = isl_local_space_take_space(ls);
482 space = isl_space_set_from_params(space);
483 ls = isl_local_space_restore_space(ls, space);
485 return ls;
488 __isl_give isl_local_space *isl_local_space_reset_space(
489 __isl_take isl_local_space *ls, __isl_take isl_space *dim)
491 ls = isl_local_space_cow(ls);
492 if (!ls || !dim)
493 goto error;
495 isl_space_free(ls->dim);
496 ls->dim = dim;
498 return ls;
499 error:
500 isl_local_space_free(ls);
501 isl_space_free(dim);
502 return NULL;
505 /* Reorder the columns of the given div definitions according to the
506 * given reordering.
507 * The order of the divs themselves is assumed not to change.
509 static __isl_give isl_mat *reorder_divs(__isl_take isl_mat *div,
510 __isl_take isl_reordering *r)
512 int i, j;
513 isl_mat *mat;
514 int extra;
516 if (!div || !r)
517 goto error;
519 extra = isl_space_dim(r->dim, isl_dim_all) + div->n_row - r->len;
520 mat = isl_mat_alloc(div->ctx, div->n_row, div->n_col + extra);
521 if (!mat)
522 goto error;
524 for (i = 0; i < div->n_row; ++i) {
525 isl_seq_cpy(mat->row[i], div->row[i], 2);
526 isl_seq_clr(mat->row[i] + 2, mat->n_col - 2);
527 for (j = 0; j < r->len; ++j)
528 isl_int_set(mat->row[i][2 + r->pos[j]],
529 div->row[i][2 + j]);
532 isl_reordering_free(r);
533 isl_mat_free(div);
534 return mat;
535 error:
536 isl_reordering_free(r);
537 isl_mat_free(div);
538 return NULL;
541 /* Reorder the dimensions of "ls" according to the given reordering.
542 * The reordering r is assumed to have been extended with the local
543 * variables, leaving them in the same order.
545 __isl_give isl_local_space *isl_local_space_realign(
546 __isl_take isl_local_space *ls, __isl_take isl_reordering *r)
548 ls = isl_local_space_cow(ls);
549 if (!ls || !r)
550 goto error;
552 ls->div = reorder_divs(ls->div, isl_reordering_copy(r));
553 if (!ls->div)
554 goto error;
556 ls = isl_local_space_reset_space(ls, isl_space_copy(r->dim));
558 isl_reordering_free(r);
559 return ls;
560 error:
561 isl_local_space_free(ls);
562 isl_reordering_free(r);
563 return NULL;
566 __isl_give isl_local_space *isl_local_space_add_div(
567 __isl_take isl_local_space *ls, __isl_take isl_vec *div)
569 ls = isl_local_space_cow(ls);
570 if (!ls || !div)
571 goto error;
573 if (ls->div->n_col != div->size)
574 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
575 "incompatible dimensions", goto error);
577 ls->div = isl_mat_add_zero_cols(ls->div, 1);
578 ls->div = isl_mat_add_rows(ls->div, 1);
579 if (!ls->div)
580 goto error;
582 isl_seq_cpy(ls->div->row[ls->div->n_row - 1], div->el, div->size);
583 isl_int_set_si(ls->div->row[ls->div->n_row - 1][div->size], 0);
585 isl_vec_free(div);
586 return ls;
587 error:
588 isl_local_space_free(ls);
589 isl_vec_free(div);
590 return NULL;
593 __isl_give isl_local_space *isl_local_space_replace_divs(
594 __isl_take isl_local_space *ls, __isl_take isl_mat *div)
596 ls = isl_local_space_cow(ls);
598 if (!ls || !div)
599 goto error;
601 isl_mat_free(ls->div);
602 ls->div = div;
603 return ls;
604 error:
605 isl_mat_free(div);
606 isl_local_space_free(ls);
607 return NULL;
610 /* Copy row "s" of "src" to row "d" of "dst", applying the expansion
611 * defined by "exp".
613 static void expand_row(__isl_keep isl_mat *dst, int d,
614 __isl_keep isl_mat *src, int s, int *exp)
616 int i;
617 unsigned c = src->n_col - src->n_row;
619 isl_seq_cpy(dst->row[d], src->row[s], c);
620 isl_seq_clr(dst->row[d] + c, dst->n_col - c);
622 for (i = 0; i < s; ++i)
623 isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
626 /* Compare (known) divs.
627 * Return non-zero if at least one of the two divs is unknown.
628 * In particular, if both divs are unknown, we respect their
629 * current order. Otherwise, we sort the known div after the unknown
630 * div only if the known div depends on the unknown div.
632 static int cmp_row(isl_int *row_i, isl_int *row_j, int i, int j,
633 unsigned n_row, unsigned n_col)
635 int li, lj;
636 int unknown_i, unknown_j;
638 unknown_i = isl_int_is_zero(row_i[0]);
639 unknown_j = isl_int_is_zero(row_j[0]);
641 if (unknown_i && unknown_j)
642 return i - j;
644 if (unknown_i)
645 li = n_col - n_row + i;
646 else
647 li = isl_seq_last_non_zero(row_i, n_col);
648 if (unknown_j)
649 lj = n_col - n_row + j;
650 else
651 lj = isl_seq_last_non_zero(row_j, n_col);
653 if (li != lj)
654 return li - lj;
656 return isl_seq_cmp(row_i, row_j, n_col);
659 /* Call cmp_row for divs in a matrix.
661 int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j)
663 return cmp_row(div->row[i], div->row[j], i, j, div->n_row, div->n_col);
666 /* Call cmp_row for divs in a basic map.
668 static int bmap_cmp_row(__isl_keep isl_basic_map *bmap, int i, int j,
669 unsigned total)
671 return cmp_row(bmap->div[i], bmap->div[j], i, j, bmap->n_div, total);
674 /* Sort the divs in "bmap".
676 * We first make sure divs are placed after divs on which they depend.
677 * Then we perform a simple insertion sort based on the same ordering
678 * that is used in isl_merge_divs.
680 __isl_give isl_basic_map *isl_basic_map_sort_divs(
681 __isl_take isl_basic_map *bmap)
683 int i, j;
684 unsigned total;
686 bmap = isl_basic_map_order_divs(bmap);
687 if (!bmap)
688 return NULL;
689 if (bmap->n_div <= 1)
690 return bmap;
692 total = 2 + isl_basic_map_total_dim(bmap);
693 for (i = 1; i < bmap->n_div; ++i) {
694 for (j = i - 1; j >= 0; --j) {
695 if (bmap_cmp_row(bmap, j, j + 1, total) <= 0)
696 break;
697 isl_basic_map_swap_div(bmap, j, j + 1);
701 return bmap;
704 /* Sort the divs in the basic maps of "map".
706 __isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map)
708 return isl_map_inline_foreach_basic_map(map, &isl_basic_map_sort_divs);
711 /* Combine the two lists of divs into a single list.
712 * For each row i in div1, exp1[i] is set to the position of the corresponding
713 * row in the result. Similarly for div2 and exp2.
714 * This function guarantees
715 * exp1[i] >= i
716 * exp1[i+1] > exp1[i]
717 * For optimal merging, the two input list should have been sorted.
719 __isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
720 __isl_keep isl_mat *div2, int *exp1, int *exp2)
722 int i, j, k;
723 isl_mat *div = NULL;
724 unsigned d;
726 if (!div1 || !div2)
727 return NULL;
729 d = div1->n_col - div1->n_row;
730 div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
731 d + div1->n_row + div2->n_row);
732 if (!div)
733 return NULL;
735 for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
736 int cmp;
738 expand_row(div, k, div1, i, exp1);
739 expand_row(div, k + 1, div2, j, exp2);
741 cmp = isl_mat_cmp_div(div, k, k + 1);
742 if (cmp == 0) {
743 exp1[i++] = k;
744 exp2[j++] = k;
745 } else if (cmp < 0) {
746 exp1[i++] = k;
747 } else {
748 exp2[j++] = k;
749 isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
752 for (; i < div1->n_row; ++i, ++k) {
753 expand_row(div, k, div1, i, exp1);
754 exp1[i] = k;
756 for (; j < div2->n_row; ++j, ++k) {
757 expand_row(div, k, div2, j, exp2);
758 exp2[j] = k;
761 div->n_row = k;
762 div->n_col = d + k;
764 return div;
767 /* Swap divs "a" and "b" in "ls".
769 __isl_give isl_local_space *isl_local_space_swap_div(
770 __isl_take isl_local_space *ls, int a, int b)
772 int offset;
774 ls = isl_local_space_cow(ls);
775 if (!ls)
776 return NULL;
777 if (a < 0 || a >= ls->div->n_row || b < 0 || b >= ls->div->n_row)
778 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
779 "index out of bounds", return isl_local_space_free(ls));
780 offset = ls->div->n_col - ls->div->n_row;
781 ls->div = isl_mat_swap_cols(ls->div, offset + a, offset + b);
782 ls->div = isl_mat_swap_rows(ls->div, a, b);
783 if (!ls->div)
784 return isl_local_space_free(ls);
785 return ls;
788 /* Construct a local space that contains all the divs in either
789 * "ls1" or "ls2".
791 __isl_give isl_local_space *isl_local_space_intersect(
792 __isl_take isl_local_space *ls1, __isl_take isl_local_space *ls2)
794 isl_ctx *ctx;
795 int *exp1 = NULL;
796 int *exp2 = NULL;
797 isl_mat *div = NULL;
798 isl_bool equal;
800 if (!ls1 || !ls2)
801 goto error;
803 ctx = isl_local_space_get_ctx(ls1);
804 if (!isl_space_is_equal(ls1->dim, ls2->dim))
805 isl_die(ctx, isl_error_invalid,
806 "spaces should be identical", goto error);
808 if (ls2->div->n_row == 0) {
809 isl_local_space_free(ls2);
810 return ls1;
813 if (ls1->div->n_row == 0) {
814 isl_local_space_free(ls1);
815 return ls2;
818 exp1 = isl_alloc_array(ctx, int, ls1->div->n_row);
819 exp2 = isl_alloc_array(ctx, int, ls2->div->n_row);
820 if (!exp1 || !exp2)
821 goto error;
823 div = isl_merge_divs(ls1->div, ls2->div, exp1, exp2);
824 if (!div)
825 goto error;
827 equal = isl_mat_is_equal(ls1->div, div);
828 if (equal < 0)
829 goto error;
830 if (!equal)
831 ls1 = isl_local_space_cow(ls1);
832 if (!ls1)
833 goto error;
835 free(exp1);
836 free(exp2);
837 isl_local_space_free(ls2);
838 isl_mat_free(ls1->div);
839 ls1->div = div;
841 return ls1;
842 error:
843 free(exp1);
844 free(exp2);
845 isl_mat_free(div);
846 isl_local_space_free(ls1);
847 isl_local_space_free(ls2);
848 return NULL;
851 /* Is the local variable "div" of "ls" marked as not having
852 * an explicit representation?
853 * Note that even if this variable is not marked in this way and therefore
854 * does have an explicit representation, this representation may still
855 * depend (indirectly) on other local variables that do not
856 * have an explicit representation.
858 isl_bool isl_local_space_div_is_marked_unknown(__isl_keep isl_local_space *ls,
859 int div)
861 if (!ls)
862 return isl_bool_error;
863 return isl_local_div_is_marked_unknown(ls->div, div);
866 /* Does "ls" have a complete explicit representation for div "div"?
868 isl_bool isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div)
870 if (!ls)
871 return isl_bool_error;
872 return isl_local_div_is_known(ls->div, div);
875 /* Does "ls" have an explicit representation for all local variables?
877 isl_bool isl_local_space_divs_known(__isl_keep isl_local_space *ls)
879 int i;
881 if (!ls)
882 return isl_bool_error;
884 for (i = 0; i < ls->div->n_row; ++i) {
885 isl_bool unknown = isl_local_space_div_is_marked_unknown(ls, i);
886 if (unknown < 0 || unknown)
887 return isl_bool_not(unknown);
890 return isl_bool_true;
893 __isl_give isl_local_space *isl_local_space_domain(
894 __isl_take isl_local_space *ls)
896 ls = isl_local_space_drop_dims(ls, isl_dim_out,
897 0, isl_local_space_dim(ls, isl_dim_out));
898 ls = isl_local_space_cow(ls);
899 if (!ls)
900 return NULL;
901 ls->dim = isl_space_domain(ls->dim);
902 if (!ls->dim)
903 return isl_local_space_free(ls);
904 return ls;
907 __isl_give isl_local_space *isl_local_space_range(
908 __isl_take isl_local_space *ls)
910 ls = isl_local_space_drop_dims(ls, isl_dim_in,
911 0, isl_local_space_dim(ls, isl_dim_in));
912 ls = isl_local_space_cow(ls);
913 if (!ls)
914 return NULL;
916 ls->dim = isl_space_range(ls->dim);
917 if (!ls->dim)
918 return isl_local_space_free(ls);
919 return ls;
922 /* Construct a local space for a map that has the given local
923 * space as domain and that has a zero-dimensional range.
925 __isl_give isl_local_space *isl_local_space_from_domain(
926 __isl_take isl_local_space *ls)
928 ls = isl_local_space_cow(ls);
929 if (!ls)
930 return NULL;
931 ls->dim = isl_space_from_domain(ls->dim);
932 if (!ls->dim)
933 return isl_local_space_free(ls);
934 return ls;
937 __isl_give isl_local_space *isl_local_space_add_dims(
938 __isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n)
940 int pos;
942 if (!ls)
943 return NULL;
944 pos = isl_local_space_dim(ls, type);
945 return isl_local_space_insert_dims(ls, type, pos, n);
948 /* Remove common factor of non-constant terms and denominator.
950 static void normalize_div(__isl_keep isl_local_space *ls, int div)
952 isl_ctx *ctx = ls->div->ctx;
953 unsigned total = ls->div->n_col - 2;
955 isl_seq_gcd(ls->div->row[div] + 2, total, &ctx->normalize_gcd);
956 isl_int_gcd(ctx->normalize_gcd,
957 ctx->normalize_gcd, ls->div->row[div][0]);
958 if (isl_int_is_one(ctx->normalize_gcd))
959 return;
961 isl_seq_scale_down(ls->div->row[div] + 2, ls->div->row[div] + 2,
962 ctx->normalize_gcd, total);
963 isl_int_divexact(ls->div->row[div][0], ls->div->row[div][0],
964 ctx->normalize_gcd);
965 isl_int_fdiv_q(ls->div->row[div][1], ls->div->row[div][1],
966 ctx->normalize_gcd);
969 /* Exploit the equalities in "eq" to simplify the expressions of
970 * the integer divisions in "ls".
971 * The integer divisions in "ls" are assumed to appear as regular
972 * dimensions in "eq".
974 __isl_give isl_local_space *isl_local_space_substitute_equalities(
975 __isl_take isl_local_space *ls, __isl_take isl_basic_set *eq)
977 int i, j, k;
978 unsigned total;
979 unsigned n_div;
981 if (!ls || !eq)
982 goto error;
984 total = isl_space_dim(eq->dim, isl_dim_all);
985 if (isl_local_space_dim(ls, isl_dim_all) != total)
986 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
987 "spaces don't match", goto error);
988 total++;
989 n_div = eq->n_div;
990 for (i = 0; i < eq->n_eq; ++i) {
991 j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
992 if (j < 0 || j == 0 || j >= total)
993 continue;
995 for (k = 0; k < ls->div->n_row; ++k) {
996 if (isl_int_is_zero(ls->div->row[k][1 + j]))
997 continue;
998 ls = isl_local_space_cow(ls);
999 if (!ls)
1000 goto error;
1001 ls->div = isl_mat_cow(ls->div);
1002 if (!ls->div)
1003 goto error;
1004 isl_seq_elim(ls->div->row[k] + 1, eq->eq[i], j, total,
1005 &ls->div->row[k][0]);
1006 normalize_div(ls, k);
1010 isl_basic_set_free(eq);
1011 return ls;
1012 error:
1013 isl_basic_set_free(eq);
1014 isl_local_space_free(ls);
1015 return NULL;
1018 /* Plug in the affine expressions "subs" of length "subs_len" (including
1019 * the denominator and the constant term) into the variable at position "pos"
1020 * of the "n" div expressions starting at "first".
1022 * Let i be the dimension to replace and let "subs" be of the form
1024 * f/d
1026 * Any integer division starting at "first" with a non-zero coefficient for i,
1028 * floor((a i + g)/m)
1030 * is replaced by
1032 * floor((a f + d g)/(m d))
1034 __isl_give isl_local_space *isl_local_space_substitute_seq(
1035 __isl_take isl_local_space *ls,
1036 enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len,
1037 int first, int n)
1039 int i;
1040 isl_int v;
1042 if (n == 0)
1043 return ls;
1044 ls = isl_local_space_cow(ls);
1045 if (!ls)
1046 return NULL;
1047 ls->div = isl_mat_cow(ls->div);
1048 if (!ls->div)
1049 return isl_local_space_free(ls);
1051 if (first + n > ls->div->n_row)
1052 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1053 "index out of bounds", return isl_local_space_free(ls));
1055 pos += isl_local_space_offset(ls, type);
1057 isl_int_init(v);
1058 for (i = first; i < first + n; ++i) {
1059 if (isl_int_is_zero(ls->div->row[i][1 + pos]))
1060 continue;
1061 isl_seq_substitute(ls->div->row[i], pos, subs,
1062 ls->div->n_col, subs_len, v);
1063 normalize_div(ls, i);
1065 isl_int_clear(v);
1067 return ls;
1070 /* Plug in "subs" for dimension "type", "pos" in the integer divisions
1071 * of "ls".
1073 * Let i be the dimension to replace and let "subs" be of the form
1075 * f/d
1077 * Any integer division with a non-zero coefficient for i,
1079 * floor((a i + g)/m)
1081 * is replaced by
1083 * floor((a f + d g)/(m d))
1085 __isl_give isl_local_space *isl_local_space_substitute(
1086 __isl_take isl_local_space *ls,
1087 enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
1089 ls = isl_local_space_cow(ls);
1090 if (!ls || !subs)
1091 return isl_local_space_free(ls);
1093 if (!isl_space_is_equal(ls->dim, subs->ls->dim))
1094 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1095 "spaces don't match", return isl_local_space_free(ls));
1096 if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
1097 isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
1098 "cannot handle divs yet",
1099 return isl_local_space_free(ls));
1101 return isl_local_space_substitute_seq(ls, type, pos, subs->v->el,
1102 subs->v->size, 0, ls->div->n_row);
1105 isl_bool isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
1106 enum isl_dim_type type)
1108 if (!ls)
1109 return isl_bool_error;
1110 return isl_space_is_named_or_nested(ls->dim, type);
1113 __isl_give isl_local_space *isl_local_space_drop_dims(
1114 __isl_take isl_local_space *ls,
1115 enum isl_dim_type type, unsigned first, unsigned n)
1117 isl_ctx *ctx;
1119 if (!ls)
1120 return NULL;
1121 if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
1122 return ls;
1124 ctx = isl_local_space_get_ctx(ls);
1125 if (first + n > isl_local_space_dim(ls, type))
1126 isl_die(ctx, isl_error_invalid, "range out of bounds",
1127 return isl_local_space_free(ls));
1129 ls = isl_local_space_cow(ls);
1130 if (!ls)
1131 return NULL;
1133 if (type == isl_dim_div) {
1134 ls->div = isl_mat_drop_rows(ls->div, first, n);
1135 } else {
1136 ls->dim = isl_space_drop_dims(ls->dim, type, first, n);
1137 if (!ls->dim)
1138 return isl_local_space_free(ls);
1141 first += 1 + isl_local_space_offset(ls, type);
1142 ls->div = isl_mat_drop_cols(ls->div, first, n);
1143 if (!ls->div)
1144 return isl_local_space_free(ls);
1146 return ls;
1149 __isl_give isl_local_space *isl_local_space_insert_dims(
1150 __isl_take isl_local_space *ls,
1151 enum isl_dim_type type, unsigned first, unsigned n)
1153 isl_ctx *ctx;
1155 if (!ls)
1156 return NULL;
1157 if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
1158 return ls;
1160 ctx = isl_local_space_get_ctx(ls);
1161 if (first > isl_local_space_dim(ls, type))
1162 isl_die(ctx, isl_error_invalid, "position out of bounds",
1163 return isl_local_space_free(ls));
1165 ls = isl_local_space_cow(ls);
1166 if (!ls)
1167 return NULL;
1169 if (type == isl_dim_div) {
1170 ls->div = isl_mat_insert_zero_rows(ls->div, first, n);
1171 } else {
1172 ls->dim = isl_space_insert_dims(ls->dim, type, first, n);
1173 if (!ls->dim)
1174 return isl_local_space_free(ls);
1177 first += 1 + isl_local_space_offset(ls, type);
1178 ls->div = isl_mat_insert_zero_cols(ls->div, first, n);
1179 if (!ls->div)
1180 return isl_local_space_free(ls);
1182 return ls;
1185 /* Check if the constraints pointed to by "constraint" is a div
1186 * constraint corresponding to div "div" in "ls".
1188 * That is, if div = floor(f/m), then check if the constraint is
1190 * f - m d >= 0
1191 * or
1192 * -(f-(m-1)) + m d >= 0
1194 isl_bool isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls,
1195 isl_int *constraint, unsigned div)
1197 unsigned pos;
1199 if (!ls)
1200 return isl_bool_error;
1202 if (isl_int_is_zero(ls->div->row[div][0]))
1203 return isl_bool_false;
1205 pos = isl_local_space_offset(ls, isl_dim_div) + div;
1207 if (isl_int_eq(constraint[pos], ls->div->row[div][0])) {
1208 int neg;
1209 isl_int_sub(ls->div->row[div][1],
1210 ls->div->row[div][1], ls->div->row[div][0]);
1211 isl_int_add_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
1212 neg = isl_seq_is_neg(constraint, ls->div->row[div]+1, pos);
1213 isl_int_sub_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
1214 isl_int_add(ls->div->row[div][1],
1215 ls->div->row[div][1], ls->div->row[div][0]);
1216 if (!neg)
1217 return isl_bool_false;
1218 if (isl_seq_first_non_zero(constraint+pos+1,
1219 ls->div->n_row-div-1) != -1)
1220 return isl_bool_false;
1221 } else if (isl_int_abs_eq(constraint[pos], ls->div->row[div][0])) {
1222 if (!isl_seq_eq(constraint, ls->div->row[div]+1, pos))
1223 return isl_bool_false;
1224 if (isl_seq_first_non_zero(constraint+pos+1,
1225 ls->div->n_row-div-1) != -1)
1226 return isl_bool_false;
1227 } else
1228 return isl_bool_false;
1230 return isl_bool_true;
1234 * Set active[i] to 1 if the dimension at position i is involved
1235 * in the linear expression l.
1237 int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l)
1239 int i, j;
1240 isl_ctx *ctx;
1241 int *active = NULL;
1242 unsigned total;
1243 unsigned offset;
1245 ctx = isl_local_space_get_ctx(ls);
1246 total = isl_local_space_dim(ls, isl_dim_all);
1247 active = isl_calloc_array(ctx, int, total);
1248 if (total && !active)
1249 return NULL;
1251 for (i = 0; i < total; ++i)
1252 active[i] = !isl_int_is_zero(l[i]);
1254 offset = isl_local_space_offset(ls, isl_dim_div) - 1;
1255 for (i = ls->div->n_row - 1; i >= 0; --i) {
1256 if (!active[offset + i])
1257 continue;
1258 for (j = 0; j < total; ++j)
1259 active[j] |= !isl_int_is_zero(ls->div->row[i][2 + j]);
1262 return active;
1265 /* Given a local space "ls" of a set, create a local space
1266 * for the lift of the set. In particular, the result
1267 * is of the form [dim -> local[..]], with ls->div->n_row variables in the
1268 * range of the wrapped map.
1270 __isl_give isl_local_space *isl_local_space_lift(
1271 __isl_take isl_local_space *ls)
1273 ls = isl_local_space_cow(ls);
1274 if (!ls)
1275 return NULL;
1277 ls->dim = isl_space_lift(ls->dim, ls->div->n_row);
1278 ls->div = isl_mat_drop_rows(ls->div, 0, ls->div->n_row);
1279 if (!ls->dim || !ls->div)
1280 return isl_local_space_free(ls);
1282 return ls;
1285 /* Construct a basic map that maps a set living in local space "ls"
1286 * to the corresponding lifted local space.
1288 __isl_give isl_basic_map *isl_local_space_lifting(
1289 __isl_take isl_local_space *ls)
1291 isl_basic_map *lifting;
1292 isl_basic_set *bset;
1294 if (!ls)
1295 return NULL;
1296 if (!isl_local_space_is_set(ls))
1297 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1298 "lifting only defined on set spaces", goto error);
1300 bset = isl_basic_set_from_local_space(ls);
1301 lifting = isl_basic_set_unwrap(isl_basic_set_lift(bset));
1302 lifting = isl_basic_map_domain_map(lifting);
1303 lifting = isl_basic_map_reverse(lifting);
1305 return lifting;
1306 error:
1307 isl_local_space_free(ls);
1308 return NULL;
1311 /* Compute the preimage of "ls" under the function represented by "ma".
1312 * In other words, plug in "ma" in "ls". The result is a local space
1313 * that is part of the domain space of "ma".
1315 * If the divs in "ls" are represented as
1317 * floor((a_i(p) + b_i x + c_i(divs))/n_i)
1319 * and ma is represented by
1321 * x = D(p) + F(y) + G(divs')
1323 * then the resulting divs are
1325 * floor((a_i(p) + b_i D(p) + b_i F(y) + B_i G(divs') + c_i(divs))/n_i)
1327 * We first copy over the divs from "ma" and then
1328 * we add the modified divs from "ls".
1330 __isl_give isl_local_space *isl_local_space_preimage_multi_aff(
1331 __isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma)
1333 int i;
1334 isl_space *space;
1335 isl_local_space *res = NULL;
1336 int n_div_ls, n_div_ma;
1337 isl_int f, c1, c2, g;
1339 ma = isl_multi_aff_align_divs(ma);
1340 if (!ls || !ma)
1341 goto error;
1342 if (!isl_space_is_range_internal(ls->dim, ma->space))
1343 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1344 "spaces don't match", goto error);
1346 n_div_ls = isl_local_space_dim(ls, isl_dim_div);
1347 n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0;
1349 space = isl_space_domain(isl_multi_aff_get_space(ma));
1350 res = isl_local_space_alloc(space, n_div_ma + n_div_ls);
1351 if (!res)
1352 goto error;
1354 if (n_div_ma) {
1355 isl_mat_free(res->div);
1356 res->div = isl_mat_copy(ma->p[0]->ls->div);
1357 res->div = isl_mat_add_zero_cols(res->div, n_div_ls);
1358 res->div = isl_mat_add_rows(res->div, n_div_ls);
1359 if (!res->div)
1360 goto error;
1363 isl_int_init(f);
1364 isl_int_init(c1);
1365 isl_int_init(c2);
1366 isl_int_init(g);
1368 for (i = 0; i < ls->div->n_row; ++i) {
1369 if (isl_int_is_zero(ls->div->row[i][0])) {
1370 isl_int_set_si(res->div->row[n_div_ma + i][0], 0);
1371 continue;
1373 isl_seq_preimage(res->div->row[n_div_ma + i], ls->div->row[i],
1374 ma, 0, 0, n_div_ma, n_div_ls, f, c1, c2, g, 1);
1375 normalize_div(res, n_div_ma + i);
1378 isl_int_clear(f);
1379 isl_int_clear(c1);
1380 isl_int_clear(c2);
1381 isl_int_clear(g);
1383 isl_local_space_free(ls);
1384 isl_multi_aff_free(ma);
1385 return res;
1386 error:
1387 isl_local_space_free(ls);
1388 isl_multi_aff_free(ma);
1389 isl_local_space_free(res);
1390 return NULL;
1393 /* Move the "n" dimensions of "src_type" starting at "src_pos" of "ls"
1394 * to dimensions of "dst_type" at "dst_pos".
1396 * Moving to/from local dimensions is not allowed.
1397 * We currently assume that the dimension type changes.
1399 __isl_give isl_local_space *isl_local_space_move_dims(
1400 __isl_take isl_local_space *ls,
1401 enum isl_dim_type dst_type, unsigned dst_pos,
1402 enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1404 unsigned g_dst_pos;
1405 unsigned g_src_pos;
1407 if (!ls)
1408 return NULL;
1409 if (n == 0 &&
1410 !isl_local_space_is_named_or_nested(ls, src_type) &&
1411 !isl_local_space_is_named_or_nested(ls, dst_type))
1412 return ls;
1414 if (src_pos + n > isl_local_space_dim(ls, src_type))
1415 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1416 "range out of bounds", return isl_local_space_free(ls));
1417 if (dst_pos > isl_local_space_dim(ls, dst_type))
1418 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1419 "position out of bounds",
1420 return isl_local_space_free(ls));
1421 if (src_type == isl_dim_div)
1422 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1423 "cannot move divs", return isl_local_space_free(ls));
1424 if (dst_type == isl_dim_div)
1425 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1426 "cannot move to divs", return isl_local_space_free(ls));
1427 if (dst_type == src_type && dst_pos == src_pos)
1428 return ls;
1429 if (dst_type == src_type)
1430 isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
1431 "moving dims within the same type not supported",
1432 return isl_local_space_free(ls));
1434 ls = isl_local_space_cow(ls);
1435 if (!ls)
1436 return NULL;
1438 g_src_pos = 1 + isl_local_space_offset(ls, src_type) + src_pos;
1439 g_dst_pos = 1 + isl_local_space_offset(ls, dst_type) + dst_pos;
1440 if (dst_type > src_type)
1441 g_dst_pos -= n;
1442 ls->div = isl_mat_move_cols(ls->div, g_dst_pos, g_src_pos, n);
1443 if (!ls->div)
1444 return isl_local_space_free(ls);
1445 ls->dim = isl_space_move_dims(ls->dim, dst_type, dst_pos,
1446 src_type, src_pos, n);
1447 if (!ls->dim)
1448 return isl_local_space_free(ls);
1450 return ls;
1453 /* Remove any internal structure of the domain of "ls".
1454 * If there is any such internal structure in the input,
1455 * then the name of the corresponding space is also removed.
1457 __isl_give isl_local_space *isl_local_space_flatten_domain(
1458 __isl_take isl_local_space *ls)
1460 if (!ls)
1461 return NULL;
1463 if (!ls->dim->nested[0])
1464 return ls;
1466 ls = isl_local_space_cow(ls);
1467 if (!ls)
1468 return NULL;
1470 ls->dim = isl_space_flatten_domain(ls->dim);
1471 if (!ls->dim)
1472 return isl_local_space_free(ls);
1474 return ls;
1477 /* Remove any internal structure of the range of "ls".
1478 * If there is any such internal structure in the input,
1479 * then the name of the corresponding space is also removed.
1481 __isl_give isl_local_space *isl_local_space_flatten_range(
1482 __isl_take isl_local_space *ls)
1484 if (!ls)
1485 return NULL;
1487 if (!ls->dim->nested[1])
1488 return ls;
1490 ls = isl_local_space_cow(ls);
1491 if (!ls)
1492 return NULL;
1494 ls->dim = isl_space_flatten_range(ls->dim);
1495 if (!ls->dim)
1496 return isl_local_space_free(ls);
1498 return ls;
1501 /* Given the local space "ls" of a map, return the local space of a set
1502 * that lives in a space that wraps the space of "ls" and that has
1503 * the same divs.
1505 __isl_give isl_local_space *isl_local_space_wrap(__isl_take isl_local_space *ls)
1507 ls = isl_local_space_cow(ls);
1508 if (!ls)
1509 return NULL;
1511 ls->dim = isl_space_wrap(ls->dim);
1512 if (!ls->dim)
1513 return isl_local_space_free(ls);
1515 return ls;