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