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)
20 #define OPT_RECURSE (BV_OPT_LAST+4)
22 struct argp_option argp_options
[] = {
23 { "split", OPT_SPLIT
, "int" },
24 { "variables", OPT_VARS
, "list", 0,
25 "comma separated list of variables over which to maximize" },
26 { "verbose", 'V', 0, 0, },
27 { "minimize", OPT_MIN
, 0, 0, "minimize instead of maximize"},
28 { "recurse", OPT_RECURSE
, "none|factors|intervals|full", 0,
29 "[default: factors]" },
34 struct convert_options convert
;
42 static error_t
parse_opt(int key
, char *arg
, struct argp_state
*state
)
44 struct options
*options
= (struct options
*) state
->input
;
48 state
->child_inputs
[0] = &options
->convert
;
49 options
->var_list
= NULL
;
52 options
->minimize
= 0;
53 options
->recurse
= BV_BERNSTEIN_FACTORS
;
59 options
->var_list
= strdup(arg
);
62 options
->split
= atoi(arg
);
65 options
->minimize
= 1;
68 if (!strcmp(arg
, "none"))
70 else if (!strcmp(arg
, "factors"))
71 options
->recurse
= BV_BERNSTEIN_FACTORS
;
72 else if (!strcmp(arg
, "intervals"))
73 options
->recurse
= BV_BERNSTEIN_INTERVALS
;
74 else if (!strcmp(arg
, "full"))
75 options
->recurse
= BV_BERNSTEIN_FACTORS
| BV_BERNSTEIN_INTERVALS
;
78 return ARGP_ERR_UNKNOWN
;
84 #define ALLOC(type) (type*)malloc(sizeof(type))
85 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
87 enum token_type
{ TOKEN_UNKNOWN
= 256, TOKEN_VALUE
, TOKEN_IDENT
, TOKEN_GE
,
102 static struct token
*token_new(int line
, int col
)
104 struct token
*tok
= ALLOC(struct token
);
110 void token_free(struct token
*tok
)
112 if (tok
->type
== TOKEN_VALUE
)
113 value_clear(tok
->u
.v
);
114 else if (tok
->type
== TOKEN_IDENT
)
130 struct token
*tokens
[5];
134 static struct stream
* stream_new(FILE *file
)
137 struct stream
*s
= ALLOC(struct stream
);
140 s
->buffer
= (char*)malloc(s
->size
);
146 for (i
= 0; i
< 5; ++i
)
152 static void stream_free(struct stream
*s
)
155 assert(s
->n_token
== 0);
159 static int stream_getc(struct stream
*s
)
178 static void stream_ungetc(struct stream
*s
, int c
)
184 static void stream_push_char(struct stream
*s
, int c
)
186 if (s
->len
>= s
->size
) {
187 s
->size
= (3*s
->size
)/2;
188 s
->buffer
= (char*)realloc(s
->buffer
, s
->size
);
190 s
->buffer
[s
->len
++] = c
;
193 static struct token
*stream_push_token(struct stream
*s
, struct token
*tok
)
195 assert(s
->n_token
< 5);
196 s
->tokens
[s
->n_token
++] = tok
;
199 static struct token
*stream_next_token(struct stream
*s
)
206 return s
->tokens
[--s
->n_token
];
211 while ((c
= stream_getc(s
)) != -1 && isspace(c
))
233 tok
= token_new(line
, col
);
234 tok
->type
= (token_type
)c
;
237 if (c
== '-' || isdigit(c
)) {
238 tok
= token_new(line
, col
);
239 tok
->type
= TOKEN_VALUE
;
240 value_init(tok
->u
.v
);
241 stream_push_char(s
, c
);
242 while ((c
= stream_getc(s
)) != -1 && isdigit(c
))
243 stream_push_char(s
, c
);
246 if (s
->len
== 1 && s
->buffer
[0] == '-')
247 value_set_si(tok
->u
.v
, -1);
249 stream_push_char(s
, '\0');
250 mpz_set_str(tok
->u
.v
, s
->buffer
, 0);
255 tok
= token_new(line
, col
);
256 stream_push_char(s
, c
);
257 while ((c
= stream_getc(s
)) != -1 && isalpha(c
))
258 stream_push_char(s
, c
);
261 stream_push_char(s
, '\0');
262 if (!strcmp(s
->buffer
, "UNION")) {
263 tok
->type
= TOKEN_UNION
;
265 tok
->type
= TOKEN_IDENT
;
266 tok
->u
.s
= strdup(s
->buffer
);
271 if ((c
= stream_getc(s
)) == '=') {
272 tok
= token_new(line
, col
);
273 tok
->type
= TOKEN_GE
;
280 tok
= token_new(line
, col
);
281 tok
->type
= TOKEN_UNKNOWN
;
285 void stream_error(struct stream
*s
, struct token
*tok
, char *msg
)
287 int line
= tok
? tok
->line
: s
->line
;
288 int col
= tok
? tok
->col
: s
->col
;
289 fprintf(stderr
, "syntax error (%d, %d): %s\n", line
, col
, msg
);
292 fprintf(stderr
, "got '%c'\n", tok
->type
);
299 struct parameter
*next
;
302 struct parameter
*parameter_new(char *name
, int pos
, struct parameter
*next
)
304 struct parameter
*p
= ALLOC(struct parameter
);
305 p
->name
= strdup(name
);
311 static int parameter_pos(struct parameter
**p
, char *s
)
313 int pos
= *p
? (*p
)->pos
+1 : 0;
316 for (q
= *p
; q
; q
= q
->next
) {
317 if (strcmp(q
->name
, s
) == 0)
323 *p
= parameter_new(s
, pos
, *p
);
327 static int optional_power(struct stream
*s
)
331 tok
= stream_next_token(s
);
334 if (tok
->type
!= '^') {
335 stream_push_token(s
, tok
);
339 tok
= stream_next_token(s
);
340 if (!tok
|| tok
->type
!= TOKEN_VALUE
) {
341 stream_error(s
, tok
, "expecting exponent");
343 stream_push_token(s
, tok
);
346 pow
= VALUE_TO_INT(tok
->u
.v
);
351 static evalue
*evalue_read_factor(struct stream
*s
, struct parameter
**p
);
352 static evalue
*evalue_read_term(struct stream
*s
, struct parameter
**p
);
354 static evalue
*create_fract_like(struct stream
*s
, evalue
*arg
, enode_type type
,
355 struct parameter
**p
)
359 pow
= optional_power(s
);
363 e
->x
.p
= new_enode(type
, pow
+2, -1);
364 value_clear(e
->x
.p
->arr
[0].d
);
365 e
->x
.p
->arr
[0] = *arg
;
367 evalue_set_si(&e
->x
.p
->arr
[1+pow
], 1, 1);
369 evalue_set_si(&e
->x
.p
->arr
[1+pow
], 0, 1);
374 static evalue
*read_fract(struct stream
*s
, struct token
*tok
, struct parameter
**p
)
378 tok
= stream_next_token(s
);
380 assert(tok
->type
== '{');
383 arg
= evalue_read_term(s
, p
);
384 tok
= stream_next_token(s
);
385 if (!tok
|| tok
->type
!= '}') {
386 stream_error(s
, tok
, "expecting \"}\"");
388 stream_push_token(s
, tok
);
392 return create_fract_like(s
, arg
, fractional
, p
);
395 static evalue
*read_periodic(struct stream
*s
, struct parameter
**p
)
403 tok
= stream_next_token(s
);
404 assert(tok
&& tok
->type
== '[');
408 list
= (evalue
**)malloc(len
* sizeof(evalue
*));
412 evalue
*e
= evalue_read_term(s
, p
);
414 stream_error(s
, NULL
, "missing argument or list element");
419 list
= (evalue
**)realloc(list
, len
* sizeof(evalue
*));
423 tok
= stream_next_token(s
);
425 stream_error(s
, NULL
, "unexpected EOF");
428 if (tok
->type
!= ',')
433 if (tok
->type
!= ']') {
434 stream_error(s
, tok
, "expecting \"]\"");
435 stream_push_token(s
, tok
);
441 tok
= stream_next_token(s
);
442 if (tok
->type
== '_') {
445 tok
= stream_next_token(s
);
446 if (!tok
|| tok
->type
!= TOKEN_IDENT
) {
447 stream_error(s
, tok
, "expecting identifier");
449 stream_push_token(s
, tok
);
454 pos
= parameter_pos(p
, tok
->u
.s
);
456 e
->x
.p
= new_enode(periodic
, n
, pos
+1);
458 value_clear(e
->x
.p
->arr
[n
].d
);
459 e
->x
.p
->arr
[n
] = *list
[n
];
463 stream_push_token(s
, tok
);
464 e
= create_fract_like(s
, list
[0], flooring
, p
);
467 stream_error(s
, tok
, "unexpected token");
468 stream_push_token(s
, tok
);
473 free_evalue_refs(list
[n
]);
480 static evalue
*evalue_read_factor(struct stream
*s
, struct parameter
**p
)
485 tok
= stream_next_token(s
);
489 if (tok
->type
== '(') {
491 e
= evalue_read_term(s
, p
);
492 tok
= stream_next_token(s
);
493 if (!tok
|| tok
->type
!= ')') {
494 stream_error(s
, tok
, "expecting \")\"");
496 stream_push_token(s
, tok
);
499 } else if (tok
->type
== TOKEN_VALUE
) {
502 value_set_si(e
->d
, 1);
504 value_assign(e
->x
.n
, tok
->u
.v
);
506 tok
= stream_next_token(s
);
507 if (tok
&& tok
->type
== '/') {
509 tok
= stream_next_token(s
);
510 if (!tok
|| tok
->type
!= TOKEN_VALUE
) {
511 stream_error(s
, tok
, "expecting denominator");
513 stream_push_token(s
, tok
);
516 value_assign(e
->d
, tok
->u
.v
);
519 stream_push_token(s
, tok
);
520 } else if (tok
->type
== TOKEN_IDENT
) {
521 int pos
= parameter_pos(p
, tok
->u
.s
);
522 int pow
= optional_power(s
);
526 e
->x
.p
= new_enode(polynomial
, pow
+1, pos
+1);
527 evalue_set_si(&e
->x
.p
->arr
[pow
], 1, 1);
529 evalue_set_si(&e
->x
.p
->arr
[pow
], 0, 1);
530 } else if (tok
->type
== '[') {
531 stream_push_token(s
, tok
);
532 e
= read_periodic(s
, p
);
533 } else if (tok
->type
== '{') {
534 stream_push_token(s
, tok
);
535 e
= read_fract(s
, tok
, p
);
538 tok
= stream_next_token(s
);
539 if (tok
&& tok
->type
== '*') {
542 e2
= evalue_read_factor(s
, p
);
544 stream_error(s
, NULL
, "unexpected EOF");
548 free_evalue_refs(e2
);
551 stream_push_token(s
, tok
);
556 static evalue
*evalue_read_term(struct stream
*s
, struct parameter
**p
)
561 e
= evalue_read_factor(s
, p
);
565 tok
= stream_next_token(s
);
569 if (tok
->type
== '+') {
572 e2
= evalue_read_term(s
, p
);
574 stream_error(s
, NULL
, "unexpected EOF");
578 free_evalue_refs(e2
);
581 stream_push_token(s
, tok
);
589 struct constraint
*next
;
590 struct constraint
*union_next
;
593 static struct constraint
*constraint_new()
595 struct constraint
*c
= ALLOC(struct constraint
);
597 c
->v
= Vector_Alloc(16);
599 c
->union_next
= NULL
;
603 static void constraint_free(struct constraint
*c
)
606 struct constraint
*next
= c
->next
? c
->next
: c
->union_next
;
613 static void constraint_extend(struct constraint
*c
, int pos
)
616 if (pos
< c
->v
->Size
)
619 v
= Vector_Alloc((3*c
->v
->Size
)/2);
620 Vector_Copy(c
->v
->p
, v
->p
, c
->v
->Size
);
625 static int evalue_read_constraint(struct stream
*s
, struct parameter
**p
,
626 struct constraint
**constraints
,
627 struct constraint
*union_next
)
630 struct constraint
*c
= NULL
;
632 while ((tok
= stream_next_token(s
))) {
635 if (tok
->type
== '+')
637 else if (tok
->type
== TOKEN_IDENT
) {
639 c
= constraint_new();
640 pos
= parameter_pos(p
, tok
->u
.s
);
641 constraint_extend(c
, 1+pos
);
642 value_set_si(c
->v
->p
[1+pos
], 1);
644 } else if (tok
->type
== TOKEN_VALUE
) {
646 c
= constraint_new();
647 tok2
= stream_next_token(s
);
648 if (tok2
&& tok2
->type
== TOKEN_IDENT
) {
649 pos
= parameter_pos(p
, tok2
->u
.s
);
650 constraint_extend(c
, 1+pos
);
651 value_assign(c
->v
->p
[1+pos
], tok
->u
.v
);
656 stream_push_token(s
, tok2
);
657 value_assign(c
->v
->p
[0], tok
->u
.v
);
660 } else if (tok
->type
== TOKEN_GE
|| tok
->type
== '=') {
661 int type
= tok
->type
== TOKEN_GE
;
663 tok
= stream_next_token(s
);
664 if (!tok
|| tok
->type
!= TOKEN_VALUE
|| value_notzero_p(tok
->u
.v
)) {
665 stream_error(s
, tok
, "expecting \"0\"");
667 stream_push_token(s
, tok
);
671 c
->next
= *constraints
;
672 c
->union_next
= union_next
;
679 stream_push_token(s
, tok
);
681 stream_error(s
, tok
, "unexpected token");
690 static struct constraint
*evalue_read_domain(struct stream
*s
, struct parameter
**p
,
693 struct constraint
*constraints
= NULL
;
694 struct constraint
*union_next
= NULL
;
698 tok
= stream_next_token(s
);
701 stream_push_token(s
, tok
);
704 while (evalue_read_constraint(s
, p
, &constraints
, union_next
)) {
705 tok
= stream_next_token(s
);
707 if (tok
->type
== TOKEN_UNION
) {
709 tok
= stream_next_token(s
);
711 stream_error(s
, NULL
, "unexpected EOF");
714 stream_push_token(s
, tok
);
715 union_next
= constraints
;
719 stream_push_token(s
, tok
);
720 /* empty line separates domain from evalue */
721 if (tok
->line
> line
+1)
731 struct constraint
*constraints
;
733 struct section
*next
;
736 static char **extract_parameters(struct parameter
*p
, unsigned *nparam
)
741 *nparam
= p
? p
->pos
+1 : 0;
742 params
= ALLOCN(char *, *nparam
);
743 for (i
= 0; i
< *nparam
; ++i
) {
744 struct parameter
*next
= p
->next
;
745 params
[p
->pos
] = p
->name
;
752 static Polyhedron
*constraints2domain(struct constraint
*constraints
,
753 unsigned nparam
, unsigned MaxRays
)
758 struct constraint
*c
;
759 struct constraint
*union_next
= NULL
;
761 for (n
= 0, c
= constraints
; c
; ++n
, c
= c
->next
)
763 M
= Matrix_Alloc(n
, 1+nparam
+1);
765 struct constraint
*next
= constraints
->next
;
766 union_next
= constraints
->union_next
;
767 Vector_Copy(constraints
->v
->p
+1, M
->p
[n
]+1, nparam
);
768 if (constraints
->type
)
769 value_set_si(M
->p
[n
][0], 1);
770 value_assign(M
->p
[n
][1+nparam
], constraints
->v
->p
[0]);
771 constraints
->next
= NULL
;
772 constraints
->union_next
= NULL
;
773 constraint_free(constraints
);
776 D
= Constraints2Polyhedron(M
, MaxRays
);
780 D
= DomainConcat(D
, constraints2domain(union_next
, nparam
, MaxRays
));
784 static evalue
*evalue_read_partition(struct stream
*s
, struct parameter
*p
,
786 unsigned *nparam
, unsigned MaxRays
)
788 struct section
*part
= NULL
;
789 struct constraint
*constraints
;
793 while ((constraints
= evalue_read_domain(s
, &p
, MaxRays
))) {
794 evalue
*e
= evalue_read_term(s
, &p
);
796 stream_error(s
, NULL
, "missing evalue");
799 struct section
*sect
= ALLOC(struct section
);
800 sect
->constraints
= constraints
;
811 *ppp
= extract_parameters(p
, nparam
);
814 e
->x
.p
= new_enode(partition
, 2*m
, *nparam
);
816 for (j
= 0; j
< m
; ++j
) {
818 struct section
*next
= part
->next
;
819 constraints
= part
->constraints
;
820 D
= constraints2domain(part
->constraints
, *nparam
, MaxRays
);
821 EVALUE_SET_DOMAIN(e
->x
.p
->arr
[2*j
], D
);
822 value_clear(e
->x
.p
->arr
[2*j
+1].d
);
823 e
->x
.p
->arr
[2*j
+1] = *part
->e
;
832 static evalue
*evalue_read(FILE *in
, char *var_list
, char ***ppp
, unsigned *nvar
,
833 unsigned *nparam
, unsigned MaxRays
)
835 struct stream
*s
= stream_new(in
);
838 struct parameter
*p
= NULL
;
843 while ((next
= strchr(var_list
, ','))) {
846 parameter_pos(&p
, var_list
);
850 if (strlen(var_list
) > 0)
851 parameter_pos(&p
, var_list
);
852 nv
= p
? p
->pos
+1 : 0;
856 if (!(tok
= stream_next_token(s
)))
859 if (tok
->type
== TOKEN_VALUE
) {
860 struct token
*tok2
= stream_next_token(s
);
862 stream_push_token(s
, tok2
);
863 stream_push_token(s
, tok
);
864 if (tok2
&& (tok2
->type
== TOKEN_IDENT
|| tok2
->type
== TOKEN_GE
))
865 e
= evalue_read_partition(s
, p
, ppp
, nparam
, MaxRays
);
867 e
= evalue_read_term(s
, &p
);
868 *ppp
= extract_parameters(p
, nparam
);
870 } else if (tok
->type
== TOKEN_IDENT
) {
871 stream_push_token(s
, tok
);
872 e
= evalue_read_partition(s
, p
, ppp
, nparam
, MaxRays
);
883 static void optimize(evalue
*EP
, char **all_vars
, unsigned nvar
, unsigned nparam
,
884 struct options
*options
, barvinok_options
*bv_options
)
887 piecewise_lst
*pl
= NULL
;
888 U
= Universe_Polyhedron(nparam
);
891 params
= constructParameterVector(all_vars
+nvar
, nparam
);
893 bv_options
->bernstein_recurse
= options
->recurse
;
894 if (options
->minimize
)
895 bv_options
->bernstein_optimize
= BV_BERNSTEIN_MIN
;
897 bv_options
->bernstein_optimize
= BV_BERNSTEIN_MAX
;
898 pl
= evalue_bernstein_coefficients(NULL
, EP
, U
, params
, bv_options
);
900 if (options
->minimize
)
910 int main(int argc
, char **argv
)
913 char **all_vars
= NULL
;
916 struct options options
;
917 struct barvinok_options
*bv_options
= barvinok_options_new_with_defaults();
918 static struct argp_child argp_children
[] = {
919 { &convert_argp
, 0, "input conversion", 1 },
922 static struct argp argp
= { argp_options
, parse_opt
, 0, 0, argp_children
};
924 argp_parse(&argp
, argc
, argv
, 0, 0, &options
);
926 EP
= evalue_read(stdin
, options
.var_list
, &all_vars
, &nvar
, &nparam
,
927 bv_options
->MaxRays
);
931 evalue_split_periods(EP
, options
.split
, bv_options
->MaxRays
);
933 evalue_convert(EP
, &options
.convert
, nparam
, options
.verbose
? all_vars
: NULL
);
935 if (EVALUE_IS_ZERO(*EP
))
936 print_evalue(stdout
, EP
, all_vars
);
938 optimize(EP
, all_vars
, nvar
, nparam
, &options
, bv_options
);
940 free_evalue_refs(EP
);
943 if (options
.var_list
)
944 free(options
.var_list
);
945 Free_ParamNames(all_vars
, nvar
+nparam
);
946 barvinok_options_free(bv_options
);