barvinok.cc: enumerator::handle: drop unused variable
[barvinok.git] / lexmin.cc
blobf4a2de3722eb8c21e118301725c3bc5c9fceeacb
1 #include <assert.h>
2 #include <iostream>
3 #include <vector>
4 #include <map>
5 #include <set>
6 #define partition STL_PARTITION
7 #include <algorithm>
8 #undef partition
9 #include <gmp.h>
10 #include <NTL/vec_ZZ.h>
11 #include <NTL/mat_ZZ.h>
12 #include <isl_set_polylib.h>
13 #include <barvinok/barvinok.h>
14 #include <barvinok/evalue.h>
15 #include <barvinok/options.h>
16 #include <barvinok/util.h>
17 #include "conversion.h"
18 #include "decomposer.h"
19 #include "lattice_point.h"
20 #include "reduce_domain.h"
21 #include "mat_util.h"
22 #include "edomain.h"
23 #include "evalue_util.h"
24 #include "remove_equalities.h"
25 #include "polysign.h"
26 #include "verify.h"
27 #include "lexmin.h"
28 #include "param_util.h"
30 #undef CS /* for Solaris 10 */
32 using namespace NTL;
34 using std::vector;
35 using std::map;
36 using std::cerr;
37 using std::cout;
38 using std::endl;
39 using std::ostream;
41 #define ALLOC(type) (type*)malloc(sizeof(type))
42 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
44 static int type_offset(enode *p)
46 return p->type == fractional ? 1 :
47 p->type == flooring ? 1 : 0;
50 void compute_evalue(evalue *e, Value *val, Value *res)
52 double d = compute_evalue(e, val);
53 if (d > 0)
54 d += .25;
55 else
56 d -= .25;
57 value_set_double(*res, d);
60 struct indicator_term {
61 int sign;
62 int pos; /* number of rational vertex */
63 int n; /* number of cone associated to given rational vertex */
64 mat_ZZ den;
65 evalue **vertex;
67 indicator_term(unsigned dim, int pos) {
68 den.SetDims(0, dim);
69 vertex = new evalue* [dim];
70 this->pos = pos;
71 n = -1;
72 sign = 0;
74 indicator_term(unsigned dim, int pos, int n) {
75 den.SetDims(dim, dim);
76 vertex = new evalue* [dim];
77 this->pos = pos;
78 this->n = n;
80 indicator_term(const indicator_term& src) {
81 sign = src.sign;
82 pos = src.pos;
83 n = src.n;
84 den = src.den;
85 unsigned dim = den.NumCols();
86 vertex = new evalue* [dim];
87 for (int i = 0; i < dim; ++i) {
88 vertex[i] = ALLOC(evalue);
89 value_init(vertex[i]->d);
90 evalue_copy(vertex[i], src.vertex[i]);
93 void swap(indicator_term *other) {
94 int tmp;
95 tmp = sign; sign = other->sign; other->sign = tmp;
96 tmp = pos; pos = other->pos; other->pos = tmp;
97 tmp = n; n = other->n; other->n = tmp;
98 mat_ZZ tmp_den = den; den = other->den; other->den = tmp_den;
99 unsigned dim = den.NumCols();
100 for (int i = 0; i < dim; ++i) {
101 evalue *tmp = vertex[i];
102 vertex[i] = other->vertex[i];
103 other->vertex[i] = tmp;
106 ~indicator_term() {
107 unsigned dim = den.NumCols();
108 for (int i = 0; i < dim; ++i)
109 evalue_free(vertex[i]);
110 delete [] vertex;
112 void print(ostream& os, char **p) const;
113 void substitute(Matrix *T);
114 void normalize();
115 void substitute(evalue *fract, evalue *val);
116 void substitute(int pos, evalue *val);
117 void reduce_in_domain(Polyhedron *D);
118 bool is_opposite(const indicator_term *neg) const;
119 vec_ZZ eval(Value *val) const {
120 vec_ZZ v;
121 unsigned dim = den.NumCols();
122 v.SetLength(dim);
123 Value tmp;
124 value_init(tmp);
125 for (int i = 0; i < dim; ++i) {
126 compute_evalue(vertex[i], val, &tmp);
127 value2zz(tmp, v[i]);
129 value_clear(tmp);
130 return v;
134 static int evalue_rational_cmp(const evalue *e1, const evalue *e2)
136 int r;
137 Value m;
138 Value m2;
139 value_init(m);
140 value_init(m2);
142 assert(value_notzero_p(e1->d));
143 assert(value_notzero_p(e2->d));
144 value_multiply(m, e1->x.n, e2->d);
145 value_multiply(m2, e2->x.n, e1->d);
146 if (value_lt(m, m2))
147 r = -1;
148 else if (value_gt(m, m2))
149 r = 1;
150 else
151 r = 0;
152 value_clear(m);
153 value_clear(m2);
155 return r;
158 static int evalue_cmp(const evalue *e1, const evalue *e2)
160 if (value_notzero_p(e1->d)) {
161 if (value_zero_p(e2->d))
162 return -1;
163 return evalue_rational_cmp(e1, e2);
165 if (value_notzero_p(e2->d))
166 return 1;
167 if (e1->x.p->type != e2->x.p->type)
168 return e1->x.p->type - e2->x.p->type;
169 if (e1->x.p->size != e2->x.p->size)
170 return e1->x.p->size - e2->x.p->size;
171 if (e1->x.p->pos != e2->x.p->pos)
172 return e1->x.p->pos - e2->x.p->pos;
173 assert(e1->x.p->type == polynomial ||
174 e1->x.p->type == fractional ||
175 e1->x.p->type == flooring);
176 for (int i = 0; i < e1->x.p->size; ++i) {
177 int s = evalue_cmp(&e1->x.p->arr[i], &e2->x.p->arr[i]);
178 if (s)
179 return s;
181 return 0;
184 void evalue_length(evalue *e, int len[2])
186 len[0] = 0;
187 len[1] = 0;
189 while (value_zero_p(e->d)) {
190 assert(e->x.p->type == polynomial ||
191 e->x.p->type == fractional ||
192 e->x.p->type == flooring);
193 if (e->x.p->type == polynomial)
194 len[1]++;
195 else
196 len[0]++;
197 int offset = type_offset(e->x.p);
198 assert(e->x.p->size == offset+2);
199 e = &e->x.p->arr[offset];
203 static bool it_smaller(const indicator_term* it1, const indicator_term* it2)
205 if (it1 == it2)
206 return false;
207 int len1[2], len2[2];
208 unsigned dim = it1->den.NumCols();
209 for (int i = 0; i < dim; ++i) {
210 evalue_length(it1->vertex[i], len1);
211 evalue_length(it2->vertex[i], len2);
212 if (len1[0] != len2[0])
213 return len1[0] < len2[0];
214 if (len1[1] != len2[1])
215 return len1[1] < len2[1];
217 if (it1->pos != it2->pos)
218 return it1->pos < it2->pos;
219 if (it1->n != it2->n)
220 return it1->n < it2->n;
221 int s = lex_cmp(it1->den, it2->den);
222 if (s)
223 return s < 0;
224 for (int i = 0; i < dim; ++i) {
225 s = evalue_cmp(it1->vertex[i], it2->vertex[i]);
226 if (s)
227 return s < 0;
229 assert(it1->sign != 0);
230 assert(it2->sign != 0);
231 if (it1->sign != it2->sign)
232 return it1->sign > 0;
233 return it1 < it2;
236 struct smaller_it {
237 static const int requires_resort;
238 bool operator()(const indicator_term* it1, const indicator_term* it2) const {
239 return it_smaller(it1, it2);
242 const int smaller_it::requires_resort = 1;
244 struct smaller_it_p {
245 static const int requires_resort;
246 bool operator()(const indicator_term* it1, const indicator_term* it2) const {
247 return it1 < it2;
250 const int smaller_it_p::requires_resort = 0;
252 /* Returns true if this and neg are opposite using the knowledge
253 * that they have the same numerator.
254 * In particular, we check that the signs are different and that
255 * the denominator is the same.
257 bool indicator_term::is_opposite(const indicator_term *neg) const
259 if (sign + neg->sign != 0)
260 return false;
261 if (den != neg->den)
262 return false;
263 return true;
266 void indicator_term::reduce_in_domain(Polyhedron *D)
268 for (int k = 0; k < den.NumCols(); ++k) {
269 reduce_evalue_in_domain(vertex[k], D);
270 if (evalue_range_reduction_in_domain(vertex[k], D))
271 reduce_evalue(vertex[k]);
275 void indicator_term::print(ostream& os, char **p) const
277 unsigned dim = den.NumCols();
278 unsigned factors = den.NumRows();
279 if (sign == 0)
280 os << " s ";
281 else if (sign > 0)
282 os << " + ";
283 else
284 os << " - ";
285 os << '[';
286 for (int i = 0; i < dim; ++i) {
287 if (i)
288 os << ',';
289 evalue_print(os, vertex[i], p);
291 os << ']';
292 for (int i = 0; i < factors; ++i) {
293 os << " + t" << i << "*[";
294 for (int j = 0; j < dim; ++j) {
295 if (j)
296 os << ',';
297 os << den[i][j];
299 os << "]";
301 os << " ((" << pos << ", " << n << ", " << (void*)this << "))";
304 /* Perform the substitution specified by T on the variables.
305 * T has dimension (newdim+nparam+1) x (olddim + nparam + 1).
306 * The substitution is performed as in gen_fun::substitute
308 void indicator_term::substitute(Matrix *T)
310 unsigned dim = den.NumCols();
311 unsigned nparam = T->NbColumns - dim - 1;
312 unsigned newdim = T->NbRows - nparam - 1;
313 evalue **newvertex;
314 mat_ZZ trans;
315 matrix2zz(T, trans, newdim, dim);
316 trans = transpose(trans);
317 den *= trans;
318 newvertex = new evalue* [newdim];
320 vec_ZZ v;
321 v.SetLength(nparam+1);
323 evalue factor;
324 value_init(factor.d);
325 value_set_si(factor.d, 1);
326 value_init(factor.x.n);
327 for (int i = 0; i < newdim; ++i) {
328 values2zz(T->p[i]+dim, v, nparam+1);
329 newvertex[i] = multi_monom(v);
331 for (int j = 0; j < dim; ++j) {
332 if (value_zero_p(T->p[i][j]))
333 continue;
334 evalue term;
335 value_init(term.d);
336 evalue_copy(&term, vertex[j]);
337 value_assign(factor.x.n, T->p[i][j]);
338 emul(&factor, &term);
339 eadd(&term, newvertex[i]);
340 free_evalue_refs(&term);
343 free_evalue_refs(&factor);
344 for (int i = 0; i < dim; ++i)
345 evalue_free(vertex[i]);
346 delete [] vertex;
347 vertex = newvertex;
350 static void evalue_add_constant(evalue *e, ZZ v)
352 Value tmp;
353 value_init(tmp);
355 /* go down to constant term */
356 while (value_zero_p(e->d))
357 e = &e->x.p->arr[type_offset(e->x.p)];
358 /* and add v */
359 zz2value(v, tmp);
360 value_multiply(tmp, tmp, e->d);
361 value_addto(e->x.n, e->x.n, tmp);
363 value_clear(tmp);
366 /* Make all powers in denominator lexico-positive */
367 void indicator_term::normalize()
369 vec_ZZ extra_vertex;
370 extra_vertex.SetLength(den.NumCols());
371 for (int r = 0; r < den.NumRows(); ++r) {
372 for (int k = 0; k < den.NumCols(); ++k) {
373 if (den[r][k] == 0)
374 continue;
375 if (den[r][k] > 0)
376 break;
377 sign = -sign;
378 den[r] = -den[r];
379 extra_vertex += den[r];
380 break;
383 for (int k = 0; k < extra_vertex.length(); ++k)
384 if (extra_vertex[k] != 0)
385 evalue_add_constant(vertex[k], extra_vertex[k]);
388 static void substitute(evalue *e, evalue *fract, evalue *val)
390 evalue *t;
392 for (t = e; value_zero_p(t->d); t = &t->x.p->arr[type_offset(t->x.p)]) {
393 if (t->x.p->type == fractional && eequal(&t->x.p->arr[0], fract))
394 break;
396 if (value_notzero_p(t->d))
397 return;
399 free_evalue_refs(&t->x.p->arr[0]);
400 evalue *term = &t->x.p->arr[2];
401 enode *p = t->x.p;
402 value_clear(t->d);
403 *t = t->x.p->arr[1];
405 emul(val, term);
406 eadd(term, e);
407 free_evalue_refs(term);
408 free(p);
410 reduce_evalue(e);
413 void indicator_term::substitute(evalue *fract, evalue *val)
415 unsigned dim = den.NumCols();
416 for (int i = 0; i < dim; ++i) {
417 ::substitute(vertex[i], fract, val);
421 static void substitute(evalue *e, int pos, evalue *val)
423 evalue *t;
425 for (t = e; value_zero_p(t->d); t = &t->x.p->arr[type_offset(t->x.p)]) {
426 if (t->x.p->type == polynomial && t->x.p->pos == pos)
427 break;
429 if (value_notzero_p(t->d))
430 return;
432 evalue *term = &t->x.p->arr[1];
433 enode *p = t->x.p;
434 value_clear(t->d);
435 *t = t->x.p->arr[0];
437 emul(val, term);
438 eadd(term, e);
439 free_evalue_refs(term);
440 free(p);
442 reduce_evalue(e);
445 void indicator_term::substitute(int pos, evalue *val)
447 unsigned dim = den.NumCols();
448 for (int i = 0; i < dim; ++i) {
449 ::substitute(vertex[i], pos, val);
453 struct indicator_constructor : public signed_cone_consumer,
454 public vertex_decomposer {
455 vec_ZZ vertex;
456 vector<indicator_term*> *terms;
457 Matrix *T; /* Transformation to original space */
458 int nbV;
459 int pos;
460 int n;
462 indicator_constructor(Polyhedron *P, unsigned dim, Param_Polyhedron *PP,
463 Matrix *T) :
464 vertex_decomposer(PP, *this), T(T), nbV(PP->nbV) {
465 vertex.SetLength(dim);
466 terms = new vector<indicator_term*>[PP->nbV];
468 ~indicator_constructor() {
469 for (int i = 0; i < nbV; ++i)
470 for (int j = 0; j < terms[i].size(); ++j)
471 delete terms[i][j];
472 delete [] terms;
474 void print(ostream& os, char **p);
476 virtual void handle(const signed_cone& sc, barvinok_options *options);
477 void decompose_at_vertex(Param_Vertices *V, int _i,
478 barvinok_options *options) {
479 pos = _i;
480 n = 0;
481 vertex_decomposer::decompose_at_vertex(V, _i, options);
485 void indicator_constructor::handle(const signed_cone& sc, barvinok_options *options)
487 assert(sc.det == 1);
488 unsigned dim = vertex.length();
490 assert(sc.rays.NumRows() == dim);
492 indicator_term *term = new indicator_term(dim, pos, n++);
493 term->sign = sc.sign;
494 terms[vert].push_back(term);
496 lattice_point(V, sc.rays, vertex, term->vertex, options);
498 term->den = sc.rays;
499 for (int r = 0; r < dim; ++r) {
500 for (int j = 0; j < dim; ++j) {
501 if (term->den[r][j] == 0)
502 continue;
503 if (term->den[r][j] > 0)
504 break;
505 term->sign = -term->sign;
506 term->den[r] = -term->den[r];
507 vertex += term->den[r];
508 break;
512 for (int i = 0; i < dim; ++i) {
513 if (!term->vertex[i]) {
514 term->vertex[i] = ALLOC(evalue);
515 value_init(term->vertex[i]->d);
516 value_init(term->vertex[i]->x.n);
517 zz2value(vertex[i], term->vertex[i]->x.n);
518 value_set_si(term->vertex[i]->d, 1);
519 continue;
521 if (vertex[i] == 0)
522 continue;
523 evalue_add_constant(term->vertex[i], vertex[i]);
526 if (T) {
527 term->substitute(T);
528 term->normalize();
531 lex_order_rows(term->den);
534 void indicator_constructor::print(ostream& os, char **p)
536 for (int i = 0; i < PP->nbV; ++i)
537 for (int j = 0; j < terms[i].size(); ++j) {
538 os << "i: " << i << ", j: " << j << endl;
539 terms[i][j]->print(os, p);
540 os << endl;
544 struct order_cache_el {
545 vector<evalue *> e;
546 order_cache_el copy() const {
547 order_cache_el n;
548 for (int i = 0; i < e.size(); ++i) {
549 evalue *c = new evalue;
550 value_init(c->d);
551 evalue_copy(c, e[i]);
552 n.e.push_back(c);
554 return n;
556 void free() {
557 for (int i = 0; i < e.size(); ++i) {
558 free_evalue_refs(e[i]);
559 delete e[i];
562 void negate() {
563 evalue mone;
564 value_init(mone.d);
565 evalue_set_si(&mone, -1, 1);
566 for (int i = 0; i < e.size(); ++i)
567 emul(&mone, e[i]);
568 free_evalue_refs(&mone);
570 void print(ostream& os, char **p);
573 void order_cache_el::print(ostream& os, char **p)
575 os << "[";
576 for (int i = 0; i < e.size(); ++i) {
577 if (i)
578 os << ",";
579 evalue_print(os, e[i], p);
581 os << "]";
584 struct order_cache {
585 vector<order_cache_el> lt;
586 vector<order_cache_el> le;
587 vector<order_cache_el> unknown;
589 void clear_transients() {
590 for (int i = 0; i < le.size(); ++i)
591 le[i].free();
592 for (int i = 0; i < unknown.size(); ++i)
593 unknown[i].free();
594 le.clear();
595 unknown.clear();
597 ~order_cache() {
598 clear_transients();
599 for (int i = 0; i < lt.size(); ++i)
600 lt[i].free();
601 lt.clear();
603 void add(order_cache_el& cache_el, order_sign sign);
604 order_sign check_lt(vector<order_cache_el>* list,
605 const indicator_term *a, const indicator_term *b,
606 order_cache_el& cache_el);
607 order_sign check_lt(const indicator_term *a, const indicator_term *b,
608 order_cache_el& cache_el);
609 order_sign check_direct(const indicator_term *a, const indicator_term *b,
610 order_cache_el& cache_el);
611 order_sign check(const indicator_term *a, const indicator_term *b,
612 order_cache_el& cache_el);
613 void copy(const order_cache& cache);
614 void print(ostream& os, char **p);
617 void order_cache::copy(const order_cache& cache)
619 for (int i = 0; i < cache.lt.size(); ++i) {
620 order_cache_el n = cache.lt[i].copy();
621 add(n, order_lt);
625 void order_cache::add(order_cache_el& cache_el, order_sign sign)
627 if (sign == order_lt) {
628 lt.push_back(cache_el);
629 } else if (sign == order_gt) {
630 cache_el.negate();
631 lt.push_back(cache_el);
632 } else if (sign == order_le) {
633 le.push_back(cache_el);
634 } else if (sign == order_ge) {
635 cache_el.negate();
636 le.push_back(cache_el);
637 } else if (sign == order_unknown) {
638 unknown.push_back(cache_el);
639 } else {
640 assert(sign == order_eq);
641 cache_el.free();
643 return;
646 /* compute a - b */
647 static evalue *ediff(const evalue *a, const evalue *b)
649 evalue mone;
650 value_init(mone.d);
651 evalue_set_si(&mone, -1, 1);
652 evalue *diff = new evalue;
653 value_init(diff->d);
654 evalue_copy(diff, b);
655 emul(&mone, diff);
656 eadd(a, diff);
657 reduce_evalue(diff);
658 free_evalue_refs(&mone);
659 return diff;
662 static bool evalue_first_difference(const evalue *e1, const evalue *e2,
663 const evalue **d1, const evalue **d2)
665 *d1 = e1;
666 *d2 = e2;
668 if (value_ne(e1->d, e2->d))
669 return true;
671 if (value_notzero_p(e1->d)) {
672 if (value_eq(e1->x.n, e2->x.n))
673 return false;
674 return true;
676 if (e1->x.p->type != e2->x.p->type)
677 return true;
678 if (e1->x.p->size != e2->x.p->size)
679 return true;
680 if (e1->x.p->pos != e2->x.p->pos)
681 return true;
683 assert(e1->x.p->type == polynomial ||
684 e1->x.p->type == fractional ||
685 e1->x.p->type == flooring);
686 int offset = type_offset(e1->x.p);
687 assert(e1->x.p->size == offset+2);
688 for (int i = 0; i < e1->x.p->size; ++i)
689 if (i != type_offset(e1->x.p) &&
690 !eequal(&e1->x.p->arr[i], &e2->x.p->arr[i]))
691 return true;
693 return evalue_first_difference(&e1->x.p->arr[offset],
694 &e2->x.p->arr[offset], d1, d2);
697 static order_sign evalue_diff_constant_sign(const evalue *e1, const evalue *e2)
699 if (!evalue_first_difference(e1, e2, &e1, &e2))
700 return order_eq;
701 if (value_zero_p(e1->d) || value_zero_p(e2->d))
702 return order_undefined;
703 int s = evalue_rational_cmp(e1, e2);
704 if (s < 0)
705 return order_lt;
706 else if (s > 0)
707 return order_gt;
708 else
709 return order_eq;
712 order_sign order_cache::check_lt(vector<order_cache_el>* list,
713 const indicator_term *a, const indicator_term *b,
714 order_cache_el& cache_el)
716 order_sign sign = order_undefined;
717 for (int i = 0; i < list->size(); ++i) {
718 int j;
719 for (j = cache_el.e.size(); j < (*list)[i].e.size(); ++j)
720 cache_el.e.push_back(ediff(a->vertex[j], b->vertex[j]));
721 for (j = 0; j < (*list)[i].e.size(); ++j) {
722 order_sign diff_sign;
723 diff_sign = evalue_diff_constant_sign((*list)[i].e[j], cache_el.e[j]);
724 if (diff_sign == order_gt) {
725 sign = order_lt;
726 break;
727 } else if (diff_sign == order_lt)
728 break;
729 else if (diff_sign == order_undefined)
730 break;
731 else
732 assert(diff_sign == order_eq);
734 if (j == (*list)[i].e.size())
735 sign = list == &lt ? order_lt : order_le;
736 if (sign != order_undefined)
737 break;
739 return sign;
742 order_sign order_cache::check_direct(const indicator_term *a,
743 const indicator_term *b,
744 order_cache_el& cache_el)
746 order_sign sign = check_lt(&lt, a, b, cache_el);
747 if (sign != order_undefined)
748 return sign;
749 sign = check_lt(&le, a, b, cache_el);
750 if (sign != order_undefined)
751 return sign;
753 for (int i = 0; i < unknown.size(); ++i) {
754 int j;
755 for (j = cache_el.e.size(); j < unknown[i].e.size(); ++j)
756 cache_el.e.push_back(ediff(a->vertex[j], b->vertex[j]));
757 for (j = 0; j < unknown[i].e.size(); ++j) {
758 if (!eequal(unknown[i].e[j], cache_el.e[j]))
759 break;
761 if (j == unknown[i].e.size()) {
762 sign = order_unknown;
763 break;
766 return sign;
769 order_sign order_cache::check(const indicator_term *a, const indicator_term *b,
770 order_cache_el& cache_el)
772 order_sign sign = check_direct(a, b, cache_el);
773 if (sign != order_undefined)
774 return sign;
775 int size = cache_el.e.size();
776 cache_el.negate();
777 sign = check_direct(a, b, cache_el);
778 cache_el.negate();
779 assert(cache_el.e.size() == size);
780 if (sign == order_undefined)
781 return sign;
782 if (sign == order_lt)
783 sign = order_gt;
784 else if (sign == order_le)
785 sign = order_ge;
786 else
787 assert(sign == order_unknown);
788 return sign;
791 struct indicator;
793 struct partial_order {
794 indicator *ind;
796 typedef std::set<const indicator_term *, smaller_it > head_type;
797 head_type head;
798 typedef map<const indicator_term *, int, smaller_it > pred_type;
799 pred_type pred;
800 typedef map<const indicator_term *, vector<const indicator_term * >, smaller_it > order_type;
801 order_type lt;
802 order_type le;
803 order_type eq;
805 order_type pending;
807 order_cache cache;
809 partial_order(indicator *ind) : ind(ind) {}
810 void copy(const partial_order& order,
811 map< const indicator_term *, indicator_term * > old2new);
812 void resort() {
813 order_type::iterator i;
814 pred_type::iterator j;
815 head_type::iterator k;
817 if (head.key_comp().requires_resort) {
818 head_type new_head;
819 for (k = head.begin(); k != head.end(); ++k)
820 new_head.insert(*k);
821 head.swap(new_head);
822 new_head.clear();
825 if (pred.key_comp().requires_resort) {
826 pred_type new_pred;
827 for (j = pred.begin(); j != pred.end(); ++j)
828 new_pred[(*j).first] = (*j).second;
829 pred.swap(new_pred);
830 new_pred.clear();
833 if (lt.key_comp().requires_resort) {
834 order_type m;
835 for (i = lt.begin(); i != lt.end(); ++i)
836 m[(*i).first] = (*i).second;
837 lt.swap(m);
838 m.clear();
841 if (le.key_comp().requires_resort) {
842 order_type m;
843 for (i = le.begin(); i != le.end(); ++i)
844 m[(*i).first] = (*i).second;
845 le.swap(m);
846 m.clear();
849 if (eq.key_comp().requires_resort) {
850 order_type m;
851 for (i = eq.begin(); i != eq.end(); ++i)
852 m[(*i).first] = (*i).second;
853 eq.swap(m);
854 m.clear();
857 if (pending.key_comp().requires_resort) {
858 order_type m;
859 for (i = pending.begin(); i != pending.end(); ++i)
860 m[(*i).first] = (*i).second;
861 pending.swap(m);
862 m.clear();
866 order_sign compare(const indicator_term *a, const indicator_term *b);
867 void set_equal(const indicator_term *a, const indicator_term *b);
868 void unset_le(const indicator_term *a, const indicator_term *b);
869 void dec_pred(const indicator_term *it) {
870 if (--pred[it] == 0) {
871 pred.erase(it);
872 head.insert(it);
875 void inc_pred(const indicator_term *it) {
876 if (head.find(it) != head.end())
877 head.erase(it);
878 pred[it]++;
881 bool compared(const indicator_term* a, const indicator_term* b);
882 void add(const indicator_term* it, std::set<const indicator_term *> *filter);
883 void remove(const indicator_term* it);
885 void print(ostream& os, char **p);
887 /* replace references to orig to references to replacement */
888 void replace(const indicator_term* orig, indicator_term* replacement);
889 void sanity_check() const;
892 /* We actually replace the contents of orig by that of replacement,
893 * but we have to be careful since replacing the content changes
894 * the order of orig in the maps.
896 void partial_order::replace(const indicator_term* orig, indicator_term* replacement)
898 head_type::iterator k;
899 k = head.find(orig);
900 bool is_head = k != head.end();
901 int orig_pred;
902 if (is_head) {
903 head.erase(orig);
904 } else {
905 orig_pred = pred[orig];
906 pred.erase(orig);
908 vector<const indicator_term * > orig_lt;
909 vector<const indicator_term * > orig_le;
910 vector<const indicator_term * > orig_eq;
911 vector<const indicator_term * > orig_pending;
912 order_type::iterator i;
913 bool in_lt = ((i = lt.find(orig)) != lt.end());
914 if (in_lt) {
915 orig_lt = (*i).second;
916 lt.erase(orig);
918 bool in_le = ((i = le.find(orig)) != le.end());
919 if (in_le) {
920 orig_le = (*i).second;
921 le.erase(orig);
923 bool in_eq = ((i = eq.find(orig)) != eq.end());
924 if (in_eq) {
925 orig_eq = (*i).second;
926 eq.erase(orig);
928 bool in_pending = ((i = pending.find(orig)) != pending.end());
929 if (in_pending) {
930 orig_pending = (*i).second;
931 pending.erase(orig);
933 indicator_term *old = const_cast<indicator_term *>(orig);
934 old->swap(replacement);
935 if (is_head)
936 head.insert(old);
937 else
938 pred[old] = orig_pred;
939 if (in_lt)
940 lt[old] = orig_lt;
941 if (in_le)
942 le[old] = orig_le;
943 if (in_eq)
944 eq[old] = orig_eq;
945 if (in_pending)
946 pending[old] = orig_pending;
949 void partial_order::unset_le(const indicator_term *a, const indicator_term *b)
951 vector<const indicator_term *>::iterator i;
952 i = std::find(le[a].begin(), le[a].end(), b);
953 le[a].erase(i);
954 if (le[a].size() == 0)
955 le.erase(a);
956 dec_pred(b);
957 i = std::find(pending[a].begin(), pending[a].end(), b);
958 if (i != pending[a].end())
959 pending[a].erase(i);
962 void partial_order::set_equal(const indicator_term *a, const indicator_term *b)
964 if (eq[a].size() == 0)
965 eq[a].push_back(a);
966 if (eq[b].size() == 0)
967 eq[b].push_back(b);
968 a = eq[a][0];
969 b = eq[b][0];
970 assert(a != b);
971 if (pred.key_comp()(b, a)) {
972 const indicator_term *c = a;
973 a = b;
974 b = c;
977 const indicator_term *base = a;
979 order_type::iterator i;
981 for (int j = 0; j < eq[b].size(); ++j) {
982 eq[base].push_back(eq[b][j]);
983 eq[eq[b][j]][0] = base;
985 eq[b].resize(1);
987 i = lt.find(b);
988 if (i != lt.end()) {
989 for (int j = 0; j < lt[b].size(); ++j) {
990 if (std::find(eq[base].begin(), eq[base].end(), lt[b][j]) != eq[base].end())
991 dec_pred(lt[b][j]);
992 else if (std::find(lt[base].begin(), lt[base].end(), lt[b][j])
993 != lt[base].end())
994 dec_pred(lt[b][j]);
995 else
996 lt[base].push_back(lt[b][j]);
998 lt.erase(b);
1001 i = le.find(b);
1002 if (i != le.end()) {
1003 for (int j = 0; j < le[b].size(); ++j) {
1004 if (std::find(eq[base].begin(), eq[base].end(), le[b][j]) != eq[base].end())
1005 dec_pred(le[b][j]);
1006 else if (std::find(le[base].begin(), le[base].end(), le[b][j])
1007 != le[base].end())
1008 dec_pred(le[b][j]);
1009 else
1010 le[base].push_back(le[b][j]);
1012 le.erase(b);
1015 i = pending.find(base);
1016 if (i != pending.end()) {
1017 vector<const indicator_term * > old = pending[base];
1018 pending[base].clear();
1019 for (int j = 0; j < old.size(); ++j) {
1020 if (std::find(eq[base].begin(), eq[base].end(), old[j]) == eq[base].end())
1021 pending[base].push_back(old[j]);
1025 i = pending.find(b);
1026 if (i != pending.end()) {
1027 for (int j = 0; j < pending[b].size(); ++j) {
1028 if (std::find(eq[base].begin(), eq[base].end(), pending[b][j]) == eq[base].end())
1029 pending[base].push_back(pending[b][j]);
1031 pending.erase(b);
1035 void partial_order::copy(const partial_order& order,
1036 map< const indicator_term *, indicator_term * > old2new)
1038 cache.copy(order.cache);
1040 order_type::const_iterator i;
1041 pred_type::const_iterator j;
1042 head_type::const_iterator k;
1044 for (k = order.head.begin(); k != order.head.end(); ++k)
1045 head.insert(old2new[*k]);
1047 for (j = order.pred.begin(); j != order.pred.end(); ++j)
1048 pred[old2new[(*j).first]] = (*j).second;
1050 for (i = order.lt.begin(); i != order.lt.end(); ++i) {
1051 for (int j = 0; j < (*i).second.size(); ++j)
1052 lt[old2new[(*i).first]].push_back(old2new[(*i).second[j]]);
1054 for (i = order.le.begin(); i != order.le.end(); ++i) {
1055 for (int j = 0; j < (*i).second.size(); ++j)
1056 le[old2new[(*i).first]].push_back(old2new[(*i).second[j]]);
1058 for (i = order.eq.begin(); i != order.eq.end(); ++i) {
1059 for (int j = 0; j < (*i).second.size(); ++j)
1060 eq[old2new[(*i).first]].push_back(old2new[(*i).second[j]]);
1062 for (i = order.pending.begin(); i != order.pending.end(); ++i) {
1063 for (int j = 0; j < (*i).second.size(); ++j)
1064 pending[old2new[(*i).first]].push_back(old2new[(*i).second[j]]);
1068 struct max_term {
1069 EDomain *domain;
1070 vector<evalue *> max;
1072 void print(ostream& os, char **p, barvinok_options *options) const;
1073 void substitute(Matrix *T, barvinok_options *options);
1074 Vector *eval(Value *val, unsigned MaxRays) const;
1076 ~max_term() {
1077 for (int i = 0; i < max.size(); ++i) {
1078 free_evalue_refs(max[i]);
1079 delete max[i];
1081 delete domain;
1086 * Project on first dim dimensions
1088 Polyhedron* Polyhedron_Project_Initial(Polyhedron *P, int dim)
1090 int i;
1091 Matrix *T;
1092 Polyhedron *I;
1094 if (P->Dimension == dim)
1095 return Polyhedron_Copy(P);
1097 T = Matrix_Alloc(dim+1, P->Dimension+1);
1098 for (i = 0; i < dim; ++i)
1099 value_set_si(T->p[i][i], 1);
1100 value_set_si(T->p[dim][P->Dimension], 1);
1101 I = Polyhedron_Image(P, T, P->NbConstraints);
1102 Matrix_Free(T);
1103 return I;
1106 struct indicator {
1107 vector<indicator_term*> term;
1108 indicator_constructor& ic;
1109 partial_order order;
1110 EDomain *D;
1111 Polyhedron *P;
1112 Param_Domain *PD;
1113 lexmin_options *options;
1114 vector<evalue *> substitutions;
1116 indicator(indicator_constructor& ic, Param_Domain *PD, EDomain *D,
1117 lexmin_options *options) :
1118 ic(ic), PD(PD), D(D), order(this), options(options), P(NULL) {}
1119 indicator(const indicator& ind, EDomain *D) :
1120 ic(ind.ic), PD(ind.PD), D(NULL), order(this), options(ind.options),
1121 P(Polyhedron_Copy(ind.P)) {
1122 map< const indicator_term *, indicator_term * > old2new;
1123 for (int i = 0; i < ind.term.size(); ++i) {
1124 indicator_term *it = new indicator_term(*ind.term[i]);
1125 old2new[ind.term[i]] = it;
1126 term.push_back(it);
1128 order.copy(ind.order, old2new);
1129 set_domain(D);
1131 ~indicator() {
1132 for (int i = 0; i < term.size(); ++i)
1133 delete term[i];
1134 if (D)
1135 delete D;
1136 if (P)
1137 Polyhedron_Free(P);
1140 void set_domain(EDomain *D) {
1141 order.cache.clear_transients();
1142 if (this->D)
1143 delete this->D;
1144 this->D = D;
1145 int nparam = ic.PP->Constraints->NbColumns-2 - ic.vertex.length();
1146 if (options->reduce) {
1147 Polyhedron *Q = Polyhedron_Project_Initial(D->D, nparam);
1148 Q = DomainConstraintSimplify(Q, options->verify->barvinok->MaxRays);
1149 if (!P || !PolyhedronIncludes(Q, P))
1150 reduce_in_domain(Q);
1151 if (P)
1152 Polyhedron_Free(P);
1153 P = Q;
1154 order.resort();
1158 void add(const indicator_term* it);
1159 void remove(const indicator_term* it);
1160 void remove_initial_rational_vertices();
1161 void expand_rational_vertex(const indicator_term *initial);
1163 void print(ostream& os, char **p);
1164 void simplify();
1165 void peel(int i, int j);
1166 void combine(const indicator_term *a, const indicator_term *b);
1167 void add_substitution(evalue *equation);
1168 void perform_pending_substitutions();
1169 void reduce_in_domain(Polyhedron *D);
1170 bool handle_equal_numerators(const indicator_term *base);
1172 max_term* create_max_term(const indicator_term *it);
1173 private:
1174 void substitute(evalue *equation);
1177 void partial_order::sanity_check() const
1179 order_type::const_iterator i;
1180 order_type::const_iterator prev;
1181 order_type::const_iterator l;
1182 pred_type::const_iterator k, prev_k;
1184 for (k = pred.begin(); k != pred.end(); prev_k = k, ++k)
1185 if (k != pred.begin())
1186 assert(pred.key_comp()((*prev_k).first, (*k).first));
1187 for (i = lt.begin(); i != lt.end(); prev = i, ++i) {
1188 vec_ZZ i_v;
1189 if (ind->D->sample)
1190 i_v = (*i).first->eval(ind->D->sample->p);
1191 if (i != lt.begin())
1192 assert(lt.key_comp()((*prev).first, (*i).first));
1193 l = eq.find((*i).first);
1194 if (l != eq.end())
1195 assert((*l).second.size() > 1);
1196 assert(head.find((*i).first) != head.end() ||
1197 pred.find((*i).first) != pred.end());
1198 for (int j = 0; j < (*i).second.size(); ++j) {
1199 k = pred.find((*i).second[j]);
1200 assert(k != pred.end());
1201 assert((*k).second != 0);
1202 if ((*i).first->sign != 0 &&
1203 (*i).second[j]->sign != 0 && ind->D->sample) {
1204 vec_ZZ j_v = (*i).second[j]->eval(ind->D->sample->p);
1205 assert(lex_cmp(i_v, j_v) < 0);
1209 for (i = le.begin(); i != le.end(); ++i) {
1210 assert((*i).second.size() > 0);
1211 assert(head.find((*i).first) != head.end() ||
1212 pred.find((*i).first) != pred.end());
1213 for (int j = 0; j < (*i).second.size(); ++j) {
1214 k = pred.find((*i).second[j]);
1215 assert(k != pred.end());
1216 assert((*k).second != 0);
1219 for (i = eq.begin(); i != eq.end(); ++i) {
1220 assert(head.find((*i).first) != head.end() ||
1221 pred.find((*i).first) != pred.end());
1222 assert((*i).second.size() >= 1);
1224 for (i = pending.begin(); i != pending.end(); ++i) {
1225 assert(head.find((*i).first) != head.end() ||
1226 pred.find((*i).first) != pred.end());
1227 for (int j = 0; j < (*i).second.size(); ++j)
1228 assert(head.find((*i).second[j]) != head.end() ||
1229 pred.find((*i).second[j]) != pred.end());
1233 max_term* indicator::create_max_term(const indicator_term *it)
1235 int dim = it->den.NumCols();
1236 int nparam = ic.PP->Constraints->NbColumns-2 - ic.vertex.length();
1237 max_term *maximum = new max_term;
1238 maximum->domain = new EDomain(D);
1239 for (int j = 0; j < dim; ++j) {
1240 evalue *E = new evalue;
1241 value_init(E->d);
1242 evalue_copy(E, it->vertex[j]);
1243 if (evalue_frac2floor_in_domain(E, D->D))
1244 reduce_evalue(E);
1245 maximum->max.push_back(E);
1247 return maximum;
1250 static order_sign evalue_sign(evalue *diff, EDomain *D, barvinok_options *options)
1252 order_sign sign = order_eq;
1253 evalue mone;
1254 value_init(mone.d);
1255 evalue_set_si(&mone, -1, 1);
1256 int len = 1 + D->D->Dimension + 1;
1257 Vector *c = Vector_Alloc(len);
1258 Matrix *T = Matrix_Alloc(2, len-1);
1260 int fract = evalue2constraint(D, diff, c->p, len);
1261 Vector_Copy(c->p+1, T->p[0], len-1);
1262 value_assign(T->p[1][len-2], c->p[0]);
1264 order_sign upper_sign = polyhedron_affine_sign(D->D, T, options);
1265 if (upper_sign == order_lt || !fract)
1266 sign = upper_sign;
1267 else {
1268 emul(&mone, diff);
1269 evalue2constraint(D, diff, c->p, len);
1270 emul(&mone, diff);
1271 Vector_Copy(c->p+1, T->p[0], len-1);
1272 value_assign(T->p[1][len-2], c->p[0]);
1274 order_sign neg_lower_sign = polyhedron_affine_sign(D->D, T, options);
1276 if (neg_lower_sign == order_lt)
1277 sign = order_gt;
1278 else if (neg_lower_sign == order_eq || neg_lower_sign == order_le) {
1279 if (upper_sign == order_eq || upper_sign == order_le)
1280 sign = order_eq;
1281 else
1282 sign = order_ge;
1283 } else {
1284 if (upper_sign == order_lt || upper_sign == order_le ||
1285 upper_sign == order_eq)
1286 sign = order_le;
1287 else
1288 sign = order_unknown;
1292 Matrix_Free(T);
1293 Vector_Free(c);
1294 free_evalue_refs(&mone);
1296 return sign;
1299 /* An auxiliary class that keeps a reference to an evalue
1300 * and frees it when it goes out of scope.
1302 struct temp_evalue {
1303 evalue *E;
1304 temp_evalue() : E(NULL) {}
1305 temp_evalue(evalue *e) : E(e) {}
1306 operator evalue* () const { return E; }
1307 evalue *operator=(evalue *e) {
1308 if (E) {
1309 free_evalue_refs(E);
1310 delete E;
1312 E = e;
1313 return E;
1315 ~temp_evalue() {
1316 if (E) {
1317 free_evalue_refs(E);
1318 delete E;
1323 static void substitute(vector<indicator_term*>& term, evalue *equation)
1325 evalue *fract = NULL;
1326 evalue *val = new evalue;
1327 value_init(val->d);
1328 evalue_copy(val, equation);
1330 evalue factor;
1331 value_init(factor.d);
1332 value_init(factor.x.n);
1334 evalue *e;
1335 for (e = val; value_zero_p(e->d) && e->x.p->type != fractional;
1336 e = &e->x.p->arr[type_offset(e->x.p)])
1339 if (value_zero_p(e->d) && e->x.p->type == fractional)
1340 fract = &e->x.p->arr[0];
1341 else {
1342 for (e = val; value_zero_p(e->d) && e->x.p->type != polynomial;
1343 e = &e->x.p->arr[type_offset(e->x.p)])
1345 assert(value_zero_p(e->d) && e->x.p->type == polynomial);
1348 int offset = type_offset(e->x.p);
1350 assert(value_notzero_p(e->x.p->arr[offset+1].d));
1351 assert(value_notzero_p(e->x.p->arr[offset+1].x.n));
1352 if (value_neg_p(e->x.p->arr[offset+1].x.n)) {
1353 value_oppose(factor.d, e->x.p->arr[offset+1].x.n);
1354 value_assign(factor.x.n, e->x.p->arr[offset+1].d);
1355 } else {
1356 value_assign(factor.d, e->x.p->arr[offset+1].x.n);
1357 value_oppose(factor.x.n, e->x.p->arr[offset+1].d);
1360 free_evalue_refs(&e->x.p->arr[offset+1]);
1361 enode *p = e->x.p;
1362 value_clear(e->d);
1363 *e = e->x.p->arr[offset];
1365 emul(&factor, val);
1367 if (fract) {
1368 for (int i = 0; i < term.size(); ++i)
1369 term[i]->substitute(fract, val);
1371 free_evalue_refs(&p->arr[0]);
1372 } else {
1373 for (int i = 0; i < term.size(); ++i)
1374 term[i]->substitute(p->pos, val);
1377 free_evalue_refs(&factor);
1378 free_evalue_refs(val);
1379 delete val;
1381 free(p);
1384 order_sign partial_order::compare(const indicator_term *a, const indicator_term *b)
1386 unsigned dim = a->den.NumCols();
1387 order_sign sign = order_eq;
1388 bool rational = a->sign == 0 || b->sign == 0;
1390 order_sign cached_sign = order_eq;
1391 for (int k = 0; k < dim; ++k) {
1392 cached_sign = evalue_diff_constant_sign(a->vertex[k], b->vertex[k]);
1393 if (cached_sign != order_eq)
1394 break;
1396 if (cached_sign != order_undefined)
1397 return cached_sign;
1399 order_cache_el cache_el;
1400 cached_sign = order_undefined;
1401 if (!rational)
1402 cached_sign = cache.check(a, b, cache_el);
1403 if (cached_sign != order_undefined) {
1404 cache_el.free();
1405 return cached_sign;
1408 sign = order_eq;
1410 vector<indicator_term *> term;
1412 for (int k = 0; k < dim; ++k) {
1413 /* compute a->vertex[k] - b->vertex[k] */
1414 evalue *diff;
1415 if (cache_el.e.size() <= k) {
1416 diff = ediff(a->vertex[k], b->vertex[k]);
1417 cache_el.e.push_back(diff);
1418 } else
1419 diff = cache_el.e[k];
1420 temp_evalue tdiff;
1421 if (term.size())
1422 tdiff = diff = ediff(term[0]->vertex[k], term[1]->vertex[k]);
1423 order_sign diff_sign;
1424 if (eequal(a->vertex[k], b->vertex[k]))
1425 diff_sign = order_eq;
1426 else
1427 diff_sign = evalue_sign(diff, ind->D,
1428 ind->options->verify->barvinok);
1430 if (diff_sign == order_undefined) {
1431 assert(sign == order_le || sign == order_ge);
1432 if (sign == order_le)
1433 sign = order_lt;
1434 else
1435 sign = order_gt;
1436 break;
1438 if (diff_sign == order_lt) {
1439 if (sign == order_eq || sign == order_le)
1440 sign = order_lt;
1441 else
1442 sign = order_unknown;
1443 break;
1445 if (diff_sign == order_gt) {
1446 if (sign == order_eq || sign == order_ge)
1447 sign = order_gt;
1448 else
1449 sign = order_unknown;
1450 break;
1452 if (diff_sign == order_eq) {
1453 if (term.size() == 0 && !rational && !EVALUE_IS_ZERO(*diff))
1454 ind->add_substitution(diff);
1455 continue;
1457 if ((diff_sign == order_unknown) ||
1458 ((diff_sign == order_lt || diff_sign == order_le) && sign == order_ge) ||
1459 ((diff_sign == order_gt || diff_sign == order_ge) && sign == order_le)) {
1460 sign = order_unknown;
1461 break;
1464 sign = diff_sign;
1466 if (!term.size()) {
1467 term.push_back(new indicator_term(*a));
1468 term.push_back(new indicator_term(*b));
1470 substitute(term, diff);
1473 if (!rational)
1474 cache.add(cache_el, sign);
1475 else
1476 cache_el.free();
1478 if (term.size()) {
1479 delete term[0];
1480 delete term[1];
1483 return sign;
1486 bool partial_order::compared(const indicator_term* a, const indicator_term* b)
1488 order_type::iterator j;
1490 j = lt.find(a);
1491 if (j != lt.end() && std::find(lt[a].begin(), lt[a].end(), b) != lt[a].end())
1492 return true;
1494 j = le.find(a);
1495 if (j != le.end() && std::find(le[a].begin(), le[a].end(), b) != le[a].end())
1496 return true;
1498 return false;
1501 void partial_order::add(const indicator_term* it,
1502 std::set<const indicator_term *> *filter)
1504 if (eq.find(it) != eq.end() && eq[it].size() == 1)
1505 return;
1507 head_type head_copy(head);
1509 if (!filter)
1510 head.insert(it);
1512 head_type::iterator i;
1513 for (i = head_copy.begin(); i != head_copy.end(); ++i) {
1514 if (*i == it)
1515 continue;
1516 if (eq.find(*i) != eq.end() && eq[*i].size() == 1)
1517 continue;
1518 if (filter) {
1519 if (filter->find(*i) == filter->end())
1520 continue;
1521 if (compared(*i, it))
1522 continue;
1524 order_sign sign = compare(it, *i);
1525 if (sign == order_lt) {
1526 lt[it].push_back(*i);
1527 inc_pred(*i);
1528 } else if (sign == order_le) {
1529 le[it].push_back(*i);
1530 inc_pred(*i);
1531 } else if (sign == order_eq) {
1532 set_equal(it, *i);
1533 return;
1534 } else if (sign == order_gt) {
1535 pending[*i].push_back(it);
1536 lt[*i].push_back(it);
1537 inc_pred(it);
1538 } else if (sign == order_ge) {
1539 pending[*i].push_back(it);
1540 le[*i].push_back(it);
1541 inc_pred(it);
1546 void partial_order::remove(const indicator_term* it)
1548 std::set<const indicator_term *> filter;
1549 order_type::iterator i;
1551 assert(head.find(it) != head.end());
1553 i = eq.find(it);
1554 if (i != eq.end()) {
1555 assert(eq[it].size() >= 1);
1556 const indicator_term *base;
1557 if (eq[it].size() == 1) {
1558 base = eq[it][0];
1559 eq.erase(it);
1561 vector<const indicator_term * >::iterator j;
1562 j = std::find(eq[base].begin(), eq[base].end(), it);
1563 assert(j != eq[base].end());
1564 eq[base].erase(j);
1565 } else {
1566 /* "it" may no longer be the smallest, since the order
1567 * structure may have been copied from another one.
1569 std::sort(eq[it].begin()+1, eq[it].end(), pred.key_comp());
1570 assert(eq[it][0] == it);
1571 eq[it].erase(eq[it].begin());
1572 base = eq[it][0];
1573 eq[base] = eq[it];
1574 eq.erase(it);
1576 for (int j = 1; j < eq[base].size(); ++j)
1577 eq[eq[base][j]][0] = base;
1579 i = lt.find(it);
1580 if (i != lt.end()) {
1581 lt[base] = lt[it];
1582 lt.erase(it);
1585 i = le.find(it);
1586 if (i != le.end()) {
1587 le[base] = le[it];
1588 le.erase(it);
1591 i = pending.find(it);
1592 if (i != pending.end()) {
1593 pending[base] = pending[it];
1594 pending.erase(it);
1598 if (eq[base].size() == 1)
1599 eq.erase(base);
1601 head.erase(it);
1603 return;
1606 i = lt.find(it);
1607 if (i != lt.end()) {
1608 for (int j = 0; j < lt[it].size(); ++j) {
1609 filter.insert(lt[it][j]);
1610 dec_pred(lt[it][j]);
1612 lt.erase(it);
1615 i = le.find(it);
1616 if (i != le.end()) {
1617 for (int j = 0; j < le[it].size(); ++j) {
1618 filter.insert(le[it][j]);
1619 dec_pred(le[it][j]);
1621 le.erase(it);
1624 head.erase(it);
1626 i = pending.find(it);
1627 if (i != pending.end()) {
1628 vector<const indicator_term *> it_pending = pending[it];
1629 pending.erase(it);
1630 for (int j = 0; j < it_pending.size(); ++j) {
1631 filter.erase(it_pending[j]);
1632 add(it_pending[j], &filter);
1637 void partial_order::print(ostream& os, char **p)
1639 order_type::iterator i;
1640 pred_type::iterator j;
1641 head_type::iterator k;
1642 for (k = head.begin(); k != head.end(); ++k) {
1643 (*k)->print(os, p);
1644 os << endl;
1646 for (j = pred.begin(); j != pred.end(); ++j) {
1647 (*j).first->print(os, p);
1648 os << ": " << (*j).second << endl;
1650 for (i = lt.begin(); i != lt.end(); ++i) {
1651 (*i).first->print(os, p);
1652 assert(head.find((*i).first) != head.end() ||
1653 pred.find((*i).first) != pred.end());
1654 if (pred.find((*i).first) != pred.end())
1655 os << "(" << pred[(*i).first] << ")";
1656 os << " < ";
1657 for (int j = 0; j < (*i).second.size(); ++j) {
1658 if (j)
1659 os << ", ";
1660 (*i).second[j]->print(os, p);
1661 assert(pred.find((*i).second[j]) != pred.end());
1662 os << "(" << pred[(*i).second[j]] << ")";
1664 os << endl;
1666 for (i = le.begin(); i != le.end(); ++i) {
1667 (*i).first->print(os, p);
1668 assert(head.find((*i).first) != head.end() ||
1669 pred.find((*i).first) != pred.end());
1670 if (pred.find((*i).first) != pred.end())
1671 os << "(" << pred[(*i).first] << ")";
1672 os << " <= ";
1673 for (int j = 0; j < (*i).second.size(); ++j) {
1674 if (j)
1675 os << ", ";
1676 (*i).second[j]->print(os, p);
1677 assert(pred.find((*i).second[j]) != pred.end());
1678 os << "(" << pred[(*i).second[j]] << ")";
1680 os << endl;
1682 for (i = eq.begin(); i != eq.end(); ++i) {
1683 if ((*i).second.size() <= 1)
1684 continue;
1685 (*i).first->print(os, p);
1686 assert(head.find((*i).first) != head.end() ||
1687 pred.find((*i).first) != pred.end());
1688 if (pred.find((*i).first) != pred.end())
1689 os << "(" << pred[(*i).first] << ")";
1690 for (int j = 1; j < (*i).second.size(); ++j) {
1691 if (j)
1692 os << " = ";
1693 (*i).second[j]->print(os, p);
1694 assert(head.find((*i).second[j]) != head.end() ||
1695 pred.find((*i).second[j]) != pred.end());
1696 if (pred.find((*i).second[j]) != pred.end())
1697 os << "(" << pred[(*i).second[j]] << ")";
1699 os << endl;
1701 for (i = pending.begin(); i != pending.end(); ++i) {
1702 os << "pending on ";
1703 (*i).first->print(os, p);
1704 assert(head.find((*i).first) != head.end() ||
1705 pred.find((*i).first) != pred.end());
1706 if (pred.find((*i).first) != pred.end())
1707 os << "(" << pred[(*i).first] << ")";
1708 os << ": ";
1709 for (int j = 0; j < (*i).second.size(); ++j) {
1710 if (j)
1711 os << ", ";
1712 (*i).second[j]->print(os, p);
1713 assert(pred.find((*i).second[j]) != pred.end());
1714 os << "(" << pred[(*i).second[j]] << ")";
1716 os << endl;
1720 void indicator::add(const indicator_term* it)
1722 indicator_term *nt = new indicator_term(*it);
1723 if (options->reduce)
1724 nt->reduce_in_domain(P ? P : D->D);
1725 term.push_back(nt);
1726 order.add(nt, NULL);
1727 assert(term.size() == order.head.size() + order.pred.size());
1730 void indicator::remove(const indicator_term* it)
1732 vector<indicator_term *>::iterator i;
1733 i = std::find(term.begin(), term.end(), it);
1734 assert(i!= term.end());
1735 order.remove(it);
1736 term.erase(i);
1737 assert(term.size() == order.head.size() + order.pred.size());
1738 delete it;
1741 void indicator::expand_rational_vertex(const indicator_term *initial)
1743 int pos = initial->pos;
1744 remove(initial);
1745 if (ic.terms[pos].size() == 0) {
1746 Param_Vertices *V;
1747 FORALL_PVertex_in_ParamPolyhedron(V, PD, ic.PP) // _i is internal counter
1748 if (_i == pos) {
1749 ic.decompose_at_vertex(V, pos, options->verify->barvinok);
1750 break;
1752 END_FORALL_PVertex_in_ParamPolyhedron;
1754 for (int j = 0; j < ic.terms[pos].size(); ++j)
1755 add(ic.terms[pos][j]);
1758 void indicator::remove_initial_rational_vertices()
1760 do {
1761 const indicator_term *initial = NULL;
1762 partial_order::head_type::iterator i;
1763 for (i = order.head.begin(); i != order.head.end(); ++i) {
1764 if ((*i)->sign != 0)
1765 continue;
1766 if (order.eq.find(*i) != order.eq.end() && order.eq[*i].size() <= 1)
1767 continue;
1768 initial = *i;
1769 break;
1771 if (!initial)
1772 break;
1773 expand_rational_vertex(initial);
1774 } while(1);
1777 void indicator::reduce_in_domain(Polyhedron *D)
1779 for (int i = 0; i < term.size(); ++i)
1780 term[i]->reduce_in_domain(D);
1783 void indicator::print(ostream& os, char **p)
1785 assert(term.size() == order.head.size() + order.pred.size());
1786 for (int i = 0; i < term.size(); ++i) {
1787 term[i]->print(os, p);
1788 if (D->sample) {
1789 os << ": " << term[i]->eval(D->sample->p);
1791 os << endl;
1793 order.print(os, p);
1796 /* Remove pairs of opposite terms */
1797 void indicator::simplify()
1799 for (int i = 0; i < term.size(); ++i) {
1800 for (int j = i+1; j < term.size(); ++j) {
1801 if (term[i]->sign + term[j]->sign != 0)
1802 continue;
1803 if (term[i]->den != term[j]->den)
1804 continue;
1805 int k;
1806 for (k = 0; k < term[i]->den.NumCols(); ++k)
1807 if (!eequal(term[i]->vertex[k], term[j]->vertex[k]))
1808 break;
1809 if (k < term[i]->den.NumCols())
1810 continue;
1811 delete term[i];
1812 delete term[j];
1813 term.erase(term.begin()+j);
1814 term.erase(term.begin()+i);
1815 --i;
1816 break;
1821 void indicator::peel(int i, int j)
1823 if (j < i) {
1824 int tmp = i;
1825 i = j;
1826 j = tmp;
1828 assert (i < j);
1829 int dim = term[i]->den.NumCols();
1831 mat_ZZ common;
1832 mat_ZZ rest_i;
1833 mat_ZZ rest_j;
1834 int n_common = 0, n_i = 0, n_j = 0;
1836 common.SetDims(min(term[i]->den.NumRows(), term[j]->den.NumRows()), dim);
1837 rest_i.SetDims(term[i]->den.NumRows(), dim);
1838 rest_j.SetDims(term[j]->den.NumRows(), dim);
1840 int k, l;
1841 for (k = 0, l = 0; k < term[i]->den.NumRows() && l < term[j]->den.NumRows(); ) {
1842 int s = lex_cmp(term[i]->den[k], term[j]->den[l]);
1843 if (s == 0) {
1844 common[n_common++] = term[i]->den[k];
1845 ++k;
1846 ++l;
1847 } else if (s < 0)
1848 rest_i[n_i++] = term[i]->den[k++];
1849 else
1850 rest_j[n_j++] = term[j]->den[l++];
1852 while (k < term[i]->den.NumRows())
1853 rest_i[n_i++] = term[i]->den[k++];
1854 while (l < term[j]->den.NumRows())
1855 rest_j[n_j++] = term[j]->den[l++];
1856 common.SetDims(n_common, dim);
1857 rest_i.SetDims(n_i, dim);
1858 rest_j.SetDims(n_j, dim);
1860 for (k = 0; k <= n_i; ++k) {
1861 indicator_term *it = new indicator_term(*term[i]);
1862 it->den.SetDims(n_common + k, dim);
1863 for (l = 0; l < n_common; ++l)
1864 it->den[l] = common[l];
1865 for (l = 0; l < k; ++l)
1866 it->den[n_common+l] = rest_i[l];
1867 lex_order_rows(it->den);
1868 if (k)
1869 for (l = 0; l < dim; ++l)
1870 evalue_add_constant(it->vertex[l], rest_i[k-1][l]);
1871 term.push_back(it);
1874 for (k = 0; k <= n_j; ++k) {
1875 indicator_term *it = new indicator_term(*term[j]);
1876 it->den.SetDims(n_common + k, dim);
1877 for (l = 0; l < n_common; ++l)
1878 it->den[l] = common[l];
1879 for (l = 0; l < k; ++l)
1880 it->den[n_common+l] = rest_j[l];
1881 lex_order_rows(it->den);
1882 if (k)
1883 for (l = 0; l < dim; ++l)
1884 evalue_add_constant(it->vertex[l], rest_j[k-1][l]);
1885 term.push_back(it);
1887 term.erase(term.begin()+j);
1888 term.erase(term.begin()+i);
1891 void indicator::combine(const indicator_term *a, const indicator_term *b)
1893 int dim = a->den.NumCols();
1895 mat_ZZ common;
1896 mat_ZZ rest_i; /* factors in a, but not in b */
1897 mat_ZZ rest_j; /* factors in b, but not in a */
1898 int n_common = 0, n_i = 0, n_j = 0;
1900 common.SetDims(min(a->den.NumRows(), b->den.NumRows()), dim);
1901 rest_i.SetDims(a->den.NumRows(), dim);
1902 rest_j.SetDims(b->den.NumRows(), dim);
1904 int k, l;
1905 for (k = 0, l = 0; k < a->den.NumRows() && l < b->den.NumRows(); ) {
1906 int s = lex_cmp(a->den[k], b->den[l]);
1907 if (s == 0) {
1908 common[n_common++] = a->den[k];
1909 ++k;
1910 ++l;
1911 } else if (s < 0)
1912 rest_i[n_i++] = a->den[k++];
1913 else
1914 rest_j[n_j++] = b->den[l++];
1916 while (k < a->den.NumRows())
1917 rest_i[n_i++] = a->den[k++];
1918 while (l < b->den.NumRows())
1919 rest_j[n_j++] = b->den[l++];
1920 common.SetDims(n_common, dim);
1921 rest_i.SetDims(n_i, dim);
1922 rest_j.SetDims(n_j, dim);
1924 assert(order.eq[a].size() > 1);
1925 indicator_term *prev;
1927 prev = NULL;
1928 for (int k = n_i-1; k >= 0; --k) {
1929 indicator_term *it = new indicator_term(*b);
1930 it->den.SetDims(n_common + n_j + n_i-k, dim);
1931 for (int l = k; l < n_i; ++l)
1932 it->den[n_common+n_j+l-k] = rest_i[l];
1933 lex_order_rows(it->den);
1934 for (int m = 0; m < dim; ++m)
1935 evalue_add_constant(it->vertex[m], rest_i[k][m]);
1936 it->sign = -it->sign;
1937 if (prev) {
1938 order.pending[it].push_back(prev);
1939 order.lt[it].push_back(prev);
1940 order.inc_pred(prev);
1942 term.push_back(it);
1943 order.head.insert(it);
1944 prev = it;
1946 if (n_i) {
1947 indicator_term *it = new indicator_term(*b);
1948 it->den.SetDims(n_common + n_i + n_j, dim);
1949 for (l = 0; l < n_i; ++l)
1950 it->den[n_common+n_j+l] = rest_i[l];
1951 lex_order_rows(it->den);
1952 assert(prev);
1953 order.pending[a].push_back(prev);
1954 order.lt[a].push_back(prev);
1955 order.inc_pred(prev);
1956 order.replace(b, it);
1957 delete it;
1960 prev = NULL;
1961 for (int k = n_j-1; k >= 0; --k) {
1962 indicator_term *it = new indicator_term(*a);
1963 it->den.SetDims(n_common + n_i + n_j-k, dim);
1964 for (int l = k; l < n_j; ++l)
1965 it->den[n_common+n_i+l-k] = rest_j[l];
1966 lex_order_rows(it->den);
1967 for (int m = 0; m < dim; ++m)
1968 evalue_add_constant(it->vertex[m], rest_j[k][m]);
1969 it->sign = -it->sign;
1970 if (prev) {
1971 order.pending[it].push_back(prev);
1972 order.lt[it].push_back(prev);
1973 order.inc_pred(prev);
1975 term.push_back(it);
1976 order.head.insert(it);
1977 prev = it;
1979 if (n_j) {
1980 indicator_term *it = new indicator_term(*a);
1981 it->den.SetDims(n_common + n_i + n_j, dim);
1982 for (l = 0; l < n_j; ++l)
1983 it->den[n_common+n_i+l] = rest_j[l];
1984 lex_order_rows(it->den);
1985 assert(prev);
1986 order.pending[a].push_back(prev);
1987 order.lt[a].push_back(prev);
1988 order.inc_pred(prev);
1989 order.replace(a, it);
1990 delete it;
1993 assert(term.size() == order.head.size() + order.pred.size());
1996 bool indicator::handle_equal_numerators(const indicator_term *base)
1998 for (int i = 0; i < order.eq[base].size(); ++i) {
1999 for (int j = i+1; j < order.eq[base].size(); ++j) {
2000 if (order.eq[base][i]->is_opposite(order.eq[base][j])) {
2001 remove(order.eq[base][j]);
2002 remove(i ? order.eq[base][i] : base);
2003 return true;
2007 for (int j = 1; j < order.eq[base].size(); ++j)
2008 if (order.eq[base][j]->sign != base->sign) {
2009 combine(base, order.eq[base][j]);
2010 return true;
2012 return false;
2015 void indicator::substitute(evalue *equation)
2017 ::substitute(term, equation);
2020 void indicator::add_substitution(evalue *equation)
2022 for (int i = 0; i < substitutions.size(); ++i)
2023 if (eequal(substitutions[i], equation))
2024 return;
2025 evalue *copy = new evalue();
2026 value_init(copy->d);
2027 evalue_copy(copy, equation);
2028 substitutions.push_back(copy);
2031 void indicator::perform_pending_substitutions()
2033 if (substitutions.size() == 0)
2034 return;
2036 for (int i = 0; i < substitutions.size(); ++i) {
2037 substitute(substitutions[i]);
2038 free_evalue_refs(substitutions[i]);
2039 delete substitutions[i];
2041 substitutions.clear();
2042 order.resort();
2045 static void print_varlist(ostream& os, int n, char **names)
2047 int i;
2048 os << "[";
2049 for (i = 0; i < n; ++i) {
2050 if (i)
2051 os << ",";
2052 os << names[i];
2054 os << "]";
2057 void max_term::print(ostream& os, char **p, barvinok_options *options) const
2059 os << "{ ";
2060 print_varlist(os, domain->dimension(), p);
2061 os << " -> ";
2062 os << "[";
2063 for (int i = 0; i < max.size(); ++i) {
2064 if (i)
2065 os << ",";
2066 evalue_print(os, max[i], p);
2068 os << "]";
2069 os << " : ";
2070 domain->print_constraints(os, p, options);
2071 os << " }" << endl;
2074 /* T maps the compressed parameters to the original parameters,
2075 * while this max_term is based on the compressed parameters
2076 * and we want get the original parameters back.
2078 void max_term::substitute(Matrix *T, barvinok_options *options)
2080 assert(domain->dimension() == T->NbColumns-1);
2081 int nexist = domain->D->Dimension - (T->NbColumns-1);
2082 Matrix *Eq;
2083 Matrix *inv = left_inverse(T, &Eq);
2085 evalue denom;
2086 value_init(denom.d);
2087 value_init(denom.x.n);
2088 value_set_si(denom.x.n, 1);
2089 value_assign(denom.d, inv->p[inv->NbRows-1][inv->NbColumns-1]);
2091 vec_ZZ v;
2092 v.SetLength(inv->NbColumns);
2093 evalue **subs = new evalue *[inv->NbRows-1];
2094 for (int i = 0; i < inv->NbRows-1; ++i) {
2095 values2zz(inv->p[i], v, v.length());
2096 subs[i] = multi_monom(v);
2097 emul(&denom, subs[i]);
2099 free_evalue_refs(&denom);
2101 domain->substitute(subs, inv, Eq, options->MaxRays);
2102 Matrix_Free(Eq);
2104 for (int i = 0; i < max.size(); ++i) {
2105 evalue_substitute(max[i], subs);
2106 reduce_evalue(max[i]);
2109 for (int i = 0; i < inv->NbRows-1; ++i) {
2110 free_evalue_refs(subs[i]);
2111 delete subs[i];
2113 delete [] subs;
2114 Matrix_Free(inv);
2117 Vector *max_term::eval(Value *val, unsigned MaxRays) const
2119 if (!domain->contains(val, domain->dimension()))
2120 return NULL;
2121 Vector *res = Vector_Alloc(max.size());
2122 for (int i = 0; i < max.size(); ++i) {
2123 compute_evalue(max[i], val, &res->p[i]);
2125 return res;
2128 struct split {
2129 evalue *constraint;
2130 enum sign { le, ge, lge } sign;
2132 split (evalue *c, enum sign s) : constraint(c), sign(s) {}
2135 static void split_on(const split& sp, EDomain *D,
2136 EDomain **Dlt, EDomain **Deq, EDomain **Dgt,
2137 lexmin_options *options)
2139 EDomain *ED[3];
2140 *Dlt = NULL;
2141 *Deq = NULL;
2142 *Dgt = NULL;
2143 ge_constraint *ge = D->compute_ge_constraint(sp.constraint);
2144 if (sp.sign == split::lge || sp.sign == split::ge)
2145 ED[2] = EDomain::new_from_ge_constraint(ge, 1, options->verify->barvinok);
2146 else
2147 ED[2] = NULL;
2148 if (sp.sign == split::lge || sp.sign == split::le)
2149 ED[0] = EDomain::new_from_ge_constraint(ge, -1, options->verify->barvinok);
2150 else
2151 ED[0] = NULL;
2153 assert(sp.sign == split::lge || sp.sign == split::ge || sp.sign == split::le);
2154 ED[1] = EDomain::new_from_ge_constraint(ge, 0, options->verify->barvinok);
2156 delete ge;
2158 for (int i = 0; i < 3; ++i) {
2159 if (!ED[i])
2160 continue;
2161 if (D->sample && ED[i]->contains(D->sample->p, D->sample->Size-1)) {
2162 ED[i]->sample = Vector_Alloc(D->sample->Size);
2163 Vector_Copy(D->sample->p, ED[i]->sample->p, D->sample->Size);
2164 } else if (emptyQ2(ED[i]->D) ||
2165 (options->emptiness_check != BV_LEXMIN_EMPTINESS_CHECK_NONE &&
2166 !(ED[i]->not_empty(options)))) {
2167 delete ED[i];
2168 ED[i] = NULL;
2171 *Dlt = ED[0];
2172 *Deq = ED[1];
2173 *Dgt = ED[2];
2176 ostream & operator<< (ostream & os, const vector<int> & v)
2178 os << "[";
2179 for (int i = 0; i < v.size(); ++i) {
2180 if (i)
2181 os << ", ";
2182 os << v[i];
2184 os << "]";
2185 return os;
2188 void construct_rational_vertices(Param_Polyhedron *PP, Matrix *T, unsigned dim,
2189 int nparam, vector<indicator_term *>& vertices)
2191 int i;
2192 Param_Vertices *PV;
2193 Value lcm, tmp;
2194 value_init(lcm);
2195 value_init(tmp);
2197 vec_ZZ v;
2198 v.SetLength(nparam+1);
2200 evalue factor;
2201 value_init(factor.d);
2202 value_init(factor.x.n);
2203 value_set_si(factor.x.n, 1);
2204 value_set_si(factor.d, 1);
2206 for (i = 0, PV = PP->V; PV; ++i, PV = PV->next) {
2207 indicator_term *term = new indicator_term(dim, i);
2208 vertices.push_back(term);
2209 Matrix *M = Matrix_Alloc(PV->Vertex->NbRows+nparam+1, nparam+1);
2210 value_set_si(lcm, 1);
2211 for (int j = 0; j < PV->Vertex->NbRows; ++j)
2212 value_lcm(lcm, lcm, PV->Vertex->p[j][nparam+1]);
2213 value_assign(M->p[M->NbRows-1][M->NbColumns-1], lcm);
2214 for (int j = 0; j < PV->Vertex->NbRows; ++j) {
2215 value_division(tmp, lcm, PV->Vertex->p[j][nparam+1]);
2216 Vector_Scale(PV->Vertex->p[j], M->p[j], tmp, nparam+1);
2218 for (int j = 0; j < nparam; ++j)
2219 value_assign(M->p[PV->Vertex->NbRows+j][j], lcm);
2220 if (T) {
2221 Matrix *M2 = Matrix_Alloc(T->NbRows, M->NbColumns);
2222 Matrix_Product(T, M, M2);
2223 Matrix_Free(M);
2224 M = M2;
2226 for (int j = 0; j < dim; ++j) {
2227 values2zz(M->p[j], v, nparam+1);
2228 term->vertex[j] = multi_monom(v);
2229 value_assign(factor.d, lcm);
2230 emul(&factor, term->vertex[j]);
2232 Matrix_Free(M);
2234 assert(i == PP->nbV);
2235 free_evalue_refs(&factor);
2236 value_clear(lcm);
2237 value_clear(tmp);
2240 static vector<max_term*> lexmin(indicator& ind, unsigned nparam,
2241 vector<int> loc)
2243 vector<max_term*> maxima;
2244 partial_order::head_type::iterator i;
2245 vector<int> best_score;
2246 vector<int> second_score;
2247 vector<int> neg_score;
2249 do {
2250 ind.perform_pending_substitutions();
2251 const indicator_term *best = NULL, *second = NULL, *neg = NULL,
2252 *neg_eq = NULL, *neg_le = NULL;
2253 for (i = ind.order.head.begin(); i != ind.order.head.end(); ++i) {
2254 vector<int> score;
2255 const indicator_term *term = *i;
2256 if (term->sign == 0) {
2257 ind.expand_rational_vertex(term);
2258 break;
2261 if (ind.order.eq.find(term) != ind.order.eq.end()) {
2262 int j;
2263 if (ind.order.eq[term].size() <= 1)
2264 continue;
2265 for (j = 1; j < ind.order.eq[term].size(); ++j)
2266 if (ind.order.pred.find(ind.order.eq[term][j]) !=
2267 ind.order.pred.end())
2268 break;
2269 if (j < ind.order.eq[term].size())
2270 continue;
2271 score.push_back(ind.order.eq[term].size());
2272 } else
2273 score.push_back(0);
2274 if (ind.order.le.find(term) != ind.order.le.end())
2275 score.push_back(ind.order.le[term].size());
2276 else
2277 score.push_back(0);
2278 if (ind.order.lt.find(term) != ind.order.lt.end())
2279 score.push_back(-ind.order.lt[term].size());
2280 else
2281 score.push_back(0);
2283 if (term->sign > 0) {
2284 if (!best || score < best_score) {
2285 second = best;
2286 second_score = best_score;
2287 best = term;
2288 best_score = score;
2289 } else if (!second || score < second_score) {
2290 second = term;
2291 second_score = score;
2293 } else {
2294 if (!neg_eq && ind.order.eq.find(term) != ind.order.eq.end()) {
2295 for (int j = 1; j < ind.order.eq[term].size(); ++j)
2296 if (ind.order.eq[term][j]->sign != term->sign) {
2297 neg_eq = term;
2298 break;
2301 if (!neg_le && ind.order.le.find(term) != ind.order.le.end())
2302 neg_le = term;
2303 if (!neg || score < neg_score) {
2304 neg = term;
2305 neg_score = score;
2309 if (i != ind.order.head.end())
2310 continue;
2312 if (!best && neg_eq) {
2313 assert(ind.order.eq[neg_eq].size() != 0);
2314 bool handled = ind.handle_equal_numerators(neg_eq);
2315 assert(handled);
2316 continue;
2319 if (!best && neg_le) {
2320 /* The smallest term is negative and <= some positive term */
2321 best = neg_le;
2322 neg = NULL;
2325 if (!best) {
2326 /* apparently there can be negative initial term on empty domains */
2327 if (ind.options->emptiness_check != BV_LEXMIN_EMPTINESS_CHECK_NONE &&
2328 ind.options->verify->barvinok->lp_solver == BV_LP_POLYLIB)
2329 assert(!neg);
2330 break;
2333 if (!second && !neg) {
2334 const indicator_term *rat = NULL;
2335 assert(best);
2336 if (ind.order.le.find(best) == ind.order.le.end()) {
2337 if (ind.order.eq.find(best) != ind.order.eq.end()) {
2338 bool handled = ind.handle_equal_numerators(best);
2339 if (ind.options->emptiness_check !=
2340 BV_LEXMIN_EMPTINESS_CHECK_NONE &&
2341 ind.options->verify->barvinok->lp_solver == BV_LP_POLYLIB)
2342 assert(handled);
2343 /* If !handled then the leading coefficient is bigger than one;
2344 * must be an empty domain
2346 if (handled)
2347 continue;
2348 else
2349 break;
2351 maxima.push_back(ind.create_max_term(best));
2352 break;
2354 for (int j = 0; j < ind.order.le[best].size(); ++j) {
2355 if (ind.order.le[best][j]->sign == 0) {
2356 if (!rat && ind.order.pred[ind.order.le[best][j]] == 1)
2357 rat = ind.order.le[best][j];
2358 } else if (ind.order.le[best][j]->sign > 0) {
2359 second = ind.order.le[best][j];
2360 break;
2361 } else if (!neg)
2362 neg = ind.order.le[best][j];
2365 if (!second && !neg) {
2366 assert(rat);
2367 ind.order.unset_le(best, rat);
2368 ind.expand_rational_vertex(rat);
2369 continue;
2372 if (!second)
2373 second = neg;
2375 ind.order.unset_le(best, second);
2378 if (!second)
2379 second = neg;
2381 unsigned dim = best->den.NumCols();
2382 temp_evalue diff;
2383 order_sign sign;
2384 for (int k = 0; k < dim; ++k) {
2385 diff = ediff(best->vertex[k], second->vertex[k]);
2386 sign = evalue_sign(diff, ind.D, ind.options->verify->barvinok);
2388 /* neg can never be smaller than best, unless it may still cancel.
2389 * This can happen if positive terms have been determined to
2390 * be equal or less than or equal to some negative term.
2392 if (second == neg && !neg_eq && !neg_le) {
2393 if (sign == order_ge)
2394 sign = order_eq;
2395 if (sign == order_unknown)
2396 sign = order_le;
2399 if (sign != order_eq)
2400 break;
2401 if (!EVALUE_IS_ZERO(*diff)) {
2402 ind.add_substitution(diff);
2403 ind.perform_pending_substitutions();
2406 if (sign == order_eq) {
2407 ind.order.set_equal(best, second);
2408 continue;
2410 if (sign == order_lt) {
2411 ind.order.lt[best].push_back(second);
2412 ind.order.inc_pred(second);
2413 continue;
2415 if (sign == order_gt) {
2416 ind.order.lt[second].push_back(best);
2417 ind.order.inc_pred(best);
2418 continue;
2421 split sp(diff, sign == order_le ? split::le :
2422 sign == order_ge ? split::ge : split::lge);
2424 EDomain *Dlt, *Deq, *Dgt;
2425 split_on(sp, ind.D, &Dlt, &Deq, &Dgt, ind.options);
2426 if (ind.options->emptiness_check != BV_LEXMIN_EMPTINESS_CHECK_NONE)
2427 assert(Dlt || Deq || Dgt);
2428 else if (!(Dlt || Deq || Dgt))
2429 /* Must have been empty all along */
2430 break;
2432 if (Deq && (Dlt || Dgt)) {
2433 int locsize = loc.size();
2434 loc.push_back(0);
2435 indicator indeq(ind, Deq);
2436 Deq = NULL;
2437 indeq.add_substitution(diff);
2438 indeq.perform_pending_substitutions();
2439 vector<max_term*> maxeq = lexmin(indeq, nparam, loc);
2440 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
2441 loc.resize(locsize);
2443 if (Dgt && Dlt) {
2444 int locsize = loc.size();
2445 loc.push_back(1);
2446 indicator indgt(ind, Dgt);
2447 Dgt = NULL;
2448 /* we don't know the new location of these terms in indgt */
2450 indgt.order.lt[second].push_back(best);
2451 indgt.order.inc_pred(best);
2453 vector<max_term*> maxgt = lexmin(indgt, nparam, loc);
2454 maxima.insert(maxima.end(), maxgt.begin(), maxgt.end());
2455 loc.resize(locsize);
2458 if (Deq) {
2459 loc.push_back(0);
2460 ind.set_domain(Deq);
2461 ind.add_substitution(diff);
2462 ind.perform_pending_substitutions();
2464 if (Dlt) {
2465 loc.push_back(-1);
2466 ind.set_domain(Dlt);
2467 ind.order.lt[best].push_back(second);
2468 ind.order.inc_pred(second);
2470 if (Dgt) {
2471 loc.push_back(1);
2472 ind.set_domain(Dgt);
2473 ind.order.lt[second].push_back(best);
2474 ind.order.inc_pred(best);
2476 } while(1);
2478 return maxima;
2481 static void lexmin_base(Polyhedron *P, Polyhedron *C,
2482 Matrix *CP, Matrix *T,
2483 vector<max_term*>& all_max,
2484 lexmin_options *options)
2486 unsigned nparam = C->Dimension;
2487 Param_Polyhedron *PP = NULL;
2489 PP = Polyhedron2Param_Polyhedron(P, C, options->verify->barvinok);
2491 unsigned dim = P->Dimension - nparam;
2493 int nd = -1;
2495 indicator_constructor ic(P, dim, PP, T);
2497 vector<indicator_term *> all_vertices;
2498 construct_rational_vertices(PP, T, T ? T->NbRows-nparam-1 : dim,
2499 nparam, all_vertices);
2501 Polyhedron *TC = true_context(P, C, options->verify->barvinok->MaxRays);
2502 FORALL_REDUCED_DOMAIN(PP, TC, nd, options->verify->barvinok, i, D, rVD)
2503 Param_Vertices *V;
2505 EDomain *epVD = new EDomain(rVD);
2506 indicator ind(ic, D, epVD, options);
2508 FORALL_PVertex_in_ParamPolyhedron(V,D,PP) // _i is internal counter
2509 ind.add(all_vertices[_i]);
2510 END_FORALL_PVertex_in_ParamPolyhedron;
2512 ind.remove_initial_rational_vertices();
2514 vector<int> loc;
2515 vector<max_term*> maxima = lexmin(ind, nparam, loc);
2516 if (CP)
2517 for (int j = 0; j < maxima.size(); ++j)
2518 maxima[j]->substitute(CP, options->verify->barvinok);
2519 all_max.insert(all_max.end(), maxima.begin(), maxima.end());
2521 Domain_Free(rVD);
2522 END_FORALL_REDUCED_DOMAIN
2523 Polyhedron_Free(TC);
2524 for (int i = 0; i < all_vertices.size(); ++i)
2525 delete all_vertices[i];
2526 Param_Polyhedron_Free(PP);
2529 static vector<max_term*> lexmin(Polyhedron *P, Polyhedron *C,
2530 lexmin_options *options)
2532 unsigned nparam = C->Dimension;
2533 Matrix *T = NULL, *CP = NULL;
2534 Polyhedron *Porig = P;
2535 Polyhedron *Corig = C;
2536 vector<max_term*> all_max;
2538 if (emptyQ2(P))
2539 return all_max;
2541 POL_ENSURE_VERTICES(P);
2543 if (emptyQ2(P))
2544 return all_max;
2546 assert(P->NbBid == 0);
2548 if (P->NbEq > 0)
2549 remove_all_equalities(&P, &C, &CP, &T, nparam,
2550 options->verify->barvinok->MaxRays);
2551 if (!emptyQ2(P))
2552 lexmin_base(P, C, CP, T, all_max, options);
2553 if (CP)
2554 Matrix_Free(CP);
2555 if (T)
2556 Matrix_Free(T);
2557 if (C != Corig)
2558 Polyhedron_Free(C);
2559 if (P != Porig)
2560 Polyhedron_Free(P);
2562 return all_max;
2565 static void verify_results(Polyhedron *A, Polyhedron *C,
2566 vector<max_term*>& maxima,
2567 struct verify_options *options);
2569 /* Turn the set dimensions of "context" into parameters and return
2570 * the corresponding parameter domain.
2572 static struct isl_basic_set *to_parameter_domain(struct isl_basic_set *context)
2574 context = isl_basic_set_move_dims(context, isl_dim_param, 0,
2575 isl_dim_set, 0, isl_basic_set_dim(context, isl_dim_set));
2576 context = isl_basic_set_params(context);
2577 return context;
2580 int main(int argc, char **argv)
2582 isl_ctx *ctx;
2583 isl_basic_set *context, *bset;
2584 Polyhedron *A, *C;
2585 int neg_one, n;
2586 char s[1024];
2587 int urs_parms = 0;
2588 int urs_unknowns = 0;
2589 int print_solution = 1;
2590 struct lexmin_options *options = lexmin_options_new_with_defaults();
2591 int nparam;
2592 options->verify->barvinok->lookup_table = 0;
2594 argc = lexmin_options_parse(options, argc, argv, ISL_ARG_ALL);
2595 ctx = isl_ctx_alloc_with_options(&lexmin_options_args, options);
2597 context = isl_basic_set_read_from_file(ctx, stdin);
2598 assert(context);
2599 n = fscanf(stdin, "%d", &neg_one);
2600 assert(n == 1);
2601 assert(neg_one == -1);
2602 bset = isl_basic_set_read_from_file(ctx, stdin);
2604 while (fgets(s, sizeof(s), stdin)) {
2605 if (strncasecmp(s, "Maximize", 8) == 0) {
2606 fprintf(stderr, "Maximize option not supported\n");
2607 abort();
2609 if (strncasecmp(s, "Rational", 8) == 0) {
2610 fprintf(stderr, "Rational option not supported\n");
2611 abort();
2613 if (strncasecmp(s, "Urs_parms", 9) == 0)
2614 urs_parms = 1;
2615 if (strncasecmp(s, "Urs_unknowns", 12) == 0)
2616 urs_unknowns = 1;
2618 if (!urs_parms)
2619 context = isl_basic_set_intersect(context,
2620 isl_basic_set_positive_orthant(isl_basic_set_get_space(context)));
2621 context = to_parameter_domain(context);
2622 nparam = isl_basic_set_dim(context, isl_dim_param);
2623 if (nparam != isl_basic_set_dim(bset, isl_dim_param)) {
2624 int dim = isl_basic_set_dim(bset, isl_dim_set);
2625 bset = isl_basic_set_move_dims(bset, isl_dim_param, 0,
2626 isl_dim_set, dim - nparam, nparam);
2628 if (!urs_unknowns)
2629 bset = isl_basic_set_intersect(bset,
2630 isl_basic_set_positive_orthant(isl_basic_set_get_space(bset)));
2632 if (options->verify->verify)
2633 print_solution = 0;
2635 A = isl_basic_set_to_polylib(bset);
2636 verify_options_set_range(options->verify, A->Dimension);
2637 C = isl_basic_set_to_polylib(context);
2638 vector<max_term*> maxima = lexmin(A, C, options);
2639 if (print_solution) {
2640 char **param_names;
2641 param_names = util_generate_names(C->Dimension, "p");
2642 for (int i = 0; i < maxima.size(); ++i)
2643 maxima[i]->print(cout, param_names,
2644 options->verify->barvinok);
2645 util_free_names(C->Dimension, param_names);
2648 if (options->verify->verify)
2649 verify_results(A, C, maxima, options->verify);
2651 for (int i = 0; i < maxima.size(); ++i)
2652 delete maxima[i];
2654 Polyhedron_Free(A);
2655 Polyhedron_Free(C);
2657 isl_basic_set_free(bset);
2658 isl_basic_set_free(context);
2659 isl_ctx_free(ctx);
2661 return 0;
2664 static bool lexmin(int pos, Polyhedron *P, Value *context)
2666 Value LB, UB, k;
2667 int lu_flags;
2668 bool found = false;
2670 if (emptyQ(P))
2671 return false;
2673 value_init(LB); value_init(UB); value_init(k);
2674 value_set_si(LB,0);
2675 value_set_si(UB,0);
2676 lu_flags = lower_upper_bounds(pos,P,context,&LB,&UB);
2677 assert(!(lu_flags & LB_INFINITY));
2679 value_set_si(context[pos],0);
2680 if (!lu_flags && value_lt(UB,LB)) {
2681 value_clear(LB); value_clear(UB); value_clear(k);
2682 return false;
2684 if (!P->next) {
2685 value_assign(context[pos], LB);
2686 value_clear(LB); value_clear(UB); value_clear(k);
2687 return true;
2689 for (value_assign(k,LB); lu_flags || value_le(k,UB); value_increment(k,k)) {
2690 value_assign(context[pos],k);
2691 if ((found = lexmin(pos+1, P->next, context)))
2692 break;
2694 if (!found)
2695 value_set_si(context[pos],0);
2696 value_clear(LB); value_clear(UB); value_clear(k);
2697 return found;
2700 static void print_list(FILE *out, Value *z, const char* brackets, int len)
2702 fprintf(out, "%c", brackets[0]);
2703 value_print(out, VALUE_FMT,z[0]);
2704 for (int k = 1; k < len; ++k) {
2705 fprintf(out, ", ");
2706 value_print(out, VALUE_FMT,z[k]);
2708 fprintf(out, "%c", brackets[1]);
2711 static int check_poly_lexmin(const struct check_poly_data *data,
2712 int nparam, Value *z,
2713 const struct verify_options *options);
2715 struct check_poly_lexmin_data : public check_poly_data {
2716 Polyhedron *S;
2717 vector<max_term*>& maxima;
2719 check_poly_lexmin_data(Polyhedron *S, Value *z,
2720 vector<max_term*>& maxima) : S(S), maxima(maxima) {
2721 this->z = z;
2722 this->check = &check_poly_lexmin;
2726 static int check_poly_lexmin(const struct check_poly_data *data,
2727 int nparam, Value *z,
2728 const struct verify_options *options)
2730 const check_poly_lexmin_data *lexmin_data;
2731 lexmin_data = static_cast<const check_poly_lexmin_data *>(data);
2732 Polyhedron *S = lexmin_data->S;
2733 vector<max_term*>& maxima = lexmin_data->maxima;
2734 int k;
2735 bool found = lexmin(1, S, lexmin_data->z);
2737 if (options->print_all) {
2738 printf("lexmin");
2739 print_list(stdout, z, "()", nparam);
2740 printf(" = ");
2741 if (found)
2742 print_list(stdout, lexmin_data->z+1, "[]", S->Dimension-nparam);
2743 printf(" ");
2746 Vector *min = NULL;
2747 for (int i = 0; i < maxima.size(); ++i)
2748 if ((min = maxima[i]->eval(z, options->barvinok->MaxRays)))
2749 break;
2751 int ok = !(found ^ !!min);
2752 if (found && min)
2753 for (int i = 0; i < S->Dimension-nparam; ++i)
2754 if (value_ne(lexmin_data->z[1+i], min->p[i])) {
2755 ok = 0;
2756 break;
2758 if (!ok) {
2759 printf("\n");
2760 fflush(stdout);
2761 fprintf(stderr, "Error !\n");
2762 fprintf(stderr, "lexmin");
2763 print_list(stderr, z, "()", nparam);
2764 fprintf(stderr, " should be ");
2765 if (found)
2766 print_list(stderr, lexmin_data->z+1, "[]", S->Dimension-nparam);
2767 fprintf(stderr, " while digging gives ");
2768 if (min)
2769 print_list(stderr, min->p, "[]", S->Dimension-nparam);
2770 fprintf(stderr, ".\n");
2771 return 0;
2772 } else if (options->print_all)
2773 printf("OK.\n");
2774 if (min)
2775 Vector_Free(min);
2777 for (k = 1; k <= S->Dimension-nparam; ++k)
2778 value_set_si(lexmin_data->z[k], 0);
2780 return 0;
2783 void verify_results(Polyhedron *A, Polyhedron *C, vector<max_term*>& maxima,
2784 struct verify_options *options)
2786 Polyhedron *CS, *S;
2787 unsigned nparam = C->Dimension;
2788 unsigned MaxRays = options->barvinok->MaxRays;
2789 Vector *p;
2790 int i;
2791 int st;
2793 CS = check_poly_context_scan(A, &C, nparam, options);
2795 p = Vector_Alloc(A->Dimension+2);
2796 value_set_si(p->p[A->Dimension+1], 1);
2798 S = Polyhedron_Scan(A, C, MaxRays & POL_NO_DUAL ? 0 : MaxRays);
2800 check_poly_init(C, options);
2802 if (S) {
2803 if (!(CS && emptyQ2(CS))) {
2804 check_poly_lexmin_data data(S, p->p, maxima);
2805 check_poly(CS, &data, nparam, 0, p->p+S->Dimension-nparam+1, options);
2807 Domain_Free(S);
2810 if (!options->print_all)
2811 printf("\n");
2813 Vector_Free(p);
2814 if (CS) {
2815 Domain_Free(CS);
2816 Polyhedron_Free(C);