lexmin: barf when polyhedron contains line
[barvinok.git] / lexmin.cc
blob17a262d4458cf465f3061754b773b3192a49a4a8
1 #include <iostream>
2 #include <vector>
3 #include <gmp.h>
4 #include <NTL/vec_ZZ.h>
5 #include <NTL/mat_ZZ.h>
6 extern "C" {
7 #include <polylib/polylibgmp.h>
9 #include <barvinok/barvinok.h>
10 #include <barvinok/evalue.h>
11 #include <barvinok/util.h>
12 #include "conversion.h"
13 #include "decomposer.h"
14 #include "lattice_point.h"
15 #include "reduce_domain.h"
16 #include "mat_util.h"
17 #include "combine.h"
18 #include "sample.h"
19 #include "fdstream.h"
20 #include "config.h"
22 #ifdef NTL_STD_CXX
23 using namespace NTL;
24 #endif
26 using std::vector;
27 using std::cerr;
28 using std::cout;
29 using std::endl;
30 using std::ostream;
32 #ifdef HAVE_GROWING_CHERNIKOVA
33 #define MAXRAYS (POL_NO_DUAL | POL_INTEGER)
34 #else
35 #define MAXRAYS 600
36 #endif
38 /* RANGE : normal range for evalutations (-RANGE -> RANGE) */
39 #define RANGE 50
41 /* SRANGE : small range for evalutations */
42 #define SRANGE 15
44 /* if dimension >= BIDDIM, use SRANGE */
45 #define BIGDIM 5
47 /* VSRANGE : very small range for evalutations */
48 #define VSRANGE 5
50 /* if dimension >= VBIDDIM, use VSRANGE */
51 #define VBIGDIM 8
53 #ifndef HAVE_GETOPT_H
54 #define getopt_long(a,b,c,d,e) getopt(a,b,c)
55 #else
56 #include <getopt.h>
57 struct option options[] = {
58 { "verify", no_argument, 0, 'T' },
59 { "print-all", no_argument, 0, 'A' },
60 { "min", required_argument, 0, 'm' },
61 { "max", required_argument, 0, 'M' },
62 { "range", required_argument, 0, 'r' },
63 { "version", no_argument, 0, 'V' },
64 { 0, 0, 0, 0 }
66 #endif
68 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
70 static int type_offset(enode *p)
72 return p->type == fractional ? 1 :
73 p->type == flooring ? 1 : 0;
76 static void evalue_denom(evalue *e, Value *d)
78 if (value_notzero_p(e->d)) {
79 value_lcm(*d, e->d, d);
80 return;
82 int offset = type_offset(e->x.p);
83 for (int i = e->x.p->size-1; i >= offset; --i)
84 evalue_denom(&e->x.p->arr[i], d);
87 static void evalue_print(std::ostream& o, evalue *e, char **p);
88 static void evalue_print(std::ostream& o, evalue *e, char **p, int d)
90 if (value_notzero_p(e->d)) {
91 o << VALUE_TO_INT(e->x.n) * (d / VALUE_TO_INT(e->d));
92 return;
94 assert(e->x.p->type == polynomial || e->x.p->type == flooring ||
95 e->x.p->type == fractional);
96 int offset = type_offset(e->x.p);
97 for (int i = e->x.p->size-1; i >= offset; --i) {
98 if (EVALUE_IS_ZERO(e->x.p->arr[i]))
99 continue;
100 if (i != e->x.p->size-1 &&
101 (value_zero_p(e->x.p->arr[i].d) ||
102 value_pos_p(e->x.p->arr[i].x.n)))
103 o << "+";
104 if (i == offset || !(value_one_p(e->x.p->arr[i].x.n) &&
105 d == VALUE_TO_INT(e->x.p->arr[i].d))) {
106 if (value_zero_p(e->x.p->arr[i].d))
107 o << "(";
108 evalue_print(o, &e->x.p->arr[i], p, d);
109 if (value_zero_p(e->x.p->arr[i].d))
110 o << ")";
111 if (i != offset)
112 o << "*";
114 for (int j = 0; j < i-offset; ++j) {
115 if (j != 0)
116 o << "*";
117 if (e->x.p->type == flooring) {
118 o << "[";
119 evalue_print(o, &e->x.p->arr[0], p);
120 o << "]";
121 } else if (e->x.p->type == fractional) {
122 o << "{";
123 evalue_print(o, &e->x.p->arr[0], p);
124 o << "}";
125 } else
126 o << p[e->x.p->pos-1];
131 static void evalue_print(std::ostream& o, evalue *e, char **p)
133 Value d;
134 value_init(d);
135 value_set_si(d, 1);
136 evalue_denom(e, &d);
137 if (value_notone_p(d))
138 o << "(";
139 evalue_print(o, e, p, VALUE_TO_INT(d));
140 if (value_notone_p(d))
141 o << ")/" << VALUE_TO_INT(d);
142 value_clear(d);
145 struct indicator_term {
146 int sign;
147 mat_ZZ den;
148 evalue **vertex;
150 indicator_term(unsigned dim) {
151 den.SetDims(dim, dim);
152 vertex = new evalue* [dim];
154 indicator_term(const indicator_term& src) {
155 sign = src.sign;
156 den = src.den;
157 unsigned dim = den.NumCols();
158 vertex = new evalue* [dim];
159 for (int i = 0; i < dim; ++i) {
160 vertex[i] = new evalue();
161 value_init(vertex[i]->d);
162 evalue_copy(vertex[i], src.vertex[i]);
165 ~indicator_term() {
166 unsigned dim = den.NumCols();
167 for (int i = 0; i < dim; ++i) {
168 free_evalue_refs(vertex[i]);
169 delete vertex[i];
171 delete [] vertex;
173 void print(ostream& os, char **p);
174 void substitute(Matrix *T);
175 void substitute(evalue *fract, evalue *val);
176 void substitute(int pos, evalue *val);
177 void reduce_in_domain(Polyhedron *D);
180 void indicator_term::reduce_in_domain(Polyhedron *D)
182 for (int k = 0; k < den.NumCols(); ++k) {
183 reduce_evalue_in_domain(vertex[k], D);
184 if (evalue_range_reduction_in_domain(vertex[k], D))
185 reduce_evalue(vertex[k]);
189 void indicator_term::print(ostream& os, char **p)
191 unsigned dim = den.NumCols();
192 unsigned factors = den.NumRows();
193 if (sign > 0)
194 os << " + ";
195 else
196 os << " - ";
197 os << '[';
198 for (int i = 0; i < dim; ++i) {
199 if (i)
200 os << ',';
201 evalue_print(os, vertex[i], p);
203 os << ']';
204 for (int i = 0; i < factors; ++i) {
205 os << " + t" << i << "*[";
206 for (int j = 0; j < dim; ++j) {
207 if (j)
208 os << ',';
209 os << den[i][j];
211 os << "]";
215 /* Perform the substitution specified by T on the variables.
216 * T has dimension (newdim+nparam+1) x (olddim + nparam + 1).
217 * The substitution is performed as in gen_fun::substitute
219 void indicator_term::substitute(Matrix *T)
221 unsigned dim = den.NumCols();
222 unsigned nparam = T->NbColumns - dim - 1;
223 unsigned newdim = T->NbRows - nparam - 1;
224 evalue **newvertex;
225 mat_ZZ trans;
226 matrix2zz(T, trans, newdim, dim);
227 trans = transpose(trans);
228 den *= trans;
229 newvertex = new evalue* [newdim];
231 vec_ZZ v;
232 v.SetLength(nparam+1);
234 evalue factor;
235 value_init(factor.d);
236 value_set_si(factor.d, 1);
237 value_init(factor.x.n);
238 for (int i = 0; i < newdim; ++i) {
239 values2zz(T->p[i]+dim, v, nparam+1);
240 newvertex[i] = multi_monom(v);
242 for (int j = 0; j < dim; ++j) {
243 if (value_zero_p(T->p[i][j]))
244 continue;
245 evalue term;
246 value_init(term.d);
247 evalue_copy(&term, vertex[j]);
248 value_assign(factor.x.n, T->p[i][j]);
249 emul(&factor, &term);
250 eadd(&term, newvertex[i]);
251 free_evalue_refs(&term);
254 free_evalue_refs(&factor);
255 for (int i = 0; i < dim; ++i) {
256 free_evalue_refs(vertex[i]);
257 delete vertex[i];
259 delete [] vertex;
260 vertex = newvertex;
263 static void substitute(evalue *e, evalue *fract, evalue *val)
265 evalue *t;
267 for (t = e; value_zero_p(t->d); t = &t->x.p->arr[type_offset(t->x.p)]) {
268 if (t->x.p->type == fractional && eequal(&t->x.p->arr[0], fract))
269 break;
271 if (value_notzero_p(t->d))
272 return;
274 free_evalue_refs(&t->x.p->arr[0]);
275 evalue *term = &t->x.p->arr[2];
276 enode *p = t->x.p;
277 value_clear(t->d);
278 *t = t->x.p->arr[1];
280 emul(val, term);
281 eadd(term, e);
282 free_evalue_refs(term);
283 free(p);
285 reduce_evalue(e);
288 void indicator_term::substitute(evalue *fract, evalue *val)
290 unsigned dim = den.NumCols();
291 for (int i = 0; i < dim; ++i) {
292 ::substitute(vertex[i], fract, val);
296 static void substitute(evalue *e, int pos, evalue *val)
298 evalue *t;
300 for (t = e; value_zero_p(t->d); t = &t->x.p->arr[type_offset(t->x.p)]) {
301 if (t->x.p->type == polynomial && t->x.p->pos == pos)
302 break;
304 if (value_notzero_p(t->d))
305 return;
307 evalue *term = &t->x.p->arr[1];
308 enode *p = t->x.p;
309 value_clear(t->d);
310 *t = t->x.p->arr[0];
312 emul(val, term);
313 eadd(term, e);
314 free_evalue_refs(term);
315 free(p);
317 reduce_evalue(e);
320 void indicator_term::substitute(int pos, evalue *val)
322 unsigned dim = den.NumCols();
323 for (int i = 0; i < dim; ++i) {
324 ::substitute(vertex[i], pos, val);
328 struct indicator_constructor : public polar_decomposer, public vertex_decomposer {
329 vec_ZZ vertex;
330 vector<indicator_term*> *terms;
332 indicator_constructor(Polyhedron *P, unsigned dim, unsigned nbV) :
333 vertex_decomposer(P, nbV, this) {
334 vertex.SetLength(dim);
335 terms = new vector<indicator_term*>[nbV];
337 ~indicator_constructor() {
338 for (int i = 0; i < nbV; ++i)
339 for (int j = 0; j < terms[i].size(); ++j)
340 delete terms[i][j];
341 delete [] terms;
343 void substitute(Matrix *T);
344 void normalize();
345 void print(ostream& os, char **p);
347 virtual void handle_polar(Polyhedron *P, int sign);
350 static void evalue_add_constant(evalue *e, ZZ v)
352 Value tmp;
353 value_init(tmp);
355 /* go down to constant term */
356 while (value_zero_p(e->d))
357 e = &e->x.p->arr[type_offset(e->x.p)];
358 /* and add v */
359 zz2value(v, tmp);
360 value_multiply(tmp, tmp, e->d);
361 value_addto(e->x.n, e->x.n, tmp);
363 value_clear(tmp);
366 void indicator_constructor::handle_polar(Polyhedron *C, int s)
368 unsigned dim = vertex.length();
370 assert(C->NbRays-1 == dim);
372 indicator_term *term = new indicator_term(dim);
373 term->sign = s;
374 terms[vert].push_back(term);
376 lattice_point(V, C, vertex, term->vertex);
378 for (int r = 0; r < dim; ++r) {
379 values2zz(C->Ray[r]+1, term->den[r], dim);
380 for (int j = 0; j < dim; ++j) {
381 if (term->den[r][j] == 0)
382 continue;
383 if (term->den[r][j] > 0)
384 break;
385 term->sign = -term->sign;
386 term->den[r] = -term->den[r];
387 vertex += term->den[r];
388 break;
391 lex_order_rows(term->den);
393 for (int i = 0; i < dim; ++i) {
394 if (!term->vertex[i]) {
395 term->vertex[i] = new evalue();
396 value_init(term->vertex[i]->d);
397 value_init(term->vertex[i]->x.n);
398 zz2value(vertex[i], term->vertex[i]->x.n);
399 value_set_si(term->vertex[i]->d, 1);
400 continue;
402 if (vertex[i] == 0)
403 continue;
404 evalue_add_constant(term->vertex[i], vertex[i]);
408 void indicator_constructor::substitute(Matrix *T)
410 for (int i = 0; i < nbV; ++i)
411 for (int j = 0; j < terms[i].size(); ++j)
412 terms[i][j]->substitute(T);
415 void indicator_constructor::print(ostream& os, char **p)
417 for (int i = 0; i < nbV; ++i)
418 for (int j = 0; j < terms[i].size(); ++j) {
419 os << "i: " << i << ", j: " << j << endl;
420 terms[i][j]->print(os, p);
421 os << endl;
425 void indicator_constructor::normalize()
427 for (int i = 0; i < nbV; ++i)
428 for (int j = 0; j < terms[i].size(); ++j) {
429 vec_ZZ vertex;
430 vertex.SetLength(terms[i][j]->den.NumCols());
431 for (int r = 0; r < terms[i][j]->den.NumRows(); ++r) {
432 for (int k = 0; k < terms[i][j]->den.NumCols(); ++k) {
433 if (terms[i][j]->den[r][k] == 0)
434 continue;
435 if (terms[i][j]->den[r][k] > 0)
436 break;
437 terms[i][j]->sign = -terms[i][j]->sign;
438 terms[i][j]->den[r] = -terms[i][j]->den[r];
439 vertex += terms[i][j]->den[r];
440 break;
443 lex_order_rows(terms[i][j]->den);
444 for (int k = 0; k < vertex.length(); ++k)
445 if (vertex[k] != 0)
446 evalue_add_constant(terms[i][j]->vertex[k], vertex[k]);
450 struct indicator {
451 vector<indicator_term*> term;
453 indicator() {}
454 indicator(const indicator& ind) {
455 for (int i = 0; i < ind.term.size(); ++i)
456 term.push_back(new indicator_term(*ind.term[i]));
458 ~indicator() {
459 for (int i = 0; i < term.size(); ++i)
460 delete term[i];
463 void print(ostream& os, char **p);
464 void simplify();
465 void peel(int i, int j);
466 void combine(int i, int j);
467 void substitute(evalue *equation);
468 void reduce_in_domain(Polyhedron *D);
471 void indicator::reduce_in_domain(Polyhedron *D)
473 for (int i = 0; i < term.size(); ++i)
474 term[i]->reduce_in_domain(D);
477 void indicator::print(ostream& os, char **p)
479 for (int i = 0; i < term.size(); ++i) {
480 term[i]->print(os, p);
481 os << endl;
485 /* Remove pairs of opposite terms */
486 void indicator::simplify()
488 for (int i = 0; i < term.size(); ++i) {
489 for (int j = i+1; j < term.size(); ++j) {
490 if (term[i]->sign + term[j]->sign != 0)
491 continue;
492 if (term[i]->den != term[j]->den)
493 continue;
494 int k;
495 for (k = 0; k < term[i]->den.NumCols(); ++k)
496 if (!eequal(term[i]->vertex[k], term[j]->vertex[k]))
497 break;
498 if (k < term[i]->den.NumCols())
499 continue;
500 delete term[i];
501 delete term[j];
502 term.erase(term.begin()+j);
503 term.erase(term.begin()+i);
504 --i;
505 break;
510 void indicator::peel(int i, int j)
512 if (j < i) {
513 int tmp = i;
514 i = j;
515 j = tmp;
517 assert (i < j);
518 int dim = term[i]->den.NumCols();
520 mat_ZZ common;
521 mat_ZZ rest_i;
522 mat_ZZ rest_j;
523 int n_common = 0, n_i = 0, n_j = 0;
525 common.SetDims(min(term[i]->den.NumRows(), term[j]->den.NumRows()), dim);
526 rest_i.SetDims(term[i]->den.NumRows(), dim);
527 rest_j.SetDims(term[j]->den.NumRows(), dim);
529 int k, l;
530 for (k = 0, l = 0; k < term[i]->den.NumRows() && l < term[j]->den.NumRows(); ) {
531 int s = lex_cmp(term[i]->den[k], term[j]->den[l]);
532 if (s == 0) {
533 common[n_common++] = term[i]->den[k];
534 ++k;
535 ++l;
536 } else if (s < 0)
537 rest_i[n_i++] = term[i]->den[k++];
538 else
539 rest_j[n_j++] = term[j]->den[l++];
541 while (k < term[i]->den.NumRows())
542 rest_i[n_i++] = term[i]->den[k++];
543 while (l < term[j]->den.NumRows())
544 rest_j[n_j++] = term[j]->den[l++];
545 common.SetDims(n_common, dim);
546 rest_i.SetDims(n_i, dim);
547 rest_j.SetDims(n_j, dim);
549 for (k = 0; k <= n_i; ++k) {
550 indicator_term *it = new indicator_term(*term[i]);
551 it->den.SetDims(n_common + k, dim);
552 for (l = 0; l < n_common; ++l)
553 it->den[l] = common[l];
554 for (l = 0; l < k; ++l)
555 it->den[n_common+l] = rest_i[l];
556 lex_order_rows(it->den);
557 if (k)
558 for (l = 0; l < dim; ++l)
559 evalue_add_constant(it->vertex[l], rest_i[k-1][l]);
560 term.push_back(it);
563 for (k = 0; k <= n_j; ++k) {
564 indicator_term *it = new indicator_term(*term[j]);
565 it->den.SetDims(n_common + k, dim);
566 for (l = 0; l < n_common; ++l)
567 it->den[l] = common[l];
568 for (l = 0; l < k; ++l)
569 it->den[n_common+l] = rest_j[l];
570 lex_order_rows(it->den);
571 if (k)
572 for (l = 0; l < dim; ++l)
573 evalue_add_constant(it->vertex[l], rest_j[k-1][l]);
574 term.push_back(it);
576 term.erase(term.begin()+j);
577 term.erase(term.begin()+i);
580 void indicator::combine(int i, int j)
582 if (j < i) {
583 int tmp = i;
584 i = j;
585 j = tmp;
587 assert (i < j);
588 int dim = term[i]->den.NumCols();
590 mat_ZZ common;
591 mat_ZZ rest_i;
592 mat_ZZ rest_j;
593 int n_common = 0, n_i = 0, n_j = 0;
595 common.SetDims(min(term[i]->den.NumRows(), term[j]->den.NumRows()), dim);
596 rest_i.SetDims(term[i]->den.NumRows(), dim);
597 rest_j.SetDims(term[j]->den.NumRows(), dim);
599 int k, l;
600 for (k = 0, l = 0; k < term[i]->den.NumRows() && l < term[j]->den.NumRows(); ) {
601 int s = lex_cmp(term[i]->den[k], term[j]->den[l]);
602 if (s == 0) {
603 common[n_common++] = term[i]->den[k];
604 ++k;
605 ++l;
606 } else if (s < 0)
607 rest_i[n_i++] = term[i]->den[k++];
608 else
609 rest_j[n_j++] = term[j]->den[l++];
611 while (k < term[i]->den.NumRows())
612 rest_i[n_i++] = term[i]->den[k++];
613 while (l < term[j]->den.NumRows())
614 rest_j[n_j++] = term[j]->den[l++];
615 common.SetDims(n_common, dim);
616 rest_i.SetDims(n_i, dim);
617 rest_j.SetDims(n_j, dim);
619 assert(n_i < 30);
620 assert(n_j < 30);
622 for (k = 0; k < (1 << n_i); ++k) {
623 indicator_term *it = new indicator_term(*term[j]);
624 it->den.SetDims(n_common + n_i + n_j, dim);
625 for (l = 0; l < n_common; ++l)
626 it->den[l] = common[l];
627 for (l = 0; l < n_i; ++l)
628 it->den[n_common+l] = rest_i[l];
629 for (l = 0; l < n_j; ++l)
630 it->den[n_common+n_i+l] = rest_j[l];
631 lex_order_rows(it->den);
632 int change = 0;
633 for (l = 0; l < n_i; ++l) {
634 if (!(k & (1 <<l)))
635 continue;
636 change ^= 1;
637 for (int m = 0; m < dim; ++m)
638 evalue_add_constant(it->vertex[m], rest_i[l][m]);
640 if (change)
641 it->sign = -it->sign;
642 term.push_back(it);
645 for (k = 0; k < (1 << n_j); ++k) {
646 indicator_term *it = new indicator_term(*term[i]);
647 it->den.SetDims(n_common + n_i + n_j, dim);
648 for (l = 0; l < n_common; ++l)
649 it->den[l] = common[l];
650 for (l = 0; l < n_i; ++l)
651 it->den[n_common+l] = rest_i[l];
652 for (l = 0; l < n_j; ++l)
653 it->den[n_common+n_i+l] = rest_j[l];
654 lex_order_rows(it->den);
655 int change = 0;
656 for (l = 0; l < n_j; ++l) {
657 if (!(k & (1 <<l)))
658 continue;
659 change ^= 1;
660 for (int m = 0; m < dim; ++m)
661 evalue_add_constant(it->vertex[m], rest_j[l][m]);
663 if (change)
664 it->sign = -it->sign;
665 term.push_back(it);
667 delete term[i];
668 delete term[j];
669 term.erase(term.begin()+j);
670 term.erase(term.begin()+i);
673 void indicator::substitute(evalue *equation)
675 evalue *fract = NULL;
676 evalue *val = new evalue;
677 value_init(val->d);
678 evalue_copy(val, equation);
680 evalue factor;
681 value_init(factor.d);
682 value_init(factor.x.n);
684 evalue *e;
685 for (e = val; value_zero_p(e->d) && e->x.p->type != fractional;
686 e = &e->x.p->arr[type_offset(e->x.p)])
689 if (value_zero_p(e->d) && e->x.p->type == fractional)
690 fract = &e->x.p->arr[0];
691 else {
692 for (e = val; value_zero_p(e->d) && e->x.p->type != polynomial;
693 e = &e->x.p->arr[type_offset(e->x.p)])
695 assert(value_zero_p(e->d) && e->x.p->type == polynomial);
698 int offset = type_offset(e->x.p);
700 assert(value_notzero_p(e->x.p->arr[offset+1].d));
701 assert(value_notzero_p(e->x.p->arr[offset+1].x.n));
702 if (value_neg_p(e->x.p->arr[offset+1].x.n)) {
703 value_oppose(factor.d, e->x.p->arr[offset+1].x.n);
704 value_assign(factor.x.n, e->x.p->arr[offset+1].d);
705 } else {
706 value_assign(factor.d, e->x.p->arr[offset+1].x.n);
707 value_oppose(factor.x.n, e->x.p->arr[offset+1].d);
710 free_evalue_refs(&e->x.p->arr[offset+1]);
711 enode *p = e->x.p;
712 value_clear(e->d);
713 *e = e->x.p->arr[offset];
715 emul(&factor, val);
717 if (fract) {
718 for (int i = 0; i < term.size(); ++i)
719 term[i]->substitute(fract, val);
721 free_evalue_refs(&p->arr[0]);
722 } else {
723 for (int i = 0; i < term.size(); ++i)
724 term[i]->substitute(p->pos, val);
727 free_evalue_refs(&factor);
728 free_evalue_refs(val);
729 delete val;
731 free(p);
734 static void add_coeff(Value *cons, int len, evalue *coeff, int pos)
736 Value tmp;
738 assert(value_notzero_p(coeff->d));
740 value_init(tmp);
742 value_lcm(cons[0], coeff->d, &tmp);
743 value_division(tmp, tmp, cons[0]);
744 Vector_Scale(cons, cons, tmp, len);
745 value_division(tmp, cons[0], coeff->d);
746 value_addmul(cons[pos], tmp, coeff->x.n);
748 value_clear(tmp);
751 struct EDomain {
752 Polyhedron *D;
753 Vector *sample;
754 vector<evalue *> floors;
756 EDomain(Polyhedron *D) {
757 this->D = Polyhedron_Copy(D);
758 sample = NULL;
760 EDomain(Polyhedron *D, vector<evalue *>floors) {
761 this->D = Polyhedron_Copy(D);
762 add_floors(floors);
763 sample = NULL;
765 EDomain(Polyhedron *D, EDomain *ED, vector<evalue *>floors) {
766 this->D = Polyhedron_Copy(D);
767 add_floors(ED->floors);
768 add_floors(floors);
769 sample = NULL;
771 void add_floors(vector<evalue *>floors) {
772 for (int i = 0; i < floors.size(); ++i) {
773 evalue *f = new evalue;
774 value_init(f->d);
775 evalue_copy(f, floors[i]);
776 this->floors.push_back(f);
779 int find_floor(evalue *needle) {
780 for (int i = 0; i < floors.size(); ++i)
781 if (eequal(needle, floors[i]))
782 return i;
783 return -1;
785 void print(FILE *out, char **p);
786 ~EDomain() {
787 for (int i = 0; i < floors.size(); ++i) {
788 free_evalue_refs(floors[i]);
789 delete floors[i];
791 Polyhedron_Free(D);
792 if (sample)
793 Vector_Free(sample);
797 void EDomain::print(FILE *out, char **p)
799 fdostream os(dup(fileno(out)));
800 for (int i = 0; i < floors.size(); ++i) {
801 os << "floor " << i << ": [";
802 evalue_print(os, floors[i], p);
803 os << "]" << endl;
805 Polyhedron_Print(out, P_VALUE_FMT, D);
808 static int evalue2constraint_r(EDomain *D, evalue *E, Value *cons, int len);
810 static void add_fract(evalue *e, Value *cons, int len, int pos)
812 evalue mone;
813 value_init(mone.d);
814 evalue_set_si(&mone, -1, 1);
816 /* contribution of alpha * fract(X) is
817 * alpha * X ...
819 assert(e->x.p->size == 3);
820 evalue argument;
821 value_init(argument.d);
822 evalue_copy(&argument, &e->x.p->arr[0]);
823 emul(&e->x.p->arr[2], &argument);
824 evalue2constraint_r(NULL, &argument, cons, len);
825 free_evalue_refs(&argument);
827 /* - alpha * floor(X) */
828 emul(&mone, &e->x.p->arr[2]);
829 add_coeff(cons, len, &e->x.p->arr[2], pos);
830 emul(&mone, &e->x.p->arr[2]);
832 free_evalue_refs(&mone);
835 static int evalue2constraint_r(EDomain *D, evalue *E, Value *cons, int len)
837 int r = 0;
838 if (value_zero_p(E->d) && E->x.p->type == fractional) {
839 int i;
840 assert(E->x.p->size == 3);
841 r = evalue2constraint_r(D, &E->x.p->arr[1], cons, len);
842 assert(value_notzero_p(E->x.p->arr[2].d));
843 if (D && (i = D->find_floor(&E->x.p->arr[0])) >= 0) {
844 add_fract(E, cons, len, 1+D->D->Dimension-D->floors.size()+i);
845 } else {
846 if (value_pos_p(E->x.p->arr[2].x.n)) {
847 evalue coeff;
848 value_init(coeff.d);
849 value_init(coeff.x.n);
850 value_set_si(coeff.d, 1);
851 evalue_denom(&E->x.p->arr[0], &coeff.d);
852 value_decrement(coeff.x.n, coeff.d);
853 emul(&E->x.p->arr[2], &coeff);
854 add_coeff(cons, len, &coeff, len-1);
855 free_evalue_refs(&coeff);
857 r = 1;
859 } else if (value_zero_p(E->d)) {
860 assert(E->x.p->type == polynomial);
861 assert(E->x.p->size == 2);
862 r = evalue2constraint_r(D, &E->x.p->arr[0], cons, len) || r;
863 add_coeff(cons, len, &E->x.p->arr[1], E->x.p->pos);
864 } else {
865 add_coeff(cons, len, E, len-1);
867 return r;
870 static int evalue2constraint(EDomain *D, evalue *E, Value *cons, int len)
872 Vector_Set(cons, 0, len);
873 value_set_si(cons[0], 1);
874 return evalue2constraint_r(D, E, cons, len);
877 static void interval_minmax(Polyhedron *I, int *min, int *max)
879 assert(I->Dimension == 1);
880 *min = 1;
881 *max = -1;
882 POL_ENSURE_VERTICES(I);
883 for (int i = 0; i < I->NbRays; ++i) {
884 if (value_pos_p(I->Ray[i][1]))
885 *max = 1;
886 else if (value_neg_p(I->Ray[i][1]))
887 *min = -1;
888 else {
889 if (*max < 0)
890 *max = 0;
891 if (*min > 0)
892 *min = 0;
897 static void interval_minmax(Polyhedron *D, Matrix *T, int *min, int *max,
898 unsigned MaxRays)
900 Polyhedron *I = Polyhedron_Image(D, T, MaxRays);
901 I = DomainConstraintSimplify(I, MaxRays);
902 if (emptyQ2(I)) {
903 Polyhedron_Free(I);
904 I = Polyhedron_Image(D, T, MaxRays);
906 interval_minmax(I, min, max);
907 Polyhedron_Free(I);
910 struct max_term {
911 unsigned dim;
912 Polyhedron *domain;
913 vector<evalue *> max;
915 void print(ostream& os, char **p) const;
916 void resolve_existential_vars() const;
917 void substitute(Matrix *T, unsigned MaxRays);
918 Vector *eval(Value *val, unsigned MaxRays) const;
920 ~max_term() {
921 for (int i = 0; i < max.size(); ++i) {
922 free_evalue_refs(max[i]);
923 delete max[i];
925 Polyhedron_Free(domain);
929 static void print_varlist(ostream& os, int n, char **names)
931 int i;
932 os << "[";
933 for (i = 0; i < n; ++i) {
934 if (i)
935 os << ",";
936 os << names[i];
938 os << "]";
941 static void print_term(ostream& os, Value v, int pos, int dim,
942 char **names, int *first)
944 if (value_zero_p(v)) {
945 if (first && *first && pos >= dim)
946 os << "0";
947 return;
950 if (first) {
951 if (!*first && value_pos_p(v))
952 os << "+";
953 *first = 0;
955 if (pos < dim) {
956 if (value_mone_p(v)) {
957 os << "-";
958 } else if (!value_one_p(v))
959 os << VALUE_TO_INT(v);
960 os << names[pos];
961 } else
962 os << VALUE_TO_INT(v);
965 /* We put all possible existentially quantified variables at the back
966 * and so if any equalities exist between these variables and the
967 * other variables, then PolyLib will replace all occurrences of some
968 * of the other variables by some existentially quantified variables.
969 * We want the output to have as few as possible references to the
970 * existentially quantified variables, so we undo what PolyLib did here.
972 void resolve_existential_vars(Polyhedron *domain, unsigned dim)
974 int last = domain->NbEq - 1;
975 /* Matrix "view" of domain for ExchangeRows */
976 Matrix M;
977 M.NbRows = domain->NbConstraints;
978 M.NbColumns = domain->Dimension+2;
979 M.p_Init = domain->p_Init;
980 M.p = domain->Constraint;
981 Value mone;
982 value_init(mone);
983 value_set_si(mone, -1);
984 for (int e = domain->Dimension-1; e >= dim; --e) {
985 int r;
986 for (r = last; r >= 0; --r)
987 if (value_notzero_p(domain->Constraint[r][1+e]))
988 break;
989 if (r < 0)
990 continue;
991 if (r != last)
992 ExchangeRows(&M, r, last);
994 /* Combine uses the coefficient as a multiplier, so it must
995 * be positive, since we are modifying an inequality.
997 if (value_neg_p(domain->Constraint[last][1+e]))
998 Vector_Scale(domain->Constraint[last]+1, domain->Constraint[last]+1,
999 mone, domain->Dimension+1);
1001 for (int c = 0; c < domain->NbConstraints; ++c) {
1002 if (c == last)
1003 continue;
1004 if (value_notzero_p(domain->Constraint[c][1+e]))
1005 Combine(domain->Constraint[c], domain->Constraint[last],
1006 domain->Constraint[c], 1+e, domain->Dimension+1);
1008 --last;
1010 value_clear(mone);
1013 void max_term::resolve_existential_vars() const
1015 ::resolve_existential_vars(domain, dim);
1018 void max_term::print(ostream& os, char **p) const
1020 char **names = p;
1021 if (dim < domain->Dimension) {
1022 resolve_existential_vars();
1023 names = new char * [domain->Dimension];
1024 int i;
1025 for (i = 0; i < dim; ++i)
1026 names[i] = p[i];
1027 for ( ; i < domain->Dimension; ++i) {
1028 names[i] = new char[10];
1029 snprintf(names[i], 10, "a%d", i - dim);
1033 Value tmp;
1034 value_init(tmp);
1035 os << "{ ";
1036 print_varlist(os, dim, p);
1037 os << " -> ";
1038 os << "[";
1039 for (int i = 0; i < max.size(); ++i) {
1040 if (i)
1041 os << ",";
1042 evalue_print(os, max[i], p);
1044 os << "]";
1045 os << " : ";
1046 if (dim < domain->Dimension) {
1047 os << "exists ";
1048 print_varlist(os, domain->Dimension-dim, names+dim);
1049 os << " : ";
1051 for (int i = 0; i < domain->NbConstraints; ++i) {
1052 int first = 1;
1053 int v = First_Non_Zero(domain->Constraint[i]+1, domain->Dimension);
1054 if (v == -1)
1055 continue;
1056 if (i)
1057 os << " && ";
1058 if (value_pos_p(domain->Constraint[i][v+1])) {
1059 print_term(os, domain->Constraint[i][v+1], v, domain->Dimension,
1060 names, NULL);
1061 if (value_zero_p(domain->Constraint[i][0]))
1062 os << " = ";
1063 else
1064 os << " >= ";
1065 for (int j = v+1; j <= domain->Dimension; ++j) {
1066 value_oppose(tmp, domain->Constraint[i][1+j]);
1067 print_term(os, tmp, j, domain->Dimension,
1068 names, &first);
1070 } else {
1071 value_oppose(tmp, domain->Constraint[i][1+v]);
1072 print_term(os, tmp, v, domain->Dimension,
1073 names, NULL);
1074 if (value_zero_p(domain->Constraint[i][0]))
1075 os << " = ";
1076 else
1077 os << " <= ";
1078 for (int j = v+1; j <= domain->Dimension; ++j)
1079 print_term(os, domain->Constraint[i][1+j], j, domain->Dimension,
1080 names, &first);
1083 os << " }" << endl;
1084 value_clear(tmp);
1086 if (dim < domain->Dimension) {
1087 for (int i = dim; i < domain->Dimension; ++i)
1088 delete [] names[i];
1089 delete [] names;
1093 static void evalue_substitute(evalue *e, evalue **subs)
1095 evalue *v;
1097 if (value_notzero_p(e->d))
1098 return;
1100 enode *p = e->x.p;
1101 for (int i = 0; i < p->size; ++i)
1102 evalue_substitute(&p->arr[i], subs);
1104 if (p->type == polynomial)
1105 v = subs[p->pos-1];
1106 else {
1107 v = new evalue;
1108 value_init(v->d);
1109 value_set_si(v->d, 0);
1110 v->x.p = new_enode(p->type, 3, -1);
1111 value_clear(v->x.p->arr[0].d);
1112 v->x.p->arr[0] = p->arr[0];
1113 evalue_set_si(&v->x.p->arr[1], 0, 1);
1114 evalue_set_si(&v->x.p->arr[2], 1, 1);
1117 int offset = type_offset(p);
1119 for (int i = p->size-1; i >= offset+1; i--) {
1120 emul(v, &p->arr[i]);
1121 eadd(&p->arr[i], &p->arr[i-1]);
1122 free_evalue_refs(&(p->arr[i]));
1125 if (p->type != polynomial) {
1126 free_evalue_refs(v);
1127 delete v;
1130 value_clear(e->d);
1131 *e = p->arr[offset];
1132 free(p);
1135 /* T maps the compressed parameters to the original parameters,
1136 * while this max_term is based on the compressed parameters
1137 * and we want get the original parameters back.
1139 void max_term::substitute(Matrix *T, unsigned MaxRays)
1141 int nexist = 0;
1142 for (int i = 0; i < T->NbRows-1; ++i)
1143 if (value_notone_p(T->p[i][i]))
1144 ++nexist;
1146 Matrix *M = Matrix_Alloc(T->NbRows + nexist, T->NbColumns);
1147 nexist = 0;
1148 for (int i = 0; i < T->NbRows-1; ++i) {
1149 Vector_Copy(T->p[i], M->p[i], T->NbColumns);
1150 if (value_notone_p(T->p[i][i]))
1151 value_set_si(M->p[T->NbRows-1 + nexist++][i], 1);
1153 value_assign(M->p[M->NbRows-1][M->NbColumns-1],
1154 T->p[T->NbRows-1][T->NbColumns-1]);
1156 Polyhedron *D = DomainImage(domain, M, MaxRays);
1157 Polyhedron_Free(domain);
1158 domain = D;
1159 Matrix_Free(M);
1161 assert(T->NbRows == T->NbColumns);
1162 Matrix *inv = Matrix_Alloc(T->NbColumns, T->NbRows);
1163 int ok = Matrix_Inverse(T, inv);
1164 assert(ok);
1166 evalue denom;
1167 value_init(denom.d);
1168 value_init(denom.x.n);
1169 value_set_si(denom.x.n, 1);
1170 value_assign(denom.d, inv->p[inv->NbRows-1][inv->NbColumns-1]);
1172 vec_ZZ v;
1173 v.SetLength(inv->NbColumns);
1174 evalue* subs[inv->NbRows-1];
1175 for (int i = 0; i < inv->NbRows-1; ++i) {
1176 values2zz(inv->p[i], v, v.length());
1177 subs[i] = multi_monom(v);
1178 emul(&denom, subs[i]);
1180 free_evalue_refs(&denom);
1182 for (int i = 0; i < max.size(); ++i) {
1183 evalue_substitute(max[i], subs);
1184 reduce_evalue(max[i]);
1187 for (int i = 0; i < inv->NbRows-1; ++i) {
1188 free_evalue_refs(subs[i]);
1189 delete subs[i];
1191 Matrix_Free(inv);
1194 int Last_Non_Zero(Value *p, unsigned len)
1196 for (int i = len-1; i >= 0; --i)
1197 if (value_notzero_p(p[i]))
1198 return i;
1199 return -1;
1202 static void SwapColumns(Value **V, int n, int i, int j)
1204 for (int r = 0; r < n; ++r)
1205 value_swap(V[r][i], V[r][j]);
1208 static void SwapColumns(Polyhedron *P, int i, int j)
1210 SwapColumns(P->Constraint, P->NbConstraints, i, j);
1211 SwapColumns(P->Ray, P->NbRays, i, j);
1214 bool in_domain(Polyhedron *P, Value *val, unsigned dim, unsigned MaxRays)
1216 int nexist = P->Dimension - dim;
1217 int last[P->NbConstraints];
1218 Value tmp, min, max;
1219 Vector *all_val = Vector_Alloc(P->Dimension+1);
1220 bool in = false;
1221 int i;
1222 int alternate;
1224 resolve_existential_vars(P, dim);
1226 Vector_Copy(val, all_val->p, dim);
1227 value_set_si(all_val->p[P->Dimension], 1);
1229 value_init(tmp);
1230 for (int i = 0; i < P->NbConstraints; ++i) {
1231 last[i] = Last_Non_Zero(P->Constraint[i]+1+dim, nexist);
1232 if (last[i] == -1) {
1233 Inner_Product(P->Constraint[i]+1, all_val->p, P->Dimension+1, &tmp);
1234 if (value_neg_p(tmp))
1235 goto out;
1236 if (i < P->NbEq && value_pos_p(tmp))
1237 goto out;
1241 value_init(min);
1242 value_init(max);
1243 alternate = nexist - 1;
1244 for (i = 0; i < nexist; ++i) {
1245 bool min_set = false;
1246 bool max_set = false;
1247 for (int j = 0; j < P->NbConstraints; ++j) {
1248 if (last[j] != i)
1249 continue;
1250 Inner_Product(P->Constraint[j]+1, all_val->p, P->Dimension+1, &tmp);
1251 value_oppose(tmp, tmp);
1252 if (j < P->NbEq) {
1253 if (!mpz_divisible_p(tmp, P->Constraint[j][1+dim+i]))
1254 goto out2;
1255 value_division(tmp, tmp, P->Constraint[j][1+dim+i]);
1256 if (!max_set || value_lt(tmp, max)) {
1257 max_set = true;
1258 value_assign(max, tmp);
1260 if (!min_set || value_gt(tmp, min)) {
1261 min_set = true;
1262 value_assign(min, tmp);
1264 } else {
1265 if (value_pos_p(P->Constraint[j][1+dim+i])) {
1266 mpz_cdiv_q(tmp, tmp, P->Constraint[j][1+dim+i]);
1267 if (!min_set || value_gt(tmp, min)) {
1268 min_set = true;
1269 value_assign(min, tmp);
1271 } else {
1272 mpz_fdiv_q(tmp, tmp, P->Constraint[j][1+dim+i]);
1273 if (!max_set || value_lt(tmp, max)) {
1274 max_set = true;
1275 value_assign(max, tmp);
1280 /* Move another existential variable in current position */
1281 if (!max_set || !min_set) {
1282 if (!(alternate > i)) {
1283 Matrix *M = Matrix_Alloc(dim+i, 1+P->Dimension+1);
1284 for (int j = 0; j < dim+i; ++j) {
1285 value_set_si(M->p[j][1+j], -1);
1286 value_assign(M->p[j][1+P->Dimension], all_val->p[j]);
1288 Polyhedron *Q = AddConstraints(M->p[0], dim+i, P, MaxRays);
1289 Matrix_Free(M);
1290 Q = DomainConstraintSimplify(Q, MaxRays);
1291 Vector *sample = Polyhedron_Sample(Q, MaxRays);
1292 in = !!sample;
1293 if (sample)
1294 Vector_Free(sample);
1295 Polyhedron_Free(Q);
1296 goto out2;
1298 assert(alternate > i);
1299 SwapColumns(P, 1+dim+i, 1+dim+alternate);
1300 resolve_existential_vars(P, dim);
1301 for (int j = 0; j < P->NbConstraints; ++j) {
1302 if (j >= P->NbEq && last[j] < i)
1303 continue;
1304 last[j] = Last_Non_Zero(P->Constraint[j]+1+dim, nexist);
1305 if (last[j] < i) {
1306 Inner_Product(P->Constraint[j]+1, all_val->p, P->Dimension+1,
1307 &tmp);
1308 if (value_neg_p(tmp))
1309 goto out2;
1310 if (j < P->NbEq && value_pos_p(tmp))
1311 goto out2;
1314 --alternate;
1315 --i;
1316 continue;
1318 assert(max_set && min_set);
1319 if (value_lt(max, min))
1320 goto out2;
1321 if (value_ne(max, min)) {
1322 Matrix *M = Matrix_Alloc(dim+i, 1+P->Dimension+1);
1323 for (int j = 0; j < dim+i; ++j) {
1324 value_set_si(M->p[j][1+j], -1);
1325 value_assign(M->p[j][1+P->Dimension], all_val->p[j]);
1327 Polyhedron *Q = AddConstraints(M->p[0], dim+i, P, MaxRays);
1328 Matrix_Free(M);
1329 Q = DomainConstraintSimplify(Q, MaxRays);
1330 Vector *sample = Polyhedron_Sample(Q, MaxRays);
1331 in = !!sample;
1332 if (sample)
1333 Vector_Free(sample);
1334 Polyhedron_Free(Q);
1335 goto out2;
1337 assert(value_eq(max, min));
1338 value_assign(all_val->p[dim+i], max);
1339 alternate = nexist - 1;
1341 in = true;
1342 out2:
1343 value_clear(min);
1344 value_clear(max);
1345 out:
1346 Vector_Free(all_val);
1347 value_clear(tmp);
1348 return in || (P->next && in_domain(P->next, val, dim, MaxRays));
1351 void compute_evalue(evalue *e, Value *val, Value *res)
1353 double d = compute_evalue(e, val);
1354 if (d > 0)
1355 d += .25;
1356 else
1357 d -= .25;
1358 value_set_double(*res, d);
1361 Vector *max_term::eval(Value *val, unsigned MaxRays) const
1363 if (dim == domain->Dimension) {
1364 if (!in_domain(domain, val))
1365 return NULL;
1366 } else {
1367 if (!in_domain(domain, val, dim, MaxRays))
1368 return NULL;
1370 Vector *res = Vector_Alloc(max.size());
1371 for (int i = 0; i < max.size(); ++i) {
1372 compute_evalue(max[i], val, &res->p[i]);
1374 return res;
1377 static Matrix *add_ge_constraint(EDomain *ED, evalue *constraint,
1378 vector<evalue *>& new_floors)
1380 Polyhedron *D = ED->D;
1381 evalue mone;
1382 value_init(mone.d);
1383 evalue_set_si(&mone, -1, 1);
1384 int fract = 0;
1385 for (evalue *e = constraint; value_zero_p(e->d);
1386 e = &e->x.p->arr[type_offset(e->x.p)]) {
1387 int i;
1388 if (e->x.p->type != fractional)
1389 continue;
1390 for (i = 0; i < ED->floors.size(); ++i)
1391 if (eequal(&e->x.p->arr[0], ED->floors[i]))
1392 break;
1393 if (i < ED->floors.size())
1394 continue;
1395 ++fract;
1398 int rows = D->NbConstraints+2*fract+1;
1399 int cols = 2+D->Dimension+fract;
1400 Matrix *M = Matrix_Alloc(rows, cols);
1401 for (int i = 0; i < D->NbConstraints; ++i) {
1402 Vector_Copy(D->Constraint[i], M->p[i], 1+D->Dimension);
1403 value_assign(M->p[i][1+D->Dimension+fract],
1404 D->Constraint[i][1+D->Dimension]);
1406 value_set_si(M->p[rows-1][0], 1);
1407 fract = 0;
1408 evalue *e;
1409 for (e = constraint; value_zero_p(e->d); e = &e->x.p->arr[type_offset(e->x.p)]) {
1410 if (e->x.p->type == fractional) {
1411 int i, pos;
1413 i = ED->find_floor(&e->x.p->arr[0]);
1414 if (i >= 0)
1415 pos = D->Dimension-ED->floors.size()+i;
1416 else
1417 pos = D->Dimension+fract;
1419 add_fract(e, M->p[rows-1], cols, 1+pos);
1421 if (pos < D->Dimension)
1422 continue;
1424 /* constraints for the new floor */
1425 int row = D->NbConstraints+2*fract;
1426 value_set_si(M->p[row][0], 1);
1427 evalue2constraint_r(NULL, &e->x.p->arr[0], M->p[row], cols);
1428 value_oppose(M->p[row][1+D->Dimension+fract], M->p[row][0]);
1429 value_set_si(M->p[row][0], 1);
1431 Vector_Scale(M->p[row]+1, M->p[row+1]+1, mone.x.n, cols-1);
1432 value_set_si(M->p[row+1][0], 1);
1433 value_addto(M->p[row+1][cols-1], M->p[row+1][cols-1],
1434 M->p[row+1][1+D->Dimension+fract]);
1435 value_decrement(M->p[row+1][cols-1], M->p[row+1][cols-1]);
1437 evalue *arg = new evalue;
1438 value_init(arg->d);
1439 evalue_copy(arg, &e->x.p->arr[0]);
1440 new_floors.push_back(arg);
1442 ++fract;
1443 } else {
1444 assert(e->x.p->type == polynomial);
1445 assert(e->x.p->size == 2);
1446 add_coeff(M->p[rows-1], cols, &e->x.p->arr[1], e->x.p->pos);
1449 add_coeff(M->p[rows-1], cols, e, cols-1);
1450 value_set_si(M->p[rows-1][0], 1);
1451 free_evalue_refs(&mone);
1452 return M;
1455 Polyhedron *unfringe (Polyhedron *P, unsigned MaxRays)
1457 int len = P->Dimension+2;
1458 Polyhedron *T, *R = P;
1459 Value g;
1460 value_init(g);
1461 Vector *row = Vector_Alloc(len);
1462 value_set_si(row->p[0], 1);
1464 R = DomainConstraintSimplify(Polyhedron_Copy(P), MaxRays);
1466 Matrix *M = Matrix_Alloc(2, len-1);
1467 value_set_si(M->p[1][len-2], 1);
1468 for (int v = 0; v < P->Dimension; ++v) {
1469 value_set_si(M->p[0][v], 1);
1470 Polyhedron *I = Polyhedron_Image(R, M, 2+1);
1471 value_set_si(M->p[0][v], 0);
1472 for (int r = 0; r < I->NbConstraints; ++r) {
1473 if (value_zero_p(I->Constraint[r][0]))
1474 continue;
1475 if (value_zero_p(I->Constraint[r][1]))
1476 continue;
1477 if (value_one_p(I->Constraint[r][1]))
1478 continue;
1479 if (value_mone_p(I->Constraint[r][1]))
1480 continue;
1481 value_absolute(g, I->Constraint[r][1]);
1482 Vector_Set(row->p+1, 0, len-2);
1483 value_division(row->p[1+v], I->Constraint[r][1], g);
1484 mpz_fdiv_q(row->p[len-1], I->Constraint[r][2], g);
1485 T = R;
1486 R = AddConstraints(row->p, 1, R, MaxRays);
1487 if (T != P)
1488 Polyhedron_Free(T);
1490 Polyhedron_Free(I);
1492 Matrix_Free(M);
1493 Vector_Free(row);
1494 value_clear(g);
1495 return R;
1498 static Matrix *remove_equalities(Polyhedron **P, unsigned nparam, unsigned MaxRays);
1500 Vector *Polyhedron_not_empty(Polyhedron *P, unsigned MaxRays)
1502 Polyhedron *Porig = P;
1503 Vector *sample = NULL;
1505 POL_ENSURE_VERTICES(P);
1506 if (emptyQ2(P))
1507 return NULL;
1509 for (int i = 0; i < P->NbRays; ++i)
1510 if (value_one_p(P->Ray[i][1+P->Dimension])) {
1511 sample = Vector_Alloc(P->Dimension + 1);
1512 Vector_Copy(P->Ray[i]+1, sample->p, P->Dimension+1);
1513 return sample;
1516 Matrix *T = remove_equalities(&P, 0, MaxRays);
1517 if (P)
1518 sample = Polyhedron_Sample(P, MaxRays);
1519 if (sample) {
1520 if (T) {
1521 Vector *P_sample = Vector_Alloc(Porig->Dimension + 1);
1522 Matrix_Vector_Product(T, sample->p, P_sample->p);
1523 Vector_Free(sample);
1524 sample = P_sample;
1527 if (T) {
1528 Polyhedron_Free(P);
1529 Matrix_Free(T);
1532 return sample;
1535 struct split {
1536 evalue *constraint;
1537 enum sign { le, ge, lge } sign;
1539 split (evalue *c, enum sign s) : constraint(c), sign(s) {}
1542 static void split_on(const split& sp, EDomain *D,
1543 EDomain **Dlt, EDomain **Deq, EDomain **Dgt,
1544 unsigned MaxRays)
1546 Matrix *M, *M2;
1547 EDomain *EDlt = NULL, *EDeq = NULL, *EDgt = NULL;
1548 Polyhedron *D2;
1549 Value mone;
1550 value_init(mone);
1551 value_set_si(mone, -1);
1552 *Dlt = NULL;
1553 *Deq = NULL;
1554 *Dgt = NULL;
1555 vector<evalue *> new_floors;
1556 M = add_ge_constraint(D, sp.constraint, new_floors);
1557 if (sp.sign == split::lge || sp.sign == split::ge) {
1558 M2 = Matrix_Copy(M);
1559 value_decrement(M2->p[M2->NbRows-1][M2->NbColumns-1],
1560 M2->p[M2->NbRows-1][M2->NbColumns-1]);
1561 D2 = Constraints2Polyhedron(M2, MaxRays);
1562 EDgt = new EDomain(D2, D, new_floors);
1563 Polyhedron_Free(D2);
1564 Matrix_Free(M2);
1566 if (sp.sign == split::lge || sp.sign == split::le) {
1567 M2 = Matrix_Copy(M);
1568 Vector_Scale(M2->p[M2->NbRows-1]+1, M2->p[M2->NbRows-1]+1,
1569 mone, M2->NbColumns-1);
1570 value_decrement(M2->p[M2->NbRows-1][M2->NbColumns-1],
1571 M2->p[M2->NbRows-1][M2->NbColumns-1]);
1572 D2 = Constraints2Polyhedron(M2, MaxRays);
1573 EDlt = new EDomain(D2, D, new_floors);
1574 Polyhedron_Free(D2);
1575 Matrix_Free(M2);
1578 assert(sp.sign == split::lge || sp.sign == split::ge || sp.sign == split::le);
1579 value_set_si(M->p[M->NbRows-1][0], 0);
1580 D2 = Constraints2Polyhedron(M, MaxRays);
1581 EDeq = new EDomain(D2, D, new_floors);
1582 Polyhedron_Free(D2);
1583 Matrix_Free(M);
1585 Vector *sample = D->sample;
1586 if (sample && new_floors.size() > 0) {
1587 assert(sample->Size == D->D->Dimension+1);
1588 sample = Vector_Alloc(D->D->Dimension+new_floors.size()+1);
1589 Vector_Copy(D->sample->p, sample->p, D->D->Dimension);
1590 value_set_si(sample->p[D->D->Dimension+new_floors.size()], 1);
1591 for (int i = 0; i < new_floors.size(); ++i)
1592 compute_evalue(new_floors[i], sample->p, sample->p+D->D->Dimension+i);
1595 for (int i = 0; i < new_floors.size(); ++i) {
1596 free_evalue_refs(new_floors[i]);
1597 delete new_floors[i];
1600 if (EDeq) {
1601 if (sample && in_domain(EDeq->D, sample->p, sample->Size-1, MaxRays)) {
1602 EDeq->sample = Vector_Alloc(sample->Size);
1603 Vector_Copy(sample->p, EDeq->sample->p, sample->Size);
1604 } else if (!(EDeq->sample = Polyhedron_not_empty(EDeq->D, MaxRays))) {
1605 delete EDeq;
1606 EDeq = NULL;
1609 if (EDgt) {
1610 if (sample && in_domain(EDgt->D, sample->p, sample->Size-1, MaxRays)) {
1611 EDgt->sample = Vector_Alloc(sample->Size);
1612 Vector_Copy(sample->p, EDgt->sample->p, sample->Size);
1613 } else if (!(EDgt->sample = Polyhedron_not_empty(EDgt->D, MaxRays))) {
1614 delete EDgt;
1615 EDgt = NULL;
1618 if (EDlt) {
1619 if (sample && in_domain(EDlt->D, sample->p, sample->Size-1, MaxRays)) {
1620 EDlt->sample = Vector_Alloc(sample->Size);
1621 Vector_Copy(sample->p, EDlt->sample->p, sample->Size);
1622 } else if (!(EDlt->sample = Polyhedron_not_empty(EDlt->D, MaxRays))) {
1623 delete EDlt;
1624 EDlt = NULL;
1627 *Dlt = EDlt;
1628 *Deq = EDeq;
1629 *Dgt = EDgt;
1630 value_clear(mone);
1631 if (sample != D->sample)
1632 Vector_Free(sample);
1635 ostream & operator<< (ostream & os, const vector<int> & v)
1637 os << "[";
1638 for (int i = 0; i < v.size(); ++i) {
1639 if (i)
1640 os << ", ";
1641 os << v[i];
1643 os << "]";
1644 return os;
1648 * Project on first dim dimensions
1650 Polyhedron* Polyhedron_Project_Initial(Polyhedron *P, int dim)
1652 int i;
1653 Matrix *T;
1654 Polyhedron *I;
1656 if (P->Dimension == dim)
1657 return Polyhedron_Copy(P);
1659 T = Matrix_Alloc(dim+1, P->Dimension+1);
1660 for (i = 0; i < dim; ++i)
1661 value_set_si(T->p[i][i], 1);
1662 value_set_si(T->p[dim][P->Dimension], 1);
1663 I = Polyhedron_Image(P, T, P->NbConstraints);
1664 Matrix_Free(T);
1665 return I;
1668 static vector<max_term*> lexmin(indicator& ind, EDomain *D, unsigned nparam,
1669 unsigned MaxRays, vector<int> loc)
1671 vector<max_term*> maxima;
1672 int len = 1 + D->D->Dimension + 1;
1673 Value lcm, a, b;
1674 evalue mone;
1675 EDomain *Dorig = D;
1677 value_init(mone.d);
1678 evalue_set_si(&mone, -1, 1);
1679 value_init(lcm);
1680 value_init(a);
1681 value_init(b);
1682 Vector *c = Vector_Alloc(len);
1683 Matrix *T = Matrix_Alloc(2, len-1);
1684 for (int i = 0; i < ind.term.size(); ++i) {
1685 bool restart = false; /* true if we have modified ind from i up */
1686 bool stop = false; /* true if i can never be smallest */
1687 int peel = -1; /* term to peel against */
1688 vector<split> splits;
1689 if (ind.term[i]->sign < 0)
1690 continue;
1691 int dim = ind.term[i]->den.NumCols();
1692 int j;
1693 for (j = 0; j < ind.term.size(); ++j) {
1694 if (i == j)
1695 continue;
1696 int k;
1697 for (k = 0; k < dim; ++k) {
1698 /* compute ind.term->[i]->vertex[k] - ind.term->[j]->vertex[k] */
1699 evalue *diff = new evalue;
1700 value_init(diff->d);
1701 evalue_copy(diff, ind.term[j]->vertex[k]);
1702 emul(&mone, diff);
1703 eadd(ind.term[i]->vertex[k], diff);
1704 reduce_evalue(diff);
1705 int fract = evalue2constraint(D, diff, c->p, len);
1706 Vector_Copy(c->p+1, T->p[0], len-1);
1707 value_assign(T->p[1][len-2], c->p[0]);
1709 int min, max;
1710 interval_minmax(D->D, T, &min, &max, MaxRays);
1711 if (max < 0) {
1712 free_evalue_refs(diff);
1713 delete diff;
1714 break;
1716 if (fract) {
1717 emul(&mone, diff);
1718 evalue2constraint(D, diff, c->p, len);
1719 emul(&mone, diff);
1720 Vector_Copy(c->p+1, T->p[0], len-1);
1721 value_assign(T->p[1][len-2], c->p[0]);
1723 int negmin, negmax;
1724 interval_minmax(D->D, T, &negmin, &negmax, MaxRays);
1725 min = -negmax;
1727 if (min > 0) {
1728 free_evalue_refs(diff);
1729 delete diff;
1730 stop = true;
1731 break;
1733 if (max == 0 && min == 0) {
1734 if (!EVALUE_IS_ZERO(*diff)) {
1735 ind.substitute(diff);
1736 ind.simplify();
1737 restart = true;
1739 free_evalue_refs(diff);
1740 delete diff;
1741 if (restart)
1742 break;
1743 continue;
1745 if (min < 0 && max == 0)
1746 splits.push_back(split(diff, split::le));
1747 else if (max > 0 && min == 0)
1748 splits.push_back(split(diff, split::ge));
1749 else
1750 splits.push_back(split(diff, split::lge));
1751 break;
1753 if (k == dim && ind.term[j]->sign < 0)
1754 peel = j;
1755 if (stop || restart)
1756 break;
1758 if (restart) {
1759 /* The ith entry may have been removed, so we have to consider
1760 * it again.
1762 --i;
1763 for (j = 0; j < splits.size(); ++j) {
1764 free_evalue_refs(splits[j].constraint);
1765 delete splits[j].constraint;
1767 continue;
1769 if (stop) {
1770 for (j = 0; j < splits.size(); ++j) {
1771 free_evalue_refs(splits[j].constraint);
1772 delete splits[j].constraint;
1774 continue;
1776 if (peel != -1) {
1777 // ind.peel(i, peel);
1778 ind.combine(i, peel);
1779 ind.simplify();
1780 i = -1; /* start over */
1781 for (j = 0; j < splits.size(); ++j) {
1782 free_evalue_refs(splits[j].constraint);
1783 delete splits[j].constraint;
1785 continue;
1787 if (splits.size() != 0) {
1788 for (j = 0; j < splits.size(); ++j)
1789 if (splits[j].sign == split::le)
1790 break;
1791 if (j == splits.size())
1792 j = 0;
1793 EDomain *Dlt, *Deq, *Dgt;
1794 split_on(splits[j], D, &Dlt, &Deq, &Dgt, MaxRays);
1795 assert(Dlt || Deq || Dgt);
1796 if (Deq) {
1797 loc.push_back(0);
1798 indicator indeq(ind);
1799 indeq.substitute(splits[j].constraint);
1800 Polyhedron *P = Polyhedron_Project_Initial(Deq->D, nparam);
1801 P = DomainConstraintSimplify(P, MaxRays);
1802 indeq.reduce_in_domain(P);
1803 Polyhedron_Free(P);
1804 indeq.simplify();
1805 vector<max_term*> maxeq = lexmin(indeq, Deq, nparam,
1806 MaxRays, loc);
1807 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
1808 loc.pop_back();
1809 delete Deq;
1811 if (Dgt) {
1812 loc.push_back(1);
1813 indicator indgt(ind);
1814 Polyhedron *P = Polyhedron_Project_Initial(Dgt->D, nparam);
1815 P = DomainConstraintSimplify(P, MaxRays);
1816 indgt.reduce_in_domain(P);
1817 Polyhedron_Free(P);
1818 indgt.simplify();
1819 vector<max_term*> maxeq = lexmin(indgt, Dgt, nparam,
1820 MaxRays, loc);
1821 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
1822 loc.pop_back();
1823 delete Dgt;
1825 if (Dlt) {
1826 loc.push_back(-1);
1827 Polyhedron *P = Polyhedron_Project_Initial(Dlt->D, nparam);
1828 P = DomainConstraintSimplify(P, MaxRays);
1829 ind.reduce_in_domain(P);
1830 Polyhedron_Free(P);
1831 ind.simplify();
1832 if (D != Dorig)
1833 delete D;
1834 D = Dlt;
1835 if (splits.size() > 1) {
1836 vector<max_term*> maxeq = lexmin(ind, Dlt, nparam,
1837 MaxRays, loc);
1838 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
1839 for (j = 0; j < splits.size(); ++j) {
1840 free_evalue_refs(splits[j].constraint);
1841 delete splits[j].constraint;
1843 break;
1846 /* the vertex turned out not to be minimal */
1847 for (j = 0; j < splits.size(); ++j) {
1848 free_evalue_refs(splits[j].constraint);
1849 delete splits[j].constraint;
1851 if (!Dlt)
1852 break;
1854 max_term *maximum = new max_term;
1855 maxima.push_back(maximum);
1856 maximum->dim = nparam;
1857 maximum->domain = Polyhedron_Copy(D->D);
1858 for (int j = 0; j < dim; ++j) {
1859 evalue *E = new evalue;
1860 value_init(E->d);
1861 evalue_copy(E, ind.term[i]->vertex[j]);
1862 if (evalue_frac2floor_in_domain(E, D->D))
1863 reduce_evalue(E);
1864 maximum->max.push_back(E);
1866 break;
1868 Matrix_Free(T);
1869 Vector_Free(c);
1870 value_clear(lcm);
1871 value_clear(a);
1872 value_clear(b);
1873 free_evalue_refs(&mone);
1874 if (D != Dorig)
1875 delete D;
1876 return maxima;
1879 static Matrix *compress_parameters(Polyhedron **P, unsigned nparam, unsigned MaxRays)
1881 Matrix *M, *T, *CP;
1883 /* compress_parms doesn't like equalities that only involve parameters */
1884 for (int i = 0; i < (*P)->NbEq; ++i)
1885 assert(First_Non_Zero((*P)->Constraint[i]+1, (*P)->Dimension-nparam) != -1);
1887 M = Matrix_Alloc((*P)->NbEq, (*P)->Dimension+2);
1888 Vector_Copy((*P)->Constraint[0], M->p[0], (*P)->NbEq * ((*P)->Dimension+2));
1889 CP = compress_parms(M, nparam);
1890 Matrix_Free(M);
1892 if (isIdentity(CP)) {
1893 Matrix_Free(CP);
1894 return NULL;
1897 T = align_matrix(CP, (*P)->Dimension+1);
1898 *P = Polyhedron_Preimage(*P, T, MaxRays);
1899 Matrix_Free(T);
1901 return CP;
1904 static Matrix *remove_equalities(Polyhedron **P, unsigned nparam, unsigned MaxRays)
1906 /* Matrix "view" of equalities */
1907 Matrix M;
1908 M.NbRows = (*P)->NbEq;
1909 M.NbColumns = (*P)->Dimension+2;
1910 M.p_Init = (*P)->p_Init;
1911 M.p = (*P)->Constraint;
1913 Matrix *T = compress_variables(&M, nparam);
1915 if (!T) {
1916 *P = NULL;
1917 return NULL;
1919 if (isIdentity(T)) {
1920 Matrix_Free(T);
1921 T = NULL;
1922 } else
1923 *P = Polyhedron_Preimage(*P, T, MaxRays);
1925 return T;
1928 static vector<max_term*> lexmin(Polyhedron *P, Polyhedron *C, unsigned MaxRays)
1930 unsigned nparam = C->Dimension;
1931 Param_Polyhedron *PP = NULL;
1932 Polyhedron *CEq = NULL, *pVD;
1933 Matrix *CT = NULL;
1934 Matrix *T = NULL, *CP = NULL;
1935 Param_Domain *D, *next;
1936 Param_Vertices *V;
1937 Polyhedron *Porig = P;
1938 int i;
1939 vector<max_term*> all_max;
1940 Polyhedron *Q;
1942 if (emptyQ2(P))
1943 return all_max;
1945 POL_ENSURE_VERTICES(P);
1947 if (emptyQ2(P))
1948 return all_max;
1950 assert(P->NbBid == 0);
1952 if (P->NbEq > 0) {
1953 if (nparam > 0)
1954 CP = compress_parameters(&P, nparam, MaxRays);
1955 Q = P;
1956 T = remove_equalities(&P, nparam, MaxRays);
1957 if (P != Q && Q != Porig)
1958 Polyhedron_Free(Q);
1959 if (!P)
1960 return all_max;
1963 Q = P;
1964 PP = Polyhedron2Param_SimplifiedDomain(&P,C,
1965 (MaxRays & POL_NO_DUAL) ? 0 : MaxRays,
1966 &CEq,&CT);
1967 if (P != Q && Q != Porig)
1968 Polyhedron_Free(Q);
1970 if (CT) {
1971 if (isIdentity(CT)) {
1972 Matrix_Free(CT);
1973 CT = NULL;
1974 } else
1975 nparam = CT->NbRows - 1;
1978 unsigned dim = P->Dimension - nparam;
1980 int nd;
1981 for (nd = 0, D=PP->D; D; ++nd, D=D->next);
1982 Polyhedron **fVD = new Polyhedron*[nd];
1984 indicator_constructor ic(P, dim, PP->nbV);
1986 for (i = 0, V = PP->V; V; V = V->next, i++) {
1987 ic.decompose_at_vertex(V, i, MaxRays);
1989 if (T) {
1990 ic.substitute(T);
1991 ic.normalize();
1994 for (nd = 0, D=PP->D; D; D=next) {
1995 next = D->next;
1997 Polyhedron *rVD = reduce_domain(D->Domain, CT, CEq,
1998 fVD, nd, MaxRays);
1999 if (!rVD)
2000 continue;
2002 pVD = CT ? DomainImage(rVD,CT,MaxRays) : rVD;
2004 indicator ind;
2006 FORALL_PVertex_in_ParamPolyhedron(V,D,PP) // _i is internal counter
2007 for (int j = 0; j < ic.terms[_i].size(); ++j) {
2008 indicator_term *term = new indicator_term(*ic.terms[_i][j]);
2009 term->reduce_in_domain(pVD);
2010 ind.term.push_back(term);
2012 END_FORALL_PVertex_in_ParamPolyhedron;
2014 ind.simplify();
2016 EDomain epVD(pVD);
2017 vector<int> loc;
2018 vector<max_term*> maxima = lexmin(ind, &epVD, nparam, MaxRays, loc);
2019 if (CP)
2020 for (int j = 0; j < maxima.size(); ++j)
2021 maxima[j]->substitute(CP, MaxRays);
2022 all_max.insert(all_max.end(), maxima.begin(), maxima.end());
2024 ++nd;
2025 if (rVD != pVD)
2026 Domain_Free(pVD);
2027 Domain_Free(rVD);
2029 if (CP)
2030 Matrix_Free(CP);
2031 if (T)
2032 Matrix_Free(T);
2033 Param_Polyhedron_Free(PP);
2034 if (CEq)
2035 Polyhedron_Free(CEq);
2036 for (--nd; nd >= 0; --nd) {
2037 Domain_Free(fVD[nd]);
2039 delete [] fVD;
2040 if (P != Porig)
2041 Polyhedron_Free(P);
2043 return all_max;
2046 static void verify_results(Polyhedron *A, Polyhedron *C,
2047 vector<max_term*>& maxima, int m, int M,
2048 int print_all, unsigned MaxRays);
2050 int main(int argc, char **argv)
2052 Polyhedron *A, *C;
2053 Matrix *MA;
2054 int bignum;
2055 char **iter_names, **param_names;
2056 int c, ind = 0;
2057 int range = 0;
2058 int verify = 0;
2059 int print_all = 0;
2060 int m = INT_MAX, M = INT_MIN, r;
2061 int print_solution = 1;
2063 while ((c = getopt_long(argc, argv, "TAm:M:r:V", options, &ind)) != -1) {
2064 switch (c) {
2065 case 'T':
2066 verify = 1;
2067 break;
2068 case 'A':
2069 print_all = 1;
2070 break;
2071 case 'm':
2072 m = atoi(optarg);
2073 verify = 1;
2074 break;
2075 case 'M':
2076 M = atoi(optarg);
2077 verify = 1;
2078 break;
2079 case 'r':
2080 M = atoi(optarg);
2081 m = -M;
2082 verify = 1;
2083 break;
2084 case 'V':
2085 printf(barvinok_version());
2086 exit(0);
2087 break;
2091 MA = Matrix_Read();
2092 C = Constraints2Polyhedron(MA, MAXRAYS);
2093 Matrix_Free(MA);
2094 fscanf(stdin, " %d", &bignum);
2095 assert(bignum == -1);
2096 MA = Matrix_Read();
2097 A = Constraints2Polyhedron(MA, MAXRAYS);
2098 Matrix_Free(MA);
2100 if (A->Dimension >= VBIGDIM)
2101 r = VSRANGE;
2102 else if (A->Dimension >= BIGDIM)
2103 r = SRANGE;
2104 else
2105 r = RANGE;
2106 if (M == INT_MIN)
2107 M = r;
2108 if (m == INT_MAX)
2109 m = -r;
2111 if (verify && m > M) {
2112 fprintf(stderr,"Nothing to do: min > max !\n");
2113 return(0);
2115 if (verify)
2116 print_solution = 0;
2118 iter_names = util_generate_names(A->Dimension - C->Dimension, "i");
2119 param_names = util_generate_names(C->Dimension, "p");
2120 if (print_solution) {
2121 Polyhedron_Print(stdout, P_VALUE_FMT, A);
2122 Polyhedron_Print(stdout, P_VALUE_FMT, C);
2124 vector<max_term*> maxima = lexmin(A, C, MAXRAYS);
2125 if (print_solution)
2126 for (int i = 0; i < maxima.size(); ++i)
2127 maxima[i]->print(cout, param_names);
2129 if (verify)
2130 verify_results(A, C, maxima, m, M, print_all, MAXRAYS);
2132 for (int i = 0; i < maxima.size(); ++i)
2133 delete maxima[i];
2135 util_free_names(A->Dimension - C->Dimension, iter_names);
2136 util_free_names(C->Dimension, param_names);
2137 Polyhedron_Free(A);
2138 Polyhedron_Free(C);
2140 return 0;
2143 static bool lexmin(int pos, Polyhedron *P, Value *context)
2145 Value LB, UB, k;
2146 int lu_flags;
2147 bool found = false;
2149 if (emptyQ(P))
2150 return false;
2152 value_init(LB); value_init(UB); value_init(k);
2153 value_set_si(LB,0);
2154 value_set_si(UB,0);
2155 lu_flags = lower_upper_bounds(pos,P,context,&LB,&UB);
2156 assert(!(lu_flags & LB_INFINITY));
2158 value_set_si(context[pos],0);
2159 if (!lu_flags && value_lt(UB,LB)) {
2160 value_clear(LB); value_clear(UB); value_clear(k);
2161 return false;
2163 if (!P->next) {
2164 value_assign(context[pos], LB);
2165 value_clear(LB); value_clear(UB); value_clear(k);
2166 return true;
2168 for (value_assign(k,LB); lu_flags || value_le(k,UB); value_increment(k,k)) {
2169 value_assign(context[pos],k);
2170 if ((found = lexmin(pos+1, P->next, context)))
2171 break;
2173 if (!found)
2174 value_set_si(context[pos],0);
2175 value_clear(LB); value_clear(UB); value_clear(k);
2176 return found;
2179 static void print_list(FILE *out, Value *z, char* brackets, int len)
2181 fprintf(out, "%c", brackets[0]);
2182 value_print(out, VALUE_FMT,z[0]);
2183 for (int k = 1; k < len; ++k) {
2184 fprintf(out, ", ");
2185 value_print(out, VALUE_FMT,z[k]);
2187 fprintf(out, "%c", brackets[1]);
2190 static int check_poly(Polyhedron *S, Polyhedron *CS, vector<max_term*>& maxima,
2191 int nparam, int pos, Value *z, int print_all, int st,
2192 unsigned MaxRays)
2194 if (pos == nparam) {
2195 int k;
2196 bool found = lexmin(1, S, z);
2198 if (print_all) {
2199 printf("lexmin");
2200 print_list(stdout, z+S->Dimension-nparam+1, "()", nparam);
2201 printf(" = ");
2202 if (found)
2203 print_list(stdout, z+1, "[]", S->Dimension-nparam);
2204 printf(" ");
2207 Vector *min = NULL;
2208 for (int i = 0; i < maxima.size(); ++i)
2209 if ((min = maxima[i]->eval(z+S->Dimension-nparam+1, MaxRays)))
2210 break;
2212 int ok = !(found ^ !!min);
2213 if (found && min)
2214 for (int i = 0; i < S->Dimension-nparam; ++i)
2215 if (value_ne(z[1+i], min->p[i])) {
2216 ok = 0;
2217 break;
2219 if (!ok) {
2220 printf("\n");
2221 fflush(stdout);
2222 fprintf(stderr, "Error !\n");
2223 fprintf(stderr, "lexmin");
2224 print_list(stderr, z+S->Dimension-nparam+1, "()", nparam);
2225 fprintf(stderr, " should be ");
2226 if (found)
2227 print_list(stderr, z+1, "[]", S->Dimension-nparam);
2228 fprintf(stderr, " while digging gives ");
2229 if (min)
2230 print_list(stderr, min->p, "[]", S->Dimension-nparam);
2231 fprintf(stderr, ".\n");
2232 return 0;
2233 } else if (print_all)
2234 printf("OK.\n");
2235 if (min)
2236 Vector_Free(min);
2238 for (k = 1; k <= S->Dimension-nparam; ++k)
2239 value_set_si(z[k], 0);
2240 } else {
2241 Value tmp;
2242 Value LB, UB;
2243 value_init(tmp);
2244 value_init(LB);
2245 value_init(UB);
2246 int ok =
2247 !(lower_upper_bounds(1+pos, CS, &z[S->Dimension-nparam], &LB, &UB));
2248 for (value_assign(tmp,LB); value_le(tmp,UB); value_increment(tmp,tmp)) {
2249 if (!print_all) {
2250 int k = VALUE_TO_INT(tmp);
2251 if (!pos && !(k%st)) {
2252 printf("o");
2253 fflush(stdout);
2256 value_assign(z[pos+S->Dimension-nparam+1],tmp);
2257 if (!check_poly(S, CS->next, maxima, nparam, pos+1, z, print_all, st,
2258 MaxRays)) {
2259 value_clear(tmp);
2260 value_clear(LB);
2261 value_clear(UB);
2262 return 0;
2265 value_set_si(z[pos+S->Dimension-nparam+1],0);
2266 value_clear(tmp);
2267 value_clear(LB);
2268 value_clear(UB);
2270 return 1;
2273 void verify_results(Polyhedron *A, Polyhedron *C, vector<max_term*>& maxima,
2274 int m, int M, int print_all, unsigned MaxRays)
2276 Polyhedron *CC, *CC2, *CS, *S;
2277 unsigned nparam = C->Dimension;
2278 Value *p;
2279 int i;
2280 int st;
2282 CC = Polyhedron_Project(A, nparam);
2283 CC2 = DomainIntersection(C, CC, MAXRAYS);
2284 Domain_Free(CC);
2285 CC = CC2;
2287 /* Intersect context with range */
2288 if (nparam > 0) {
2289 Matrix *MM;
2290 Polyhedron *U;
2292 MM = Matrix_Alloc(2*C->Dimension, C->Dimension+2);
2293 for (int i = 0; i < C->Dimension; ++i) {
2294 value_set_si(MM->p[2*i][0], 1);
2295 value_set_si(MM->p[2*i][1+i], 1);
2296 value_set_si(MM->p[2*i][1+C->Dimension], -m);
2297 value_set_si(MM->p[2*i+1][0], 1);
2298 value_set_si(MM->p[2*i+1][1+i], -1);
2299 value_set_si(MM->p[2*i+1][1+C->Dimension], M);
2301 CC2 = AddConstraints(MM->p[0], 2*CC->Dimension, CC, MAXRAYS);
2302 U = Universe_Polyhedron(0);
2303 CS = Polyhedron_Scan(CC2, U, MAXRAYS & POL_NO_DUAL ? 0 : MAXRAYS);
2304 Polyhedron_Free(U);
2305 Polyhedron_Free(CC2);
2306 Matrix_Free(MM);
2307 } else
2308 CS = NULL;
2310 p = ALLOCN(Value, A->Dimension+2);
2311 for (i=0; i <= A->Dimension; i++) {
2312 value_init(p[i]);
2313 value_set_si(p[i],0);
2315 value_init(p[i]);
2316 value_set_si(p[i], 1);
2318 S = Polyhedron_Scan(A, C, MAXRAYS & POL_NO_DUAL ? 0 : MAXRAYS);
2320 if (!print_all && C->Dimension > 0) {
2321 if (M-m > 80)
2322 st = 1+(M-m)/80;
2323 else
2324 st = 1;
2325 for (int i = m; i <= M; i += st)
2326 printf(".");
2327 printf( "\r" );
2328 fflush(stdout);
2331 if (S) {
2332 if (!(CS && emptyQ2(CS)))
2333 check_poly(S, CS, maxima, nparam, 0, p, print_all, st, MaxRays);
2334 Domain_Free(S);
2337 if (!print_all)
2338 printf("\n");
2340 for (i=0; i <= (A->Dimension+1); i++)
2341 value_clear(p[i]);
2342 free(p);
2343 if (CS)
2344 Domain_Free(CS);
2345 Polyhedron_Free(CC);