add isl_aff_gist
[platform/upstream/isl.git] / isl_aff.c
1 /*
2  * Copyright 2011      INRIA Saclay
3  *
4  * Use of this software is governed by the GNU LGPLv2.1 license
5  *
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  */
10
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>
16
17 __isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls,
18         __isl_take isl_vec *v)
19 {
20         isl_aff *aff;
21
22         if (!ls || !v)
23                 goto error;
24
25         aff = isl_calloc_type(v->ctx, struct isl_aff);
26         if (!aff)
27                 goto error;
28
29         aff->ref = 1;
30         aff->ls = ls;
31         aff->v = v;
32
33         return aff;
34 error:
35         isl_local_space_free(ls);
36         isl_vec_free(v);
37         return NULL;
38 }
39
40 __isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls)
41 {
42         isl_ctx *ctx;
43         isl_vec *v;
44         unsigned total;
45
46         if (!ls)
47                 return NULL;
48
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);
53
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;
60 }
61
62 __isl_give isl_aff *isl_aff_zero(__isl_take isl_local_space *ls)
63 {
64         isl_aff *aff;
65
66         aff = isl_aff_alloc(ls);
67         if (!aff)
68                 return NULL;
69
70         isl_int_set_si(aff->v->el[0], 1);
71         isl_seq_clr(aff->v->el + 1, aff->v->size - 1);
72
73         return aff;
74 }
75
76 __isl_give isl_aff *isl_aff_copy(__isl_keep isl_aff *aff)
77 {
78         if (!aff)
79                 return NULL;
80
81         aff->ref++;
82         return aff;
83 }
84
85 __isl_give isl_aff *isl_aff_dup(__isl_keep isl_aff *aff)
86 {
87         if (!aff)
88                 return NULL;
89
90         return isl_aff_alloc_vec(isl_local_space_copy(aff->ls),
91                                  isl_vec_copy(aff->v));
92 }
93
94 __isl_give isl_aff *isl_aff_cow(__isl_take isl_aff *aff)
95 {
96         if (!aff)
97                 return NULL;
98
99         if (aff->ref == 1)
100                 return aff;
101         aff->ref--;
102         return isl_aff_dup(aff);
103 }
104
105 void *isl_aff_free(__isl_take isl_aff *aff)
106 {
107         if (!aff)
108                 return NULL;
109
110         if (--aff->ref > 0)
111                 return NULL;
112
113         isl_local_space_free(aff->ls);
114         isl_vec_free(aff->v);
115
116         free(aff);
117
118         return NULL;
119 }
120
121 isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff)
122 {
123         return aff ? isl_local_space_get_ctx(aff->ls) : NULL;
124 }
125
126 int isl_aff_dim(__isl_keep isl_aff *aff, enum isl_dim_type type)
127 {
128         return aff ? isl_local_space_dim(aff->ls, type) : 0;
129 }
130
131 __isl_give isl_dim *isl_aff_get_dim(__isl_keep isl_aff *aff)
132 {
133         return aff ? isl_local_space_get_dim(aff->ls) : NULL;
134 }
135
136 __isl_give isl_local_space *isl_aff_get_local_space(__isl_keep isl_aff *aff)
137 {
138         return aff ? isl_local_space_copy(aff->ls) : NULL;
139 }
140
141 const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff,
142         enum isl_dim_type type, unsigned pos)
143 {
144         return aff ? isl_local_space_get_dim_name(aff->ls, type, pos) : 0;
145 }
146
147 int isl_aff_plain_is_zero(__isl_keep isl_aff *aff)
148 {
149         if (!aff)
150                 return -1;
151
152         return isl_seq_first_non_zero(aff->v->el + 1, aff->v->size - 1) < 0;
153 }
154
155 int isl_aff_plain_is_equal(__isl_keep isl_aff *aff1, __isl_keep isl_aff *aff2)
156 {
157         int equal;
158
159         if (!aff1 || !aff2)
160                 return -1;
161
162         equal = isl_local_space_is_equal(aff1->ls, aff2->ls);
163         if (equal < 0 || !equal)
164                 return equal;
165
166         return isl_vec_is_equal(aff1->v, aff2->v);
167 }
168
169 int isl_aff_get_denominator(__isl_keep isl_aff *aff, isl_int *v)
170 {
171         if (!aff)
172                 return -1;
173         isl_int_set(*v, aff->v->el[0]);
174         return 0;
175 }
176
177 int isl_aff_get_constant(__isl_keep isl_aff *aff, isl_int *v)
178 {
179         if (!aff)
180                 return -1;
181         isl_int_set(*v, aff->v->el[1]);
182         return 0;
183 }
184
185 int isl_aff_get_coefficient(__isl_keep isl_aff *aff,
186         enum isl_dim_type type, int pos, isl_int *v)
187 {
188         if (!aff)
189                 return -1;
190
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);
194
195         pos += isl_local_space_offset(aff->ls, type);
196         isl_int_set(*v, aff->v->el[1 + pos]);
197
198         return 0;
199 }
200
201 __isl_give isl_aff *isl_aff_set_denominator(__isl_take isl_aff *aff, isl_int v)
202 {
203         aff = isl_aff_cow(aff);
204         if (!aff)
205                 return NULL;
206
207         aff->v = isl_vec_cow(aff->v);
208         if (!aff->v)
209                 return isl_aff_free(aff);
210
211         isl_int_set(aff->v->el[0], v);
212
213         return aff;
214 }
215
216 __isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_int v)
217 {
218         aff = isl_aff_cow(aff);
219         if (!aff)
220                 return NULL;
221
222         aff->v = isl_vec_cow(aff->v);
223         if (!aff->v)
224                 return isl_aff_free(aff);
225
226         isl_int_set(aff->v->el[1], v);
227
228         return aff;
229 }
230
231 __isl_give isl_aff *isl_aff_add_constant(__isl_take isl_aff *aff, isl_int v)
232 {
233         if (isl_int_is_zero(v))
234                 return aff;
235
236         aff = isl_aff_cow(aff);
237         if (!aff)
238                 return NULL;
239
240         aff->v = isl_vec_cow(aff->v);
241         if (!aff->v)
242                 return isl_aff_free(aff);
243
244         isl_int_addmul(aff->v->el[1], aff->v->el[0], v);
245
246         return aff;
247 }
248
249 __isl_give isl_aff *isl_aff_add_constant_si(__isl_take isl_aff *aff, int v)
250 {
251         isl_int t;
252
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);
257
258         return aff;
259 }
260
261 __isl_give isl_aff *isl_aff_set_constant_si(__isl_take isl_aff *aff, int v)
262 {
263         aff = isl_aff_cow(aff);
264         if (!aff)
265                 return NULL;
266
267         aff->v = isl_vec_cow(aff->v);
268         if (!aff->v)
269                 return isl_aff_free(aff);
270
271         isl_int_set_si(aff->v->el[1], v);
272
273         return aff;
274 }
275
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)
278 {
279         if (!aff)
280                 return NULL;
281
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));
285
286         aff = isl_aff_cow(aff);
287         if (!aff)
288                 return NULL;
289
290         aff->v = isl_vec_cow(aff->v);
291         if (!aff->v)
292                 return isl_aff_free(aff);
293
294         pos += isl_local_space_offset(aff->ls, type);
295         isl_int_set(aff->v->el[1 + pos], v);
296
297         return aff;
298 }
299
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)
302 {
303         if (!aff)
304                 return NULL;
305
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));
309
310         aff = isl_aff_cow(aff);
311         if (!aff)
312                 return NULL;
313
314         aff->v = isl_vec_cow(aff->v);
315         if (!aff->v)
316                 return isl_aff_free(aff);
317
318         pos += isl_local_space_offset(aff->ls, type);
319         isl_int_set_si(aff->v->el[1 + pos], v);
320
321         return aff;
322 }
323
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)
326 {
327         if (!aff)
328                 return NULL;
329
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));
333
334         aff = isl_aff_cow(aff);
335         if (!aff)
336                 return NULL;
337
338         aff->v = isl_vec_cow(aff->v);
339         if (!aff->v)
340                 return isl_aff_free(aff);
341
342         pos += isl_local_space_offset(aff->ls, type);
343         isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v);
344
345         return aff;
346 }
347
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)
350 {
351         isl_int t;
352
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);
357
358         return aff;
359 }
360
361 __isl_give isl_div *isl_aff_get_div(__isl_keep isl_aff *aff, int pos)
362 {
363         if (!aff)
364                 return NULL;
365
366         return isl_local_space_get_div(aff->ls, pos);
367 }
368
369 __isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff)
370 {
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);
377
378         isl_seq_neg(aff->v->el + 1, aff->v->el + 1, aff->v->size - 1);
379
380         return aff;
381 }
382
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.
386  */
387 __isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff)
388 {
389         int size;
390         isl_ctx *ctx;
391
392         if (!aff)
393                 return NULL;
394
395         if (isl_int_is_one(aff->v->el[0]))
396                 return aff;
397
398         aff = isl_aff_cow(aff);
399         if (!aff)
400                 return NULL;
401
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);
405
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);
415
416         return aff;
417 }
418
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.
422  */
423 __isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff)
424 {
425         if (!aff)
426                 return NULL;
427
428         if (isl_int_is_one(aff->v->el[0]))
429                 return aff;
430
431         aff = isl_aff_neg(aff);
432         aff = isl_aff_floor(aff);
433         aff = isl_aff_neg(aff);
434
435         return aff;
436 }
437
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".
441  */
442 __isl_give isl_aff *isl_aff_expand_divs( __isl_take isl_aff *aff,
443         __isl_take isl_mat *div, int *exp)
444 {
445         int i, j;
446         int old_n_div;
447         int new_n_div;
448         int offset;
449
450         aff = isl_aff_cow(aff);
451         if (!aff || !div)
452                 goto error;
453
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);
459
460         aff->v = isl_vec_extend(aff->v, aff->v->size + new_n_div - old_n_div);
461         if (!aff->v)
462                 goto error;
463
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);
474         }
475
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;
485 }
486
487 /* Add two affine expressions that live in the same local space.
488  */
489 static __isl_give isl_aff *add_expanded(__isl_take isl_aff *aff1,
490         __isl_take isl_aff *aff2)
491 {
492         isl_int gcd, f;
493
494         aff1 = isl_aff_cow(aff1);
495         if (!aff1 || !aff2)
496                 goto error;
497
498         aff1->v = isl_vec_cow(aff1->v);
499         if (!aff1->v)
500                 goto error;
501
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);
513
514         isl_aff_free(aff2);
515         return aff1;
516 error:
517         isl_aff_free(aff1);
518         isl_aff_free(aff2);
519         return NULL;
520 }
521
522 __isl_give isl_aff *isl_aff_add(__isl_take isl_aff *aff1,
523         __isl_take isl_aff *aff2)
524 {
525         isl_ctx *ctx;
526         int *exp1 = NULL;
527         int *exp2 = NULL;
528         isl_mat *div;
529
530         if (!aff1 || !aff2)
531                 goto error;
532
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);
537
538         if (aff1->ls->div->n_row == 0 && aff2->ls->div->n_row == 0)
539                 return add_expanded(aff1, aff2);
540
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;
545
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);
551
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;
559 }
560
561 __isl_give isl_aff *isl_aff_sub(__isl_take isl_aff *aff1,
562         __isl_take isl_aff *aff2)
563 {
564         return isl_aff_add(aff1, isl_aff_neg(aff2));
565 }
566
567 __isl_give isl_aff *isl_aff_scale(__isl_take isl_aff *aff, isl_int f)
568 {
569         isl_int gcd;
570
571         if (isl_int_is_one(f))
572                 return aff;
573
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);
580
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);
587
588         return aff;
589 }
590
591 __isl_give isl_aff *isl_aff_scale_down(__isl_take isl_aff *aff, isl_int f)
592 {
593         isl_int gcd;
594
595         if (isl_int_is_one(f))
596                 return aff;
597
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);
604
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);
612
613         return aff;
614 }
615
616 __isl_give isl_aff *isl_aff_scale_down_ui(__isl_take isl_aff *aff, unsigned f)
617 {
618         isl_int v;
619
620         if (f == 1)
621                 return aff;
622
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);
627
628         return aff;
629 }
630
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)
633 {
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);
640
641         return aff;
642 }
643
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".
648  */
649 static __isl_give isl_aff *isl_aff_substitute_equalities(
650         __isl_take isl_aff *aff, __isl_take isl_basic_set *eq)
651 {
652         int i, j;
653         unsigned total;
654         unsigned n_div;
655
656         if (!eq)
657                 goto error;
658         if (eq->n_eq == 0) {
659                 isl_basic_set_free(eq);
660                 return aff;
661         }
662
663         aff = isl_aff_cow(aff);
664         if (!aff)
665                 goto error;
666
667         aff->ls = isl_local_space_substitute_equalities(aff->ls,
668                                                         isl_basic_set_copy(eq));
669         if (!aff->ls)
670                 goto error;
671
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;
678
679                 isl_seq_elim(aff->v->el + 1, eq->eq[i], j, total,
680                                 &aff->v->el[0]);
681         }
682
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;
689 }
690
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.
695  */
696 __isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff,
697         __isl_take isl_set *context)
698 {
699         isl_basic_set *hull;
700         int n_div;
701
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));
714         }
715
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;
722 }