barvinok.cc: make use of sampling for counting infinite domains configurable
[barvinok.git] / lexmin.cc
blob6d16b7923b8aa0b80815022c039be9817a76bba9
1 #include <iostream>
2 #include <vector>
3 #include <map>
4 #include <set>
5 #include <gmp.h>
6 #include <NTL/vec_ZZ.h>
7 #include <NTL/mat_ZZ.h>
8 #include <barvinok/barvinok.h>
9 #include <barvinok/evalue.h>
10 #include <barvinok/options.h>
11 #include <barvinok/util.h>
12 #include "argp.h"
13 #include "conversion.h"
14 #include "decomposer.h"
15 #include "lattice_point.h"
16 #include "reduce_domain.h"
17 #include "mat_util.h"
18 #include "combine.h"
19 #include "edomain.h"
20 #include "evalue_util.h"
21 #include "remove_equalities.h"
22 #include "polysign.h"
23 #include "verify.h"
25 #ifdef NTL_STD_CXX
26 using namespace NTL;
27 #endif
29 using std::vector;
30 using std::map;
31 using std::cerr;
32 using std::cout;
33 using std::endl;
34 using std::ostream;
36 #define EMPTINESS_CHECK (BV_OPT_LAST+1)
37 #define BASIS_REDUCTION_CDD (BV_OPT_LAST+2)
38 #define NO_REDUCTION (BV_OPT_LAST+3)
39 #define POLYSIGN (BV_OPT_LAST+4)
41 struct argp_option argp_options[] = {
42 { "emptiness-check", EMPTINESS_CHECK, "[none|count]", 0 },
43 { "no-reduction", NO_REDUCTION, 0, 0 },
44 { "polysign", POLYSIGN, "[cdd|cddf]", 0 },
45 { 0 }
48 struct arguments {
49 struct barvinok_options *options;
50 struct verify_options verify;
53 static error_t parse_opt(int key, char *arg, struct argp_state *state)
55 struct arguments *arguments = (struct arguments *)(state->input);
56 struct barvinok_options *options = arguments->options;
58 switch (key) {
59 case ARGP_KEY_INIT:
60 state->child_inputs[0] = arguments->options;
61 state->child_inputs[1] = &arguments->verify;
62 break;
63 case EMPTINESS_CHECK:
64 if (!strcmp(arg, "none"))
65 options->lexmin_emptiness_check = BV_LEXMIN_EMPTINESS_CHECK_NONE;
66 else if (!strcmp(arg, "count")) {
67 options->lexmin_emptiness_check = BV_LEXMIN_EMPTINESS_CHECK_COUNT;
68 options->count_sample_infinite = 0;
70 break;
71 case NO_REDUCTION:
72 options->lexmin_reduce = 0;
73 break;
74 case POLYSIGN:
75 if (!strcmp(arg, "cddf"))
76 options->lexmin_polysign = BV_LEXMIN_POLYSIGN_CDDF;
77 else if (!strcmp(arg, "cdd"))
78 options->lexmin_polysign = BV_LEXMIN_POLYSIGN_CDD;
79 break;
80 default:
81 return ARGP_ERR_UNKNOWN;
83 return 0;
86 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
88 static int type_offset(enode *p)
90 return p->type == fractional ? 1 :
91 p->type == flooring ? 1 : 0;
94 void compute_evalue(evalue *e, Value *val, Value *res)
96 double d = compute_evalue(e, val);
97 if (d > 0)
98 d += .25;
99 else
100 d -= .25;
101 value_set_double(*res, d);
104 struct indicator_term {
105 int sign;
106 int pos; /* number of rational vertex */
107 int n; /* number of cone associated to given rational vertex */
108 mat_ZZ den;
109 evalue **vertex;
111 indicator_term(unsigned dim, int pos) {
112 den.SetDims(0, dim);
113 vertex = new evalue* [dim];
114 this->pos = pos;
115 n = -1;
116 sign = 0;
118 indicator_term(unsigned dim, int pos, int n) {
119 den.SetDims(dim, dim);
120 vertex = new evalue* [dim];
121 this->pos = pos;
122 this->n = n;
124 indicator_term(const indicator_term& src) {
125 sign = src.sign;
126 pos = src.pos;
127 n = src.n;
128 den = src.den;
129 unsigned dim = den.NumCols();
130 vertex = new evalue* [dim];
131 for (int i = 0; i < dim; ++i) {
132 vertex[i] = new evalue();
133 value_init(vertex[i]->d);
134 evalue_copy(vertex[i], src.vertex[i]);
137 void swap(indicator_term *other) {
138 int tmp;
139 tmp = sign; sign = other->sign; other->sign = tmp;
140 tmp = pos; pos = other->pos; other->pos = tmp;
141 tmp = n; n = other->n; other->n = tmp;
142 mat_ZZ tmp_den = den; den = other->den; other->den = tmp_den;
143 unsigned dim = den.NumCols();
144 for (int i = 0; i < dim; ++i) {
145 evalue *tmp = vertex[i];
146 vertex[i] = other->vertex[i];
147 other->vertex[i] = tmp;
150 ~indicator_term() {
151 unsigned dim = den.NumCols();
152 for (int i = 0; i < dim; ++i) {
153 free_evalue_refs(vertex[i]);
154 delete vertex[i];
156 delete [] vertex;
158 void print(ostream& os, char **p) const;
159 void substitute(Matrix *T);
160 void normalize();
161 void substitute(evalue *fract, evalue *val);
162 void substitute(int pos, evalue *val);
163 void reduce_in_domain(Polyhedron *D);
164 bool is_opposite(const indicator_term *neg) const;
165 vec_ZZ eval(Value *val) const {
166 vec_ZZ v;
167 unsigned dim = den.NumCols();
168 v.SetLength(dim);
169 Value tmp;
170 value_init(tmp);
171 for (int i = 0; i < dim; ++i) {
172 compute_evalue(vertex[i], val, &tmp);
173 value2zz(tmp, v[i]);
175 value_clear(tmp);
176 return v;
180 static int evalue_rational_cmp(const evalue *e1, const evalue *e2)
182 int r;
183 Value m;
184 Value m2;
185 value_init(m);
186 value_init(m2);
188 assert(value_notzero_p(e1->d));
189 assert(value_notzero_p(e2->d));
190 value_multiply(m, e1->x.n, e2->d);
191 value_multiply(m2, e2->x.n, e1->d);
192 if (value_lt(m, m2))
193 r = -1;
194 else if (value_gt(m, m2))
195 r = 1;
196 else
197 r = 0;
198 value_clear(m);
199 value_clear(m2);
201 return r;
204 static int evalue_cmp(const evalue *e1, const evalue *e2)
206 if (value_notzero_p(e1->d)) {
207 if (value_zero_p(e2->d))
208 return -1;
209 return evalue_rational_cmp(e1, e2);
211 if (value_notzero_p(e2->d))
212 return 1;
213 if (e1->x.p->type != e2->x.p->type)
214 return e1->x.p->type - e2->x.p->type;
215 if (e1->x.p->size != e2->x.p->size)
216 return e1->x.p->size - e2->x.p->size;
217 if (e1->x.p->pos != e2->x.p->pos)
218 return e1->x.p->pos - e2->x.p->pos;
219 assert(e1->x.p->type == polynomial ||
220 e1->x.p->type == fractional ||
221 e1->x.p->type == flooring);
222 for (int i = 0; i < e1->x.p->size; ++i) {
223 int s = evalue_cmp(&e1->x.p->arr[i], &e2->x.p->arr[i]);
224 if (s)
225 return s;
227 return 0;
230 void evalue_length(evalue *e, int len[2])
232 len[0] = 0;
233 len[1] = 0;
235 while (value_zero_p(e->d)) {
236 assert(e->x.p->type == polynomial ||
237 e->x.p->type == fractional ||
238 e->x.p->type == flooring);
239 if (e->x.p->type == polynomial)
240 len[1]++;
241 else
242 len[0]++;
243 int offset = type_offset(e->x.p);
244 assert(e->x.p->size == offset+2);
245 e = &e->x.p->arr[offset];
249 static bool it_smaller(const indicator_term* it1, const indicator_term* it2)
251 if (it1 == it2)
252 return false;
253 int len1[2], len2[2];
254 unsigned dim = it1->den.NumCols();
255 for (int i = 0; i < dim; ++i) {
256 evalue_length(it1->vertex[i], len1);
257 evalue_length(it2->vertex[i], len2);
258 if (len1[0] != len2[0])
259 return len1[0] < len2[0];
260 if (len1[1] != len2[1])
261 return len1[1] < len2[1];
263 if (it1->pos != it2->pos)
264 return it1->pos < it2->pos;
265 if (it1->n != it2->n)
266 return it1->n < it2->n;
267 int s = lex_cmp(it1->den, it2->den);
268 if (s)
269 return s < 0;
270 for (int i = 0; i < dim; ++i) {
271 s = evalue_cmp(it1->vertex[i], it2->vertex[i]);
272 if (s)
273 return s < 0;
275 assert(it1->sign != 0);
276 assert(it2->sign != 0);
277 if (it1->sign != it2->sign)
278 return it1->sign > 0;
279 return it1 < it2;
282 struct smaller_it {
283 static const int requires_resort;
284 bool operator()(const indicator_term* it1, const indicator_term* it2) const {
285 return it_smaller(it1, it2);
288 const int smaller_it::requires_resort = 1;
290 struct smaller_it_p {
291 static const int requires_resort;
292 bool operator()(const indicator_term* it1, const indicator_term* it2) const {
293 return it1 < it2;
296 const int smaller_it_p::requires_resort = 0;
298 /* Returns true if this and neg are opposite using the knowledge
299 * that they have the same numerator.
300 * In particular, we check that the signs are different and that
301 * the denominator is the same.
303 bool indicator_term::is_opposite(const indicator_term *neg) const
305 if (sign + neg->sign != 0)
306 return false;
307 if (den != neg->den)
308 return false;
309 return true;
312 void indicator_term::reduce_in_domain(Polyhedron *D)
314 for (int k = 0; k < den.NumCols(); ++k) {
315 reduce_evalue_in_domain(vertex[k], D);
316 if (evalue_range_reduction_in_domain(vertex[k], D))
317 reduce_evalue(vertex[k]);
321 void indicator_term::print(ostream& os, char **p) const
323 unsigned dim = den.NumCols();
324 unsigned factors = den.NumRows();
325 if (sign == 0)
326 os << " s ";
327 else if (sign > 0)
328 os << " + ";
329 else
330 os << " - ";
331 os << '[';
332 for (int i = 0; i < dim; ++i) {
333 if (i)
334 os << ',';
335 evalue_print(os, vertex[i], p);
337 os << ']';
338 for (int i = 0; i < factors; ++i) {
339 os << " + t" << i << "*[";
340 for (int j = 0; j < dim; ++j) {
341 if (j)
342 os << ',';
343 os << den[i][j];
345 os << "]";
347 os << " ((" << pos << ", " << n << ", " << (void*)this << "))";
350 /* Perform the substitution specified by T on the variables.
351 * T has dimension (newdim+nparam+1) x (olddim + nparam + 1).
352 * The substitution is performed as in gen_fun::substitute
354 void indicator_term::substitute(Matrix *T)
356 unsigned dim = den.NumCols();
357 unsigned nparam = T->NbColumns - dim - 1;
358 unsigned newdim = T->NbRows - nparam - 1;
359 evalue **newvertex;
360 mat_ZZ trans;
361 matrix2zz(T, trans, newdim, dim);
362 trans = transpose(trans);
363 den *= trans;
364 newvertex = new evalue* [newdim];
366 vec_ZZ v;
367 v.SetLength(nparam+1);
369 evalue factor;
370 value_init(factor.d);
371 value_set_si(factor.d, 1);
372 value_init(factor.x.n);
373 for (int i = 0; i < newdim; ++i) {
374 values2zz(T->p[i]+dim, v, nparam+1);
375 newvertex[i] = multi_monom(v);
377 for (int j = 0; j < dim; ++j) {
378 if (value_zero_p(T->p[i][j]))
379 continue;
380 evalue term;
381 value_init(term.d);
382 evalue_copy(&term, vertex[j]);
383 value_assign(factor.x.n, T->p[i][j]);
384 emul(&factor, &term);
385 eadd(&term, newvertex[i]);
386 free_evalue_refs(&term);
389 free_evalue_refs(&factor);
390 for (int i = 0; i < dim; ++i) {
391 free_evalue_refs(vertex[i]);
392 delete vertex[i];
394 delete [] vertex;
395 vertex = newvertex;
398 static void evalue_add_constant(evalue *e, ZZ v)
400 Value tmp;
401 value_init(tmp);
403 /* go down to constant term */
404 while (value_zero_p(e->d))
405 e = &e->x.p->arr[type_offset(e->x.p)];
406 /* and add v */
407 zz2value(v, tmp);
408 value_multiply(tmp, tmp, e->d);
409 value_addto(e->x.n, e->x.n, tmp);
411 value_clear(tmp);
414 /* Make all powers in denominator lexico-positive */
415 void indicator_term::normalize()
417 vec_ZZ extra_vertex;
418 extra_vertex.SetLength(den.NumCols());
419 for (int r = 0; r < den.NumRows(); ++r) {
420 for (int k = 0; k < den.NumCols(); ++k) {
421 if (den[r][k] == 0)
422 continue;
423 if (den[r][k] > 0)
424 break;
425 sign = -sign;
426 den[r] = -den[r];
427 extra_vertex += den[r];
428 break;
431 for (int k = 0; k < extra_vertex.length(); ++k)
432 if (extra_vertex[k] != 0)
433 evalue_add_constant(vertex[k], extra_vertex[k]);
436 static void substitute(evalue *e, evalue *fract, evalue *val)
438 evalue *t;
440 for (t = e; value_zero_p(t->d); t = &t->x.p->arr[type_offset(t->x.p)]) {
441 if (t->x.p->type == fractional && eequal(&t->x.p->arr[0], fract))
442 break;
444 if (value_notzero_p(t->d))
445 return;
447 free_evalue_refs(&t->x.p->arr[0]);
448 evalue *term = &t->x.p->arr[2];
449 enode *p = t->x.p;
450 value_clear(t->d);
451 *t = t->x.p->arr[1];
453 emul(val, term);
454 eadd(term, e);
455 free_evalue_refs(term);
456 free(p);
458 reduce_evalue(e);
461 void indicator_term::substitute(evalue *fract, evalue *val)
463 unsigned dim = den.NumCols();
464 for (int i = 0; i < dim; ++i) {
465 ::substitute(vertex[i], fract, val);
469 static void substitute(evalue *e, int pos, evalue *val)
471 evalue *t;
473 for (t = e; value_zero_p(t->d); t = &t->x.p->arr[type_offset(t->x.p)]) {
474 if (t->x.p->type == polynomial && t->x.p->pos == pos)
475 break;
477 if (value_notzero_p(t->d))
478 return;
480 evalue *term = &t->x.p->arr[1];
481 enode *p = t->x.p;
482 value_clear(t->d);
483 *t = t->x.p->arr[0];
485 emul(val, term);
486 eadd(term, e);
487 free_evalue_refs(term);
488 free(p);
490 reduce_evalue(e);
493 void indicator_term::substitute(int pos, evalue *val)
495 unsigned dim = den.NumCols();
496 for (int i = 0; i < dim; ++i) {
497 ::substitute(vertex[i], pos, val);
501 struct indicator_constructor : public signed_cone_consumer,
502 public vertex_decomposer {
503 vec_ZZ vertex;
504 vector<indicator_term*> *terms;
505 Matrix *T; /* Transformation to original space */
506 Param_Polyhedron *PP;
507 int pos;
508 int n;
510 indicator_constructor(Polyhedron *P, unsigned dim, Param_Polyhedron *PP,
511 Matrix *T) :
512 vertex_decomposer(P, PP->nbV, *this), T(T), PP(PP) {
513 vertex.SetLength(dim);
514 terms = new vector<indicator_term*>[nbV];
516 ~indicator_constructor() {
517 for (int i = 0; i < nbV; ++i)
518 for (int j = 0; j < terms[i].size(); ++j)
519 delete terms[i][j];
520 delete [] terms;
522 void substitute(Matrix *T);
523 void normalize();
524 void print(ostream& os, char **p);
526 virtual void handle(const signed_cone& sc, barvinok_options *options);
527 void decompose_at_vertex(Param_Vertices *V, int _i,
528 barvinok_options *options) {
529 pos = _i;
530 n = 0;
531 vertex_decomposer::decompose_at_vertex(V, _i, options);
535 void indicator_constructor::handle(const signed_cone& sc, barvinok_options *options)
537 assert(!sc.closed);
538 unsigned dim = vertex.length();
540 assert(sc.rays.NumRows() == dim);
542 indicator_term *term = new indicator_term(dim, pos, n++);
543 term->sign = sc.sign;
544 terms[vert].push_back(term);
546 lattice_point(V, sc.rays, vertex, term->vertex, options);
548 term->den = sc.rays;
549 for (int r = 0; r < dim; ++r) {
550 for (int j = 0; j < dim; ++j) {
551 if (term->den[r][j] == 0)
552 continue;
553 if (term->den[r][j] > 0)
554 break;
555 term->sign = -term->sign;
556 term->den[r] = -term->den[r];
557 vertex += term->den[r];
558 break;
562 for (int i = 0; i < dim; ++i) {
563 if (!term->vertex[i]) {
564 term->vertex[i] = new evalue();
565 value_init(term->vertex[i]->d);
566 value_init(term->vertex[i]->x.n);
567 zz2value(vertex[i], term->vertex[i]->x.n);
568 value_set_si(term->vertex[i]->d, 1);
569 continue;
571 if (vertex[i] == 0)
572 continue;
573 evalue_add_constant(term->vertex[i], vertex[i]);
576 if (T) {
577 term->substitute(T);
578 term->normalize();
581 lex_order_rows(term->den);
584 void indicator_constructor::print(ostream& os, char **p)
586 for (int i = 0; i < nbV; ++i)
587 for (int j = 0; j < terms[i].size(); ++j) {
588 os << "i: " << i << ", j: " << j << endl;
589 terms[i][j]->print(os, p);
590 os << endl;
594 void indicator_constructor::normalize()
596 for (int i = 0; i < nbV; ++i)
597 for (int j = 0; j < terms[i].size(); ++j) {
598 vec_ZZ vertex;
599 vertex.SetLength(terms[i][j]->den.NumCols());
600 for (int r = 0; r < terms[i][j]->den.NumRows(); ++r) {
601 for (int k = 0; k < terms[i][j]->den.NumCols(); ++k) {
602 if (terms[i][j]->den[r][k] == 0)
603 continue;
604 if (terms[i][j]->den[r][k] > 0)
605 break;
606 terms[i][j]->sign = -terms[i][j]->sign;
607 terms[i][j]->den[r] = -terms[i][j]->den[r];
608 vertex += terms[i][j]->den[r];
609 break;
612 lex_order_rows(terms[i][j]->den);
613 for (int k = 0; k < vertex.length(); ++k)
614 if (vertex[k] != 0)
615 evalue_add_constant(terms[i][j]->vertex[k], vertex[k]);
619 struct order_cache_el {
620 vector<evalue *> e;
621 order_cache_el copy() const {
622 order_cache_el n;
623 for (int i = 0; i < e.size(); ++i) {
624 evalue *c = new evalue;
625 value_init(c->d);
626 evalue_copy(c, e[i]);
627 n.e.push_back(c);
629 return n;
631 void free() {
632 for (int i = 0; i < e.size(); ++i) {
633 free_evalue_refs(e[i]);
634 delete e[i];
637 void negate() {
638 evalue mone;
639 value_init(mone.d);
640 evalue_set_si(&mone, -1, 1);
641 for (int i = 0; i < e.size(); ++i)
642 emul(&mone, e[i]);
643 free_evalue_refs(&mone);
645 void print(ostream& os, char **p);
648 void order_cache_el::print(ostream& os, char **p)
650 os << "[";
651 for (int i = 0; i < e.size(); ++i) {
652 if (i)
653 os << ",";
654 evalue_print(os, e[i], p);
656 os << "]";
659 struct order_cache {
660 vector<order_cache_el> lt;
661 vector<order_cache_el> le;
662 vector<order_cache_el> unknown;
664 void clear_transients() {
665 for (int i = 0; i < le.size(); ++i)
666 le[i].free();
667 for (int i = 0; i < unknown.size(); ++i)
668 unknown[i].free();
669 le.resize(0);
670 unknown.resize(0);
672 ~order_cache() {
673 clear_transients();
674 for (int i = 0; i < lt.size(); ++i)
675 lt[i].free();
676 lt.resize(0);
678 void add(order_cache_el& cache_el, order_sign sign);
679 order_sign check_lt(vector<order_cache_el>* list,
680 const indicator_term *a, const indicator_term *b,
681 order_cache_el& cache_el);
682 order_sign check_lt(const indicator_term *a, const indicator_term *b,
683 order_cache_el& cache_el);
684 order_sign check_direct(const indicator_term *a, const indicator_term *b,
685 order_cache_el& cache_el);
686 order_sign check(const indicator_term *a, const indicator_term *b,
687 order_cache_el& cache_el);
688 void copy(const order_cache& cache);
689 void print(ostream& os, char **p);
692 void order_cache::copy(const order_cache& cache)
694 for (int i = 0; i < cache.lt.size(); ++i) {
695 order_cache_el n = cache.lt[i].copy();
696 add(n, order_lt);
700 void order_cache::add(order_cache_el& cache_el, order_sign sign)
702 if (sign == order_lt) {
703 lt.push_back(cache_el);
704 } else if (sign == order_gt) {
705 cache_el.negate();
706 lt.push_back(cache_el);
707 } else if (sign == order_le) {
708 le.push_back(cache_el);
709 } else if (sign == order_ge) {
710 cache_el.negate();
711 le.push_back(cache_el);
712 } else if (sign == order_unknown) {
713 unknown.push_back(cache_el);
714 } else {
715 assert(sign == order_eq);
716 cache_el.free();
718 return;
721 /* compute a - b */
722 static evalue *ediff(const evalue *a, const evalue *b)
724 evalue mone;
725 value_init(mone.d);
726 evalue_set_si(&mone, -1, 1);
727 evalue *diff = new evalue;
728 value_init(diff->d);
729 evalue_copy(diff, b);
730 emul(&mone, diff);
731 eadd(a, diff);
732 reduce_evalue(diff);
733 free_evalue_refs(&mone);
734 return diff;
737 static bool evalue_first_difference(const evalue *e1, const evalue *e2,
738 const evalue **d1, const evalue **d2)
740 *d1 = e1;
741 *d2 = e2;
743 if (value_ne(e1->d, e2->d))
744 return true;
746 if (value_notzero_p(e1->d)) {
747 if (value_eq(e1->x.n, e2->x.n))
748 return false;
749 return true;
751 if (e1->x.p->type != e2->x.p->type)
752 return true;
753 if (e1->x.p->size != e2->x.p->size)
754 return true;
755 if (e1->x.p->pos != e2->x.p->pos)
756 return true;
758 assert(e1->x.p->type == polynomial ||
759 e1->x.p->type == fractional ||
760 e1->x.p->type == flooring);
761 int offset = type_offset(e1->x.p);
762 assert(e1->x.p->size == offset+2);
763 for (int i = 0; i < e1->x.p->size; ++i)
764 if (i != type_offset(e1->x.p) &&
765 !eequal(&e1->x.p->arr[i], &e2->x.p->arr[i]))
766 return true;
768 return evalue_first_difference(&e1->x.p->arr[offset],
769 &e2->x.p->arr[offset], d1, d2);
772 static order_sign evalue_diff_constant_sign(const evalue *e1, const evalue *e2)
774 if (!evalue_first_difference(e1, e2, &e1, &e2))
775 return order_eq;
776 if (value_zero_p(e1->d) || value_zero_p(e2->d))
777 return order_undefined;
778 int s = evalue_rational_cmp(e1, e2);
779 if (s < 0)
780 return order_lt;
781 else if (s > 0)
782 return order_gt;
783 else
784 return order_eq;
787 order_sign order_cache::check_lt(vector<order_cache_el>* list,
788 const indicator_term *a, const indicator_term *b,
789 order_cache_el& cache_el)
791 order_sign sign = order_undefined;
792 for (int i = 0; i < list->size(); ++i) {
793 int j;
794 for (j = cache_el.e.size(); j < (*list)[i].e.size(); ++j)
795 cache_el.e.push_back(ediff(a->vertex[j], b->vertex[j]));
796 for (j = 0; j < (*list)[i].e.size(); ++j) {
797 order_sign diff_sign;
798 diff_sign = evalue_diff_constant_sign((*list)[i].e[j], cache_el.e[j]);
799 if (diff_sign == order_gt) {
800 sign = order_lt;
801 break;
802 } else if (diff_sign == order_lt)
803 break;
804 else if (diff_sign == order_undefined)
805 break;
806 else
807 assert(diff_sign == order_eq);
809 if (j == (*list)[i].e.size())
810 sign = list == &lt ? order_lt : order_le;
811 if (sign != order_undefined)
812 break;
814 return sign;
817 order_sign order_cache::check_direct(const indicator_term *a,
818 const indicator_term *b,
819 order_cache_el& cache_el)
821 order_sign sign = check_lt(&lt, a, b, cache_el);
822 if (sign != order_undefined)
823 return sign;
824 sign = check_lt(&le, a, b, cache_el);
825 if (sign != order_undefined)
826 return sign;
828 for (int i = 0; i < unknown.size(); ++i) {
829 int j;
830 for (j = cache_el.e.size(); j < unknown[i].e.size(); ++j)
831 cache_el.e.push_back(ediff(a->vertex[j], b->vertex[j]));
832 for (j = 0; j < unknown[i].e.size(); ++j) {
833 if (!eequal(unknown[i].e[j], cache_el.e[j]))
834 break;
836 if (j == unknown[i].e.size()) {
837 sign = order_unknown;
838 break;
841 return sign;
844 order_sign order_cache::check(const indicator_term *a, const indicator_term *b,
845 order_cache_el& cache_el)
847 order_sign sign = check_direct(a, b, cache_el);
848 if (sign != order_undefined)
849 return sign;
850 int size = cache_el.e.size();
851 cache_el.negate();
852 sign = check_direct(a, b, cache_el);
853 cache_el.negate();
854 assert(cache_el.e.size() == size);
855 if (sign == order_undefined)
856 return sign;
857 if (sign == order_lt)
858 sign = order_gt;
859 else if (sign == order_le)
860 sign = order_ge;
861 else
862 assert(sign == order_unknown);
863 return sign;
866 struct indicator;
868 struct partial_order {
869 indicator *ind;
871 std::set<const indicator_term *, smaller_it > head;
872 map<const indicator_term *, int, smaller_it > pred;
873 map<const indicator_term *, vector<const indicator_term * >, smaller_it > lt;
874 map<const indicator_term *, vector<const indicator_term * >, smaller_it > le;
875 map<const indicator_term *, vector<const indicator_term * >, smaller_it > eq;
877 map<const indicator_term *, vector<const indicator_term * >, smaller_it > pending;
879 order_cache cache;
881 partial_order(indicator *ind) : ind(ind) {}
882 void copy(const partial_order& order,
883 map< const indicator_term *, indicator_term * > old2new);
884 void resort() {
885 map<const indicator_term *, vector<const indicator_term * > >::iterator i;
886 map<const indicator_term *, int >::iterator j;
887 std::set<const indicator_term *>::iterator k;
889 if (head.key_comp().requires_resort) {
890 typeof(head) new_head;
891 for (k = head.begin(); k != head.end(); ++k)
892 new_head.insert(*k);
893 head.swap(new_head);
894 new_head.clear();
897 if (pred.key_comp().requires_resort) {
898 typeof(pred) new_pred;
899 for (j = pred.begin(); j != pred.end(); ++j)
900 new_pred[(*j).first] = (*j).second;
901 pred.swap(new_pred);
902 new_pred.clear();
905 if (lt.key_comp().requires_resort) {
906 typeof(lt) m;
907 for (i = lt.begin(); i != lt.end(); ++i)
908 m[(*i).first] = (*i).second;
909 lt.swap(m);
910 m.clear();
913 if (le.key_comp().requires_resort) {
914 typeof(le) m;
915 for (i = le.begin(); i != le.end(); ++i)
916 m[(*i).first] = (*i).second;
917 le.swap(m);
918 m.clear();
921 if (eq.key_comp().requires_resort) {
922 typeof(eq) m;
923 for (i = eq.begin(); i != eq.end(); ++i)
924 m[(*i).first] = (*i).second;
925 eq.swap(m);
926 m.clear();
929 if (pending.key_comp().requires_resort) {
930 typeof(pending) m;
931 for (i = pending.begin(); i != pending.end(); ++i)
932 m[(*i).first] = (*i).second;
933 pending.swap(m);
934 m.clear();
938 order_sign compare(const indicator_term *a, const indicator_term *b);
939 void set_equal(const indicator_term *a, const indicator_term *b);
940 void unset_le(const indicator_term *a, const indicator_term *b);
941 void dec_pred(const indicator_term *it) {
942 if (--pred[it] == 0) {
943 pred.erase(it);
944 head.insert(it);
947 void inc_pred(const indicator_term *it) {
948 if (head.find(it) != head.end())
949 head.erase(it);
950 pred[it]++;
953 bool compared(const indicator_term* a, const indicator_term* b);
954 void add(const indicator_term* it, std::set<const indicator_term *> *filter);
955 void remove(const indicator_term* it);
957 void print(ostream& os, char **p);
959 /* replace references to orig to references to replacement */
960 void replace(const indicator_term* orig, indicator_term* replacement);
961 void sanity_check() const;
964 /* We actually replace the contents of orig by that of replacement,
965 * but we have to be careful since replacing the content changes
966 * the order of orig in the maps.
968 void partial_order::replace(const indicator_term* orig, indicator_term* replacement)
970 std::set<const indicator_term *>::iterator k;
971 k = head.find(orig);
972 bool is_head = k != head.end();
973 int orig_pred;
974 if (is_head) {
975 head.erase(orig);
976 } else {
977 orig_pred = pred[orig];
978 pred.erase(orig);
980 vector<const indicator_term * > orig_lt;
981 vector<const indicator_term * > orig_le;
982 vector<const indicator_term * > orig_eq;
983 vector<const indicator_term * > orig_pending;
984 map<const indicator_term *, vector<const indicator_term * > >::iterator i;
985 bool in_lt = ((i = lt.find(orig)) != lt.end());
986 if (in_lt) {
987 orig_lt = (*i).second;
988 lt.erase(orig);
990 bool in_le = ((i = le.find(orig)) != le.end());
991 if (in_le) {
992 orig_le = (*i).second;
993 le.erase(orig);
995 bool in_eq = ((i = eq.find(orig)) != eq.end());
996 if (in_eq) {
997 orig_eq = (*i).second;
998 eq.erase(orig);
1000 bool in_pending = ((i = pending.find(orig)) != pending.end());
1001 if (in_pending) {
1002 orig_pending = (*i).second;
1003 pending.erase(orig);
1005 indicator_term *old = const_cast<indicator_term *>(orig);
1006 old->swap(replacement);
1007 if (is_head)
1008 head.insert(old);
1009 else
1010 pred[old] = orig_pred;
1011 if (in_lt)
1012 lt[old] = orig_lt;
1013 if (in_le)
1014 le[old] = orig_le;
1015 if (in_eq)
1016 eq[old] = orig_eq;
1017 if (in_pending)
1018 pending[old] = orig_pending;
1021 void partial_order::unset_le(const indicator_term *a, const indicator_term *b)
1023 vector<const indicator_term *>::iterator i;
1024 i = find(le[a].begin(), le[a].end(), b);
1025 le[a].erase(i);
1026 if (le[a].size() == 0)
1027 le.erase(a);
1028 dec_pred(b);
1029 i = find(pending[a].begin(), pending[a].end(), b);
1030 if (i != pending[a].end())
1031 pending[a].erase(i);
1034 void partial_order::set_equal(const indicator_term *a, const indicator_term *b)
1036 if (eq[a].size() == 0)
1037 eq[a].push_back(a);
1038 if (eq[b].size() == 0)
1039 eq[b].push_back(b);
1040 a = eq[a][0];
1041 b = eq[b][0];
1042 assert(a != b);
1043 if (pred.key_comp()(b, a)) {
1044 const indicator_term *c = a;
1045 a = b;
1046 b = c;
1049 const indicator_term *base = a;
1051 map<const indicator_term *, vector<const indicator_term * > >::iterator i;
1053 for (int j = 0; j < eq[b].size(); ++j) {
1054 eq[base].push_back(eq[b][j]);
1055 eq[eq[b][j]][0] = base;
1057 eq[b].resize(1);
1059 i = lt.find(b);
1060 if (i != lt.end()) {
1061 for (int j = 0; j < lt[b].size(); ++j) {
1062 if (find(eq[base].begin(), eq[base].end(), lt[b][j]) != eq[base].end())
1063 dec_pred(lt[b][j]);
1064 else if (find(lt[base].begin(), lt[base].end(), lt[b][j])
1065 != lt[base].end())
1066 dec_pred(lt[b][j]);
1067 else
1068 lt[base].push_back(lt[b][j]);
1070 lt.erase(b);
1073 i = le.find(b);
1074 if (i != le.end()) {
1075 for (int j = 0; j < le[b].size(); ++j) {
1076 if (find(eq[base].begin(), eq[base].end(), le[b][j]) != eq[base].end())
1077 dec_pred(le[b][j]);
1078 else if (find(le[base].begin(), le[base].end(), le[b][j])
1079 != le[base].end())
1080 dec_pred(le[b][j]);
1081 else
1082 le[base].push_back(le[b][j]);
1084 le.erase(b);
1087 i = pending.find(base);
1088 if (i != pending.end()) {
1089 vector<const indicator_term * > old = pending[base];
1090 pending[base].clear();
1091 for (int j = 0; j < old.size(); ++j) {
1092 if (find(eq[base].begin(), eq[base].end(), old[j]) == eq[base].end())
1093 pending[base].push_back(old[j]);
1097 i = pending.find(b);
1098 if (i != pending.end()) {
1099 for (int j = 0; j < pending[b].size(); ++j) {
1100 if (find(eq[base].begin(), eq[base].end(), pending[b][j]) == eq[base].end())
1101 pending[base].push_back(pending[b][j]);
1103 pending.erase(b);
1107 void partial_order::copy(const partial_order& order,
1108 map< const indicator_term *, indicator_term * > old2new)
1110 cache.copy(order.cache);
1112 map<const indicator_term *, vector<const indicator_term * > >::const_iterator i;
1113 map<const indicator_term *, int >::const_iterator j;
1114 std::set<const indicator_term *>::const_iterator k;
1116 for (k = order.head.begin(); k != order.head.end(); ++k)
1117 head.insert(old2new[*k]);
1119 for (j = order.pred.begin(); j != order.pred.end(); ++j)
1120 pred[old2new[(*j).first]] = (*j).second;
1122 for (i = order.lt.begin(); i != order.lt.end(); ++i) {
1123 for (int j = 0; j < (*i).second.size(); ++j)
1124 lt[old2new[(*i).first]].push_back(old2new[(*i).second[j]]);
1126 for (i = order.le.begin(); i != order.le.end(); ++i) {
1127 for (int j = 0; j < (*i).second.size(); ++j)
1128 le[old2new[(*i).first]].push_back(old2new[(*i).second[j]]);
1130 for (i = order.eq.begin(); i != order.eq.end(); ++i) {
1131 for (int j = 0; j < (*i).second.size(); ++j)
1132 eq[old2new[(*i).first]].push_back(old2new[(*i).second[j]]);
1134 for (i = order.pending.begin(); i != order.pending.end(); ++i) {
1135 for (int j = 0; j < (*i).second.size(); ++j)
1136 pending[old2new[(*i).first]].push_back(old2new[(*i).second[j]]);
1140 struct max_term {
1141 EDomain *domain;
1142 vector<evalue *> max;
1144 void print(ostream& os, char **p, barvinok_options *options) const;
1145 void substitute(Matrix *T, barvinok_options *options);
1146 Vector *eval(Value *val, unsigned MaxRays) const;
1148 ~max_term() {
1149 for (int i = 0; i < max.size(); ++i) {
1150 free_evalue_refs(max[i]);
1151 delete max[i];
1153 delete domain;
1158 * Project on first dim dimensions
1160 Polyhedron* Polyhedron_Project_Initial(Polyhedron *P, int dim)
1162 int i;
1163 Matrix *T;
1164 Polyhedron *I;
1166 if (P->Dimension == dim)
1167 return Polyhedron_Copy(P);
1169 T = Matrix_Alloc(dim+1, P->Dimension+1);
1170 for (i = 0; i < dim; ++i)
1171 value_set_si(T->p[i][i], 1);
1172 value_set_si(T->p[dim][P->Dimension], 1);
1173 I = Polyhedron_Image(P, T, P->NbConstraints);
1174 Matrix_Free(T);
1175 return I;
1178 struct indicator {
1179 vector<indicator_term*> term;
1180 indicator_constructor& ic;
1181 partial_order order;
1182 EDomain *D;
1183 Polyhedron *P;
1184 Param_Domain *PD;
1185 barvinok_options *options;
1186 vector<evalue *> substitutions;
1188 indicator(indicator_constructor& ic, Param_Domain *PD, EDomain *D,
1189 barvinok_options *options) :
1190 ic(ic), PD(PD), D(D), order(this), options(options), P(NULL) {}
1191 indicator(const indicator& ind, EDomain *D) :
1192 ic(ind.ic), PD(ind.PD), D(NULL), order(this), options(ind.options),
1193 P(Polyhedron_Copy(ind.P)) {
1194 map< const indicator_term *, indicator_term * > old2new;
1195 for (int i = 0; i < ind.term.size(); ++i) {
1196 indicator_term *it = new indicator_term(*ind.term[i]);
1197 old2new[ind.term[i]] = it;
1198 term.push_back(it);
1200 order.copy(ind.order, old2new);
1201 set_domain(D);
1203 ~indicator() {
1204 for (int i = 0; i < term.size(); ++i)
1205 delete term[i];
1206 if (D)
1207 delete D;
1208 if (P)
1209 Polyhedron_Free(P);
1212 void set_domain(EDomain *D) {
1213 order.cache.clear_transients();
1214 if (this->D)
1215 delete this->D;
1216 this->D = D;
1217 int nparam = ic.P->Dimension - ic.vertex.length();
1218 if (options->lexmin_reduce) {
1219 Polyhedron *Q = Polyhedron_Project_Initial(D->D, nparam);
1220 Q = DomainConstraintSimplify(Q, options->MaxRays);
1221 if (!P || !PolyhedronIncludes(Q, P))
1222 reduce_in_domain(Q);
1223 if (P)
1224 Polyhedron_Free(P);
1225 P = Q;
1226 order.resort();
1230 void add(const indicator_term* it);
1231 void remove(const indicator_term* it);
1232 void remove_initial_rational_vertices();
1233 void expand_rational_vertex(const indicator_term *initial);
1235 void print(ostream& os, char **p);
1236 void simplify();
1237 void peel(int i, int j);
1238 void combine(const indicator_term *a, const indicator_term *b);
1239 void add_substitution(evalue *equation);
1240 void perform_pending_substitutions();
1241 void reduce_in_domain(Polyhedron *D);
1242 bool handle_equal_numerators(const indicator_term *base);
1244 max_term* create_max_term(const indicator_term *it);
1245 private:
1246 void substitute(evalue *equation);
1249 void partial_order::sanity_check() const
1251 map<const indicator_term *, vector<const indicator_term * > >::const_iterator i;
1252 map<const indicator_term *, vector<const indicator_term * > >::const_iterator prev;
1253 map<const indicator_term *, vector<const indicator_term * > >::const_iterator l;
1254 map<const indicator_term *, int >::const_iterator k, prev_k;
1256 for (k = pred.begin(); k != pred.end(); prev_k = k, ++k)
1257 if (k != pred.begin())
1258 assert(pred.key_comp()((*prev_k).first, (*k).first));
1259 for (i = lt.begin(); i != lt.end(); prev = i, ++i) {
1260 vec_ZZ i_v;
1261 if (ind->D->sample)
1262 i_v = (*i).first->eval(ind->D->sample->p);
1263 if (i != lt.begin())
1264 assert(lt.key_comp()((*prev).first, (*i).first));
1265 l = eq.find((*i).first);
1266 if (l != eq.end())
1267 assert((*l).second.size() > 1);
1268 assert(head.find((*i).first) != head.end() ||
1269 pred.find((*i).first) != pred.end());
1270 for (int j = 0; j < (*i).second.size(); ++j) {
1271 k = pred.find((*i).second[j]);
1272 assert(k != pred.end());
1273 assert((*k).second != 0);
1274 if ((*i).first->sign != 0 &&
1275 (*i).second[j]->sign != 0 && ind->D->sample) {
1276 vec_ZZ j_v = (*i).second[j]->eval(ind->D->sample->p);
1277 assert(lex_cmp(i_v, j_v) < 0);
1281 for (i = le.begin(); i != le.end(); ++i) {
1282 assert((*i).second.size() > 0);
1283 assert(head.find((*i).first) != head.end() ||
1284 pred.find((*i).first) != pred.end());
1285 for (int j = 0; j < (*i).second.size(); ++j) {
1286 k = pred.find((*i).second[j]);
1287 assert(k != pred.end());
1288 assert((*k).second != 0);
1291 for (i = eq.begin(); i != eq.end(); ++i) {
1292 assert(head.find((*i).first) != head.end() ||
1293 pred.find((*i).first) != pred.end());
1294 assert((*i).second.size() >= 1);
1296 for (i = pending.begin(); i != pending.end(); ++i) {
1297 assert(head.find((*i).first) != head.end() ||
1298 pred.find((*i).first) != pred.end());
1299 for (int j = 0; j < (*i).second.size(); ++j)
1300 assert(head.find((*i).second[j]) != head.end() ||
1301 pred.find((*i).second[j]) != pred.end());
1305 max_term* indicator::create_max_term(const indicator_term *it)
1307 int dim = it->den.NumCols();
1308 int nparam = ic.P->Dimension - ic.vertex.length();
1309 max_term *maximum = new max_term;
1310 maximum->domain = new EDomain(D);
1311 for (int j = 0; j < dim; ++j) {
1312 evalue *E = new evalue;
1313 value_init(E->d);
1314 evalue_copy(E, it->vertex[j]);
1315 if (evalue_frac2floor_in_domain3(E, D->D, 0))
1316 reduce_evalue(E);
1317 maximum->max.push_back(E);
1319 return maximum;
1322 static order_sign evalue_sign(evalue *diff, EDomain *D, barvinok_options *options)
1324 order_sign sign = order_eq;
1325 evalue mone;
1326 value_init(mone.d);
1327 evalue_set_si(&mone, -1, 1);
1328 int len = 1 + D->D->Dimension + 1;
1329 Vector *c = Vector_Alloc(len);
1330 Matrix *T = Matrix_Alloc(2, len-1);
1332 int fract = evalue2constraint(D, diff, c->p, len);
1333 Vector_Copy(c->p+1, T->p[0], len-1);
1334 value_assign(T->p[1][len-2], c->p[0]);
1336 order_sign upper_sign = polyhedron_affine_sign(D->D, T, options);
1337 if (upper_sign == order_lt || !fract)
1338 sign = upper_sign;
1339 else {
1340 emul(&mone, diff);
1341 evalue2constraint(D, diff, c->p, len);
1342 emul(&mone, diff);
1343 Vector_Copy(c->p+1, T->p[0], len-1);
1344 value_assign(T->p[1][len-2], c->p[0]);
1346 order_sign neg_lower_sign = polyhedron_affine_sign(D->D, T, options);
1348 if (neg_lower_sign == order_lt)
1349 sign = order_gt;
1350 else if (neg_lower_sign == order_eq || neg_lower_sign == order_le) {
1351 if (upper_sign == order_eq || upper_sign == order_le)
1352 sign = order_eq;
1353 else
1354 sign = order_ge;
1355 } else {
1356 if (upper_sign == order_lt || upper_sign == order_le ||
1357 upper_sign == order_eq)
1358 sign = order_le;
1359 else
1360 sign = order_unknown;
1364 Matrix_Free(T);
1365 Vector_Free(c);
1366 free_evalue_refs(&mone);
1368 return sign;
1371 /* An auxiliary class that keeps a reference to an evalue
1372 * and frees it when it goes out of scope.
1374 struct temp_evalue {
1375 evalue *E;
1376 temp_evalue() : E(NULL) {}
1377 temp_evalue(evalue *e) : E(e) {}
1378 operator evalue* () const { return E; }
1379 evalue *operator=(evalue *e) {
1380 if (E) {
1381 free_evalue_refs(E);
1382 delete E;
1384 E = e;
1385 return E;
1387 ~temp_evalue() {
1388 if (E) {
1389 free_evalue_refs(E);
1390 delete E;
1395 static void substitute(vector<indicator_term*>& term, evalue *equation)
1397 evalue *fract = NULL;
1398 evalue *val = new evalue;
1399 value_init(val->d);
1400 evalue_copy(val, equation);
1402 evalue factor;
1403 value_init(factor.d);
1404 value_init(factor.x.n);
1406 evalue *e;
1407 for (e = val; value_zero_p(e->d) && e->x.p->type != fractional;
1408 e = &e->x.p->arr[type_offset(e->x.p)])
1411 if (value_zero_p(e->d) && e->x.p->type == fractional)
1412 fract = &e->x.p->arr[0];
1413 else {
1414 for (e = val; value_zero_p(e->d) && e->x.p->type != polynomial;
1415 e = &e->x.p->arr[type_offset(e->x.p)])
1417 assert(value_zero_p(e->d) && e->x.p->type == polynomial);
1420 int offset = type_offset(e->x.p);
1422 assert(value_notzero_p(e->x.p->arr[offset+1].d));
1423 assert(value_notzero_p(e->x.p->arr[offset+1].x.n));
1424 if (value_neg_p(e->x.p->arr[offset+1].x.n)) {
1425 value_oppose(factor.d, e->x.p->arr[offset+1].x.n);
1426 value_assign(factor.x.n, e->x.p->arr[offset+1].d);
1427 } else {
1428 value_assign(factor.d, e->x.p->arr[offset+1].x.n);
1429 value_oppose(factor.x.n, e->x.p->arr[offset+1].d);
1432 free_evalue_refs(&e->x.p->arr[offset+1]);
1433 enode *p = e->x.p;
1434 value_clear(e->d);
1435 *e = e->x.p->arr[offset];
1437 emul(&factor, val);
1439 if (fract) {
1440 for (int i = 0; i < term.size(); ++i)
1441 term[i]->substitute(fract, val);
1443 free_evalue_refs(&p->arr[0]);
1444 } else {
1445 for (int i = 0; i < term.size(); ++i)
1446 term[i]->substitute(p->pos, val);
1449 free_evalue_refs(&factor);
1450 free_evalue_refs(val);
1451 delete val;
1453 free(p);
1456 order_sign partial_order::compare(const indicator_term *a, const indicator_term *b)
1458 unsigned dim = a->den.NumCols();
1459 order_sign sign = order_eq;
1460 EDomain *D = ind->D;
1461 unsigned MaxRays = ind->options->MaxRays;
1462 bool rational = a->sign == 0 || b->sign == 0;
1464 order_sign cached_sign = order_eq;
1465 for (int k = 0; k < dim; ++k) {
1466 cached_sign = evalue_diff_constant_sign(a->vertex[k], b->vertex[k]);
1467 if (cached_sign != order_eq)
1468 break;
1470 if (cached_sign != order_undefined)
1471 return cached_sign;
1473 order_cache_el cache_el;
1474 cached_sign = order_undefined;
1475 if (!rational)
1476 cached_sign = cache.check(a, b, cache_el);
1477 if (cached_sign != order_undefined) {
1478 cache_el.free();
1479 return cached_sign;
1482 if (rational && POL_ISSET(ind->options->MaxRays, POL_INTEGER)) {
1483 ind->options->MaxRays &= ~POL_INTEGER;
1484 if (ind->options->MaxRays)
1485 ind->options->MaxRays |= POL_HIGH_BIT;
1488 sign = order_eq;
1490 vector<indicator_term *> term;
1492 for (int k = 0; k < dim; ++k) {
1493 /* compute a->vertex[k] - b->vertex[k] */
1494 evalue *diff;
1495 if (cache_el.e.size() <= k) {
1496 diff = ediff(a->vertex[k], b->vertex[k]);
1497 cache_el.e.push_back(diff);
1498 } else
1499 diff = cache_el.e[k];
1500 temp_evalue tdiff;
1501 if (term.size())
1502 tdiff = diff = ediff(term[0]->vertex[k], term[1]->vertex[k]);
1503 order_sign diff_sign;
1504 if (!D)
1505 diff_sign = order_undefined;
1506 else if (eequal(a->vertex[k], b->vertex[k]))
1507 diff_sign = order_eq;
1508 else
1509 diff_sign = evalue_sign(diff, D, ind->options);
1511 if (diff_sign == order_undefined) {
1512 assert(sign == order_le || sign == order_ge);
1513 if (sign == order_le)
1514 sign = order_lt;
1515 else
1516 sign = order_gt;
1517 break;
1519 if (diff_sign == order_lt) {
1520 if (sign == order_eq || sign == order_le)
1521 sign = order_lt;
1522 else
1523 sign = order_unknown;
1524 break;
1526 if (diff_sign == order_gt) {
1527 if (sign == order_eq || sign == order_ge)
1528 sign = order_gt;
1529 else
1530 sign = order_unknown;
1531 break;
1533 if (diff_sign == order_eq) {
1534 if (D == ind->D && term.size() == 0 && !rational &&
1535 !EVALUE_IS_ZERO(*diff))
1536 ind->add_substitution(diff);
1537 continue;
1539 if ((diff_sign == order_unknown) ||
1540 ((diff_sign == order_lt || diff_sign == order_le) && sign == order_ge) ||
1541 ((diff_sign == order_gt || diff_sign == order_ge) && sign == order_le)) {
1542 sign = order_unknown;
1543 break;
1546 sign = diff_sign;
1548 if (!term.size()) {
1549 term.push_back(new indicator_term(*a));
1550 term.push_back(new indicator_term(*b));
1552 substitute(term, diff);
1555 if (!rational)
1556 cache.add(cache_el, sign);
1557 else
1558 cache_el.free();
1560 if (D && D != ind->D)
1561 delete D;
1563 if (term.size()) {
1564 delete term[0];
1565 delete term[1];
1568 ind->options->MaxRays = MaxRays;
1569 return sign;
1572 bool partial_order::compared(const indicator_term* a, const indicator_term* b)
1574 map<const indicator_term *, vector<const indicator_term * > >::iterator j;
1576 j = lt.find(a);
1577 if (j != lt.end() && find(lt[a].begin(), lt[a].end(), b) != lt[a].end())
1578 return true;
1580 j = le.find(a);
1581 if (j != le.end() && find(le[a].begin(), le[a].end(), b) != le[a].end())
1582 return true;
1584 return false;
1587 void partial_order::add(const indicator_term* it,
1588 std::set<const indicator_term *> *filter)
1590 if (eq.find(it) != eq.end() && eq[it].size() == 1)
1591 return;
1593 typeof(head) head_copy(head);
1595 if (!filter)
1596 head.insert(it);
1598 std::set<const indicator_term *>::iterator i;
1599 for (i = head_copy.begin(); i != head_copy.end(); ++i) {
1600 if (*i == it)
1601 continue;
1602 if (eq.find(*i) != eq.end() && eq[*i].size() == 1)
1603 continue;
1604 if (filter) {
1605 if (filter->find(*i) == filter->end())
1606 continue;
1607 if (compared(*i, it))
1608 continue;
1610 order_sign sign = compare(it, *i);
1611 if (sign == order_lt) {
1612 lt[it].push_back(*i);
1613 inc_pred(*i);
1614 } else if (sign == order_le) {
1615 le[it].push_back(*i);
1616 inc_pred(*i);
1617 } else if (sign == order_eq) {
1618 set_equal(it, *i);
1619 return;
1620 } else if (sign == order_gt) {
1621 pending[*i].push_back(it);
1622 lt[*i].push_back(it);
1623 inc_pred(it);
1624 } else if (sign == order_ge) {
1625 pending[*i].push_back(it);
1626 le[*i].push_back(it);
1627 inc_pred(it);
1632 void partial_order::remove(const indicator_term* it)
1634 std::set<const indicator_term *> filter;
1635 map<const indicator_term *, vector<const indicator_term * > >::iterator i;
1637 assert(head.find(it) != head.end());
1639 i = eq.find(it);
1640 if (i != eq.end()) {
1641 assert(eq[it].size() >= 1);
1642 const indicator_term *base;
1643 if (eq[it].size() == 1) {
1644 base = eq[it][0];
1645 eq.erase(it);
1647 vector<const indicator_term * >::iterator j;
1648 j = find(eq[base].begin(), eq[base].end(), it);
1649 assert(j != eq[base].end());
1650 eq[base].erase(j);
1651 } else {
1652 /* "it" may no longer be the smallest, since the order
1653 * structure may have been copied from another one.
1655 sort(eq[it].begin()+1, eq[it].end(), pred.key_comp());
1656 assert(eq[it][0] == it);
1657 eq[it].erase(eq[it].begin());
1658 base = eq[it][0];
1659 eq[base] = eq[it];
1660 eq.erase(it);
1662 for (int j = 1; j < eq[base].size(); ++j)
1663 eq[eq[base][j]][0] = base;
1665 i = lt.find(it);
1666 if (i != lt.end()) {
1667 lt[base] = lt[it];
1668 lt.erase(it);
1671 i = le.find(it);
1672 if (i != le.end()) {
1673 le[base] = le[it];
1674 le.erase(it);
1677 i = pending.find(it);
1678 if (i != pending.end()) {
1679 pending[base] = pending[it];
1680 pending.erase(it);
1684 if (eq[base].size() == 1)
1685 eq.erase(base);
1687 head.erase(it);
1689 return;
1692 i = lt.find(it);
1693 if (i != lt.end()) {
1694 for (int j = 0; j < lt[it].size(); ++j) {
1695 filter.insert(lt[it][j]);
1696 dec_pred(lt[it][j]);
1698 lt.erase(it);
1701 i = le.find(it);
1702 if (i != le.end()) {
1703 for (int j = 0; j < le[it].size(); ++j) {
1704 filter.insert(le[it][j]);
1705 dec_pred(le[it][j]);
1707 le.erase(it);
1710 head.erase(it);
1712 i = pending.find(it);
1713 if (i != pending.end()) {
1714 vector<const indicator_term *> it_pending = pending[it];
1715 pending.erase(it);
1716 for (int j = 0; j < it_pending.size(); ++j) {
1717 filter.erase(it_pending[j]);
1718 add(it_pending[j], &filter);
1723 void partial_order::print(ostream& os, char **p)
1725 map<const indicator_term *, vector<const indicator_term * > >::iterator i;
1726 map<const indicator_term *, int >::iterator j;
1727 std::set<const indicator_term *>::iterator k;
1728 for (k = head.begin(); k != head.end(); ++k) {
1729 (*k)->print(os, p);
1730 os << endl;
1732 for (j = pred.begin(); j != pred.end(); ++j) {
1733 (*j).first->print(os, p);
1734 os << ": " << (*j).second << endl;
1736 for (i = lt.begin(); i != lt.end(); ++i) {
1737 (*i).first->print(os, p);
1738 assert(head.find((*i).first) != head.end() ||
1739 pred.find((*i).first) != pred.end());
1740 if (pred.find((*i).first) != pred.end())
1741 os << "(" << pred[(*i).first] << ")";
1742 os << " < ";
1743 for (int j = 0; j < (*i).second.size(); ++j) {
1744 if (j)
1745 os << ", ";
1746 (*i).second[j]->print(os, p);
1747 assert(pred.find((*i).second[j]) != pred.end());
1748 os << "(" << pred[(*i).second[j]] << ")";
1750 os << endl;
1752 for (i = le.begin(); i != le.end(); ++i) {
1753 (*i).first->print(os, p);
1754 assert(head.find((*i).first) != head.end() ||
1755 pred.find((*i).first) != pred.end());
1756 if (pred.find((*i).first) != pred.end())
1757 os << "(" << pred[(*i).first] << ")";
1758 os << " <= ";
1759 for (int j = 0; j < (*i).second.size(); ++j) {
1760 if (j)
1761 os << ", ";
1762 (*i).second[j]->print(os, p);
1763 assert(pred.find((*i).second[j]) != pred.end());
1764 os << "(" << pred[(*i).second[j]] << ")";
1766 os << endl;
1768 for (i = eq.begin(); i != eq.end(); ++i) {
1769 if ((*i).second.size() <= 1)
1770 continue;
1771 (*i).first->print(os, p);
1772 assert(head.find((*i).first) != head.end() ||
1773 pred.find((*i).first) != pred.end());
1774 if (pred.find((*i).first) != pred.end())
1775 os << "(" << pred[(*i).first] << ")";
1776 for (int j = 1; j < (*i).second.size(); ++j) {
1777 if (j)
1778 os << " = ";
1779 (*i).second[j]->print(os, p);
1780 assert(head.find((*i).second[j]) != head.end() ||
1781 pred.find((*i).second[j]) != pred.end());
1782 if (pred.find((*i).second[j]) != pred.end())
1783 os << "(" << pred[(*i).second[j]] << ")";
1785 os << endl;
1787 for (i = pending.begin(); i != pending.end(); ++i) {
1788 os << "pending on ";
1789 (*i).first->print(os, p);
1790 assert(head.find((*i).first) != head.end() ||
1791 pred.find((*i).first) != pred.end());
1792 if (pred.find((*i).first) != pred.end())
1793 os << "(" << pred[(*i).first] << ")";
1794 os << ": ";
1795 for (int j = 0; j < (*i).second.size(); ++j) {
1796 if (j)
1797 os << ", ";
1798 (*i).second[j]->print(os, p);
1799 assert(pred.find((*i).second[j]) != pred.end());
1800 os << "(" << pred[(*i).second[j]] << ")";
1802 os << endl;
1806 void indicator::add(const indicator_term* it)
1808 indicator_term *nt = new indicator_term(*it);
1809 if (options->lexmin_reduce)
1810 nt->reduce_in_domain(P ? P : D->D);
1811 term.push_back(nt);
1812 order.add(nt, NULL);
1813 assert(term.size() == order.head.size() + order.pred.size());
1816 void indicator::remove(const indicator_term* it)
1818 vector<indicator_term *>::iterator i;
1819 i = find(term.begin(), term.end(), it);
1820 assert(i!= term.end());
1821 order.remove(it);
1822 term.erase(i);
1823 assert(term.size() == order.head.size() + order.pred.size());
1824 delete it;
1827 void indicator::expand_rational_vertex(const indicator_term *initial)
1829 int pos = initial->pos;
1830 remove(initial);
1831 if (ic.terms[pos].size() == 0) {
1832 Param_Vertices *V;
1833 FORALL_PVertex_in_ParamPolyhedron(V, PD, ic.PP) // _i is internal counter
1834 if (_i == pos) {
1835 ic.decompose_at_vertex(V, pos, options);
1836 break;
1838 END_FORALL_PVertex_in_ParamPolyhedron;
1840 for (int j = 0; j < ic.terms[pos].size(); ++j)
1841 add(ic.terms[pos][j]);
1844 void indicator::remove_initial_rational_vertices()
1846 do {
1847 const indicator_term *initial = NULL;
1848 std::set<const indicator_term *>::iterator i;
1849 for (i = order.head.begin(); i != order.head.end(); ++i) {
1850 if ((*i)->sign != 0)
1851 continue;
1852 if (order.eq.find(*i) != order.eq.end() && order.eq[*i].size() <= 1)
1853 continue;
1854 initial = *i;
1855 break;
1857 if (!initial)
1858 break;
1859 expand_rational_vertex(initial);
1860 } while(1);
1863 void indicator::reduce_in_domain(Polyhedron *D)
1865 for (int i = 0; i < term.size(); ++i)
1866 term[i]->reduce_in_domain(D);
1869 void indicator::print(ostream& os, char **p)
1871 assert(term.size() == order.head.size() + order.pred.size());
1872 for (int i = 0; i < term.size(); ++i) {
1873 term[i]->print(os, p);
1874 if (D->sample) {
1875 os << ": " << term[i]->eval(D->sample->p);
1877 os << endl;
1879 order.print(os, p);
1882 /* Remove pairs of opposite terms */
1883 void indicator::simplify()
1885 for (int i = 0; i < term.size(); ++i) {
1886 for (int j = i+1; j < term.size(); ++j) {
1887 if (term[i]->sign + term[j]->sign != 0)
1888 continue;
1889 if (term[i]->den != term[j]->den)
1890 continue;
1891 int k;
1892 for (k = 0; k < term[i]->den.NumCols(); ++k)
1893 if (!eequal(term[i]->vertex[k], term[j]->vertex[k]))
1894 break;
1895 if (k < term[i]->den.NumCols())
1896 continue;
1897 delete term[i];
1898 delete term[j];
1899 term.erase(term.begin()+j);
1900 term.erase(term.begin()+i);
1901 --i;
1902 break;
1907 void indicator::peel(int i, int j)
1909 if (j < i) {
1910 int tmp = i;
1911 i = j;
1912 j = tmp;
1914 assert (i < j);
1915 int dim = term[i]->den.NumCols();
1917 mat_ZZ common;
1918 mat_ZZ rest_i;
1919 mat_ZZ rest_j;
1920 int n_common = 0, n_i = 0, n_j = 0;
1922 common.SetDims(min(term[i]->den.NumRows(), term[j]->den.NumRows()), dim);
1923 rest_i.SetDims(term[i]->den.NumRows(), dim);
1924 rest_j.SetDims(term[j]->den.NumRows(), dim);
1926 int k, l;
1927 for (k = 0, l = 0; k < term[i]->den.NumRows() && l < term[j]->den.NumRows(); ) {
1928 int s = lex_cmp(term[i]->den[k], term[j]->den[l]);
1929 if (s == 0) {
1930 common[n_common++] = term[i]->den[k];
1931 ++k;
1932 ++l;
1933 } else if (s < 0)
1934 rest_i[n_i++] = term[i]->den[k++];
1935 else
1936 rest_j[n_j++] = term[j]->den[l++];
1938 while (k < term[i]->den.NumRows())
1939 rest_i[n_i++] = term[i]->den[k++];
1940 while (l < term[j]->den.NumRows())
1941 rest_j[n_j++] = term[j]->den[l++];
1942 common.SetDims(n_common, dim);
1943 rest_i.SetDims(n_i, dim);
1944 rest_j.SetDims(n_j, dim);
1946 for (k = 0; k <= n_i; ++k) {
1947 indicator_term *it = new indicator_term(*term[i]);
1948 it->den.SetDims(n_common + k, dim);
1949 for (l = 0; l < n_common; ++l)
1950 it->den[l] = common[l];
1951 for (l = 0; l < k; ++l)
1952 it->den[n_common+l] = rest_i[l];
1953 lex_order_rows(it->den);
1954 if (k)
1955 for (l = 0; l < dim; ++l)
1956 evalue_add_constant(it->vertex[l], rest_i[k-1][l]);
1957 term.push_back(it);
1960 for (k = 0; k <= n_j; ++k) {
1961 indicator_term *it = new indicator_term(*term[j]);
1962 it->den.SetDims(n_common + k, dim);
1963 for (l = 0; l < n_common; ++l)
1964 it->den[l] = common[l];
1965 for (l = 0; l < k; ++l)
1966 it->den[n_common+l] = rest_j[l];
1967 lex_order_rows(it->den);
1968 if (k)
1969 for (l = 0; l < dim; ++l)
1970 evalue_add_constant(it->vertex[l], rest_j[k-1][l]);
1971 term.push_back(it);
1973 term.erase(term.begin()+j);
1974 term.erase(term.begin()+i);
1977 void indicator::combine(const indicator_term *a, const indicator_term *b)
1979 int dim = a->den.NumCols();
1981 mat_ZZ common;
1982 mat_ZZ rest_i; /* factors in a, but not in b */
1983 mat_ZZ rest_j; /* factors in b, but not in a */
1984 int n_common = 0, n_i = 0, n_j = 0;
1986 common.SetDims(min(a->den.NumRows(), b->den.NumRows()), dim);
1987 rest_i.SetDims(a->den.NumRows(), dim);
1988 rest_j.SetDims(b->den.NumRows(), dim);
1990 int k, l;
1991 for (k = 0, l = 0; k < a->den.NumRows() && l < b->den.NumRows(); ) {
1992 int s = lex_cmp(a->den[k], b->den[l]);
1993 if (s == 0) {
1994 common[n_common++] = a->den[k];
1995 ++k;
1996 ++l;
1997 } else if (s < 0)
1998 rest_i[n_i++] = a->den[k++];
1999 else
2000 rest_j[n_j++] = b->den[l++];
2002 while (k < a->den.NumRows())
2003 rest_i[n_i++] = a->den[k++];
2004 while (l < b->den.NumRows())
2005 rest_j[n_j++] = b->den[l++];
2006 common.SetDims(n_common, dim);
2007 rest_i.SetDims(n_i, dim);
2008 rest_j.SetDims(n_j, dim);
2010 assert(order.eq[a].size() > 1);
2011 indicator_term *prev;
2013 prev = NULL;
2014 for (int k = n_i-1; k >= 0; --k) {
2015 indicator_term *it = new indicator_term(*b);
2016 it->den.SetDims(n_common + n_j + n_i-k, dim);
2017 for (int l = k; l < n_i; ++l)
2018 it->den[n_common+n_j+l-k] = rest_i[l];
2019 lex_order_rows(it->den);
2020 for (int m = 0; m < dim; ++m)
2021 evalue_add_constant(it->vertex[m], rest_i[k][m]);
2022 it->sign = -it->sign;
2023 if (prev) {
2024 order.pending[it].push_back(prev);
2025 order.lt[it].push_back(prev);
2026 order.inc_pred(prev);
2028 term.push_back(it);
2029 order.head.insert(it);
2030 prev = it;
2032 if (n_i) {
2033 indicator_term *it = new indicator_term(*b);
2034 it->den.SetDims(n_common + n_i + n_j, dim);
2035 for (l = 0; l < n_i; ++l)
2036 it->den[n_common+n_j+l] = rest_i[l];
2037 lex_order_rows(it->den);
2038 assert(prev);
2039 order.pending[a].push_back(prev);
2040 order.lt[a].push_back(prev);
2041 order.inc_pred(prev);
2042 order.replace(b, it);
2043 delete it;
2046 prev = NULL;
2047 for (int k = n_j-1; k >= 0; --k) {
2048 indicator_term *it = new indicator_term(*a);
2049 it->den.SetDims(n_common + n_i + n_j-k, dim);
2050 for (int l = k; l < n_j; ++l)
2051 it->den[n_common+n_i+l-k] = rest_j[l];
2052 lex_order_rows(it->den);
2053 for (int m = 0; m < dim; ++m)
2054 evalue_add_constant(it->vertex[m], rest_j[k][m]);
2055 it->sign = -it->sign;
2056 if (prev) {
2057 order.pending[it].push_back(prev);
2058 order.lt[it].push_back(prev);
2059 order.inc_pred(prev);
2061 term.push_back(it);
2062 order.head.insert(it);
2063 prev = it;
2065 if (n_j) {
2066 indicator_term *it = new indicator_term(*a);
2067 it->den.SetDims(n_common + n_i + n_j, dim);
2068 for (l = 0; l < n_j; ++l)
2069 it->den[n_common+n_i+l] = rest_j[l];
2070 lex_order_rows(it->den);
2071 assert(prev);
2072 order.pending[a].push_back(prev);
2073 order.lt[a].push_back(prev);
2074 order.inc_pred(prev);
2075 order.replace(a, it);
2076 delete it;
2079 assert(term.size() == order.head.size() + order.pred.size());
2082 bool indicator::handle_equal_numerators(const indicator_term *base)
2084 for (int i = 0; i < order.eq[base].size(); ++i) {
2085 for (int j = i+1; j < order.eq[base].size(); ++j) {
2086 if (order.eq[base][i]->is_opposite(order.eq[base][j])) {
2087 remove(order.eq[base][j]);
2088 remove(i ? order.eq[base][i] : base);
2089 return true;
2093 for (int j = 1; j < order.eq[base].size(); ++j)
2094 if (order.eq[base][j]->sign != base->sign) {
2095 combine(base, order.eq[base][j]);
2096 return true;
2098 return false;
2101 void indicator::substitute(evalue *equation)
2103 ::substitute(term, equation);
2106 void indicator::add_substitution(evalue *equation)
2108 for (int i = 0; i < substitutions.size(); ++i)
2109 if (eequal(substitutions[i], equation))
2110 return;
2111 evalue *copy = new evalue();
2112 value_init(copy->d);
2113 evalue_copy(copy, equation);
2114 substitutions.push_back(copy);
2117 void indicator::perform_pending_substitutions()
2119 if (substitutions.size() == 0)
2120 return;
2122 for (int i = 0; i < substitutions.size(); ++i) {
2123 substitute(substitutions[i]);
2124 free_evalue_refs(substitutions[i]);
2125 delete substitutions[i];
2127 substitutions.clear();
2128 order.resort();
2131 static void print_varlist(ostream& os, int n, char **names)
2133 int i;
2134 os << "[";
2135 for (i = 0; i < n; ++i) {
2136 if (i)
2137 os << ",";
2138 os << names[i];
2140 os << "]";
2143 void max_term::print(ostream& os, char **p, barvinok_options *options) const
2145 os << "{ ";
2146 print_varlist(os, domain->dimension(), p);
2147 os << " -> ";
2148 os << "[";
2149 for (int i = 0; i < max.size(); ++i) {
2150 if (i)
2151 os << ",";
2152 evalue_print(os, max[i], p);
2154 os << "]";
2155 os << " : ";
2156 domain->print_constraints(os, p, options);
2157 os << " }" << endl;
2160 Matrix *left_inverse(Matrix *M, Matrix **Eq)
2162 int i, ok;
2163 Matrix *L, *H, *Q, *U, *ratH, *invH, *Ut, *inv;
2164 Vector *t;
2166 if (Eq)
2167 *Eq = NULL;
2168 L = Matrix_Alloc(M->NbRows-1, M->NbColumns-1);
2169 for (i = 0; i < L->NbRows; ++i)
2170 Vector_Copy(M->p[i], L->p[i], L->NbColumns);
2171 right_hermite(L, &H, &U, &Q);
2172 Matrix_Free(L);
2173 Matrix_Free(Q);
2174 t = Vector_Alloc(U->NbColumns);
2175 for (i = 0; i < U->NbColumns; ++i)
2176 value_oppose(t->p[i], M->p[i][M->NbColumns-1]);
2177 if (Eq) {
2178 *Eq = Matrix_Alloc(H->NbRows - H->NbColumns, 2 + U->NbColumns);
2179 for (i = 0; i < H->NbRows - H->NbColumns; ++i) {
2180 Vector_Copy(U->p[H->NbColumns+i], (*Eq)->p[i]+1, U->NbColumns);
2181 Inner_Product(U->p[H->NbColumns+i], t->p, U->NbColumns,
2182 (*Eq)->p[i]+1+U->NbColumns);
2185 ratH = Matrix_Alloc(H->NbColumns+1, H->NbColumns+1);
2186 invH = Matrix_Alloc(H->NbColumns+1, H->NbColumns+1);
2187 for (i = 0; i < H->NbColumns; ++i)
2188 Vector_Copy(H->p[i], ratH->p[i], H->NbColumns);
2189 value_set_si(ratH->p[ratH->NbRows-1][ratH->NbColumns-1], 1);
2190 Matrix_Free(H);
2191 ok = Matrix_Inverse(ratH, invH);
2192 assert(ok);
2193 Matrix_Free(ratH);
2194 Ut = Matrix_Alloc(invH->NbRows, U->NbColumns+1);
2195 for (i = 0; i < Ut->NbRows-1; ++i) {
2196 Vector_Copy(U->p[i], Ut->p[i], U->NbColumns);
2197 Inner_Product(U->p[i], t->p, U->NbColumns, &Ut->p[i][Ut->NbColumns-1]);
2199 Matrix_Free(U);
2200 Vector_Free(t);
2201 value_set_si(Ut->p[Ut->NbRows-1][Ut->NbColumns-1], 1);
2202 inv = Matrix_Alloc(invH->NbRows, Ut->NbColumns);
2203 Matrix_Product(invH, Ut, inv);
2204 Matrix_Free(Ut);
2205 Matrix_Free(invH);
2206 return inv;
2209 /* T maps the compressed parameters to the original parameters,
2210 * while this max_term is based on the compressed parameters
2211 * and we want get the original parameters back.
2213 void max_term::substitute(Matrix *T, barvinok_options *options)
2215 assert(domain->dimension() == T->NbColumns-1);
2216 int nexist = domain->D->Dimension - (T->NbColumns-1);
2217 Matrix *Eq;
2218 Matrix *inv = left_inverse(T, &Eq);
2220 evalue denom;
2221 value_init(denom.d);
2222 value_init(denom.x.n);
2223 value_set_si(denom.x.n, 1);
2224 value_assign(denom.d, inv->p[inv->NbRows-1][inv->NbColumns-1]);
2226 vec_ZZ v;
2227 v.SetLength(inv->NbColumns);
2228 evalue* subs[inv->NbRows-1];
2229 for (int i = 0; i < inv->NbRows-1; ++i) {
2230 values2zz(inv->p[i], v, v.length());
2231 subs[i] = multi_monom(v);
2232 emul(&denom, subs[i]);
2234 free_evalue_refs(&denom);
2236 domain->substitute(subs, inv, Eq, options->MaxRays);
2237 Matrix_Free(Eq);
2239 for (int i = 0; i < max.size(); ++i) {
2240 evalue_substitute(max[i], subs);
2241 reduce_evalue(max[i]);
2244 for (int i = 0; i < inv->NbRows-1; ++i) {
2245 free_evalue_refs(subs[i]);
2246 delete subs[i];
2248 Matrix_Free(inv);
2251 int Last_Non_Zero(Value *p, unsigned len)
2253 for (int i = len-1; i >= 0; --i)
2254 if (value_notzero_p(p[i]))
2255 return i;
2256 return -1;
2259 static void SwapColumns(Value **V, int n, int i, int j)
2261 for (int r = 0; r < n; ++r)
2262 value_swap(V[r][i], V[r][j]);
2265 static void SwapColumns(Polyhedron *P, int i, int j)
2267 SwapColumns(P->Constraint, P->NbConstraints, i, j);
2268 SwapColumns(P->Ray, P->NbRays, i, j);
2271 Vector *max_term::eval(Value *val, unsigned MaxRays) const
2273 if (!domain->contains(val, domain->dimension()))
2274 return NULL;
2275 Vector *res = Vector_Alloc(max.size());
2276 for (int i = 0; i < max.size(); ++i) {
2277 compute_evalue(max[i], val, &res->p[i]);
2279 return res;
2282 struct split {
2283 evalue *constraint;
2284 enum sign { le, ge, lge } sign;
2286 split (evalue *c, enum sign s) : constraint(c), sign(s) {}
2289 static void split_on(const split& sp, EDomain *D,
2290 EDomain **Dlt, EDomain **Deq, EDomain **Dgt,
2291 barvinok_options *options)
2293 EDomain *ED[3];
2294 *Dlt = NULL;
2295 *Deq = NULL;
2296 *Dgt = NULL;
2297 ge_constraint *ge = D->compute_ge_constraint(sp.constraint);
2298 if (sp.sign == split::lge || sp.sign == split::ge)
2299 ED[2] = EDomain::new_from_ge_constraint(ge, 1, options);
2300 else
2301 ED[2] = NULL;
2302 if (sp.sign == split::lge || sp.sign == split::le)
2303 ED[0] = EDomain::new_from_ge_constraint(ge, -1, options);
2304 else
2305 ED[0] = NULL;
2307 assert(sp.sign == split::lge || sp.sign == split::ge || sp.sign == split::le);
2308 ED[1] = EDomain::new_from_ge_constraint(ge, 0, options);
2310 delete ge;
2312 for (int i = 0; i < 3; ++i) {
2313 if (!ED[i])
2314 continue;
2315 if (D->sample && ED[i]->contains(D->sample->p, D->sample->Size-1)) {
2316 ED[i]->sample = Vector_Alloc(D->sample->Size);
2317 Vector_Copy(D->sample->p, ED[i]->sample->p, D->sample->Size);
2318 } else if (emptyQ2(ED[i]->D) ||
2319 (options->lexmin_emptiness_check != BV_LEXMIN_EMPTINESS_CHECK_NONE &&
2320 !(ED[i]->not_empty(options)))) {
2321 delete ED[i];
2322 ED[i] = NULL;
2325 *Dlt = ED[0];
2326 *Deq = ED[1];
2327 *Dgt = ED[2];
2330 ostream & operator<< (ostream & os, const vector<int> & v)
2332 os << "[";
2333 for (int i = 0; i < v.size(); ++i) {
2334 if (i)
2335 os << ", ";
2336 os << v[i];
2338 os << "]";
2339 return os;
2342 static bool isTranslation(Matrix *M)
2344 unsigned i, j;
2345 if (M->NbRows != M->NbColumns)
2346 return False;
2348 for (i = 0;i < M->NbRows; i ++)
2349 for (j = 0; j < M->NbColumns-1; j ++)
2350 if (i == j) {
2351 if(value_notone_p(M->p[i][j]))
2352 return False;
2353 } else {
2354 if(value_notzero_p(M->p[i][j]))
2355 return False;
2357 return value_one_p(M->p[M->NbRows-1][M->NbColumns-1]);
2360 static Matrix *compress_parameters(Polyhedron **P, Polyhedron **C,
2361 unsigned nparam, unsigned MaxRays)
2363 Matrix *M, *T, *CP;
2365 /* compress_parms doesn't like equalities that only involve parameters */
2366 for (int i = 0; i < (*P)->NbEq; ++i)
2367 assert(First_Non_Zero((*P)->Constraint[i]+1, (*P)->Dimension-nparam) != -1);
2369 M = Matrix_Alloc((*P)->NbEq, (*P)->Dimension+2);
2370 Vector_Copy((*P)->Constraint[0], M->p[0], (*P)->NbEq * ((*P)->Dimension+2));
2371 CP = compress_parms(M, nparam);
2372 Matrix_Free(M);
2374 if (isTranslation(CP)) {
2375 Matrix_Free(CP);
2376 return NULL;
2379 T = align_matrix(CP, (*P)->Dimension+1);
2380 *P = Polyhedron_Preimage(*P, T, MaxRays);
2381 Matrix_Free(T);
2383 *C = Polyhedron_Preimage(*C, CP, MaxRays);
2385 return CP;
2388 void construct_rational_vertices(Param_Polyhedron *PP, Matrix *T, unsigned dim,
2389 int nparam, vector<indicator_term *>& vertices)
2391 int i;
2392 Param_Vertices *PV;
2393 Value lcm, tmp;
2394 value_init(lcm);
2395 value_init(tmp);
2397 vec_ZZ v;
2398 v.SetLength(nparam+1);
2400 evalue factor;
2401 value_init(factor.d);
2402 value_init(factor.x.n);
2403 value_set_si(factor.x.n, 1);
2404 value_set_si(factor.d, 1);
2406 for (i = 0, PV = PP->V; PV; ++i, PV = PV->next) {
2407 indicator_term *term = new indicator_term(dim, i);
2408 vertices.push_back(term);
2409 Matrix *M = Matrix_Alloc(PV->Vertex->NbRows+nparam+1, nparam+1);
2410 value_set_si(lcm, 1);
2411 for (int j = 0; j < PV->Vertex->NbRows; ++j)
2412 value_lcm(lcm, PV->Vertex->p[j][nparam+1], &lcm);
2413 value_assign(M->p[M->NbRows-1][M->NbColumns-1], lcm);
2414 for (int j = 0; j < PV->Vertex->NbRows; ++j) {
2415 value_division(tmp, lcm, PV->Vertex->p[j][nparam+1]);
2416 Vector_Scale(PV->Vertex->p[j], M->p[j], tmp, nparam+1);
2418 for (int j = 0; j < nparam; ++j)
2419 value_assign(M->p[PV->Vertex->NbRows+j][j], lcm);
2420 if (T) {
2421 Matrix *M2 = Matrix_Alloc(T->NbRows, M->NbColumns);
2422 Matrix_Product(T, M, M2);
2423 Matrix_Free(M);
2424 M = M2;
2426 for (int j = 0; j < dim; ++j) {
2427 values2zz(M->p[j], v, nparam+1);
2428 term->vertex[j] = multi_monom(v);
2429 value_assign(factor.d, lcm);
2430 emul(&factor, term->vertex[j]);
2432 Matrix_Free(M);
2434 assert(i == PP->nbV);
2435 free_evalue_refs(&factor);
2436 value_clear(lcm);
2437 value_clear(tmp);
2440 static vector<max_term*> lexmin(indicator& ind, unsigned nparam,
2441 vector<int> loc)
2443 vector<max_term*> maxima;
2444 std::set<const indicator_term *>::iterator i;
2445 vector<int> best_score;
2446 vector<int> second_score;
2447 vector<int> neg_score;
2449 do {
2450 ind.perform_pending_substitutions();
2451 const indicator_term *best = NULL, *second = NULL, *neg = NULL,
2452 *neg_eq = NULL, *neg_le = NULL;
2453 for (i = ind.order.head.begin(); i != ind.order.head.end(); ++i) {
2454 vector<int> score;
2455 const indicator_term *term = *i;
2456 if (term->sign == 0) {
2457 ind.expand_rational_vertex(term);
2458 break;
2461 if (ind.order.eq.find(term) != ind.order.eq.end()) {
2462 int j;
2463 if (ind.order.eq[term].size() <= 1)
2464 continue;
2465 for (j = 1; j < ind.order.eq[term].size(); ++j)
2466 if (ind.order.pred.find(ind.order.eq[term][j]) !=
2467 ind.order.pred.end())
2468 break;
2469 if (j < ind.order.eq[term].size())
2470 continue;
2471 score.push_back(ind.order.eq[term].size());
2472 } else
2473 score.push_back(0);
2474 if (ind.order.le.find(term) != ind.order.le.end())
2475 score.push_back(ind.order.le[term].size());
2476 else
2477 score.push_back(0);
2478 if (ind.order.lt.find(term) != ind.order.lt.end())
2479 score.push_back(-ind.order.lt[term].size());
2480 else
2481 score.push_back(0);
2483 if (term->sign > 0) {
2484 if (!best || score < best_score) {
2485 second = best;
2486 second_score = best_score;
2487 best = term;
2488 best_score = score;
2489 } else if (!second || score < second_score) {
2490 second = term;
2491 second_score = score;
2493 } else {
2494 if (!neg_eq && ind.order.eq.find(term) != ind.order.eq.end()) {
2495 for (int j = 1; j < ind.order.eq[term].size(); ++j)
2496 if (ind.order.eq[term][j]->sign != term->sign) {
2497 neg_eq = term;
2498 break;
2501 if (!neg_le && ind.order.le.find(term) != ind.order.le.end())
2502 neg_le = term;
2503 if (!neg || score < neg_score) {
2504 neg = term;
2505 neg_score = score;
2509 if (i != ind.order.head.end())
2510 continue;
2512 if (!best && neg_eq) {
2513 assert(ind.order.eq[neg_eq].size() != 0);
2514 bool handled = ind.handle_equal_numerators(neg_eq);
2515 assert(handled);
2516 continue;
2519 if (!best && neg_le) {
2520 /* The smallest term is negative and <= some positive term */
2521 best = neg_le;
2522 neg = NULL;
2525 if (!best) {
2526 /* apparently there can be negative initial term on empty domains */
2527 if (ind.options->lexmin_emptiness_check !=
2528 BV_LEXMIN_EMPTINESS_CHECK_NONE &&
2529 ind.options->lexmin_polysign == BV_LEXMIN_POLYSIGN_POLYLIB)
2530 assert(!neg);
2531 break;
2534 if (!second && !neg) {
2535 const indicator_term *rat = NULL;
2536 assert(best);
2537 if (ind.order.le.find(best) == ind.order.le.end()) {
2538 if (ind.order.eq.find(best) != ind.order.eq.end()) {
2539 bool handled = ind.handle_equal_numerators(best);
2540 if (ind.options->lexmin_emptiness_check !=
2541 BV_LEXMIN_EMPTINESS_CHECK_NONE &&
2542 ind.options->lexmin_polysign == BV_LEXMIN_POLYSIGN_POLYLIB)
2543 assert(handled);
2544 /* If !handled then the leading coefficient is bigger than one;
2545 * must be an empty domain
2547 if (handled)
2548 continue;
2549 else
2550 break;
2552 maxima.push_back(ind.create_max_term(best));
2553 break;
2555 for (int j = 0; j < ind.order.le[best].size(); ++j) {
2556 if (ind.order.le[best][j]->sign == 0) {
2557 if (!rat && ind.order.pred[ind.order.le[best][j]] == 1)
2558 rat = ind.order.le[best][j];
2559 } else if (ind.order.le[best][j]->sign > 0) {
2560 second = ind.order.le[best][j];
2561 break;
2562 } else if (!neg)
2563 neg = ind.order.le[best][j];
2566 if (!second && !neg) {
2567 assert(rat);
2568 ind.order.unset_le(best, rat);
2569 ind.expand_rational_vertex(rat);
2570 continue;
2573 if (!second)
2574 second = neg;
2576 ind.order.unset_le(best, second);
2579 if (!second)
2580 second = neg;
2582 unsigned dim = best->den.NumCols();
2583 temp_evalue diff;
2584 order_sign sign;
2585 for (int k = 0; k < dim; ++k) {
2586 diff = ediff(best->vertex[k], second->vertex[k]);
2587 sign = evalue_sign(diff, ind.D, ind.options);
2589 /* neg can never be smaller than best, unless it may still cancel.
2590 * This can happen if positive terms have been determined to
2591 * be equal or less than or equal to some negative term.
2593 if (second == neg && !neg_eq && !neg_le) {
2594 if (sign == order_ge)
2595 sign = order_eq;
2596 if (sign == order_unknown)
2597 sign = order_le;
2600 if (sign != order_eq)
2601 break;
2602 if (!EVALUE_IS_ZERO(*diff)) {
2603 ind.add_substitution(diff);
2604 ind.perform_pending_substitutions();
2607 if (sign == order_eq) {
2608 ind.order.set_equal(best, second);
2609 continue;
2611 if (sign == order_lt) {
2612 ind.order.lt[best].push_back(second);
2613 ind.order.inc_pred(second);
2614 continue;
2616 if (sign == order_gt) {
2617 ind.order.lt[second].push_back(best);
2618 ind.order.inc_pred(best);
2619 continue;
2622 split sp(diff, sign == order_le ? split::le :
2623 sign == order_ge ? split::ge : split::lge);
2625 EDomain *Dlt, *Deq, *Dgt;
2626 split_on(sp, ind.D, &Dlt, &Deq, &Dgt, ind.options);
2627 if (ind.options->lexmin_emptiness_check != BV_LEXMIN_EMPTINESS_CHECK_NONE)
2628 assert(Dlt || Deq || Dgt);
2629 else if (!(Dlt || Deq || Dgt))
2630 /* Must have been empty all along */
2631 break;
2633 if (Deq && (Dlt || Dgt)) {
2634 int locsize = loc.size();
2635 loc.push_back(0);
2636 indicator indeq(ind, Deq);
2637 Deq = NULL;
2638 indeq.add_substitution(diff);
2639 indeq.perform_pending_substitutions();
2640 vector<max_term*> maxeq = lexmin(indeq, nparam, loc);
2641 maxima.insert(maxima.end(), maxeq.begin(), maxeq.end());
2642 loc.resize(locsize);
2644 if (Dgt && Dlt) {
2645 int locsize = loc.size();
2646 loc.push_back(1);
2647 indicator indgt(ind, Dgt);
2648 Dgt = NULL;
2649 /* we don't know the new location of these terms in indgt */
2651 indgt.order.lt[second].push_back(best);
2652 indgt.order.inc_pred(best);
2654 vector<max_term*> maxgt = lexmin(indgt, nparam, loc);
2655 maxima.insert(maxima.end(), maxgt.begin(), maxgt.end());
2656 loc.resize(locsize);
2659 if (Deq) {
2660 loc.push_back(0);
2661 ind.set_domain(Deq);
2662 ind.add_substitution(diff);
2663 ind.perform_pending_substitutions();
2665 if (Dlt) {
2666 loc.push_back(-1);
2667 ind.set_domain(Dlt);
2668 ind.order.lt[best].push_back(second);
2669 ind.order.inc_pred(second);
2671 if (Dgt) {
2672 loc.push_back(1);
2673 ind.set_domain(Dgt);
2674 ind.order.lt[second].push_back(best);
2675 ind.order.inc_pred(best);
2677 } while(1);
2679 return maxima;
2682 static vector<max_term*> lexmin(Polyhedron *P, Polyhedron *C,
2683 barvinok_options *options)
2685 unsigned nparam = C->Dimension;
2686 Param_Polyhedron *PP = NULL;
2687 Polyhedron *CEq = NULL, *pVD;
2688 Matrix *CT = NULL;
2689 Matrix *T = NULL, *CP = NULL;
2690 Param_Domain *D, *next;
2691 Param_Vertices *V;
2692 Polyhedron *Porig = P;
2693 Polyhedron *Corig = C;
2694 vector<max_term*> all_max;
2695 Polyhedron *Q;
2696 unsigned P2PSD_MaxRays;
2698 if (emptyQ2(P))
2699 return all_max;
2701 POL_ENSURE_VERTICES(P);
2703 if (emptyQ2(P))
2704 return all_max;
2706 assert(P->NbBid == 0);
2708 if (P->NbEq > 0) {
2709 remove_all_equalities(&P, &C, &CP, &T, nparam, options->MaxRays);
2710 if (CP)
2711 nparam = CP->NbColumns-1;
2712 if (!P) {
2713 if (C != Corig)
2714 Polyhedron_Free(C);
2715 return all_max;
2719 if (options->MaxRays & POL_NO_DUAL)
2720 P2PSD_MaxRays = 0;
2721 else
2722 P2PSD_MaxRays = options->MaxRays;
2724 Q = P;
2725 PP = Polyhedron2Param_SimplifiedDomain(&P, C, P2PSD_MaxRays, &CEq, &CT);
2726 if (P != Q && Q != Porig)
2727 Polyhedron_Free(Q);
2729 if (CT) {
2730 if (isIdentity(CT)) {
2731 Matrix_Free(CT);
2732 CT = NULL;
2733 } else
2734 nparam = CT->NbRows - 1;
2736 assert(!CT);
2738 unsigned dim = P->Dimension - nparam;
2740 int nd;
2741 for (nd = 0, D=PP->D; D; ++nd, D=D->next);
2742 Polyhedron **fVD = new Polyhedron*[nd];
2744 indicator_constructor ic(P, dim, PP, T);
2746 vector<indicator_term *> all_vertices;
2747 construct_rational_vertices(PP, T, T ? T->NbRows-nparam-1 : dim,
2748 nparam, all_vertices);
2750 for (nd = 0, D=PP->D; D; D=next) {
2751 next = D->next;
2753 Polyhedron *rVD = reduce_domain(D->Domain, CT, CEq,
2754 fVD, nd, options->MaxRays);
2755 if (!rVD)
2756 continue;
2758 pVD = CT ? DomainImage(rVD,CT,options->MaxRays) : rVD;
2760 EDomain *epVD = new EDomain(pVD);
2761 indicator ind(ic, D, epVD, options);
2763 FORALL_PVertex_in_ParamPolyhedron(V,D,PP) // _i is internal counter
2764 ind.add(all_vertices[_i]);
2765 END_FORALL_PVertex_in_ParamPolyhedron;
2767 ind.remove_initial_rational_vertices();
2769 vector<int> loc;
2770 vector<max_term*> maxima = lexmin(ind, nparam, loc);
2771 if (CP)
2772 for (int j = 0; j < maxima.size(); ++j)
2773 maxima[j]->substitute(CP, options);
2774 all_max.insert(all_max.end(), maxima.begin(), maxima.end());
2776 ++nd;
2777 if (rVD != pVD)
2778 Domain_Free(pVD);
2779 Domain_Free(rVD);
2781 for (int i = 0; i < all_vertices.size(); ++i)
2782 delete all_vertices[i];
2783 if (CP)
2784 Matrix_Free(CP);
2785 if (T)
2786 Matrix_Free(T);
2787 Param_Polyhedron_Free(PP);
2788 if (CEq)
2789 Polyhedron_Free(CEq);
2790 for (--nd; nd >= 0; --nd) {
2791 Domain_Free(fVD[nd]);
2793 delete [] fVD;
2794 if (C != Corig)
2795 Polyhedron_Free(C);
2796 if (P != Porig)
2797 Polyhedron_Free(P);
2799 return all_max;
2802 static void verify_results(Polyhedron *A, Polyhedron *C,
2803 vector<max_term*>& maxima, int m, int M,
2804 int print_all, unsigned MaxRays);
2806 int main(int argc, char **argv)
2808 Polyhedron *A, *C;
2809 Matrix *MA;
2810 int bignum;
2811 char **iter_names, **param_names;
2812 int print_solution = 1;
2813 struct arguments arguments;
2814 static struct argp_child argp_children[] = {
2815 { &barvinok_argp, 0, 0, 0 },
2816 { &verify_argp, 0, "verification", 1 },
2817 { 0 }
2819 static struct argp argp = { argp_options, parse_opt, 0, 0, argp_children };
2820 struct barvinok_options *options;
2822 options = barvinok_options_new_with_defaults();
2823 options->lookup_table = 0;
2825 arguments.options = options;
2826 argp_parse(&argp, argc, argv, 0, 0, &arguments);
2828 MA = Matrix_Read();
2829 C = Constraints2Polyhedron(MA, options->MaxRays);
2830 Matrix_Free(MA);
2831 fscanf(stdin, " %d", &bignum);
2832 assert(bignum == -1);
2833 MA = Matrix_Read();
2834 A = Constraints2Polyhedron(MA, options->MaxRays);
2835 Matrix_Free(MA);
2837 verify_options_set_range(&arguments.verify, A);
2839 if (arguments.verify.verify)
2840 print_solution = 0;
2842 iter_names = util_generate_names(A->Dimension - C->Dimension, "i");
2843 param_names = util_generate_names(C->Dimension, "p");
2844 if (print_solution) {
2845 Polyhedron_Print(stdout, P_VALUE_FMT, A);
2846 Polyhedron_Print(stdout, P_VALUE_FMT, C);
2848 vector<max_term*> maxima = lexmin(A, C, options);
2849 if (print_solution)
2850 for (int i = 0; i < maxima.size(); ++i)
2851 maxima[i]->print(cout, param_names, options);
2853 if (arguments.verify.verify)
2854 verify_results(A, C, maxima, arguments.verify.m, arguments.verify.M,
2855 arguments.verify.print_all, options->MaxRays);
2857 for (int i = 0; i < maxima.size(); ++i)
2858 delete maxima[i];
2860 util_free_names(A->Dimension - C->Dimension, iter_names);
2861 util_free_names(C->Dimension, param_names);
2862 Polyhedron_Free(A);
2863 Polyhedron_Free(C);
2865 free(options);
2867 return 0;
2870 static bool lexmin(int pos, Polyhedron *P, Value *context)
2872 Value LB, UB, k;
2873 int lu_flags;
2874 bool found = false;
2876 if (emptyQ(P))
2877 return false;
2879 value_init(LB); value_init(UB); value_init(k);
2880 value_set_si(LB,0);
2881 value_set_si(UB,0);
2882 lu_flags = lower_upper_bounds(pos,P,context,&LB,&UB);
2883 assert(!(lu_flags & LB_INFINITY));
2885 value_set_si(context[pos],0);
2886 if (!lu_flags && value_lt(UB,LB)) {
2887 value_clear(LB); value_clear(UB); value_clear(k);
2888 return false;
2890 if (!P->next) {
2891 value_assign(context[pos], LB);
2892 value_clear(LB); value_clear(UB); value_clear(k);
2893 return true;
2895 for (value_assign(k,LB); lu_flags || value_le(k,UB); value_increment(k,k)) {
2896 value_assign(context[pos],k);
2897 if ((found = lexmin(pos+1, P->next, context)))
2898 break;
2900 if (!found)
2901 value_set_si(context[pos],0);
2902 value_clear(LB); value_clear(UB); value_clear(k);
2903 return found;
2906 static void print_list(FILE *out, Value *z, char* brackets, int len)
2908 fprintf(out, "%c", brackets[0]);
2909 value_print(out, VALUE_FMT,z[0]);
2910 for (int k = 1; k < len; ++k) {
2911 fprintf(out, ", ");
2912 value_print(out, VALUE_FMT,z[k]);
2914 fprintf(out, "%c", brackets[1]);
2917 static int check_poly(Polyhedron *S, Polyhedron *CS, vector<max_term*>& maxima,
2918 int nparam, int pos, Value *z, int print_all, int st,
2919 unsigned MaxRays)
2921 if (pos == nparam) {
2922 int k;
2923 bool found = lexmin(1, S, z);
2925 if (print_all) {
2926 printf("lexmin");
2927 print_list(stdout, z+S->Dimension-nparam+1, "()", nparam);
2928 printf(" = ");
2929 if (found)
2930 print_list(stdout, z+1, "[]", S->Dimension-nparam);
2931 printf(" ");
2934 Vector *min = NULL;
2935 for (int i = 0; i < maxima.size(); ++i)
2936 if ((min = maxima[i]->eval(z+S->Dimension-nparam+1, MaxRays)))
2937 break;
2939 int ok = !(found ^ !!min);
2940 if (found && min)
2941 for (int i = 0; i < S->Dimension-nparam; ++i)
2942 if (value_ne(z[1+i], min->p[i])) {
2943 ok = 0;
2944 break;
2946 if (!ok) {
2947 printf("\n");
2948 fflush(stdout);
2949 fprintf(stderr, "Error !\n");
2950 fprintf(stderr, "lexmin");
2951 print_list(stderr, z+S->Dimension-nparam+1, "()", nparam);
2952 fprintf(stderr, " should be ");
2953 if (found)
2954 print_list(stderr, z+1, "[]", S->Dimension-nparam);
2955 fprintf(stderr, " while digging gives ");
2956 if (min)
2957 print_list(stderr, min->p, "[]", S->Dimension-nparam);
2958 fprintf(stderr, ".\n");
2959 return 0;
2960 } else if (print_all)
2961 printf("OK.\n");
2962 if (min)
2963 Vector_Free(min);
2965 for (k = 1; k <= S->Dimension-nparam; ++k)
2966 value_set_si(z[k], 0);
2967 } else {
2968 Value tmp;
2969 Value LB, UB;
2970 value_init(tmp);
2971 value_init(LB);
2972 value_init(UB);
2973 int ok =
2974 !(lower_upper_bounds(1+pos, CS, &z[S->Dimension-nparam], &LB, &UB));
2975 for (value_assign(tmp,LB); value_le(tmp,UB); value_increment(tmp,tmp)) {
2976 if (!print_all) {
2977 int k = VALUE_TO_INT(tmp);
2978 if (!pos && !(k%st)) {
2979 printf("o");
2980 fflush(stdout);
2983 value_assign(z[pos+S->Dimension-nparam+1],tmp);
2984 if (!check_poly(S, CS->next, maxima, nparam, pos+1, z, print_all, st,
2985 MaxRays)) {
2986 value_clear(tmp);
2987 value_clear(LB);
2988 value_clear(UB);
2989 return 0;
2992 value_set_si(z[pos+S->Dimension-nparam+1],0);
2993 value_clear(tmp);
2994 value_clear(LB);
2995 value_clear(UB);
2997 return 1;
3000 void verify_results(Polyhedron *A, Polyhedron *C, vector<max_term*>& maxima,
3001 int m, int M, int print_all, unsigned MaxRays)
3003 Polyhedron *CC, *CC2, *CS, *S;
3004 unsigned nparam = C->Dimension;
3005 Value *p;
3006 int i;
3007 int st;
3009 CC = Polyhedron_Project(A, nparam);
3010 CC2 = DomainIntersection(C, CC, MaxRays);
3011 Domain_Free(CC);
3012 CC = CC2;
3014 /* Intersect context with range */
3015 if (nparam > 0) {
3016 Matrix *MM;
3017 Polyhedron *U;
3019 MM = Matrix_Alloc(2*C->Dimension, C->Dimension+2);
3020 for (int i = 0; i < C->Dimension; ++i) {
3021 value_set_si(MM->p[2*i][0], 1);
3022 value_set_si(MM->p[2*i][1+i], 1);
3023 value_set_si(MM->p[2*i][1+C->Dimension], -m);
3024 value_set_si(MM->p[2*i+1][0], 1);
3025 value_set_si(MM->p[2*i+1][1+i], -1);
3026 value_set_si(MM->p[2*i+1][1+C->Dimension], M);
3028 CC2 = AddConstraints(MM->p[0], 2*CC->Dimension, CC, MaxRays);
3029 U = Universe_Polyhedron(0);
3030 CS = Polyhedron_Scan(CC2, U, MaxRays & POL_NO_DUAL ? 0 : MaxRays);
3031 Polyhedron_Free(U);
3032 Polyhedron_Free(CC2);
3033 Matrix_Free(MM);
3034 } else
3035 CS = NULL;
3037 p = ALLOCN(Value, A->Dimension+2);
3038 for (i=0; i <= A->Dimension; i++) {
3039 value_init(p[i]);
3040 value_set_si(p[i],0);
3042 value_init(p[i]);
3043 value_set_si(p[i], 1);
3045 S = Polyhedron_Scan(A, C, MaxRays & POL_NO_DUAL ? 0 : MaxRays);
3047 if (!print_all && C->Dimension > 0) {
3048 if (M-m > 80)
3049 st = 1+(M-m)/80;
3050 else
3051 st = 1;
3052 for (int i = m; i <= M; i += st)
3053 printf(".");
3054 printf( "\r" );
3055 fflush(stdout);
3058 if (S) {
3059 if (!(CS && emptyQ2(CS)))
3060 check_poly(S, CS, maxima, nparam, 0, p, print_all, st, MaxRays);
3061 Domain_Free(S);
3064 if (!print_all)
3065 printf("\n");
3067 for (i=0; i <= (A->Dimension+1); i++)
3068 value_clear(p[i]);
3069 free(p);
3070 if (CS)
3071 Domain_Free(CS);
3072 Polyhedron_Free(CC);