barvinok/evalue.h: make more self-contained
[barvinok.git] / lexmin.cc
blob5c5404fb9a8911eae8cb00a96f5a9991ca4ad928
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 /* "align" matrix to have nrows by inserting
1125 * the necessary number of rows and an equal number of columns at the end
1126 * right before the constant row/column
1128 static Matrix *align_matrix_initial(Matrix *M, int nrows)
1130 int i;
1131 int newrows = nrows - M->NbRows;
1132 Matrix *M2 = Matrix_Alloc(nrows, newrows + M->NbColumns);
1133 for (i = 0; i < newrows; ++i)
1134 value_set_si(M2->p[M->NbRows-1+i][M->NbColumns-1+i], 1);
1135 for (i = 0; i < M->NbRows-1; ++i) {
1136 Vector_Copy(M->p[i], M2->p[i], M->NbColumns-1);
1137 value_assign(M2->p[i][M2->NbColumns-1], M->p[i][M->NbColumns-1]);
1139 value_assign(M2->p[M2->NbRows-1][M2->NbColumns-1],
1140 M->p[M->NbRows-1][M->NbColumns-1]);
1141 return M2;
1144 /* T maps the compressed parameters to the original parameters,
1145 * while this max_term is based on the compressed parameters
1146 * and we want get the original parameters back.
1148 void max_term::substitute(Matrix *T, unsigned MaxRays)
1150 int nexist = domain->Dimension - (T->NbColumns-1);
1151 Matrix *M = align_matrix_initial(T, T->NbRows+nexist);
1153 Polyhedron *D = DomainImage(domain, M, MaxRays);
1154 Polyhedron_Free(domain);
1155 domain = D;
1156 Matrix_Free(M);
1158 assert(T->NbRows == T->NbColumns);
1159 Matrix *T2 = Matrix_Copy(T);
1160 Matrix *inv = Matrix_Alloc(T->NbColumns, T->NbRows);
1161 int ok = Matrix_Inverse(T2, inv);
1162 Matrix_Free(T2);
1163 assert(ok);
1165 evalue denom;
1166 value_init(denom.d);
1167 value_init(denom.x.n);
1168 value_set_si(denom.x.n, 1);
1169 value_assign(denom.d, inv->p[inv->NbRows-1][inv->NbColumns-1]);
1171 vec_ZZ v;
1172 v.SetLength(inv->NbColumns);
1173 evalue* subs[inv->NbRows-1];
1174 for (int i = 0; i < inv->NbRows-1; ++i) {
1175 values2zz(inv->p[i], v, v.length());
1176 subs[i] = multi_monom(v);
1177 emul(&denom, subs[i]);
1179 free_evalue_refs(&denom);
1181 for (int i = 0; i < max.size(); ++i) {
1182 evalue_substitute(max[i], subs);
1183 reduce_evalue(max[i]);
1186 for (int i = 0; i < inv->NbRows-1; ++i) {
1187 free_evalue_refs(subs[i]);
1188 delete subs[i];
1190 Matrix_Free(inv);
1193 int Last_Non_Zero(Value *p, unsigned len)
1195 for (int i = len-1; i >= 0; --i)
1196 if (value_notzero_p(p[i]))
1197 return i;
1198 return -1;
1201 static void SwapColumns(Value **V, int n, int i, int j)
1203 for (int r = 0; r < n; ++r)
1204 value_swap(V[r][i], V[r][j]);
1207 static void SwapColumns(Polyhedron *P, int i, int j)
1209 SwapColumns(P->Constraint, P->NbConstraints, i, j);
1210 SwapColumns(P->Ray, P->NbRays, i, j);
1213 bool in_domain(Polyhedron *P, Value *val, unsigned dim, unsigned MaxRays)
1215 int nexist = P->Dimension - dim;
1216 int last[P->NbConstraints];
1217 Value tmp, min, max;
1218 Vector *all_val = Vector_Alloc(P->Dimension+1);
1219 bool in = false;
1220 int i;
1221 int alternate;
1223 resolve_existential_vars(P, dim);
1225 Vector_Copy(val, all_val->p, dim);
1226 value_set_si(all_val->p[P->Dimension], 1);
1228 value_init(tmp);
1229 for (int i = 0; i < P->NbConstraints; ++i) {
1230 last[i] = Last_Non_Zero(P->Constraint[i]+1+dim, nexist);
1231 if (last[i] == -1) {
1232 Inner_Product(P->Constraint[i]+1, all_val->p, P->Dimension+1, &tmp);
1233 if (value_neg_p(tmp))
1234 goto out;
1235 if (i < P->NbEq && value_pos_p(tmp))
1236 goto out;
1240 value_init(min);
1241 value_init(max);
1242 alternate = nexist - 1;
1243 for (i = 0; i < nexist; ++i) {
1244 bool min_set = false;
1245 bool max_set = false;
1246 for (int j = 0; j < P->NbConstraints; ++j) {
1247 if (last[j] != i)
1248 continue;
1249 Inner_Product(P->Constraint[j]+1, all_val->p, P->Dimension+1, &tmp);
1250 value_oppose(tmp, tmp);
1251 if (j < P->NbEq) {
1252 if (!mpz_divisible_p(tmp, P->Constraint[j][1+dim+i]))
1253 goto out2;
1254 value_division(tmp, tmp, P->Constraint[j][1+dim+i]);
1255 if (!max_set || value_lt(tmp, max)) {
1256 max_set = true;
1257 value_assign(max, tmp);
1259 if (!min_set || value_gt(tmp, min)) {
1260 min_set = true;
1261 value_assign(min, tmp);
1263 } else {
1264 if (value_pos_p(P->Constraint[j][1+dim+i])) {
1265 mpz_cdiv_q(tmp, tmp, P->Constraint[j][1+dim+i]);
1266 if (!min_set || value_gt(tmp, min)) {
1267 min_set = true;
1268 value_assign(min, tmp);
1270 } else {
1271 mpz_fdiv_q(tmp, tmp, P->Constraint[j][1+dim+i]);
1272 if (!max_set || value_lt(tmp, max)) {
1273 max_set = true;
1274 value_assign(max, tmp);
1279 /* Move another existential variable in current position */
1280 if (!max_set || !min_set) {
1281 if (!(alternate > i)) {
1282 Matrix *M = Matrix_Alloc(dim+i, 1+P->Dimension+1);
1283 for (int j = 0; j < dim+i; ++j) {
1284 value_set_si(M->p[j][1+j], -1);
1285 value_assign(M->p[j][1+P->Dimension], all_val->p[j]);
1287 Polyhedron *Q = AddConstraints(M->p[0], dim+i, P, MaxRays);
1288 Matrix_Free(M);
1289 Q = DomainConstraintSimplify(Q, MaxRays);
1290 Vector *sample = Polyhedron_Sample(Q, MaxRays);
1291 in = !!sample;
1292 if (sample)
1293 Vector_Free(sample);
1294 Polyhedron_Free(Q);
1295 goto out2;
1297 assert(alternate > i);
1298 SwapColumns(P, 1+dim+i, 1+dim+alternate);
1299 resolve_existential_vars(P, dim);
1300 for (int j = 0; j < P->NbConstraints; ++j) {
1301 if (j >= P->NbEq && last[j] < i)
1302 continue;
1303 last[j] = Last_Non_Zero(P->Constraint[j]+1+dim, nexist);
1304 if (last[j] < i) {
1305 Inner_Product(P->Constraint[j]+1, all_val->p, P->Dimension+1,
1306 &tmp);
1307 if (value_neg_p(tmp))
1308 goto out2;
1309 if (j < P->NbEq && value_pos_p(tmp))
1310 goto out2;
1313 --alternate;
1314 --i;
1315 continue;
1317 assert(max_set && min_set);
1318 if (value_lt(max, min))
1319 goto out2;
1320 if (value_ne(max, min)) {
1321 Matrix *M = Matrix_Alloc(dim+i, 1+P->Dimension+1);
1322 for (int j = 0; j < dim+i; ++j) {
1323 value_set_si(M->p[j][1+j], -1);
1324 value_assign(M->p[j][1+P->Dimension], all_val->p[j]);
1326 Polyhedron *Q = AddConstraints(M->p[0], dim+i, P, MaxRays);
1327 Matrix_Free(M);
1328 Q = DomainConstraintSimplify(Q, MaxRays);
1329 Vector *sample = Polyhedron_Sample(Q, MaxRays);
1330 in = !!sample;
1331 if (sample)
1332 Vector_Free(sample);
1333 Polyhedron_Free(Q);
1334 goto out2;
1336 assert(value_eq(max, min));
1337 value_assign(all_val->p[dim+i], max);
1338 alternate = nexist - 1;
1340 in = true;
1341 out2:
1342 value_clear(min);
1343 value_clear(max);
1344 out:
1345 Vector_Free(all_val);
1346 value_clear(tmp);
1347 return in || (P->next && in_domain(P->next, val, dim, MaxRays));
1350 void compute_evalue(evalue *e, Value *val, Value *res)
1352 double d = compute_evalue(e, val);
1353 if (d > 0)
1354 d += .25;
1355 else
1356 d -= .25;
1357 value_set_double(*res, d);
1360 Vector *max_term::eval(Value *val, unsigned MaxRays) const
1362 if (dim == domain->Dimension) {
1363 if (!in_domain(domain, val))
1364 return NULL;
1365 } else {
1366 if (!in_domain(domain, val, dim, MaxRays))
1367 return NULL;
1369 Vector *res = Vector_Alloc(max.size());
1370 for (int i = 0; i < max.size(); ++i) {
1371 compute_evalue(max[i], val, &res->p[i]);
1373 return res;
1376 static Matrix *add_ge_constraint(EDomain *ED, evalue *constraint,
1377 vector<evalue *>& new_floors)
1379 Polyhedron *D = ED->D;
1380 evalue mone;
1381 value_init(mone.d);
1382 evalue_set_si(&mone, -1, 1);
1383 int fract = 0;
1384 for (evalue *e = constraint; value_zero_p(e->d);
1385 e = &e->x.p->arr[type_offset(e->x.p)]) {
1386 int i;
1387 if (e->x.p->type != fractional)
1388 continue;
1389 for (i = 0; i < ED->floors.size(); ++i)
1390 if (eequal(&e->x.p->arr[0], ED->floors[i]))
1391 break;
1392 if (i < ED->floors.size())
1393 continue;
1394 ++fract;
1397 int rows = D->NbConstraints+2*fract+1;
1398 int cols = 2+D->Dimension+fract;
1399 Matrix *M = Matrix_Alloc(rows, cols);
1400 for (int i = 0; i < D->NbConstraints; ++i) {
1401 Vector_Copy(D->Constraint[i], M->p[i], 1+D->Dimension);
1402 value_assign(M->p[i][1+D->Dimension+fract],
1403 D->Constraint[i][1+D->Dimension]);
1405 value_set_si(M->p[rows-1][0], 1);
1406 fract = 0;
1407 evalue *e;
1408 for (e = constraint; value_zero_p(e->d); e = &e->x.p->arr[type_offset(e->x.p)]) {
1409 if (e->x.p->type == fractional) {
1410 int i, pos;
1412 i = ED->find_floor(&e->x.p->arr[0]);
1413 if (i >= 0)
1414 pos = D->Dimension-ED->floors.size()+i;
1415 else
1416 pos = D->Dimension+fract;
1418 add_fract(e, M->p[rows-1], cols, 1+pos);
1420 if (pos < D->Dimension)
1421 continue;
1423 /* constraints for the new floor */
1424 int row = D->NbConstraints+2*fract;
1425 value_set_si(M->p[row][0], 1);
1426 evalue2constraint_r(NULL, &e->x.p->arr[0], M->p[row], cols);
1427 value_oppose(M->p[row][1+D->Dimension+fract], M->p[row][0]);
1428 value_set_si(M->p[row][0], 1);
1430 Vector_Scale(M->p[row]+1, M->p[row+1]+1, mone.x.n, cols-1);
1431 value_set_si(M->p[row+1][0], 1);
1432 value_addto(M->p[row+1][cols-1], M->p[row+1][cols-1],
1433 M->p[row+1][1+D->Dimension+fract]);
1434 value_decrement(M->p[row+1][cols-1], M->p[row+1][cols-1]);
1436 evalue *arg = new evalue;
1437 value_init(arg->d);
1438 evalue_copy(arg, &e->x.p->arr[0]);
1439 new_floors.push_back(arg);
1441 ++fract;
1442 } else {
1443 assert(e->x.p->type == polynomial);
1444 assert(e->x.p->size == 2);
1445 add_coeff(M->p[rows-1], cols, &e->x.p->arr[1], e->x.p->pos);
1448 add_coeff(M->p[rows-1], cols, e, cols-1);
1449 value_set_si(M->p[rows-1][0], 1);
1450 free_evalue_refs(&mone);
1451 return M;
1454 static Matrix *remove_equalities(Polyhedron **P, unsigned nparam, unsigned MaxRays);
1456 Vector *Polyhedron_not_empty(Polyhedron *P, unsigned MaxRays)
1458 Polyhedron *Porig = P;
1459 Vector *sample = NULL;
1461 POL_ENSURE_VERTICES(P);
1462 if (emptyQ2(P))
1463 return NULL;
1465 for (int i = 0; i < P->NbRays; ++i)
1466 if (value_one_p(P->Ray[i][1+P->Dimension])) {
1467 sample = Vector_Alloc(P->Dimension + 1);
1468 Vector_Copy(P->Ray[i]+1, sample->p, P->Dimension+1);
1469 return sample;
1472 Matrix *T = remove_equalities(&P, 0, MaxRays);
1473 if (P)
1474 sample = Polyhedron_Sample(P, MaxRays);
1475 if (sample) {
1476 if (T) {
1477 Vector *P_sample = Vector_Alloc(Porig->Dimension + 1);
1478 Matrix_Vector_Product(T, sample->p, P_sample->p);
1479 Vector_Free(sample);
1480 sample = P_sample;
1483 if (T) {
1484 Polyhedron_Free(P);
1485 Matrix_Free(T);
1488 return sample;
1491 struct split {
1492 evalue *constraint;
1493 enum sign { le, ge, lge } sign;
1495 split (evalue *c, enum sign s) : constraint(c), sign(s) {}
1498 static void split_on(const split& sp, EDomain *D,
1499 EDomain **Dlt, EDomain **Deq, EDomain **Dgt,
1500 unsigned MaxRays)
1502 Matrix *M, *M2;
1503 EDomain *EDlt = NULL, *EDeq = NULL, *EDgt = NULL;
1504 Polyhedron *D2;
1505 Value mone;
1506 value_init(mone);
1507 value_set_si(mone, -1);
1508 *Dlt = NULL;
1509 *Deq = NULL;
1510 *Dgt = NULL;
1511 vector<evalue *> new_floors;
1512 M = add_ge_constraint(D, sp.constraint, new_floors);
1513 if (sp.sign == split::lge || sp.sign == split::ge) {
1514 M2 = Matrix_Copy(M);
1515 value_decrement(M2->p[M2->NbRows-1][M2->NbColumns-1],
1516 M2->p[M2->NbRows-1][M2->NbColumns-1]);
1517 D2 = Constraints2Polyhedron(M2, MaxRays);
1518 EDgt = new EDomain(D2, D, new_floors);
1519 Polyhedron_Free(D2);
1520 Matrix_Free(M2);
1522 if (sp.sign == split::lge || sp.sign == split::le) {
1523 M2 = Matrix_Copy(M);
1524 Vector_Scale(M2->p[M2->NbRows-1]+1, M2->p[M2->NbRows-1]+1,
1525 mone, M2->NbColumns-1);
1526 value_decrement(M2->p[M2->NbRows-1][M2->NbColumns-1],
1527 M2->p[M2->NbRows-1][M2->NbColumns-1]);
1528 D2 = Constraints2Polyhedron(M2, MaxRays);
1529 EDlt = new EDomain(D2, D, new_floors);
1530 Polyhedron_Free(D2);
1531 Matrix_Free(M2);
1534 assert(sp.sign == split::lge || sp.sign == split::ge || sp.sign == split::le);
1535 value_set_si(M->p[M->NbRows-1][0], 0);
1536 D2 = Constraints2Polyhedron(M, MaxRays);
1537 EDeq = new EDomain(D2, D, new_floors);
1538 Polyhedron_Free(D2);
1539 Matrix_Free(M);
1541 Vector *sample = D->sample;
1542 if (sample && new_floors.size() > 0) {
1543 assert(sample->Size == D->D->Dimension+1);
1544 sample = Vector_Alloc(D->D->Dimension+new_floors.size()+1);
1545 Vector_Copy(D->sample->p, sample->p, D->D->Dimension);
1546 value_set_si(sample->p[D->D->Dimension+new_floors.size()], 1);
1547 for (int i = 0; i < new_floors.size(); ++i)
1548 compute_evalue(new_floors[i], sample->p, sample->p+D->D->Dimension+i);
1551 for (int i = 0; i < new_floors.size(); ++i) {
1552 free_evalue_refs(new_floors[i]);
1553 delete new_floors[i];
1556 if (EDeq) {
1557 if (sample && in_domain(EDeq->D, sample->p, sample->Size-1, MaxRays)) {
1558 EDeq->sample = Vector_Alloc(sample->Size);
1559 Vector_Copy(sample->p, EDeq->sample->p, sample->Size);
1560 } else if (!(EDeq->sample = Polyhedron_not_empty(EDeq->D, MaxRays))) {
1561 delete EDeq;
1562 EDeq = NULL;
1565 if (EDgt) {
1566 if (sample && in_domain(EDgt->D, sample->p, sample->Size-1, MaxRays)) {
1567 EDgt->sample = Vector_Alloc(sample->Size);
1568 Vector_Copy(sample->p, EDgt->sample->p, sample->Size);
1569 } else if (!(EDgt->sample = Polyhedron_not_empty(EDgt->D, MaxRays))) {
1570 delete EDgt;
1571 EDgt = NULL;
1574 if (EDlt) {
1575 if (sample && in_domain(EDlt->D, sample->p, sample->Size-1, MaxRays)) {
1576 EDlt->sample = Vector_Alloc(sample->Size);
1577 Vector_Copy(sample->p, EDlt->sample->p, sample->Size);
1578 } else if (!(EDlt->sample = Polyhedron_not_empty(EDlt->D, MaxRays))) {
1579 delete EDlt;
1580 EDlt = NULL;
1583 *Dlt = EDlt;
1584 *Deq = EDeq;
1585 *Dgt = EDgt;
1586 value_clear(mone);
1587 if (sample != D->sample)
1588 Vector_Free(sample);
1591 ostream & operator<< (ostream & os, const vector<int> & v)
1593 os << "[";
1594 for (int i = 0; i < v.size(); ++i) {
1595 if (i)
1596 os << ", ";
1597 os << v[i];
1599 os << "]";
1600 return os;
1604 * Project on first dim dimensions
1606 Polyhedron* Polyhedron_Project_Initial(Polyhedron *P, int dim)
1608 int i;
1609 Matrix *T;
1610 Polyhedron *I;
1612 if (P->Dimension == dim)
1613 return Polyhedron_Copy(P);
1615 T = Matrix_Alloc(dim+1, P->Dimension+1);
1616 for (i = 0; i < dim; ++i)
1617 value_set_si(T->p[i][i], 1);
1618 value_set_si(T->p[dim][P->Dimension], 1);
1619 I = Polyhedron_Image(P, T, P->NbConstraints);
1620 Matrix_Free(T);
1621 return I;
1624 static vector<max_term*> lexmin(indicator& ind, EDomain *D, unsigned nparam,
1625 unsigned MaxRays, vector<int> loc)
1627 vector<max_term*> maxima;
1628 int len = 1 + D->D->Dimension + 1;
1629 Value lcm, a, b;
1630 evalue mone;
1631 EDomain *Dorig = D;
1633 value_init(mone.d);
1634 evalue_set_si(&mone, -1, 1);
1635 value_init(lcm);
1636 value_init(a);
1637 value_init(b);
1638 Vector *c = Vector_Alloc(len);
1639 Matrix *T = Matrix_Alloc(2, len-1);
1640 for (int i = 0; i < ind.term.size(); ++i) {
1641 bool restart = false; /* true if we have modified ind from i up */
1642 bool stop = false; /* true if i can never be smallest */
1643 int peel = -1; /* term to peel against */
1644 vector<split> splits;
1645 if (ind.term[i]->sign < 0)
1646 continue;
1647 int dim = ind.term[i]->den.NumCols();
1648 int j;
1649 for (j = 0; j < ind.term.size(); ++j) {
1650 if (i == j)
1651 continue;
1652 int k;
1653 for (k = 0; k < dim; ++k) {
1654 /* compute ind.term->[i]->vertex[k] - ind.term->[j]->vertex[k] */
1655 evalue *diff = new evalue;
1656 value_init(diff->d);
1657 evalue_copy(diff, ind.term[j]->vertex[k]);
1658 emul(&mone, diff);
1659 eadd(ind.term[i]->vertex[k], diff);
1660 reduce_evalue(diff);
1661 int fract = evalue2constraint(D, diff, c->p, len);
1662 Vector_Copy(c->p+1, T->p[0], len-1);
1663 value_assign(T->p[1][len-2], c->p[0]);
1665 int min, max;
1666 interval_minmax(D->D, T, &min, &max, MaxRays);
1667 if (max < 0) {
1668 free_evalue_refs(diff);
1669 delete diff;
1670 break;
1672 if (fract) {
1673 emul(&mone, diff);
1674 evalue2constraint(D, diff, c->p, len);
1675 emul(&mone, diff);
1676 Vector_Copy(c->p+1, T->p[0], len-1);
1677 value_assign(T->p[1][len-2], c->p[0]);
1679 int negmin, negmax;
1680 interval_minmax(D->D, T, &negmin, &negmax, MaxRays);
1681 min = -negmax;
1683 if (min > 0) {
1684 free_evalue_refs(diff);
1685 delete diff;
1686 stop = true;
1687 break;
1689 if (max == 0 && min == 0) {
1690 if (!EVALUE_IS_ZERO(*diff)) {
1691 ind.substitute(diff);
1692 ind.simplify();
1693 restart = true;
1695 free_evalue_refs(diff);
1696 delete diff;
1697 if (restart)
1698 break;
1699 continue;
1701 if (min < 0 && max == 0)
1702 splits.push_back(split(diff, split::le));
1703 else if (max > 0 && min == 0)
1704 splits.push_back(split(diff, split::ge));
1705 else
1706 splits.push_back(split(diff, split::lge));
1707 break;
1709 if (k == dim && ind.term[j]->sign < 0)
1710 peel = j;
1711 if (stop || restart)
1712 break;
1714 if (restart) {
1715 /* The ith entry may have been removed, so we have to consider
1716 * it again.
1718 --i;
1719 for (j = 0; j < splits.size(); ++j) {
1720 free_evalue_refs(splits[j].constraint);
1721 delete splits[j].constraint;
1723 continue;
1725 if (stop) {
1726 for (j = 0; j < splits.size(); ++j) {
1727 free_evalue_refs(splits[j].constraint);
1728 delete splits[j].constraint;
1730 continue;
1732 if (peel != -1) {
1733 // ind.peel(i, peel);
1734 ind.combine(i, peel);
1735 ind.simplify();
1736 i = -1; /* start over */
1737 for (j = 0; j < splits.size(); ++j) {
1738 free_evalue_refs(splits[j].constraint);
1739 delete splits[j].constraint;
1741 continue;
1743 if (splits.size() != 0) {
1744 for (j = 0; j < splits.size(); ++j)
1745 if (splits[j].sign == split::le)
1746 break;
1747 if (j == splits.size())
1748 j = 0;
1749 EDomain *Dlt, *Deq, *Dgt;
1750 split_on(splits[j], D, &Dlt, &Deq, &Dgt, MaxRays);
1751 assert(Dlt || Deq || Dgt);
1752 if (Deq) {
1753 loc.push_back(0);
1754 indicator indeq(ind);
1755 indeq.substitute(splits[j].constraint);
1756 Polyhedron *P = Polyhedron_Project_Initial(Deq->D, nparam);
1757 P = DomainConstraintSimplify(P, MaxRays);
1758 indeq.reduce_in_domain(P);
1759 Polyhedron_Free(P);
1760 indeq.simplify();
1761 vector<max_term*> maxeq = lexmin(indeq, Deq, nparam,
1762 MaxRays, loc);
1763 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
1764 loc.pop_back();
1765 delete Deq;
1767 if (Dgt) {
1768 loc.push_back(1);
1769 indicator indgt(ind);
1770 Polyhedron *P = Polyhedron_Project_Initial(Dgt->D, nparam);
1771 P = DomainConstraintSimplify(P, MaxRays);
1772 indgt.reduce_in_domain(P);
1773 Polyhedron_Free(P);
1774 indgt.simplify();
1775 vector<max_term*> maxeq = lexmin(indgt, Dgt, nparam,
1776 MaxRays, loc);
1777 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
1778 loc.pop_back();
1779 delete Dgt;
1781 if (Dlt) {
1782 loc.push_back(-1);
1783 Polyhedron *P = Polyhedron_Project_Initial(Dlt->D, nparam);
1784 P = DomainConstraintSimplify(P, MaxRays);
1785 ind.reduce_in_domain(P);
1786 Polyhedron_Free(P);
1787 ind.simplify();
1788 if (D != Dorig)
1789 delete D;
1790 D = Dlt;
1791 if (splits.size() > 1) {
1792 vector<max_term*> maxeq = lexmin(ind, Dlt, nparam,
1793 MaxRays, loc);
1794 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
1795 for (j = 0; j < splits.size(); ++j) {
1796 free_evalue_refs(splits[j].constraint);
1797 delete splits[j].constraint;
1799 break;
1802 /* the vertex turned out not to be minimal */
1803 for (j = 0; j < splits.size(); ++j) {
1804 free_evalue_refs(splits[j].constraint);
1805 delete splits[j].constraint;
1807 if (!Dlt)
1808 break;
1810 max_term *maximum = new max_term;
1811 maxima.push_back(maximum);
1812 maximum->dim = nparam;
1813 maximum->domain = Polyhedron_Copy(D->D);
1814 for (int j = 0; j < dim; ++j) {
1815 evalue *E = new evalue;
1816 value_init(E->d);
1817 evalue_copy(E, ind.term[i]->vertex[j]);
1818 if (evalue_frac2floor_in_domain(E, D->D))
1819 reduce_evalue(E);
1820 maximum->max.push_back(E);
1822 break;
1824 Matrix_Free(T);
1825 Vector_Free(c);
1826 value_clear(lcm);
1827 value_clear(a);
1828 value_clear(b);
1829 free_evalue_refs(&mone);
1830 if (D != Dorig)
1831 delete D;
1832 return maxima;
1835 static bool isTranslation(Matrix *M)
1837 unsigned i, j;
1838 if (M->NbRows != M->NbColumns)
1839 return False;
1841 for (i = 0;i < M->NbRows; i ++)
1842 for (j = 0; j < M->NbColumns-1; j ++)
1843 if (i == j) {
1844 if(value_notone_p(M->p[i][j]))
1845 return False;
1846 } else {
1847 if(value_notzero_p(M->p[i][j]))
1848 return False;
1850 return value_one_p(M->p[M->NbRows-1][M->NbColumns-1]);
1853 static Matrix *compress_parameters(Polyhedron **P, Polyhedron **C,
1854 unsigned nparam, unsigned MaxRays)
1856 Matrix *M, *T, *CP;
1858 /* compress_parms doesn't like equalities that only involve parameters */
1859 for (int i = 0; i < (*P)->NbEq; ++i)
1860 assert(First_Non_Zero((*P)->Constraint[i]+1, (*P)->Dimension-nparam) != -1);
1862 M = Matrix_Alloc((*P)->NbEq, (*P)->Dimension+2);
1863 Vector_Copy((*P)->Constraint[0], M->p[0], (*P)->NbEq * ((*P)->Dimension+2));
1864 CP = compress_parms(M, nparam);
1865 Matrix_Free(M);
1867 if (isTranslation(CP)) {
1868 Matrix_Free(CP);
1869 return NULL;
1872 T = align_matrix(CP, (*P)->Dimension+1);
1873 *P = Polyhedron_Preimage(*P, T, MaxRays);
1874 Matrix_Free(T);
1876 *C = Polyhedron_Preimage(*C, CP, MaxRays);
1878 return CP;
1881 static Matrix *remove_equalities(Polyhedron **P, unsigned nparam, unsigned MaxRays)
1883 /* Matrix "view" of equalities */
1884 Matrix M;
1885 M.NbRows = (*P)->NbEq;
1886 M.NbColumns = (*P)->Dimension+2;
1887 M.p_Init = (*P)->p_Init;
1888 M.p = (*P)->Constraint;
1890 Matrix *T = compress_variables(&M, nparam);
1892 if (!T) {
1893 *P = NULL;
1894 return NULL;
1896 if (isIdentity(T)) {
1897 Matrix_Free(T);
1898 T = NULL;
1899 } else
1900 *P = Polyhedron_Preimage(*P, T, MaxRays);
1902 return T;
1905 static vector<max_term*> lexmin(Polyhedron *P, Polyhedron *C, unsigned MaxRays)
1907 unsigned nparam = C->Dimension;
1908 Param_Polyhedron *PP = NULL;
1909 Polyhedron *CEq = NULL, *pVD;
1910 Matrix *CT = NULL;
1911 Matrix *T = NULL, *CP = NULL;
1912 Param_Domain *D, *next;
1913 Param_Vertices *V;
1914 Polyhedron *Porig = P;
1915 Polyhedron *Corig = C;
1916 int i;
1917 vector<max_term*> all_max;
1918 Polyhedron *Q;
1920 if (emptyQ2(P))
1921 return all_max;
1923 POL_ENSURE_VERTICES(P);
1925 if (emptyQ2(P))
1926 return all_max;
1928 assert(P->NbBid == 0);
1930 if (P->NbEq > 0) {
1931 if (nparam > 0)
1932 CP = compress_parameters(&P, &C, nparam, MaxRays);
1933 Q = P;
1934 T = remove_equalities(&P, nparam, MaxRays);
1935 if (P != Q && Q != Porig)
1936 Polyhedron_Free(Q);
1937 if (!P) {
1938 if (C != Corig)
1939 Polyhedron_Free(C);
1940 return all_max;
1944 Q = P;
1945 PP = Polyhedron2Param_SimplifiedDomain(&P,C,
1946 (MaxRays & POL_NO_DUAL) ? 0 : MaxRays,
1947 &CEq,&CT);
1948 if (P != Q && Q != Porig)
1949 Polyhedron_Free(Q);
1951 if (CT) {
1952 if (isIdentity(CT)) {
1953 Matrix_Free(CT);
1954 CT = NULL;
1955 } else
1956 nparam = CT->NbRows - 1;
1959 unsigned dim = P->Dimension - nparam;
1961 int nd;
1962 for (nd = 0, D=PP->D; D; ++nd, D=D->next);
1963 Polyhedron **fVD = new Polyhedron*[nd];
1965 indicator_constructor ic(P, dim, PP->nbV);
1967 for (i = 0, V = PP->V; V; V = V->next, i++) {
1968 ic.decompose_at_vertex(V, i, MaxRays);
1970 if (T) {
1971 ic.substitute(T);
1972 ic.normalize();
1975 for (nd = 0, D=PP->D; D; D=next) {
1976 next = D->next;
1978 Polyhedron *rVD = reduce_domain(D->Domain, CT, CEq,
1979 fVD, nd, MaxRays);
1980 if (!rVD)
1981 continue;
1983 pVD = CT ? DomainImage(rVD,CT,MaxRays) : rVD;
1985 indicator ind;
1987 FORALL_PVertex_in_ParamPolyhedron(V,D,PP) // _i is internal counter
1988 for (int j = 0; j < ic.terms[_i].size(); ++j) {
1989 indicator_term *term = new indicator_term(*ic.terms[_i][j]);
1990 term->reduce_in_domain(pVD);
1991 ind.term.push_back(term);
1993 END_FORALL_PVertex_in_ParamPolyhedron;
1995 ind.simplify();
1997 EDomain epVD(pVD);
1998 vector<int> loc;
1999 vector<max_term*> maxima = lexmin(ind, &epVD, nparam, MaxRays, loc);
2000 if (CP)
2001 for (int j = 0; j < maxima.size(); ++j)
2002 maxima[j]->substitute(CP, MaxRays);
2003 all_max.insert(all_max.end(), maxima.begin(), maxima.end());
2005 ++nd;
2006 if (rVD != pVD)
2007 Domain_Free(pVD);
2008 Domain_Free(rVD);
2010 if (CP)
2011 Matrix_Free(CP);
2012 if (T)
2013 Matrix_Free(T);
2014 Param_Polyhedron_Free(PP);
2015 if (CEq)
2016 Polyhedron_Free(CEq);
2017 for (--nd; nd >= 0; --nd) {
2018 Domain_Free(fVD[nd]);
2020 delete [] fVD;
2021 if (C != Corig)
2022 Polyhedron_Free(C);
2023 if (P != Porig)
2024 Polyhedron_Free(P);
2026 return all_max;
2029 static void verify_results(Polyhedron *A, Polyhedron *C,
2030 vector<max_term*>& maxima, int m, int M,
2031 int print_all, unsigned MaxRays);
2033 int main(int argc, char **argv)
2035 Polyhedron *A, *C;
2036 Matrix *MA;
2037 int bignum;
2038 char **iter_names, **param_names;
2039 int c, ind = 0;
2040 int range = 0;
2041 int verify = 0;
2042 int print_all = 0;
2043 int m = INT_MAX, M = INT_MIN, r;
2044 int print_solution = 1;
2046 while ((c = getopt_long(argc, argv, "TAm:M:r:V", options, &ind)) != -1) {
2047 switch (c) {
2048 case 'T':
2049 verify = 1;
2050 break;
2051 case 'A':
2052 print_all = 1;
2053 break;
2054 case 'm':
2055 m = atoi(optarg);
2056 verify = 1;
2057 break;
2058 case 'M':
2059 M = atoi(optarg);
2060 verify = 1;
2061 break;
2062 case 'r':
2063 M = atoi(optarg);
2064 m = -M;
2065 verify = 1;
2066 break;
2067 case 'V':
2068 printf(barvinok_version());
2069 exit(0);
2070 break;
2074 MA = Matrix_Read();
2075 C = Constraints2Polyhedron(MA, MAXRAYS);
2076 Matrix_Free(MA);
2077 fscanf(stdin, " %d", &bignum);
2078 assert(bignum == -1);
2079 MA = Matrix_Read();
2080 A = Constraints2Polyhedron(MA, MAXRAYS);
2081 Matrix_Free(MA);
2083 if (A->Dimension >= VBIGDIM)
2084 r = VSRANGE;
2085 else if (A->Dimension >= BIGDIM)
2086 r = SRANGE;
2087 else
2088 r = RANGE;
2089 if (M == INT_MIN)
2090 M = r;
2091 if (m == INT_MAX)
2092 m = -r;
2094 if (verify && m > M) {
2095 fprintf(stderr,"Nothing to do: min > max !\n");
2096 return(0);
2098 if (verify)
2099 print_solution = 0;
2101 iter_names = util_generate_names(A->Dimension - C->Dimension, "i");
2102 param_names = util_generate_names(C->Dimension, "p");
2103 if (print_solution) {
2104 Polyhedron_Print(stdout, P_VALUE_FMT, A);
2105 Polyhedron_Print(stdout, P_VALUE_FMT, C);
2107 vector<max_term*> maxima = lexmin(A, C, MAXRAYS);
2108 if (print_solution)
2109 for (int i = 0; i < maxima.size(); ++i)
2110 maxima[i]->print(cout, param_names);
2112 if (verify)
2113 verify_results(A, C, maxima, m, M, print_all, MAXRAYS);
2115 for (int i = 0; i < maxima.size(); ++i)
2116 delete maxima[i];
2118 util_free_names(A->Dimension - C->Dimension, iter_names);
2119 util_free_names(C->Dimension, param_names);
2120 Polyhedron_Free(A);
2121 Polyhedron_Free(C);
2123 return 0;
2126 static bool lexmin(int pos, Polyhedron *P, Value *context)
2128 Value LB, UB, k;
2129 int lu_flags;
2130 bool found = false;
2132 if (emptyQ(P))
2133 return false;
2135 value_init(LB); value_init(UB); value_init(k);
2136 value_set_si(LB,0);
2137 value_set_si(UB,0);
2138 lu_flags = lower_upper_bounds(pos,P,context,&LB,&UB);
2139 assert(!(lu_flags & LB_INFINITY));
2141 value_set_si(context[pos],0);
2142 if (!lu_flags && value_lt(UB,LB)) {
2143 value_clear(LB); value_clear(UB); value_clear(k);
2144 return false;
2146 if (!P->next) {
2147 value_assign(context[pos], LB);
2148 value_clear(LB); value_clear(UB); value_clear(k);
2149 return true;
2151 for (value_assign(k,LB); lu_flags || value_le(k,UB); value_increment(k,k)) {
2152 value_assign(context[pos],k);
2153 if ((found = lexmin(pos+1, P->next, context)))
2154 break;
2156 if (!found)
2157 value_set_si(context[pos],0);
2158 value_clear(LB); value_clear(UB); value_clear(k);
2159 return found;
2162 static void print_list(FILE *out, Value *z, char* brackets, int len)
2164 fprintf(out, "%c", brackets[0]);
2165 value_print(out, VALUE_FMT,z[0]);
2166 for (int k = 1; k < len; ++k) {
2167 fprintf(out, ", ");
2168 value_print(out, VALUE_FMT,z[k]);
2170 fprintf(out, "%c", brackets[1]);
2173 static int check_poly(Polyhedron *S, Polyhedron *CS, vector<max_term*>& maxima,
2174 int nparam, int pos, Value *z, int print_all, int st,
2175 unsigned MaxRays)
2177 if (pos == nparam) {
2178 int k;
2179 bool found = lexmin(1, S, z);
2181 if (print_all) {
2182 printf("lexmin");
2183 print_list(stdout, z+S->Dimension-nparam+1, "()", nparam);
2184 printf(" = ");
2185 if (found)
2186 print_list(stdout, z+1, "[]", S->Dimension-nparam);
2187 printf(" ");
2190 Vector *min = NULL;
2191 for (int i = 0; i < maxima.size(); ++i)
2192 if ((min = maxima[i]->eval(z+S->Dimension-nparam+1, MaxRays)))
2193 break;
2195 int ok = !(found ^ !!min);
2196 if (found && min)
2197 for (int i = 0; i < S->Dimension-nparam; ++i)
2198 if (value_ne(z[1+i], min->p[i])) {
2199 ok = 0;
2200 break;
2202 if (!ok) {
2203 printf("\n");
2204 fflush(stdout);
2205 fprintf(stderr, "Error !\n");
2206 fprintf(stderr, "lexmin");
2207 print_list(stderr, z+S->Dimension-nparam+1, "()", nparam);
2208 fprintf(stderr, " should be ");
2209 if (found)
2210 print_list(stderr, z+1, "[]", S->Dimension-nparam);
2211 fprintf(stderr, " while digging gives ");
2212 if (min)
2213 print_list(stderr, min->p, "[]", S->Dimension-nparam);
2214 fprintf(stderr, ".\n");
2215 return 0;
2216 } else if (print_all)
2217 printf("OK.\n");
2218 if (min)
2219 Vector_Free(min);
2221 for (k = 1; k <= S->Dimension-nparam; ++k)
2222 value_set_si(z[k], 0);
2223 } else {
2224 Value tmp;
2225 Value LB, UB;
2226 value_init(tmp);
2227 value_init(LB);
2228 value_init(UB);
2229 int ok =
2230 !(lower_upper_bounds(1+pos, CS, &z[S->Dimension-nparam], &LB, &UB));
2231 for (value_assign(tmp,LB); value_le(tmp,UB); value_increment(tmp,tmp)) {
2232 if (!print_all) {
2233 int k = VALUE_TO_INT(tmp);
2234 if (!pos && !(k%st)) {
2235 printf("o");
2236 fflush(stdout);
2239 value_assign(z[pos+S->Dimension-nparam+1],tmp);
2240 if (!check_poly(S, CS->next, maxima, nparam, pos+1, z, print_all, st,
2241 MaxRays)) {
2242 value_clear(tmp);
2243 value_clear(LB);
2244 value_clear(UB);
2245 return 0;
2248 value_set_si(z[pos+S->Dimension-nparam+1],0);
2249 value_clear(tmp);
2250 value_clear(LB);
2251 value_clear(UB);
2253 return 1;
2256 void verify_results(Polyhedron *A, Polyhedron *C, vector<max_term*>& maxima,
2257 int m, int M, int print_all, unsigned MaxRays)
2259 Polyhedron *CC, *CC2, *CS, *S;
2260 unsigned nparam = C->Dimension;
2261 Value *p;
2262 int i;
2263 int st;
2265 CC = Polyhedron_Project(A, nparam);
2266 CC2 = DomainIntersection(C, CC, MAXRAYS);
2267 Domain_Free(CC);
2268 CC = CC2;
2270 /* Intersect context with range */
2271 if (nparam > 0) {
2272 Matrix *MM;
2273 Polyhedron *U;
2275 MM = Matrix_Alloc(2*C->Dimension, C->Dimension+2);
2276 for (int i = 0; i < C->Dimension; ++i) {
2277 value_set_si(MM->p[2*i][0], 1);
2278 value_set_si(MM->p[2*i][1+i], 1);
2279 value_set_si(MM->p[2*i][1+C->Dimension], -m);
2280 value_set_si(MM->p[2*i+1][0], 1);
2281 value_set_si(MM->p[2*i+1][1+i], -1);
2282 value_set_si(MM->p[2*i+1][1+C->Dimension], M);
2284 CC2 = AddConstraints(MM->p[0], 2*CC->Dimension, CC, MAXRAYS);
2285 U = Universe_Polyhedron(0);
2286 CS = Polyhedron_Scan(CC2, U, MAXRAYS & POL_NO_DUAL ? 0 : MAXRAYS);
2287 Polyhedron_Free(U);
2288 Polyhedron_Free(CC2);
2289 Matrix_Free(MM);
2290 } else
2291 CS = NULL;
2293 p = ALLOCN(Value, A->Dimension+2);
2294 for (i=0; i <= A->Dimension; i++) {
2295 value_init(p[i]);
2296 value_set_si(p[i],0);
2298 value_init(p[i]);
2299 value_set_si(p[i], 1);
2301 S = Polyhedron_Scan(A, C, MAXRAYS & POL_NO_DUAL ? 0 : MAXRAYS);
2303 if (!print_all && C->Dimension > 0) {
2304 if (M-m > 80)
2305 st = 1+(M-m)/80;
2306 else
2307 st = 1;
2308 for (int i = m; i <= M; i += st)
2309 printf(".");
2310 printf( "\r" );
2311 fflush(stdout);
2314 if (S) {
2315 if (!(CS && emptyQ2(CS)))
2316 check_poly(S, CS, maxima, nparam, 0, p, print_all, st, MaxRays);
2317 Domain_Free(S);
2320 if (!print_all)
2321 printf("\n");
2323 for (i=0; i <= (A->Dimension+1); i++)
2324 value_clear(p[i]);
2325 free(p);
2326 if (CS)
2327 Domain_Free(CS);
2328 Polyhedron_Free(CC);