Merge branch 'master' into bernstein
[barvinok.git] / lexmin.cc
blob4903f8e64f4b1ef7099e39127b5422d425d0e4cf
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_print(std::ostream& o, evalue *e, char **p);
77 static void evalue_print(std::ostream& o, evalue *e, char **p, int d)
79 if (value_notzero_p(e->d)) {
80 o << VALUE_TO_INT(e->x.n) * (d / VALUE_TO_INT(e->d));
81 return;
83 assert(e->x.p->type == polynomial || e->x.p->type == flooring ||
84 e->x.p->type == fractional);
85 int offset = type_offset(e->x.p);
86 for (int i = e->x.p->size-1; i >= offset; --i) {
87 if (EVALUE_IS_ZERO(e->x.p->arr[i]))
88 continue;
89 if (i != e->x.p->size-1 &&
90 (value_zero_p(e->x.p->arr[i].d) ||
91 value_pos_p(e->x.p->arr[i].x.n)))
92 o << "+";
93 if (i == offset || !(value_one_p(e->x.p->arr[i].x.n) &&
94 d == VALUE_TO_INT(e->x.p->arr[i].d))) {
95 if (value_zero_p(e->x.p->arr[i].d))
96 o << "(";
97 evalue_print(o, &e->x.p->arr[i], p, d);
98 if (value_zero_p(e->x.p->arr[i].d))
99 o << ")";
100 if (i != offset)
101 o << "*";
103 for (int j = 0; j < i-offset; ++j) {
104 if (j != 0)
105 o << "*";
106 if (e->x.p->type == flooring) {
107 o << "[";
108 evalue_print(o, &e->x.p->arr[0], p);
109 o << "]";
110 } else if (e->x.p->type == fractional) {
111 o << "{";
112 evalue_print(o, &e->x.p->arr[0], p);
113 o << "}";
114 } else
115 o << p[e->x.p->pos-1];
120 static void evalue_print(std::ostream& o, evalue *e, char **p)
122 Value d;
123 value_init(d);
124 value_set_si(d, 1);
125 evalue_denom(e, &d);
126 if (value_notone_p(d))
127 o << "(";
128 evalue_print(o, e, p, VALUE_TO_INT(d));
129 if (value_notone_p(d))
130 o << ")/" << VALUE_TO_INT(d);
131 value_clear(d);
134 struct indicator_term {
135 int sign;
136 mat_ZZ den;
137 evalue **vertex;
139 indicator_term(unsigned dim) {
140 den.SetDims(dim, dim);
141 vertex = new evalue* [dim];
143 indicator_term(const indicator_term& src) {
144 sign = src.sign;
145 den = src.den;
146 unsigned dim = den.NumCols();
147 vertex = new evalue* [dim];
148 for (int i = 0; i < dim; ++i) {
149 vertex[i] = new evalue();
150 value_init(vertex[i]->d);
151 evalue_copy(vertex[i], src.vertex[i]);
154 ~indicator_term() {
155 unsigned dim = den.NumCols();
156 for (int i = 0; i < dim; ++i) {
157 free_evalue_refs(vertex[i]);
158 delete vertex[i];
160 delete [] vertex;
162 void print(ostream& os, char **p);
163 void substitute(Matrix *T);
164 void substitute(evalue *fract, evalue *val);
165 void substitute(int pos, evalue *val);
166 void reduce_in_domain(Polyhedron *D);
169 void indicator_term::reduce_in_domain(Polyhedron *D)
171 for (int k = 0; k < den.NumCols(); ++k) {
172 reduce_evalue_in_domain(vertex[k], D);
173 if (evalue_range_reduction_in_domain(vertex[k], D))
174 reduce_evalue(vertex[k]);
178 void indicator_term::print(ostream& os, char **p)
180 unsigned dim = den.NumCols();
181 unsigned factors = den.NumRows();
182 if (sign > 0)
183 os << " + ";
184 else
185 os << " - ";
186 os << '[';
187 for (int i = 0; i < dim; ++i) {
188 if (i)
189 os << ',';
190 evalue_print(os, vertex[i], p);
192 os << ']';
193 for (int i = 0; i < factors; ++i) {
194 os << " + t" << i << "*[";
195 for (int j = 0; j < dim; ++j) {
196 if (j)
197 os << ',';
198 os << den[i][j];
200 os << "]";
204 /* Perform the substitution specified by T on the variables.
205 * T has dimension (newdim+nparam+1) x (olddim + nparam + 1).
206 * The substitution is performed as in gen_fun::substitute
208 void indicator_term::substitute(Matrix *T)
210 unsigned dim = den.NumCols();
211 unsigned nparam = T->NbColumns - dim - 1;
212 unsigned newdim = T->NbRows - nparam - 1;
213 evalue **newvertex;
214 mat_ZZ trans;
215 matrix2zz(T, trans, newdim, dim);
216 trans = transpose(trans);
217 den *= trans;
218 newvertex = new evalue* [newdim];
220 vec_ZZ v;
221 v.SetLength(nparam+1);
223 evalue factor;
224 value_init(factor.d);
225 value_set_si(factor.d, 1);
226 value_init(factor.x.n);
227 for (int i = 0; i < newdim; ++i) {
228 values2zz(T->p[i]+dim, v, nparam+1);
229 newvertex[i] = multi_monom(v);
231 for (int j = 0; j < dim; ++j) {
232 if (value_zero_p(T->p[i][j]))
233 continue;
234 evalue term;
235 value_init(term.d);
236 evalue_copy(&term, vertex[j]);
237 value_assign(factor.x.n, T->p[i][j]);
238 emul(&factor, &term);
239 eadd(&term, newvertex[i]);
240 free_evalue_refs(&term);
243 free_evalue_refs(&factor);
244 for (int i = 0; i < dim; ++i) {
245 free_evalue_refs(vertex[i]);
246 delete vertex[i];
248 delete [] vertex;
249 vertex = newvertex;
252 static void substitute(evalue *e, evalue *fract, evalue *val)
254 evalue *t;
256 for (t = e; value_zero_p(t->d); t = &t->x.p->arr[type_offset(t->x.p)]) {
257 if (t->x.p->type == fractional && eequal(&t->x.p->arr[0], fract))
258 break;
260 if (value_notzero_p(t->d))
261 return;
263 free_evalue_refs(&t->x.p->arr[0]);
264 evalue *term = &t->x.p->arr[2];
265 enode *p = t->x.p;
266 value_clear(t->d);
267 *t = t->x.p->arr[1];
269 emul(val, term);
270 eadd(term, e);
271 free_evalue_refs(term);
272 free(p);
274 reduce_evalue(e);
277 void indicator_term::substitute(evalue *fract, evalue *val)
279 unsigned dim = den.NumCols();
280 for (int i = 0; i < dim; ++i) {
281 ::substitute(vertex[i], fract, val);
285 static void substitute(evalue *e, int pos, evalue *val)
287 evalue *t;
289 for (t = e; value_zero_p(t->d); t = &t->x.p->arr[type_offset(t->x.p)]) {
290 if (t->x.p->type == polynomial && t->x.p->pos == pos)
291 break;
293 if (value_notzero_p(t->d))
294 return;
296 evalue *term = &t->x.p->arr[1];
297 enode *p = t->x.p;
298 value_clear(t->d);
299 *t = t->x.p->arr[0];
301 emul(val, term);
302 eadd(term, e);
303 free_evalue_refs(term);
304 free(p);
306 reduce_evalue(e);
309 void indicator_term::substitute(int pos, evalue *val)
311 unsigned dim = den.NumCols();
312 for (int i = 0; i < dim; ++i) {
313 ::substitute(vertex[i], pos, val);
317 struct indicator_constructor : public polar_decomposer, public vertex_decomposer {
318 vec_ZZ vertex;
319 vector<indicator_term*> *terms;
321 indicator_constructor(Polyhedron *P, unsigned dim, unsigned nbV) :
322 vertex_decomposer(P, nbV, this) {
323 vertex.SetLength(dim);
324 terms = new vector<indicator_term*>[nbV];
326 ~indicator_constructor() {
327 for (int i = 0; i < nbV; ++i)
328 for (int j = 0; j < terms[i].size(); ++j)
329 delete terms[i][j];
330 delete [] terms;
332 void substitute(Matrix *T);
333 void normalize();
334 void print(ostream& os, char **p);
336 virtual void handle_polar(Polyhedron *P, int sign);
339 static void evalue_add_constant(evalue *e, ZZ v)
341 Value tmp;
342 value_init(tmp);
344 /* go down to constant term */
345 while (value_zero_p(e->d))
346 e = &e->x.p->arr[type_offset(e->x.p)];
347 /* and add v */
348 zz2value(v, tmp);
349 value_multiply(tmp, tmp, e->d);
350 value_addto(e->x.n, e->x.n, tmp);
352 value_clear(tmp);
355 void indicator_constructor::handle_polar(Polyhedron *C, int s)
357 unsigned dim = vertex.length();
359 assert(C->NbRays-1 == dim);
361 indicator_term *term = new indicator_term(dim);
362 term->sign = s;
363 terms[vert].push_back(term);
365 lattice_point(V, C, vertex, term->vertex);
367 for (int r = 0; r < dim; ++r) {
368 values2zz(C->Ray[r]+1, term->den[r], dim);
369 for (int j = 0; j < dim; ++j) {
370 if (term->den[r][j] == 0)
371 continue;
372 if (term->den[r][j] > 0)
373 break;
374 term->sign = -term->sign;
375 term->den[r] = -term->den[r];
376 vertex += term->den[r];
377 break;
380 lex_order_rows(term->den);
382 for (int i = 0; i < dim; ++i) {
383 if (!term->vertex[i]) {
384 term->vertex[i] = new evalue();
385 value_init(term->vertex[i]->d);
386 value_init(term->vertex[i]->x.n);
387 zz2value(vertex[i], term->vertex[i]->x.n);
388 value_set_si(term->vertex[i]->d, 1);
389 continue;
391 if (vertex[i] == 0)
392 continue;
393 evalue_add_constant(term->vertex[i], vertex[i]);
397 void indicator_constructor::substitute(Matrix *T)
399 for (int i = 0; i < nbV; ++i)
400 for (int j = 0; j < terms[i].size(); ++j)
401 terms[i][j]->substitute(T);
404 void indicator_constructor::print(ostream& os, char **p)
406 for (int i = 0; i < nbV; ++i)
407 for (int j = 0; j < terms[i].size(); ++j) {
408 os << "i: " << i << ", j: " << j << endl;
409 terms[i][j]->print(os, p);
410 os << endl;
414 void indicator_constructor::normalize()
416 for (int i = 0; i < nbV; ++i)
417 for (int j = 0; j < terms[i].size(); ++j) {
418 vec_ZZ vertex;
419 vertex.SetLength(terms[i][j]->den.NumCols());
420 for (int r = 0; r < terms[i][j]->den.NumRows(); ++r) {
421 for (int k = 0; k < terms[i][j]->den.NumCols(); ++k) {
422 if (terms[i][j]->den[r][k] == 0)
423 continue;
424 if (terms[i][j]->den[r][k] > 0)
425 break;
426 terms[i][j]->sign = -terms[i][j]->sign;
427 terms[i][j]->den[r] = -terms[i][j]->den[r];
428 vertex += terms[i][j]->den[r];
429 break;
432 lex_order_rows(terms[i][j]->den);
433 for (int k = 0; k < vertex.length(); ++k)
434 if (vertex[k] != 0)
435 evalue_add_constant(terms[i][j]->vertex[k], vertex[k]);
439 struct indicator {
440 vector<indicator_term*> term;
442 indicator() {}
443 indicator(const indicator& ind) {
444 for (int i = 0; i < ind.term.size(); ++i)
445 term.push_back(new indicator_term(*ind.term[i]));
447 ~indicator() {
448 for (int i = 0; i < term.size(); ++i)
449 delete term[i];
452 void print(ostream& os, char **p);
453 void simplify();
454 void peel(int i, int j);
455 void combine(int i, int j);
456 void substitute(evalue *equation);
457 void reduce_in_domain(Polyhedron *D);
460 void indicator::reduce_in_domain(Polyhedron *D)
462 for (int i = 0; i < term.size(); ++i)
463 term[i]->reduce_in_domain(D);
466 void indicator::print(ostream& os, char **p)
468 for (int i = 0; i < term.size(); ++i) {
469 term[i]->print(os, p);
470 os << endl;
474 /* Remove pairs of opposite terms */
475 void indicator::simplify()
477 for (int i = 0; i < term.size(); ++i) {
478 for (int j = i+1; j < term.size(); ++j) {
479 if (term[i]->sign + term[j]->sign != 0)
480 continue;
481 if (term[i]->den != term[j]->den)
482 continue;
483 int k;
484 for (k = 0; k < term[i]->den.NumCols(); ++k)
485 if (!eequal(term[i]->vertex[k], term[j]->vertex[k]))
486 break;
487 if (k < term[i]->den.NumCols())
488 continue;
489 delete term[i];
490 delete term[j];
491 term.erase(term.begin()+j);
492 term.erase(term.begin()+i);
493 --i;
494 break;
499 void indicator::peel(int i, int j)
501 if (j < i) {
502 int tmp = i;
503 i = j;
504 j = tmp;
506 assert (i < j);
507 int dim = term[i]->den.NumCols();
509 mat_ZZ common;
510 mat_ZZ rest_i;
511 mat_ZZ rest_j;
512 int n_common = 0, n_i = 0, n_j = 0;
514 common.SetDims(min(term[i]->den.NumRows(), term[j]->den.NumRows()), dim);
515 rest_i.SetDims(term[i]->den.NumRows(), dim);
516 rest_j.SetDims(term[j]->den.NumRows(), dim);
518 int k, l;
519 for (k = 0, l = 0; k < term[i]->den.NumRows() && l < term[j]->den.NumRows(); ) {
520 int s = lex_cmp(term[i]->den[k], term[j]->den[l]);
521 if (s == 0) {
522 common[n_common++] = term[i]->den[k];
523 ++k;
524 ++l;
525 } else if (s < 0)
526 rest_i[n_i++] = term[i]->den[k++];
527 else
528 rest_j[n_j++] = term[j]->den[l++];
530 while (k < term[i]->den.NumRows())
531 rest_i[n_i++] = term[i]->den[k++];
532 while (l < term[j]->den.NumRows())
533 rest_j[n_j++] = term[j]->den[l++];
534 common.SetDims(n_common, dim);
535 rest_i.SetDims(n_i, dim);
536 rest_j.SetDims(n_j, dim);
538 for (k = 0; k <= n_i; ++k) {
539 indicator_term *it = new indicator_term(*term[i]);
540 it->den.SetDims(n_common + k, dim);
541 for (l = 0; l < n_common; ++l)
542 it->den[l] = common[l];
543 for (l = 0; l < k; ++l)
544 it->den[n_common+l] = rest_i[l];
545 lex_order_rows(it->den);
546 if (k)
547 for (l = 0; l < dim; ++l)
548 evalue_add_constant(it->vertex[l], rest_i[k-1][l]);
549 term.push_back(it);
552 for (k = 0; k <= n_j; ++k) {
553 indicator_term *it = new indicator_term(*term[j]);
554 it->den.SetDims(n_common + k, dim);
555 for (l = 0; l < n_common; ++l)
556 it->den[l] = common[l];
557 for (l = 0; l < k; ++l)
558 it->den[n_common+l] = rest_j[l];
559 lex_order_rows(it->den);
560 if (k)
561 for (l = 0; l < dim; ++l)
562 evalue_add_constant(it->vertex[l], rest_j[k-1][l]);
563 term.push_back(it);
565 term.erase(term.begin()+j);
566 term.erase(term.begin()+i);
569 void indicator::combine(int i, int j)
571 if (j < i) {
572 int tmp = i;
573 i = j;
574 j = tmp;
576 assert (i < j);
577 int dim = term[i]->den.NumCols();
579 mat_ZZ common;
580 mat_ZZ rest_i;
581 mat_ZZ rest_j;
582 int n_common = 0, n_i = 0, n_j = 0;
584 common.SetDims(min(term[i]->den.NumRows(), term[j]->den.NumRows()), dim);
585 rest_i.SetDims(term[i]->den.NumRows(), dim);
586 rest_j.SetDims(term[j]->den.NumRows(), dim);
588 int k, l;
589 for (k = 0, l = 0; k < term[i]->den.NumRows() && l < term[j]->den.NumRows(); ) {
590 int s = lex_cmp(term[i]->den[k], term[j]->den[l]);
591 if (s == 0) {
592 common[n_common++] = term[i]->den[k];
593 ++k;
594 ++l;
595 } else if (s < 0)
596 rest_i[n_i++] = term[i]->den[k++];
597 else
598 rest_j[n_j++] = term[j]->den[l++];
600 while (k < term[i]->den.NumRows())
601 rest_i[n_i++] = term[i]->den[k++];
602 while (l < term[j]->den.NumRows())
603 rest_j[n_j++] = term[j]->den[l++];
604 common.SetDims(n_common, dim);
605 rest_i.SetDims(n_i, dim);
606 rest_j.SetDims(n_j, dim);
608 assert(n_i < 30);
609 assert(n_j < 30);
611 for (k = 0; k < (1 << n_i); ++k) {
612 indicator_term *it = new indicator_term(*term[j]);
613 it->den.SetDims(n_common + n_i + n_j, dim);
614 for (l = 0; l < n_common; ++l)
615 it->den[l] = common[l];
616 for (l = 0; l < n_i; ++l)
617 it->den[n_common+l] = rest_i[l];
618 for (l = 0; l < n_j; ++l)
619 it->den[n_common+n_i+l] = rest_j[l];
620 lex_order_rows(it->den);
621 int change = 0;
622 for (l = 0; l < n_i; ++l) {
623 if (!(k & (1 <<l)))
624 continue;
625 change ^= 1;
626 for (int m = 0; m < dim; ++m)
627 evalue_add_constant(it->vertex[m], rest_i[l][m]);
629 if (change)
630 it->sign = -it->sign;
631 term.push_back(it);
634 for (k = 0; k < (1 << n_j); ++k) {
635 indicator_term *it = new indicator_term(*term[i]);
636 it->den.SetDims(n_common + n_i + n_j, dim);
637 for (l = 0; l < n_common; ++l)
638 it->den[l] = common[l];
639 for (l = 0; l < n_i; ++l)
640 it->den[n_common+l] = rest_i[l];
641 for (l = 0; l < n_j; ++l)
642 it->den[n_common+n_i+l] = rest_j[l];
643 lex_order_rows(it->den);
644 int change = 0;
645 for (l = 0; l < n_j; ++l) {
646 if (!(k & (1 <<l)))
647 continue;
648 change ^= 1;
649 for (int m = 0; m < dim; ++m)
650 evalue_add_constant(it->vertex[m], rest_j[l][m]);
652 if (change)
653 it->sign = -it->sign;
654 term.push_back(it);
656 delete term[i];
657 delete term[j];
658 term.erase(term.begin()+j);
659 term.erase(term.begin()+i);
662 void indicator::substitute(evalue *equation)
664 evalue *fract = NULL;
665 evalue *val = new evalue;
666 value_init(val->d);
667 evalue_copy(val, equation);
669 evalue factor;
670 value_init(factor.d);
671 value_init(factor.x.n);
673 evalue *e;
674 for (e = val; value_zero_p(e->d) && e->x.p->type != fractional;
675 e = &e->x.p->arr[type_offset(e->x.p)])
678 if (value_zero_p(e->d) && e->x.p->type == fractional)
679 fract = &e->x.p->arr[0];
680 else {
681 for (e = val; value_zero_p(e->d) && e->x.p->type != polynomial;
682 e = &e->x.p->arr[type_offset(e->x.p)])
684 assert(value_zero_p(e->d) && e->x.p->type == polynomial);
687 int offset = type_offset(e->x.p);
689 assert(value_notzero_p(e->x.p->arr[offset+1].d));
690 assert(value_notzero_p(e->x.p->arr[offset+1].x.n));
691 if (value_neg_p(e->x.p->arr[offset+1].x.n)) {
692 value_oppose(factor.d, e->x.p->arr[offset+1].x.n);
693 value_assign(factor.x.n, e->x.p->arr[offset+1].d);
694 } else {
695 value_assign(factor.d, e->x.p->arr[offset+1].x.n);
696 value_oppose(factor.x.n, e->x.p->arr[offset+1].d);
699 free_evalue_refs(&e->x.p->arr[offset+1]);
700 enode *p = e->x.p;
701 value_clear(e->d);
702 *e = e->x.p->arr[offset];
704 emul(&factor, val);
706 if (fract) {
707 for (int i = 0; i < term.size(); ++i)
708 term[i]->substitute(fract, val);
710 free_evalue_refs(&p->arr[0]);
711 } else {
712 for (int i = 0; i < term.size(); ++i)
713 term[i]->substitute(p->pos, val);
716 free_evalue_refs(&factor);
717 free_evalue_refs(val);
718 delete val;
720 free(p);
723 static void add_coeff(Value *cons, int len, evalue *coeff, int pos)
725 Value tmp;
727 assert(value_notzero_p(coeff->d));
729 value_init(tmp);
731 value_lcm(cons[0], coeff->d, &tmp);
732 value_division(tmp, tmp, cons[0]);
733 Vector_Scale(cons, cons, tmp, len);
734 value_division(tmp, cons[0], coeff->d);
735 value_addmul(cons[pos], tmp, coeff->x.n);
737 value_clear(tmp);
740 struct EDomain {
741 Polyhedron *D;
742 Vector *sample;
743 vector<evalue *> floors;
745 EDomain(Polyhedron *D) {
746 this->D = Polyhedron_Copy(D);
747 sample = NULL;
749 EDomain(Polyhedron *D, vector<evalue *>floors) {
750 this->D = Polyhedron_Copy(D);
751 add_floors(floors);
752 sample = NULL;
754 EDomain(Polyhedron *D, EDomain *ED, vector<evalue *>floors) {
755 this->D = Polyhedron_Copy(D);
756 add_floors(ED->floors);
757 add_floors(floors);
758 sample = NULL;
760 void add_floors(vector<evalue *>floors) {
761 for (int i = 0; i < floors.size(); ++i) {
762 evalue *f = new evalue;
763 value_init(f->d);
764 evalue_copy(f, floors[i]);
765 this->floors.push_back(f);
768 int find_floor(evalue *needle) {
769 for (int i = 0; i < floors.size(); ++i)
770 if (eequal(needle, floors[i]))
771 return i;
772 return -1;
774 void print(FILE *out, char **p);
775 ~EDomain() {
776 for (int i = 0; i < floors.size(); ++i) {
777 free_evalue_refs(floors[i]);
778 delete floors[i];
780 Polyhedron_Free(D);
781 if (sample)
782 Vector_Free(sample);
786 void EDomain::print(FILE *out, char **p)
788 fdostream os(dup(fileno(out)));
789 for (int i = 0; i < floors.size(); ++i) {
790 os << "floor " << i << ": [";
791 evalue_print(os, floors[i], p);
792 os << "]" << endl;
794 Polyhedron_Print(out, P_VALUE_FMT, D);
797 static int evalue2constraint_r(EDomain *D, evalue *E, Value *cons, int len);
799 static void add_fract(evalue *e, Value *cons, int len, int pos)
801 evalue mone;
802 value_init(mone.d);
803 evalue_set_si(&mone, -1, 1);
805 /* contribution of alpha * fract(X) is
806 * alpha * X ...
808 assert(e->x.p->size == 3);
809 evalue argument;
810 value_init(argument.d);
811 evalue_copy(&argument, &e->x.p->arr[0]);
812 emul(&e->x.p->arr[2], &argument);
813 evalue2constraint_r(NULL, &argument, cons, len);
814 free_evalue_refs(&argument);
816 /* - alpha * floor(X) */
817 emul(&mone, &e->x.p->arr[2]);
818 add_coeff(cons, len, &e->x.p->arr[2], pos);
819 emul(&mone, &e->x.p->arr[2]);
821 free_evalue_refs(&mone);
824 static int evalue2constraint_r(EDomain *D, evalue *E, Value *cons, int len)
826 int r = 0;
827 if (value_zero_p(E->d) && E->x.p->type == fractional) {
828 int i;
829 assert(E->x.p->size == 3);
830 r = evalue2constraint_r(D, &E->x.p->arr[1], cons, len);
831 assert(value_notzero_p(E->x.p->arr[2].d));
832 if (D && (i = D->find_floor(&E->x.p->arr[0])) >= 0) {
833 add_fract(E, cons, len, 1+D->D->Dimension-D->floors.size()+i);
834 } else {
835 if (value_pos_p(E->x.p->arr[2].x.n)) {
836 evalue coeff;
837 value_init(coeff.d);
838 value_init(coeff.x.n);
839 value_set_si(coeff.d, 1);
840 evalue_denom(&E->x.p->arr[0], &coeff.d);
841 value_decrement(coeff.x.n, coeff.d);
842 emul(&E->x.p->arr[2], &coeff);
843 add_coeff(cons, len, &coeff, len-1);
844 free_evalue_refs(&coeff);
846 r = 1;
848 } else if (value_zero_p(E->d)) {
849 assert(E->x.p->type == polynomial);
850 assert(E->x.p->size == 2);
851 r = evalue2constraint_r(D, &E->x.p->arr[0], cons, len) || r;
852 add_coeff(cons, len, &E->x.p->arr[1], E->x.p->pos);
853 } else {
854 add_coeff(cons, len, E, len-1);
856 return r;
859 static int evalue2constraint(EDomain *D, evalue *E, Value *cons, int len)
861 Vector_Set(cons, 0, len);
862 value_set_si(cons[0], 1);
863 return evalue2constraint_r(D, E, cons, len);
866 static void interval_minmax(Polyhedron *I, int *min, int *max)
868 assert(I->Dimension == 1);
869 *min = 1;
870 *max = -1;
871 POL_ENSURE_VERTICES(I);
872 for (int i = 0; i < I->NbRays; ++i) {
873 if (value_pos_p(I->Ray[i][1]))
874 *max = 1;
875 else if (value_neg_p(I->Ray[i][1]))
876 *min = -1;
877 else {
878 if (*max < 0)
879 *max = 0;
880 if (*min > 0)
881 *min = 0;
886 static void interval_minmax(Polyhedron *D, Matrix *T, int *min, int *max,
887 unsigned MaxRays)
889 Polyhedron *I = Polyhedron_Image(D, T, MaxRays);
890 I = DomainConstraintSimplify(I, MaxRays);
891 if (emptyQ2(I)) {
892 Polyhedron_Free(I);
893 I = Polyhedron_Image(D, T, MaxRays);
895 interval_minmax(I, min, max);
896 Polyhedron_Free(I);
899 struct max_term {
900 unsigned dim;
901 Polyhedron *domain;
902 vector<evalue *> max;
904 void print(ostream& os, char **p) const;
905 void resolve_existential_vars() const;
906 void substitute(Matrix *T, unsigned MaxRays);
907 Vector *eval(Value *val, unsigned MaxRays) const;
909 ~max_term() {
910 for (int i = 0; i < max.size(); ++i) {
911 free_evalue_refs(max[i]);
912 delete max[i];
914 Polyhedron_Free(domain);
918 static void print_varlist(ostream& os, int n, char **names)
920 int i;
921 os << "[";
922 for (i = 0; i < n; ++i) {
923 if (i)
924 os << ",";
925 os << names[i];
927 os << "]";
930 static void print_term(ostream& os, Value v, int pos, int dim,
931 char **names, int *first)
933 if (value_zero_p(v)) {
934 if (first && *first && pos >= dim)
935 os << "0";
936 return;
939 if (first) {
940 if (!*first && value_pos_p(v))
941 os << "+";
942 *first = 0;
944 if (pos < dim) {
945 if (value_mone_p(v)) {
946 os << "-";
947 } else if (!value_one_p(v))
948 os << VALUE_TO_INT(v);
949 os << names[pos];
950 } else
951 os << VALUE_TO_INT(v);
954 /* We put all possible existentially quantified variables at the back
955 * and so if any equalities exist between these variables and the
956 * other variables, then PolyLib will replace all occurrences of some
957 * of the other variables by some existentially quantified variables.
958 * We want the output to have as few as possible references to the
959 * existentially quantified variables, so we undo what PolyLib did here.
961 void resolve_existential_vars(Polyhedron *domain, unsigned dim)
963 int last = domain->NbEq - 1;
964 /* Matrix "view" of domain for ExchangeRows */
965 Matrix M;
966 M.NbRows = domain->NbConstraints;
967 M.NbColumns = domain->Dimension+2;
968 M.p_Init = domain->p_Init;
969 M.p = domain->Constraint;
970 Value mone;
971 value_init(mone);
972 value_set_si(mone, -1);
973 for (int e = domain->Dimension-1; e >= dim; --e) {
974 int r;
975 for (r = last; r >= 0; --r)
976 if (value_notzero_p(domain->Constraint[r][1+e]))
977 break;
978 if (r < 0)
979 continue;
980 if (r != last)
981 ExchangeRows(&M, r, last);
983 /* Combine uses the coefficient as a multiplier, so it must
984 * be positive, since we are modifying an inequality.
986 if (value_neg_p(domain->Constraint[last][1+e]))
987 Vector_Scale(domain->Constraint[last]+1, domain->Constraint[last]+1,
988 mone, domain->Dimension+1);
990 for (int c = 0; c < domain->NbConstraints; ++c) {
991 if (c == last)
992 continue;
993 if (value_notzero_p(domain->Constraint[c][1+e]))
994 Combine(domain->Constraint[c], domain->Constraint[last],
995 domain->Constraint[c], 1+e, domain->Dimension+1);
997 --last;
999 value_clear(mone);
1002 void max_term::resolve_existential_vars() const
1004 ::resolve_existential_vars(domain, dim);
1007 void max_term::print(ostream& os, char **p) const
1009 char **names = p;
1010 if (dim < domain->Dimension) {
1011 resolve_existential_vars();
1012 names = new char * [domain->Dimension];
1013 int i;
1014 for (i = 0; i < dim; ++i)
1015 names[i] = p[i];
1016 for ( ; i < domain->Dimension; ++i) {
1017 names[i] = new char[10];
1018 snprintf(names[i], 10, "a%d", i - dim);
1022 Value tmp;
1023 value_init(tmp);
1024 os << "{ ";
1025 print_varlist(os, dim, p);
1026 os << " -> ";
1027 os << "[";
1028 for (int i = 0; i < max.size(); ++i) {
1029 if (i)
1030 os << ",";
1031 evalue_print(os, max[i], p);
1033 os << "]";
1034 os << " : ";
1035 if (dim < domain->Dimension) {
1036 os << "exists ";
1037 print_varlist(os, domain->Dimension-dim, names+dim);
1038 os << " : ";
1040 for (int i = 0; i < domain->NbConstraints; ++i) {
1041 int first = 1;
1042 int v = First_Non_Zero(domain->Constraint[i]+1, domain->Dimension);
1043 if (v == -1)
1044 continue;
1045 if (i)
1046 os << " && ";
1047 if (value_pos_p(domain->Constraint[i][v+1])) {
1048 print_term(os, domain->Constraint[i][v+1], v, domain->Dimension,
1049 names, NULL);
1050 if (value_zero_p(domain->Constraint[i][0]))
1051 os << " = ";
1052 else
1053 os << " >= ";
1054 for (int j = v+1; j <= domain->Dimension; ++j) {
1055 value_oppose(tmp, domain->Constraint[i][1+j]);
1056 print_term(os, tmp, j, domain->Dimension,
1057 names, &first);
1059 } else {
1060 value_oppose(tmp, domain->Constraint[i][1+v]);
1061 print_term(os, tmp, v, domain->Dimension,
1062 names, NULL);
1063 if (value_zero_p(domain->Constraint[i][0]))
1064 os << " = ";
1065 else
1066 os << " <= ";
1067 for (int j = v+1; j <= domain->Dimension; ++j)
1068 print_term(os, domain->Constraint[i][1+j], j, domain->Dimension,
1069 names, &first);
1072 os << " }" << endl;
1073 value_clear(tmp);
1075 if (dim < domain->Dimension) {
1076 for (int i = dim; i < domain->Dimension; ++i)
1077 delete [] names[i];
1078 delete [] names;
1082 static void evalue_substitute(evalue *e, evalue **subs)
1084 evalue *v;
1086 if (value_notzero_p(e->d))
1087 return;
1089 enode *p = e->x.p;
1090 for (int i = 0; i < p->size; ++i)
1091 evalue_substitute(&p->arr[i], subs);
1093 if (p->type == polynomial)
1094 v = subs[p->pos-1];
1095 else {
1096 v = new evalue;
1097 value_init(v->d);
1098 value_set_si(v->d, 0);
1099 v->x.p = new_enode(p->type, 3, -1);
1100 value_clear(v->x.p->arr[0].d);
1101 v->x.p->arr[0] = p->arr[0];
1102 evalue_set_si(&v->x.p->arr[1], 0, 1);
1103 evalue_set_si(&v->x.p->arr[2], 1, 1);
1106 int offset = type_offset(p);
1108 for (int i = p->size-1; i >= offset+1; i--) {
1109 emul(v, &p->arr[i]);
1110 eadd(&p->arr[i], &p->arr[i-1]);
1111 free_evalue_refs(&(p->arr[i]));
1114 if (p->type != polynomial) {
1115 free_evalue_refs(v);
1116 delete v;
1119 value_clear(e->d);
1120 *e = p->arr[offset];
1121 free(p);
1124 /* T maps the compressed parameters to the original parameters,
1125 * while this max_term is based on the compressed parameters
1126 * and we want get the original parameters back.
1128 void max_term::substitute(Matrix *T, unsigned MaxRays)
1130 int nexist = 0;
1131 for (int i = 0; i < T->NbRows-1; ++i)
1132 if (value_notone_p(T->p[i][i]))
1133 ++nexist;
1135 Matrix *M = Matrix_Alloc(T->NbRows + nexist, T->NbColumns);
1136 nexist = 0;
1137 for (int i = 0; i < T->NbRows-1; ++i) {
1138 Vector_Copy(T->p[i], M->p[i], T->NbColumns);
1139 if (value_notone_p(T->p[i][i]))
1140 value_set_si(M->p[T->NbRows-1 + nexist++][i], 1);
1142 value_assign(M->p[M->NbRows-1][M->NbColumns-1],
1143 T->p[T->NbRows-1][T->NbColumns-1]);
1145 Polyhedron *D = DomainImage(domain, M, MaxRays);
1146 Polyhedron_Free(domain);
1147 domain = D;
1148 Matrix_Free(M);
1150 assert(T->NbRows == T->NbColumns);
1151 Matrix *inv = Matrix_Alloc(T->NbColumns, T->NbRows);
1152 int ok = Matrix_Inverse(T, inv);
1153 assert(ok);
1155 evalue denom;
1156 value_init(denom.d);
1157 value_init(denom.x.n);
1158 value_set_si(denom.x.n, 1);
1159 value_assign(denom.d, inv->p[inv->NbRows-1][inv->NbColumns-1]);
1161 vec_ZZ v;
1162 v.SetLength(inv->NbColumns);
1163 evalue* subs[inv->NbRows-1];
1164 for (int i = 0; i < inv->NbRows-1; ++i) {
1165 values2zz(inv->p[i], v, v.length());
1166 subs[i] = multi_monom(v);
1167 emul(&denom, subs[i]);
1169 free_evalue_refs(&denom);
1171 for (int i = 0; i < max.size(); ++i) {
1172 evalue_substitute(max[i], subs);
1173 reduce_evalue(max[i]);
1176 for (int i = 0; i < inv->NbRows-1; ++i) {
1177 free_evalue_refs(subs[i]);
1178 delete subs[i];
1180 Matrix_Free(inv);
1183 int Last_Non_Zero(Value *p, unsigned len)
1185 for (int i = len-1; i >= 0; --i)
1186 if (value_notzero_p(p[i]))
1187 return i;
1188 return -1;
1191 static void SwapColumns(Value **V, int n, int i, int j)
1193 for (int r = 0; r < n; ++r)
1194 value_swap(V[r][i], V[r][j]);
1197 static void SwapColumns(Polyhedron *P, int i, int j)
1199 SwapColumns(P->Constraint, P->NbConstraints, i, j);
1200 SwapColumns(P->Ray, P->NbRays, i, j);
1203 bool in_domain(Polyhedron *P, Value *val, unsigned dim, unsigned MaxRays)
1205 int nexist = P->Dimension - dim;
1206 int last[P->NbConstraints];
1207 Value tmp, min, max;
1208 Vector *all_val = Vector_Alloc(P->Dimension+1);
1209 bool in = false;
1210 int i;
1211 int alternate;
1213 resolve_existential_vars(P, dim);
1215 Vector_Copy(val, all_val->p, dim);
1216 value_set_si(all_val->p[P->Dimension], 1);
1218 value_init(tmp);
1219 for (int i = 0; i < P->NbConstraints; ++i) {
1220 last[i] = Last_Non_Zero(P->Constraint[i]+1+dim, nexist);
1221 if (last[i] == -1) {
1222 Inner_Product(P->Constraint[i]+1, all_val->p, P->Dimension+1, &tmp);
1223 if (value_neg_p(tmp))
1224 goto out;
1225 if (i < P->NbEq && value_pos_p(tmp))
1226 goto out;
1230 value_init(min);
1231 value_init(max);
1232 alternate = nexist - 1;
1233 for (i = 0; i < nexist; ++i) {
1234 bool min_set = false;
1235 bool max_set = false;
1236 for (int j = 0; j < P->NbConstraints; ++j) {
1237 if (last[j] != i)
1238 continue;
1239 Inner_Product(P->Constraint[j]+1, all_val->p, P->Dimension+1, &tmp);
1240 value_oppose(tmp, tmp);
1241 if (j < P->NbEq) {
1242 if (!mpz_divisible_p(tmp, P->Constraint[j][1+dim+i]))
1243 goto out2;
1244 value_division(tmp, tmp, P->Constraint[j][1+dim+i]);
1245 if (!max_set || value_lt(tmp, max)) {
1246 max_set = true;
1247 value_assign(max, tmp);
1249 if (!min_set || value_gt(tmp, min)) {
1250 min_set = true;
1251 value_assign(min, tmp);
1253 } else {
1254 if (value_pos_p(P->Constraint[j][1+dim+i])) {
1255 mpz_cdiv_q(tmp, tmp, P->Constraint[j][1+dim+i]);
1256 if (!min_set || value_gt(tmp, min)) {
1257 min_set = true;
1258 value_assign(min, tmp);
1260 } else {
1261 mpz_fdiv_q(tmp, tmp, P->Constraint[j][1+dim+i]);
1262 if (!max_set || value_lt(tmp, max)) {
1263 max_set = true;
1264 value_assign(max, tmp);
1269 /* Move another existential variable in current position */
1270 if (!max_set || !min_set) {
1271 if (!(alternate > i)) {
1272 Matrix *M = Matrix_Alloc(dim+i, 1+P->Dimension+1);
1273 for (int j = 0; j < dim+i; ++j) {
1274 value_set_si(M->p[j][1+j], -1);
1275 value_assign(M->p[j][1+P->Dimension], all_val->p[j]);
1277 Polyhedron *Q = AddConstraints(M->p[0], dim+i, P, MaxRays);
1278 Matrix_Free(M);
1279 Q = DomainConstraintSimplify(Q, MaxRays);
1280 Vector *sample = Polyhedron_Sample(Q, MaxRays);
1281 in = !!sample;
1282 if (sample)
1283 Vector_Free(sample);
1284 Polyhedron_Free(Q);
1285 goto out2;
1287 assert(alternate > i);
1288 SwapColumns(P, 1+dim+i, 1+dim+alternate);
1289 resolve_existential_vars(P, dim);
1290 for (int j = 0; j < P->NbConstraints; ++j) {
1291 if (j >= P->NbEq && last[j] < i)
1292 continue;
1293 last[j] = Last_Non_Zero(P->Constraint[j]+1+dim, nexist);
1294 if (last[j] < i) {
1295 Inner_Product(P->Constraint[j]+1, all_val->p, P->Dimension+1,
1296 &tmp);
1297 if (value_neg_p(tmp))
1298 goto out2;
1299 if (j < P->NbEq && value_pos_p(tmp))
1300 goto out2;
1303 --alternate;
1304 --i;
1305 continue;
1307 assert(max_set && min_set);
1308 if (value_lt(max, min))
1309 goto out2;
1310 if (value_ne(max, min)) {
1311 Matrix *M = Matrix_Alloc(dim+i, 1+P->Dimension+1);
1312 for (int j = 0; j < dim+i; ++j) {
1313 value_set_si(M->p[j][1+j], -1);
1314 value_assign(M->p[j][1+P->Dimension], all_val->p[j]);
1316 Polyhedron *Q = AddConstraints(M->p[0], dim+i, P, MaxRays);
1317 Matrix_Free(M);
1318 Q = DomainConstraintSimplify(Q, MaxRays);
1319 Vector *sample = Polyhedron_Sample(Q, MaxRays);
1320 in = !!sample;
1321 if (sample)
1322 Vector_Free(sample);
1323 Polyhedron_Free(Q);
1324 goto out2;
1326 assert(value_eq(max, min));
1327 value_assign(all_val->p[dim+i], max);
1328 alternate = nexist - 1;
1330 in = true;
1331 out2:
1332 value_clear(min);
1333 value_clear(max);
1334 out:
1335 Vector_Free(all_val);
1336 value_clear(tmp);
1337 return in || (P->next && in_domain(P->next, val, dim, MaxRays));
1340 void compute_evalue(evalue *e, Value *val, Value *res)
1342 double d = compute_evalue(e, val);
1343 if (d > 0)
1344 d += .25;
1345 else
1346 d -= .25;
1347 value_set_double(*res, d);
1350 Vector *max_term::eval(Value *val, unsigned MaxRays) const
1352 if (dim == domain->Dimension) {
1353 if (!in_domain(domain, val))
1354 return NULL;
1355 } else {
1356 if (!in_domain(domain, val, dim, MaxRays))
1357 return NULL;
1359 Vector *res = Vector_Alloc(max.size());
1360 for (int i = 0; i < max.size(); ++i) {
1361 compute_evalue(max[i], val, &res->p[i]);
1363 return res;
1366 static Matrix *add_ge_constraint(EDomain *ED, evalue *constraint,
1367 vector<evalue *>& new_floors)
1369 Polyhedron *D = ED->D;
1370 evalue mone;
1371 value_init(mone.d);
1372 evalue_set_si(&mone, -1, 1);
1373 int fract = 0;
1374 for (evalue *e = constraint; value_zero_p(e->d);
1375 e = &e->x.p->arr[type_offset(e->x.p)]) {
1376 int i;
1377 if (e->x.p->type != fractional)
1378 continue;
1379 for (i = 0; i < ED->floors.size(); ++i)
1380 if (eequal(&e->x.p->arr[0], ED->floors[i]))
1381 break;
1382 if (i < ED->floors.size())
1383 continue;
1384 ++fract;
1387 int rows = D->NbConstraints+2*fract+1;
1388 int cols = 2+D->Dimension+fract;
1389 Matrix *M = Matrix_Alloc(rows, cols);
1390 for (int i = 0; i < D->NbConstraints; ++i) {
1391 Vector_Copy(D->Constraint[i], M->p[i], 1+D->Dimension);
1392 value_assign(M->p[i][1+D->Dimension+fract],
1393 D->Constraint[i][1+D->Dimension]);
1395 value_set_si(M->p[rows-1][0], 1);
1396 fract = 0;
1397 evalue *e;
1398 for (e = constraint; value_zero_p(e->d); e = &e->x.p->arr[type_offset(e->x.p)]) {
1399 if (e->x.p->type == fractional) {
1400 int i, pos;
1402 i = ED->find_floor(&e->x.p->arr[0]);
1403 if (i >= 0)
1404 pos = D->Dimension-ED->floors.size()+i;
1405 else
1406 pos = D->Dimension+fract;
1408 add_fract(e, M->p[rows-1], cols, 1+pos);
1410 if (pos < D->Dimension)
1411 continue;
1413 /* constraints for the new floor */
1414 int row = D->NbConstraints+2*fract;
1415 value_set_si(M->p[row][0], 1);
1416 evalue2constraint_r(NULL, &e->x.p->arr[0], M->p[row], cols);
1417 value_oppose(M->p[row][1+D->Dimension+fract], M->p[row][0]);
1418 value_set_si(M->p[row][0], 1);
1420 Vector_Scale(M->p[row]+1, M->p[row+1]+1, mone.x.n, cols-1);
1421 value_set_si(M->p[row+1][0], 1);
1422 value_addto(M->p[row+1][cols-1], M->p[row+1][cols-1],
1423 M->p[row+1][1+D->Dimension+fract]);
1424 value_decrement(M->p[row+1][cols-1], M->p[row+1][cols-1]);
1426 evalue *arg = new evalue;
1427 value_init(arg->d);
1428 evalue_copy(arg, &e->x.p->arr[0]);
1429 new_floors.push_back(arg);
1431 ++fract;
1432 } else {
1433 assert(e->x.p->type == polynomial);
1434 assert(e->x.p->size == 2);
1435 add_coeff(M->p[rows-1], cols, &e->x.p->arr[1], e->x.p->pos);
1438 add_coeff(M->p[rows-1], cols, e, cols-1);
1439 value_set_si(M->p[rows-1][0], 1);
1440 free_evalue_refs(&mone);
1441 return M;
1444 Polyhedron *unfringe (Polyhedron *P, unsigned MaxRays)
1446 int len = P->Dimension+2;
1447 Polyhedron *T, *R = P;
1448 Value g;
1449 value_init(g);
1450 Vector *row = Vector_Alloc(len);
1451 value_set_si(row->p[0], 1);
1453 R = DomainConstraintSimplify(Polyhedron_Copy(P), MaxRays);
1455 Matrix *M = Matrix_Alloc(2, len-1);
1456 value_set_si(M->p[1][len-2], 1);
1457 for (int v = 0; v < P->Dimension; ++v) {
1458 value_set_si(M->p[0][v], 1);
1459 Polyhedron *I = Polyhedron_Image(R, M, 2+1);
1460 value_set_si(M->p[0][v], 0);
1461 for (int r = 0; r < I->NbConstraints; ++r) {
1462 if (value_zero_p(I->Constraint[r][0]))
1463 continue;
1464 if (value_zero_p(I->Constraint[r][1]))
1465 continue;
1466 if (value_one_p(I->Constraint[r][1]))
1467 continue;
1468 if (value_mone_p(I->Constraint[r][1]))
1469 continue;
1470 value_absolute(g, I->Constraint[r][1]);
1471 Vector_Set(row->p+1, 0, len-2);
1472 value_division(row->p[1+v], I->Constraint[r][1], g);
1473 mpz_fdiv_q(row->p[len-1], I->Constraint[r][2], g);
1474 T = R;
1475 R = AddConstraints(row->p, 1, R, MaxRays);
1476 if (T != P)
1477 Polyhedron_Free(T);
1479 Polyhedron_Free(I);
1481 Matrix_Free(M);
1482 Vector_Free(row);
1483 value_clear(g);
1484 return R;
1487 static Matrix *remove_equalities(Polyhedron **P, unsigned nparam, unsigned MaxRays);
1489 Vector *Polyhedron_not_empty(Polyhedron *P, unsigned MaxRays)
1491 Polyhedron *Porig = P;
1492 Vector *sample = NULL;
1494 POL_ENSURE_VERTICES(P);
1495 if (emptyQ2(P))
1496 return NULL;
1498 for (int i = 0; i < P->NbRays; ++i)
1499 if (value_one_p(P->Ray[i][1+P->Dimension])) {
1500 sample = Vector_Alloc(P->Dimension + 1);
1501 Vector_Copy(P->Ray[i]+1, sample->p, P->Dimension+1);
1502 return sample;
1505 Matrix *T = remove_equalities(&P, 0, MaxRays);
1506 if (P)
1507 sample = Polyhedron_Sample(P, MaxRays);
1508 if (sample) {
1509 if (T) {
1510 Vector *P_sample = Vector_Alloc(Porig->Dimension + 1);
1511 Matrix_Vector_Product(T, sample->p, P_sample->p);
1512 Vector_Free(sample);
1513 sample = P_sample;
1516 if (T) {
1517 Polyhedron_Free(P);
1518 Matrix_Free(T);
1521 return sample;
1524 struct split {
1525 evalue *constraint;
1526 enum sign { le, ge, lge } sign;
1528 split (evalue *c, enum sign s) : constraint(c), sign(s) {}
1531 static void split_on(const split& sp, EDomain *D,
1532 EDomain **Dlt, EDomain **Deq, EDomain **Dgt,
1533 unsigned MaxRays)
1535 Matrix *M, *M2;
1536 EDomain *EDlt = NULL, *EDeq = NULL, *EDgt = NULL;
1537 Polyhedron *D2;
1538 Value mone;
1539 value_init(mone);
1540 value_set_si(mone, -1);
1541 *Dlt = NULL;
1542 *Deq = NULL;
1543 *Dgt = NULL;
1544 vector<evalue *> new_floors;
1545 M = add_ge_constraint(D, sp.constraint, new_floors);
1546 if (sp.sign == split::lge || sp.sign == split::ge) {
1547 M2 = Matrix_Copy(M);
1548 value_decrement(M2->p[M2->NbRows-1][M2->NbColumns-1],
1549 M2->p[M2->NbRows-1][M2->NbColumns-1]);
1550 D2 = Constraints2Polyhedron(M2, MaxRays);
1551 EDgt = new EDomain(D2, D, new_floors);
1552 Polyhedron_Free(D2);
1553 Matrix_Free(M2);
1555 if (sp.sign == split::lge || sp.sign == split::le) {
1556 M2 = Matrix_Copy(M);
1557 Vector_Scale(M2->p[M2->NbRows-1]+1, M2->p[M2->NbRows-1]+1,
1558 mone, M2->NbColumns-1);
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 EDlt = new EDomain(D2, D, new_floors);
1563 Polyhedron_Free(D2);
1564 Matrix_Free(M2);
1567 assert(sp.sign == split::lge || sp.sign == split::ge || sp.sign == split::le);
1568 value_set_si(M->p[M->NbRows-1][0], 0);
1569 D2 = Constraints2Polyhedron(M, MaxRays);
1570 EDeq = new EDomain(D2, D, new_floors);
1571 Polyhedron_Free(D2);
1572 Matrix_Free(M);
1574 Vector *sample = D->sample;
1575 if (sample && new_floors.size() > 0) {
1576 assert(sample->Size == D->D->Dimension+1);
1577 sample = Vector_Alloc(D->D->Dimension+new_floors.size()+1);
1578 Vector_Copy(D->sample->p, sample->p, D->D->Dimension);
1579 value_set_si(sample->p[D->D->Dimension+new_floors.size()], 1);
1580 for (int i = 0; i < new_floors.size(); ++i)
1581 compute_evalue(new_floors[i], sample->p, sample->p+D->D->Dimension+i);
1584 for (int i = 0; i < new_floors.size(); ++i) {
1585 free_evalue_refs(new_floors[i]);
1586 delete new_floors[i];
1589 if (EDeq) {
1590 if (sample && in_domain(EDeq->D, sample->p, sample->Size-1, MaxRays)) {
1591 EDeq->sample = Vector_Alloc(sample->Size);
1592 Vector_Copy(sample->p, EDeq->sample->p, sample->Size);
1593 } else if (!(EDeq->sample = Polyhedron_not_empty(EDeq->D, MaxRays))) {
1594 delete EDeq;
1595 EDeq = NULL;
1598 if (EDgt) {
1599 if (sample && in_domain(EDgt->D, sample->p, sample->Size-1, MaxRays)) {
1600 EDgt->sample = Vector_Alloc(sample->Size);
1601 Vector_Copy(sample->p, EDgt->sample->p, sample->Size);
1602 } else if (!(EDgt->sample = Polyhedron_not_empty(EDgt->D, MaxRays))) {
1603 delete EDgt;
1604 EDgt = NULL;
1607 if (EDlt) {
1608 if (sample && in_domain(EDlt->D, sample->p, sample->Size-1, MaxRays)) {
1609 EDlt->sample = Vector_Alloc(sample->Size);
1610 Vector_Copy(sample->p, EDlt->sample->p, sample->Size);
1611 } else if (!(EDlt->sample = Polyhedron_not_empty(EDlt->D, MaxRays))) {
1612 delete EDlt;
1613 EDlt = NULL;
1616 *Dlt = EDlt;
1617 *Deq = EDeq;
1618 *Dgt = EDgt;
1619 value_clear(mone);
1620 if (sample != D->sample)
1621 Vector_Free(sample);
1624 ostream & operator<< (ostream & os, const vector<int> & v)
1626 os << "[";
1627 for (int i = 0; i < v.size(); ++i) {
1628 if (i)
1629 os << ", ";
1630 os << v[i];
1632 os << "]";
1633 return os;
1637 * Project on first dim dimensions
1639 Polyhedron* Polyhedron_Project_Initial(Polyhedron *P, int dim)
1641 int i;
1642 Matrix *T;
1643 Polyhedron *I;
1645 if (P->Dimension == dim)
1646 return Polyhedron_Copy(P);
1648 T = Matrix_Alloc(dim+1, P->Dimension+1);
1649 for (i = 0; i < dim; ++i)
1650 value_set_si(T->p[i][i], 1);
1651 value_set_si(T->p[dim][P->Dimension], 1);
1652 I = Polyhedron_Image(P, T, P->NbConstraints);
1653 Matrix_Free(T);
1654 return I;
1657 static vector<max_term*> lexmin(indicator& ind, EDomain *D, unsigned nparam,
1658 unsigned MaxRays, vector<int> loc)
1660 vector<max_term*> maxima;
1661 int len = 1 + D->D->Dimension + 1;
1662 Value lcm, a, b;
1663 evalue mone;
1664 EDomain *Dorig = D;
1666 value_init(mone.d);
1667 evalue_set_si(&mone, -1, 1);
1668 value_init(lcm);
1669 value_init(a);
1670 value_init(b);
1671 Vector *c = Vector_Alloc(len);
1672 Matrix *T = Matrix_Alloc(2, len-1);
1673 for (int i = 0; i < ind.term.size(); ++i) {
1674 bool restart = false; /* true if we have modified ind from i up */
1675 bool stop = false; /* true if i can never be smallest */
1676 int peel = -1; /* term to peel against */
1677 vector<split> splits;
1678 if (ind.term[i]->sign < 0)
1679 continue;
1680 int dim = ind.term[i]->den.NumCols();
1681 int j;
1682 for (j = 0; j < ind.term.size(); ++j) {
1683 if (i == j)
1684 continue;
1685 int k;
1686 for (k = 0; k < dim; ++k) {
1687 /* compute ind.term->[i]->vertex[k] - ind.term->[j]->vertex[k] */
1688 evalue *diff = new evalue;
1689 value_init(diff->d);
1690 evalue_copy(diff, ind.term[j]->vertex[k]);
1691 emul(&mone, diff);
1692 eadd(ind.term[i]->vertex[k], diff);
1693 reduce_evalue(diff);
1694 int fract = evalue2constraint(D, diff, c->p, len);
1695 Vector_Copy(c->p+1, T->p[0], len-1);
1696 value_assign(T->p[1][len-2], c->p[0]);
1698 int min, max;
1699 interval_minmax(D->D, T, &min, &max, MaxRays);
1700 if (max < 0) {
1701 free_evalue_refs(diff);
1702 delete diff;
1703 break;
1705 if (fract) {
1706 emul(&mone, diff);
1707 evalue2constraint(D, diff, c->p, len);
1708 emul(&mone, diff);
1709 Vector_Copy(c->p+1, T->p[0], len-1);
1710 value_assign(T->p[1][len-2], c->p[0]);
1712 int negmin, negmax;
1713 interval_minmax(D->D, T, &negmin, &negmax, MaxRays);
1714 min = -negmax;
1716 if (min > 0) {
1717 free_evalue_refs(diff);
1718 delete diff;
1719 stop = true;
1720 break;
1722 if (max == 0 && min == 0) {
1723 if (!EVALUE_IS_ZERO(*diff)) {
1724 ind.substitute(diff);
1725 ind.simplify();
1726 restart = true;
1728 free_evalue_refs(diff);
1729 delete diff;
1730 if (restart)
1731 break;
1732 continue;
1734 if (min < 0 && max == 0)
1735 splits.push_back(split(diff, split::le));
1736 else if (max > 0 && min == 0)
1737 splits.push_back(split(diff, split::ge));
1738 else
1739 splits.push_back(split(diff, split::lge));
1740 break;
1742 if (k == dim && ind.term[j]->sign < 0)
1743 peel = j;
1744 if (stop || restart)
1745 break;
1747 if (restart) {
1748 /* The ith entry may have been removed, so we have to consider
1749 * it again.
1751 --i;
1752 for (j = 0; j < splits.size(); ++j) {
1753 free_evalue_refs(splits[j].constraint);
1754 delete splits[j].constraint;
1756 continue;
1758 if (stop) {
1759 for (j = 0; j < splits.size(); ++j) {
1760 free_evalue_refs(splits[j].constraint);
1761 delete splits[j].constraint;
1763 continue;
1765 if (peel != -1) {
1766 // ind.peel(i, peel);
1767 ind.combine(i, peel);
1768 ind.simplify();
1769 i = -1; /* start over */
1770 for (j = 0; j < splits.size(); ++j) {
1771 free_evalue_refs(splits[j].constraint);
1772 delete splits[j].constraint;
1774 continue;
1776 if (splits.size() != 0) {
1777 for (j = 0; j < splits.size(); ++j)
1778 if (splits[j].sign == split::le)
1779 break;
1780 if (j == splits.size())
1781 j = 0;
1782 EDomain *Dlt, *Deq, *Dgt;
1783 split_on(splits[j], D, &Dlt, &Deq, &Dgt, MaxRays);
1784 assert(Dlt || Deq || Dgt);
1785 if (Deq) {
1786 loc.push_back(0);
1787 indicator indeq(ind);
1788 indeq.substitute(splits[j].constraint);
1789 Polyhedron *P = Polyhedron_Project_Initial(Deq->D, nparam);
1790 P = DomainConstraintSimplify(P, MaxRays);
1791 indeq.reduce_in_domain(P);
1792 Polyhedron_Free(P);
1793 indeq.simplify();
1794 vector<max_term*> maxeq = lexmin(indeq, Deq, nparam,
1795 MaxRays, loc);
1796 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
1797 loc.pop_back();
1798 delete Deq;
1800 if (Dgt) {
1801 loc.push_back(1);
1802 indicator indgt(ind);
1803 Polyhedron *P = Polyhedron_Project_Initial(Dgt->D, nparam);
1804 P = DomainConstraintSimplify(P, MaxRays);
1805 indgt.reduce_in_domain(P);
1806 Polyhedron_Free(P);
1807 indgt.simplify();
1808 vector<max_term*> maxeq = lexmin(indgt, Dgt, nparam,
1809 MaxRays, loc);
1810 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
1811 loc.pop_back();
1812 delete Dgt;
1814 if (Dlt) {
1815 loc.push_back(-1);
1816 Polyhedron *P = Polyhedron_Project_Initial(Dlt->D, nparam);
1817 P = DomainConstraintSimplify(P, MaxRays);
1818 ind.reduce_in_domain(P);
1819 Polyhedron_Free(P);
1820 ind.simplify();
1821 if (D != Dorig)
1822 delete D;
1823 D = Dlt;
1824 if (splits.size() > 1) {
1825 vector<max_term*> maxeq = lexmin(ind, Dlt, nparam,
1826 MaxRays, loc);
1827 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
1828 for (j = 0; j < splits.size(); ++j) {
1829 free_evalue_refs(splits[j].constraint);
1830 delete splits[j].constraint;
1832 break;
1835 /* the vertex turned out not to be minimal */
1836 for (j = 0; j < splits.size(); ++j) {
1837 free_evalue_refs(splits[j].constraint);
1838 delete splits[j].constraint;
1840 if (!Dlt)
1841 break;
1843 max_term *maximum = new max_term;
1844 maxima.push_back(maximum);
1845 maximum->dim = nparam;
1846 maximum->domain = Polyhedron_Copy(D->D);
1847 for (int j = 0; j < dim; ++j) {
1848 evalue *E = new evalue;
1849 value_init(E->d);
1850 evalue_copy(E, ind.term[i]->vertex[j]);
1851 if (evalue_frac2floor_in_domain(E, D->D))
1852 reduce_evalue(E);
1853 maximum->max.push_back(E);
1855 break;
1857 Matrix_Free(T);
1858 Vector_Free(c);
1859 value_clear(lcm);
1860 value_clear(a);
1861 value_clear(b);
1862 free_evalue_refs(&mone);
1863 if (D != Dorig)
1864 delete D;
1865 return maxima;
1868 static Matrix *compress_parameters(Polyhedron **P, unsigned nparam, unsigned MaxRays)
1870 Matrix *M, *T, *CP;
1872 /* compress_parms doesn't like equalities that only involve parameters */
1873 for (int i = 0; i < (*P)->NbEq; ++i)
1874 assert(First_Non_Zero((*P)->Constraint[i]+1, (*P)->Dimension-nparam) != -1);
1876 M = Matrix_Alloc((*P)->NbEq, (*P)->Dimension+2);
1877 Vector_Copy((*P)->Constraint[0], M->p[0], (*P)->NbEq * ((*P)->Dimension+2));
1878 CP = compress_parms(M, nparam);
1879 Matrix_Free(M);
1881 if (isIdentity(CP)) {
1882 Matrix_Free(CP);
1883 return NULL;
1886 T = align_matrix(CP, (*P)->Dimension+1);
1887 *P = Polyhedron_Preimage(*P, T, MaxRays);
1888 Matrix_Free(T);
1890 return CP;
1893 static Matrix *remove_equalities(Polyhedron **P, unsigned nparam, unsigned MaxRays)
1895 /* Matrix "view" of equalities */
1896 Matrix M;
1897 M.NbRows = (*P)->NbEq;
1898 M.NbColumns = (*P)->Dimension+2;
1899 M.p_Init = (*P)->p_Init;
1900 M.p = (*P)->Constraint;
1902 Matrix *T = compress_variables(&M, nparam);
1904 if (!T) {
1905 *P = NULL;
1906 return NULL;
1908 if (isIdentity(T)) {
1909 Matrix_Free(T);
1910 T = NULL;
1911 } else
1912 *P = Polyhedron_Preimage(*P, T, MaxRays);
1914 return T;
1917 static vector<max_term*> lexmin(Polyhedron *P, Polyhedron *C, unsigned MaxRays)
1919 unsigned nparam = C->Dimension;
1920 Param_Polyhedron *PP = NULL;
1921 Polyhedron *CEq = NULL, *pVD;
1922 Matrix *CT = NULL;
1923 Matrix *T = NULL, *CP = NULL;
1924 Param_Domain *D, *next;
1925 Param_Vertices *V;
1926 Polyhedron *Porig = P;
1927 int i;
1928 vector<max_term*> all_max;
1929 Polyhedron *Q;
1931 if (emptyQ2(P))
1932 return all_max;
1934 POL_ENSURE_VERTICES(P);
1936 if (emptyQ2(P))
1937 return all_max;
1939 assert(P->NbBid == 0);
1941 if (P->NbEq > 0) {
1942 if (nparam > 0)
1943 CP = compress_parameters(&P, nparam, MaxRays);
1944 Q = P;
1945 T = remove_equalities(&P, nparam, MaxRays);
1946 if (P != Q && Q != Porig)
1947 Polyhedron_Free(Q);
1948 if (!P)
1949 return all_max;
1952 Q = P;
1953 PP = Polyhedron2Param_SimplifiedDomain(&P,C,
1954 (MaxRays & POL_NO_DUAL) ? 0 : MaxRays,
1955 &CEq,&CT);
1956 if (P != Q && Q != Porig)
1957 Polyhedron_Free(Q);
1959 if (CT) {
1960 if (isIdentity(CT)) {
1961 Matrix_Free(CT);
1962 CT = NULL;
1963 } else
1964 nparam = CT->NbRows - 1;
1967 unsigned dim = P->Dimension - nparam;
1969 int nd;
1970 for (nd = 0, D=PP->D; D; ++nd, D=D->next);
1971 Polyhedron **fVD = new Polyhedron*[nd];
1973 indicator_constructor ic(P, dim, PP->nbV);
1975 for (i = 0, V = PP->V; V; V = V->next, i++) {
1976 ic.decompose_at_vertex(V, i, MaxRays);
1978 if (T) {
1979 ic.substitute(T);
1980 ic.normalize();
1983 for (nd = 0, D=PP->D; D; D=next) {
1984 next = D->next;
1986 Polyhedron *rVD = reduce_domain(D->Domain, CT, CEq,
1987 fVD, nd, MaxRays);
1988 if (!rVD)
1989 continue;
1991 pVD = CT ? DomainImage(rVD,CT,MaxRays) : rVD;
1993 indicator ind;
1995 FORALL_PVertex_in_ParamPolyhedron(V,D,PP) // _i is internal counter
1996 for (int j = 0; j < ic.terms[_i].size(); ++j) {
1997 indicator_term *term = new indicator_term(*ic.terms[_i][j]);
1998 term->reduce_in_domain(pVD);
1999 ind.term.push_back(term);
2001 END_FORALL_PVertex_in_ParamPolyhedron;
2003 ind.simplify();
2005 EDomain epVD(pVD);
2006 vector<int> loc;
2007 vector<max_term*> maxima = lexmin(ind, &epVD, nparam, MaxRays, loc);
2008 if (CP)
2009 for (int j = 0; j < maxima.size(); ++j)
2010 maxima[j]->substitute(CP, MaxRays);
2011 all_max.insert(all_max.end(), maxima.begin(), maxima.end());
2013 ++nd;
2014 if (rVD != pVD)
2015 Domain_Free(pVD);
2016 Domain_Free(rVD);
2018 if (CP)
2019 Matrix_Free(CP);
2020 if (T)
2021 Matrix_Free(T);
2022 Param_Polyhedron_Free(PP);
2023 if (CEq)
2024 Polyhedron_Free(CEq);
2025 for (--nd; nd >= 0; --nd) {
2026 Domain_Free(fVD[nd]);
2028 delete [] fVD;
2029 if (P != Porig)
2030 Polyhedron_Free(P);
2032 return all_max;
2035 static void verify_results(Polyhedron *A, Polyhedron *C,
2036 vector<max_term*>& maxima, int m, int M,
2037 int print_all, unsigned MaxRays);
2039 int main(int argc, char **argv)
2041 Polyhedron *A, *C;
2042 Matrix *MA;
2043 int bignum;
2044 char **iter_names, **param_names;
2045 int c, ind = 0;
2046 int range = 0;
2047 int verify = 0;
2048 int print_all = 0;
2049 int m = INT_MAX, M = INT_MIN, r;
2050 int print_solution = 1;
2052 while ((c = getopt_long(argc, argv, "TAm:M:r:V", options, &ind)) != -1) {
2053 switch (c) {
2054 case 'T':
2055 verify = 1;
2056 break;
2057 case 'A':
2058 print_all = 1;
2059 break;
2060 case 'm':
2061 m = atoi(optarg);
2062 verify = 1;
2063 break;
2064 case 'M':
2065 M = atoi(optarg);
2066 verify = 1;
2067 break;
2068 case 'r':
2069 M = atoi(optarg);
2070 m = -M;
2071 verify = 1;
2072 break;
2073 case 'V':
2074 printf(barvinok_version());
2075 exit(0);
2076 break;
2080 MA = Matrix_Read();
2081 C = Constraints2Polyhedron(MA, MAXRAYS);
2082 Matrix_Free(MA);
2083 fscanf(stdin, " %d", &bignum);
2084 assert(bignum == -1);
2085 MA = Matrix_Read();
2086 A = Constraints2Polyhedron(MA, MAXRAYS);
2087 Matrix_Free(MA);
2089 if (A->Dimension >= VBIGDIM)
2090 r = VSRANGE;
2091 else if (A->Dimension >= BIGDIM)
2092 r = SRANGE;
2093 else
2094 r = RANGE;
2095 if (M == INT_MIN)
2096 M = r;
2097 if (m == INT_MAX)
2098 m = -r;
2100 if (verify && m > M) {
2101 fprintf(stderr,"Nothing to do: min > max !\n");
2102 return(0);
2104 if (verify)
2105 print_solution = 0;
2107 iter_names = util_generate_names(A->Dimension - C->Dimension, "i");
2108 param_names = util_generate_names(C->Dimension, "p");
2109 if (print_solution) {
2110 Polyhedron_Print(stdout, P_VALUE_FMT, A);
2111 Polyhedron_Print(stdout, P_VALUE_FMT, C);
2113 vector<max_term*> maxima = lexmin(A, C, MAXRAYS);
2114 if (print_solution)
2115 for (int i = 0; i < maxima.size(); ++i)
2116 maxima[i]->print(cout, param_names);
2118 if (verify)
2119 verify_results(A, C, maxima, m, M, print_all, MAXRAYS);
2121 for (int i = 0; i < maxima.size(); ++i)
2122 delete maxima[i];
2124 util_free_names(A->Dimension - C->Dimension, iter_names);
2125 util_free_names(C->Dimension, param_names);
2126 Polyhedron_Free(A);
2127 Polyhedron_Free(C);
2129 return 0;
2132 static bool lexmin(int pos, Polyhedron *P, Value *context)
2134 Value LB, UB, k;
2135 int lu_flags;
2136 bool found = false;
2138 if (emptyQ(P))
2139 return false;
2141 value_init(LB); value_init(UB); value_init(k);
2142 value_set_si(LB,0);
2143 value_set_si(UB,0);
2144 lu_flags = lower_upper_bounds(pos,P,context,&LB,&UB);
2145 assert(!(lu_flags & LB_INFINITY));
2147 value_set_si(context[pos],0);
2148 if (!lu_flags && value_lt(UB,LB)) {
2149 value_clear(LB); value_clear(UB); value_clear(k);
2150 return false;
2152 if (!P->next) {
2153 value_assign(context[pos], LB);
2154 value_clear(LB); value_clear(UB); value_clear(k);
2155 return true;
2157 for (value_assign(k,LB); lu_flags || value_le(k,UB); value_increment(k,k)) {
2158 value_assign(context[pos],k);
2159 if ((found = lexmin(pos+1, P->next, context)))
2160 break;
2162 if (!found)
2163 value_set_si(context[pos],0);
2164 value_clear(LB); value_clear(UB); value_clear(k);
2165 return found;
2168 static void print_list(FILE *out, Value *z, char* brackets, int len)
2170 fprintf(out, "%c", brackets[0]);
2171 value_print(out, VALUE_FMT,z[0]);
2172 for (int k = 1; k < len; ++k) {
2173 fprintf(out, ", ");
2174 value_print(out, VALUE_FMT,z[k]);
2176 fprintf(out, "%c", brackets[1]);
2179 static int check_poly(Polyhedron *S, Polyhedron *CS, vector<max_term*>& maxima,
2180 int nparam, int pos, Value *z, int print_all, int st,
2181 unsigned MaxRays)
2183 if (pos == nparam) {
2184 int k;
2185 bool found = lexmin(1, S, z);
2187 if (print_all) {
2188 printf("lexmin");
2189 print_list(stdout, z+S->Dimension-nparam+1, "()", nparam);
2190 printf(" = ");
2191 if (found)
2192 print_list(stdout, z+1, "[]", S->Dimension-nparam);
2193 printf(" ");
2196 Vector *min = NULL;
2197 for (int i = 0; i < maxima.size(); ++i)
2198 if ((min = maxima[i]->eval(z+S->Dimension-nparam+1, MaxRays)))
2199 break;
2201 int ok = !(found ^ !!min);
2202 if (found && min)
2203 for (int i = 0; i < S->Dimension-nparam; ++i)
2204 if (value_ne(z[1+i], min->p[i])) {
2205 ok = 0;
2206 break;
2208 if (!ok) {
2209 printf("\n");
2210 fflush(stdout);
2211 fprintf(stderr, "Error !\n");
2212 fprintf(stderr, "lexmin");
2213 print_list(stderr, z+S->Dimension-nparam+1, "()", nparam);
2214 fprintf(stderr, " should be ");
2215 if (found)
2216 print_list(stderr, z+1, "[]", S->Dimension-nparam);
2217 fprintf(stderr, " while digging gives ");
2218 if (min)
2219 print_list(stderr, min->p, "[]", S->Dimension-nparam);
2220 fprintf(stderr, ".\n");
2221 return 0;
2222 } else if (print_all)
2223 printf("OK.\n");
2224 if (min)
2225 Vector_Free(min);
2227 for (k = 1; k <= S->Dimension-nparam; ++k)
2228 value_set_si(z[k], 0);
2229 } else {
2230 Value tmp;
2231 Value LB, UB;
2232 value_init(tmp);
2233 value_init(LB);
2234 value_init(UB);
2235 int ok =
2236 !(lower_upper_bounds(1+pos, CS, &z[S->Dimension-nparam], &LB, &UB));
2237 for (value_assign(tmp,LB); value_le(tmp,UB); value_increment(tmp,tmp)) {
2238 if (!print_all) {
2239 int k = VALUE_TO_INT(tmp);
2240 if (!pos && !(k%st)) {
2241 printf("o");
2242 fflush(stdout);
2245 value_assign(z[pos+S->Dimension-nparam+1],tmp);
2246 if (!check_poly(S, CS->next, maxima, nparam, pos+1, z, print_all, st,
2247 MaxRays)) {
2248 value_clear(tmp);
2249 value_clear(LB);
2250 value_clear(UB);
2251 return 0;
2254 value_set_si(z[pos+S->Dimension-nparam+1],0);
2255 value_clear(tmp);
2256 value_clear(LB);
2257 value_clear(UB);
2259 return 1;
2262 void verify_results(Polyhedron *A, Polyhedron *C, vector<max_term*>& maxima,
2263 int m, int M, int print_all, unsigned MaxRays)
2265 Polyhedron *CC, *CC2, *CS, *S;
2266 unsigned nparam = C->Dimension;
2267 Value *p;
2268 int i;
2269 int st;
2271 CC = Polyhedron_Project(A, nparam);
2272 CC2 = DomainIntersection(C, CC, MAXRAYS);
2273 Domain_Free(CC);
2274 CC = CC2;
2276 /* Intersect context with range */
2277 if (nparam > 0) {
2278 Matrix *MM;
2279 Polyhedron *U;
2281 MM = Matrix_Alloc(2*C->Dimension, C->Dimension+2);
2282 for (int i = 0; i < C->Dimension; ++i) {
2283 value_set_si(MM->p[2*i][0], 1);
2284 value_set_si(MM->p[2*i][1+i], 1);
2285 value_set_si(MM->p[2*i][1+C->Dimension], -m);
2286 value_set_si(MM->p[2*i+1][0], 1);
2287 value_set_si(MM->p[2*i+1][1+i], -1);
2288 value_set_si(MM->p[2*i+1][1+C->Dimension], M);
2290 CC2 = AddConstraints(MM->p[0], 2*CC->Dimension, CC, MAXRAYS);
2291 U = Universe_Polyhedron(0);
2292 CS = Polyhedron_Scan(CC2, U, MAXRAYS & POL_NO_DUAL ? 0 : MAXRAYS);
2293 Polyhedron_Free(U);
2294 Polyhedron_Free(CC2);
2295 Matrix_Free(MM);
2296 } else
2297 CS = NULL;
2299 p = ALLOCN(Value, A->Dimension+2);
2300 for (i=0; i <= A->Dimension; i++) {
2301 value_init(p[i]);
2302 value_set_si(p[i],0);
2304 value_init(p[i]);
2305 value_set_si(p[i], 1);
2307 S = Polyhedron_Scan(A, C, MAXRAYS & POL_NO_DUAL ? 0 : MAXRAYS);
2309 if (!print_all && C->Dimension > 0) {
2310 if (M-m > 80)
2311 st = 1+(M-m)/80;
2312 else
2313 st = 1;
2314 for (int i = m; i <= M; i += st)
2315 printf(".");
2316 printf( "\r" );
2317 fflush(stdout);
2320 if (S) {
2321 if (!(CS && emptyQ2(CS)))
2322 check_poly(S, CS, maxima, nparam, 0, p, print_all, st, MaxRays);
2323 Domain_Free(S);
2326 if (!print_all)
2327 printf("\n");
2329 for (i=0; i <= (A->Dimension+1); i++)
2330 value_clear(p[i]);
2331 free(p);
2332 if (CS)
2333 Domain_Free(CS);
2334 Polyhedron_Free(CC);