isl_basic_set_opt: avoid invalid access on error path
[platform/upstream/isl.git] / isl_ilp.c
1 /*
2  * Copyright 2008-2009 Katholieke Universiteit Leuven
3  *
4  * Use of this software is governed by the MIT license
5  *
6  * Written by Sven Verdoolaege, K.U.Leuven, Departement
7  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
8  */
9
10 #include <isl_ctx_private.h>
11 #include <isl_map_private.h>
12 #include <isl/ilp.h>
13 #include "isl_sample.h"
14 #include <isl/seq.h>
15 #include "isl_equalities.h"
16 #include <isl_aff_private.h>
17 #include <isl_local_space_private.h>
18 #include <isl_mat_private.h>
19
20 /* Given a basic set "bset", construct a basic set U such that for
21  * each element x in U, the whole unit box positioned at x is inside
22  * the given basic set.
23  * Note that U may not contain all points that satisfy this property.
24  *
25  * We simply add the sum of all negative coefficients to the constant
26  * term.  This ensures that if x satisfies the resulting constraints,
27  * then x plus any sum of unit vectors satisfies the original constraints.
28  */
29 static struct isl_basic_set *unit_box_base_points(struct isl_basic_set *bset)
30 {
31         int i, j, k;
32         struct isl_basic_set *unit_box = NULL;
33         unsigned total;
34
35         if (!bset)
36                 goto error;
37
38         if (bset->n_eq != 0) {
39                 unit_box = isl_basic_set_empty_like(bset);
40                 isl_basic_set_free(bset);
41                 return unit_box;
42         }
43
44         total = isl_basic_set_total_dim(bset);
45         unit_box = isl_basic_set_alloc_space(isl_basic_set_get_space(bset),
46                                         0, 0, bset->n_ineq);
47
48         for (i = 0; i < bset->n_ineq; ++i) {
49                 k = isl_basic_set_alloc_inequality(unit_box);
50                 if (k < 0)
51                         goto error;
52                 isl_seq_cpy(unit_box->ineq[k], bset->ineq[i], 1 + total);
53                 for (j = 0; j < total; ++j) {
54                         if (isl_int_is_nonneg(unit_box->ineq[k][1 + j]))
55                                 continue;
56                         isl_int_add(unit_box->ineq[k][0],
57                                 unit_box->ineq[k][0], unit_box->ineq[k][1 + j]);
58                 }
59         }
60
61         isl_basic_set_free(bset);
62         return unit_box;
63 error:
64         isl_basic_set_free(bset);
65         isl_basic_set_free(unit_box);
66         return NULL;
67 }
68
69 /* Find an integer point in "bset", preferably one that is
70  * close to minimizing "f".
71  *
72  * We first check if we can easily put unit boxes inside bset.
73  * If so, we take the best base point of any of the unit boxes we can find
74  * and round it up to the nearest integer.
75  * If not, we simply pick any integer point in "bset".
76  */
77 static struct isl_vec *initial_solution(struct isl_basic_set *bset, isl_int *f)
78 {
79         enum isl_lp_result res;
80         struct isl_basic_set *unit_box;
81         struct isl_vec *sol;
82
83         unit_box = unit_box_base_points(isl_basic_set_copy(bset));
84
85         res = isl_basic_set_solve_lp(unit_box, 0, f, bset->ctx->one,
86                                         NULL, NULL, &sol);
87         if (res == isl_lp_ok) {
88                 isl_basic_set_free(unit_box);
89                 return isl_vec_ceil(sol);
90         }
91
92         isl_basic_set_free(unit_box);
93
94         return isl_basic_set_sample_vec(isl_basic_set_copy(bset));
95 }
96
97 /* Restrict "bset" to those points with values for f in the interval [l, u].
98  */
99 static struct isl_basic_set *add_bounds(struct isl_basic_set *bset,
100         isl_int *f, isl_int l, isl_int u)
101 {
102         int k;
103         unsigned total;
104
105         total = isl_basic_set_total_dim(bset);
106         bset = isl_basic_set_extend_constraints(bset, 0, 2);
107
108         k = isl_basic_set_alloc_inequality(bset);
109         if (k < 0)
110                 goto error;
111         isl_seq_cpy(bset->ineq[k], f, 1 + total);
112         isl_int_sub(bset->ineq[k][0], bset->ineq[k][0], l);
113
114         k = isl_basic_set_alloc_inequality(bset);
115         if (k < 0)
116                 goto error;
117         isl_seq_neg(bset->ineq[k], f, 1 + total);
118         isl_int_add(bset->ineq[k][0], bset->ineq[k][0], u);
119
120         return bset;
121 error:
122         isl_basic_set_free(bset);
123         return NULL;
124 }
125
126 /* Find an integer point in "bset" that minimizes f (in any) such that
127  * the value of f lies inside the interval [l, u].
128  * Return this integer point if it can be found.
129  * Otherwise, return sol.
130  *
131  * We perform a number of steps until l > u.
132  * In each step, we look for an integer point with value in either
133  * the whole interval [l, u] or half of the interval [l, l+floor(u-l-1/2)].
134  * The choice depends on whether we have found an integer point in the
135  * previous step.  If so, we look for the next point in half of the remaining
136  * interval.
137  * If we find a point, the current solution is updated and u is set
138  * to its value minus 1.
139  * If no point can be found, we update l to the upper bound of the interval
140  * we checked (u or l+floor(u-l-1/2)) plus 1.
141  */
142 static struct isl_vec *solve_ilp_search(struct isl_basic_set *bset,
143         isl_int *f, isl_int *opt, struct isl_vec *sol, isl_int l, isl_int u)
144 {
145         isl_int tmp;
146         int divide = 1;
147
148         isl_int_init(tmp);
149
150         while (isl_int_le(l, u)) {
151                 struct isl_basic_set *slice;
152                 struct isl_vec *sample;
153
154                 if (!divide)
155                         isl_int_set(tmp, u);
156                 else {
157                         isl_int_sub(tmp, u, l);
158                         isl_int_fdiv_q_ui(tmp, tmp, 2);
159                         isl_int_add(tmp, tmp, l);
160                 }
161                 slice = add_bounds(isl_basic_set_copy(bset), f, l, tmp);
162                 sample = isl_basic_set_sample_vec(slice);
163                 if (!sample) {
164                         isl_vec_free(sol);
165                         sol = NULL;
166                         break;
167                 }
168                 if (sample->size > 0) {
169                         isl_vec_free(sol);
170                         sol = sample;
171                         isl_seq_inner_product(f, sol->el, sol->size, opt);
172                         isl_int_sub_ui(u, *opt, 1);
173                         divide = 1;
174                 } else {
175                         isl_vec_free(sample);
176                         if (!divide)
177                                 break;
178                         isl_int_add_ui(l, tmp, 1);
179                         divide = 0;
180                 }
181         }
182
183         isl_int_clear(tmp);
184
185         return sol;
186 }
187
188 /* Find an integer point in "bset" that minimizes f (if any).
189  * If sol_p is not NULL then the integer point is returned in *sol_p.
190  * The optimal value of f is returned in *opt.
191  *
192  * The algorithm maintains a currently best solution and an interval [l, u]
193  * of values of f for which integer solutions could potentially still be found.
194  * The initial value of the best solution so far is any solution.
195  * The initial value of l is minimal value of f over the rationals
196  * (rounded up to the nearest integer).
197  * The initial value of u is the value of f at the initial solution minus 1.
198  *
199  * We then call solve_ilp_search to perform a binary search on the interval.
200  */
201 static enum isl_lp_result solve_ilp(struct isl_basic_set *bset,
202                                       isl_int *f, isl_int *opt,
203                                       struct isl_vec **sol_p)
204 {
205         enum isl_lp_result res;
206         isl_int l, u;
207         struct isl_vec *sol;
208
209         res = isl_basic_set_solve_lp(bset, 0, f, bset->ctx->one,
210                                         opt, NULL, &sol);
211         if (res == isl_lp_ok && isl_int_is_one(sol->el[0])) {
212                 if (sol_p)
213                         *sol_p = sol;
214                 else
215                         isl_vec_free(sol);
216                 return isl_lp_ok;
217         }
218         isl_vec_free(sol);
219         if (res == isl_lp_error || res == isl_lp_empty)
220                 return res;
221
222         sol = initial_solution(bset, f);
223         if (!sol)
224                 return isl_lp_error;
225         if (sol->size == 0) {
226                 isl_vec_free(sol);
227                 return isl_lp_empty;
228         }
229         if (res == isl_lp_unbounded) {
230                 isl_vec_free(sol);
231                 return isl_lp_unbounded;
232         }
233
234         isl_int_init(l);
235         isl_int_init(u);
236
237         isl_int_set(l, *opt);
238
239         isl_seq_inner_product(f, sol->el, sol->size, opt);
240         isl_int_sub_ui(u, *opt, 1);
241
242         sol = solve_ilp_search(bset, f, opt, sol, l, u);
243         if (!sol)
244                 res = isl_lp_error;
245
246         isl_int_clear(l);
247         isl_int_clear(u);
248
249         if (sol_p)
250                 *sol_p = sol;
251         else
252                 isl_vec_free(sol);
253
254         return res;
255 }
256
257 static enum isl_lp_result solve_ilp_with_eq(struct isl_basic_set *bset, int max,
258                                       isl_int *f, isl_int *opt,
259                                       struct isl_vec **sol_p)
260 {
261         unsigned dim;
262         enum isl_lp_result res;
263         struct isl_mat *T = NULL;
264         struct isl_vec *v;
265
266         bset = isl_basic_set_copy(bset);
267         dim = isl_basic_set_total_dim(bset);
268         v = isl_vec_alloc(bset->ctx, 1 + dim);
269         if (!v)
270                 goto error;
271         isl_seq_cpy(v->el, f, 1 + dim);
272         bset = isl_basic_set_remove_equalities(bset, &T, NULL);
273         v = isl_vec_mat_product(v, isl_mat_copy(T));
274         if (!v)
275                 goto error;
276         res = isl_basic_set_solve_ilp(bset, max, v->el, opt, sol_p);
277         isl_vec_free(v);
278         if (res == isl_lp_ok && sol_p) {
279                 *sol_p = isl_mat_vec_product(T, *sol_p);
280                 if (!*sol_p)
281                         res = isl_lp_error;
282         } else
283                 isl_mat_free(T);
284         isl_basic_set_free(bset);
285         return res;
286 error:
287         isl_mat_free(T);
288         isl_basic_set_free(bset);
289         return isl_lp_error;
290 }
291
292 /* Find an integer point in "bset" that minimizes (or maximizes if max is set)
293  * f (if any).
294  * If sol_p is not NULL then the integer point is returned in *sol_p.
295  * The optimal value of f is returned in *opt.
296  *
297  * If there is any equality among the points in "bset", then we first
298  * project it out.  Otherwise, we continue with solve_ilp above.
299  */
300 enum isl_lp_result isl_basic_set_solve_ilp(struct isl_basic_set *bset, int max,
301                                       isl_int *f, isl_int *opt,
302                                       struct isl_vec **sol_p)
303 {
304         unsigned dim;
305         enum isl_lp_result res;
306
307         if (!bset)
308                 return isl_lp_error;
309         if (sol_p)
310                 *sol_p = NULL;
311
312         isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
313
314         if (isl_basic_set_plain_is_empty(bset))
315                 return isl_lp_empty;
316
317         if (bset->n_eq)
318                 return solve_ilp_with_eq(bset, max, f, opt, sol_p);
319
320         dim = isl_basic_set_total_dim(bset);
321
322         if (max)
323                 isl_seq_neg(f, f, 1 + dim);
324
325         res = solve_ilp(bset, f, opt, sol_p);
326
327         if (max) {
328                 isl_seq_neg(f, f, 1 + dim);
329                 isl_int_neg(*opt, *opt);
330         }
331
332         return res;
333 error:
334         isl_basic_set_free(bset);
335         return isl_lp_error;
336 }
337
338 static enum isl_lp_result basic_set_opt(__isl_keep isl_basic_set *bset, int max,
339         __isl_keep isl_aff *obj, isl_int *opt)
340 {
341         enum isl_lp_result res;
342
343         if (!obj)
344                 return isl_lp_error;
345         bset = isl_basic_set_copy(bset);
346         bset = isl_basic_set_underlying_set(bset);
347         res = isl_basic_set_solve_ilp(bset, max, obj->v->el + 1, opt, NULL);
348         isl_basic_set_free(bset);
349         return res;
350 }
351
352 static __isl_give isl_mat *extract_divs(__isl_keep isl_basic_set *bset)
353 {
354         int i;
355         isl_ctx *ctx = isl_basic_set_get_ctx(bset);
356         isl_mat *div;
357
358         div = isl_mat_alloc(ctx, bset->n_div,
359                             1 + 1 + isl_basic_set_total_dim(bset));
360         if (!div)
361                 return NULL;
362
363         for (i = 0; i < bset->n_div; ++i)
364                 isl_seq_cpy(div->row[i], bset->div[i], div->n_col);
365
366         return div;
367 }
368
369 enum isl_lp_result isl_basic_set_opt(__isl_keep isl_basic_set *bset, int max,
370         __isl_keep isl_aff *obj, isl_int *opt)
371 {
372         int *exp1 = NULL;
373         int *exp2 = NULL;
374         isl_ctx *ctx;
375         isl_mat *bset_div = NULL;
376         isl_mat *div = NULL;
377         enum isl_lp_result res;
378         int bset_n_div;
379
380         if (!bset || !obj)
381                 return isl_lp_error;
382
383         ctx = isl_aff_get_ctx(obj);
384         if (!isl_space_is_equal(bset->dim, obj->ls->dim))
385                 isl_die(ctx, isl_error_invalid,
386                         "spaces don't match", return isl_lp_error);
387         if (!isl_int_is_one(obj->v->el[0]))
388                 isl_die(ctx, isl_error_unsupported,
389                         "expecting integer affine expression",
390                         return isl_lp_error);
391
392         bset_n_div = isl_basic_set_dim(bset, isl_dim_div);
393         if (bset_n_div == 0 && obj->ls->div->n_row == 0)
394                 return basic_set_opt(bset, max, obj, opt);
395
396         bset = isl_basic_set_copy(bset);
397         obj = isl_aff_copy(obj);
398
399         bset_div = extract_divs(bset);
400         exp1 = isl_alloc_array(ctx, int, bset_n_div);
401         exp2 = isl_alloc_array(ctx, int, obj->ls->div->n_row);
402         if (!bset_div || !exp1 || !exp2)
403                 goto error;
404
405         div = isl_merge_divs(bset_div, obj->ls->div, exp1, exp2);
406
407         bset = isl_basic_set_expand_divs(bset, isl_mat_copy(div), exp1);
408         obj = isl_aff_expand_divs(obj, isl_mat_copy(div), exp2);
409
410         res = basic_set_opt(bset, max, obj, opt);
411
412         isl_mat_free(bset_div);
413         isl_mat_free(div);
414         free(exp1);
415         free(exp2);
416         isl_basic_set_free(bset);
417         isl_aff_free(obj);
418
419         return res;
420 error:
421         isl_mat_free(div);
422         isl_mat_free(bset_div);
423         free(exp1);
424         free(exp2);
425         isl_basic_set_free(bset);
426         isl_aff_free(obj);
427         return isl_lp_error;
428 }
429
430 /* Compute the minimum (maximum if max is set) of the integer affine
431  * expression obj over the points in set and put the result in *opt.
432  *
433  * The parameters are assumed to have been aligned.
434  */
435 static enum isl_lp_result isl_set_opt_aligned(__isl_keep isl_set *set, int max,
436         __isl_keep isl_aff *obj, isl_int *opt)
437 {
438         int i;
439         enum isl_lp_result res;
440         int empty = 1;
441         isl_int opt_i;
442
443         if (!set || !obj)
444                 return isl_lp_error;
445         if (set->n == 0)
446                 return isl_lp_empty;
447
448         res = isl_basic_set_opt(set->p[0], max, obj, opt);
449         if (res == isl_lp_error || res == isl_lp_unbounded)
450                 return res;
451         if (set->n == 1)
452                 return res;
453         if (res == isl_lp_ok)
454                 empty = 0;
455
456         isl_int_init(opt_i);
457         for (i = 1; i < set->n; ++i) {
458                 res = isl_basic_set_opt(set->p[i], max, obj, &opt_i);
459                 if (res == isl_lp_error || res == isl_lp_unbounded) {
460                         isl_int_clear(opt_i);
461                         return res;
462                 }
463                 if (res == isl_lp_ok)
464                         empty = 0;
465                 if (isl_int_gt(opt_i, *opt))
466                         isl_int_set(*opt, opt_i);
467         }
468         isl_int_clear(opt_i);
469
470         return empty ? isl_lp_empty : isl_lp_ok;
471 }
472
473 /* Compute the minimum (maximum if max is set) of the integer affine
474  * expression obj over the points in set and put the result in *opt.
475  */
476 enum isl_lp_result isl_set_opt(__isl_keep isl_set *set, int max,
477         __isl_keep isl_aff *obj, isl_int *opt)
478 {
479         enum isl_lp_result res;
480
481         if (!set || !obj)
482                 return isl_lp_error;
483
484         if (isl_space_match(set->dim, isl_dim_param,
485                             obj->ls->dim, isl_dim_param))
486                 return isl_set_opt_aligned(set, max, obj, opt);
487
488         set = isl_set_copy(set);
489         obj = isl_aff_copy(obj);
490         set = isl_set_align_params(set, isl_aff_get_domain_space(obj));
491         obj = isl_aff_align_params(obj, isl_set_get_space(set));
492
493         res = isl_set_opt_aligned(set, max, obj, opt);
494
495         isl_set_free(set);
496         isl_aff_free(obj);
497
498         return res;
499 }
500
501 enum isl_lp_result isl_basic_set_max(__isl_keep isl_basic_set *bset,
502         __isl_keep isl_aff *obj, isl_int *opt)
503 {
504         return isl_basic_set_opt(bset, 1, obj, opt);
505 }
506
507 enum isl_lp_result isl_set_max(__isl_keep isl_set *set,
508         __isl_keep isl_aff *obj, isl_int *opt)
509 {
510         return isl_set_opt(set, 1, obj, opt);
511 }
512
513 enum isl_lp_result isl_set_min(__isl_keep isl_set *set,
514         __isl_keep isl_aff *obj, isl_int *opt)
515 {
516         return isl_set_opt(set, 0, obj, opt);
517 }