3 #include <bernstein/bernstein.h>
4 #include <barvinok/evalue.h>
5 #include <barvinok/options.h>
6 #include <barvinok/util.h>
7 #include <barvinok/barvinok.h>
8 #include <barvinok/bernstein.h>
11 #include "evalue_convert.h"
12 #include "evalue_read.h"
19 using namespace GiNaC
;
20 using namespace bernstein
;
21 using namespace barvinok
;
23 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
25 #define OPT_VARS (BV_OPT_LAST+1)
26 #define OPT_SPLIT (BV_OPT_LAST+2)
27 #define OPT_LOWER (BV_OPT_LAST+3)
28 #define OPT_ITERATE (BV_OPT_LAST+4)
30 struct argp_option argp_options
[] = {
31 { "split", OPT_SPLIT
, "int" },
32 { "variables", OPT_VARS
, "list", 0,
33 "comma separated list of variables over which to compute a bound" },
34 { "lower", OPT_LOWER
, 0, 0, "compute lower bound instead of upper bound"},
35 { "iterate", OPT_ITERATE
, "int", 1,
36 "exact result by iterating over domain (of specified maximal size)"},
41 struct convert_options convert
;
42 struct verify_options verify
;
49 static error_t
parse_opt(int key
, char *arg
, struct argp_state
*state
)
51 struct options
*options
= (struct options
*) state
->input
;
55 state
->child_inputs
[0] = &options
->convert
;
56 state
->child_inputs
[1] = &options
->verify
;
57 state
->child_inputs
[2] = options
->verify
.barvinok
;
58 options
->var_list
= NULL
;
64 options
->var_list
= strdup(arg
);
67 options
->split
= atoi(arg
);
74 options
->iterate
= -1;
76 options
->iterate
= atoi(arg
);
79 return ARGP_ERR_UNKNOWN
;
84 struct verify_point_bound
{
85 struct verify_point_data vpd
;
86 isl_pw_qpolynomial
*pwqp
;
87 isl_pw_qpolynomial_fold
*pwf
;
90 static int verify_point(__isl_take isl_point
*pnt
, void *user
)
94 struct verify_point_bound
*vpb
= (struct verify_point_bound
*) user
;
95 isl_int v
, n
, d
, b
, t
;
96 isl_pw_qpolynomial
*pwqp
;
97 isl_qpolynomial
*bound
;
103 FILE *out
= vpb
->vpd
.options
->print_all
? stdout
: stderr
;
107 if (vpb
->vpd
.options
->barvinok
->bernstein_optimize
== BV_BERNSTEIN_MAX
) {
121 pwqp
= isl_pw_qpolynomial_copy(vpb
->pwqp
);
123 nparam
= isl_pw_qpolynomial_dim(pwqp
, isl_dim_param
);
124 for (i
= 0; i
< nparam
; ++i
) {
125 isl_point_get_coordinate(pnt
, isl_dim_param
, i
, &v
);
126 pwqp
= isl_pw_qpolynomial_fix_dim(pwqp
, isl_dim_param
, i
, v
);
129 bound
= isl_pw_qpolynomial_fold_eval(isl_pw_qpolynomial_fold_copy(vpb
->pwf
),
130 isl_point_copy(pnt
));
133 opt
= isl_pw_qpolynomial_max(pwqp
);
135 opt
= isl_pw_qpolynomial_min(pwqp
);
137 cst
= isl_qpolynomial_is_cst(opt
, &n
, &d
);
141 isl_int_fdiv_q(v
, n
, d
);
143 isl_int_cdiv_q(v
, n
, d
);
145 cst
= isl_qpolynomial_is_cst(bound
, &n
, &d
);
149 isl_int_fdiv_q(b
, n
, d
);
151 isl_int_cdiv_q(b
, n
, d
);
158 if (vpb
->vpd
.options
->print_all
|| !ok
) {
159 fprintf(out
, "%s(", minmax
);
160 for (i
= 0; i
< nparam
; ++i
) {
163 isl_point_get_coordinate(pnt
, isl_dim_param
, i
, &t
);
164 isl_int_print(out
, t
, 0);
166 fprintf(out
, ") = ");
167 isl_int_print(out
, n
, 0);
168 if (!isl_int_is_one(d
)) {
170 isl_int_print(out
, d
, 0);
172 isl_int_print(out
, b
, 0);
175 fprintf(out
, ", %s(EP) = ", minmax
);
176 isl_int_print(out
, v
, 0);
178 fprintf(out
, ". OK\n");
180 fprintf(out
, ". NOT OK\n");
181 } else if ((vpb
->vpd
.n
% vpb
->vpd
.s
) == 0) {
191 isl_qpolynomial_free(bound
);
192 isl_qpolynomial_free(opt
);
204 if (vpb
->vpd
.options
->continue_on_error
)
207 return (vpb
->vpd
.n
>= 1 && ok
) ? 0 : -1;
210 static int verify(piecewise_lst
*pl
, evalue
*EP
, unsigned nvar
,
211 const GiNaC::exvector
¶ms
,
212 struct verify_options
*options
)
214 struct verify_point_bound vpb
= { { options
} };
215 isl_ctx
*ctx
= isl_ctx_alloc();
220 dim
= isl_dim_set_alloc(ctx
, params
.size(), 0);
221 vpb
.pwf
= isl_pw_qpolynomial_fold_from_ginac(dim
, pl
, params
);
222 dim
= isl_dim_set_alloc(ctx
, nvar
+ params
.size(), 0);
223 vpb
.pwqp
= isl_pw_qpolynomial_from_evalue(dim
, EP
);
224 vpb
.pwqp
= isl_pw_qpolynomial_move(vpb
.pwqp
, isl_dim_set
, 0,
225 isl_dim_param
, 0, nvar
);
226 context
= isl_pw_qpolynomial_fold_domain(
227 isl_pw_qpolynomial_fold_copy(vpb
.pwf
));
228 context
= verify_context_set_bounds(context
, options
);
230 r
= verify_point_data_init(&vpb
.vpd
, context
);
233 isl_set_foreach_point(context
, verify_point
, &vpb
);
237 isl_set_free(context
);
238 isl_pw_qpolynomial_free(vpb
.pwqp
);
239 isl_pw_qpolynomial_fold_free(vpb
.pwf
);
243 verify_point_data_fini(&vpb
.vpd
);
248 static piecewise_lst
*iterate(evalue
*EP
, unsigned nvar
, Polyhedron
*C
,
249 struct options
*options
)
251 assert(C
->Dimension
== 0);
252 Vector
*p
= Vector_Alloc(nvar
+2);
253 value_set_si(p
->p
[nvar
+1], 1);
257 struct check_EP_data data
;
259 data
.cp
.check
= NULL
;
262 check_EP_set_scan(&data
, C
, options
->verify
.barvinok
->MaxRays
);
263 int sign
= options
->verify
.barvinok
->bernstein_optimize
;
264 evalue_optimum(&data
, &opt
, sign
);
265 check_EP_clear_scan(&data
);
268 piecewise_lst
*pl
= new piecewise_lst(params
, sign
);
269 pl
->add_guarded_lst(Polyhedron_Copy(C
), lst(value2numeric(opt
)));
278 * Split (partition) EP into a partition with (sub)domains containing
279 * size integer points or less and a partition with (sub)domains
280 * containing more integer points.
282 static void split_on_domain_size(evalue
*EP
, evalue
**EP_less
, evalue
**EP_more
,
283 int size
, barvinok_options
*options
)
285 assert(value_zero_p(EP
->d
));
286 assert(EP
->x
.p
->type
== partition
);
287 assert(EP
->x
.p
->size
>= 2);
289 struct evalue_section
*s_less
= new evalue_section
[EP
->x
.p
->size
/2];
290 struct evalue_section
*s_more
= new evalue_section
[EP
->x
.p
->size
/2];
298 for (int i
= 0; i
< EP
->x
.p
->size
/2; ++i
) {
299 Polyhedron
*D
= EVALUE_DOMAIN(EP
->x
.p
->arr
[2*i
]);
300 Polyhedron
*D_less
= NULL
;
301 Polyhedron
*D_more
= NULL
;
302 Polyhedron
**next_less
= &D_less
;
303 Polyhedron
**next_more
= &D_more
;
305 for (Polyhedron
*P
= D
; P
; P
= P
->next
) {
306 Polyhedron
*next
= P
->next
;
308 barvinok_count_with_options(P
, &c
, options
);
314 if (value_pos_p(c
) && value_cmp_si(c
, size
) <= 0) {
315 *next_less
= Polyhedron_Copy(P
);
316 next_less
= &(*next_less
)->next
;
318 *next_more
= Polyhedron_Copy(P
);
319 next_more
= &(*next_more
)->next
;
324 s_less
[n_less
].D
= D_less
;
325 s_less
[n_less
].E
= evalue_dup(&EP
->x
.p
->arr
[2*i
+1]);
328 s_more
[n_more
].D
= D_more
;
329 s_more
[n_more
].E
= evalue_dup(&EP
->x
.p
->arr
[2*i
+1]);
336 *EP_less
= evalue_from_section_array(s_less
, n_less
);
337 *EP_more
= evalue_from_section_array(s_more
, n_more
);
343 static piecewise_lst
*optimize(evalue
*EP
, unsigned nvar
, Polyhedron
*C
,
344 const exvector
& params
,
345 struct options
*options
)
347 piecewise_lst
*pl
= NULL
;
348 if (options
->iterate
> 0) {
349 evalue
*EP_less
= NULL
;
350 evalue
*EP_more
= NULL
;
351 piecewise_lst
*pl_more
= NULL
;
352 split_on_domain_size(EP
, &EP_less
, &EP_more
, options
->iterate
,
353 options
->verify
.barvinok
);
354 if (!EVALUE_IS_ZERO(*EP_less
)) {
355 options
->iterate
= -1;
356 pl
= optimize(EP_less
, nvar
, C
, params
, options
);
358 if (!EVALUE_IS_ZERO(*EP_more
)) {
359 options
->iterate
= 0;
360 pl_more
= optimize(EP_more
, nvar
, C
, params
, options
);
362 evalue_free(EP_less
);
363 evalue_free(EP_more
);
368 pl
->combine(*pl_more
);
372 if (options
->iterate
)
373 pl
= iterate(EP
, nvar
, C
, options
);
374 else if (options
->verify
.barvinok
->bound
== BV_BOUND_BERNSTEIN
) {
375 pl
= evalue_bernstein_coefficients(NULL
, EP
, C
, params
,
376 options
->verify
.barvinok
);
382 pl
= evalue_range_propagation(NULL
, EP
, params
,
383 options
->verify
.barvinok
);
387 static int optimize(evalue
*EP
, const char **all_vars
,
388 unsigned nvar
, unsigned nparam
, struct options
*options
)
391 piecewise_lst
*pl
= NULL
;
392 U
= Universe_Polyhedron(nparam
);
393 int print_solution
= 1;
397 params
= constructParameterVector(all_vars
+nvar
, nparam
);
399 if (options
->verify
.verify
) {
400 verify_options_set_range(&options
->verify
, nvar
+nparam
);
401 if (!options
->verify
.barvinok
->verbose
)
406 options
->verify
.barvinok
->bernstein_optimize
= BV_BERNSTEIN_MIN
;
408 options
->verify
.barvinok
->bernstein_optimize
= BV_BERNSTEIN_MAX
;
409 pl
= optimize(EP
, nvar
, U
, params
, options
);
413 if (options
->verify
.verify
) {
414 result
= verify(pl
, EP
, nvar
, params
, &options
->verify
);
423 int main(int argc
, char **argv
)
426 const char **all_vars
= NULL
;
429 struct options options
;
430 struct barvinok_options
*bv_options
= barvinok_options_new_with_defaults();
431 static struct argp_child argp_children
[] = {
432 { &convert_argp
, 0, "input conversion", 1 },
433 { &verify_argp
, 0, "verification", 2 },
434 { &barvinok_argp
, 0, "barvinok options", 3 },
437 static struct argp argp
= { argp_options
, parse_opt
, 0, 0, argp_children
};
440 options
.verify
.barvinok
= bv_options
;
441 set_program_name(argv
[0]);
442 argp_parse(&argp
, argc
, argv
, 0, 0, &options
);
444 EP
= evalue_read_from_file(stdin
, options
.var_list
, &all_vars
,
445 &nvar
, &nparam
, bv_options
->MaxRays
);
449 evalue_split_periods(EP
, options
.split
, bv_options
->MaxRays
);
451 evalue_convert(EP
, &options
.convert
, bv_options
->verbose
,
452 nvar
+nparam
, all_vars
);
454 if (EVALUE_IS_ZERO(*EP
))
455 print_evalue(stdout
, EP
, all_vars
);
457 result
= optimize(EP
, all_vars
, nvar
, nparam
, &options
);
461 if (options
.var_list
)
462 free(options
.var_list
);
463 Free_ParamNames(all_vars
, nvar
+nparam
);
464 barvinok_options_free(bv_options
);