isl_pw_qpolynomial_fold_bound: explicitly project on parameter space
[platform/upstream/isl.git] / isl_bound.c
1 /*
2  * Copyright 2010      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_ctx_private.h>
12 #include <isl_map_private.h>
13 #include <isl_bound.h>
14 #include <isl_bernstein.h>
15 #include <isl_range.h>
16 #include <isl_polynomial_private.h>
17
18 /* Compute a bound on the polynomial defined over the parametric polytope
19  * using either range propagation or bernstein expansion and
20  * store the result in bound->pwf and bound->pwf_tight.
21  * Since bernstein expansion requires bounded domains, we apply
22  * range propagation on unbounded domains.  Otherwise, we respect the choice
23  * of the user.
24  */
25 static int compressed_guarded_poly_bound(__isl_take isl_basic_set *bset,
26         __isl_take isl_qpolynomial *poly, void *user)
27 {
28         struct isl_bound *bound = (struct isl_bound *)user;
29         int bounded;
30
31         if (!bset || !poly)
32                 goto error;
33
34         if (bset->ctx->opt->bound == ISL_BOUND_RANGE)
35                 return isl_qpolynomial_bound_on_domain_range(bset, poly, bound);
36
37         bounded = isl_basic_set_is_bounded(bset);
38         if (bounded < 0)
39                 goto error;
40         if (bounded)
41                 return isl_qpolynomial_bound_on_domain_bernstein(bset, poly, bound);
42         else
43                 return isl_qpolynomial_bound_on_domain_range(bset, poly, bound);
44 error:
45         isl_basic_set_free(bset);
46         isl_qpolynomial_free(poly);
47         return -1;
48 }
49
50 static int unwrapped_guarded_poly_bound(__isl_take isl_basic_set *bset,
51         __isl_take isl_qpolynomial *poly, void *user)
52 {
53         struct isl_bound *bound = (struct isl_bound *)user;
54         isl_pw_qpolynomial_fold *top_pwf;
55         isl_pw_qpolynomial_fold *top_pwf_tight;
56         isl_space *dim;
57         isl_morph *morph;
58         int r;
59
60         bset = isl_basic_set_detect_equalities(bset);
61
62         if (!bset)
63                 goto error;
64
65         if (bset->n_eq == 0)
66                 return compressed_guarded_poly_bound(bset, poly, user);
67
68         morph = isl_basic_set_full_compression(bset);
69
70         bset = isl_morph_basic_set(isl_morph_copy(morph), bset);
71         poly = isl_qpolynomial_morph(poly, isl_morph_copy(morph));
72
73         dim = isl_morph_get_ran_space(morph);
74         dim = isl_space_params(dim);
75
76         top_pwf = bound->pwf;
77         top_pwf_tight = bound->pwf_tight;
78
79         bound->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(dim),
80                                                   bound->type);
81         bound->pwf_tight = isl_pw_qpolynomial_fold_zero(dim, bound->type);
82
83         r = compressed_guarded_poly_bound(bset, poly, user);
84
85         morph = isl_morph_dom_params(morph);
86         morph = isl_morph_ran_params(morph);
87         morph = isl_morph_inverse(morph);
88
89         bound->pwf = isl_pw_qpolynomial_fold_morph(bound->pwf,
90                                                         isl_morph_copy(morph));
91         bound->pwf_tight = isl_pw_qpolynomial_fold_morph(bound->pwf_tight, morph);
92
93         bound->pwf = isl_pw_qpolynomial_fold_fold(top_pwf, bound->pwf);
94         bound->pwf_tight = isl_pw_qpolynomial_fold_fold(top_pwf_tight,
95                                                         bound->pwf_tight);
96
97         return r;
98 error:
99         isl_basic_set_free(bset);
100         isl_qpolynomial_free(poly);
101         return -1;
102 }
103
104 static int guarded_poly_bound(__isl_take isl_basic_set *bset,
105         __isl_take isl_qpolynomial *poly, void *user)
106 {
107         struct isl_bound *bound = (struct isl_bound *)user;
108         isl_space *dim;
109         isl_pw_qpolynomial_fold *top_pwf;
110         isl_pw_qpolynomial_fold *top_pwf_tight;
111         int nparam;
112         int n_in;
113         int r;
114
115         if (!bound->wrapping)
116                 return unwrapped_guarded_poly_bound(bset, poly, user);
117
118         nparam = isl_space_dim(bound->dim, isl_dim_param);
119         n_in = isl_space_dim(bound->dim, isl_dim_set);
120
121         bset = isl_basic_set_move_dims(bset, isl_dim_param, nparam,
122                                         isl_dim_set, 0, n_in);
123         poly = isl_qpolynomial_move_dims(poly, isl_dim_param, nparam,
124                                         isl_dim_set, 0, n_in);
125
126         dim = isl_basic_set_get_space(bset);
127         dim = isl_space_params(dim);
128
129         top_pwf = bound->pwf;
130         top_pwf_tight = bound->pwf_tight;
131
132         bound->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(dim),
133                                                   bound->type);
134         bound->pwf_tight = isl_pw_qpolynomial_fold_zero(dim, bound->type);
135
136         r = unwrapped_guarded_poly_bound(bset, poly, user);
137
138         bound->pwf = isl_pw_qpolynomial_fold_reset_space(bound->pwf,
139                                                     isl_space_copy(bound->dim));
140         bound->pwf_tight = isl_pw_qpolynomial_fold_reset_space(bound->pwf_tight,
141                                                     isl_space_copy(bound->dim));
142
143         bound->pwf = isl_pw_qpolynomial_fold_fold(top_pwf, bound->pwf);
144         bound->pwf_tight = isl_pw_qpolynomial_fold_fold(top_pwf_tight,
145                                                         bound->pwf_tight);
146
147         return r;
148 }
149
150 static int guarded_qp(__isl_take isl_qpolynomial *qp, void *user)
151 {
152         struct isl_bound *bound = (struct isl_bound *)user;
153         int r;
154
155         r = isl_qpolynomial_as_polynomial_on_domain(qp, bound->bset,
156                                                     &guarded_poly_bound, user);
157         isl_qpolynomial_free(qp);
158         return r;
159 }
160
161 static int basic_guarded_fold(__isl_take isl_basic_set *bset, void *user)
162 {
163         struct isl_bound *bound = (struct isl_bound *)user;
164         int r;
165
166         bound->bset = bset;
167         r = isl_qpolynomial_fold_foreach_qpolynomial(bound->fold,
168                                                         &guarded_qp, user);
169         isl_basic_set_free(bset);
170         return r;
171 }
172
173 static int guarded_fold(__isl_take isl_set *set,
174         __isl_take isl_qpolynomial_fold *fold, void *user)
175 {
176         struct isl_bound *bound = (struct isl_bound *)user;
177
178         if (!set || !fold)
179                 goto error;
180
181         set = isl_set_make_disjoint(set);
182
183         bound->fold = fold;
184         bound->type = isl_qpolynomial_fold_get_type(fold);
185
186         if (isl_set_foreach_basic_set(set, &basic_guarded_fold, bound) < 0)
187                 goto error;
188
189         isl_set_free(set);
190         isl_qpolynomial_fold_free(fold);
191
192         return 0;
193 error:
194         isl_set_free(set);
195         isl_qpolynomial_fold_free(fold);
196         return -1;
197 }
198
199 __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_bound(
200         __isl_take isl_pw_qpolynomial_fold *pwf, int *tight)
201 {
202         unsigned nvar;
203         struct isl_bound bound;
204         int covers;
205
206         if (!pwf)
207                 return NULL;
208
209         bound.dim = isl_pw_qpolynomial_fold_get_space(pwf);
210
211         bound.wrapping = isl_space_is_wrapping(bound.dim);
212         if (bound.wrapping)
213                 bound.dim = isl_space_unwrap(bound.dim);
214         nvar = isl_space_dim(bound.dim, isl_dim_out);
215         bound.dim = isl_space_domain(bound.dim);
216
217         if (nvar == 0) {
218                 if (tight)
219                         *tight = 1;
220                 return isl_pw_qpolynomial_fold_reset_space(pwf, bound.dim);
221         }
222
223         if (isl_pw_qpolynomial_fold_is_zero(pwf)) {
224                 enum isl_fold type = pwf->type;
225                 isl_pw_qpolynomial_fold_free(pwf);
226                 if (tight)
227                         *tight = 1;
228                 return isl_pw_qpolynomial_fold_zero(bound.dim, type);
229         }
230
231         bound.pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(bound.dim),
232                                                         pwf->type);
233         bound.pwf_tight = isl_pw_qpolynomial_fold_zero(isl_space_copy(bound.dim),
234                                                         pwf->type);
235         bound.check_tight = !!tight;
236
237         if (isl_pw_qpolynomial_fold_foreach_lifted_piece(pwf,
238                                                         guarded_fold, &bound) < 0)
239                 goto error;
240
241         covers = isl_pw_qpolynomial_fold_covers(bound.pwf_tight, bound.pwf);
242         if (covers < 0)
243                 goto error;
244
245         if (tight)
246                 *tight = covers;
247
248         isl_space_free(bound.dim);
249         isl_pw_qpolynomial_fold_free(pwf);
250
251         if (covers) {
252                 isl_pw_qpolynomial_fold_free(bound.pwf);
253                 return bound.pwf_tight;
254         }
255
256         bound.pwf = isl_pw_qpolynomial_fold_fold(bound.pwf, bound.pwf_tight);
257
258         return bound.pwf;
259 error:
260         isl_pw_qpolynomial_fold_free(bound.pwf_tight);
261         isl_pw_qpolynomial_fold_free(bound.pwf);
262         isl_pw_qpolynomial_fold_free(pwf);
263         isl_space_free(bound.dim);
264         return NULL;
265 }
266
267 __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_bound(
268         __isl_take isl_pw_qpolynomial *pwqp, enum isl_fold type, int *tight)
269 {
270         isl_pw_qpolynomial_fold *pwf;
271
272         pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(type, pwqp);
273         return isl_pw_qpolynomial_fold_bound(pwf, tight);
274 }
275
276 struct isl_union_bound_data {
277         enum isl_fold type;
278         int tight;
279         isl_union_pw_qpolynomial_fold *res;
280 };
281
282 static int bound_pw(__isl_take isl_pw_qpolynomial *pwqp, void *user)
283 {
284         struct isl_union_bound_data *data = user;
285         isl_pw_qpolynomial_fold *pwf;
286
287         pwf = isl_pw_qpolynomial_bound(pwqp, data->type,
288                                         data->tight ? &data->tight : NULL);
289         data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
290                                                                 data->res, pwf);
291
292         return 0;
293 }
294
295 __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_bound(
296         __isl_take isl_union_pw_qpolynomial *upwqp,
297         enum isl_fold type, int *tight)
298 {
299         isl_space *dim;
300         struct isl_union_bound_data data = { type, 1, NULL };
301
302         if (!upwqp)
303                 return NULL;
304
305         if (!tight)
306                 data.tight = 0;
307
308         dim = isl_union_pw_qpolynomial_get_space(upwqp);
309         data.res = isl_union_pw_qpolynomial_fold_zero(dim, type);
310         if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp,
311                                                     &bound_pw, &data) < 0)
312                 goto error;
313
314         isl_union_pw_qpolynomial_free(upwqp);
315         if (tight)
316                 *tight = data.tight;
317
318         return data.res;
319 error:
320         isl_union_pw_qpolynomial_free(upwqp);
321         isl_union_pw_qpolynomial_fold_free(data.res);
322         return NULL;
323 }