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 static int check_poly_max(const struct check_poly_data
*data
,
86 const struct verify_options
*options
);
88 struct check_poly_max_data
: public check_EP_data
{
91 check_poly_max_data(evalue
*EP
, piecewise_lst
*pl
) : pl(pl
) {
93 this->cp
.check
= check_poly_max
;
97 static int check_poly_max(const struct check_poly_data
*data
,
99 const struct verify_options
*options
)
103 const check_poly_max_data
*max_data
;
104 max_data
= (const check_poly_max_data
*)data
;
112 if (options
->barvinok
->bernstein_optimize
== BV_BERNSTEIN_MAX
) {
120 max_data
->pl
->evaluate(nparam
, z
, &n
, &d
);
126 if (options
->print_all
) {
127 printf("%s(", minmax
);
128 value_print(stdout
, VALUE_FMT
, z
[0]);
129 for (k
= 1; k
< nparam
; ++k
) {
131 value_print(stdout
, VALUE_FMT
, z
[k
]);
134 value_print(stdout
, VALUE_FMT
, n
);
135 if (value_notone_p(d
)) {
137 value_print(stdout
, VALUE_FMT
, d
);
140 value_print(stdout
, VALUE_FMT
, m
);
144 evalue_optimum(max_data
, &n
, sign
);
151 if (options
->print_all
) {
152 printf(", %s(EP) = ", minmax
);
153 value_print(stdout
, VALUE_FMT
, n
);
160 fprintf(stderr
, "Error !\n");
161 fprintf(stderr
, "%s(", minmax
);
162 value_print(stderr
, VALUE_FMT
, z
[0]);
163 for (k
= 1; k
< nparam
; ++k
) {
164 fprintf(stderr
,", ");
165 value_print(stderr
, VALUE_FMT
, z
[k
]);
167 fprintf(stderr
, ") should be ");
169 fprintf(stderr
, "greater");
171 fprintf(stderr
, "smaller");
172 fprintf(stderr
, " than or equal to ");
173 value_print(stderr
, VALUE_FMT
, n
);
174 fprintf(stderr
, ", while pl eval gives ");
175 value_print(stderr
, VALUE_FMT
, m
);
176 fprintf(stderr
, ".\n");
177 cerr
<< *max_data
->pl
<< endl
;
178 } else if (options
->print_all
)
188 static int verify(piecewise_lst
*pl
, evalue
*EP
, unsigned nvar
, unsigned nparam
,
189 struct verify_options
*options
)
191 check_poly_max_data
data(EP
, pl
);
192 return !check_EP(&data
, nvar
, nparam
, options
);
195 static piecewise_lst
*iterate(evalue
*EP
, unsigned nvar
, Polyhedron
*C
,
196 struct options
*options
)
198 assert(C
->Dimension
== 0);
199 Vector
*p
= Vector_Alloc(nvar
+2);
200 value_set_si(p
->p
[nvar
+1], 1);
204 struct check_EP_data data
;
206 data
.cp
.check
= NULL
;
209 check_EP_set_scan(&data
, C
, options
->verify
.barvinok
->MaxRays
);
210 int sign
= options
->verify
.barvinok
->bernstein_optimize
;
211 evalue_optimum(&data
, &opt
, sign
);
212 check_EP_clear_scan(&data
);
215 piecewise_lst
*pl
= new piecewise_lst(params
, sign
);
216 pl
->add_guarded_lst(Polyhedron_Copy(C
), lst(value2numeric(opt
)));
225 * Split (partition) EP into a partition with (sub)domains containing
226 * size integer points or less and a partition with (sub)domains
227 * containing more integer points.
229 static void split_on_domain_size(evalue
*EP
, evalue
**EP_less
, evalue
**EP_more
,
230 int size
, barvinok_options
*options
)
232 assert(value_zero_p(EP
->d
));
233 assert(EP
->x
.p
->type
== partition
);
234 assert(EP
->x
.p
->size
>= 2);
236 struct evalue_section
*s_less
= new evalue_section
[EP
->x
.p
->size
/2];
237 struct evalue_section
*s_more
= new evalue_section
[EP
->x
.p
->size
/2];
245 for (int i
= 0; i
< EP
->x
.p
->size
/2; ++i
) {
246 Polyhedron
*D
= EVALUE_DOMAIN(EP
->x
.p
->arr
[2*i
]);
247 Polyhedron
*D_less
= NULL
;
248 Polyhedron
*D_more
= NULL
;
249 Polyhedron
**next_less
= &D_less
;
250 Polyhedron
**next_more
= &D_more
;
252 for (Polyhedron
*P
= D
; P
; P
= P
->next
) {
253 Polyhedron
*next
= P
->next
;
255 barvinok_count_with_options(P
, &c
, options
);
261 if (value_pos_p(c
) && value_cmp_si(c
, size
) <= 0) {
262 *next_less
= Polyhedron_Copy(P
);
263 next_less
= &(*next_less
)->next
;
265 *next_more
= Polyhedron_Copy(P
);
266 next_more
= &(*next_more
)->next
;
271 s_less
[n_less
].D
= D_less
;
272 s_less
[n_less
].E
= evalue_dup(&EP
->x
.p
->arr
[2*i
+1]);
275 s_more
[n_more
].D
= D_more
;
276 s_more
[n_more
].E
= evalue_dup(&EP
->x
.p
->arr
[2*i
+1]);
283 *EP_less
= evalue_from_section_array(s_less
, n_less
);
284 *EP_more
= evalue_from_section_array(s_more
, n_more
);
290 static piecewise_lst
*optimize(evalue
*EP
, unsigned nvar
, Polyhedron
*C
,
291 const exvector
& params
,
292 struct options
*options
)
294 piecewise_lst
*pl
= NULL
;
295 if (options
->iterate
> 0) {
296 evalue
*EP_less
= NULL
;
297 evalue
*EP_more
= NULL
;
298 piecewise_lst
*pl_more
= NULL
;
299 split_on_domain_size(EP
, &EP_less
, &EP_more
, options
->iterate
,
300 options
->verify
.barvinok
);
301 if (!EVALUE_IS_ZERO(*EP_less
)) {
302 options
->iterate
= -1;
303 pl
= optimize(EP_less
, nvar
, C
, params
, options
);
305 if (!EVALUE_IS_ZERO(*EP_more
)) {
306 options
->iterate
= 0;
307 pl_more
= optimize(EP_more
, nvar
, C
, params
, options
);
309 evalue_free(EP_less
);
310 evalue_free(EP_more
);
315 pl
->combine(*pl_more
);
319 if (options
->iterate
)
320 pl
= iterate(EP
, nvar
, C
, options
);
321 else if (options
->verify
.barvinok
->bound
== BV_BOUND_BERNSTEIN
) {
322 pl
= evalue_bernstein_coefficients(NULL
, EP
, C
, params
,
323 options
->verify
.barvinok
);
329 pl
= evalue_range_propagation(NULL
, EP
, params
,
330 options
->verify
.barvinok
);
334 static int optimize(evalue
*EP
, const char **all_vars
,
335 unsigned nvar
, unsigned nparam
, struct options
*options
)
338 piecewise_lst
*pl
= NULL
;
339 U
= Universe_Polyhedron(nparam
);
340 int print_solution
= 1;
344 params
= constructParameterVector(all_vars
+nvar
, nparam
);
346 if (options
->verify
.verify
) {
347 verify_options_set_range(&options
->verify
, nvar
+nparam
);
348 if (!options
->verify
.barvinok
->verbose
)
353 options
->verify
.barvinok
->bernstein_optimize
= BV_BERNSTEIN_MIN
;
355 options
->verify
.barvinok
->bernstein_optimize
= BV_BERNSTEIN_MAX
;
356 pl
= optimize(EP
, nvar
, U
, params
, options
);
360 if (options
->verify
.verify
) {
361 result
= verify(pl
, EP
, nvar
, nparam
, &options
->verify
);
370 int main(int argc
, char **argv
)
373 const char **all_vars
= NULL
;
376 struct options options
;
377 struct barvinok_options
*bv_options
= barvinok_options_new_with_defaults();
378 static struct argp_child argp_children
[] = {
379 { &convert_argp
, 0, "input conversion", 1 },
380 { &verify_argp
, 0, "verification", 2 },
381 { &barvinok_argp
, 0, "barvinok options", 3 },
384 static struct argp argp
= { argp_options
, parse_opt
, 0, 0, argp_children
};
387 options
.verify
.barvinok
= bv_options
;
388 set_program_name(argv
[0]);
389 argp_parse(&argp
, argc
, argv
, 0, 0, &options
);
391 EP
= evalue_read_from_file(stdin
, options
.var_list
, &all_vars
,
392 &nvar
, &nparam
, bv_options
->MaxRays
);
396 evalue_split_periods(EP
, options
.split
, bv_options
->MaxRays
);
398 evalue_convert(EP
, &options
.convert
, bv_options
->verbose
,
399 nvar
+nparam
, all_vars
);
401 if (EVALUE_IS_ZERO(*EP
))
402 print_evalue(stdout
, EP
, all_vars
);
404 result
= optimize(EP
, all_vars
, nvar
, nparam
, &options
);
408 if (options
.var_list
)
409 free(options
.var_list
);
410 Free_ParamNames(all_vars
, nvar
+nparam
);
411 barvinok_options_free(bv_options
);