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>
12 using namespace GiNaC
;
13 using namespace bernstein
;
14 using namespace barvinok
;
16 #define OPT_VARS (BV_OPT_LAST+1)
17 #define OPT_SPLIT (BV_OPT_LAST+2)
18 #define OPT_MIN (BV_OPT_LAST+3)
20 struct argp_option argp_options
[] = {
21 { "split", OPT_SPLIT
, "int" },
22 { "variables", OPT_VARS
, "int", 0,
23 "number of variables over which to maximize" },
24 { "verbose", 'V', 0, 0, },
25 { "minimize", OPT_MIN
, 0, 0, "minimize instead of maximize"},
36 static error_t
parse_opt(int key
, char *arg
, struct argp_state
*state
)
38 struct options
*options
= (struct options
*) state
->input
;
45 options
->minimize
= 0;
51 options
->nvar
= atoi(arg
);
54 options
->split
= atoi(arg
);
57 options
->minimize
= 1;
60 return ARGP_ERR_UNKNOWN
;
66 #define ALLOC(type) (type*)malloc(sizeof(type))
67 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
69 enum token_type
{ TOKEN_UNKNOWN
= 256, TOKEN_VALUE
, TOKEN_IDENT
, TOKEN_GE
,
84 static struct token
*token_new(int line
, int col
)
86 struct token
*tok
= ALLOC(struct token
);
92 void token_free(struct token
*tok
)
94 if (tok
->type
== TOKEN_VALUE
)
95 value_clear(tok
->u
.v
);
96 else if (tok
->type
== TOKEN_IDENT
)
112 struct token
*tokens
[5];
116 static struct stream
* stream_new(FILE *file
)
119 struct stream
*s
= ALLOC(struct stream
);
122 s
->buffer
= (char*)malloc(s
->size
);
128 for (i
= 0; i
< 5; ++i
)
134 static void stream_free(struct stream
*s
)
137 assert(s
->n_token
== 0);
141 static int stream_getc(struct stream
*s
)
160 static void stream_ungetc(struct stream
*s
, int c
)
166 static void stream_push_char(struct stream
*s
, int c
)
168 if (s
->len
>= s
->size
) {
169 s
->size
= (3*s
->size
)/2;
170 s
->buffer
= (char*)realloc(s
->buffer
, s
->size
);
172 s
->buffer
[s
->len
++] = c
;
175 static struct token
*stream_push_token(struct stream
*s
, struct token
*tok
)
177 assert(s
->n_token
< 5);
178 s
->tokens
[s
->n_token
++] = tok
;
181 static struct token
*stream_next_token(struct stream
*s
)
188 return s
->tokens
[--s
->n_token
];
193 while ((c
= stream_getc(s
)) != -1 && isspace(c
))
215 tok
= token_new(line
, col
);
216 tok
->type
= (token_type
)c
;
219 if (c
== '-' || isdigit(c
)) {
220 tok
= token_new(line
, col
);
221 tok
->type
= TOKEN_VALUE
;
222 value_init(tok
->u
.v
);
223 stream_push_char(s
, c
);
224 while ((c
= stream_getc(s
)) != -1 && isdigit(c
))
225 stream_push_char(s
, c
);
228 if (s
->len
== 1 && s
->buffer
[0] == '-')
229 value_set_si(tok
->u
.v
, -1);
231 stream_push_char(s
, '\0');
232 mpz_set_str(tok
->u
.v
, s
->buffer
, 0);
237 tok
= token_new(line
, col
);
238 stream_push_char(s
, c
);
239 while ((c
= stream_getc(s
)) != -1 && isalpha(c
))
240 stream_push_char(s
, c
);
243 stream_push_char(s
, '\0');
244 if (!strcmp(s
->buffer
, "UNION")) {
245 tok
->type
= TOKEN_UNION
;
247 tok
->type
= TOKEN_IDENT
;
248 tok
->u
.s
= strdup(s
->buffer
);
253 if ((c
= stream_getc(s
)) == '=') {
254 tok
= token_new(line
, col
);
255 tok
->type
= TOKEN_GE
;
262 tok
= token_new(line
, col
);
263 tok
->type
= TOKEN_UNKNOWN
;
267 void stream_error(struct stream
*s
, struct token
*tok
, char *msg
)
269 int line
= tok
? tok
->line
: s
->line
;
270 int col
= tok
? tok
->col
: s
->col
;
271 fprintf(stderr
, "syntax error (%d, %d): %s\n", line
, col
, msg
);
274 fprintf(stderr
, "got '%c'\n", tok
->type
);
281 struct parameter
*next
;
284 struct parameter
*parameter_new(char *name
, int pos
, struct parameter
*next
)
286 struct parameter
*p
= ALLOC(struct parameter
);
287 p
->name
= strdup(name
);
293 static int parameter_pos(struct parameter
**p
, char *s
)
295 int pos
= *p
? (*p
)->pos
+1 : 0;
298 for (q
= *p
; q
; q
= q
->next
) {
299 if (strcmp(q
->name
, s
) == 0)
305 *p
= parameter_new(s
, pos
, *p
);
309 static int optional_power(struct stream
*s
)
313 tok
= stream_next_token(s
);
316 if (tok
->type
!= '^') {
317 stream_push_token(s
, tok
);
321 tok
= stream_next_token(s
);
322 if (!tok
|| tok
->type
!= TOKEN_VALUE
) {
323 stream_error(s
, tok
, "expecting exponent");
325 stream_push_token(s
, tok
);
328 pow
= VALUE_TO_INT(tok
->u
.v
);
333 static evalue
*evalue_read_factor(struct stream
*s
, struct parameter
**p
);
334 static evalue
*evalue_read_term(struct stream
*s
, struct parameter
**p
);
336 static evalue
*create_fract_like(struct stream
*s
, evalue
*arg
, enode_type type
,
337 struct parameter
**p
)
341 pow
= optional_power(s
);
345 e
->x
.p
= new_enode(type
, pow
+2, -1);
346 value_clear(e
->x
.p
->arr
[0].d
);
347 e
->x
.p
->arr
[0] = *arg
;
349 evalue_set_si(&e
->x
.p
->arr
[1+pow
], 1, 1);
351 evalue_set_si(&e
->x
.p
->arr
[1+pow
], 0, 1);
356 static evalue
*read_fract(struct stream
*s
, struct token
*tok
, struct parameter
**p
)
360 tok
= stream_next_token(s
);
362 assert(tok
->type
== '{');
365 arg
= evalue_read_term(s
, p
);
366 tok
= stream_next_token(s
);
367 if (!tok
|| tok
->type
!= '}') {
368 stream_error(s
, tok
, "expecting \"}\"");
370 stream_push_token(s
, tok
);
374 return create_fract_like(s
, arg
, fractional
, p
);
377 static evalue
*read_periodic(struct stream
*s
, struct parameter
**p
)
385 tok
= stream_next_token(s
);
386 assert(tok
&& tok
->type
== '[');
390 list
= (evalue
**)malloc(len
* sizeof(evalue
*));
394 evalue
*e
= evalue_read_term(s
, p
);
396 stream_error(s
, NULL
, "missing argument or list element");
401 list
= (evalue
**)realloc(list
, len
* sizeof(evalue
*));
405 tok
= stream_next_token(s
);
407 stream_error(s
, NULL
, "unexpected EOF");
410 if (tok
->type
!= ',')
415 if (tok
->type
!= ']') {
416 stream_error(s
, tok
, "expecting \"]\"");
417 stream_push_token(s
, tok
);
423 tok
= stream_next_token(s
);
424 if (tok
->type
== '_') {
427 tok
= stream_next_token(s
);
428 if (!tok
|| tok
->type
!= TOKEN_IDENT
) {
429 stream_error(s
, tok
, "expecting identifier");
431 stream_push_token(s
, tok
);
436 pos
= parameter_pos(p
, tok
->u
.s
);
438 e
->x
.p
= new_enode(periodic
, n
, pos
+1);
440 value_clear(e
->x
.p
->arr
[n
].d
);
441 e
->x
.p
->arr
[n
] = *list
[n
];
445 stream_push_token(s
, tok
);
446 e
= create_fract_like(s
, list
[0], flooring
, p
);
449 stream_error(s
, tok
, "unexpected token");
450 stream_push_token(s
, tok
);
455 free_evalue_refs(list
[n
]);
462 static evalue
*evalue_read_factor(struct stream
*s
, struct parameter
**p
)
467 tok
= stream_next_token(s
);
471 if (tok
->type
== '(') {
473 e
= evalue_read_term(s
, p
);
474 tok
= stream_next_token(s
);
475 if (!tok
|| tok
->type
!= ')') {
476 stream_error(s
, tok
, "expecting \")\"");
478 stream_push_token(s
, tok
);
481 } else if (tok
->type
== TOKEN_VALUE
) {
484 value_set_si(e
->d
, 1);
486 value_assign(e
->x
.n
, tok
->u
.v
);
488 tok
= stream_next_token(s
);
489 if (tok
&& tok
->type
== '/') {
491 tok
= stream_next_token(s
);
492 if (!tok
|| tok
->type
!= TOKEN_VALUE
) {
493 stream_error(s
, tok
, "expecting denominator");
495 stream_push_token(s
, tok
);
498 value_assign(e
->d
, tok
->u
.v
);
501 stream_push_token(s
, tok
);
502 } else if (tok
->type
== TOKEN_IDENT
) {
503 int pos
= parameter_pos(p
, tok
->u
.s
);
504 int pow
= optional_power(s
);
508 e
->x
.p
= new_enode(polynomial
, pow
+1, pos
+1);
509 evalue_set_si(&e
->x
.p
->arr
[pow
], 1, 1);
511 evalue_set_si(&e
->x
.p
->arr
[pow
], 0, 1);
512 } else if (tok
->type
== '[') {
513 stream_push_token(s
, tok
);
514 e
= read_periodic(s
, p
);
515 } else if (tok
->type
== '{') {
516 stream_push_token(s
, tok
);
517 e
= read_fract(s
, tok
, p
);
520 tok
= stream_next_token(s
);
521 if (tok
&& tok
->type
== '*') {
524 e2
= evalue_read_factor(s
, p
);
526 stream_error(s
, NULL
, "unexpected EOF");
530 free_evalue_refs(e2
);
533 stream_push_token(s
, tok
);
538 static evalue
*evalue_read_term(struct stream
*s
, struct parameter
**p
)
543 e
= evalue_read_factor(s
, p
);
547 tok
= stream_next_token(s
);
551 if (tok
->type
== '+') {
554 e2
= evalue_read_term(s
, p
);
556 stream_error(s
, NULL
, "unexpected EOF");
560 free_evalue_refs(e2
);
563 stream_push_token(s
, tok
);
571 struct constraint
*next
;
572 struct constraint
*union_next
;
575 static struct constraint
*constraint_new()
577 struct constraint
*c
= ALLOC(struct constraint
);
579 c
->v
= Vector_Alloc(16);
581 c
->union_next
= NULL
;
585 static void constraint_free(struct constraint
*c
)
588 struct constraint
*next
= c
->next
? c
->next
: c
->union_next
;
595 static void constraint_extend(struct constraint
*c
, int pos
)
598 if (pos
< c
->v
->Size
)
601 v
= Vector_Alloc((3*c
->v
->Size
)/2);
602 Vector_Copy(c
->v
->p
, v
->p
, c
->v
->Size
);
607 static int evalue_read_constraint(struct stream
*s
, struct parameter
**p
,
608 struct constraint
**constraints
,
609 struct constraint
*union_next
)
612 struct constraint
*c
= NULL
;
614 while ((tok
= stream_next_token(s
))) {
617 if (tok
->type
== '+')
619 else if (tok
->type
== TOKEN_IDENT
) {
621 c
= constraint_new();
622 pos
= parameter_pos(p
, tok
->u
.s
);
623 constraint_extend(c
, 1+pos
);
624 value_set_si(c
->v
->p
[1+pos
], 1);
626 } else if (tok
->type
== TOKEN_VALUE
) {
628 c
= constraint_new();
629 tok2
= stream_next_token(s
);
630 if (tok2
&& tok2
->type
== TOKEN_IDENT
) {
631 pos
= parameter_pos(p
, tok2
->u
.s
);
632 constraint_extend(c
, 1+pos
);
633 value_assign(c
->v
->p
[1+pos
], tok
->u
.v
);
638 stream_push_token(s
, tok2
);
639 value_assign(c
->v
->p
[0], tok
->u
.v
);
642 } else if (tok
->type
== TOKEN_GE
|| tok
->type
== '=') {
643 int type
= tok
->type
== TOKEN_GE
;
645 tok
= stream_next_token(s
);
646 if (!tok
|| tok
->type
!= TOKEN_VALUE
|| value_notzero_p(tok
->u
.v
)) {
647 stream_error(s
, tok
, "expecting \"0\"");
649 stream_push_token(s
, tok
);
653 c
->next
= *constraints
;
654 c
->union_next
= union_next
;
661 stream_push_token(s
, tok
);
663 stream_error(s
, tok
, "unexpected token");
672 static struct constraint
*evalue_read_domain(struct stream
*s
, struct parameter
**p
,
675 struct constraint
*constraints
= NULL
;
676 struct constraint
*union_next
= NULL
;
680 tok
= stream_next_token(s
);
683 stream_push_token(s
, tok
);
686 while (evalue_read_constraint(s
, p
, &constraints
, union_next
)) {
687 tok
= stream_next_token(s
);
690 if (tok
->type
== TOKEN_UNION
) {
692 union_next
= constraints
;
696 stream_push_token(s
, tok
);
697 /* empty line separates domain from evalue */
698 if (tok
->line
> line
+1)
707 struct constraint
*constraints
;
709 struct section
*next
;
712 static char **extract_parameters(struct parameter
*p
, unsigned *nparam
)
717 *nparam
= p
? p
->pos
+1 : 0;
718 params
= ALLOCN(char *, *nparam
);
719 for (i
= 0; i
< *nparam
; ++i
) {
720 struct parameter
*next
= p
->next
;
721 params
[p
->pos
] = p
->name
;
728 static Polyhedron
*constraints2domain(struct constraint
*constraints
,
729 unsigned nparam
, unsigned MaxRays
)
734 struct constraint
*c
;
735 struct constraint
*union_next
= NULL
;
737 for (n
= 0, c
= constraints
; c
; ++n
, c
= c
->next
)
739 M
= Matrix_Alloc(n
, 1+nparam
+1);
741 struct constraint
*next
= constraints
->next
;
742 union_next
= constraints
->union_next
;
743 Vector_Copy(constraints
->v
->p
+1, M
->p
[n
]+1, nparam
);
744 if (constraints
->type
)
745 value_set_si(M
->p
[n
][0], 1);
746 value_assign(M
->p
[n
][1+nparam
], constraints
->v
->p
[0]);
747 constraints
->next
= NULL
;
748 constraints
->union_next
= NULL
;
749 constraint_free(constraints
);
752 D
= Constraints2Polyhedron(M
, MaxRays
);
756 D
= DomainConcat(D
, constraints2domain(union_next
, nparam
, MaxRays
));
760 static evalue
*evalue_read_partition(struct stream
*s
, char ***ppp
,
761 unsigned *nparam
, unsigned MaxRays
)
763 struct section
*part
= NULL
;
764 struct constraint
*constraints
;
767 struct parameter
*p
= NULL
;
769 while ((constraints
= evalue_read_domain(s
, &p
, MaxRays
))) {
770 evalue
*e
= evalue_read_term(s
, &p
);
772 stream_error(s
, NULL
, "missing evalue");
775 struct section
*sect
= ALLOC(struct section
);
776 sect
->constraints
= constraints
;
787 *ppp
= extract_parameters(p
, nparam
);
790 e
->x
.p
= new_enode(partition
, 2*m
, *nparam
);
792 for (j
= 0; j
< m
; ++j
) {
794 struct section
*next
= part
->next
;
795 constraints
= part
->constraints
;
796 D
= constraints2domain(part
->constraints
, *nparam
, MaxRays
);
797 EVALUE_SET_DOMAIN(e
->x
.p
->arr
[2*j
], D
);
798 value_clear(e
->x
.p
->arr
[2*j
+1].d
);
799 e
->x
.p
->arr
[2*j
+1] = *part
->e
;
808 static evalue
*evalue_read(FILE *in
, char ***ppp
, unsigned *nparam
,
811 struct stream
*s
= stream_new(in
);
814 struct parameter
*p
= NULL
;
816 if (!(tok
= stream_next_token(s
)))
819 if (tok
->type
== TOKEN_VALUE
) {
820 struct token
*tok2
= stream_next_token(s
);
822 stream_push_token(s
, tok2
);
823 stream_push_token(s
, tok
);
824 if (tok2
&& (tok2
->type
== TOKEN_IDENT
|| tok2
->type
== TOKEN_GE
))
825 e
= evalue_read_partition(s
, ppp
, nparam
, MaxRays
);
827 e
= evalue_read_term(s
, &p
);
828 *ppp
= extract_parameters(p
, nparam
);
830 } else if (tok
->type
== TOKEN_IDENT
) {
831 stream_push_token(s
, tok
);
832 e
= evalue_read_partition(s
, ppp
, nparam
, MaxRays
);
838 int main(int argc
, char **argv
)
841 char **all_vars
= NULL
;
843 struct options options
;
844 struct barvinok_options
*bv_options
= barvinok_options_new_with_defaults();
845 static struct argp argp
= { argp_options
, parse_opt
, 0, 0, 0 };
847 piecewise_lst
*pl
= NULL
;
849 argp_parse(&argp
, argc
, argv
, 0, 0, &options
);
851 EP
= evalue_read(stdin
, &all_vars
, &ntotal
, bv_options
->MaxRays
);
855 evalue_split_periods(EP
, options
.split
, bv_options
->MaxRays
);
858 print_evalue(stderr
, EP
, all_vars
);
860 if (options
.nvar
== -1)
861 options
.nvar
= ntotal
;
863 U
= Universe_Polyhedron(ntotal
- options
.nvar
);
866 params
= constructParameterVector(all_vars
+options
.nvar
, ntotal
-options
.nvar
);
868 pl
= evalue_bernstein_coefficients(NULL
, EP
, U
, params
, bv_options
);
870 if (options
.minimize
)
877 free_evalue_refs(EP
);
881 Free_ParamNames(all_vars
, ntotal
);
882 barvinok_options_free(bv_options
);