AX_DETECT_GIT_HEAD: avoid empty version string
[isl.git] / isl_local_space.c
blobd587713bb553faf48ba264ab2186ebe5302a7028
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>
22 isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls)
24 return ls ? ls->dim->ctx : NULL;
27 __isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim,
28 __isl_take isl_mat *div)
30 isl_ctx *ctx;
31 isl_local_space *ls = NULL;
33 if (!dim || !div)
34 goto error;
36 ctx = isl_space_get_ctx(dim);
37 ls = isl_calloc_type(ctx, struct isl_local_space);
38 if (!ls)
39 goto error;
41 ls->ref = 1;
42 ls->dim = dim;
43 ls->div = div;
45 return ls;
46 error:
47 isl_mat_free(div);
48 isl_space_free(dim);
49 isl_local_space_free(ls);
50 return NULL;
53 __isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim,
54 unsigned n_div)
56 isl_ctx *ctx;
57 isl_mat *div;
58 unsigned total;
60 if (!dim)
61 return NULL;
63 total = isl_space_dim(dim, isl_dim_all);
65 ctx = isl_space_get_ctx(dim);
66 div = isl_mat_alloc(ctx, n_div, 1 + 1 + total + n_div);
67 return isl_local_space_alloc_div(dim, div);
70 __isl_give isl_local_space *isl_local_space_from_space(__isl_take isl_space *dim)
72 return isl_local_space_alloc(dim, 0);
75 __isl_give isl_local_space *isl_local_space_copy(__isl_keep isl_local_space *ls)
77 if (!ls)
78 return NULL;
80 ls->ref++;
81 return ls;
84 __isl_give isl_local_space *isl_local_space_dup(__isl_keep isl_local_space *ls)
86 if (!ls)
87 return NULL;
89 return isl_local_space_alloc_div(isl_space_copy(ls->dim),
90 isl_mat_copy(ls->div));
94 __isl_give isl_local_space *isl_local_space_cow(__isl_take isl_local_space *ls)
96 if (!ls)
97 return NULL;
99 if (ls->ref == 1)
100 return ls;
101 ls->ref--;
102 return isl_local_space_dup(ls);
105 __isl_null isl_local_space *isl_local_space_free(
106 __isl_take isl_local_space *ls)
108 if (!ls)
109 return NULL;
111 if (--ls->ref > 0)
112 return NULL;
114 isl_space_free(ls->dim);
115 isl_mat_free(ls->div);
117 free(ls);
119 return NULL;
122 /* Is the local space that of a set?
124 int isl_local_space_is_set(__isl_keep isl_local_space *ls)
126 return ls ? isl_space_is_set(ls->dim) : -1;
129 /* Return true if the two local spaces are identical, with identical
130 * expressions for the integer divisions.
132 int isl_local_space_is_equal(__isl_keep isl_local_space *ls1,
133 __isl_keep isl_local_space *ls2)
135 int equal;
137 if (!ls1 || !ls2)
138 return -1;
140 equal = isl_space_is_equal(ls1->dim, ls2->dim);
141 if (equal < 0 || !equal)
142 return equal;
144 if (!isl_local_space_divs_known(ls1))
145 return 0;
146 if (!isl_local_space_divs_known(ls2))
147 return 0;
149 return isl_mat_is_equal(ls1->div, ls2->div);
152 int isl_local_space_dim(__isl_keep isl_local_space *ls,
153 enum isl_dim_type type)
155 if (!ls)
156 return 0;
157 if (type == isl_dim_div)
158 return ls->div->n_row;
159 if (type == isl_dim_all)
160 return isl_space_dim(ls->dim, isl_dim_all) + ls->div->n_row;
161 return isl_space_dim(ls->dim, type);
164 unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
165 enum isl_dim_type type)
167 isl_space *dim;
169 if (!ls)
170 return 0;
172 dim = ls->dim;
173 switch (type) {
174 case isl_dim_cst: return 0;
175 case isl_dim_param: return 1;
176 case isl_dim_in: return 1 + dim->nparam;
177 case isl_dim_out: return 1 + dim->nparam + dim->n_in;
178 case isl_dim_div: return 1 + dim->nparam + dim->n_in + dim->n_out;
179 default: return 0;
183 /* Does the given dimension have a name?
185 int isl_local_space_has_dim_name(__isl_keep isl_local_space *ls,
186 enum isl_dim_type type, unsigned pos)
188 return ls ? isl_space_has_dim_name(ls->dim, type, pos) : -1;
191 const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
192 enum isl_dim_type type, unsigned pos)
194 return ls ? isl_space_get_dim_name(ls->dim, type, pos) : NULL;
197 int isl_local_space_has_dim_id(__isl_keep isl_local_space *ls,
198 enum isl_dim_type type, unsigned pos)
200 return ls ? isl_space_has_dim_id(ls->dim, type, pos) : -1;
203 __isl_give isl_id *isl_local_space_get_dim_id(__isl_keep isl_local_space *ls,
204 enum isl_dim_type type, unsigned pos)
206 return ls ? isl_space_get_dim_id(ls->dim, type, pos) : NULL;
209 __isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls,
210 int pos)
212 isl_aff *aff;
214 if (!ls)
215 return NULL;
217 if (pos < 0 || pos >= ls->div->n_row)
218 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
219 "index out of bounds", return NULL);
221 if (isl_int_is_zero(ls->div->row[pos][0]))
222 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
223 "expression of div unknown", return NULL);
224 if (!isl_local_space_is_set(ls))
225 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
226 "cannot represent divs of map spaces", return NULL);
228 aff = isl_aff_alloc(isl_local_space_copy(ls));
229 if (!aff)
230 return NULL;
231 isl_seq_cpy(aff->v->el, ls->div->row[pos], aff->v->size);
232 return aff;
235 __isl_give isl_space *isl_local_space_get_space(__isl_keep isl_local_space *ls)
237 if (!ls)
238 return NULL;
240 return isl_space_copy(ls->dim);
243 /* Replace the identifier of the tuple of type "type" by "id".
245 __isl_give isl_local_space *isl_local_space_set_tuple_id(
246 __isl_take isl_local_space *ls,
247 enum isl_dim_type type, __isl_take isl_id *id)
249 ls = isl_local_space_cow(ls);
250 if (!ls)
251 goto error;
252 ls->dim = isl_space_set_tuple_id(ls->dim, type, id);
253 if (!ls->dim)
254 return isl_local_space_free(ls);
255 return ls;
256 error:
257 isl_id_free(id);
258 return NULL;
261 __isl_give isl_local_space *isl_local_space_set_dim_name(
262 __isl_take isl_local_space *ls,
263 enum isl_dim_type type, unsigned pos, const char *s)
265 ls = isl_local_space_cow(ls);
266 if (!ls)
267 return NULL;
268 ls->dim = isl_space_set_dim_name(ls->dim, type, pos, s);
269 if (!ls->dim)
270 return isl_local_space_free(ls);
272 return ls;
275 __isl_give isl_local_space *isl_local_space_set_dim_id(
276 __isl_take isl_local_space *ls,
277 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
279 ls = isl_local_space_cow(ls);
280 if (!ls)
281 goto error;
282 ls->dim = isl_space_set_dim_id(ls->dim, type, pos, id);
283 if (!ls->dim)
284 return isl_local_space_free(ls);
286 return ls;
287 error:
288 isl_id_free(id);
289 return NULL;
292 __isl_give isl_local_space *isl_local_space_reset_space(
293 __isl_take isl_local_space *ls, __isl_take isl_space *dim)
295 ls = isl_local_space_cow(ls);
296 if (!ls || !dim)
297 goto error;
299 isl_space_free(ls->dim);
300 ls->dim = dim;
302 return ls;
303 error:
304 isl_local_space_free(ls);
305 isl_space_free(dim);
306 return NULL;
309 /* Reorder the columns of the given div definitions according to the
310 * given reordering.
311 * The order of the divs themselves is assumed not to change.
313 static __isl_give isl_mat *reorder_divs(__isl_take isl_mat *div,
314 __isl_take isl_reordering *r)
316 int i, j;
317 isl_mat *mat;
318 int extra;
320 if (!div || !r)
321 goto error;
323 extra = isl_space_dim(r->dim, isl_dim_all) + div->n_row - r->len;
324 mat = isl_mat_alloc(div->ctx, div->n_row, div->n_col + extra);
325 if (!mat)
326 goto error;
328 for (i = 0; i < div->n_row; ++i) {
329 isl_seq_cpy(mat->row[i], div->row[i], 2);
330 isl_seq_clr(mat->row[i] + 2, mat->n_col - 2);
331 for (j = 0; j < r->len; ++j)
332 isl_int_set(mat->row[i][2 + r->pos[j]],
333 div->row[i][2 + j]);
336 isl_reordering_free(r);
337 isl_mat_free(div);
338 return mat;
339 error:
340 isl_reordering_free(r);
341 isl_mat_free(div);
342 return NULL;
345 /* Reorder the dimensions of "ls" according to the given reordering.
346 * The reordering r is assumed to have been extended with the local
347 * variables, leaving them in the same order.
349 __isl_give isl_local_space *isl_local_space_realign(
350 __isl_take isl_local_space *ls, __isl_take isl_reordering *r)
352 ls = isl_local_space_cow(ls);
353 if (!ls || !r)
354 goto error;
356 ls->div = reorder_divs(ls->div, isl_reordering_copy(r));
357 if (!ls->div)
358 goto error;
360 ls = isl_local_space_reset_space(ls, isl_space_copy(r->dim));
362 isl_reordering_free(r);
363 return ls;
364 error:
365 isl_local_space_free(ls);
366 isl_reordering_free(r);
367 return NULL;
370 __isl_give isl_local_space *isl_local_space_add_div(
371 __isl_take isl_local_space *ls, __isl_take isl_vec *div)
373 ls = isl_local_space_cow(ls);
374 if (!ls || !div)
375 goto error;
377 if (ls->div->n_col != div->size)
378 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
379 "incompatible dimensions", goto error);
381 ls->div = isl_mat_add_zero_cols(ls->div, 1);
382 ls->div = isl_mat_add_rows(ls->div, 1);
383 if (!ls->div)
384 goto error;
386 isl_seq_cpy(ls->div->row[ls->div->n_row - 1], div->el, div->size);
387 isl_int_set_si(ls->div->row[ls->div->n_row - 1][div->size], 0);
389 isl_vec_free(div);
390 return ls;
391 error:
392 isl_local_space_free(ls);
393 isl_vec_free(div);
394 return NULL;
397 __isl_give isl_local_space *isl_local_space_replace_divs(
398 __isl_take isl_local_space *ls, __isl_take isl_mat *div)
400 ls = isl_local_space_cow(ls);
402 if (!ls || !div)
403 goto error;
405 isl_mat_free(ls->div);
406 ls->div = div;
407 return ls;
408 error:
409 isl_mat_free(div);
410 isl_local_space_free(ls);
411 return NULL;
414 /* Copy row "s" of "src" to row "d" of "dst", applying the expansion
415 * defined by "exp".
417 static void expand_row(__isl_keep isl_mat *dst, int d,
418 __isl_keep isl_mat *src, int s, int *exp)
420 int i;
421 unsigned c = src->n_col - src->n_row;
423 isl_seq_cpy(dst->row[d], src->row[s], c);
424 isl_seq_clr(dst->row[d] + c, dst->n_col - c);
426 for (i = 0; i < s; ++i)
427 isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
430 /* Compare (known) divs.
431 * Return non-zero if at least one of the two divs is unknown.
432 * In particular, if both divs are unknown, we respect their
433 * current order. Otherwise, we sort the known div after the unknown
434 * div only if the known div depends on the unknown div.
436 static int cmp_row(isl_int *row_i, isl_int *row_j, int i, int j,
437 unsigned n_row, unsigned n_col)
439 int li, lj;
440 int unknown_i, unknown_j;
442 unknown_i = isl_int_is_zero(row_i[0]);
443 unknown_j = isl_int_is_zero(row_j[0]);
445 if (unknown_i && unknown_j)
446 return i - j;
448 if (unknown_i)
449 li = n_col - n_row + i;
450 else
451 li = isl_seq_last_non_zero(row_i, n_col);
452 if (unknown_j)
453 lj = n_col - n_row + j;
454 else
455 lj = isl_seq_last_non_zero(row_j, n_col);
457 if (li != lj)
458 return li - lj;
460 return isl_seq_cmp(row_i, row_j, n_col);
463 /* Call cmp_row for divs in a matrix.
465 int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j)
467 return cmp_row(div->row[i], div->row[j], i, j, div->n_row, div->n_col);
470 /* Call cmp_row for divs in a basic map.
472 static int bmap_cmp_row(__isl_keep isl_basic_map *bmap, int i, int j,
473 unsigned total)
475 return cmp_row(bmap->div[i], bmap->div[j], i, j, bmap->n_div, total);
478 /* Sort the divs in "bmap".
480 * We first make sure divs are placed after divs on which they depend.
481 * Then we perform a simple insertion sort based on the same ordering
482 * that is used in isl_merge_divs.
484 __isl_give isl_basic_map *isl_basic_map_sort_divs(
485 __isl_take isl_basic_map *bmap)
487 int i, j;
488 unsigned total;
490 bmap = isl_basic_map_order_divs(bmap);
491 if (!bmap)
492 return NULL;
493 if (bmap->n_div <= 1)
494 return bmap;
496 total = 2 + isl_basic_map_total_dim(bmap);
497 for (i = 1; i < bmap->n_div; ++i) {
498 for (j = i - 1; j >= 0; --j) {
499 if (bmap_cmp_row(bmap, j, j + 1, total) <= 0)
500 break;
501 isl_basic_map_swap_div(bmap, j, j + 1);
505 return bmap;
508 /* Sort the divs in the basic maps of "map".
510 __isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map)
512 return isl_map_inline_foreach_basic_map(map, &isl_basic_map_sort_divs);
515 /* Combine the two lists of divs into a single list.
516 * For each row i in div1, exp1[i] is set to the position of the corresponding
517 * row in the result. Similarly for div2 and exp2.
518 * This function guarantees
519 * exp1[i] >= i
520 * exp1[i+1] > exp1[i]
521 * For optimal merging, the two input list should have been sorted.
523 __isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
524 __isl_keep isl_mat *div2, int *exp1, int *exp2)
526 int i, j, k;
527 isl_mat *div = NULL;
528 unsigned d;
530 if (!div1 || !div2)
531 return NULL;
533 d = div1->n_col - div1->n_row;
534 div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
535 d + div1->n_row + div2->n_row);
536 if (!div)
537 return NULL;
539 for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
540 int cmp;
542 expand_row(div, k, div1, i, exp1);
543 expand_row(div, k + 1, div2, j, exp2);
545 cmp = isl_mat_cmp_div(div, k, k + 1);
546 if (cmp == 0) {
547 exp1[i++] = k;
548 exp2[j++] = k;
549 } else if (cmp < 0) {
550 exp1[i++] = k;
551 } else {
552 exp2[j++] = k;
553 isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
556 for (; i < div1->n_row; ++i, ++k) {
557 expand_row(div, k, div1, i, exp1);
558 exp1[i] = k;
560 for (; j < div2->n_row; ++j, ++k) {
561 expand_row(div, k, div2, j, exp2);
562 exp2[j] = k;
565 div->n_row = k;
566 div->n_col = d + k;
568 return div;
571 /* Swap divs "a" and "b" in "ls".
573 __isl_give isl_local_space *isl_local_space_swap_div(
574 __isl_take isl_local_space *ls, int a, int b)
576 int offset;
578 ls = isl_local_space_cow(ls);
579 if (!ls)
580 return NULL;
581 if (a < 0 || a >= ls->div->n_row || b < 0 || b >= ls->div->n_row)
582 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
583 "index out of bounds", return isl_local_space_free(ls));
584 offset = ls->div->n_col - ls->div->n_row;
585 ls->div = isl_mat_swap_cols(ls->div, offset + a, offset + b);
586 ls->div = isl_mat_swap_rows(ls->div, a, b);
587 if (!ls->div)
588 return isl_local_space_free(ls);
589 return ls;
592 /* Construct a local space that contains all the divs in either
593 * "ls1" or "ls2".
595 __isl_give isl_local_space *isl_local_space_intersect(
596 __isl_take isl_local_space *ls1, __isl_take isl_local_space *ls2)
598 isl_ctx *ctx;
599 int *exp1 = NULL;
600 int *exp2 = NULL;
601 isl_mat *div;
603 if (!ls1 || !ls2)
604 goto error;
606 ctx = isl_local_space_get_ctx(ls1);
607 if (!isl_space_is_equal(ls1->dim, ls2->dim))
608 isl_die(ctx, isl_error_invalid,
609 "spaces should be identical", goto error);
611 if (ls2->div->n_row == 0) {
612 isl_local_space_free(ls2);
613 return ls1;
616 if (ls1->div->n_row == 0) {
617 isl_local_space_free(ls1);
618 return ls2;
621 exp1 = isl_alloc_array(ctx, int, ls1->div->n_row);
622 exp2 = isl_alloc_array(ctx, int, ls2->div->n_row);
623 if (!exp1 || !exp2)
624 goto error;
626 div = isl_merge_divs(ls1->div, ls2->div, exp1, exp2);
627 if (!div)
628 goto error;
630 free(exp1);
631 free(exp2);
632 isl_local_space_free(ls2);
633 isl_mat_free(ls1->div);
634 ls1->div = div;
636 return ls1;
637 error:
638 free(exp1);
639 free(exp2);
640 isl_local_space_free(ls1);
641 isl_local_space_free(ls2);
642 return NULL;
645 int isl_local_space_divs_known(__isl_keep isl_local_space *ls)
647 int i;
649 if (!ls)
650 return -1;
652 for (i = 0; i < ls->div->n_row; ++i)
653 if (isl_int_is_zero(ls->div->row[i][0]))
654 return 0;
656 return 1;
659 __isl_give isl_local_space *isl_local_space_domain(
660 __isl_take isl_local_space *ls)
662 ls = isl_local_space_drop_dims(ls, isl_dim_out,
663 0, isl_local_space_dim(ls, isl_dim_out));
664 ls = isl_local_space_cow(ls);
665 if (!ls)
666 return NULL;
667 ls->dim = isl_space_domain(ls->dim);
668 if (!ls->dim)
669 return isl_local_space_free(ls);
670 return ls;
673 __isl_give isl_local_space *isl_local_space_range(
674 __isl_take isl_local_space *ls)
676 ls = isl_local_space_drop_dims(ls, isl_dim_in,
677 0, isl_local_space_dim(ls, isl_dim_in));
678 ls = isl_local_space_cow(ls);
679 if (!ls)
680 return NULL;
682 ls->dim = isl_space_range(ls->dim);
683 if (!ls->dim)
684 return isl_local_space_free(ls);
685 return ls;
688 /* Construct a local space for a map that has the given local
689 * space as domain and that has a zero-dimensional range.
691 __isl_give isl_local_space *isl_local_space_from_domain(
692 __isl_take isl_local_space *ls)
694 ls = isl_local_space_cow(ls);
695 if (!ls)
696 return NULL;
697 ls->dim = isl_space_from_domain(ls->dim);
698 if (!ls->dim)
699 return isl_local_space_free(ls);
700 return ls;
703 __isl_give isl_local_space *isl_local_space_add_dims(
704 __isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n)
706 int pos;
708 if (!ls)
709 return NULL;
710 pos = isl_local_space_dim(ls, type);
711 return isl_local_space_insert_dims(ls, type, pos, n);
714 /* Remove common factor of non-constant terms and denominator.
716 static void normalize_div(__isl_keep isl_local_space *ls, int div)
718 isl_ctx *ctx = ls->div->ctx;
719 unsigned total = ls->div->n_col - 2;
721 isl_seq_gcd(ls->div->row[div] + 2, total, &ctx->normalize_gcd);
722 isl_int_gcd(ctx->normalize_gcd,
723 ctx->normalize_gcd, ls->div->row[div][0]);
724 if (isl_int_is_one(ctx->normalize_gcd))
725 return;
727 isl_seq_scale_down(ls->div->row[div] + 2, ls->div->row[div] + 2,
728 ctx->normalize_gcd, total);
729 isl_int_divexact(ls->div->row[div][0], ls->div->row[div][0],
730 ctx->normalize_gcd);
731 isl_int_fdiv_q(ls->div->row[div][1], ls->div->row[div][1],
732 ctx->normalize_gcd);
735 /* Exploit the equalities in "eq" to simplify the expressions of
736 * the integer divisions in "ls".
737 * The integer divisions in "ls" are assumed to appear as regular
738 * dimensions in "eq".
740 __isl_give isl_local_space *isl_local_space_substitute_equalities(
741 __isl_take isl_local_space *ls, __isl_take isl_basic_set *eq)
743 int i, j, k;
744 unsigned total;
745 unsigned n_div;
747 if (!ls || !eq)
748 goto error;
750 total = isl_space_dim(eq->dim, isl_dim_all);
751 if (isl_local_space_dim(ls, isl_dim_all) != total)
752 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
753 "spaces don't match", goto error);
754 total++;
755 n_div = eq->n_div;
756 for (i = 0; i < eq->n_eq; ++i) {
757 j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
758 if (j < 0 || j == 0 || j >= total)
759 continue;
761 for (k = 0; k < ls->div->n_row; ++k) {
762 if (isl_int_is_zero(ls->div->row[k][1 + j]))
763 continue;
764 ls = isl_local_space_cow(ls);
765 if (!ls)
766 goto error;
767 ls->div = isl_mat_cow(ls->div);
768 if (!ls->div)
769 goto error;
770 isl_seq_elim(ls->div->row[k] + 1, eq->eq[i], j, total,
771 &ls->div->row[k][0]);
772 normalize_div(ls, k);
776 isl_basic_set_free(eq);
777 return ls;
778 error:
779 isl_basic_set_free(eq);
780 isl_local_space_free(ls);
781 return NULL;
784 /* Plug in the affine expressions "subs" of length "subs_len" (including
785 * the denominator and the constant term) into the variable at position "pos"
786 * of the "n" div expressions starting at "first".
788 * Let i be the dimension to replace and let "subs" be of the form
790 * f/d
792 * Any integer division starting at "first" with a non-zero coefficient for i,
794 * floor((a i + g)/m)
796 * is replaced by
798 * floor((a f + d g)/(m d))
800 __isl_give isl_local_space *isl_local_space_substitute_seq(
801 __isl_take isl_local_space *ls,
802 enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len,
803 int first, int n)
805 int i;
806 isl_int v;
808 if (n == 0)
809 return ls;
810 ls = isl_local_space_cow(ls);
811 if (!ls)
812 return NULL;
813 ls->div = isl_mat_cow(ls->div);
814 if (!ls->div)
815 return isl_local_space_free(ls);
817 if (first + n > ls->div->n_row)
818 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
819 "index out of bounds", return isl_local_space_free(ls));
821 pos += isl_local_space_offset(ls, type);
823 isl_int_init(v);
824 for (i = first; i < ls->div->n_row; ++i) {
825 if (isl_int_is_zero(ls->div->row[i][1 + pos]))
826 continue;
827 isl_seq_substitute(ls->div->row[i], pos, subs,
828 ls->div->n_col, subs_len, v);
829 normalize_div(ls, i);
831 isl_int_clear(v);
833 return ls;
836 /* Plug in "subs" for dimension "type", "pos" in the integer divisions
837 * of "ls".
839 * Let i be the dimension to replace and let "subs" be of the form
841 * f/d
843 * Any integer division with a non-zero coefficient for i,
845 * floor((a i + g)/m)
847 * is replaced by
849 * floor((a f + d g)/(m d))
851 __isl_give isl_local_space *isl_local_space_substitute(
852 __isl_take isl_local_space *ls,
853 enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
855 ls = isl_local_space_cow(ls);
856 if (!ls || !subs)
857 return isl_local_space_free(ls);
859 if (!isl_space_is_equal(ls->dim, subs->ls->dim))
860 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
861 "spaces don't match", return isl_local_space_free(ls));
862 if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
863 isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
864 "cannot handle divs yet",
865 return isl_local_space_free(ls));
867 return isl_local_space_substitute_seq(ls, type, pos, subs->v->el,
868 subs->v->size, 0, ls->div->n_row);
871 int isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
872 enum isl_dim_type type)
874 if (!ls)
875 return -1;
876 return isl_space_is_named_or_nested(ls->dim, type);
879 __isl_give isl_local_space *isl_local_space_drop_dims(
880 __isl_take isl_local_space *ls,
881 enum isl_dim_type type, unsigned first, unsigned n)
883 isl_ctx *ctx;
885 if (!ls)
886 return NULL;
887 if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
888 return ls;
890 ctx = isl_local_space_get_ctx(ls);
891 if (first + n > isl_local_space_dim(ls, type))
892 isl_die(ctx, isl_error_invalid, "range out of bounds",
893 return isl_local_space_free(ls));
895 ls = isl_local_space_cow(ls);
896 if (!ls)
897 return NULL;
899 if (type == isl_dim_div) {
900 ls->div = isl_mat_drop_rows(ls->div, first, n);
901 } else {
902 ls->dim = isl_space_drop_dims(ls->dim, type, first, n);
903 if (!ls->dim)
904 return isl_local_space_free(ls);
907 first += 1 + isl_local_space_offset(ls, type);
908 ls->div = isl_mat_drop_cols(ls->div, first, n);
909 if (!ls->div)
910 return isl_local_space_free(ls);
912 return ls;
915 __isl_give isl_local_space *isl_local_space_insert_dims(
916 __isl_take isl_local_space *ls,
917 enum isl_dim_type type, unsigned first, unsigned n)
919 isl_ctx *ctx;
921 if (!ls)
922 return NULL;
923 if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
924 return ls;
926 ctx = isl_local_space_get_ctx(ls);
927 if (first > isl_local_space_dim(ls, type))
928 isl_die(ctx, isl_error_invalid, "position out of bounds",
929 return isl_local_space_free(ls));
931 ls = isl_local_space_cow(ls);
932 if (!ls)
933 return NULL;
935 if (type == isl_dim_div) {
936 ls->div = isl_mat_insert_zero_rows(ls->div, first, n);
937 } else {
938 ls->dim = isl_space_insert_dims(ls->dim, type, first, n);
939 if (!ls->dim)
940 return isl_local_space_free(ls);
943 first += 1 + isl_local_space_offset(ls, type);
944 ls->div = isl_mat_insert_zero_cols(ls->div, first, n);
945 if (!ls->div)
946 return isl_local_space_free(ls);
948 return ls;
951 /* Check if the constraints pointed to by "constraint" is a div
952 * constraint corresponding to div "div" in "ls".
954 * That is, if div = floor(f/m), then check if the constraint is
956 * f - m d >= 0
957 * or
958 * -(f-(m-1)) + m d >= 0
960 int isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls,
961 isl_int *constraint, unsigned div)
963 unsigned pos;
965 if (!ls)
966 return -1;
968 if (isl_int_is_zero(ls->div->row[div][0]))
969 return 0;
971 pos = isl_local_space_offset(ls, isl_dim_div) + div;
973 if (isl_int_eq(constraint[pos], ls->div->row[div][0])) {
974 int neg;
975 isl_int_sub(ls->div->row[div][1],
976 ls->div->row[div][1], ls->div->row[div][0]);
977 isl_int_add_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
978 neg = isl_seq_is_neg(constraint, ls->div->row[div]+1, pos);
979 isl_int_sub_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
980 isl_int_add(ls->div->row[div][1],
981 ls->div->row[div][1], ls->div->row[div][0]);
982 if (!neg)
983 return 0;
984 if (isl_seq_first_non_zero(constraint+pos+1,
985 ls->div->n_row-div-1) != -1)
986 return 0;
987 } else if (isl_int_abs_eq(constraint[pos], ls->div->row[div][0])) {
988 if (!isl_seq_eq(constraint, ls->div->row[div]+1, pos))
989 return 0;
990 if (isl_seq_first_non_zero(constraint+pos+1,
991 ls->div->n_row-div-1) != -1)
992 return 0;
993 } else
994 return 0;
996 return 1;
1000 * Set active[i] to 1 if the dimension at position i is involved
1001 * in the linear expression l.
1003 int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l)
1005 int i, j;
1006 isl_ctx *ctx;
1007 int *active = NULL;
1008 unsigned total;
1009 unsigned offset;
1011 ctx = isl_local_space_get_ctx(ls);
1012 total = isl_local_space_dim(ls, isl_dim_all);
1013 active = isl_calloc_array(ctx, int, total);
1014 if (total && !active)
1015 return NULL;
1017 for (i = 0; i < total; ++i)
1018 active[i] = !isl_int_is_zero(l[i]);
1020 offset = isl_local_space_offset(ls, isl_dim_div) - 1;
1021 for (i = ls->div->n_row - 1; i >= 0; --i) {
1022 if (!active[offset + i])
1023 continue;
1024 for (j = 0; j < total; ++j)
1025 active[j] |= !isl_int_is_zero(ls->div->row[i][2 + j]);
1028 return active;
1031 /* Given a local space "ls" of a set, create a local space
1032 * for the lift of the set. In particular, the result
1033 * is of the form [dim -> local[..]], with ls->div->n_row variables in the
1034 * range of the wrapped map.
1036 __isl_give isl_local_space *isl_local_space_lift(
1037 __isl_take isl_local_space *ls)
1039 ls = isl_local_space_cow(ls);
1040 if (!ls)
1041 return NULL;
1043 ls->dim = isl_space_lift(ls->dim, ls->div->n_row);
1044 ls->div = isl_mat_drop_rows(ls->div, 0, ls->div->n_row);
1045 if (!ls->dim || !ls->div)
1046 return isl_local_space_free(ls);
1048 return ls;
1051 /* Construct a basic map that maps a set living in local space "ls"
1052 * to the corresponding lifted local space.
1054 __isl_give isl_basic_map *isl_local_space_lifting(
1055 __isl_take isl_local_space *ls)
1057 isl_basic_map *lifting;
1058 isl_basic_set *bset;
1060 if (!ls)
1061 return NULL;
1062 if (!isl_local_space_is_set(ls))
1063 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1064 "lifting only defined on set spaces", goto error);
1066 bset = isl_basic_set_from_local_space(ls);
1067 lifting = isl_basic_set_unwrap(isl_basic_set_lift(bset));
1068 lifting = isl_basic_map_domain_map(lifting);
1069 lifting = isl_basic_map_reverse(lifting);
1071 return lifting;
1072 error:
1073 isl_local_space_free(ls);
1074 return NULL;
1077 /* Compute the preimage of "ls" under the function represented by "ma".
1078 * In other words, plug in "ma" in "ls". The result is a local space
1079 * that is part of the domain space of "ma".
1081 * If the divs in "ls" are represented as
1083 * floor((a_i(p) + b_i x + c_i(divs))/n_i)
1085 * and ma is represented by
1087 * x = D(p) + F(y) + G(divs')
1089 * then the resulting divs are
1091 * floor((a_i(p) + b_i D(p) + b_i F(y) + B_i G(divs') + c_i(divs))/n_i)
1093 * We first copy over the divs from "ma" and then
1094 * we add the modified divs from "ls".
1096 __isl_give isl_local_space *isl_local_space_preimage_multi_aff(
1097 __isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma)
1099 int i;
1100 isl_space *space;
1101 isl_local_space *res = NULL;
1102 int n_div_ls, n_div_ma;
1103 isl_int f, c1, c2, g;
1105 ma = isl_multi_aff_align_divs(ma);
1106 if (!ls || !ma)
1107 goto error;
1108 if (!isl_space_is_range_internal(ls->dim, ma->space))
1109 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1110 "spaces don't match", goto error);
1112 n_div_ls = isl_local_space_dim(ls, isl_dim_div);
1113 n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0;
1115 space = isl_space_domain(isl_multi_aff_get_space(ma));
1116 res = isl_local_space_alloc(space, n_div_ma + n_div_ls);
1117 if (!res)
1118 goto error;
1120 if (n_div_ma) {
1121 isl_mat_free(res->div);
1122 res->div = isl_mat_copy(ma->p[0]->ls->div);
1123 res->div = isl_mat_add_zero_cols(res->div, n_div_ls);
1124 res->div = isl_mat_add_rows(res->div, n_div_ls);
1125 if (!res->div)
1126 goto error;
1129 isl_int_init(f);
1130 isl_int_init(c1);
1131 isl_int_init(c2);
1132 isl_int_init(g);
1134 for (i = 0; i < ls->div->n_row; ++i) {
1135 if (isl_int_is_zero(ls->div->row[i][0])) {
1136 isl_int_set_si(res->div->row[n_div_ma + i][0], 0);
1137 continue;
1139 isl_seq_preimage(res->div->row[n_div_ma + i], ls->div->row[i],
1140 ma, 0, 0, n_div_ma, n_div_ls, f, c1, c2, g, 1);
1141 normalize_div(res, n_div_ma + i);
1144 isl_int_clear(f);
1145 isl_int_clear(c1);
1146 isl_int_clear(c2);
1147 isl_int_clear(g);
1149 isl_local_space_free(ls);
1150 isl_multi_aff_free(ma);
1151 return res;
1152 error:
1153 isl_local_space_free(ls);
1154 isl_multi_aff_free(ma);
1155 isl_local_space_free(res);
1156 return NULL;
1159 /* Move the "n" dimensions of "src_type" starting at "src_pos" of "ls"
1160 * to dimensions of "dst_type" at "dst_pos".
1162 * Moving to/from local dimensions is not allowed.
1163 * We currently assume that the dimension type changes.
1165 __isl_give isl_local_space *isl_local_space_move_dims(
1166 __isl_take isl_local_space *ls,
1167 enum isl_dim_type dst_type, unsigned dst_pos,
1168 enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1170 unsigned g_dst_pos;
1171 unsigned g_src_pos;
1173 if (!ls)
1174 return NULL;
1175 if (n == 0 &&
1176 !isl_local_space_is_named_or_nested(ls, src_type) &&
1177 !isl_local_space_is_named_or_nested(ls, dst_type))
1178 return ls;
1180 if (src_pos + n > isl_local_space_dim(ls, src_type))
1181 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1182 "range out of bounds", return isl_local_space_free(ls));
1183 if (dst_pos > isl_local_space_dim(ls, dst_type))
1184 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1185 "position out of bounds",
1186 return isl_local_space_free(ls));
1187 if (src_type == isl_dim_div)
1188 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1189 "cannot move divs", return isl_local_space_free(ls));
1190 if (dst_type == isl_dim_div)
1191 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1192 "cannot move to divs", return isl_local_space_free(ls));
1193 if (dst_type == src_type && dst_pos == src_pos)
1194 return ls;
1195 if (dst_type == src_type)
1196 isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
1197 "moving dims within the same type not supported",
1198 return isl_local_space_free(ls));
1200 ls = isl_local_space_cow(ls);
1201 if (!ls)
1202 return NULL;
1204 g_src_pos = 1 + isl_local_space_offset(ls, src_type) + src_pos;
1205 g_dst_pos = 1 + isl_local_space_offset(ls, dst_type) + dst_pos;
1206 if (dst_type > src_type)
1207 g_dst_pos -= n;
1208 ls->div = isl_mat_move_cols(ls->div, g_dst_pos, g_src_pos, n);
1209 if (!ls->div)
1210 return isl_local_space_free(ls);
1211 ls->dim = isl_space_move_dims(ls->dim, dst_type, dst_pos,
1212 src_type, src_pos, n);
1213 if (!ls->dim)
1214 return isl_local_space_free(ls);
1216 return ls;
1219 /* Remove any internal structure of the domain of "ls".
1220 * If there is any such internal structure in the input,
1221 * then the name of the corresponding space is also removed.
1223 __isl_give isl_local_space *isl_local_space_flatten_domain(
1224 __isl_take isl_local_space *ls)
1226 if (!ls)
1227 return NULL;
1229 if (!ls->dim->nested[0])
1230 return ls;
1232 ls = isl_local_space_cow(ls);
1233 if (!ls)
1234 return NULL;
1236 ls->dim = isl_space_flatten_domain(ls->dim);
1237 if (!ls->dim)
1238 return isl_local_space_free(ls);
1240 return ls;
1243 /* Remove any internal structure of the range of "ls".
1244 * If there is any such internal structure in the input,
1245 * then the name of the corresponding space is also removed.
1247 __isl_give isl_local_space *isl_local_space_flatten_range(
1248 __isl_take isl_local_space *ls)
1250 if (!ls)
1251 return NULL;
1253 if (!ls->dim->nested[1])
1254 return ls;
1256 ls = isl_local_space_cow(ls);
1257 if (!ls)
1258 return NULL;
1260 ls->dim = isl_space_flatten_range(ls->dim);
1261 if (!ls->dim)
1262 return isl_local_space_free(ls);
1264 return ls;