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_METHOD (BV_OPT_LAST+4)
29 #define OPT_ITERATE (BV_OPT_LAST+5)
31 struct argp_option argp_options
[] = {
32 { "split", OPT_SPLIT
, "int" },
33 { "variables", OPT_VARS
, "list", 0,
34 "comma separated list of variables over which to compute a bound" },
35 { "lower", OPT_LOWER
, 0, 0, "compute lower bound instead of upper bound"},
36 { "optimization-method", OPT_METHOD
, "bernstein|propagation",
37 0, "optimization method to use" },
38 { "iterate", OPT_ITERATE
, "int", 1,
39 "exact result by iterating over domain (of specified maximal size)"},
44 struct convert_options convert
;
45 struct verify_options verify
;
49 #define METHOD_BERNSTEIN 0
50 #define METHOD_PROPAGATION 1
55 static error_t
parse_opt(int key
, char *arg
, struct argp_state
*state
)
57 struct options
*options
= (struct options
*) state
->input
;
61 state
->child_inputs
[0] = &options
->convert
;
62 state
->child_inputs
[1] = &options
->verify
;
63 state
->child_inputs
[2] = options
->verify
.barvinok
;
64 options
->var_list
= NULL
;
67 options
->method
= METHOD_BERNSTEIN
;
71 options
->var_list
= strdup(arg
);
74 options
->split
= atoi(arg
);
80 if (!strcmp(arg
, "bernstein"))
81 options
->method
= METHOD_BERNSTEIN
;
82 else if (!strcmp(arg
, "propagation"))
83 options
->method
= METHOD_PROPAGATION
;
85 argp_error(state
, "unknown value for --optimization-method option");
89 options
->iterate
= -1;
91 options
->iterate
= atoi(arg
);
94 return ARGP_ERR_UNKNOWN
;
99 static int check_poly_max(const struct check_poly_data
*data
,
100 int nparam
, Value
*z
,
101 const struct verify_options
*options
);
103 struct check_poly_max_data
: public check_EP_data
{
106 check_poly_max_data(evalue
*EP
, piecewise_lst
*pl
) : pl(pl
) {
108 this->cp
.check
= check_poly_max
;
112 static int check_poly_max(const struct check_poly_data
*data
,
113 int nparam
, Value
*z
,
114 const struct verify_options
*options
)
118 const check_poly_max_data
*max_data
;
119 max_data
= (const check_poly_max_data
*)data
;
127 if (options
->barvinok
->bernstein_optimize
== BV_BERNSTEIN_MAX
) {
135 max_data
->pl
->evaluate(nparam
, z
, &n
, &d
);
141 if (options
->print_all
) {
142 printf("%s(", minmax
);
143 value_print(stdout
, VALUE_FMT
, z
[0]);
144 for (k
= 1; k
< nparam
; ++k
) {
146 value_print(stdout
, VALUE_FMT
, z
[k
]);
149 value_print(stdout
, VALUE_FMT
, n
);
150 if (value_notone_p(d
)) {
152 value_print(stdout
, VALUE_FMT
, d
);
155 value_print(stdout
, VALUE_FMT
, m
);
159 evalue_optimum(max_data
, &n
, sign
);
166 if (options
->print_all
) {
167 printf(", %s(EP) = ", minmax
);
168 value_print(stdout
, VALUE_FMT
, n
);
175 fprintf(stderr
, "Error !\n");
176 fprintf(stderr
, "%s(", minmax
);
177 value_print(stderr
, VALUE_FMT
, z
[0]);
178 for (k
= 1; k
< nparam
; ++k
) {
179 fprintf(stderr
,", ");
180 value_print(stderr
, VALUE_FMT
, z
[k
]);
182 fprintf(stderr
, ") should be ");
184 fprintf(stderr
, "greater");
186 fprintf(stderr
, "smaller");
187 fprintf(stderr
, " than or equal to ");
188 value_print(stderr
, VALUE_FMT
, n
);
189 fprintf(stderr
, ", while pl eval gives ");
190 value_print(stderr
, VALUE_FMT
, m
);
191 fprintf(stderr
, ".\n");
192 cerr
<< *max_data
->pl
<< endl
;
193 } else if (options
->print_all
)
203 static int verify(piecewise_lst
*pl
, evalue
*EP
, unsigned nvar
, unsigned nparam
,
204 struct verify_options
*options
)
206 check_poly_max_data
data(EP
, pl
);
207 return !check_EP(&data
, nvar
, nparam
, options
);
210 static piecewise_lst
*iterate(evalue
*EP
, unsigned nvar
, Polyhedron
*C
,
211 struct options
*options
)
213 assert(C
->Dimension
== 0);
214 Vector
*p
= Vector_Alloc(nvar
+2);
215 value_set_si(p
->p
[nvar
+1], 1);
219 struct check_EP_data data
;
221 data
.cp
.check
= NULL
;
224 check_EP_set_scan(&data
, C
, options
->verify
.barvinok
->MaxRays
);
225 int sign
= options
->verify
.barvinok
->bernstein_optimize
;
226 evalue_optimum(&data
, &opt
, sign
);
227 check_EP_clear_scan(&data
);
230 piecewise_lst
*pl
= new piecewise_lst(params
, sign
);
231 pl
->add_guarded_lst(Polyhedron_Copy(C
), lst(value2numeric(opt
)));
240 * Split (partition) EP into a partition with (sub)domains containing
241 * size integer points or less and a partition with (sub)domains
242 * containing more integer points.
244 static void split_on_domain_size(evalue
*EP
, evalue
**EP_less
, evalue
**EP_more
,
245 int size
, barvinok_options
*options
)
247 assert(value_zero_p(EP
->d
));
248 assert(EP
->x
.p
->type
== partition
);
249 assert(EP
->x
.p
->size
>= 2);
251 struct evalue_section
*s_less
= new evalue_section
[EP
->x
.p
->size
/2];
252 struct evalue_section
*s_more
= new evalue_section
[EP
->x
.p
->size
/2];
260 for (int i
= 0; i
< EP
->x
.p
->size
/2; ++i
) {
261 Polyhedron
*D
= EVALUE_DOMAIN(EP
->x
.p
->arr
[2*i
]);
262 Polyhedron
*D_less
= NULL
;
263 Polyhedron
*D_more
= NULL
;
264 Polyhedron
**next_less
= &D_less
;
265 Polyhedron
**next_more
= &D_more
;
267 for (Polyhedron
*P
= D
; P
; P
= P
->next
) {
268 Polyhedron
*next
= P
->next
;
270 barvinok_count_with_options(P
, &c
, options
);
276 if (value_pos_p(c
) && value_cmp_si(c
, size
) <= 0) {
277 *next_less
= Polyhedron_Copy(P
);
278 next_less
= &(*next_less
)->next
;
280 *next_more
= Polyhedron_Copy(P
);
281 next_more
= &(*next_more
)->next
;
286 s_less
[n_less
].D
= D_less
;
287 s_less
[n_less
].E
= evalue_dup(&EP
->x
.p
->arr
[2*i
+1]);
290 s_more
[n_more
].D
= D_more
;
291 s_more
[n_more
].E
= evalue_dup(&EP
->x
.p
->arr
[2*i
+1]);
298 *EP_less
= evalue_from_section_array(s_less
, n_less
);
299 *EP_more
= evalue_from_section_array(s_more
, n_more
);
305 static piecewise_lst
*optimize(evalue
*EP
, unsigned nvar
, Polyhedron
*C
,
306 const exvector
& params
,
307 struct options
*options
)
309 piecewise_lst
*pl
= NULL
;
310 if (options
->iterate
> 0) {
311 evalue
*EP_less
= NULL
;
312 evalue
*EP_more
= NULL
;
313 piecewise_lst
*pl_more
= NULL
;
314 split_on_domain_size(EP
, &EP_less
, &EP_more
, options
->iterate
,
315 options
->verify
.barvinok
);
316 if (!EVALUE_IS_ZERO(*EP_less
)) {
317 options
->iterate
= -1;
318 pl
= optimize(EP_less
, nvar
, C
, params
, options
);
320 if (!EVALUE_IS_ZERO(*EP_more
)) {
321 options
->iterate
= 0;
322 pl_more
= optimize(EP_more
, nvar
, C
, params
, options
);
324 evalue_free(EP_less
);
325 evalue_free(EP_more
);
330 pl
->combine(*pl_more
);
334 if (options
->iterate
)
335 pl
= iterate(EP
, nvar
, C
, options
);
336 else if (options
->method
== METHOD_BERNSTEIN
) {
337 pl
= evalue_bernstein_coefficients(NULL
, EP
, C
, params
,
338 options
->verify
.barvinok
);
344 pl
= evalue_range_propagation(NULL
, EP
, params
,
345 options
->verify
.barvinok
);
349 static int optimize(evalue
*EP
, char **all_vars
, unsigned nvar
, unsigned nparam
,
350 struct options
*options
)
353 piecewise_lst
*pl
= NULL
;
354 U
= Universe_Polyhedron(nparam
);
355 int print_solution
= 1;
359 params
= constructParameterVector(all_vars
+nvar
, nparam
);
361 if (options
->verify
.verify
) {
362 verify_options_set_range(&options
->verify
, nvar
+nparam
);
363 if (!options
->verify
.barvinok
->verbose
)
368 options
->verify
.barvinok
->bernstein_optimize
= BV_BERNSTEIN_MIN
;
370 options
->verify
.barvinok
->bernstein_optimize
= BV_BERNSTEIN_MAX
;
371 pl
= optimize(EP
, nvar
, U
, params
, options
);
375 if (options
->verify
.verify
) {
376 result
= verify(pl
, EP
, nvar
, nparam
, &options
->verify
);
385 int main(int argc
, char **argv
)
388 char **all_vars
= NULL
;
391 struct options options
;
392 struct barvinok_options
*bv_options
= barvinok_options_new_with_defaults();
393 static struct argp_child argp_children
[] = {
394 { &convert_argp
, 0, "input conversion", 1 },
395 { &verify_argp
, 0, "verification", 2 },
396 { &barvinok_argp
, 0, "barvinok options", 3 },
399 static struct argp argp
= { argp_options
, parse_opt
, 0, 0, argp_children
};
402 options
.verify
.barvinok
= bv_options
;
403 set_program_name(argv
[0]);
404 argp_parse(&argp
, argc
, argv
, 0, 0, &options
);
406 EP
= evalue_read_from_file(stdin
, options
.var_list
, &all_vars
,
407 &nvar
, &nparam
, bv_options
->MaxRays
);
411 evalue_split_periods(EP
, options
.split
, bv_options
->MaxRays
);
413 evalue_convert(EP
, &options
.convert
, bv_options
->verbose
,
414 nvar
+nparam
, all_vars
);
416 if (EVALUE_IS_ZERO(*EP
))
417 print_evalue(stdout
, EP
, all_vars
);
419 result
= optimize(EP
, all_vars
, nvar
, nparam
, &options
);
423 if (options
.var_list
)
424 free(options
.var_list
);
425 Free_ParamNames(all_vars
, nvar
+nparam
);
426 barvinok_options_free(bv_options
);