add isl_aff_gist
[isl.git] / isl_aff.c
blobe258941c6a529a89a1275a03041a55dbe0c42dd1
1 /*
2 * Copyright 2011 INRIA Saclay
4 * Use of this software is governed by the GNU LGPLv2.1 license
6 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
7 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
8 * 91893 Orsay, France
9 */
11 #include <isl_map_private.h>
12 #include <isl_aff_private.h>
13 #include <isl_local_space_private.h>
14 #include <isl_mat_private.h>
15 #include <isl/seq.h>
17 __isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls,
18 __isl_take isl_vec *v)
20 isl_aff *aff;
22 if (!ls || !v)
23 goto error;
25 aff = isl_calloc_type(v->ctx, struct isl_aff);
26 if (!aff)
27 goto error;
29 aff->ref = 1;
30 aff->ls = ls;
31 aff->v = v;
33 return aff;
34 error:
35 isl_local_space_free(ls);
36 isl_vec_free(v);
37 return NULL;
40 __isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls)
42 isl_ctx *ctx;
43 isl_vec *v;
44 unsigned total;
46 if (!ls)
47 return NULL;
49 ctx = isl_local_space_get_ctx(ls);
50 if (!isl_local_space_divs_known(ls))
51 isl_die(ctx, isl_error_invalid, "local space has unknown divs",
52 goto error);
54 total = isl_local_space_dim(ls, isl_dim_all);
55 v = isl_vec_alloc(ctx, 1 + 1 + total);
56 return isl_aff_alloc_vec(ls, v);
57 error:
58 isl_local_space_free(ls);
59 return NULL;
62 __isl_give isl_aff *isl_aff_zero(__isl_take isl_local_space *ls)
64 isl_aff *aff;
66 aff = isl_aff_alloc(ls);
67 if (!aff)
68 return NULL;
70 isl_int_set_si(aff->v->el[0], 1);
71 isl_seq_clr(aff->v->el + 1, aff->v->size - 1);
73 return aff;
76 __isl_give isl_aff *isl_aff_copy(__isl_keep isl_aff *aff)
78 if (!aff)
79 return NULL;
81 aff->ref++;
82 return aff;
85 __isl_give isl_aff *isl_aff_dup(__isl_keep isl_aff *aff)
87 if (!aff)
88 return NULL;
90 return isl_aff_alloc_vec(isl_local_space_copy(aff->ls),
91 isl_vec_copy(aff->v));
94 __isl_give isl_aff *isl_aff_cow(__isl_take isl_aff *aff)
96 if (!aff)
97 return NULL;
99 if (aff->ref == 1)
100 return aff;
101 aff->ref--;
102 return isl_aff_dup(aff);
105 void *isl_aff_free(__isl_take isl_aff *aff)
107 if (!aff)
108 return NULL;
110 if (--aff->ref > 0)
111 return NULL;
113 isl_local_space_free(aff->ls);
114 isl_vec_free(aff->v);
116 free(aff);
118 return NULL;
121 isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff)
123 return aff ? isl_local_space_get_ctx(aff->ls) : NULL;
126 int isl_aff_dim(__isl_keep isl_aff *aff, enum isl_dim_type type)
128 return aff ? isl_local_space_dim(aff->ls, type) : 0;
131 __isl_give isl_dim *isl_aff_get_dim(__isl_keep isl_aff *aff)
133 return aff ? isl_local_space_get_dim(aff->ls) : NULL;
136 __isl_give isl_local_space *isl_aff_get_local_space(__isl_keep isl_aff *aff)
138 return aff ? isl_local_space_copy(aff->ls) : NULL;
141 const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff,
142 enum isl_dim_type type, unsigned pos)
144 return aff ? isl_local_space_get_dim_name(aff->ls, type, pos) : 0;
147 int isl_aff_plain_is_zero(__isl_keep isl_aff *aff)
149 if (!aff)
150 return -1;
152 return isl_seq_first_non_zero(aff->v->el + 1, aff->v->size - 1) < 0;
155 int isl_aff_plain_is_equal(__isl_keep isl_aff *aff1, __isl_keep isl_aff *aff2)
157 int equal;
159 if (!aff1 || !aff2)
160 return -1;
162 equal = isl_local_space_is_equal(aff1->ls, aff2->ls);
163 if (equal < 0 || !equal)
164 return equal;
166 return isl_vec_is_equal(aff1->v, aff2->v);
169 int isl_aff_get_denominator(__isl_keep isl_aff *aff, isl_int *v)
171 if (!aff)
172 return -1;
173 isl_int_set(*v, aff->v->el[0]);
174 return 0;
177 int isl_aff_get_constant(__isl_keep isl_aff *aff, isl_int *v)
179 if (!aff)
180 return -1;
181 isl_int_set(*v, aff->v->el[1]);
182 return 0;
185 int isl_aff_get_coefficient(__isl_keep isl_aff *aff,
186 enum isl_dim_type type, int pos, isl_int *v)
188 if (!aff)
189 return -1;
191 if (pos >= isl_local_space_dim(aff->ls, type))
192 isl_die(aff->v->ctx, isl_error_invalid,
193 "position out of bounds", return -1);
195 pos += isl_local_space_offset(aff->ls, type);
196 isl_int_set(*v, aff->v->el[1 + pos]);
198 return 0;
201 __isl_give isl_aff *isl_aff_set_denominator(__isl_take isl_aff *aff, isl_int v)
203 aff = isl_aff_cow(aff);
204 if (!aff)
205 return NULL;
207 aff->v = isl_vec_cow(aff->v);
208 if (!aff->v)
209 return isl_aff_free(aff);
211 isl_int_set(aff->v->el[0], v);
213 return aff;
216 __isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_int v)
218 aff = isl_aff_cow(aff);
219 if (!aff)
220 return NULL;
222 aff->v = isl_vec_cow(aff->v);
223 if (!aff->v)
224 return isl_aff_free(aff);
226 isl_int_set(aff->v->el[1], v);
228 return aff;
231 __isl_give isl_aff *isl_aff_add_constant(__isl_take isl_aff *aff, isl_int v)
233 if (isl_int_is_zero(v))
234 return aff;
236 aff = isl_aff_cow(aff);
237 if (!aff)
238 return NULL;
240 aff->v = isl_vec_cow(aff->v);
241 if (!aff->v)
242 return isl_aff_free(aff);
244 isl_int_addmul(aff->v->el[1], aff->v->el[0], v);
246 return aff;
249 __isl_give isl_aff *isl_aff_add_constant_si(__isl_take isl_aff *aff, int v)
251 isl_int t;
253 isl_int_init(t);
254 isl_int_set_si(t, v);
255 aff = isl_aff_add_constant(aff, t);
256 isl_int_clear(t);
258 return aff;
261 __isl_give isl_aff *isl_aff_set_constant_si(__isl_take isl_aff *aff, int v)
263 aff = isl_aff_cow(aff);
264 if (!aff)
265 return NULL;
267 aff->v = isl_vec_cow(aff->v);
268 if (!aff->v)
269 return isl_aff_free(aff);
271 isl_int_set_si(aff->v->el[1], v);
273 return aff;
276 __isl_give isl_aff *isl_aff_set_coefficient(__isl_take isl_aff *aff,
277 enum isl_dim_type type, int pos, isl_int v)
279 if (!aff)
280 return NULL;
282 if (pos >= isl_local_space_dim(aff->ls, type))
283 isl_die(aff->v->ctx, isl_error_invalid,
284 "position out of bounds", return isl_aff_free(aff));
286 aff = isl_aff_cow(aff);
287 if (!aff)
288 return NULL;
290 aff->v = isl_vec_cow(aff->v);
291 if (!aff->v)
292 return isl_aff_free(aff);
294 pos += isl_local_space_offset(aff->ls, type);
295 isl_int_set(aff->v->el[1 + pos], v);
297 return aff;
300 __isl_give isl_aff *isl_aff_set_coefficient_si(__isl_take isl_aff *aff,
301 enum isl_dim_type type, int pos, int v)
303 if (!aff)
304 return NULL;
306 if (pos >= isl_local_space_dim(aff->ls, type))
307 isl_die(aff->v->ctx, isl_error_invalid,
308 "position out of bounds", return isl_aff_free(aff));
310 aff = isl_aff_cow(aff);
311 if (!aff)
312 return NULL;
314 aff->v = isl_vec_cow(aff->v);
315 if (!aff->v)
316 return isl_aff_free(aff);
318 pos += isl_local_space_offset(aff->ls, type);
319 isl_int_set_si(aff->v->el[1 + pos], v);
321 return aff;
324 __isl_give isl_aff *isl_aff_add_coefficient(__isl_take isl_aff *aff,
325 enum isl_dim_type type, int pos, isl_int v)
327 if (!aff)
328 return NULL;
330 if (pos >= isl_local_space_dim(aff->ls, type))
331 isl_die(aff->v->ctx, isl_error_invalid,
332 "position out of bounds", return isl_aff_free(aff));
334 aff = isl_aff_cow(aff);
335 if (!aff)
336 return NULL;
338 aff->v = isl_vec_cow(aff->v);
339 if (!aff->v)
340 return isl_aff_free(aff);
342 pos += isl_local_space_offset(aff->ls, type);
343 isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v);
345 return aff;
348 __isl_give isl_aff *isl_aff_add_coefficient_si(__isl_take isl_aff *aff,
349 enum isl_dim_type type, int pos, int v)
351 isl_int t;
353 isl_int_init(t);
354 isl_int_set_si(t, v);
355 aff = isl_aff_add_coefficient(aff, type, pos, t);
356 isl_int_clear(t);
358 return aff;
361 __isl_give isl_div *isl_aff_get_div(__isl_keep isl_aff *aff, int pos)
363 if (!aff)
364 return NULL;
366 return isl_local_space_get_div(aff->ls, pos);
369 __isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff)
371 aff = isl_aff_cow(aff);
372 if (!aff)
373 return NULL;
374 aff->v = isl_vec_cow(aff->v);
375 if (!aff->v)
376 return isl_aff_free(aff);
378 isl_seq_neg(aff->v->el + 1, aff->v->el + 1, aff->v->size - 1);
380 return aff;
383 /* Given f, return floor(f).
384 * If f is an integer expression, then just return f.
385 * Otherwise, create a new div d = [f] and return the expression d.
387 __isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff)
389 int size;
390 isl_ctx *ctx;
392 if (!aff)
393 return NULL;
395 if (isl_int_is_one(aff->v->el[0]))
396 return aff;
398 aff = isl_aff_cow(aff);
399 if (!aff)
400 return NULL;
402 aff->ls = isl_local_space_add_div(aff->ls, isl_vec_copy(aff->v));
403 if (!aff->ls)
404 return isl_aff_free(aff);
406 ctx = isl_aff_get_ctx(aff);
407 size = aff->v->size;
408 isl_vec_free(aff->v);
409 aff->v = isl_vec_alloc(ctx, size + 1);
410 aff->v = isl_vec_clr(aff->v);
411 if (!aff->v)
412 return isl_aff_free(aff);
413 isl_int_set_si(aff->v->el[0], 1);
414 isl_int_set_si(aff->v->el[size], 1);
416 return aff;
419 /* Given f, return ceil(f).
420 * If f is an integer expression, then just return f.
421 * Otherwise, create a new div d = [-f] and return the expression -d.
423 __isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff)
425 if (!aff)
426 return NULL;
428 if (isl_int_is_one(aff->v->el[0]))
429 return aff;
431 aff = isl_aff_neg(aff);
432 aff = isl_aff_floor(aff);
433 aff = isl_aff_neg(aff);
435 return aff;
438 /* Apply the expansion computed by isl_merge_divs.
439 * The expansion itself is given by "exp" while the resulting
440 * list of divs is given by "div".
442 __isl_give isl_aff *isl_aff_expand_divs( __isl_take isl_aff *aff,
443 __isl_take isl_mat *div, int *exp)
445 int i, j;
446 int old_n_div;
447 int new_n_div;
448 int offset;
450 aff = isl_aff_cow(aff);
451 if (!aff || !div)
452 goto error;
454 old_n_div = isl_local_space_dim(aff->ls, isl_dim_div);
455 new_n_div = isl_mat_rows(div);
456 if (new_n_div < old_n_div)
457 isl_die(isl_mat_get_ctx(div), isl_error_invalid,
458 "not an expansion", goto error);
460 aff->v = isl_vec_extend(aff->v, aff->v->size + new_n_div - old_n_div);
461 if (!aff->v)
462 goto error;
464 offset = 1 + isl_local_space_offset(aff->ls, isl_dim_div);
465 j = old_n_div - 1;
466 for (i = new_n_div - 1; i >= 0; --i) {
467 if (j >= 0 && exp[j] == i) {
468 if (i != j)
469 isl_int_swap(aff->v->el[offset + i],
470 aff->v->el[offset + j]);
471 j--;
472 } else
473 isl_int_set_si(aff->v->el[offset + i], 0);
476 aff->ls = isl_local_space_replace_divs(aff->ls, isl_mat_copy(div));
477 if (!aff->ls)
478 goto error;
479 isl_mat_free(div);
480 return aff;
481 error:
482 isl_aff_free(aff);
483 isl_mat_free(div);
484 return NULL;
487 /* Add two affine expressions that live in the same local space.
489 static __isl_give isl_aff *add_expanded(__isl_take isl_aff *aff1,
490 __isl_take isl_aff *aff2)
492 isl_int gcd, f;
494 aff1 = isl_aff_cow(aff1);
495 if (!aff1 || !aff2)
496 goto error;
498 aff1->v = isl_vec_cow(aff1->v);
499 if (!aff1->v)
500 goto error;
502 isl_int_init(gcd);
503 isl_int_init(f);
504 isl_int_gcd(gcd, aff1->v->el[0], aff2->v->el[0]);
505 isl_int_divexact(f, aff2->v->el[0], gcd);
506 isl_seq_scale(aff1->v->el + 1, aff1->v->el + 1, f, aff1->v->size - 1);
507 isl_int_divexact(f, aff1->v->el[0], gcd);
508 isl_seq_addmul(aff1->v->el + 1, f, aff2->v->el + 1, aff1->v->size - 1);
509 isl_int_divexact(f, aff2->v->el[0], gcd);
510 isl_int_mul(aff1->v->el[0], aff1->v->el[0], f);
511 isl_int_clear(f);
512 isl_int_clear(gcd);
514 isl_aff_free(aff2);
515 return aff1;
516 error:
517 isl_aff_free(aff1);
518 isl_aff_free(aff2);
519 return NULL;
522 __isl_give isl_aff *isl_aff_add(__isl_take isl_aff *aff1,
523 __isl_take isl_aff *aff2)
525 isl_ctx *ctx;
526 int *exp1 = NULL;
527 int *exp2 = NULL;
528 isl_mat *div;
530 if (!aff1 || !aff2)
531 goto error;
533 ctx = isl_aff_get_ctx(aff1);
534 if (!isl_dim_equal(aff1->ls->dim, aff2->ls->dim))
535 isl_die(ctx, isl_error_invalid,
536 "spaces don't match", goto error);
538 if (aff1->ls->div->n_row == 0 && aff2->ls->div->n_row == 0)
539 return add_expanded(aff1, aff2);
541 exp1 = isl_alloc_array(ctx, int, aff1->ls->div->n_row);
542 exp2 = isl_alloc_array(ctx, int, aff2->ls->div->n_row);
543 if (!exp1 || !exp2)
544 goto error;
546 div = isl_merge_divs(aff1->ls->div, aff2->ls->div, exp1, exp2);
547 aff1 = isl_aff_expand_divs(aff1, isl_mat_copy(div), exp1);
548 aff2 = isl_aff_expand_divs(aff2, div, exp2);
549 free(exp1);
550 free(exp2);
552 return add_expanded(aff1, aff2);
553 error:
554 free(exp1);
555 free(exp2);
556 isl_aff_free(aff1);
557 isl_aff_free(aff2);
558 return NULL;
561 __isl_give isl_aff *isl_aff_sub(__isl_take isl_aff *aff1,
562 __isl_take isl_aff *aff2)
564 return isl_aff_add(aff1, isl_aff_neg(aff2));
567 __isl_give isl_aff *isl_aff_scale(__isl_take isl_aff *aff, isl_int f)
569 isl_int gcd;
571 if (isl_int_is_one(f))
572 return aff;
574 aff = isl_aff_cow(aff);
575 if (!aff)
576 return NULL;
577 aff->v = isl_vec_cow(aff->v);
578 if (!aff->v)
579 return isl_aff_free(aff);
581 isl_int_init(gcd);
582 isl_int_gcd(gcd, aff->v->el[0], f);
583 isl_int_divexact(aff->v->el[0], aff->v->el[0], gcd);
584 isl_int_divexact(gcd, f, gcd);
585 isl_seq_scale(aff->v->el + 1, aff->v->el + 1, gcd, aff->v->size - 1);
586 isl_int_clear(gcd);
588 return aff;
591 __isl_give isl_aff *isl_aff_scale_down(__isl_take isl_aff *aff, isl_int f)
593 isl_int gcd;
595 if (isl_int_is_one(f))
596 return aff;
598 aff = isl_aff_cow(aff);
599 if (!aff)
600 return NULL;
601 aff->v = isl_vec_cow(aff->v);
602 if (!aff->v)
603 return isl_aff_free(aff);
605 isl_int_init(gcd);
606 isl_seq_gcd(aff->v->el + 1, aff->v->size - 1, &gcd);
607 isl_int_gcd(gcd, gcd, f);
608 isl_seq_scale_down(aff->v->el + 1, aff->v->el + 1, gcd, aff->v->size - 1);
609 isl_int_divexact(gcd, f, gcd);
610 isl_int_mul(aff->v->el[0], aff->v->el[0], gcd);
611 isl_int_clear(gcd);
613 return aff;
616 __isl_give isl_aff *isl_aff_scale_down_ui(__isl_take isl_aff *aff, unsigned f)
618 isl_int v;
620 if (f == 1)
621 return aff;
623 isl_int_init(v);
624 isl_int_set_ui(v, f);
625 aff = isl_aff_scale_down(aff, v);
626 isl_int_clear(v);
628 return aff;
631 __isl_give isl_aff *isl_aff_set_dim_name(__isl_take isl_aff *aff,
632 enum isl_dim_type type, unsigned pos, const char *s)
634 aff = isl_aff_cow(aff);
635 if (!aff)
636 return NULL;
637 aff->ls = isl_local_space_set_dim_name(aff->ls, type, pos, s);
638 if (!aff->ls)
639 return isl_aff_free(aff);
641 return aff;
644 /* Exploit the equalities in "eq" to simplify the affine expression
645 * and the expressions of the integer divisions in the local space.
646 * The integer divisions in this local space are assumed to appear
647 * as regular dimensions in "eq".
649 static __isl_give isl_aff *isl_aff_substitute_equalities(
650 __isl_take isl_aff *aff, __isl_take isl_basic_set *eq)
652 int i, j;
653 unsigned total;
654 unsigned n_div;
656 if (!eq)
657 goto error;
658 if (eq->n_eq == 0) {
659 isl_basic_set_free(eq);
660 return aff;
663 aff = isl_aff_cow(aff);
664 if (!aff)
665 goto error;
667 aff->ls = isl_local_space_substitute_equalities(aff->ls,
668 isl_basic_set_copy(eq));
669 if (!aff->ls)
670 goto error;
672 total = 1 + isl_dim_total(eq->dim);
673 n_div = eq->n_div;
674 for (i = 0; i < eq->n_eq; ++i) {
675 j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
676 if (j < 0 || j == 0 || j >= total)
677 continue;
679 isl_seq_elim(aff->v->el + 1, eq->eq[i], j, total,
680 &aff->v->el[0]);
683 isl_basic_set_free(eq);
684 return aff;
685 error:
686 isl_basic_set_free(eq);
687 isl_aff_free(aff);
688 return NULL;
691 /* Look for equalities among the variables shared by context and aff
692 * and the integer divisions of aff, if any.
693 * The equalities are then used to eliminate coefficients and/or integer
694 * divisions from aff.
696 __isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff,
697 __isl_take isl_set *context)
699 isl_basic_set *hull;
700 int n_div;
702 if (!aff)
703 goto error;
704 n_div = isl_local_space_dim(aff->ls, isl_dim_div);
705 if (n_div > 0) {
706 isl_basic_set *bset;
707 context = isl_set_add_dims(context, isl_dim_set, n_div);
708 bset = isl_basic_set_from_local_space(
709 isl_aff_get_local_space(aff));
710 bset = isl_basic_set_lift(bset);
711 bset = isl_basic_set_flatten(bset);
712 context = isl_set_intersect(context,
713 isl_set_from_basic_set(bset));
716 hull = isl_set_affine_hull(context);
717 return isl_aff_substitute_equalities(aff, hull);
718 error:
719 isl_aff_free(aff);
720 isl_set_free(context);
721 return NULL;