document isl_union_set_apply_union_pw_qpolynomial
[barvinok.git] / bound.c
blob329fb2e0318fd65d47f1a7e47b88d27071ee6dfb
1 #include <assert.h>
2 #include <isl/stream.h>
3 #include <barvinok/options.h>
4 #include <barvinok/util.h>
5 #include <barvinok/barvinok.h>
6 #include "verify.h"
8 struct options {
9 struct verify_options *verify;
10 long split;
11 int lower;
12 long iterate;
15 struct isl_arg options_arg[] = {
16 ISL_ARG_CHILD(struct options, verify, NULL,
17 verify_options_arg, "verification")
18 ISL_ARG_LONG(struct options, split, 0, "split", 0, NULL)
19 ISL_ARG_OPT_LONG(struct options, iterate, 0, "iterate", 0, -1,
20 "exact result by iterating over domain (of specified maximal size)")
21 ISL_ARG_BOOL(struct options, lower, 0, "lower", 0,
22 "compute lower bound instead of upper bound")
23 ISL_ARG_END
26 ISL_ARG_DEF(options, struct options, options_arg)
28 struct verify_point_bound {
29 struct verify_point_data vpd;
30 isl_pw_qpolynomial *pwqp;
31 isl_pw_qpolynomial_fold *pwf;
32 enum isl_fold type;
35 static int verify_point(__isl_take isl_point *pnt, void *user)
37 int i;
38 unsigned nparam;
39 struct verify_point_bound *vpb = (struct verify_point_bound *) user;
40 isl_int v, n, d, b, t;
41 isl_pw_qpolynomial *pwqp;
42 isl_qpolynomial *bound;
43 isl_qpolynomial *opt;
44 const char *minmax;
45 int sign;
46 int ok;
47 int cst;
48 FILE *out = vpb->vpd.options->print_all ? stdout : stderr;
50 vpb->vpd.n--;
52 if (vpb->type == isl_fold_max) {
53 minmax = "max";
54 sign = 1;
55 } else {
56 minmax = "min";
57 sign = -1;
60 isl_int_init(b);
61 isl_int_init(t);
62 isl_int_init(v);
63 isl_int_init(n);
64 isl_int_init(d);
66 pwqp = isl_pw_qpolynomial_copy(vpb->pwqp);
68 nparam = isl_pw_qpolynomial_dim(pwqp, isl_dim_param);
69 for (i = 0; i < nparam; ++i) {
70 isl_point_get_coordinate(pnt, isl_dim_param, i, &v);
71 pwqp = isl_pw_qpolynomial_fix_dim(pwqp, isl_dim_param, i, v);
74 bound = isl_pw_qpolynomial_fold_eval(isl_pw_qpolynomial_fold_copy(vpb->pwf),
75 isl_point_copy(pnt));
77 if (sign > 0)
78 opt = isl_pw_qpolynomial_max(pwqp);
79 else
80 opt = isl_pw_qpolynomial_min(pwqp);
82 cst = isl_qpolynomial_is_cst(opt, &n, &d);
83 if (cst != 1)
84 goto error;
85 if (sign > 0)
86 isl_int_fdiv_q(v, n, d);
87 else
88 isl_int_cdiv_q(v, n, d);
90 cst = isl_qpolynomial_is_cst(bound, &n, &d);
91 if (cst != 1)
92 goto error;
93 if (sign > 0)
94 isl_int_fdiv_q(b, n, d);
95 else
96 isl_int_cdiv_q(b, n, d);
98 if (sign > 0)
99 ok = value_ge(b, v);
100 else
101 ok = value_le(b, v);
103 if (vpb->vpd.options->print_all || !ok) {
104 fprintf(out, "%s(", minmax);
105 for (i = 0; i < nparam; ++i) {
106 if (i)
107 fprintf(out, ", ");
108 isl_point_get_coordinate(pnt, isl_dim_param, i, &t);
109 isl_int_print(out, t, 0);
111 fprintf(out, ") = ");
112 isl_int_print(out, n, 0);
113 if (!isl_int_is_one(d)) {
114 fprintf(out, "/");
115 isl_int_print(out, d, 0);
116 fprintf(out, " (");
117 isl_int_print(out, b, 0);
118 fprintf(out, ")");
120 fprintf(out, ", %s(EP) = ", minmax);
121 isl_int_print(out, v, 0);
122 if (ok)
123 fprintf(out, ". OK\n");
124 else
125 fprintf(out, ". NOT OK\n");
126 } else if ((vpb->vpd.n % vpb->vpd.s) == 0) {
127 printf("o");
128 fflush(stdout);
131 if (0) {
132 error:
133 ok = 0;
136 isl_qpolynomial_free(bound);
137 isl_qpolynomial_free(opt);
138 isl_point_free(pnt);
140 isl_int_clear(t);
141 isl_int_clear(d);
142 isl_int_clear(n);
143 isl_int_clear(v);
144 isl_int_clear(b);
146 if (!ok)
147 vpb->vpd.error = 1;
149 if (vpb->vpd.options->continue_on_error)
150 ok = 1;
152 return (vpb->vpd.n >= 1 && ok) ? 0 : -1;
155 static int verify(__isl_keep isl_pw_qpolynomial_fold *pwf,
156 __isl_take isl_pw_qpolynomial *pwqp, enum isl_fold type,
157 struct verify_options *options)
159 struct verify_point_bound vpb = { { options } };
160 isl_set *context;
161 int r;
163 vpb.pwf = pwf;
164 vpb.type = type;
165 vpb.pwqp = pwqp;
166 context = isl_pw_qpolynomial_fold_domain(
167 isl_pw_qpolynomial_fold_copy(vpb.pwf));
168 context = verify_context_set_bounds(context, options);
170 r = verify_point_data_init(&vpb.vpd, context);
172 if (r == 0)
173 isl_set_foreach_point(context, verify_point, &vpb);
174 if (vpb.vpd.error)
175 r = -1;
177 isl_set_free(context);
178 isl_pw_qpolynomial_free(pwqp);
180 verify_point_data_fini(&vpb.vpd);
182 return r;
185 static __isl_give isl_pw_qpolynomial_fold *iterate(
186 __isl_take isl_pw_qpolynomial *pwqp, enum isl_fold type)
188 isl_dim *dim = isl_pw_qpolynomial_get_dim(pwqp);
189 isl_set *set;
190 isl_qpolynomial *qp;
191 isl_qpolynomial_fold *fold;
192 unsigned nvar;
194 assert(isl_dim_size(dim, isl_dim_param) == 0);
195 nvar = isl_dim_size(dim, isl_dim_set);
197 if (type == isl_fold_min)
198 qp = isl_pw_qpolynomial_min(pwqp);
199 else
200 qp = isl_pw_qpolynomial_max(pwqp);
202 qp = isl_qpolynomial_drop_dims(qp, isl_dim_set, 0, nvar);
203 fold = isl_qpolynomial_fold_alloc(type, qp);
204 dim = isl_dim_drop(dim, isl_dim_set, 0, nvar);
205 set = isl_set_universe(dim);
207 return isl_pw_qpolynomial_fold_alloc(type, set, fold);
210 struct bv_split_data {
211 int size;
212 __isl_give isl_pw_qpolynomial *pwqp_less;
213 __isl_give isl_pw_qpolynomial *pwqp_more;
216 static int split_on_size(__isl_take isl_set *set,
217 __isl_take isl_qpolynomial *qp, void *user)
219 struct bv_split_data *data = (struct bv_split_data *)user;
220 int bounded;
221 isl_set *set_np;
222 isl_pw_qpolynomial *pwqp;
223 int nparam;
225 nparam = isl_set_dim(set, isl_dim_param);
226 set_np = isl_set_move_dims(isl_set_copy(set), isl_dim_set, 0,
227 isl_dim_param, 0, nparam);
228 bounded = isl_set_is_bounded(set_np);
229 assert(bounded >= 0);
230 if (bounded) {
231 isl_pw_qpolynomial *pwqp;
232 isl_qpolynomial *cst;
233 isl_int m;
234 int is_cst;
236 pwqp = isl_set_card(set_np);
237 cst = isl_pw_qpolynomial_max(pwqp);
238 isl_int_init(m);
239 is_cst = isl_qpolynomial_is_cst(cst, &m, NULL);
240 isl_qpolynomial_free(cst);
241 assert(is_cst);
242 bounded = isl_int_cmp_si(m, data->size) <= 0;
243 isl_int_clear(m);
244 } else
245 isl_set_free(set_np);
247 pwqp = isl_pw_qpolynomial_alloc(set, qp);
248 if (bounded)
249 data->pwqp_less = isl_pw_qpolynomial_add_disjoint(
250 data->pwqp_less, pwqp);
251 else
252 data->pwqp_more = isl_pw_qpolynomial_add_disjoint(
253 data->pwqp_more, pwqp);
255 return 0;
259 * Split (partition) pwpq into a partition with (sub)domains containing
260 * size integer points or less and a partition with (sub)domains
261 * containing more integer points.
263 static int split_on_domain_size(__isl_take isl_pw_qpolynomial *pwqp,
264 __isl_give isl_pw_qpolynomial **pwqp_less,
265 __isl_give isl_pw_qpolynomial **pwqp_more,
266 int size)
268 isl_dim *dim;
269 struct bv_split_data data = { size };
270 int r;
272 dim = isl_pw_qpolynomial_get_dim(pwqp);
273 data.pwqp_less = isl_pw_qpolynomial_zero(isl_dim_copy(dim));
274 data.pwqp_more = isl_pw_qpolynomial_zero(dim);
275 r = isl_pw_qpolynomial_foreach_piece(pwqp, &split_on_size, &data);
276 *pwqp_less = data.pwqp_less;
277 *pwqp_more = data.pwqp_more;
278 isl_pw_qpolynomial_free(pwqp);
280 return r;
283 static __isl_give isl_pw_qpolynomial_fold *optimize(
284 __isl_take isl_pw_qpolynomial *pwqp, enum isl_fold type,
285 struct options *options)
287 isl_pw_qpolynomial_fold *pwf;
289 if (options->iterate > 0) {
290 isl_pw_qpolynomial *pwqp_less, *pwqp_more;
291 isl_pw_qpolynomial_fold *pwf_less, *pwf_more;
292 split_on_domain_size(pwqp, &pwqp_less, &pwqp_more, options->iterate);
293 pwf_less = iterate(pwqp_less, type);
294 pwf_more = isl_pw_qpolynomial_bound(pwqp_more, type, NULL);
295 pwf = isl_pw_qpolynomial_fold_fold(pwf_less, pwf_more);
296 } else if (options->iterate)
297 pwf = iterate(pwqp, type);
298 else
299 pwf = isl_pw_qpolynomial_bound(pwqp, type, NULL);
300 return pwf;
303 static int optimize_and_print(__isl_take isl_pw_qpolynomial *pwqp,
304 struct options *options)
306 int print_solution = 1;
307 int result = 0;
308 isl_pw_qpolynomial_fold *pwf;
309 enum isl_fold type = options->lower ? isl_fold_min : isl_fold_max;
311 if (options->verify->verify) {
312 isl_dim *dim = isl_pw_qpolynomial_get_dim(pwqp);
313 unsigned total = isl_dim_total(dim);
314 isl_dim_free(dim);
315 verify_options_set_range(options->verify, total);
316 if (!options->verify->barvinok->verbose)
317 print_solution = 0;
320 pwf = optimize(isl_pw_qpolynomial_copy(pwqp), type, options);
321 assert(pwf);
322 if (print_solution) {
323 isl_ctx *ctx = isl_pw_qpolynomial_get_ctx(pwqp);
324 isl_printer *p = isl_printer_to_file(ctx, stdout);
325 p = isl_printer_print_pw_qpolynomial_fold(p, pwf);
326 p = isl_printer_end_line(p);
327 isl_printer_free(p);
329 if (options->verify->verify) {
330 enum isl_fold type = options->lower ? isl_fold_min : isl_fold_max;
331 result = verify(pwf, pwqp, type, options->verify);
332 } else
333 isl_pw_qpolynomial_free(pwqp);
334 isl_pw_qpolynomial_fold_free(pwf);
336 return result;
339 int main(int argc, char **argv)
341 struct options *options = options_new_with_defaults();
342 isl_ctx *ctx;
343 isl_pw_qpolynomial *pwqp;
344 struct isl_stream *s;
345 int result = 0;
347 argc = options_parse(options, argc, argv, ISL_ARG_ALL);
348 ctx = isl_ctx_alloc_with_options(options_arg, options);
350 s = isl_stream_new_file(ctx, stdin);
351 pwqp = isl_stream_read_pw_qpolynomial(s);
353 if (options->split)
354 pwqp = isl_pw_qpolynomial_split_periods(pwqp, options->split);
356 result = optimize_and_print(pwqp, options);
358 isl_stream_free(s);
359 isl_ctx_free(ctx);
360 return result;