2 #include <bernstein/bernstein.h>
3 #include <barvinok/evalue.h>
4 #include <barvinok/options.h>
5 #include <barvinok/util.h>
6 #include <barvinok/bernstein.h>
8 #include "evalue_convert.h"
13 using namespace GiNaC
;
14 using namespace bernstein
;
15 using namespace barvinok
;
17 #define OPT_VARS (BV_OPT_LAST+1)
18 #define OPT_SPLIT (BV_OPT_LAST+2)
19 #define OPT_MIN (BV_OPT_LAST+3)
21 struct argp_option argp_options
[] = {
22 { "split", OPT_SPLIT
, "int" },
23 { "variables", OPT_VARS
, "list", 0,
24 "comma separated list of variables over which to maximize" },
25 { "verbose", 'V', 0, 0, },
26 { "minimize", OPT_MIN
, 0, 0, "minimize instead of maximize"},
31 struct convert_options convert
;
38 static error_t
parse_opt(int key
, char *arg
, struct argp_state
*state
)
40 struct options
*options
= (struct options
*) state
->input
;
44 state
->child_inputs
[0] = &options
->convert
;
45 options
->var_list
= NULL
;
48 options
->minimize
= 0;
54 options
->var_list
= strdup(arg
);
57 options
->split
= atoi(arg
);
60 options
->minimize
= 1;
63 return ARGP_ERR_UNKNOWN
;
69 #define ALLOC(type) (type*)malloc(sizeof(type))
70 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
72 enum token_type
{ TOKEN_UNKNOWN
= 256, TOKEN_VALUE
, TOKEN_IDENT
, TOKEN_GE
,
87 static struct token
*token_new(int line
, int col
)
89 struct token
*tok
= ALLOC(struct token
);
95 void token_free(struct token
*tok
)
97 if (tok
->type
== TOKEN_VALUE
)
98 value_clear(tok
->u
.v
);
99 else if (tok
->type
== TOKEN_IDENT
)
115 struct token
*tokens
[5];
119 static struct stream
* stream_new(FILE *file
)
122 struct stream
*s
= ALLOC(struct stream
);
125 s
->buffer
= (char*)malloc(s
->size
);
131 for (i
= 0; i
< 5; ++i
)
137 static void stream_free(struct stream
*s
)
140 assert(s
->n_token
== 0);
144 static int stream_getc(struct stream
*s
)
163 static void stream_ungetc(struct stream
*s
, int c
)
169 static void stream_push_char(struct stream
*s
, int c
)
171 if (s
->len
>= s
->size
) {
172 s
->size
= (3*s
->size
)/2;
173 s
->buffer
= (char*)realloc(s
->buffer
, s
->size
);
175 s
->buffer
[s
->len
++] = c
;
178 static struct token
*stream_push_token(struct stream
*s
, struct token
*tok
)
180 assert(s
->n_token
< 5);
181 s
->tokens
[s
->n_token
++] = tok
;
184 static struct token
*stream_next_token(struct stream
*s
)
191 return s
->tokens
[--s
->n_token
];
196 while ((c
= stream_getc(s
)) != -1 && isspace(c
))
218 tok
= token_new(line
, col
);
219 tok
->type
= (token_type
)c
;
222 if (c
== '-' || isdigit(c
)) {
223 tok
= token_new(line
, col
);
224 tok
->type
= TOKEN_VALUE
;
225 value_init(tok
->u
.v
);
226 stream_push_char(s
, c
);
227 while ((c
= stream_getc(s
)) != -1 && isdigit(c
))
228 stream_push_char(s
, c
);
231 if (s
->len
== 1 && s
->buffer
[0] == '-')
232 value_set_si(tok
->u
.v
, -1);
234 stream_push_char(s
, '\0');
235 mpz_set_str(tok
->u
.v
, s
->buffer
, 0);
240 tok
= token_new(line
, col
);
241 stream_push_char(s
, c
);
242 while ((c
= stream_getc(s
)) != -1 && isalpha(c
))
243 stream_push_char(s
, c
);
246 stream_push_char(s
, '\0');
247 if (!strcmp(s
->buffer
, "UNION")) {
248 tok
->type
= TOKEN_UNION
;
250 tok
->type
= TOKEN_IDENT
;
251 tok
->u
.s
= strdup(s
->buffer
);
256 if ((c
= stream_getc(s
)) == '=') {
257 tok
= token_new(line
, col
);
258 tok
->type
= TOKEN_GE
;
265 tok
= token_new(line
, col
);
266 tok
->type
= TOKEN_UNKNOWN
;
270 void stream_error(struct stream
*s
, struct token
*tok
, char *msg
)
272 int line
= tok
? tok
->line
: s
->line
;
273 int col
= tok
? tok
->col
: s
->col
;
274 fprintf(stderr
, "syntax error (%d, %d): %s\n", line
, col
, msg
);
277 fprintf(stderr
, "got '%c'\n", tok
->type
);
284 struct parameter
*next
;
287 struct parameter
*parameter_new(char *name
, int pos
, struct parameter
*next
)
289 struct parameter
*p
= ALLOC(struct parameter
);
290 p
->name
= strdup(name
);
296 static int parameter_pos(struct parameter
**p
, char *s
)
298 int pos
= *p
? (*p
)->pos
+1 : 0;
301 for (q
= *p
; q
; q
= q
->next
) {
302 if (strcmp(q
->name
, s
) == 0)
308 *p
= parameter_new(s
, pos
, *p
);
312 static int optional_power(struct stream
*s
)
316 tok
= stream_next_token(s
);
319 if (tok
->type
!= '^') {
320 stream_push_token(s
, tok
);
324 tok
= stream_next_token(s
);
325 if (!tok
|| tok
->type
!= TOKEN_VALUE
) {
326 stream_error(s
, tok
, "expecting exponent");
328 stream_push_token(s
, tok
);
331 pow
= VALUE_TO_INT(tok
->u
.v
);
336 static evalue
*evalue_read_factor(struct stream
*s
, struct parameter
**p
);
337 static evalue
*evalue_read_term(struct stream
*s
, struct parameter
**p
);
339 static evalue
*create_fract_like(struct stream
*s
, evalue
*arg
, enode_type type
,
340 struct parameter
**p
)
344 pow
= optional_power(s
);
348 e
->x
.p
= new_enode(type
, pow
+2, -1);
349 value_clear(e
->x
.p
->arr
[0].d
);
350 e
->x
.p
->arr
[0] = *arg
;
352 evalue_set_si(&e
->x
.p
->arr
[1+pow
], 1, 1);
354 evalue_set_si(&e
->x
.p
->arr
[1+pow
], 0, 1);
359 static evalue
*read_fract(struct stream
*s
, struct token
*tok
, struct parameter
**p
)
363 tok
= stream_next_token(s
);
365 assert(tok
->type
== '{');
368 arg
= evalue_read_term(s
, p
);
369 tok
= stream_next_token(s
);
370 if (!tok
|| tok
->type
!= '}') {
371 stream_error(s
, tok
, "expecting \"}\"");
373 stream_push_token(s
, tok
);
377 return create_fract_like(s
, arg
, fractional
, p
);
380 static evalue
*read_periodic(struct stream
*s
, struct parameter
**p
)
388 tok
= stream_next_token(s
);
389 assert(tok
&& tok
->type
== '[');
393 list
= (evalue
**)malloc(len
* sizeof(evalue
*));
397 evalue
*e
= evalue_read_term(s
, p
);
399 stream_error(s
, NULL
, "missing argument or list element");
404 list
= (evalue
**)realloc(list
, len
* sizeof(evalue
*));
408 tok
= stream_next_token(s
);
410 stream_error(s
, NULL
, "unexpected EOF");
413 if (tok
->type
!= ',')
418 if (tok
->type
!= ']') {
419 stream_error(s
, tok
, "expecting \"]\"");
420 stream_push_token(s
, tok
);
426 tok
= stream_next_token(s
);
427 if (tok
->type
== '_') {
430 tok
= stream_next_token(s
);
431 if (!tok
|| tok
->type
!= TOKEN_IDENT
) {
432 stream_error(s
, tok
, "expecting identifier");
434 stream_push_token(s
, tok
);
439 pos
= parameter_pos(p
, tok
->u
.s
);
441 e
->x
.p
= new_enode(periodic
, n
, pos
+1);
443 value_clear(e
->x
.p
->arr
[n
].d
);
444 e
->x
.p
->arr
[n
] = *list
[n
];
448 stream_push_token(s
, tok
);
449 e
= create_fract_like(s
, list
[0], flooring
, p
);
452 stream_error(s
, tok
, "unexpected token");
453 stream_push_token(s
, tok
);
458 free_evalue_refs(list
[n
]);
465 static evalue
*evalue_read_factor(struct stream
*s
, struct parameter
**p
)
470 tok
= stream_next_token(s
);
474 if (tok
->type
== '(') {
476 e
= evalue_read_term(s
, p
);
477 tok
= stream_next_token(s
);
478 if (!tok
|| tok
->type
!= ')') {
479 stream_error(s
, tok
, "expecting \")\"");
481 stream_push_token(s
, tok
);
484 } else if (tok
->type
== TOKEN_VALUE
) {
487 value_set_si(e
->d
, 1);
489 value_assign(e
->x
.n
, tok
->u
.v
);
491 tok
= stream_next_token(s
);
492 if (tok
&& tok
->type
== '/') {
494 tok
= stream_next_token(s
);
495 if (!tok
|| tok
->type
!= TOKEN_VALUE
) {
496 stream_error(s
, tok
, "expecting denominator");
498 stream_push_token(s
, tok
);
501 value_assign(e
->d
, tok
->u
.v
);
504 stream_push_token(s
, tok
);
505 } else if (tok
->type
== TOKEN_IDENT
) {
506 int pos
= parameter_pos(p
, tok
->u
.s
);
507 int pow
= optional_power(s
);
511 e
->x
.p
= new_enode(polynomial
, pow
+1, pos
+1);
512 evalue_set_si(&e
->x
.p
->arr
[pow
], 1, 1);
514 evalue_set_si(&e
->x
.p
->arr
[pow
], 0, 1);
515 } else if (tok
->type
== '[') {
516 stream_push_token(s
, tok
);
517 e
= read_periodic(s
, p
);
518 } else if (tok
->type
== '{') {
519 stream_push_token(s
, tok
);
520 e
= read_fract(s
, tok
, p
);
523 tok
= stream_next_token(s
);
524 if (tok
&& tok
->type
== '*') {
527 e2
= evalue_read_factor(s
, p
);
529 stream_error(s
, NULL
, "unexpected EOF");
533 free_evalue_refs(e2
);
536 stream_push_token(s
, tok
);
541 static evalue
*evalue_read_term(struct stream
*s
, struct parameter
**p
)
546 e
= evalue_read_factor(s
, p
);
550 tok
= stream_next_token(s
);
554 if (tok
->type
== '+') {
557 e2
= evalue_read_term(s
, p
);
559 stream_error(s
, NULL
, "unexpected EOF");
563 free_evalue_refs(e2
);
566 stream_push_token(s
, tok
);
574 struct constraint
*next
;
575 struct constraint
*union_next
;
578 static struct constraint
*constraint_new()
580 struct constraint
*c
= ALLOC(struct constraint
);
582 c
->v
= Vector_Alloc(16);
584 c
->union_next
= NULL
;
588 static void constraint_free(struct constraint
*c
)
591 struct constraint
*next
= c
->next
? c
->next
: c
->union_next
;
598 static void constraint_extend(struct constraint
*c
, int pos
)
601 if (pos
< c
->v
->Size
)
604 v
= Vector_Alloc((3*c
->v
->Size
)/2);
605 Vector_Copy(c
->v
->p
, v
->p
, c
->v
->Size
);
610 static int evalue_read_constraint(struct stream
*s
, struct parameter
**p
,
611 struct constraint
**constraints
,
612 struct constraint
*union_next
)
615 struct constraint
*c
= NULL
;
617 while ((tok
= stream_next_token(s
))) {
620 if (tok
->type
== '+')
622 else if (tok
->type
== TOKEN_IDENT
) {
624 c
= constraint_new();
625 pos
= parameter_pos(p
, tok
->u
.s
);
626 constraint_extend(c
, 1+pos
);
627 value_set_si(c
->v
->p
[1+pos
], 1);
629 } else if (tok
->type
== TOKEN_VALUE
) {
631 c
= constraint_new();
632 tok2
= stream_next_token(s
);
633 if (tok2
&& tok2
->type
== TOKEN_IDENT
) {
634 pos
= parameter_pos(p
, tok2
->u
.s
);
635 constraint_extend(c
, 1+pos
);
636 value_assign(c
->v
->p
[1+pos
], tok
->u
.v
);
641 stream_push_token(s
, tok2
);
642 value_assign(c
->v
->p
[0], tok
->u
.v
);
645 } else if (tok
->type
== TOKEN_GE
|| tok
->type
== '=') {
646 int type
= tok
->type
== TOKEN_GE
;
648 tok
= stream_next_token(s
);
649 if (!tok
|| tok
->type
!= TOKEN_VALUE
|| value_notzero_p(tok
->u
.v
)) {
650 stream_error(s
, tok
, "expecting \"0\"");
652 stream_push_token(s
, tok
);
656 c
->next
= *constraints
;
657 c
->union_next
= union_next
;
664 stream_push_token(s
, tok
);
666 stream_error(s
, tok
, "unexpected token");
675 static struct constraint
*evalue_read_domain(struct stream
*s
, struct parameter
**p
,
678 struct constraint
*constraints
= NULL
;
679 struct constraint
*union_next
= NULL
;
683 tok
= stream_next_token(s
);
686 stream_push_token(s
, tok
);
689 while (evalue_read_constraint(s
, p
, &constraints
, union_next
)) {
690 tok
= stream_next_token(s
);
692 if (tok
->type
== TOKEN_UNION
) {
694 tok
= stream_next_token(s
);
696 stream_error(s
, NULL
, "unexpected EOF");
699 stream_push_token(s
, tok
);
700 union_next
= constraints
;
704 stream_push_token(s
, tok
);
705 /* empty line separates domain from evalue */
706 if (tok
->line
> line
+1)
716 struct constraint
*constraints
;
718 struct section
*next
;
721 static char **extract_parameters(struct parameter
*p
, unsigned *nparam
)
726 *nparam
= p
? p
->pos
+1 : 0;
727 params
= ALLOCN(char *, *nparam
);
728 for (i
= 0; i
< *nparam
; ++i
) {
729 struct parameter
*next
= p
->next
;
730 params
[p
->pos
] = p
->name
;
737 static Polyhedron
*constraints2domain(struct constraint
*constraints
,
738 unsigned nparam
, unsigned MaxRays
)
743 struct constraint
*c
;
744 struct constraint
*union_next
= NULL
;
746 for (n
= 0, c
= constraints
; c
; ++n
, c
= c
->next
)
748 M
= Matrix_Alloc(n
, 1+nparam
+1);
750 struct constraint
*next
= constraints
->next
;
751 union_next
= constraints
->union_next
;
752 Vector_Copy(constraints
->v
->p
+1, M
->p
[n
]+1, nparam
);
753 if (constraints
->type
)
754 value_set_si(M
->p
[n
][0], 1);
755 value_assign(M
->p
[n
][1+nparam
], constraints
->v
->p
[0]);
756 constraints
->next
= NULL
;
757 constraints
->union_next
= NULL
;
758 constraint_free(constraints
);
761 D
= Constraints2Polyhedron(M
, MaxRays
);
765 D
= DomainConcat(D
, constraints2domain(union_next
, nparam
, MaxRays
));
769 static evalue
*evalue_read_partition(struct stream
*s
, struct parameter
*p
,
771 unsigned *nparam
, unsigned MaxRays
)
773 struct section
*part
= NULL
;
774 struct constraint
*constraints
;
778 while ((constraints
= evalue_read_domain(s
, &p
, MaxRays
))) {
779 evalue
*e
= evalue_read_term(s
, &p
);
781 stream_error(s
, NULL
, "missing evalue");
784 struct section
*sect
= ALLOC(struct section
);
785 sect
->constraints
= constraints
;
796 *ppp
= extract_parameters(p
, nparam
);
799 e
->x
.p
= new_enode(partition
, 2*m
, *nparam
);
801 for (j
= 0; j
< m
; ++j
) {
803 struct section
*next
= part
->next
;
804 constraints
= part
->constraints
;
805 D
= constraints2domain(part
->constraints
, *nparam
, MaxRays
);
806 EVALUE_SET_DOMAIN(e
->x
.p
->arr
[2*j
], D
);
807 value_clear(e
->x
.p
->arr
[2*j
+1].d
);
808 e
->x
.p
->arr
[2*j
+1] = *part
->e
;
817 static evalue
*evalue_read(FILE *in
, char *var_list
, char ***ppp
, unsigned *nvar
,
818 unsigned *nparam
, unsigned MaxRays
)
820 struct stream
*s
= stream_new(in
);
823 struct parameter
*p
= NULL
;
828 while ((next
= strchr(var_list
, ','))) {
831 parameter_pos(&p
, var_list
);
835 if (strlen(var_list
) > 0)
836 parameter_pos(&p
, var_list
);
837 nv
= p
? p
->pos
+1 : 0;
841 if (!(tok
= stream_next_token(s
)))
844 if (tok
->type
== TOKEN_VALUE
) {
845 struct token
*tok2
= stream_next_token(s
);
847 stream_push_token(s
, tok2
);
848 stream_push_token(s
, tok
);
849 if (tok2
&& (tok2
->type
== TOKEN_IDENT
|| tok2
->type
== TOKEN_GE
))
850 e
= evalue_read_partition(s
, p
, ppp
, nparam
, MaxRays
);
852 e
= evalue_read_term(s
, &p
);
853 *ppp
= extract_parameters(p
, nparam
);
855 } else if (tok
->type
== TOKEN_IDENT
) {
856 stream_push_token(s
, tok
);
857 e
= evalue_read_partition(s
, p
, ppp
, nparam
, MaxRays
);
868 static void optimize(evalue
*EP
, char **all_vars
, unsigned nvar
, unsigned nparam
,
869 struct options
*options
, barvinok_options
*bv_options
)
872 piecewise_lst
*pl
= NULL
;
873 U
= Universe_Polyhedron(nparam
);
876 params
= constructParameterVector(all_vars
+nvar
, nparam
);
878 if (options
->minimize
)
879 bv_options
->bernstein_optimize
= BV_BERNSTEIN_MIN
;
881 bv_options
->bernstein_optimize
= BV_BERNSTEIN_MAX
;
882 pl
= evalue_bernstein_coefficients(NULL
, EP
, U
, params
, bv_options
);
884 if (options
->minimize
)
894 int main(int argc
, char **argv
)
897 char **all_vars
= NULL
;
900 struct options options
;
901 struct barvinok_options
*bv_options
= barvinok_options_new_with_defaults();
902 static struct argp_child argp_children
[] = {
903 { &convert_argp
, 0, "input conversion", 1 },
906 static struct argp argp
= { argp_options
, parse_opt
, 0, 0, argp_children
};
908 argp_parse(&argp
, argc
, argv
, 0, 0, &options
);
910 EP
= evalue_read(stdin
, options
.var_list
, &all_vars
, &nvar
, &nparam
,
911 bv_options
->MaxRays
);
915 evalue_split_periods(EP
, options
.split
, bv_options
->MaxRays
);
917 evalue_convert(EP
, &options
.convert
, nparam
, options
.verbose
? all_vars
: NULL
);
919 if (EVALUE_IS_ZERO(*EP
))
920 print_evalue(stdout
, EP
, all_vars
);
922 optimize(EP
, all_vars
, nvar
, nparam
, &options
, bv_options
);
924 free_evalue_refs(EP
);
927 if (options
.var_list
)
928 free(options
.var_list
);
929 Free_ParamNames(all_vars
, nvar
+nparam
);
930 barvinok_options_free(bv_options
);