barvinok_maximize: optionally call evalue_split_periods
[barvinok.git] / maximize.cc
blob0d407c012fc2dc776e2031f76c49556c6bd8029b
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)
17 #define OPT_SPLIT (BV_OPT_LAST+2)
19 struct argp_option argp_options[] = {
20 { "split", OPT_SPLIT, "int" },
21 { "variables", OPT_VARS, "int", 0,
22 "number of variables over which to maximize" },
23 { "verbose", 'V', 0, 0, },
24 { 0 }
27 struct options {
28 int nvar;
29 int verbose;
30 int split;
33 static error_t parse_opt(int key, char *arg, struct argp_state *state)
35 struct options *options = (struct options*) state->input;
37 switch (key) {
38 case ARGP_KEY_INIT:
39 options->nvar = -1;
40 options->verbose = 0;
41 options->split = 0;
42 break;
43 case 'V':
44 options->verbose = 1;
45 break;
46 case OPT_VARS:
47 options->nvar = atoi(arg);
48 break;
49 case OPT_SPLIT:
50 options->split = atoi(arg);
51 break;
52 default:
53 return ARGP_ERR_UNKNOWN;
55 return 0;
59 #define ALLOC(type) (type*)malloc(sizeof(type))
60 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
62 enum token_type { TOKEN_UNKNOWN = 256, TOKEN_VALUE, TOKEN_IDENT, TOKEN_GE };
64 struct token {
65 enum token_type type;
67 int line;
68 int col;
70 union {
71 Value v;
72 char *s;
73 } u;
76 static struct token *token_new(int line, int col)
78 struct token *tok = ALLOC(struct token);
79 tok->line = line;
80 tok->col = col;
81 return tok;
84 void token_free(struct token *tok)
86 if (tok->type == TOKEN_VALUE)
87 value_clear(tok->u.v);
88 else if (tok->type == TOKEN_IDENT)
89 free(tok->u.s);
90 free(tok);
93 struct stream {
94 FILE *file;
95 int line;
96 int col;
97 int eof;
99 char *buffer;
100 size_t size;
101 size_t len;
102 int c;
104 struct token *tokens[5];
105 int n_token;
108 static struct stream* stream_new(FILE *file)
110 int i;
111 struct stream *s = ALLOC(struct stream);
112 s->file = file;
113 s->size = 256;
114 s->buffer = (char*)malloc(s->size);
115 s->len = 0;
116 s->line = 1;
117 s->col = 0;
118 s->eof = 0;
119 s->c = -1;
120 for (i = 0; i < 5; ++i)
121 s->tokens[i] = NULL;
122 s->n_token = 0;
123 return s;
126 static void stream_free(struct stream *s)
128 free(s->buffer);
129 assert(s->n_token == 0);
130 free(s);
133 static int stream_getc(struct stream *s)
135 int c;
136 if (s->eof)
137 return -1;
138 c = fgetc(s->file);
139 if (c == -1)
140 s->eof = 1;
141 if (s->c != -1) {
142 if (s->c == '\n') {
143 s->line++;
144 s->col = 0;
145 } else
146 s->col++;
148 s->c = c;
149 return c;
152 static void stream_ungetc(struct stream *s, int c)
154 ungetc(c, s->file);
155 s->c = -1;
158 static void stream_push_char(struct stream *s, int c)
160 if (s->len >= s->size) {
161 s->size = (3*s->size)/2;
162 s->buffer = (char*)realloc(s->buffer, s->size);
164 s->buffer[s->len++] = c;
167 static struct token *stream_push_token(struct stream *s, struct token *tok)
169 assert(s->n_token < 5);
170 s->tokens[s->n_token++] = tok;
173 static struct token *stream_next_token(struct stream *s)
175 int c;
176 struct token *tok;
177 int line, col;
179 if (s->n_token)
180 return s->tokens[--s->n_token];
182 s->len = 0;
184 /* skip spaces */
185 while ((c = stream_getc(s)) != -1 && isspace(c))
186 /* nothing */
189 line = s->line;
190 col = s->col;
192 if (c == -1)
193 return NULL;
194 if (c == '(' ||
195 c == ')' ||
196 c == '+' ||
197 c == '/' ||
198 c == '*' ||
199 c == '^' ||
200 c == '=' ||
201 c == ',' ||
202 c == '_' ||
203 c == '[' ||
204 c == ']' ||
205 c == '{' ||
206 c == '}') {
207 tok = token_new(line, col);
208 tok->type = (token_type)c;
209 return tok;
211 if (c == '-' || isdigit(c)) {
212 tok = token_new(line, col);
213 tok->type = TOKEN_VALUE;
214 value_init(tok->u.v);
215 stream_push_char(s, c);
216 while ((c = stream_getc(s)) != -1 && isdigit(c))
217 stream_push_char(s, c);
218 if (c != -1)
219 stream_ungetc(s, c);
220 if (s->len == 1 && s->buffer[0] == '-')
221 value_set_si(tok->u.v, -1);
222 else {
223 stream_push_char(s, '\0');
224 mpz_set_str(tok->u.v, s->buffer, 0);
226 return tok;
228 if (isalpha(c)) {
229 tok = token_new(line, col);
230 tok->type = TOKEN_IDENT;
231 stream_push_char(s, c);
232 while ((c = stream_getc(s)) != -1 && isalpha(c))
233 stream_push_char(s, c);
234 if (c != -1)
235 stream_ungetc(s, c);
236 stream_push_char(s, '\0');
237 tok->u.s = strdup(s->buffer);
238 return tok;
240 if (c == '>') {
241 if ((c = stream_getc(s)) == '=') {
242 tok = token_new(line, col);
243 tok->type = TOKEN_GE;
244 return tok;
246 if (c != -1)
247 stream_ungetc(s, c);
250 tok = token_new(line, col);
251 tok->type = TOKEN_UNKNOWN;
252 return tok;
255 void stream_error(struct stream *s, struct token *tok, char *msg)
257 int line = tok ? tok->line : s->line;
258 int col = tok ? tok->col : s->col;
259 fprintf(stderr, "syntax error (%d, %d): %s\n", line, col, msg);
260 if (tok) {
261 if (tok->type < 256)
262 fprintf(stderr, "got '%c'\n", tok->type);
266 struct parameter {
267 char *name;
268 int pos;
269 struct parameter *next;
272 struct parameter *parameter_new(char *name, int pos, struct parameter *next)
274 struct parameter *p = ALLOC(struct parameter);
275 p->name = strdup(name);
276 p->pos = pos;
277 p->next = next;
278 return p;
281 static int parameter_pos(struct parameter **p, char *s)
283 int pos = *p ? (*p)->pos+1 : 0;
284 struct parameter *q;
286 for (q = *p; q; q = q->next) {
287 if (strcmp(q->name, s) == 0)
288 break;
290 if (q)
291 pos = q->pos;
292 else
293 *p = parameter_new(s, pos, *p);
294 return pos;
297 static int optional_power(struct stream *s)
299 int pow;
300 struct token *tok;
301 tok = stream_next_token(s);
302 if (!tok)
303 return 1;
304 if (tok->type != '^') {
305 stream_push_token(s, tok);
306 return 1;
308 token_free(tok);
309 tok = stream_next_token(s);
310 if (!tok || tok->type != TOKEN_VALUE) {
311 stream_error(s, tok, "expecting exponent");
312 if (tok)
313 stream_push_token(s, tok);
314 return 1;
316 pow = VALUE_TO_INT(tok->u.v);
317 token_free(tok);
318 return pow;
321 static evalue *evalue_read_factor(struct stream *s, struct parameter **p);
322 static evalue *evalue_read_term(struct stream *s, struct parameter **p);
324 static evalue *create_fract_like(struct stream *s, evalue *arg, enode_type type,
325 struct parameter **p)
327 evalue *e;
328 int pow;
329 pow = optional_power(s);
331 e = ALLOC(evalue);
332 value_init(e->d);
333 e->x.p = new_enode(type, pow+2, -1);
334 value_clear(e->x.p->arr[0].d);
335 e->x.p->arr[0] = *arg;
336 free(arg);
337 evalue_set_si(&e->x.p->arr[1+pow], 1, 1);
338 while (--pow >= 0)
339 evalue_set_si(&e->x.p->arr[1+pow], 0, 1);
341 return e;
344 static evalue *read_fract(struct stream *s, struct token *tok, struct parameter **p)
346 evalue *arg;
348 tok = stream_next_token(s);
349 assert(tok);
350 assert(tok->type == '{');
352 token_free(tok);
353 arg = evalue_read_term(s, p);
354 tok = stream_next_token(s);
355 if (!tok || tok->type != '}') {
356 stream_error(s, tok, "expecting \"}\"");
357 if (tok)
358 stream_push_token(s, tok);
359 } else
360 token_free(tok);
362 return create_fract_like(s, arg, fractional, p);
365 static evalue *read_periodic(struct stream *s, struct parameter **p)
367 evalue **list;
368 int len;
369 int n;
370 evalue *e = NULL;
372 struct token *tok;
373 tok = stream_next_token(s);
374 assert(tok && tok->type == '[');
375 token_free(tok);
377 len = 100;
378 list = (evalue **)malloc(len * sizeof(evalue *));
379 n = 0;
381 for (;;) {
382 evalue *e = evalue_read_term(s, p);
383 if (!e) {
384 stream_error(s, NULL, "missing argument or list element");
385 goto out;
387 if (n >= len) {
388 len = (3*len)/2;
389 list = (evalue **)realloc(list, len * sizeof(evalue *));
391 list[n++] = e;
393 tok = stream_next_token(s);
394 if (!tok) {
395 stream_error(s, NULL, "unexpected EOF");
396 goto out;
398 if (tok->type != ',')
399 break;
400 token_free(tok);
403 if (tok->type != ']') {
404 stream_error(s, tok, "expecting \"]\"");
405 stream_push_token(s, tok);
406 goto out;
409 token_free(tok);
411 tok = stream_next_token(s);
412 if (tok->type == '_') {
413 int pos;
414 token_free(tok);
415 tok = stream_next_token(s);
416 if (!tok || tok->type != TOKEN_IDENT) {
417 stream_error(s, tok, "expecting identifier");
418 if (tok)
419 stream_push_token(s, tok);
420 goto out;
422 e = ALLOC(evalue);
423 value_init(e->d);
424 pos = parameter_pos(p, tok->u.s);
425 token_free(tok);
426 e->x.p = new_enode(periodic, n, pos+1);
427 while (--n >= 0) {
428 value_clear(e->x.p->arr[n].d);
429 e->x.p->arr[n] = *list[n];
430 free(list[n]);
432 } else if (n == 1) {
433 stream_push_token(s, tok);
434 e = create_fract_like(s, list[0], flooring, p);
435 n = 0;
436 } else {
437 stream_error(s, tok, "unexpected token");
438 stream_push_token(s, tok);
441 out:
442 while (--n >= 0) {
443 free_evalue_refs(list[n]);
444 free(list[n]);
446 free(list);
447 return e;
450 static evalue *evalue_read_factor(struct stream *s, struct parameter **p)
452 struct token *tok;
453 evalue *e = NULL;
455 tok = stream_next_token(s);
456 if (!tok)
457 return NULL;
459 if (tok->type == '(') {
460 token_free(tok);
461 e = evalue_read_term(s, p);
462 tok = stream_next_token(s);
463 if (!tok || tok->type != ')') {
464 stream_error(s, tok, "expecting \")\"");
465 if (tok)
466 stream_push_token(s, tok);
467 } else
468 token_free(tok);
469 } else if (tok->type == TOKEN_VALUE) {
470 e = ALLOC(evalue);
471 value_init(e->d);
472 value_set_si(e->d, 1);
473 value_init(e->x.n);
474 value_assign(e->x.n, tok->u.v);
475 token_free(tok);
476 tok = stream_next_token(s);
477 if (tok && tok->type == '/') {
478 token_free(tok);
479 tok = stream_next_token(s);
480 if (!tok || tok->type != TOKEN_VALUE) {
481 stream_error(s, tok, "expecting denominator");
482 if (tok)
483 stream_push_token(s, tok);
484 return NULL;
486 value_assign(e->d, tok->u.v);
487 token_free(tok);
488 } else if (tok)
489 stream_push_token(s, tok);
490 } else if (tok->type == TOKEN_IDENT) {
491 int pos = parameter_pos(p, tok->u.s);
492 int pow = optional_power(s);
493 token_free(tok);
494 e = ALLOC(evalue);
495 value_init(e->d);
496 e->x.p = new_enode(polynomial, pow+1, pos+1);
497 evalue_set_si(&e->x.p->arr[pow], 1, 1);
498 while (--pow >= 0)
499 evalue_set_si(&e->x.p->arr[pow], 0, 1);
500 } else if (tok->type == '[') {
501 stream_push_token(s, tok);
502 e = read_periodic(s, p);
503 } else if (tok->type == '{') {
504 stream_push_token(s, tok);
505 e = read_fract(s, tok, p);
508 tok = stream_next_token(s);
509 if (tok && tok->type == '*') {
510 evalue *e2;
511 token_free(tok);
512 e2 = evalue_read_factor(s, p);
513 if (!e2) {
514 stream_error(s, NULL, "unexpected EOF");
515 return NULL;
517 emul(e2, e);
518 free_evalue_refs(e2);
519 free(e2);
520 } else if (tok)
521 stream_push_token(s, tok);
523 return e;
526 static evalue *evalue_read_term(struct stream *s, struct parameter **p)
528 struct token *tok;
529 evalue *e = NULL;
531 e = evalue_read_factor(s, p);
532 if (!e)
533 return NULL;
535 tok = stream_next_token(s);
536 if (!tok)
537 return e;
539 if (tok->type == '+') {
540 evalue *e2;
541 token_free(tok);
542 e2 = evalue_read_term(s, p);
543 if (!e2) {
544 stream_error(s, NULL, "unexpected EOF");
545 return NULL;
547 eadd(e2, e);
548 free_evalue_refs(e2);
549 free(e2);
550 } else
551 stream_push_token(s, tok);
553 return e;
556 struct constraint {
557 int type;
558 Vector *v;
559 struct constraint *next;
562 static struct constraint *constraint_new()
564 struct constraint *c = ALLOC(struct constraint);
565 c->type = -1;
566 c->v = Vector_Alloc(16);
567 c->next = NULL;
568 return c;
571 static void constraint_free(struct constraint *c)
573 while (c) {
574 struct constraint *next = c->next;
575 Vector_Free(c->v);
576 free(c);
577 c = next;
581 static void constraint_extend(struct constraint *c, int pos)
583 Vector *v;
584 if (pos < c->v->Size)
585 return;
587 v = Vector_Alloc((3*c->v->Size)/2);
588 Vector_Copy(c->v->p, v->p, c->v->Size);
589 Vector_Free(c->v);
590 c->v = v;
593 static int evalue_read_constraint(struct stream *s, struct parameter **p,
594 struct constraint **constraints)
596 struct token *tok;
597 struct constraint *c = NULL;
599 while ((tok = stream_next_token(s))) {
600 struct token *tok2;
601 int pos;
602 if (tok->type == '+')
603 token_free(tok);
604 else if (tok->type == TOKEN_IDENT) {
605 if (!c)
606 c = constraint_new();
607 pos = parameter_pos(p, tok->u.s);
608 constraint_extend(c, 1+pos);
609 value_set_si(c->v->p[1+pos], 1);
610 token_free(tok);
611 } else if (tok->type == TOKEN_VALUE) {
612 if (!c)
613 c = constraint_new();
614 tok2 = stream_next_token(s);
615 if (tok2 && tok2->type == TOKEN_IDENT) {
616 pos = parameter_pos(p, tok2->u.s);
617 constraint_extend(c, 1+pos);
618 value_assign(c->v->p[1+pos], tok->u.v);
619 token_free(tok);
620 token_free(tok2);
621 } else {
622 if (tok2)
623 stream_push_token(s, tok2);
624 value_assign(c->v->p[0], tok->u.v);
625 token_free(tok);
627 } else if (tok->type == TOKEN_GE || tok->type == '=') {
628 int type = tok->type == TOKEN_GE;
629 token_free(tok);
630 tok = stream_next_token(s);
631 if (!tok || tok->type != TOKEN_VALUE || value_notzero_p(tok->u.v)) {
632 stream_error(s, tok, "expecting \"0\"");
633 if (tok)
634 stream_push_token(s, tok);
635 *constraints = NULL;
636 } else {
637 c->type = type;
638 c->next = *constraints;
639 *constraints = c;
640 token_free(tok);
642 break;
643 } else {
644 if (!c)
645 stream_push_token(s, tok);
646 else {
647 stream_error(s, tok, "unexpected token");
648 *constraints = NULL;
650 return 0;
653 return tok != NULL;
656 static struct constraint *evalue_read_domain(struct stream *s, struct parameter **p,
657 unsigned MaxRays)
659 struct constraint *constraints = NULL;
660 struct token *tok;
661 int line;
663 tok = stream_next_token(s);
664 if (!tok)
665 return NULL;
666 stream_push_token(s, tok);
668 line = tok->line;
669 while (evalue_read_constraint(s, p, &constraints)) {
670 tok = stream_next_token(s);
671 if (tok) {
672 stream_push_token(s, tok);
673 /* empty line separates domain from evalue */
674 if (tok->line > line+1)
675 break;
676 line = tok->line;
679 return constraints;
682 struct section {
683 struct constraint *constraints;
684 evalue *e;
685 struct section *next;
688 static char **extract_parameters(struct parameter *p, unsigned *nparam)
690 int i;
691 char **params;
693 *nparam = p ? p->pos+1 : 0;
694 params = ALLOCN(char *, *nparam);
695 for (i = 0; i < *nparam; ++i) {
696 struct parameter *next = p->next;
697 params[p->pos] = p->name;
698 free(p);
699 p = next;
701 return params;
704 static evalue *evalue_read_partition(struct stream *s, char ***ppp,
705 unsigned *nparam, unsigned MaxRays)
707 struct section *part = NULL;
708 struct constraint *constraints;
709 evalue *e = NULL;
710 int m = 0;
711 struct parameter *p = NULL;
713 while ((constraints = evalue_read_domain(s, &p, MaxRays))) {
714 evalue *e = evalue_read_term(s, &p);
715 if (!e) {
716 stream_error(s, NULL, "missing evalue");
717 break;
719 struct section *sect = ALLOC(struct section);
720 sect->constraints = constraints;
721 sect->e = e;
722 sect->next = part;
723 part = sect;
724 ++m;
727 if (part) {
728 Polyhedron *D;
729 Matrix *M;
730 int j;
732 *ppp = extract_parameters(p, nparam);
733 e = ALLOC(evalue);
734 value_init(e->d);
735 e->x.p = new_enode(partition, 2*m, *nparam);
737 for (j = 0; j < m; ++j) {
738 int n;
739 struct section *next = part->next;
740 struct constraint *c;
741 constraints = part->constraints;
742 for (n = 0, c = constraints; c; ++n, c = c->next)
744 M = Matrix_Alloc(n, 1+*nparam+1);
745 while (--n >= 0) {
746 struct constraint *next = constraints->next;
747 Vector_Copy(constraints->v->p+1, M->p[n]+1, *nparam);
748 if (constraints->type)
749 value_set_si(M->p[n][0], 1);
750 value_assign(M->p[n][1+*nparam], constraints->v->p[0]);
751 constraints->next = NULL;
752 constraint_free(constraints);
753 constraints = next;
755 D = Constraints2Polyhedron(M, MaxRays);
756 Matrix_Free(M);
757 EVALUE_SET_DOMAIN(e->x.p->arr[2*j], D);
758 value_clear(e->x.p->arr[2*j+1].d);
759 e->x.p->arr[2*j+1] = *part->e;
760 free(part->e);
761 free(part);
762 part = next;
765 return e;
768 static evalue *evalue_read(FILE *in, char ***ppp, unsigned *nparam,
769 unsigned MaxRays)
771 struct stream *s = stream_new(in);
772 struct token *tok;
773 evalue *e;
774 struct parameter *p = NULL;
776 if (!(tok = stream_next_token(s)))
777 return NULL;
779 if (tok->type == TOKEN_VALUE) {
780 struct token *tok2 = stream_next_token(s);
781 if (tok2)
782 stream_push_token(s, tok2);
783 stream_push_token(s, tok);
784 if (tok2 && (tok2->type == TOKEN_IDENT || tok2->type == TOKEN_GE))
785 e = evalue_read_partition(s, ppp, nparam, MaxRays);
786 else {
787 e = evalue_read_term(s, &p);
788 *ppp = extract_parameters(p, nparam);
790 } else if (tok->type == TOKEN_IDENT) {
791 stream_push_token(s, tok);
792 e = evalue_read_partition(s, ppp, nparam, MaxRays);
794 stream_free(s);
795 return e;
798 int main(int argc, char **argv)
800 evalue *EP;
801 char **all_vars = NULL;
802 unsigned ntotal;
803 struct options options;
804 struct barvinok_options *bv_options = barvinok_options_new_with_defaults();
805 static struct argp argp = { argp_options, parse_opt, 0, 0, 0 };
806 Polyhedron *U;
807 piecewise_lst *pl = NULL;
809 argp_parse(&argp, argc, argv, 0, 0, &options);
811 EP = evalue_read(stdin, &all_vars, &ntotal, bv_options->MaxRays);
812 assert(EP);
814 if (options.split)
815 evalue_split_periods(EP, options.split, bv_options->MaxRays);
817 if (options.verbose)
818 print_evalue(stderr, EP, all_vars);
820 if (options.nvar == -1)
821 options.nvar = ntotal;
823 U = Universe_Polyhedron(ntotal - options.nvar);
825 exvector params;
826 params = constructParameterVector(all_vars+options.nvar, ntotal-options.nvar);
828 pl = evalue_bernstein_coefficients(NULL, EP, U, params, bv_options);
829 assert(pl);
830 pl->maximize();
831 cout << *pl << endl;
832 delete pl;
834 free_evalue_refs(EP);
835 free(EP);
837 Polyhedron_Free(U);
838 Free_ParamNames(all_vars, ntotal);
839 barvinok_options_free(bv_options);
840 return 0;