evalue.c: add evalue_split_periods
[barvinok.git] / maximize.cc
blobd9276ec27c9c6a5ea24a8c000fb8d3b734207666
1 #include <iostream>
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>
7 #include "argp.h"
9 using std::cout;
10 using std::cerr;
11 using std::endl;
12 using namespace GiNaC;
13 using namespace bernstein;
14 using namespace barvinok;
16 #define OPT_VARS (BV_OPT_LAST+1)
18 struct argp_option argp_options[] = {
19 { "variables", OPT_VARS, "int", 0,
20 "number of variables over which to maximize" },
21 { "verbose", 'V', 0, 0, },
22 { 0 }
25 struct options {
26 int nvar;
27 int verbose;
30 static error_t parse_opt(int key, char *arg, struct argp_state *state)
32 struct options *options = (struct options*) state->input;
34 switch (key) {
35 case ARGP_KEY_INIT:
36 options->nvar = -1;
37 options->verbose = 0;
38 break;
39 case 'V':
40 options->verbose = 1;
41 break;
42 case OPT_VARS:
43 options->nvar = atoi(arg);
44 break;
45 default:
46 return ARGP_ERR_UNKNOWN;
48 return 0;
52 #define ALLOC(type) (type*)malloc(sizeof(type))
53 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
55 enum token_type { TOKEN_UNKNOWN = 256, TOKEN_VALUE, TOKEN_IDENT, TOKEN_GE };
57 struct token {
58 enum token_type type;
60 int line;
61 int col;
63 union {
64 Value v;
65 char *s;
66 } u;
69 static struct token *token_new(int line, int col)
71 struct token *tok = ALLOC(struct token);
72 tok->line = line;
73 tok->col = col;
74 return tok;
77 void token_free(struct token *tok)
79 if (tok->type == TOKEN_VALUE)
80 value_clear(tok->u.v);
81 else if (tok->type == TOKEN_IDENT)
82 free(tok->u.s);
83 free(tok);
86 struct stream {
87 FILE *file;
88 int line;
89 int col;
90 int eof;
92 char *buffer;
93 size_t size;
94 size_t len;
95 int c;
97 struct token *tokens[5];
98 int n_token;
101 static struct stream* stream_new(FILE *file)
103 int i;
104 struct stream *s = ALLOC(struct stream);
105 s->file = file;
106 s->size = 256;
107 s->buffer = (char*)malloc(s->size);
108 s->len = 0;
109 s->line = 1;
110 s->col = 0;
111 s->eof = 0;
112 s->c = -1;
113 for (i = 0; i < 5; ++i)
114 s->tokens[i] = NULL;
115 s->n_token = 0;
116 return s;
119 static void stream_free(struct stream *s)
121 free(s->buffer);
122 assert(s->n_token == 0);
123 free(s);
126 static int stream_getc(struct stream *s)
128 int c;
129 if (s->eof)
130 return -1;
131 c = fgetc(s->file);
132 if (c == -1)
133 s->eof = 1;
134 if (s->c != -1) {
135 if (s->c == '\n') {
136 s->line++;
137 s->col = 0;
138 } else
139 s->col++;
141 s->c = c;
142 return c;
145 static void stream_ungetc(struct stream *s, int c)
147 ungetc(c, s->file);
148 s->c = -1;
151 static void stream_push_char(struct stream *s, int c)
153 if (s->len >= s->size) {
154 s->size = (3*s->size)/2;
155 s->buffer = (char*)realloc(s->buffer, s->size);
157 s->buffer[s->len++] = c;
160 static struct token *stream_push_token(struct stream *s, struct token *tok)
162 assert(s->n_token < 5);
163 s->tokens[s->n_token++] = tok;
166 static struct token *stream_next_token(struct stream *s)
168 int c;
169 struct token *tok;
170 int line, col;
172 if (s->n_token)
173 return s->tokens[--s->n_token];
175 s->len = 0;
177 /* skip spaces */
178 while ((c = stream_getc(s)) != -1 && isspace(c))
179 /* nothing */
182 line = s->line;
183 col = s->col;
185 if (c == -1)
186 return NULL;
187 if (c == '(' ||
188 c == ')' ||
189 c == '+' ||
190 c == '/' ||
191 c == '*' ||
192 c == '^' ||
193 c == '=' ||
194 c == ',' ||
195 c == '_' ||
196 c == '[' ||
197 c == ']' ||
198 c == '{' ||
199 c == '}') {
200 tok = token_new(line, col);
201 tok->type = (token_type)c;
202 return tok;
204 if (c == '-' || isdigit(c)) {
205 tok = token_new(line, col);
206 tok->type = TOKEN_VALUE;
207 value_init(tok->u.v);
208 stream_push_char(s, c);
209 while ((c = stream_getc(s)) != -1 && isdigit(c))
210 stream_push_char(s, c);
211 if (c != -1)
212 stream_ungetc(s, c);
213 if (s->len == 1 && s->buffer[0] == '-')
214 value_set_si(tok->u.v, -1);
215 else {
216 stream_push_char(s, '\0');
217 mpz_set_str(tok->u.v, s->buffer, 0);
219 return tok;
221 if (isalpha(c)) {
222 tok = token_new(line, col);
223 tok->type = TOKEN_IDENT;
224 stream_push_char(s, c);
225 while ((c = stream_getc(s)) != -1 && isalpha(c))
226 stream_push_char(s, c);
227 if (c != -1)
228 stream_ungetc(s, c);
229 stream_push_char(s, '\0');
230 tok->u.s = strdup(s->buffer);
231 return tok;
233 if (c == '>') {
234 if ((c = stream_getc(s)) == '=') {
235 tok = token_new(line, col);
236 tok->type = TOKEN_GE;
237 return tok;
239 if (c != -1)
240 stream_ungetc(s, c);
243 tok = token_new(line, col);
244 tok->type = TOKEN_UNKNOWN;
245 return tok;
248 void stream_error(struct stream *s, struct token *tok, char *msg)
250 int line = tok ? tok->line : s->line;
251 int col = tok ? tok->col : s->col;
252 fprintf(stderr, "syntax error (%d, %d): %s\n", line, col, msg);
253 if (tok) {
254 if (tok->type < 256)
255 fprintf(stderr, "got '%c'\n", tok->type);
259 struct parameter {
260 char *name;
261 int pos;
262 struct parameter *next;
265 struct parameter *parameter_new(char *name, int pos, struct parameter *next)
267 struct parameter *p = ALLOC(struct parameter);
268 p->name = strdup(name);
269 p->pos = pos;
270 p->next = next;
271 return p;
274 static int parameter_pos(struct parameter **p, char *s)
276 int pos = *p ? (*p)->pos+1 : 0;
277 struct parameter *q;
279 for (q = *p; q; q = q->next) {
280 if (strcmp(q->name, s) == 0)
281 break;
283 if (q)
284 pos = q->pos;
285 else
286 *p = parameter_new(s, pos, *p);
287 return pos;
290 static int optional_power(struct stream *s)
292 int pow;
293 struct token *tok;
294 tok = stream_next_token(s);
295 if (!tok)
296 return 1;
297 if (tok->type != '^') {
298 stream_push_token(s, tok);
299 return 1;
301 token_free(tok);
302 tok = stream_next_token(s);
303 if (!tok || tok->type != TOKEN_VALUE) {
304 stream_error(s, tok, "expecting exponent");
305 if (tok)
306 stream_push_token(s, tok);
307 return 1;
309 pow = VALUE_TO_INT(tok->u.v);
310 token_free(tok);
311 return pow;
314 static evalue *evalue_read_factor(struct stream *s, struct parameter **p);
315 static evalue *evalue_read_term(struct stream *s, struct parameter **p);
317 static evalue *create_fract_like(struct stream *s, evalue *arg, enode_type type,
318 struct parameter **p)
320 evalue *e;
321 int pow;
322 pow = optional_power(s);
324 e = ALLOC(evalue);
325 value_init(e->d);
326 e->x.p = new_enode(type, pow+2, -1);
327 value_clear(e->x.p->arr[0].d);
328 e->x.p->arr[0] = *arg;
329 free(arg);
330 evalue_set_si(&e->x.p->arr[1+pow], 1, 1);
331 while (--pow >= 0)
332 evalue_set_si(&e->x.p->arr[1+pow], 0, 1);
334 return e;
337 static evalue *read_fract(struct stream *s, struct token *tok, struct parameter **p)
339 evalue *arg;
341 tok = stream_next_token(s);
342 assert(tok);
343 assert(tok->type == '{');
345 token_free(tok);
346 arg = evalue_read_term(s, p);
347 tok = stream_next_token(s);
348 if (!tok || tok->type != '}') {
349 stream_error(s, tok, "expecting \"}\"");
350 if (tok)
351 stream_push_token(s, tok);
352 } else
353 token_free(tok);
355 return create_fract_like(s, arg, fractional, p);
358 static evalue *read_periodic(struct stream *s, struct parameter **p)
360 evalue **list;
361 int len;
362 int n;
363 evalue *e = NULL;
365 struct token *tok;
366 tok = stream_next_token(s);
367 assert(tok && tok->type == '[');
368 token_free(tok);
370 len = 100;
371 list = (evalue **)malloc(len * sizeof(evalue *));
372 n = 0;
374 for (;;) {
375 evalue *e = evalue_read_term(s, p);
376 if (!e) {
377 stream_error(s, NULL, "missing argument or list element");
378 goto out;
380 if (n >= len) {
381 len = (3*len)/2;
382 list = (evalue **)realloc(list, len * sizeof(evalue *));
384 list[n++] = e;
386 tok = stream_next_token(s);
387 if (!tok) {
388 stream_error(s, NULL, "unexpected EOF");
389 goto out;
391 if (tok->type != ',')
392 break;
393 token_free(tok);
396 if (tok->type != ']') {
397 stream_error(s, tok, "expecting \"]\"");
398 stream_push_token(s, tok);
399 goto out;
402 token_free(tok);
404 tok = stream_next_token(s);
405 if (tok->type == '_') {
406 int pos;
407 token_free(tok);
408 tok = stream_next_token(s);
409 if (!tok || tok->type != TOKEN_IDENT) {
410 stream_error(s, tok, "expecting identifier");
411 if (tok)
412 stream_push_token(s, tok);
413 goto out;
415 e = ALLOC(evalue);
416 value_init(e->d);
417 pos = parameter_pos(p, tok->u.s);
418 token_free(tok);
419 e->x.p = new_enode(periodic, n, pos+1);
420 while (--n >= 0) {
421 value_clear(e->x.p->arr[n].d);
422 e->x.p->arr[n] = *list[n];
423 free(list[n]);
425 } else if (n == 1) {
426 stream_push_token(s, tok);
427 e = create_fract_like(s, list[0], flooring, p);
428 n = 0;
429 } else {
430 stream_error(s, tok, "unexpected token");
431 stream_push_token(s, tok);
434 out:
435 while (--n >= 0) {
436 free_evalue_refs(list[n]);
437 free(list[n]);
439 free(list);
440 return e;
443 static evalue *evalue_read_factor(struct stream *s, struct parameter **p)
445 struct token *tok;
446 evalue *e = NULL;
448 tok = stream_next_token(s);
449 if (!tok)
450 return NULL;
452 if (tok->type == '(') {
453 token_free(tok);
454 e = evalue_read_term(s, p);
455 tok = stream_next_token(s);
456 if (!tok || tok->type != ')') {
457 stream_error(s, tok, "expecting \")\"");
458 if (tok)
459 stream_push_token(s, tok);
460 } else
461 token_free(tok);
462 } else if (tok->type == TOKEN_VALUE) {
463 e = ALLOC(evalue);
464 value_init(e->d);
465 value_set_si(e->d, 1);
466 value_init(e->x.n);
467 value_assign(e->x.n, tok->u.v);
468 token_free(tok);
469 tok = stream_next_token(s);
470 if (tok && tok->type == '/') {
471 token_free(tok);
472 tok = stream_next_token(s);
473 if (!tok || tok->type != TOKEN_VALUE) {
474 stream_error(s, tok, "expecting denominator");
475 if (tok)
476 stream_push_token(s, tok);
477 return NULL;
479 value_assign(e->d, tok->u.v);
480 token_free(tok);
481 } else if (tok)
482 stream_push_token(s, tok);
483 } else if (tok->type == TOKEN_IDENT) {
484 int pos = parameter_pos(p, tok->u.s);
485 int pow = optional_power(s);
486 token_free(tok);
487 e = ALLOC(evalue);
488 value_init(e->d);
489 e->x.p = new_enode(polynomial, pow+1, pos+1);
490 evalue_set_si(&e->x.p->arr[pow], 1, 1);
491 while (--pow >= 0)
492 evalue_set_si(&e->x.p->arr[pow], 0, 1);
493 } else if (tok->type == '[') {
494 stream_push_token(s, tok);
495 e = read_periodic(s, p);
496 } else if (tok->type == '{') {
497 stream_push_token(s, tok);
498 e = read_fract(s, tok, p);
501 tok = stream_next_token(s);
502 if (tok && tok->type == '*') {
503 evalue *e2;
504 token_free(tok);
505 e2 = evalue_read_factor(s, p);
506 if (!e2) {
507 stream_error(s, NULL, "unexpected EOF");
508 return NULL;
510 emul(e2, e);
511 free_evalue_refs(e2);
512 free(e2);
513 } else if (tok)
514 stream_push_token(s, tok);
516 return e;
519 static evalue *evalue_read_term(struct stream *s, struct parameter **p)
521 struct token *tok;
522 evalue *e = NULL;
524 e = evalue_read_factor(s, p);
525 if (!e)
526 return NULL;
528 tok = stream_next_token(s);
529 if (!tok)
530 return e;
532 if (tok->type == '+') {
533 evalue *e2;
534 token_free(tok);
535 e2 = evalue_read_term(s, p);
536 if (!e2) {
537 stream_error(s, NULL, "unexpected EOF");
538 return NULL;
540 eadd(e2, e);
541 free_evalue_refs(e2);
542 free(e2);
543 } else
544 stream_push_token(s, tok);
546 return e;
549 struct constraint {
550 int type;
551 Vector *v;
552 struct constraint *next;
555 static struct constraint *constraint_new()
557 struct constraint *c = ALLOC(struct constraint);
558 c->type = -1;
559 c->v = Vector_Alloc(16);
560 c->next = NULL;
561 return c;
564 static void constraint_free(struct constraint *c)
566 while (c) {
567 struct constraint *next = c->next;
568 Vector_Free(c->v);
569 free(c);
570 c = next;
574 static void constraint_extend(struct constraint *c, int pos)
576 Vector *v;
577 if (pos < c->v->Size)
578 return;
580 v = Vector_Alloc((3*c->v->Size)/2);
581 Vector_Copy(c->v->p, v->p, c->v->Size);
582 Vector_Free(c->v);
583 c->v = v;
586 static int evalue_read_constraint(struct stream *s, struct parameter **p,
587 struct constraint **constraints)
589 struct token *tok;
590 struct constraint *c = NULL;
592 while ((tok = stream_next_token(s))) {
593 struct token *tok2;
594 int pos;
595 if (tok->type == '+')
596 token_free(tok);
597 else if (tok->type == TOKEN_IDENT) {
598 if (!c)
599 c = constraint_new();
600 pos = parameter_pos(p, tok->u.s);
601 constraint_extend(c, 1+pos);
602 value_set_si(c->v->p[1+pos], 1);
603 token_free(tok);
604 } else if (tok->type == TOKEN_VALUE) {
605 if (!c)
606 c = constraint_new();
607 tok2 = stream_next_token(s);
608 if (tok2 && tok2->type == TOKEN_IDENT) {
609 pos = parameter_pos(p, tok2->u.s);
610 constraint_extend(c, 1+pos);
611 value_assign(c->v->p[1+pos], tok->u.v);
612 token_free(tok);
613 token_free(tok2);
614 } else {
615 if (tok2)
616 stream_push_token(s, tok2);
617 value_assign(c->v->p[0], tok->u.v);
618 token_free(tok);
620 } else if (tok->type == TOKEN_GE || tok->type == '=') {
621 int type = tok->type == TOKEN_GE;
622 token_free(tok);
623 tok = stream_next_token(s);
624 if (!tok || tok->type != TOKEN_VALUE || value_notzero_p(tok->u.v)) {
625 stream_error(s, tok, "expecting \"0\"");
626 if (tok)
627 stream_push_token(s, tok);
628 *constraints = NULL;
629 } else {
630 c->type = type;
631 c->next = *constraints;
632 *constraints = c;
633 token_free(tok);
635 break;
636 } else {
637 if (!c)
638 stream_push_token(s, tok);
639 else {
640 stream_error(s, tok, "unexpected token");
641 *constraints = NULL;
643 return 0;
646 return tok != NULL;
649 static struct constraint *evalue_read_domain(struct stream *s, struct parameter **p,
650 unsigned MaxRays)
652 struct constraint *constraints = NULL;
653 struct token *tok;
654 int line;
656 tok = stream_next_token(s);
657 if (!tok)
658 return NULL;
659 stream_push_token(s, tok);
661 line = tok->line;
662 while (evalue_read_constraint(s, p, &constraints)) {
663 tok = stream_next_token(s);
664 if (tok) {
665 stream_push_token(s, tok);
666 /* empty line separates domain from evalue */
667 if (tok->line > line+1)
668 break;
669 line = tok->line;
672 return constraints;
675 struct section {
676 struct constraint *constraints;
677 evalue *e;
678 struct section *next;
681 static char **extract_parameters(struct parameter *p, unsigned *nparam)
683 int i;
684 char **params;
686 *nparam = p ? p->pos+1 : 0;
687 params = ALLOCN(char *, *nparam);
688 for (i = 0; i < *nparam; ++i) {
689 struct parameter *next = p->next;
690 params[p->pos] = p->name;
691 free(p);
692 p = next;
694 return params;
697 static evalue *evalue_read_partition(struct stream *s, char ***ppp,
698 unsigned *nparam, unsigned MaxRays)
700 struct section *part = NULL;
701 struct constraint *constraints;
702 evalue *e = NULL;
703 int m = 0;
704 struct parameter *p = NULL;
706 while ((constraints = evalue_read_domain(s, &p, MaxRays))) {
707 evalue *e = evalue_read_term(s, &p);
708 if (!e) {
709 stream_error(s, NULL, "missing evalue");
710 break;
712 struct section *sect = ALLOC(struct section);
713 sect->constraints = constraints;
714 sect->e = e;
715 sect->next = part;
716 part = sect;
717 ++m;
720 if (part) {
721 Polyhedron *D;
722 Matrix *M;
723 int j;
725 *ppp = extract_parameters(p, nparam);
726 e = ALLOC(evalue);
727 value_init(e->d);
728 e->x.p = new_enode(partition, 2*m, *nparam);
730 for (j = 0; j < m; ++j) {
731 int n;
732 struct section *next = part->next;
733 struct constraint *c;
734 constraints = part->constraints;
735 for (n = 0, c = constraints; c; ++n, c = c->next)
737 M = Matrix_Alloc(n, 1+*nparam+1);
738 while (--n >= 0) {
739 struct constraint *next = constraints->next;
740 Vector_Copy(constraints->v->p+1, M->p[n]+1, *nparam);
741 if (constraints->type)
742 value_set_si(M->p[n][0], 1);
743 value_assign(M->p[n][1+*nparam], constraints->v->p[0]);
744 constraints->next = NULL;
745 constraint_free(constraints);
746 constraints = next;
748 D = Constraints2Polyhedron(M, MaxRays);
749 Matrix_Free(M);
750 EVALUE_SET_DOMAIN(e->x.p->arr[2*j], D);
751 value_clear(e->x.p->arr[2*j+1].d);
752 e->x.p->arr[2*j+1] = *part->e;
753 free(part->e);
754 free(part);
755 part = next;
758 return e;
761 static evalue *evalue_read(FILE *in, char ***ppp, unsigned *nparam,
762 unsigned MaxRays)
764 struct stream *s = stream_new(in);
765 struct token *tok;
766 evalue *e;
767 struct parameter *p = NULL;
769 if (!(tok = stream_next_token(s)))
770 return NULL;
772 if (tok->type == TOKEN_VALUE) {
773 struct token *tok2 = stream_next_token(s);
774 if (tok2)
775 stream_push_token(s, tok2);
776 stream_push_token(s, tok);
777 if (tok2 && (tok2->type == TOKEN_IDENT || tok2->type == TOKEN_GE))
778 e = evalue_read_partition(s, ppp, nparam, MaxRays);
779 else {
780 e = evalue_read_term(s, &p);
781 *ppp = extract_parameters(p, nparam);
783 } else if (tok->type == TOKEN_IDENT) {
784 stream_push_token(s, tok);
785 e = evalue_read_partition(s, ppp, nparam, MaxRays);
787 stream_free(s);
788 return e;
791 int main(int argc, char **argv)
793 evalue *EP;
794 char **all_vars = NULL;
795 unsigned ntotal;
796 struct options options;
797 struct barvinok_options *bv_options = barvinok_options_new_with_defaults();
798 static struct argp argp = { argp_options, parse_opt, 0, 0, 0 };
799 Polyhedron *U;
800 piecewise_lst *pl = NULL;
802 argp_parse(&argp, argc, argv, 0, 0, &options);
804 EP = evalue_read(stdin, &all_vars, &ntotal, bv_options->MaxRays);
805 assert(EP);
807 if (options.verbose)
808 print_evalue(stderr, EP, all_vars);
810 if (options.nvar == -1)
811 options.nvar = ntotal;
813 U = Universe_Polyhedron(ntotal - options.nvar);
815 exvector params;
816 params = constructParameterVector(all_vars+options.nvar, ntotal-options.nvar);
818 pl = evalue_bernstein_coefficients(NULL, EP, U, params, bv_options);
819 assert(pl);
820 pl->maximize();
821 cout << *pl << endl;
822 delete pl;
824 free_evalue_refs(EP);
825 free(EP);
827 Polyhedron_Free(U);
828 Free_ParamNames(all_vars, ntotal);
829 barvinok_options_free(bv_options);
830 return 0;