isl_transitive_closure.c: empty_path_is_identity: use isl_basic_map_fix_si
[isl.git] / isl_bernstein.c
blobff5dfd021da19ff703d3417899a3f9db170721b3
1 /*
2 * Copyright 2006-2007 Universiteit Leiden
3 * Copyright 2008-2009 Katholieke Universiteit Leuven
4 * Copyright 2010 INRIA Saclay
6 * Use of this software is governed by the MIT license
8 * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science,
9 * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands
10 * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A,
11 * B-3001 Leuven, Belgium
12 * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
13 * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
16 #include <isl_ctx_private.h>
17 #include <isl_map_private.h>
18 #include <isl/set.h>
19 #include <isl_seq.h>
20 #include <isl_morph.h>
21 #include <isl_factorization.h>
22 #include <isl_vertices_private.h>
23 #include <isl_polynomial_private.h>
24 #include <isl_options_private.h>
25 #include <isl_vec_private.h>
26 #include <isl_bernstein.h>
28 struct bernstein_data {
29 enum isl_fold type;
30 isl_qpolynomial *poly;
31 int check_tight;
33 isl_cell *cell;
35 isl_qpolynomial_fold *fold;
36 isl_qpolynomial_fold *fold_tight;
37 isl_pw_qpolynomial_fold *pwf;
38 isl_pw_qpolynomial_fold *pwf_tight;
41 static isl_bool vertex_is_integral(__isl_keep isl_basic_set *vertex)
43 unsigned nvar;
44 unsigned nparam;
45 int i;
47 nvar = isl_basic_set_dim(vertex, isl_dim_set);
48 nparam = isl_basic_set_dim(vertex, isl_dim_param);
49 for (i = 0; i < nvar; ++i) {
50 int r = nvar - 1 - i;
51 if (!isl_int_is_one(vertex->eq[r][1 + nparam + i]) &&
52 !isl_int_is_negone(vertex->eq[r][1 + nparam + i]))
53 return isl_bool_false;
56 return isl_bool_true;
59 static __isl_give isl_qpolynomial *vertex_coordinate(
60 __isl_keep isl_basic_set *vertex, int i, __isl_take isl_space *space)
62 unsigned nvar;
63 unsigned nparam;
64 int r;
65 isl_int denom;
66 isl_qpolynomial *v;
68 nvar = isl_basic_set_dim(vertex, isl_dim_set);
69 nparam = isl_basic_set_dim(vertex, isl_dim_param);
70 r = nvar - 1 - i;
72 isl_int_init(denom);
73 isl_int_set(denom, vertex->eq[r][1 + nparam + i]);
74 isl_assert(vertex->ctx, !isl_int_is_zero(denom), goto error);
76 if (isl_int_is_pos(denom))
77 isl_seq_neg(vertex->eq[r], vertex->eq[r],
78 1 + isl_basic_set_total_dim(vertex));
79 else
80 isl_int_neg(denom, denom);
82 v = isl_qpolynomial_from_affine(space, vertex->eq[r], denom);
83 isl_int_clear(denom);
85 return v;
86 error:
87 isl_space_free(space);
88 isl_int_clear(denom);
89 return NULL;
92 /* Check whether the bound associated to the selection "k" is tight,
93 * which is the case if we select exactly one vertex (i.e., one of the
94 * exponents in "k" is exactly "d") and if that vertex
95 * is integral for all values of the parameters.
97 static isl_bool is_tight(int *k, int n, int d, isl_cell *cell)
99 int i;
101 for (i = 0; i < n; ++i) {
102 int v;
103 if (!k[i])
104 continue;
105 if (k[i] != d)
106 return isl_bool_false;
107 v = cell->ids[n - 1 - i];
108 return vertex_is_integral(cell->vertices->v[v].vertex);
111 return isl_bool_false;
114 static isl_stat add_fold(__isl_take isl_qpolynomial *b, __isl_keep isl_set *dom,
115 int *k, int n, int d, struct bernstein_data *data)
117 isl_qpolynomial_fold *fold;
118 isl_bool tight;
120 fold = isl_qpolynomial_fold_alloc(data->type, b);
122 tight = isl_bool_false;
123 if (data->check_tight)
124 tight = is_tight(k, n, d, data->cell);
125 if (tight < 0)
126 return isl_stat_error;
127 if (tight)
128 data->fold_tight = isl_qpolynomial_fold_fold_on_domain(dom,
129 data->fold_tight, fold);
130 else
131 data->fold = isl_qpolynomial_fold_fold_on_domain(dom,
132 data->fold, fold);
133 return isl_stat_ok;
136 /* Extract the coefficients of the Bernstein base polynomials and store
137 * them in data->fold and data->fold_tight.
139 * In particular, the coefficient of each monomial
140 * of multi-degree (k[0], k[1], ..., k[n-1]) is divided by the corresponding
141 * multinomial coefficient d!/k[0]! k[1]! ... k[n-1]!
143 * c[i] contains the coefficient of the selected powers of the first i+1 vars.
144 * multinom[i] contains the partial multinomial coefficient.
146 static isl_stat extract_coefficients(isl_qpolynomial *poly,
147 __isl_keep isl_set *dom, struct bernstein_data *data)
149 int i;
150 int d;
151 int n;
152 isl_ctx *ctx;
153 isl_qpolynomial **c = NULL;
154 int *k = NULL;
155 int *left = NULL;
156 isl_vec *multinom = NULL;
158 if (!poly)
159 return isl_stat_error;
161 ctx = isl_qpolynomial_get_ctx(poly);
162 n = isl_qpolynomial_dim(poly, isl_dim_in);
163 d = isl_qpolynomial_degree(poly);
164 isl_assert(ctx, n >= 2, return isl_stat_error);
166 c = isl_calloc_array(ctx, isl_qpolynomial *, n);
167 k = isl_alloc_array(ctx, int, n);
168 left = isl_alloc_array(ctx, int, n);
169 multinom = isl_vec_alloc(ctx, n);
170 if (!c || !k || !left || !multinom)
171 goto error;
173 isl_int_set_si(multinom->el[0], 1);
174 for (k[0] = d; k[0] >= 0; --k[0]) {
175 int i = 1;
176 isl_qpolynomial_free(c[0]);
177 c[0] = isl_qpolynomial_coeff(poly, isl_dim_in, n - 1, k[0]);
178 left[0] = d - k[0];
179 k[1] = -1;
180 isl_int_set(multinom->el[1], multinom->el[0]);
181 while (i > 0) {
182 if (i == n - 1) {
183 int j;
184 isl_space *dim;
185 isl_qpolynomial *b;
186 isl_qpolynomial *f;
187 for (j = 2; j <= left[i - 1]; ++j)
188 isl_int_divexact_ui(multinom->el[i],
189 multinom->el[i], j);
190 b = isl_qpolynomial_coeff(c[i - 1], isl_dim_in,
191 n - 1 - i, left[i - 1]);
192 b = isl_qpolynomial_project_domain_on_params(b);
193 dim = isl_qpolynomial_get_domain_space(b);
194 f = isl_qpolynomial_rat_cst_on_domain(dim, ctx->one,
195 multinom->el[i]);
196 b = isl_qpolynomial_mul(b, f);
197 k[n - 1] = left[n - 2];
198 if (add_fold(b, dom, k, n, d, data) < 0)
199 goto error;
200 --i;
201 continue;
203 if (k[i] >= left[i - 1]) {
204 --i;
205 continue;
207 ++k[i];
208 if (k[i])
209 isl_int_divexact_ui(multinom->el[i],
210 multinom->el[i], k[i]);
211 isl_qpolynomial_free(c[i]);
212 c[i] = isl_qpolynomial_coeff(c[i - 1], isl_dim_in,
213 n - 1 - i, k[i]);
214 left[i] = left[i - 1] - k[i];
215 k[i + 1] = -1;
216 isl_int_set(multinom->el[i + 1], multinom->el[i]);
217 ++i;
219 isl_int_mul_ui(multinom->el[0], multinom->el[0], k[0]);
222 for (i = 0; i < n; ++i)
223 isl_qpolynomial_free(c[i]);
225 isl_vec_free(multinom);
226 free(left);
227 free(k);
228 free(c);
229 return isl_stat_ok;
230 error:
231 isl_vec_free(multinom);
232 free(left);
233 free(k);
234 if (c)
235 for (i = 0; i < n; ++i)
236 isl_qpolynomial_free(c[i]);
237 free(c);
238 return isl_stat_error;
241 /* Perform bernstein expansion on the parametric vertices that are active
242 * on "cell".
244 * data->poly has been homogenized in the calling function.
246 * We plug in the barycentric coordinates for the set variables
248 * \vec x = \sum_i \alpha_i v_i(\vec p)
250 * and the constant "1 = \sum_i \alpha_i" for the homogeneous dimension.
251 * Next, we extract the coefficients of the Bernstein base polynomials.
253 static isl_stat bernstein_coefficients_cell(__isl_take isl_cell *cell,
254 void *user)
256 int i, j;
257 struct bernstein_data *data = (struct bernstein_data *)user;
258 isl_space *space_param;
259 isl_space *space_dst;
260 isl_qpolynomial *poly = data->poly;
261 unsigned nvar;
262 int n_vertices;
263 isl_qpolynomial **subs;
264 isl_pw_qpolynomial_fold *pwf;
265 isl_set *dom;
266 isl_ctx *ctx;
268 if (!poly)
269 goto error;
271 nvar = isl_qpolynomial_dim(poly, isl_dim_in) - 1;
272 n_vertices = cell->n_vertices;
274 ctx = isl_qpolynomial_get_ctx(poly);
275 if (n_vertices > nvar + 1 && ctx->opt->bernstein_triangulate)
276 return isl_cell_foreach_simplex(cell,
277 &bernstein_coefficients_cell, user);
279 subs = isl_alloc_array(ctx, isl_qpolynomial *, 1 + nvar);
280 if (!subs)
281 goto error;
283 space_param = isl_basic_set_get_space(cell->dom);
284 space_dst = isl_qpolynomial_get_domain_space(poly);
285 space_dst = isl_space_add_dims(space_dst, isl_dim_set, n_vertices);
287 for (i = 0; i < 1 + nvar; ++i)
288 subs[i] =
289 isl_qpolynomial_zero_on_domain(isl_space_copy(space_dst));
291 for (i = 0; i < n_vertices; ++i) {
292 isl_qpolynomial *c;
293 c = isl_qpolynomial_var_on_domain(isl_space_copy(space_dst),
294 isl_dim_set, 1 + nvar + i);
295 for (j = 0; j < nvar; ++j) {
296 int k = cell->ids[i];
297 isl_qpolynomial *v;
298 v = vertex_coordinate(cell->vertices->v[k].vertex, j,
299 isl_space_copy(space_param));
300 v = isl_qpolynomial_add_dims(v, isl_dim_in,
301 1 + nvar + n_vertices);
302 v = isl_qpolynomial_mul(v, isl_qpolynomial_copy(c));
303 subs[1 + j] = isl_qpolynomial_add(subs[1 + j], v);
305 subs[0] = isl_qpolynomial_add(subs[0], c);
307 isl_space_free(space_dst);
309 poly = isl_qpolynomial_copy(poly);
311 poly = isl_qpolynomial_add_dims(poly, isl_dim_in, n_vertices);
312 poly = isl_qpolynomial_substitute(poly, isl_dim_in, 0, 1 + nvar, subs);
313 poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, 0, 1 + nvar);
315 data->cell = cell;
316 dom = isl_set_from_basic_set(isl_basic_set_copy(cell->dom));
317 data->fold = isl_qpolynomial_fold_empty(data->type,
318 isl_space_copy(space_param));
319 data->fold_tight = isl_qpolynomial_fold_empty(data->type, space_param);
320 if (extract_coefficients(poly, dom, data) < 0) {
321 data->fold = isl_qpolynomial_fold_free(data->fold);
322 data->fold_tight = isl_qpolynomial_fold_free(data->fold_tight);
325 pwf = isl_pw_qpolynomial_fold_alloc(data->type, isl_set_copy(dom),
326 data->fold);
327 data->pwf = isl_pw_qpolynomial_fold_fold(data->pwf, pwf);
328 pwf = isl_pw_qpolynomial_fold_alloc(data->type, dom, data->fold_tight);
329 data->pwf_tight = isl_pw_qpolynomial_fold_fold(data->pwf_tight, pwf);
331 isl_qpolynomial_free(poly);
332 isl_cell_free(cell);
333 for (i = 0; i < 1 + nvar; ++i)
334 isl_qpolynomial_free(subs[i]);
335 free(subs);
336 return isl_stat_ok;
337 error:
338 isl_cell_free(cell);
339 return isl_stat_error;
342 /* Base case of applying bernstein expansion.
344 * We compute the chamber decomposition of the parametric polytope "bset"
345 * and then perform bernstein expansion on the parametric vertices
346 * that are active on each chamber.
348 static __isl_give isl_pw_qpolynomial_fold *bernstein_coefficients_base(
349 __isl_take isl_basic_set *bset,
350 __isl_take isl_qpolynomial *poly, struct bernstein_data *data, int *tight)
352 unsigned nvar;
353 isl_space *space;
354 isl_pw_qpolynomial_fold *pwf;
355 isl_vertices *vertices;
356 isl_bool covers;
358 nvar = isl_basic_set_dim(bset, isl_dim_set);
359 if (nvar == 0) {
360 isl_set *dom;
361 isl_qpolynomial_fold *fold;
363 fold = isl_qpolynomial_fold_alloc(data->type, poly);
364 dom = isl_set_from_basic_set(bset);
365 if (tight)
366 *tight = 1;
367 pwf = isl_pw_qpolynomial_fold_alloc(data->type, dom, fold);
368 return isl_pw_qpolynomial_fold_project_domain_on_params(pwf);
371 if (isl_qpolynomial_is_zero(poly)) {
372 isl_set *dom;
373 isl_qpolynomial_fold *fold;
374 fold = isl_qpolynomial_fold_alloc(data->type, poly);
375 dom = isl_set_from_basic_set(bset);
376 pwf = isl_pw_qpolynomial_fold_alloc(data->type, dom, fold);
377 if (tight)
378 *tight = 1;
379 return isl_pw_qpolynomial_fold_project_domain_on_params(pwf);
382 space = isl_basic_set_get_space(bset);
383 space = isl_space_params(space);
384 space = isl_space_from_domain(space);
385 space = isl_space_add_dims(space, isl_dim_set, 1);
386 data->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(space),
387 data->type);
388 data->pwf_tight = isl_pw_qpolynomial_fold_zero(space, data->type);
389 data->poly = isl_qpolynomial_homogenize(isl_qpolynomial_copy(poly));
390 vertices = isl_basic_set_compute_vertices(bset);
391 if (isl_vertices_foreach_disjoint_cell(vertices,
392 &bernstein_coefficients_cell, data) < 0)
393 data->pwf = isl_pw_qpolynomial_fold_free(data->pwf);
394 isl_vertices_free(vertices);
395 isl_qpolynomial_free(data->poly);
397 isl_basic_set_free(bset);
398 isl_qpolynomial_free(poly);
400 covers = isl_pw_qpolynomial_fold_covers(data->pwf_tight, data->pwf);
401 if (covers < 0)
402 goto error;
404 if (tight)
405 *tight = covers;
407 if (covers) {
408 isl_pw_qpolynomial_fold_free(data->pwf);
409 return data->pwf_tight;
412 data->pwf = isl_pw_qpolynomial_fold_fold(data->pwf, data->pwf_tight);
414 return data->pwf;
415 error:
416 isl_pw_qpolynomial_fold_free(data->pwf_tight);
417 isl_pw_qpolynomial_fold_free(data->pwf);
418 return NULL;
421 /* Apply bernstein expansion recursively by working in on len[i]
422 * set variables at a time, with i ranging from n_group - 1 to 0.
424 static __isl_give isl_pw_qpolynomial_fold *bernstein_coefficients_recursive(
425 __isl_take isl_pw_qpolynomial *pwqp,
426 int n_group, int *len, struct bernstein_data *data, int *tight)
428 int i;
429 unsigned nparam;
430 unsigned nvar;
431 isl_pw_qpolynomial_fold *pwf;
433 if (!pwqp)
434 return NULL;
436 nparam = isl_pw_qpolynomial_dim(pwqp, isl_dim_param);
437 nvar = isl_pw_qpolynomial_dim(pwqp, isl_dim_in);
439 pwqp = isl_pw_qpolynomial_move_dims(pwqp, isl_dim_param, nparam,
440 isl_dim_in, 0, nvar - len[n_group - 1]);
441 pwf = isl_pw_qpolynomial_bound(pwqp, data->type, tight);
443 for (i = n_group - 2; i >= 0; --i) {
444 nparam = isl_pw_qpolynomial_fold_dim(pwf, isl_dim_param);
445 pwf = isl_pw_qpolynomial_fold_move_dims(pwf, isl_dim_in, 0,
446 isl_dim_param, nparam - len[i], len[i]);
447 if (tight && !*tight)
448 tight = NULL;
449 pwf = isl_pw_qpolynomial_fold_bound(pwf, tight);
452 return pwf;
455 static __isl_give isl_pw_qpolynomial_fold *bernstein_coefficients_factors(
456 __isl_take isl_basic_set *bset,
457 __isl_take isl_qpolynomial *poly, struct bernstein_data *data, int *tight)
459 isl_factorizer *f;
460 isl_set *set;
461 isl_pw_qpolynomial *pwqp;
462 isl_pw_qpolynomial_fold *pwf;
464 f = isl_basic_set_factorizer(bset);
465 if (!f)
466 goto error;
467 if (f->n_group == 0) {
468 isl_factorizer_free(f);
469 return bernstein_coefficients_base(bset, poly, data, tight);
472 set = isl_set_from_basic_set(bset);
473 pwqp = isl_pw_qpolynomial_alloc(set, poly);
474 pwqp = isl_pw_qpolynomial_morph_domain(pwqp, isl_morph_copy(f->morph));
476 pwf = bernstein_coefficients_recursive(pwqp, f->n_group, f->len, data,
477 tight);
479 isl_factorizer_free(f);
481 return pwf;
482 error:
483 isl_basic_set_free(bset);
484 isl_qpolynomial_free(poly);
485 return NULL;
488 static __isl_give isl_pw_qpolynomial_fold *bernstein_coefficients_full_recursive(
489 __isl_take isl_basic_set *bset,
490 __isl_take isl_qpolynomial *poly, struct bernstein_data *data, int *tight)
492 int i;
493 int *len;
494 unsigned nvar;
495 isl_pw_qpolynomial_fold *pwf;
496 isl_set *set;
497 isl_pw_qpolynomial *pwqp;
499 if (!bset || !poly)
500 goto error;
502 nvar = isl_basic_set_dim(bset, isl_dim_set);
504 len = isl_alloc_array(bset->ctx, int, nvar);
505 if (nvar && !len)
506 goto error;
508 for (i = 0; i < nvar; ++i)
509 len[i] = 1;
511 set = isl_set_from_basic_set(bset);
512 pwqp = isl_pw_qpolynomial_alloc(set, poly);
514 pwf = bernstein_coefficients_recursive(pwqp, nvar, len, data, tight);
516 free(len);
518 return pwf;
519 error:
520 isl_basic_set_free(bset);
521 isl_qpolynomial_free(poly);
522 return NULL;
525 /* Compute a bound on the polynomial defined over the parametric polytope
526 * using bernstein expansion and store the result
527 * in bound->pwf and bound->pwf_tight.
529 * If bernstein_recurse is set to ISL_BERNSTEIN_FACTORS, we check if
530 * the polytope can be factorized and apply bernstein expansion recursively
531 * on the factors.
532 * If bernstein_recurse is set to ISL_BERNSTEIN_INTERVALS, we apply
533 * bernstein expansion recursively on each dimension.
534 * Otherwise, we apply bernstein expansion on the entire polytope.
536 isl_stat isl_qpolynomial_bound_on_domain_bernstein(
537 __isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *poly,
538 struct isl_bound *bound)
540 struct bernstein_data data;
541 isl_pw_qpolynomial_fold *pwf;
542 unsigned nvar;
543 int tight = 0;
544 int *tp = bound->check_tight ? &tight : NULL;
546 if (!bset || !poly)
547 goto error;
549 data.type = bound->type;
550 data.check_tight = bound->check_tight;
552 nvar = isl_basic_set_dim(bset, isl_dim_set);
554 if (bset->ctx->opt->bernstein_recurse & ISL_BERNSTEIN_FACTORS)
555 pwf = bernstein_coefficients_factors(bset, poly, &data, tp);
556 else if (nvar > 1 &&
557 (bset->ctx->opt->bernstein_recurse & ISL_BERNSTEIN_INTERVALS))
558 pwf = bernstein_coefficients_full_recursive(bset, poly, &data, tp);
559 else
560 pwf = bernstein_coefficients_base(bset, poly, &data, tp);
562 if (tight)
563 bound->pwf_tight = isl_pw_qpolynomial_fold_fold(bound->pwf_tight, pwf);
564 else
565 bound->pwf = isl_pw_qpolynomial_fold_fold(bound->pwf, pwf);
567 return isl_stat_ok;
568 error:
569 isl_basic_set_free(bset);
570 isl_qpolynomial_free(poly);
571 return isl_stat_error;