lexmin.cc: move some code around to prepare for new version
[barvinok.git] / lexmin.cc
blobdfce2b26f2c979f8ea255bd2122f3c29e5ac2872
1 #include <iostream>
2 #include <vector>
3 #include <gmp.h>
4 #include <NTL/vec_ZZ.h>
5 #include <NTL/mat_ZZ.h>
6 extern "C" {
7 #include <polylib/polylibgmp.h>
9 #include <barvinok/barvinok.h>
10 #include <barvinok/evalue.h>
11 #include <barvinok/util.h>
12 #include "conversion.h"
13 #include "decomposer.h"
14 #include "lattice_point.h"
15 #include "reduce_domain.h"
16 #include "mat_util.h"
17 #include "combine.h"
18 #include "sample.h"
19 #include "fdstream.h"
20 #include "config.h"
22 #ifdef NTL_STD_CXX
23 using namespace NTL;
24 #endif
26 using std::vector;
27 using std::cerr;
28 using std::cout;
29 using std::endl;
30 using std::ostream;
32 #ifdef HAVE_GROWING_CHERNIKOVA
33 #define MAXRAYS (POL_NO_DUAL | POL_INTEGER)
34 #else
35 #define MAXRAYS 600
36 #endif
38 /* RANGE : normal range for evalutations (-RANGE -> RANGE) */
39 #define RANGE 50
41 /* SRANGE : small range for evalutations */
42 #define SRANGE 15
44 /* if dimension >= BIDDIM, use SRANGE */
45 #define BIGDIM 5
47 /* VSRANGE : very small range for evalutations */
48 #define VSRANGE 5
50 /* if dimension >= VBIDDIM, use VSRANGE */
51 #define VBIGDIM 8
53 #ifndef HAVE_GETOPT_H
54 #define getopt_long(a,b,c,d,e) getopt(a,b,c)
55 #else
56 #include <getopt.h>
57 struct option options[] = {
58 { "verify", no_argument, 0, 'T' },
59 { "print-all", no_argument, 0, 'A' },
60 { "min", required_argument, 0, 'm' },
61 { "max", required_argument, 0, 'M' },
62 { "range", required_argument, 0, 'r' },
63 { "version", no_argument, 0, 'V' },
64 { 0, 0, 0, 0 }
66 #endif
68 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
70 static int type_offset(enode *p)
72 return p->type == fractional ? 1 :
73 p->type == flooring ? 1 : 0;
76 static void evalue_denom(evalue *e, Value *d)
78 if (value_notzero_p(e->d)) {
79 value_lcm(*d, e->d, d);
80 return;
82 int offset = type_offset(e->x.p);
83 for (int i = e->x.p->size-1; i >= offset; --i)
84 evalue_denom(&e->x.p->arr[i], d);
87 static void evalue_print(std::ostream& o, evalue *e, char **p);
88 static void evalue_print(std::ostream& o, evalue *e, char **p, int d)
90 if (value_notzero_p(e->d)) {
91 o << VALUE_TO_INT(e->x.n) * (d / VALUE_TO_INT(e->d));
92 return;
94 assert(e->x.p->type == polynomial || e->x.p->type == flooring ||
95 e->x.p->type == fractional);
96 int offset = type_offset(e->x.p);
97 for (int i = e->x.p->size-1; i >= offset; --i) {
98 if (EVALUE_IS_ZERO(e->x.p->arr[i]))
99 continue;
100 if (i != e->x.p->size-1 &&
101 (value_zero_p(e->x.p->arr[i].d) ||
102 value_pos_p(e->x.p->arr[i].x.n)))
103 o << "+";
104 if (i == offset || !(value_one_p(e->x.p->arr[i].x.n) &&
105 d == VALUE_TO_INT(e->x.p->arr[i].d))) {
106 if (value_zero_p(e->x.p->arr[i].d))
107 o << "(";
108 evalue_print(o, &e->x.p->arr[i], p, d);
109 if (value_zero_p(e->x.p->arr[i].d))
110 o << ")";
111 if (i != offset)
112 o << "*";
114 for (int j = 0; j < i-offset; ++j) {
115 if (j != 0)
116 o << "*";
117 if (e->x.p->type == flooring) {
118 o << "[";
119 evalue_print(o, &e->x.p->arr[0], p);
120 o << "]";
121 } else if (e->x.p->type == fractional) {
122 o << "{";
123 evalue_print(o, &e->x.p->arr[0], p);
124 o << "}";
125 } else
126 o << p[e->x.p->pos-1];
131 static void evalue_print(std::ostream& o, evalue *e, char **p)
133 Value d;
134 value_init(d);
135 value_set_si(d, 1);
136 evalue_denom(e, &d);
137 if (value_notone_p(d))
138 o << "(";
139 evalue_print(o, e, p, VALUE_TO_INT(d));
140 if (value_notone_p(d))
141 o << ")/" << VALUE_TO_INT(d);
142 value_clear(d);
145 struct indicator_term {
146 int sign;
147 mat_ZZ den;
148 evalue **vertex;
150 indicator_term(unsigned dim) {
151 den.SetDims(dim, dim);
152 vertex = new evalue* [dim];
154 indicator_term(const indicator_term& src) {
155 sign = src.sign;
156 den = src.den;
157 unsigned dim = den.NumCols();
158 vertex = new evalue* [dim];
159 for (int i = 0; i < dim; ++i) {
160 vertex[i] = new evalue();
161 value_init(vertex[i]->d);
162 evalue_copy(vertex[i], src.vertex[i]);
165 ~indicator_term() {
166 unsigned dim = den.NumCols();
167 for (int i = 0; i < dim; ++i) {
168 free_evalue_refs(vertex[i]);
169 delete vertex[i];
171 delete [] vertex;
173 void print(ostream& os, char **p);
174 void substitute(Matrix *T);
175 void normalize();
176 void substitute(evalue *fract, evalue *val);
177 void substitute(int pos, evalue *val);
178 void reduce_in_domain(Polyhedron *D);
181 void indicator_term::reduce_in_domain(Polyhedron *D)
183 for (int k = 0; k < den.NumCols(); ++k) {
184 reduce_evalue_in_domain(vertex[k], D);
185 if (evalue_range_reduction_in_domain(vertex[k], D))
186 reduce_evalue(vertex[k]);
190 void indicator_term::print(ostream& os, char **p)
192 unsigned dim = den.NumCols();
193 unsigned factors = den.NumRows();
194 if (sign > 0)
195 os << " + ";
196 else
197 os << " - ";
198 os << '[';
199 for (int i = 0; i < dim; ++i) {
200 if (i)
201 os << ',';
202 evalue_print(os, vertex[i], p);
204 os << ']';
205 for (int i = 0; i < factors; ++i) {
206 os << " + t" << i << "*[";
207 for (int j = 0; j < dim; ++j) {
208 if (j)
209 os << ',';
210 os << den[i][j];
212 os << "]";
216 /* Perform the substitution specified by T on the variables.
217 * T has dimension (newdim+nparam+1) x (olddim + nparam + 1).
218 * The substitution is performed as in gen_fun::substitute
220 void indicator_term::substitute(Matrix *T)
222 unsigned dim = den.NumCols();
223 unsigned nparam = T->NbColumns - dim - 1;
224 unsigned newdim = T->NbRows - nparam - 1;
225 evalue **newvertex;
226 mat_ZZ trans;
227 matrix2zz(T, trans, newdim, dim);
228 trans = transpose(trans);
229 den *= trans;
230 newvertex = new evalue* [newdim];
232 vec_ZZ v;
233 v.SetLength(nparam+1);
235 evalue factor;
236 value_init(factor.d);
237 value_set_si(factor.d, 1);
238 value_init(factor.x.n);
239 for (int i = 0; i < newdim; ++i) {
240 values2zz(T->p[i]+dim, v, nparam+1);
241 newvertex[i] = multi_monom(v);
243 for (int j = 0; j < dim; ++j) {
244 if (value_zero_p(T->p[i][j]))
245 continue;
246 evalue term;
247 value_init(term.d);
248 evalue_copy(&term, vertex[j]);
249 value_assign(factor.x.n, T->p[i][j]);
250 emul(&factor, &term);
251 eadd(&term, newvertex[i]);
252 free_evalue_refs(&term);
255 free_evalue_refs(&factor);
256 for (int i = 0; i < dim; ++i) {
257 free_evalue_refs(vertex[i]);
258 delete vertex[i];
260 delete [] vertex;
261 vertex = newvertex;
264 static void evalue_add_constant(evalue *e, ZZ v)
266 Value tmp;
267 value_init(tmp);
269 /* go down to constant term */
270 while (value_zero_p(e->d))
271 e = &e->x.p->arr[type_offset(e->x.p)];
272 /* and add v */
273 zz2value(v, tmp);
274 value_multiply(tmp, tmp, e->d);
275 value_addto(e->x.n, e->x.n, tmp);
277 value_clear(tmp);
280 /* Make all powers in denominator lexico-positive */
281 void indicator_term::normalize()
283 vec_ZZ extra_vertex;
284 extra_vertex.SetLength(den.NumCols());
285 for (int r = 0; r < den.NumRows(); ++r) {
286 for (int k = 0; k < den.NumCols(); ++k) {
287 if (den[r][k] == 0)
288 continue;
289 if (den[r][k] > 0)
290 break;
291 sign = -sign;
292 den[r] = -den[r];
293 extra_vertex += den[r];
294 break;
297 for (int k = 0; k < extra_vertex.length(); ++k)
298 if (extra_vertex[k] != 0)
299 evalue_add_constant(vertex[k], extra_vertex[k]);
302 static void substitute(evalue *e, evalue *fract, evalue *val)
304 evalue *t;
306 for (t = e; value_zero_p(t->d); t = &t->x.p->arr[type_offset(t->x.p)]) {
307 if (t->x.p->type == fractional && eequal(&t->x.p->arr[0], fract))
308 break;
310 if (value_notzero_p(t->d))
311 return;
313 free_evalue_refs(&t->x.p->arr[0]);
314 evalue *term = &t->x.p->arr[2];
315 enode *p = t->x.p;
316 value_clear(t->d);
317 *t = t->x.p->arr[1];
319 emul(val, term);
320 eadd(term, e);
321 free_evalue_refs(term);
322 free(p);
324 reduce_evalue(e);
327 void indicator_term::substitute(evalue *fract, evalue *val)
329 unsigned dim = den.NumCols();
330 for (int i = 0; i < dim; ++i) {
331 ::substitute(vertex[i], fract, val);
335 static void substitute(evalue *e, int pos, evalue *val)
337 evalue *t;
339 for (t = e; value_zero_p(t->d); t = &t->x.p->arr[type_offset(t->x.p)]) {
340 if (t->x.p->type == polynomial && t->x.p->pos == pos)
341 break;
343 if (value_notzero_p(t->d))
344 return;
346 evalue *term = &t->x.p->arr[1];
347 enode *p = t->x.p;
348 value_clear(t->d);
349 *t = t->x.p->arr[0];
351 emul(val, term);
352 eadd(term, e);
353 free_evalue_refs(term);
354 free(p);
356 reduce_evalue(e);
359 void indicator_term::substitute(int pos, evalue *val)
361 unsigned dim = den.NumCols();
362 for (int i = 0; i < dim; ++i) {
363 ::substitute(vertex[i], pos, val);
367 struct indicator_constructor : public polar_decomposer, public vertex_decomposer {
368 vec_ZZ vertex;
369 vector<indicator_term*> *terms;
370 Matrix *T; /* Transformation to original space */
372 indicator_constructor(Polyhedron *P, unsigned dim, unsigned nbV, Matrix *T) :
373 vertex_decomposer(P, nbV, this), T(T) {
374 vertex.SetLength(dim);
375 terms = new vector<indicator_term*>[nbV];
377 ~indicator_constructor() {
378 for (int i = 0; i < nbV; ++i)
379 for (int j = 0; j < terms[i].size(); ++j)
380 delete terms[i][j];
381 delete [] terms;
383 void substitute(Matrix *T);
384 void normalize();
385 void print(ostream& os, char **p);
387 virtual void handle_polar(Polyhedron *P, int sign);
390 void indicator_constructor::handle_polar(Polyhedron *C, int s)
392 unsigned dim = vertex.length();
394 assert(C->NbRays-1 == dim);
396 indicator_term *term = new indicator_term(dim);
397 term->sign = s;
398 terms[vert].push_back(term);
400 lattice_point(V, C, vertex, term->vertex);
402 for (int r = 0; r < dim; ++r) {
403 values2zz(C->Ray[r]+1, term->den[r], dim);
404 for (int j = 0; j < dim; ++j) {
405 if (term->den[r][j] == 0)
406 continue;
407 if (term->den[r][j] > 0)
408 break;
409 term->sign = -term->sign;
410 term->den[r] = -term->den[r];
411 vertex += term->den[r];
412 break;
416 for (int i = 0; i < dim; ++i) {
417 if (!term->vertex[i]) {
418 term->vertex[i] = new evalue();
419 value_init(term->vertex[i]->d);
420 value_init(term->vertex[i]->x.n);
421 zz2value(vertex[i], term->vertex[i]->x.n);
422 value_set_si(term->vertex[i]->d, 1);
423 continue;
425 if (vertex[i] == 0)
426 continue;
427 evalue_add_constant(term->vertex[i], vertex[i]);
430 if (T) {
431 term->substitute(T);
432 term->normalize();
435 lex_order_rows(term->den);
438 void indicator_constructor::print(ostream& os, char **p)
440 for (int i = 0; i < nbV; ++i)
441 for (int j = 0; j < terms[i].size(); ++j) {
442 os << "i: " << i << ", j: " << j << endl;
443 terms[i][j]->print(os, p);
444 os << endl;
448 void indicator_constructor::normalize()
450 for (int i = 0; i < nbV; ++i)
451 for (int j = 0; j < terms[i].size(); ++j) {
452 vec_ZZ vertex;
453 vertex.SetLength(terms[i][j]->den.NumCols());
454 for (int r = 0; r < terms[i][j]->den.NumRows(); ++r) {
455 for (int k = 0; k < terms[i][j]->den.NumCols(); ++k) {
456 if (terms[i][j]->den[r][k] == 0)
457 continue;
458 if (terms[i][j]->den[r][k] > 0)
459 break;
460 terms[i][j]->sign = -terms[i][j]->sign;
461 terms[i][j]->den[r] = -terms[i][j]->den[r];
462 vertex += terms[i][j]->den[r];
463 break;
466 lex_order_rows(terms[i][j]->den);
467 for (int k = 0; k < vertex.length(); ++k)
468 if (vertex[k] != 0)
469 evalue_add_constant(terms[i][j]->vertex[k], vertex[k]);
473 struct EDomain {
474 Polyhedron *D;
475 Vector *sample;
476 vector<evalue *> floors;
478 EDomain(Polyhedron *D) {
479 this->D = Polyhedron_Copy(D);
480 sample = NULL;
482 EDomain(Polyhedron *D, vector<evalue *>floors) {
483 this->D = Polyhedron_Copy(D);
484 add_floors(floors);
485 sample = NULL;
487 EDomain(Polyhedron *D, EDomain *ED, vector<evalue *>floors) {
488 this->D = Polyhedron_Copy(D);
489 add_floors(ED->floors);
490 add_floors(floors);
491 sample = NULL;
493 void add_floors(vector<evalue *>floors) {
494 for (int i = 0; i < floors.size(); ++i) {
495 evalue *f = new evalue;
496 value_init(f->d);
497 evalue_copy(f, floors[i]);
498 this->floors.push_back(f);
501 int find_floor(evalue *needle) {
502 for (int i = 0; i < floors.size(); ++i)
503 if (eequal(needle, floors[i]))
504 return i;
505 return -1;
507 void print(FILE *out, char **p);
508 ~EDomain() {
509 for (int i = 0; i < floors.size(); ++i) {
510 free_evalue_refs(floors[i]);
511 delete floors[i];
513 Polyhedron_Free(D);
514 if (sample)
515 Vector_Free(sample);
519 void EDomain::print(FILE *out, char **p)
521 fdostream os(dup(fileno(out)));
522 for (int i = 0; i < floors.size(); ++i) {
523 os << "floor " << i << ": [";
524 evalue_print(os, floors[i], p);
525 os << "]" << endl;
527 Polyhedron_Print(out, P_VALUE_FMT, D);
530 static void add_coeff(Value *cons, int len, evalue *coeff, int pos)
532 Value tmp;
534 assert(value_notzero_p(coeff->d));
536 value_init(tmp);
538 value_lcm(cons[0], coeff->d, &tmp);
539 value_division(tmp, tmp, cons[0]);
540 Vector_Scale(cons, cons, tmp, len);
541 value_division(tmp, cons[0], coeff->d);
542 value_addmul(cons[pos], tmp, coeff->x.n);
544 value_clear(tmp);
547 static int evalue2constraint_r(EDomain *D, evalue *E, Value *cons, int len);
549 static void add_fract(evalue *e, Value *cons, int len, int pos)
551 evalue mone;
552 value_init(mone.d);
553 evalue_set_si(&mone, -1, 1);
555 /* contribution of alpha * fract(X) is
556 * alpha * X ...
558 assert(e->x.p->size == 3);
559 evalue argument;
560 value_init(argument.d);
561 evalue_copy(&argument, &e->x.p->arr[0]);
562 emul(&e->x.p->arr[2], &argument);
563 evalue2constraint_r(NULL, &argument, cons, len);
564 free_evalue_refs(&argument);
566 /* - alpha * floor(X) */
567 emul(&mone, &e->x.p->arr[2]);
568 add_coeff(cons, len, &e->x.p->arr[2], pos);
569 emul(&mone, &e->x.p->arr[2]);
571 free_evalue_refs(&mone);
574 static int evalue2constraint_r(EDomain *D, evalue *E, Value *cons, int len)
576 int r = 0;
577 if (value_zero_p(E->d) && E->x.p->type == fractional) {
578 int i;
579 assert(E->x.p->size == 3);
580 r = evalue2constraint_r(D, &E->x.p->arr[1], cons, len);
581 assert(value_notzero_p(E->x.p->arr[2].d));
582 if (D && (i = D->find_floor(&E->x.p->arr[0])) >= 0) {
583 add_fract(E, cons, len, 1+D->D->Dimension-D->floors.size()+i);
584 } else {
585 if (value_pos_p(E->x.p->arr[2].x.n)) {
586 evalue coeff;
587 value_init(coeff.d);
588 value_init(coeff.x.n);
589 value_set_si(coeff.d, 1);
590 evalue_denom(&E->x.p->arr[0], &coeff.d);
591 value_decrement(coeff.x.n, coeff.d);
592 emul(&E->x.p->arr[2], &coeff);
593 add_coeff(cons, len, &coeff, len-1);
594 free_evalue_refs(&coeff);
596 r = 1;
598 } else if (value_zero_p(E->d)) {
599 assert(E->x.p->type == polynomial);
600 assert(E->x.p->size == 2);
601 r = evalue2constraint_r(D, &E->x.p->arr[0], cons, len) || r;
602 add_coeff(cons, len, &E->x.p->arr[1], E->x.p->pos);
603 } else {
604 add_coeff(cons, len, E, len-1);
606 return r;
609 static int evalue2constraint(EDomain *D, evalue *E, Value *cons, int len)
611 Vector_Set(cons, 0, len);
612 value_set_si(cons[0], 1);
613 return evalue2constraint_r(D, E, cons, len);
616 static void interval_minmax(Polyhedron *I, int *min, int *max)
618 assert(I->Dimension == 1);
619 *min = 1;
620 *max = -1;
621 POL_ENSURE_VERTICES(I);
622 for (int i = 0; i < I->NbRays; ++i) {
623 if (value_pos_p(I->Ray[i][1]))
624 *max = 1;
625 else if (value_neg_p(I->Ray[i][1]))
626 *min = -1;
627 else {
628 if (*max < 0)
629 *max = 0;
630 if (*min > 0)
631 *min = 0;
636 static void interval_minmax(Polyhedron *D, Matrix *T, int *min, int *max,
637 unsigned MaxRays)
639 Polyhedron *I = Polyhedron_Image(D, T, MaxRays);
640 I = DomainConstraintSimplify(I, MaxRays);
641 if (emptyQ2(I)) {
642 Polyhedron_Free(I);
643 I = Polyhedron_Image(D, T, MaxRays);
645 interval_minmax(I, min, max);
646 Polyhedron_Free(I);
649 struct max_term {
650 unsigned dim;
651 Polyhedron *domain;
652 vector<evalue *> max;
654 void print(ostream& os, char **p) const;
655 void resolve_existential_vars() const;
656 void substitute(Matrix *T, unsigned MaxRays);
657 Vector *eval(Value *val, unsigned MaxRays) const;
659 ~max_term() {
660 for (int i = 0; i < max.size(); ++i) {
661 free_evalue_refs(max[i]);
662 delete max[i];
664 Polyhedron_Free(domain);
669 * Project on first dim dimensions
671 Polyhedron* Polyhedron_Project_Initial(Polyhedron *P, int dim)
673 int i;
674 Matrix *T;
675 Polyhedron *I;
677 if (P->Dimension == dim)
678 return Polyhedron_Copy(P);
680 T = Matrix_Alloc(dim+1, P->Dimension+1);
681 for (i = 0; i < dim; ++i)
682 value_set_si(T->p[i][i], 1);
683 value_set_si(T->p[dim][P->Dimension], 1);
684 I = Polyhedron_Image(P, T, P->NbConstraints);
685 Matrix_Free(T);
686 return I;
689 struct indicator {
690 vector<indicator_term*> term;
692 indicator() {}
693 indicator(const indicator& ind) {
694 for (int i = 0; i < ind.term.size(); ++i)
695 term.push_back(new indicator_term(*ind.term[i]));
697 ~indicator() {
698 for (int i = 0; i < term.size(); ++i)
699 delete term[i];
702 void print(ostream& os, char **p);
703 void simplify();
704 void peel(int i, int j);
705 void combine(int i, int j);
706 void substitute(evalue *equation);
707 void reduce_in_domain(Polyhedron *D);
710 static Matrix *add_ge_constraint(EDomain *ED, evalue *constraint,
711 vector<evalue *>& new_floors)
713 Polyhedron *D = ED->D;
714 evalue mone;
715 value_init(mone.d);
716 evalue_set_si(&mone, -1, 1);
717 int fract = 0;
718 for (evalue *e = constraint; value_zero_p(e->d);
719 e = &e->x.p->arr[type_offset(e->x.p)]) {
720 int i;
721 if (e->x.p->type != fractional)
722 continue;
723 for (i = 0; i < ED->floors.size(); ++i)
724 if (eequal(&e->x.p->arr[0], ED->floors[i]))
725 break;
726 if (i < ED->floors.size())
727 continue;
728 ++fract;
731 int rows = D->NbConstraints+2*fract+1;
732 int cols = 2+D->Dimension+fract;
733 Matrix *M = Matrix_Alloc(rows, cols);
734 for (int i = 0; i < D->NbConstraints; ++i) {
735 Vector_Copy(D->Constraint[i], M->p[i], 1+D->Dimension);
736 value_assign(M->p[i][1+D->Dimension+fract],
737 D->Constraint[i][1+D->Dimension]);
739 value_set_si(M->p[rows-1][0], 1);
740 fract = 0;
741 evalue *e;
742 for (e = constraint; value_zero_p(e->d); e = &e->x.p->arr[type_offset(e->x.p)]) {
743 if (e->x.p->type == fractional) {
744 int i, pos;
746 i = ED->find_floor(&e->x.p->arr[0]);
747 if (i >= 0)
748 pos = D->Dimension-ED->floors.size()+i;
749 else
750 pos = D->Dimension+fract;
752 add_fract(e, M->p[rows-1], cols, 1+pos);
754 if (pos < D->Dimension)
755 continue;
757 /* constraints for the new floor */
758 int row = D->NbConstraints+2*fract;
759 value_set_si(M->p[row][0], 1);
760 evalue2constraint_r(NULL, &e->x.p->arr[0], M->p[row], cols);
761 value_oppose(M->p[row][1+D->Dimension+fract], M->p[row][0]);
762 value_set_si(M->p[row][0], 1);
764 Vector_Scale(M->p[row]+1, M->p[row+1]+1, mone.x.n, cols-1);
765 value_set_si(M->p[row+1][0], 1);
766 value_addto(M->p[row+1][cols-1], M->p[row+1][cols-1],
767 M->p[row+1][1+D->Dimension+fract]);
768 value_decrement(M->p[row+1][cols-1], M->p[row+1][cols-1]);
770 evalue *arg = new evalue;
771 value_init(arg->d);
772 evalue_copy(arg, &e->x.p->arr[0]);
773 new_floors.push_back(arg);
775 ++fract;
776 } else {
777 assert(e->x.p->type == polynomial);
778 assert(e->x.p->size == 2);
779 add_coeff(M->p[rows-1], cols, &e->x.p->arr[1], e->x.p->pos);
782 add_coeff(M->p[rows-1], cols, e, cols-1);
783 value_set_si(M->p[rows-1][0], 1);
784 free_evalue_refs(&mone);
785 return M;
788 void indicator::reduce_in_domain(Polyhedron *D)
790 for (int i = 0; i < term.size(); ++i)
791 term[i]->reduce_in_domain(D);
794 void indicator::print(ostream& os, char **p)
796 for (int i = 0; i < term.size(); ++i) {
797 term[i]->print(os, p);
798 os << endl;
802 /* Remove pairs of opposite terms */
803 void indicator::simplify()
805 for (int i = 0; i < term.size(); ++i) {
806 for (int j = i+1; j < term.size(); ++j) {
807 if (term[i]->sign + term[j]->sign != 0)
808 continue;
809 if (term[i]->den != term[j]->den)
810 continue;
811 int k;
812 for (k = 0; k < term[i]->den.NumCols(); ++k)
813 if (!eequal(term[i]->vertex[k], term[j]->vertex[k]))
814 break;
815 if (k < term[i]->den.NumCols())
816 continue;
817 delete term[i];
818 delete term[j];
819 term.erase(term.begin()+j);
820 term.erase(term.begin()+i);
821 --i;
822 break;
827 void indicator::peel(int i, int j)
829 if (j < i) {
830 int tmp = i;
831 i = j;
832 j = tmp;
834 assert (i < j);
835 int dim = term[i]->den.NumCols();
837 mat_ZZ common;
838 mat_ZZ rest_i;
839 mat_ZZ rest_j;
840 int n_common = 0, n_i = 0, n_j = 0;
842 common.SetDims(min(term[i]->den.NumRows(), term[j]->den.NumRows()), dim);
843 rest_i.SetDims(term[i]->den.NumRows(), dim);
844 rest_j.SetDims(term[j]->den.NumRows(), dim);
846 int k, l;
847 for (k = 0, l = 0; k < term[i]->den.NumRows() && l < term[j]->den.NumRows(); ) {
848 int s = lex_cmp(term[i]->den[k], term[j]->den[l]);
849 if (s == 0) {
850 common[n_common++] = term[i]->den[k];
851 ++k;
852 ++l;
853 } else if (s < 0)
854 rest_i[n_i++] = term[i]->den[k++];
855 else
856 rest_j[n_j++] = term[j]->den[l++];
858 while (k < term[i]->den.NumRows())
859 rest_i[n_i++] = term[i]->den[k++];
860 while (l < term[j]->den.NumRows())
861 rest_j[n_j++] = term[j]->den[l++];
862 common.SetDims(n_common, dim);
863 rest_i.SetDims(n_i, dim);
864 rest_j.SetDims(n_j, dim);
866 for (k = 0; k <= n_i; ++k) {
867 indicator_term *it = new indicator_term(*term[i]);
868 it->den.SetDims(n_common + k, dim);
869 for (l = 0; l < n_common; ++l)
870 it->den[l] = common[l];
871 for (l = 0; l < k; ++l)
872 it->den[n_common+l] = rest_i[l];
873 lex_order_rows(it->den);
874 if (k)
875 for (l = 0; l < dim; ++l)
876 evalue_add_constant(it->vertex[l], rest_i[k-1][l]);
877 term.push_back(it);
880 for (k = 0; k <= n_j; ++k) {
881 indicator_term *it = new indicator_term(*term[j]);
882 it->den.SetDims(n_common + k, dim);
883 for (l = 0; l < n_common; ++l)
884 it->den[l] = common[l];
885 for (l = 0; l < k; ++l)
886 it->den[n_common+l] = rest_j[l];
887 lex_order_rows(it->den);
888 if (k)
889 for (l = 0; l < dim; ++l)
890 evalue_add_constant(it->vertex[l], rest_j[k-1][l]);
891 term.push_back(it);
893 term.erase(term.begin()+j);
894 term.erase(term.begin()+i);
897 void indicator::combine(int i, int j)
899 if (j < i) {
900 int tmp = i;
901 i = j;
902 j = tmp;
904 assert (i < j);
905 int dim = term[i]->den.NumCols();
907 mat_ZZ common;
908 mat_ZZ rest_i;
909 mat_ZZ rest_j;
910 int n_common = 0, n_i = 0, n_j = 0;
912 common.SetDims(min(term[i]->den.NumRows(), term[j]->den.NumRows()), dim);
913 rest_i.SetDims(term[i]->den.NumRows(), dim);
914 rest_j.SetDims(term[j]->den.NumRows(), dim);
916 int k, l;
917 for (k = 0, l = 0; k < term[i]->den.NumRows() && l < term[j]->den.NumRows(); ) {
918 int s = lex_cmp(term[i]->den[k], term[j]->den[l]);
919 if (s == 0) {
920 common[n_common++] = term[i]->den[k];
921 ++k;
922 ++l;
923 } else if (s < 0)
924 rest_i[n_i++] = term[i]->den[k++];
925 else
926 rest_j[n_j++] = term[j]->den[l++];
928 while (k < term[i]->den.NumRows())
929 rest_i[n_i++] = term[i]->den[k++];
930 while (l < term[j]->den.NumRows())
931 rest_j[n_j++] = term[j]->den[l++];
932 common.SetDims(n_common, dim);
933 rest_i.SetDims(n_i, dim);
934 rest_j.SetDims(n_j, dim);
936 assert(n_i < 30);
937 assert(n_j < 30);
939 for (k = 0; k < (1 << n_i); ++k) {
940 indicator_term *it = new indicator_term(*term[j]);
941 it->den.SetDims(n_common + n_i + n_j, dim);
942 for (l = 0; l < n_common; ++l)
943 it->den[l] = common[l];
944 for (l = 0; l < n_i; ++l)
945 it->den[n_common+l] = rest_i[l];
946 for (l = 0; l < n_j; ++l)
947 it->den[n_common+n_i+l] = rest_j[l];
948 lex_order_rows(it->den);
949 int change = 0;
950 for (l = 0; l < n_i; ++l) {
951 if (!(k & (1 <<l)))
952 continue;
953 change ^= 1;
954 for (int m = 0; m < dim; ++m)
955 evalue_add_constant(it->vertex[m], rest_i[l][m]);
957 if (change)
958 it->sign = -it->sign;
959 term.push_back(it);
962 for (k = 0; k < (1 << n_j); ++k) {
963 indicator_term *it = new indicator_term(*term[i]);
964 it->den.SetDims(n_common + n_i + n_j, dim);
965 for (l = 0; l < n_common; ++l)
966 it->den[l] = common[l];
967 for (l = 0; l < n_i; ++l)
968 it->den[n_common+l] = rest_i[l];
969 for (l = 0; l < n_j; ++l)
970 it->den[n_common+n_i+l] = rest_j[l];
971 lex_order_rows(it->den);
972 int change = 0;
973 for (l = 0; l < n_j; ++l) {
974 if (!(k & (1 <<l)))
975 continue;
976 change ^= 1;
977 for (int m = 0; m < dim; ++m)
978 evalue_add_constant(it->vertex[m], rest_j[l][m]);
980 if (change)
981 it->sign = -it->sign;
982 term.push_back(it);
984 delete term[i];
985 delete term[j];
986 term.erase(term.begin()+j);
987 term.erase(term.begin()+i);
990 void indicator::substitute(evalue *equation)
992 evalue *fract = NULL;
993 evalue *val = new evalue;
994 value_init(val->d);
995 evalue_copy(val, equation);
997 evalue factor;
998 value_init(factor.d);
999 value_init(factor.x.n);
1001 evalue *e;
1002 for (e = val; value_zero_p(e->d) && e->x.p->type != fractional;
1003 e = &e->x.p->arr[type_offset(e->x.p)])
1006 if (value_zero_p(e->d) && e->x.p->type == fractional)
1007 fract = &e->x.p->arr[0];
1008 else {
1009 for (e = val; value_zero_p(e->d) && e->x.p->type != polynomial;
1010 e = &e->x.p->arr[type_offset(e->x.p)])
1012 assert(value_zero_p(e->d) && e->x.p->type == polynomial);
1015 int offset = type_offset(e->x.p);
1017 assert(value_notzero_p(e->x.p->arr[offset+1].d));
1018 assert(value_notzero_p(e->x.p->arr[offset+1].x.n));
1019 if (value_neg_p(e->x.p->arr[offset+1].x.n)) {
1020 value_oppose(factor.d, e->x.p->arr[offset+1].x.n);
1021 value_assign(factor.x.n, e->x.p->arr[offset+1].d);
1022 } else {
1023 value_assign(factor.d, e->x.p->arr[offset+1].x.n);
1024 value_oppose(factor.x.n, e->x.p->arr[offset+1].d);
1027 free_evalue_refs(&e->x.p->arr[offset+1]);
1028 enode *p = e->x.p;
1029 value_clear(e->d);
1030 *e = e->x.p->arr[offset];
1032 emul(&factor, val);
1034 if (fract) {
1035 for (int i = 0; i < term.size(); ++i)
1036 term[i]->substitute(fract, val);
1038 free_evalue_refs(&p->arr[0]);
1039 } else {
1040 for (int i = 0; i < term.size(); ++i)
1041 term[i]->substitute(p->pos, val);
1044 free_evalue_refs(&factor);
1045 free_evalue_refs(val);
1046 delete val;
1048 free(p);
1051 static void print_varlist(ostream& os, int n, char **names)
1053 int i;
1054 os << "[";
1055 for (i = 0; i < n; ++i) {
1056 if (i)
1057 os << ",";
1058 os << names[i];
1060 os << "]";
1063 static void print_term(ostream& os, Value v, int pos, int dim,
1064 char **names, int *first)
1066 if (value_zero_p(v)) {
1067 if (first && *first && pos >= dim)
1068 os << "0";
1069 return;
1072 if (first) {
1073 if (!*first && value_pos_p(v))
1074 os << "+";
1075 *first = 0;
1077 if (pos < dim) {
1078 if (value_mone_p(v)) {
1079 os << "-";
1080 } else if (!value_one_p(v))
1081 os << VALUE_TO_INT(v);
1082 os << names[pos];
1083 } else
1084 os << VALUE_TO_INT(v);
1087 /* We put all possible existentially quantified variables at the back
1088 * and so if any equalities exist between these variables and the
1089 * other variables, then PolyLib will replace all occurrences of some
1090 * of the other variables by some existentially quantified variables.
1091 * We want the output to have as few as possible references to the
1092 * existentially quantified variables, so we undo what PolyLib did here.
1094 void resolve_existential_vars(Polyhedron *domain, unsigned dim)
1096 int last = domain->NbEq - 1;
1097 /* Matrix "view" of domain for ExchangeRows */
1098 Matrix M;
1099 M.NbRows = domain->NbConstraints;
1100 M.NbColumns = domain->Dimension+2;
1101 M.p_Init = domain->p_Init;
1102 M.p = domain->Constraint;
1103 Value mone;
1104 value_init(mone);
1105 value_set_si(mone, -1);
1106 for (int e = domain->Dimension-1; e >= dim; --e) {
1107 int r;
1108 for (r = last; r >= 0; --r)
1109 if (value_notzero_p(domain->Constraint[r][1+e]))
1110 break;
1111 if (r < 0)
1112 continue;
1113 if (r != last)
1114 ExchangeRows(&M, r, last);
1116 /* Combine uses the coefficient as a multiplier, so it must
1117 * be positive, since we are modifying an inequality.
1119 if (value_neg_p(domain->Constraint[last][1+e]))
1120 Vector_Scale(domain->Constraint[last]+1, domain->Constraint[last]+1,
1121 mone, domain->Dimension+1);
1123 for (int c = 0; c < domain->NbConstraints; ++c) {
1124 if (c == last)
1125 continue;
1126 if (value_notzero_p(domain->Constraint[c][1+e]))
1127 Combine(domain->Constraint[c], domain->Constraint[last],
1128 domain->Constraint[c], 1+e, domain->Dimension+1);
1130 --last;
1132 value_clear(mone);
1135 void max_term::resolve_existential_vars() const
1137 ::resolve_existential_vars(domain, dim);
1140 void max_term::print(ostream& os, char **p) const
1142 char **names = p;
1143 if (dim < domain->Dimension) {
1144 resolve_existential_vars();
1145 names = new char * [domain->Dimension];
1146 int i;
1147 for (i = 0; i < dim; ++i)
1148 names[i] = p[i];
1149 for ( ; i < domain->Dimension; ++i) {
1150 names[i] = new char[10];
1151 snprintf(names[i], 10, "a%d", i - dim);
1155 Value tmp;
1156 value_init(tmp);
1157 os << "{ ";
1158 print_varlist(os, dim, p);
1159 os << " -> ";
1160 os << "[";
1161 for (int i = 0; i < max.size(); ++i) {
1162 if (i)
1163 os << ",";
1164 evalue_print(os, max[i], p);
1166 os << "]";
1167 os << " : ";
1168 if (dim < domain->Dimension) {
1169 os << "exists ";
1170 print_varlist(os, domain->Dimension-dim, names+dim);
1171 os << " : ";
1173 for (int i = 0; i < domain->NbConstraints; ++i) {
1174 int first = 1;
1175 int v = First_Non_Zero(domain->Constraint[i]+1, domain->Dimension);
1176 if (v == -1)
1177 continue;
1178 if (i)
1179 os << " && ";
1180 if (value_pos_p(domain->Constraint[i][v+1])) {
1181 print_term(os, domain->Constraint[i][v+1], v, domain->Dimension,
1182 names, NULL);
1183 if (value_zero_p(domain->Constraint[i][0]))
1184 os << " = ";
1185 else
1186 os << " >= ";
1187 for (int j = v+1; j <= domain->Dimension; ++j) {
1188 value_oppose(tmp, domain->Constraint[i][1+j]);
1189 print_term(os, tmp, j, domain->Dimension,
1190 names, &first);
1192 } else {
1193 value_oppose(tmp, domain->Constraint[i][1+v]);
1194 print_term(os, tmp, v, domain->Dimension,
1195 names, NULL);
1196 if (value_zero_p(domain->Constraint[i][0]))
1197 os << " = ";
1198 else
1199 os << " <= ";
1200 for (int j = v+1; j <= domain->Dimension; ++j)
1201 print_term(os, domain->Constraint[i][1+j], j, domain->Dimension,
1202 names, &first);
1205 os << " }" << endl;
1206 value_clear(tmp);
1208 if (dim < domain->Dimension) {
1209 for (int i = dim; i < domain->Dimension; ++i)
1210 delete [] names[i];
1211 delete [] names;
1215 static void evalue_substitute(evalue *e, evalue **subs)
1217 evalue *v;
1219 if (value_notzero_p(e->d))
1220 return;
1222 enode *p = e->x.p;
1223 for (int i = 0; i < p->size; ++i)
1224 evalue_substitute(&p->arr[i], subs);
1226 if (p->type == polynomial)
1227 v = subs[p->pos-1];
1228 else {
1229 v = new evalue;
1230 value_init(v->d);
1231 value_set_si(v->d, 0);
1232 v->x.p = new_enode(p->type, 3, -1);
1233 value_clear(v->x.p->arr[0].d);
1234 v->x.p->arr[0] = p->arr[0];
1235 evalue_set_si(&v->x.p->arr[1], 0, 1);
1236 evalue_set_si(&v->x.p->arr[2], 1, 1);
1239 int offset = type_offset(p);
1241 for (int i = p->size-1; i >= offset+1; i--) {
1242 emul(v, &p->arr[i]);
1243 eadd(&p->arr[i], &p->arr[i-1]);
1244 free_evalue_refs(&(p->arr[i]));
1247 if (p->type != polynomial) {
1248 free_evalue_refs(v);
1249 delete v;
1252 value_clear(e->d);
1253 *e = p->arr[offset];
1254 free(p);
1257 /* "align" matrix to have nrows by inserting
1258 * the necessary number of rows and an equal number of columns at the end
1259 * right before the constant row/column
1261 static Matrix *align_matrix_initial(Matrix *M, int nrows)
1263 int i;
1264 int newrows = nrows - M->NbRows;
1265 Matrix *M2 = Matrix_Alloc(nrows, newrows + M->NbColumns);
1266 for (i = 0; i < newrows; ++i)
1267 value_set_si(M2->p[M->NbRows-1+i][M->NbColumns-1+i], 1);
1268 for (i = 0; i < M->NbRows-1; ++i) {
1269 Vector_Copy(M->p[i], M2->p[i], M->NbColumns-1);
1270 value_assign(M2->p[i][M2->NbColumns-1], M->p[i][M->NbColumns-1]);
1272 value_assign(M2->p[M2->NbRows-1][M2->NbColumns-1],
1273 M->p[M->NbRows-1][M->NbColumns-1]);
1274 return M2;
1277 /* T maps the compressed parameters to the original parameters,
1278 * while this max_term is based on the compressed parameters
1279 * and we want get the original parameters back.
1281 void max_term::substitute(Matrix *T, unsigned MaxRays)
1283 int nexist = domain->Dimension - (T->NbColumns-1);
1284 Matrix *M = align_matrix_initial(T, T->NbRows+nexist);
1286 Polyhedron *D = DomainImage(domain, M, MaxRays);
1287 Polyhedron_Free(domain);
1288 domain = D;
1289 Matrix_Free(M);
1291 assert(T->NbRows == T->NbColumns);
1292 Matrix *T2 = Matrix_Copy(T);
1293 Matrix *inv = Matrix_Alloc(T->NbColumns, T->NbRows);
1294 int ok = Matrix_Inverse(T2, inv);
1295 Matrix_Free(T2);
1296 assert(ok);
1298 evalue denom;
1299 value_init(denom.d);
1300 value_init(denom.x.n);
1301 value_set_si(denom.x.n, 1);
1302 value_assign(denom.d, inv->p[inv->NbRows-1][inv->NbColumns-1]);
1304 vec_ZZ v;
1305 v.SetLength(inv->NbColumns);
1306 evalue* subs[inv->NbRows-1];
1307 for (int i = 0; i < inv->NbRows-1; ++i) {
1308 values2zz(inv->p[i], v, v.length());
1309 subs[i] = multi_monom(v);
1310 emul(&denom, subs[i]);
1312 free_evalue_refs(&denom);
1314 for (int i = 0; i < max.size(); ++i) {
1315 evalue_substitute(max[i], subs);
1316 reduce_evalue(max[i]);
1319 for (int i = 0; i < inv->NbRows-1; ++i) {
1320 free_evalue_refs(subs[i]);
1321 delete subs[i];
1323 Matrix_Free(inv);
1326 int Last_Non_Zero(Value *p, unsigned len)
1328 for (int i = len-1; i >= 0; --i)
1329 if (value_notzero_p(p[i]))
1330 return i;
1331 return -1;
1334 static void SwapColumns(Value **V, int n, int i, int j)
1336 for (int r = 0; r < n; ++r)
1337 value_swap(V[r][i], V[r][j]);
1340 static void SwapColumns(Polyhedron *P, int i, int j)
1342 SwapColumns(P->Constraint, P->NbConstraints, i, j);
1343 SwapColumns(P->Ray, P->NbRays, i, j);
1346 bool in_domain(Polyhedron *P, Value *val, unsigned dim, unsigned MaxRays)
1348 int nexist = P->Dimension - dim;
1349 int last[P->NbConstraints];
1350 Value tmp, min, max;
1351 Vector *all_val = Vector_Alloc(P->Dimension+1);
1352 bool in = false;
1353 int i;
1354 int alternate;
1356 resolve_existential_vars(P, dim);
1358 Vector_Copy(val, all_val->p, dim);
1359 value_set_si(all_val->p[P->Dimension], 1);
1361 value_init(tmp);
1362 for (int i = 0; i < P->NbConstraints; ++i) {
1363 last[i] = Last_Non_Zero(P->Constraint[i]+1+dim, nexist);
1364 if (last[i] == -1) {
1365 Inner_Product(P->Constraint[i]+1, all_val->p, P->Dimension+1, &tmp);
1366 if (value_neg_p(tmp))
1367 goto out;
1368 if (i < P->NbEq && value_pos_p(tmp))
1369 goto out;
1373 value_init(min);
1374 value_init(max);
1375 alternate = nexist - 1;
1376 for (i = 0; i < nexist; ++i) {
1377 bool min_set = false;
1378 bool max_set = false;
1379 for (int j = 0; j < P->NbConstraints; ++j) {
1380 if (last[j] != i)
1381 continue;
1382 Inner_Product(P->Constraint[j]+1, all_val->p, P->Dimension+1, &tmp);
1383 value_oppose(tmp, tmp);
1384 if (j < P->NbEq) {
1385 if (!mpz_divisible_p(tmp, P->Constraint[j][1+dim+i]))
1386 goto out2;
1387 value_division(tmp, tmp, P->Constraint[j][1+dim+i]);
1388 if (!max_set || value_lt(tmp, max)) {
1389 max_set = true;
1390 value_assign(max, tmp);
1392 if (!min_set || value_gt(tmp, min)) {
1393 min_set = true;
1394 value_assign(min, tmp);
1396 } else {
1397 if (value_pos_p(P->Constraint[j][1+dim+i])) {
1398 mpz_cdiv_q(tmp, tmp, P->Constraint[j][1+dim+i]);
1399 if (!min_set || value_gt(tmp, min)) {
1400 min_set = true;
1401 value_assign(min, tmp);
1403 } else {
1404 mpz_fdiv_q(tmp, tmp, P->Constraint[j][1+dim+i]);
1405 if (!max_set || value_lt(tmp, max)) {
1406 max_set = true;
1407 value_assign(max, tmp);
1412 /* Move another existential variable in current position */
1413 if (!max_set || !min_set) {
1414 if (!(alternate > i)) {
1415 Matrix *M = Matrix_Alloc(dim+i, 1+P->Dimension+1);
1416 for (int j = 0; j < dim+i; ++j) {
1417 value_set_si(M->p[j][1+j], -1);
1418 value_assign(M->p[j][1+P->Dimension], all_val->p[j]);
1420 Polyhedron *Q = AddConstraints(M->p[0], dim+i, P, MaxRays);
1421 Matrix_Free(M);
1422 Q = DomainConstraintSimplify(Q, MaxRays);
1423 Vector *sample = Polyhedron_Sample(Q, MaxRays);
1424 in = !!sample;
1425 if (sample)
1426 Vector_Free(sample);
1427 Polyhedron_Free(Q);
1428 goto out2;
1430 assert(alternate > i);
1431 SwapColumns(P, 1+dim+i, 1+dim+alternate);
1432 resolve_existential_vars(P, dim);
1433 for (int j = 0; j < P->NbConstraints; ++j) {
1434 if (j >= P->NbEq && last[j] < i)
1435 continue;
1436 last[j] = Last_Non_Zero(P->Constraint[j]+1+dim, nexist);
1437 if (last[j] < i) {
1438 Inner_Product(P->Constraint[j]+1, all_val->p, P->Dimension+1,
1439 &tmp);
1440 if (value_neg_p(tmp))
1441 goto out2;
1442 if (j < P->NbEq && value_pos_p(tmp))
1443 goto out2;
1446 --alternate;
1447 --i;
1448 continue;
1450 assert(max_set && min_set);
1451 if (value_lt(max, min))
1452 goto out2;
1453 if (value_ne(max, min)) {
1454 Matrix *M = Matrix_Alloc(dim+i, 1+P->Dimension+1);
1455 for (int j = 0; j < dim+i; ++j) {
1456 value_set_si(M->p[j][1+j], -1);
1457 value_assign(M->p[j][1+P->Dimension], all_val->p[j]);
1459 Polyhedron *Q = AddConstraints(M->p[0], dim+i, P, MaxRays);
1460 Matrix_Free(M);
1461 Q = DomainConstraintSimplify(Q, MaxRays);
1462 Vector *sample = Polyhedron_Sample(Q, MaxRays);
1463 in = !!sample;
1464 if (sample)
1465 Vector_Free(sample);
1466 Polyhedron_Free(Q);
1467 goto out2;
1469 assert(value_eq(max, min));
1470 value_assign(all_val->p[dim+i], max);
1471 alternate = nexist - 1;
1473 in = true;
1474 out2:
1475 value_clear(min);
1476 value_clear(max);
1477 out:
1478 Vector_Free(all_val);
1479 value_clear(tmp);
1480 return in || (P->next && in_domain(P->next, val, dim, MaxRays));
1483 void compute_evalue(evalue *e, Value *val, Value *res)
1485 double d = compute_evalue(e, val);
1486 if (d > 0)
1487 d += .25;
1488 else
1489 d -= .25;
1490 value_set_double(*res, d);
1493 Vector *max_term::eval(Value *val, unsigned MaxRays) const
1495 if (dim == domain->Dimension) {
1496 if (!in_domain(domain, val))
1497 return NULL;
1498 } else {
1499 if (!in_domain(domain, val, dim, MaxRays))
1500 return NULL;
1502 Vector *res = Vector_Alloc(max.size());
1503 for (int i = 0; i < max.size(); ++i) {
1504 compute_evalue(max[i], val, &res->p[i]);
1506 return res;
1509 static Matrix *remove_equalities(Polyhedron **P, unsigned nparam, unsigned MaxRays);
1511 Vector *Polyhedron_not_empty(Polyhedron *P, unsigned MaxRays)
1513 Polyhedron *Porig = P;
1514 Vector *sample = NULL;
1516 POL_ENSURE_VERTICES(P);
1517 if (emptyQ2(P))
1518 return NULL;
1520 for (int i = 0; i < P->NbRays; ++i)
1521 if (value_one_p(P->Ray[i][1+P->Dimension])) {
1522 sample = Vector_Alloc(P->Dimension + 1);
1523 Vector_Copy(P->Ray[i]+1, sample->p, P->Dimension+1);
1524 return sample;
1527 Matrix *T = remove_equalities(&P, 0, MaxRays);
1528 if (P)
1529 sample = Polyhedron_Sample(P, MaxRays);
1530 if (sample) {
1531 if (T) {
1532 Vector *P_sample = Vector_Alloc(Porig->Dimension + 1);
1533 Matrix_Vector_Product(T, sample->p, P_sample->p);
1534 Vector_Free(sample);
1535 sample = P_sample;
1538 if (T) {
1539 Polyhedron_Free(P);
1540 Matrix_Free(T);
1543 return sample;
1546 struct split {
1547 evalue *constraint;
1548 enum sign { le, ge, lge } sign;
1550 split (evalue *c, enum sign s) : constraint(c), sign(s) {}
1553 static void split_on(const split& sp, EDomain *D,
1554 EDomain **Dlt, EDomain **Deq, EDomain **Dgt,
1555 unsigned MaxRays)
1557 Matrix *M, *M2;
1558 EDomain *EDlt = NULL, *EDeq = NULL, *EDgt = NULL;
1559 Polyhedron *D2;
1560 Value mone;
1561 value_init(mone);
1562 value_set_si(mone, -1);
1563 *Dlt = NULL;
1564 *Deq = NULL;
1565 *Dgt = NULL;
1566 vector<evalue *> new_floors;
1567 M = add_ge_constraint(D, sp.constraint, new_floors);
1568 if (sp.sign == split::lge || sp.sign == split::ge) {
1569 M2 = Matrix_Copy(M);
1570 value_decrement(M2->p[M2->NbRows-1][M2->NbColumns-1],
1571 M2->p[M2->NbRows-1][M2->NbColumns-1]);
1572 D2 = Constraints2Polyhedron(M2, MaxRays);
1573 EDgt = new EDomain(D2, D, new_floors);
1574 Polyhedron_Free(D2);
1575 Matrix_Free(M2);
1577 if (sp.sign == split::lge || sp.sign == split::le) {
1578 M2 = Matrix_Copy(M);
1579 Vector_Scale(M2->p[M2->NbRows-1]+1, M2->p[M2->NbRows-1]+1,
1580 mone, M2->NbColumns-1);
1581 value_decrement(M2->p[M2->NbRows-1][M2->NbColumns-1],
1582 M2->p[M2->NbRows-1][M2->NbColumns-1]);
1583 D2 = Constraints2Polyhedron(M2, MaxRays);
1584 EDlt = new EDomain(D2, D, new_floors);
1585 Polyhedron_Free(D2);
1586 Matrix_Free(M2);
1589 assert(sp.sign == split::lge || sp.sign == split::ge || sp.sign == split::le);
1590 value_set_si(M->p[M->NbRows-1][0], 0);
1591 D2 = Constraints2Polyhedron(M, MaxRays);
1592 EDeq = new EDomain(D2, D, new_floors);
1593 Polyhedron_Free(D2);
1594 Matrix_Free(M);
1596 Vector *sample = D->sample;
1597 if (sample && new_floors.size() > 0) {
1598 assert(sample->Size == D->D->Dimension+1);
1599 sample = Vector_Alloc(D->D->Dimension+new_floors.size()+1);
1600 Vector_Copy(D->sample->p, sample->p, D->D->Dimension);
1601 value_set_si(sample->p[D->D->Dimension+new_floors.size()], 1);
1602 for (int i = 0; i < new_floors.size(); ++i)
1603 compute_evalue(new_floors[i], sample->p, sample->p+D->D->Dimension+i);
1606 for (int i = 0; i < new_floors.size(); ++i) {
1607 free_evalue_refs(new_floors[i]);
1608 delete new_floors[i];
1611 if (EDeq) {
1612 if (sample && in_domain(EDeq->D, sample->p, sample->Size-1, MaxRays)) {
1613 EDeq->sample = Vector_Alloc(sample->Size);
1614 Vector_Copy(sample->p, EDeq->sample->p, sample->Size);
1615 } else if (!(EDeq->sample = Polyhedron_not_empty(EDeq->D, MaxRays))) {
1616 delete EDeq;
1617 EDeq = NULL;
1620 if (EDgt) {
1621 if (sample && in_domain(EDgt->D, sample->p, sample->Size-1, MaxRays)) {
1622 EDgt->sample = Vector_Alloc(sample->Size);
1623 Vector_Copy(sample->p, EDgt->sample->p, sample->Size);
1624 } else if (!(EDgt->sample = Polyhedron_not_empty(EDgt->D, MaxRays))) {
1625 delete EDgt;
1626 EDgt = NULL;
1629 if (EDlt) {
1630 if (sample && in_domain(EDlt->D, sample->p, sample->Size-1, MaxRays)) {
1631 EDlt->sample = Vector_Alloc(sample->Size);
1632 Vector_Copy(sample->p, EDlt->sample->p, sample->Size);
1633 } else if (!(EDlt->sample = Polyhedron_not_empty(EDlt->D, MaxRays))) {
1634 delete EDlt;
1635 EDlt = NULL;
1638 *Dlt = EDlt;
1639 *Deq = EDeq;
1640 *Dgt = EDgt;
1641 value_clear(mone);
1642 if (sample != D->sample)
1643 Vector_Free(sample);
1646 ostream & operator<< (ostream & os, const vector<int> & v)
1648 os << "[";
1649 for (int i = 0; i < v.size(); ++i) {
1650 if (i)
1651 os << ", ";
1652 os << v[i];
1654 os << "]";
1655 return os;
1658 static bool isTranslation(Matrix *M)
1660 unsigned i, j;
1661 if (M->NbRows != M->NbColumns)
1662 return False;
1664 for (i = 0;i < M->NbRows; i ++)
1665 for (j = 0; j < M->NbColumns-1; j ++)
1666 if (i == j) {
1667 if(value_notone_p(M->p[i][j]))
1668 return False;
1669 } else {
1670 if(value_notzero_p(M->p[i][j]))
1671 return False;
1673 return value_one_p(M->p[M->NbRows-1][M->NbColumns-1]);
1676 static Matrix *compress_parameters(Polyhedron **P, Polyhedron **C,
1677 unsigned nparam, unsigned MaxRays)
1679 Matrix *M, *T, *CP;
1681 /* compress_parms doesn't like equalities that only involve parameters */
1682 for (int i = 0; i < (*P)->NbEq; ++i)
1683 assert(First_Non_Zero((*P)->Constraint[i]+1, (*P)->Dimension-nparam) != -1);
1685 M = Matrix_Alloc((*P)->NbEq, (*P)->Dimension+2);
1686 Vector_Copy((*P)->Constraint[0], M->p[0], (*P)->NbEq * ((*P)->Dimension+2));
1687 CP = compress_parms(M, nparam);
1688 Matrix_Free(M);
1690 if (isTranslation(CP)) {
1691 Matrix_Free(CP);
1692 return NULL;
1695 T = align_matrix(CP, (*P)->Dimension+1);
1696 *P = Polyhedron_Preimage(*P, T, MaxRays);
1697 Matrix_Free(T);
1699 *C = Polyhedron_Preimage(*C, CP, MaxRays);
1701 return CP;
1704 static Matrix *remove_equalities(Polyhedron **P, unsigned nparam, unsigned MaxRays)
1706 /* Matrix "view" of equalities */
1707 Matrix M;
1708 M.NbRows = (*P)->NbEq;
1709 M.NbColumns = (*P)->Dimension+2;
1710 M.p_Init = (*P)->p_Init;
1711 M.p = (*P)->Constraint;
1713 Matrix *T = compress_variables(&M, nparam);
1715 if (!T) {
1716 *P = NULL;
1717 return NULL;
1719 if (isIdentity(T)) {
1720 Matrix_Free(T);
1721 T = NULL;
1722 } else
1723 *P = Polyhedron_Preimage(*P, T, MaxRays);
1725 return T;
1728 static vector<max_term*> lexmin(indicator& ind, EDomain *D, unsigned nparam,
1729 unsigned MaxRays, vector<int> loc)
1731 vector<max_term*> maxima;
1732 int len = 1 + D->D->Dimension + 1;
1733 Value lcm, a, b;
1734 evalue mone;
1735 EDomain *Dorig = D;
1737 value_init(mone.d);
1738 evalue_set_si(&mone, -1, 1);
1739 value_init(lcm);
1740 value_init(a);
1741 value_init(b);
1742 Vector *c = Vector_Alloc(len);
1743 Matrix *T = Matrix_Alloc(2, len-1);
1744 for (int i = 0; i < ind.term.size(); ++i) {
1745 bool restart = false; /* true if we have modified ind from i up */
1746 bool stop = false; /* true if i can never be smallest */
1747 int peel = -1; /* term to peel against */
1748 vector<split> splits;
1749 if (ind.term[i]->sign < 0)
1750 continue;
1751 int dim = ind.term[i]->den.NumCols();
1752 int j;
1753 for (j = 0; j < ind.term.size(); ++j) {
1754 if (i == j)
1755 continue;
1756 int k;
1757 for (k = 0; k < dim; ++k) {
1758 /* compute ind.term->[i]->vertex[k] - ind.term->[j]->vertex[k] */
1759 evalue *diff = new evalue;
1760 value_init(diff->d);
1761 evalue_copy(diff, ind.term[j]->vertex[k]);
1762 emul(&mone, diff);
1763 eadd(ind.term[i]->vertex[k], diff);
1764 reduce_evalue(diff);
1765 int fract = evalue2constraint(D, diff, c->p, len);
1766 Vector_Copy(c->p+1, T->p[0], len-1);
1767 value_assign(T->p[1][len-2], c->p[0]);
1769 int min, max;
1770 interval_minmax(D->D, T, &min, &max, MaxRays);
1771 if (max < 0) {
1772 free_evalue_refs(diff);
1773 delete diff;
1774 break;
1776 if (fract) {
1777 emul(&mone, diff);
1778 evalue2constraint(D, diff, c->p, len);
1779 emul(&mone, diff);
1780 Vector_Copy(c->p+1, T->p[0], len-1);
1781 value_assign(T->p[1][len-2], c->p[0]);
1783 int negmin, negmax;
1784 interval_minmax(D->D, T, &negmin, &negmax, MaxRays);
1785 min = -negmax;
1787 if (min > 0) {
1788 free_evalue_refs(diff);
1789 delete diff;
1790 stop = true;
1791 break;
1793 if (max == 0 && min == 0) {
1794 if (!EVALUE_IS_ZERO(*diff)) {
1795 ind.substitute(diff);
1796 ind.simplify();
1797 restart = true;
1799 free_evalue_refs(diff);
1800 delete diff;
1801 if (restart)
1802 break;
1803 continue;
1805 if (min < 0 && max == 0)
1806 splits.push_back(split(diff, split::le));
1807 else if (max > 0 && min == 0)
1808 splits.push_back(split(diff, split::ge));
1809 else
1810 splits.push_back(split(diff, split::lge));
1811 break;
1813 if (k == dim && ind.term[j]->sign < 0)
1814 peel = j;
1815 if (stop || restart)
1816 break;
1818 if (restart) {
1819 /* The ith entry may have been removed, so we have to consider
1820 * it again.
1822 --i;
1823 for (j = 0; j < splits.size(); ++j) {
1824 free_evalue_refs(splits[j].constraint);
1825 delete splits[j].constraint;
1827 continue;
1829 if (stop) {
1830 for (j = 0; j < splits.size(); ++j) {
1831 free_evalue_refs(splits[j].constraint);
1832 delete splits[j].constraint;
1834 continue;
1836 if (peel != -1) {
1837 // ind.peel(i, peel);
1838 ind.combine(i, peel);
1839 ind.simplify();
1840 i = -1; /* start over */
1841 for (j = 0; j < splits.size(); ++j) {
1842 free_evalue_refs(splits[j].constraint);
1843 delete splits[j].constraint;
1845 continue;
1847 if (splits.size() != 0) {
1848 for (j = 0; j < splits.size(); ++j)
1849 if (splits[j].sign == split::le)
1850 break;
1851 if (j == splits.size())
1852 j = 0;
1853 EDomain *Dlt, *Deq, *Dgt;
1854 split_on(splits[j], D, &Dlt, &Deq, &Dgt, MaxRays);
1855 assert(Dlt || Deq || Dgt);
1856 if (Deq) {
1857 loc.push_back(0);
1858 indicator indeq(ind);
1859 indeq.substitute(splits[j].constraint);
1860 Polyhedron *P = Polyhedron_Project_Initial(Deq->D, nparam);
1861 P = DomainConstraintSimplify(P, MaxRays);
1862 indeq.reduce_in_domain(P);
1863 Polyhedron_Free(P);
1864 indeq.simplify();
1865 vector<max_term*> maxeq = lexmin(indeq, Deq, nparam,
1866 MaxRays, loc);
1867 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
1868 loc.pop_back();
1869 delete Deq;
1871 if (Dgt) {
1872 loc.push_back(1);
1873 indicator indgt(ind);
1874 Polyhedron *P = Polyhedron_Project_Initial(Dgt->D, nparam);
1875 P = DomainConstraintSimplify(P, MaxRays);
1876 indgt.reduce_in_domain(P);
1877 Polyhedron_Free(P);
1878 indgt.simplify();
1879 vector<max_term*> maxeq = lexmin(indgt, Dgt, nparam,
1880 MaxRays, loc);
1881 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
1882 loc.pop_back();
1883 delete Dgt;
1885 if (Dlt) {
1886 loc.push_back(-1);
1887 Polyhedron *P = Polyhedron_Project_Initial(Dlt->D, nparam);
1888 P = DomainConstraintSimplify(P, MaxRays);
1889 ind.reduce_in_domain(P);
1890 Polyhedron_Free(P);
1891 ind.simplify();
1892 if (D != Dorig)
1893 delete D;
1894 D = Dlt;
1895 if (splits.size() > 1) {
1896 vector<max_term*> maxeq = lexmin(ind, Dlt, nparam,
1897 MaxRays, loc);
1898 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
1899 for (j = 0; j < splits.size(); ++j) {
1900 free_evalue_refs(splits[j].constraint);
1901 delete splits[j].constraint;
1903 break;
1906 /* the vertex turned out not to be minimal */
1907 for (j = 0; j < splits.size(); ++j) {
1908 free_evalue_refs(splits[j].constraint);
1909 delete splits[j].constraint;
1911 if (!Dlt)
1912 break;
1914 max_term *maximum = new max_term;
1915 maxima.push_back(maximum);
1916 maximum->dim = nparam;
1917 maximum->domain = Polyhedron_Copy(D->D);
1918 for (int j = 0; j < dim; ++j) {
1919 evalue *E = new evalue;
1920 value_init(E->d);
1921 evalue_copy(E, ind.term[i]->vertex[j]);
1922 if (evalue_frac2floor_in_domain(E, D->D))
1923 reduce_evalue(E);
1924 maximum->max.push_back(E);
1926 break;
1928 Matrix_Free(T);
1929 Vector_Free(c);
1930 value_clear(lcm);
1931 value_clear(a);
1932 value_clear(b);
1933 free_evalue_refs(&mone);
1934 if (D != Dorig)
1935 delete D;
1936 return maxima;
1939 static vector<max_term*> lexmin(Polyhedron *P, Polyhedron *C, unsigned MaxRays)
1941 unsigned nparam = C->Dimension;
1942 Param_Polyhedron *PP = NULL;
1943 Polyhedron *CEq = NULL, *pVD;
1944 Matrix *CT = NULL;
1945 Matrix *T = NULL, *CP = NULL;
1946 Param_Domain *D, *next;
1947 Param_Vertices *V;
1948 Polyhedron *Porig = P;
1949 Polyhedron *Corig = C;
1950 int i;
1951 vector<max_term*> all_max;
1952 Polyhedron *Q;
1954 if (emptyQ2(P))
1955 return all_max;
1957 POL_ENSURE_VERTICES(P);
1959 if (emptyQ2(P))
1960 return all_max;
1962 assert(P->NbBid == 0);
1964 if (P->NbEq > 0) {
1965 if (nparam > 0)
1966 CP = compress_parameters(&P, &C, nparam, MaxRays);
1967 Q = P;
1968 T = remove_equalities(&P, nparam, MaxRays);
1969 if (P != Q && Q != Porig)
1970 Polyhedron_Free(Q);
1971 if (!P) {
1972 if (C != Corig)
1973 Polyhedron_Free(C);
1974 return all_max;
1978 Q = P;
1979 PP = Polyhedron2Param_SimplifiedDomain(&P,C,
1980 (MaxRays & POL_NO_DUAL) ? 0 : MaxRays,
1981 &CEq,&CT);
1982 if (P != Q && Q != Porig)
1983 Polyhedron_Free(Q);
1985 if (CT) {
1986 if (isIdentity(CT)) {
1987 Matrix_Free(CT);
1988 CT = NULL;
1989 } else
1990 nparam = CT->NbRows - 1;
1993 unsigned dim = P->Dimension - nparam;
1995 int nd;
1996 for (nd = 0, D=PP->D; D; ++nd, D=D->next);
1997 Polyhedron **fVD = new Polyhedron*[nd];
1999 indicator_constructor ic(P, dim, PP->nbV, T);
2001 for (i = 0, V = PP->V; V; V = V->next, i++) {
2002 ic.decompose_at_vertex(V, i, MaxRays);
2005 for (nd = 0, D=PP->D; D; D=next) {
2006 next = D->next;
2008 Polyhedron *rVD = reduce_domain(D->Domain, CT, CEq,
2009 fVD, nd, MaxRays);
2010 if (!rVD)
2011 continue;
2013 pVD = CT ? DomainImage(rVD,CT,MaxRays) : rVD;
2015 indicator ind;
2017 FORALL_PVertex_in_ParamPolyhedron(V,D,PP) // _i is internal counter
2018 for (int j = 0; j < ic.terms[_i].size(); ++j) {
2019 indicator_term *term = new indicator_term(*ic.terms[_i][j]);
2020 term->reduce_in_domain(pVD);
2021 ind.term.push_back(term);
2023 END_FORALL_PVertex_in_ParamPolyhedron;
2025 ind.simplify();
2027 EDomain epVD(pVD);
2028 vector<int> loc;
2029 vector<max_term*> maxima = lexmin(ind, &epVD, nparam, MaxRays, loc);
2030 if (CP)
2031 for (int j = 0; j < maxima.size(); ++j)
2032 maxima[j]->substitute(CP, MaxRays);
2033 all_max.insert(all_max.end(), maxima.begin(), maxima.end());
2035 ++nd;
2036 if (rVD != pVD)
2037 Domain_Free(pVD);
2038 Domain_Free(rVD);
2040 if (CP)
2041 Matrix_Free(CP);
2042 if (T)
2043 Matrix_Free(T);
2044 Param_Polyhedron_Free(PP);
2045 if (CEq)
2046 Polyhedron_Free(CEq);
2047 for (--nd; nd >= 0; --nd) {
2048 Domain_Free(fVD[nd]);
2050 delete [] fVD;
2051 if (C != Corig)
2052 Polyhedron_Free(C);
2053 if (P != Porig)
2054 Polyhedron_Free(P);
2056 return all_max;
2059 static void verify_results(Polyhedron *A, Polyhedron *C,
2060 vector<max_term*>& maxima, int m, int M,
2061 int print_all, unsigned MaxRays);
2063 int main(int argc, char **argv)
2065 Polyhedron *A, *C;
2066 Matrix *MA;
2067 int bignum;
2068 char **iter_names, **param_names;
2069 int c, ind = 0;
2070 int range = 0;
2071 int verify = 0;
2072 int print_all = 0;
2073 int m = INT_MAX, M = INT_MIN, r;
2074 int print_solution = 1;
2076 while ((c = getopt_long(argc, argv, "TAm:M:r:V", options, &ind)) != -1) {
2077 switch (c) {
2078 case 'T':
2079 verify = 1;
2080 break;
2081 case 'A':
2082 print_all = 1;
2083 break;
2084 case 'm':
2085 m = atoi(optarg);
2086 verify = 1;
2087 break;
2088 case 'M':
2089 M = atoi(optarg);
2090 verify = 1;
2091 break;
2092 case 'r':
2093 M = atoi(optarg);
2094 m = -M;
2095 verify = 1;
2096 break;
2097 case 'V':
2098 printf(barvinok_version());
2099 exit(0);
2100 break;
2104 MA = Matrix_Read();
2105 C = Constraints2Polyhedron(MA, MAXRAYS);
2106 Matrix_Free(MA);
2107 fscanf(stdin, " %d", &bignum);
2108 assert(bignum == -1);
2109 MA = Matrix_Read();
2110 A = Constraints2Polyhedron(MA, MAXRAYS);
2111 Matrix_Free(MA);
2113 if (A->Dimension >= VBIGDIM)
2114 r = VSRANGE;
2115 else if (A->Dimension >= BIGDIM)
2116 r = SRANGE;
2117 else
2118 r = RANGE;
2119 if (M == INT_MIN)
2120 M = r;
2121 if (m == INT_MAX)
2122 m = -r;
2124 if (verify && m > M) {
2125 fprintf(stderr,"Nothing to do: min > max !\n");
2126 return(0);
2128 if (verify)
2129 print_solution = 0;
2131 iter_names = util_generate_names(A->Dimension - C->Dimension, "i");
2132 param_names = util_generate_names(C->Dimension, "p");
2133 if (print_solution) {
2134 Polyhedron_Print(stdout, P_VALUE_FMT, A);
2135 Polyhedron_Print(stdout, P_VALUE_FMT, C);
2137 vector<max_term*> maxima = lexmin(A, C, MAXRAYS);
2138 if (print_solution)
2139 for (int i = 0; i < maxima.size(); ++i)
2140 maxima[i]->print(cout, param_names);
2142 if (verify)
2143 verify_results(A, C, maxima, m, M, print_all, MAXRAYS);
2145 for (int i = 0; i < maxima.size(); ++i)
2146 delete maxima[i];
2148 util_free_names(A->Dimension - C->Dimension, iter_names);
2149 util_free_names(C->Dimension, param_names);
2150 Polyhedron_Free(A);
2151 Polyhedron_Free(C);
2153 return 0;
2156 static bool lexmin(int pos, Polyhedron *P, Value *context)
2158 Value LB, UB, k;
2159 int lu_flags;
2160 bool found = false;
2162 if (emptyQ(P))
2163 return false;
2165 value_init(LB); value_init(UB); value_init(k);
2166 value_set_si(LB,0);
2167 value_set_si(UB,0);
2168 lu_flags = lower_upper_bounds(pos,P,context,&LB,&UB);
2169 assert(!(lu_flags & LB_INFINITY));
2171 value_set_si(context[pos],0);
2172 if (!lu_flags && value_lt(UB,LB)) {
2173 value_clear(LB); value_clear(UB); value_clear(k);
2174 return false;
2176 if (!P->next) {
2177 value_assign(context[pos], LB);
2178 value_clear(LB); value_clear(UB); value_clear(k);
2179 return true;
2181 for (value_assign(k,LB); lu_flags || value_le(k,UB); value_increment(k,k)) {
2182 value_assign(context[pos],k);
2183 if ((found = lexmin(pos+1, P->next, context)))
2184 break;
2186 if (!found)
2187 value_set_si(context[pos],0);
2188 value_clear(LB); value_clear(UB); value_clear(k);
2189 return found;
2192 static void print_list(FILE *out, Value *z, char* brackets, int len)
2194 fprintf(out, "%c", brackets[0]);
2195 value_print(out, VALUE_FMT,z[0]);
2196 for (int k = 1; k < len; ++k) {
2197 fprintf(out, ", ");
2198 value_print(out, VALUE_FMT,z[k]);
2200 fprintf(out, "%c", brackets[1]);
2203 static int check_poly(Polyhedron *S, Polyhedron *CS, vector<max_term*>& maxima,
2204 int nparam, int pos, Value *z, int print_all, int st,
2205 unsigned MaxRays)
2207 if (pos == nparam) {
2208 int k;
2209 bool found = lexmin(1, S, z);
2211 if (print_all) {
2212 printf("lexmin");
2213 print_list(stdout, z+S->Dimension-nparam+1, "()", nparam);
2214 printf(" = ");
2215 if (found)
2216 print_list(stdout, z+1, "[]", S->Dimension-nparam);
2217 printf(" ");
2220 Vector *min = NULL;
2221 for (int i = 0; i < maxima.size(); ++i)
2222 if ((min = maxima[i]->eval(z+S->Dimension-nparam+1, MaxRays)))
2223 break;
2225 int ok = !(found ^ !!min);
2226 if (found && min)
2227 for (int i = 0; i < S->Dimension-nparam; ++i)
2228 if (value_ne(z[1+i], min->p[i])) {
2229 ok = 0;
2230 break;
2232 if (!ok) {
2233 printf("\n");
2234 fflush(stdout);
2235 fprintf(stderr, "Error !\n");
2236 fprintf(stderr, "lexmin");
2237 print_list(stderr, z+S->Dimension-nparam+1, "()", nparam);
2238 fprintf(stderr, " should be ");
2239 if (found)
2240 print_list(stderr, z+1, "[]", S->Dimension-nparam);
2241 fprintf(stderr, " while digging gives ");
2242 if (min)
2243 print_list(stderr, min->p, "[]", S->Dimension-nparam);
2244 fprintf(stderr, ".\n");
2245 return 0;
2246 } else if (print_all)
2247 printf("OK.\n");
2248 if (min)
2249 Vector_Free(min);
2251 for (k = 1; k <= S->Dimension-nparam; ++k)
2252 value_set_si(z[k], 0);
2253 } else {
2254 Value tmp;
2255 Value LB, UB;
2256 value_init(tmp);
2257 value_init(LB);
2258 value_init(UB);
2259 int ok =
2260 !(lower_upper_bounds(1+pos, CS, &z[S->Dimension-nparam], &LB, &UB));
2261 for (value_assign(tmp,LB); value_le(tmp,UB); value_increment(tmp,tmp)) {
2262 if (!print_all) {
2263 int k = VALUE_TO_INT(tmp);
2264 if (!pos && !(k%st)) {
2265 printf("o");
2266 fflush(stdout);
2269 value_assign(z[pos+S->Dimension-nparam+1],tmp);
2270 if (!check_poly(S, CS->next, maxima, nparam, pos+1, z, print_all, st,
2271 MaxRays)) {
2272 value_clear(tmp);
2273 value_clear(LB);
2274 value_clear(UB);
2275 return 0;
2278 value_set_si(z[pos+S->Dimension-nparam+1],0);
2279 value_clear(tmp);
2280 value_clear(LB);
2281 value_clear(UB);
2283 return 1;
2286 void verify_results(Polyhedron *A, Polyhedron *C, vector<max_term*>& maxima,
2287 int m, int M, int print_all, unsigned MaxRays)
2289 Polyhedron *CC, *CC2, *CS, *S;
2290 unsigned nparam = C->Dimension;
2291 Value *p;
2292 int i;
2293 int st;
2295 CC = Polyhedron_Project(A, nparam);
2296 CC2 = DomainIntersection(C, CC, MAXRAYS);
2297 Domain_Free(CC);
2298 CC = CC2;
2300 /* Intersect context with range */
2301 if (nparam > 0) {
2302 Matrix *MM;
2303 Polyhedron *U;
2305 MM = Matrix_Alloc(2*C->Dimension, C->Dimension+2);
2306 for (int i = 0; i < C->Dimension; ++i) {
2307 value_set_si(MM->p[2*i][0], 1);
2308 value_set_si(MM->p[2*i][1+i], 1);
2309 value_set_si(MM->p[2*i][1+C->Dimension], -m);
2310 value_set_si(MM->p[2*i+1][0], 1);
2311 value_set_si(MM->p[2*i+1][1+i], -1);
2312 value_set_si(MM->p[2*i+1][1+C->Dimension], M);
2314 CC2 = AddConstraints(MM->p[0], 2*CC->Dimension, CC, MAXRAYS);
2315 U = Universe_Polyhedron(0);
2316 CS = Polyhedron_Scan(CC2, U, MAXRAYS & POL_NO_DUAL ? 0 : MAXRAYS);
2317 Polyhedron_Free(U);
2318 Polyhedron_Free(CC2);
2319 Matrix_Free(MM);
2320 } else
2321 CS = NULL;
2323 p = ALLOCN(Value, A->Dimension+2);
2324 for (i=0; i <= A->Dimension; i++) {
2325 value_init(p[i]);
2326 value_set_si(p[i],0);
2328 value_init(p[i]);
2329 value_set_si(p[i], 1);
2331 S = Polyhedron_Scan(A, C, MAXRAYS & POL_NO_DUAL ? 0 : MAXRAYS);
2333 if (!print_all && C->Dimension > 0) {
2334 if (M-m > 80)
2335 st = 1+(M-m)/80;
2336 else
2337 st = 1;
2338 for (int i = m; i <= M; i += st)
2339 printf(".");
2340 printf( "\r" );
2341 fflush(stdout);
2344 if (S) {
2345 if (!(CS && emptyQ2(CS)))
2346 check_poly(S, CS, maxima, nparam, 0, p, print_all, st, MaxRays);
2347 Domain_Free(S);
2350 if (!print_all)
2351 printf("\n");
2353 for (i=0; i <= (A->Dimension+1); i++)
2354 value_clear(p[i]);
2355 free(p);
2356 if (CS)
2357 Domain_Free(CS);
2358 Polyhedron_Free(CC);