4 #include <NTL/vec_ZZ.h>
5 #include <NTL/mat_ZZ.h>
7 #include <polylib/polylibgmp.h>
9 #include <barvinok/barvinok.h>
10 #include <barvinok/evalue.h>
11 #include <barvinok/util.h>
12 #include "conversion.h"
13 #include "decomposer.h"
14 #include "lattice_point.h"
15 #include "reduce_domain.h"
32 #ifdef HAVE_GROWING_CHERNIKOVA
33 #define MAXRAYS (POL_NO_DUAL | POL_INTEGER)
38 /* RANGE : normal range for evalutations (-RANGE -> RANGE) */
41 /* SRANGE : small range for evalutations */
44 /* if dimension >= BIDDIM, use SRANGE */
47 /* VSRANGE : very small range for evalutations */
50 /* if dimension >= VBIDDIM, use VSRANGE */
54 #define getopt_long(a,b,c,d,e) getopt(a,b,c)
57 struct option options
[] = {
58 { "verify", no_argument
, 0, 'T' },
59 { "print-all", no_argument
, 0, 'A' },
60 { "min", required_argument
, 0, 'm' },
61 { "max", required_argument
, 0, 'M' },
62 { "range", required_argument
, 0, 'r' },
63 { "version", no_argument
, 0, 'V' },
68 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
70 static int type_offset(enode
*p
)
72 return p
->type
== fractional
? 1 :
73 p
->type
== flooring
? 1 : 0;
76 static void evalue_denom(evalue
*e
, Value
*d
)
78 if (value_notzero_p(e
->d
)) {
79 value_lcm(*d
, e
->d
, d
);
82 int offset
= type_offset(e
->x
.p
);
83 for (int i
= e
->x
.p
->size
-1; i
>= offset
; --i
)
84 evalue_denom(&e
->x
.p
->arr
[i
], d
);
87 static void evalue_print(std::ostream
& o
, evalue
*e
, char **p
);
88 static void evalue_print(std::ostream
& o
, evalue
*e
, char **p
, int d
)
90 if (value_notzero_p(e
->d
)) {
91 o
<< VALUE_TO_INT(e
->x
.n
) * (d
/ VALUE_TO_INT(e
->d
));
94 assert(e
->x
.p
->type
== polynomial
|| e
->x
.p
->type
== flooring
||
95 e
->x
.p
->type
== fractional
);
96 int offset
= type_offset(e
->x
.p
);
97 for (int i
= e
->x
.p
->size
-1; i
>= offset
; --i
) {
98 if (EVALUE_IS_ZERO(e
->x
.p
->arr
[i
]))
100 if (i
!= e
->x
.p
->size
-1 &&
101 (value_zero_p(e
->x
.p
->arr
[i
].d
) ||
102 value_pos_p(e
->x
.p
->arr
[i
].x
.n
)))
104 if (i
== offset
|| !(value_one_p(e
->x
.p
->arr
[i
].x
.n
) &&
105 d
== VALUE_TO_INT(e
->x
.p
->arr
[i
].d
))) {
106 if (value_zero_p(e
->x
.p
->arr
[i
].d
))
108 evalue_print(o
, &e
->x
.p
->arr
[i
], p
, d
);
109 if (value_zero_p(e
->x
.p
->arr
[i
].d
))
114 for (int j
= 0; j
< i
-offset
; ++j
) {
117 if (e
->x
.p
->type
== flooring
) {
119 evalue_print(o
, &e
->x
.p
->arr
[0], p
);
121 } else if (e
->x
.p
->type
== fractional
) {
123 evalue_print(o
, &e
->x
.p
->arr
[0], p
);
126 o
<< p
[e
->x
.p
->pos
-1];
131 static void evalue_print(std::ostream
& o
, evalue
*e
, char **p
)
137 if (value_notone_p(d
))
139 evalue_print(o
, e
, p
, VALUE_TO_INT(d
));
140 if (value_notone_p(d
))
141 o
<< ")/" << VALUE_TO_INT(d
);
145 struct indicator_term
{
150 indicator_term(unsigned dim
) {
151 den
.SetDims(dim
, dim
);
152 vertex
= new evalue
* [dim
];
154 indicator_term(const indicator_term
& src
) {
157 unsigned dim
= den
.NumCols();
158 vertex
= new evalue
* [dim
];
159 for (int i
= 0; i
< dim
; ++i
) {
160 vertex
[i
] = new evalue();
161 value_init(vertex
[i
]->d
);
162 evalue_copy(vertex
[i
], src
.vertex
[i
]);
166 unsigned dim
= den
.NumCols();
167 for (int i
= 0; i
< dim
; ++i
) {
168 free_evalue_refs(vertex
[i
]);
173 void print(ostream
& os
, char **p
);
174 void substitute(Matrix
*T
);
175 void substitute(evalue
*fract
, evalue
*val
);
176 void substitute(int pos
, evalue
*val
);
177 void reduce_in_domain(Polyhedron
*D
);
180 void indicator_term::reduce_in_domain(Polyhedron
*D
)
182 for (int k
= 0; k
< den
.NumCols(); ++k
) {
183 reduce_evalue_in_domain(vertex
[k
], D
);
184 if (evalue_range_reduction_in_domain(vertex
[k
], D
))
185 reduce_evalue(vertex
[k
]);
189 void indicator_term::print(ostream
& os
, char **p
)
191 unsigned dim
= den
.NumCols();
192 unsigned factors
= den
.NumRows();
198 for (int i
= 0; i
< dim
; ++i
) {
201 evalue_print(os
, vertex
[i
], p
);
204 for (int i
= 0; i
< factors
; ++i
) {
205 os
<< " + t" << i
<< "*[";
206 for (int j
= 0; j
< dim
; ++j
) {
215 /* Perform the substitution specified by T on the variables.
216 * T has dimension (newdim+nparam+1) x (olddim + nparam + 1).
217 * The substitution is performed as in gen_fun::substitute
219 void indicator_term::substitute(Matrix
*T
)
221 unsigned dim
= den
.NumCols();
222 unsigned nparam
= T
->NbColumns
- dim
- 1;
223 unsigned newdim
= T
->NbRows
- nparam
- 1;
226 matrix2zz(T
, trans
, newdim
, dim
);
227 trans
= transpose(trans
);
229 newvertex
= new evalue
* [newdim
];
232 v
.SetLength(nparam
+1);
235 value_init(factor
.d
);
236 value_set_si(factor
.d
, 1);
237 value_init(factor
.x
.n
);
238 for (int i
= 0; i
< newdim
; ++i
) {
239 values2zz(T
->p
[i
]+dim
, v
, nparam
+1);
240 newvertex
[i
] = multi_monom(v
);
242 for (int j
= 0; j
< dim
; ++j
) {
243 if (value_zero_p(T
->p
[i
][j
]))
247 evalue_copy(&term
, vertex
[j
]);
248 value_assign(factor
.x
.n
, T
->p
[i
][j
]);
249 emul(&factor
, &term
);
250 eadd(&term
, newvertex
[i
]);
251 free_evalue_refs(&term
);
254 free_evalue_refs(&factor
);
255 for (int i
= 0; i
< dim
; ++i
) {
256 free_evalue_refs(vertex
[i
]);
263 static void substitute(evalue
*e
, evalue
*fract
, evalue
*val
)
267 for (t
= e
; value_zero_p(t
->d
); t
= &t
->x
.p
->arr
[type_offset(t
->x
.p
)]) {
268 if (t
->x
.p
->type
== fractional
&& eequal(&t
->x
.p
->arr
[0], fract
))
271 if (value_notzero_p(t
->d
))
274 free_evalue_refs(&t
->x
.p
->arr
[0]);
275 evalue
*term
= &t
->x
.p
->arr
[2];
282 free_evalue_refs(term
);
288 void indicator_term::substitute(evalue
*fract
, evalue
*val
)
290 unsigned dim
= den
.NumCols();
291 for (int i
= 0; i
< dim
; ++i
) {
292 ::substitute(vertex
[i
], fract
, val
);
296 static void substitute(evalue
*e
, int pos
, evalue
*val
)
300 for (t
= e
; value_zero_p(t
->d
); t
= &t
->x
.p
->arr
[type_offset(t
->x
.p
)]) {
301 if (t
->x
.p
->type
== polynomial
&& t
->x
.p
->pos
== pos
)
304 if (value_notzero_p(t
->d
))
307 evalue
*term
= &t
->x
.p
->arr
[1];
314 free_evalue_refs(term
);
320 void indicator_term::substitute(int pos
, evalue
*val
)
322 unsigned dim
= den
.NumCols();
323 for (int i
= 0; i
< dim
; ++i
) {
324 ::substitute(vertex
[i
], pos
, val
);
328 struct indicator_constructor
: public polar_decomposer
, public vertex_decomposer
{
330 vector
<indicator_term
*> *terms
;
332 indicator_constructor(Polyhedron
*P
, unsigned dim
, unsigned nbV
) :
333 vertex_decomposer(P
, nbV
, this) {
334 vertex
.SetLength(dim
);
335 terms
= new vector
<indicator_term
*>[nbV
];
337 ~indicator_constructor() {
338 for (int i
= 0; i
< nbV
; ++i
)
339 for (int j
= 0; j
< terms
[i
].size(); ++j
)
343 void substitute(Matrix
*T
);
345 void print(ostream
& os
, char **p
);
347 virtual void handle_polar(Polyhedron
*P
, int sign
);
350 static void evalue_add_constant(evalue
*e
, ZZ v
)
355 /* go down to constant term */
356 while (value_zero_p(e
->d
))
357 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)];
360 value_multiply(tmp
, tmp
, e
->d
);
361 value_addto(e
->x
.n
, e
->x
.n
, tmp
);
366 void indicator_constructor::handle_polar(Polyhedron
*C
, int s
)
368 unsigned dim
= vertex
.length();
370 assert(C
->NbRays
-1 == dim
);
372 indicator_term
*term
= new indicator_term(dim
);
374 terms
[vert
].push_back(term
);
376 lattice_point(V
, C
, vertex
, term
->vertex
);
378 for (int r
= 0; r
< dim
; ++r
) {
379 values2zz(C
->Ray
[r
]+1, term
->den
[r
], dim
);
380 for (int j
= 0; j
< dim
; ++j
) {
381 if (term
->den
[r
][j
] == 0)
383 if (term
->den
[r
][j
] > 0)
385 term
->sign
= -term
->sign
;
386 term
->den
[r
] = -term
->den
[r
];
387 vertex
+= term
->den
[r
];
391 lex_order_rows(term
->den
);
393 for (int i
= 0; i
< dim
; ++i
) {
394 if (!term
->vertex
[i
]) {
395 term
->vertex
[i
] = new evalue();
396 value_init(term
->vertex
[i
]->d
);
397 value_init(term
->vertex
[i
]->x
.n
);
398 zz2value(vertex
[i
], term
->vertex
[i
]->x
.n
);
399 value_set_si(term
->vertex
[i
]->d
, 1);
404 evalue_add_constant(term
->vertex
[i
], vertex
[i
]);
408 void indicator_constructor::substitute(Matrix
*T
)
410 for (int i
= 0; i
< nbV
; ++i
)
411 for (int j
= 0; j
< terms
[i
].size(); ++j
)
412 terms
[i
][j
]->substitute(T
);
415 void indicator_constructor::print(ostream
& os
, char **p
)
417 for (int i
= 0; i
< nbV
; ++i
)
418 for (int j
= 0; j
< terms
[i
].size(); ++j
) {
419 os
<< "i: " << i
<< ", j: " << j
<< endl
;
420 terms
[i
][j
]->print(os
, p
);
425 void indicator_constructor::normalize()
427 for (int i
= 0; i
< nbV
; ++i
)
428 for (int j
= 0; j
< terms
[i
].size(); ++j
) {
430 vertex
.SetLength(terms
[i
][j
]->den
.NumCols());
431 for (int r
= 0; r
< terms
[i
][j
]->den
.NumRows(); ++r
) {
432 for (int k
= 0; k
< terms
[i
][j
]->den
.NumCols(); ++k
) {
433 if (terms
[i
][j
]->den
[r
][k
] == 0)
435 if (terms
[i
][j
]->den
[r
][k
] > 0)
437 terms
[i
][j
]->sign
= -terms
[i
][j
]->sign
;
438 terms
[i
][j
]->den
[r
] = -terms
[i
][j
]->den
[r
];
439 vertex
+= terms
[i
][j
]->den
[r
];
443 lex_order_rows(terms
[i
][j
]->den
);
444 for (int k
= 0; k
< vertex
.length(); ++k
)
446 evalue_add_constant(terms
[i
][j
]->vertex
[k
], vertex
[k
]);
451 vector
<indicator_term
*> term
;
454 indicator(const indicator
& ind
) {
455 for (int i
= 0; i
< ind
.term
.size(); ++i
)
456 term
.push_back(new indicator_term(*ind
.term
[i
]));
459 for (int i
= 0; i
< term
.size(); ++i
)
463 void print(ostream
& os
, char **p
);
465 void peel(int i
, int j
);
466 void combine(int i
, int j
);
467 void substitute(evalue
*equation
);
468 void reduce_in_domain(Polyhedron
*D
);
471 void indicator::reduce_in_domain(Polyhedron
*D
)
473 for (int i
= 0; i
< term
.size(); ++i
)
474 term
[i
]->reduce_in_domain(D
);
477 void indicator::print(ostream
& os
, char **p
)
479 for (int i
= 0; i
< term
.size(); ++i
) {
480 term
[i
]->print(os
, p
);
485 /* Remove pairs of opposite terms */
486 void indicator::simplify()
488 for (int i
= 0; i
< term
.size(); ++i
) {
489 for (int j
= i
+1; j
< term
.size(); ++j
) {
490 if (term
[i
]->sign
+ term
[j
]->sign
!= 0)
492 if (term
[i
]->den
!= term
[j
]->den
)
495 for (k
= 0; k
< term
[i
]->den
.NumCols(); ++k
)
496 if (!eequal(term
[i
]->vertex
[k
], term
[j
]->vertex
[k
]))
498 if (k
< term
[i
]->den
.NumCols())
502 term
.erase(term
.begin()+j
);
503 term
.erase(term
.begin()+i
);
510 void indicator::peel(int i
, int j
)
518 int dim
= term
[i
]->den
.NumCols();
523 int n_common
= 0, n_i
= 0, n_j
= 0;
525 common
.SetDims(min(term
[i
]->den
.NumRows(), term
[j
]->den
.NumRows()), dim
);
526 rest_i
.SetDims(term
[i
]->den
.NumRows(), dim
);
527 rest_j
.SetDims(term
[j
]->den
.NumRows(), dim
);
530 for (k
= 0, l
= 0; k
< term
[i
]->den
.NumRows() && l
< term
[j
]->den
.NumRows(); ) {
531 int s
= lex_cmp(term
[i
]->den
[k
], term
[j
]->den
[l
]);
533 common
[n_common
++] = term
[i
]->den
[k
];
537 rest_i
[n_i
++] = term
[i
]->den
[k
++];
539 rest_j
[n_j
++] = term
[j
]->den
[l
++];
541 while (k
< term
[i
]->den
.NumRows())
542 rest_i
[n_i
++] = term
[i
]->den
[k
++];
543 while (l
< term
[j
]->den
.NumRows())
544 rest_j
[n_j
++] = term
[j
]->den
[l
++];
545 common
.SetDims(n_common
, dim
);
546 rest_i
.SetDims(n_i
, dim
);
547 rest_j
.SetDims(n_j
, dim
);
549 for (k
= 0; k
<= n_i
; ++k
) {
550 indicator_term
*it
= new indicator_term(*term
[i
]);
551 it
->den
.SetDims(n_common
+ k
, dim
);
552 for (l
= 0; l
< n_common
; ++l
)
553 it
->den
[l
] = common
[l
];
554 for (l
= 0; l
< k
; ++l
)
555 it
->den
[n_common
+l
] = rest_i
[l
];
556 lex_order_rows(it
->den
);
558 for (l
= 0; l
< dim
; ++l
)
559 evalue_add_constant(it
->vertex
[l
], rest_i
[k
-1][l
]);
563 for (k
= 0; k
<= n_j
; ++k
) {
564 indicator_term
*it
= new indicator_term(*term
[j
]);
565 it
->den
.SetDims(n_common
+ k
, dim
);
566 for (l
= 0; l
< n_common
; ++l
)
567 it
->den
[l
] = common
[l
];
568 for (l
= 0; l
< k
; ++l
)
569 it
->den
[n_common
+l
] = rest_j
[l
];
570 lex_order_rows(it
->den
);
572 for (l
= 0; l
< dim
; ++l
)
573 evalue_add_constant(it
->vertex
[l
], rest_j
[k
-1][l
]);
576 term
.erase(term
.begin()+j
);
577 term
.erase(term
.begin()+i
);
580 void indicator::combine(int i
, int j
)
588 int dim
= term
[i
]->den
.NumCols();
593 int n_common
= 0, n_i
= 0, n_j
= 0;
595 common
.SetDims(min(term
[i
]->den
.NumRows(), term
[j
]->den
.NumRows()), dim
);
596 rest_i
.SetDims(term
[i
]->den
.NumRows(), dim
);
597 rest_j
.SetDims(term
[j
]->den
.NumRows(), dim
);
600 for (k
= 0, l
= 0; k
< term
[i
]->den
.NumRows() && l
< term
[j
]->den
.NumRows(); ) {
601 int s
= lex_cmp(term
[i
]->den
[k
], term
[j
]->den
[l
]);
603 common
[n_common
++] = term
[i
]->den
[k
];
607 rest_i
[n_i
++] = term
[i
]->den
[k
++];
609 rest_j
[n_j
++] = term
[j
]->den
[l
++];
611 while (k
< term
[i
]->den
.NumRows())
612 rest_i
[n_i
++] = term
[i
]->den
[k
++];
613 while (l
< term
[j
]->den
.NumRows())
614 rest_j
[n_j
++] = term
[j
]->den
[l
++];
615 common
.SetDims(n_common
, dim
);
616 rest_i
.SetDims(n_i
, dim
);
617 rest_j
.SetDims(n_j
, dim
);
622 for (k
= 0; k
< (1 << n_i
); ++k
) {
623 indicator_term
*it
= new indicator_term(*term
[j
]);
624 it
->den
.SetDims(n_common
+ n_i
+ n_j
, dim
);
625 for (l
= 0; l
< n_common
; ++l
)
626 it
->den
[l
] = common
[l
];
627 for (l
= 0; l
< n_i
; ++l
)
628 it
->den
[n_common
+l
] = rest_i
[l
];
629 for (l
= 0; l
< n_j
; ++l
)
630 it
->den
[n_common
+n_i
+l
] = rest_j
[l
];
631 lex_order_rows(it
->den
);
633 for (l
= 0; l
< n_i
; ++l
) {
637 for (int m
= 0; m
< dim
; ++m
)
638 evalue_add_constant(it
->vertex
[m
], rest_i
[l
][m
]);
641 it
->sign
= -it
->sign
;
645 for (k
= 0; k
< (1 << n_j
); ++k
) {
646 indicator_term
*it
= new indicator_term(*term
[i
]);
647 it
->den
.SetDims(n_common
+ n_i
+ n_j
, dim
);
648 for (l
= 0; l
< n_common
; ++l
)
649 it
->den
[l
] = common
[l
];
650 for (l
= 0; l
< n_i
; ++l
)
651 it
->den
[n_common
+l
] = rest_i
[l
];
652 for (l
= 0; l
< n_j
; ++l
)
653 it
->den
[n_common
+n_i
+l
] = rest_j
[l
];
654 lex_order_rows(it
->den
);
656 for (l
= 0; l
< n_j
; ++l
) {
660 for (int m
= 0; m
< dim
; ++m
)
661 evalue_add_constant(it
->vertex
[m
], rest_j
[l
][m
]);
664 it
->sign
= -it
->sign
;
669 term
.erase(term
.begin()+j
);
670 term
.erase(term
.begin()+i
);
673 void indicator::substitute(evalue
*equation
)
675 evalue
*fract
= NULL
;
676 evalue
*val
= new evalue
;
678 evalue_copy(val
, equation
);
681 value_init(factor
.d
);
682 value_init(factor
.x
.n
);
685 for (e
= val
; value_zero_p(e
->d
) && e
->x
.p
->type
!= fractional
;
686 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)])
689 if (value_zero_p(e
->d
) && e
->x
.p
->type
== fractional
)
690 fract
= &e
->x
.p
->arr
[0];
692 for (e
= val
; value_zero_p(e
->d
) && e
->x
.p
->type
!= polynomial
;
693 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)])
695 assert(value_zero_p(e
->d
) && e
->x
.p
->type
== polynomial
);
698 int offset
= type_offset(e
->x
.p
);
700 assert(value_notzero_p(e
->x
.p
->arr
[offset
+1].d
));
701 assert(value_notzero_p(e
->x
.p
->arr
[offset
+1].x
.n
));
702 if (value_neg_p(e
->x
.p
->arr
[offset
+1].x
.n
)) {
703 value_oppose(factor
.d
, e
->x
.p
->arr
[offset
+1].x
.n
);
704 value_assign(factor
.x
.n
, e
->x
.p
->arr
[offset
+1].d
);
706 value_assign(factor
.d
, e
->x
.p
->arr
[offset
+1].x
.n
);
707 value_oppose(factor
.x
.n
, e
->x
.p
->arr
[offset
+1].d
);
710 free_evalue_refs(&e
->x
.p
->arr
[offset
+1]);
713 *e
= e
->x
.p
->arr
[offset
];
718 for (int i
= 0; i
< term
.size(); ++i
)
719 term
[i
]->substitute(fract
, val
);
721 free_evalue_refs(&p
->arr
[0]);
723 for (int i
= 0; i
< term
.size(); ++i
)
724 term
[i
]->substitute(p
->pos
, val
);
727 free_evalue_refs(&factor
);
728 free_evalue_refs(val
);
734 static void add_coeff(Value
*cons
, int len
, evalue
*coeff
, int pos
)
738 assert(value_notzero_p(coeff
->d
));
742 value_lcm(cons
[0], coeff
->d
, &tmp
);
743 value_division(tmp
, tmp
, cons
[0]);
744 Vector_Scale(cons
, cons
, tmp
, len
);
745 value_division(tmp
, cons
[0], coeff
->d
);
746 value_addmul(cons
[pos
], tmp
, coeff
->x
.n
);
754 vector
<evalue
*> floors
;
756 EDomain(Polyhedron
*D
) {
757 this->D
= Polyhedron_Copy(D
);
760 EDomain(Polyhedron
*D
, vector
<evalue
*>floors
) {
761 this->D
= Polyhedron_Copy(D
);
765 EDomain(Polyhedron
*D
, EDomain
*ED
, vector
<evalue
*>floors
) {
766 this->D
= Polyhedron_Copy(D
);
767 add_floors(ED
->floors
);
771 void add_floors(vector
<evalue
*>floors
) {
772 for (int i
= 0; i
< floors
.size(); ++i
) {
773 evalue
*f
= new evalue
;
775 evalue_copy(f
, floors
[i
]);
776 this->floors
.push_back(f
);
779 int find_floor(evalue
*needle
) {
780 for (int i
= 0; i
< floors
.size(); ++i
)
781 if (eequal(needle
, floors
[i
]))
785 void print(FILE *out
, char **p
);
787 for (int i
= 0; i
< floors
.size(); ++i
) {
788 free_evalue_refs(floors
[i
]);
797 void EDomain::print(FILE *out
, char **p
)
799 fdostream
os(dup(fileno(out
)));
800 for (int i
= 0; i
< floors
.size(); ++i
) {
801 os
<< "floor " << i
<< ": [";
802 evalue_print(os
, floors
[i
], p
);
805 Polyhedron_Print(out
, P_VALUE_FMT
, D
);
808 static int evalue2constraint_r(EDomain
*D
, evalue
*E
, Value
*cons
, int len
);
810 static void add_fract(evalue
*e
, Value
*cons
, int len
, int pos
)
814 evalue_set_si(&mone
, -1, 1);
816 /* contribution of alpha * fract(X) is
819 assert(e
->x
.p
->size
== 3);
821 value_init(argument
.d
);
822 evalue_copy(&argument
, &e
->x
.p
->arr
[0]);
823 emul(&e
->x
.p
->arr
[2], &argument
);
824 evalue2constraint_r(NULL
, &argument
, cons
, len
);
825 free_evalue_refs(&argument
);
827 /* - alpha * floor(X) */
828 emul(&mone
, &e
->x
.p
->arr
[2]);
829 add_coeff(cons
, len
, &e
->x
.p
->arr
[2], pos
);
830 emul(&mone
, &e
->x
.p
->arr
[2]);
832 free_evalue_refs(&mone
);
835 static int evalue2constraint_r(EDomain
*D
, evalue
*E
, Value
*cons
, int len
)
838 if (value_zero_p(E
->d
) && E
->x
.p
->type
== fractional
) {
840 assert(E
->x
.p
->size
== 3);
841 r
= evalue2constraint_r(D
, &E
->x
.p
->arr
[1], cons
, len
);
842 assert(value_notzero_p(E
->x
.p
->arr
[2].d
));
843 if (D
&& (i
= D
->find_floor(&E
->x
.p
->arr
[0])) >= 0) {
844 add_fract(E
, cons
, len
, 1+D
->D
->Dimension
-D
->floors
.size()+i
);
846 if (value_pos_p(E
->x
.p
->arr
[2].x
.n
)) {
849 value_init(coeff
.x
.n
);
850 value_set_si(coeff
.d
, 1);
851 evalue_denom(&E
->x
.p
->arr
[0], &coeff
.d
);
852 value_decrement(coeff
.x
.n
, coeff
.d
);
853 emul(&E
->x
.p
->arr
[2], &coeff
);
854 add_coeff(cons
, len
, &coeff
, len
-1);
855 free_evalue_refs(&coeff
);
859 } else if (value_zero_p(E
->d
)) {
860 assert(E
->x
.p
->type
== polynomial
);
861 assert(E
->x
.p
->size
== 2);
862 r
= evalue2constraint_r(D
, &E
->x
.p
->arr
[0], cons
, len
) || r
;
863 add_coeff(cons
, len
, &E
->x
.p
->arr
[1], E
->x
.p
->pos
);
865 add_coeff(cons
, len
, E
, len
-1);
870 static int evalue2constraint(EDomain
*D
, evalue
*E
, Value
*cons
, int len
)
872 Vector_Set(cons
, 0, len
);
873 value_set_si(cons
[0], 1);
874 return evalue2constraint_r(D
, E
, cons
, len
);
877 static void interval_minmax(Polyhedron
*I
, int *min
, int *max
)
879 assert(I
->Dimension
== 1);
882 POL_ENSURE_VERTICES(I
);
883 for (int i
= 0; i
< I
->NbRays
; ++i
) {
884 if (value_pos_p(I
->Ray
[i
][1]))
886 else if (value_neg_p(I
->Ray
[i
][1]))
897 static void interval_minmax(Polyhedron
*D
, Matrix
*T
, int *min
, int *max
,
900 Polyhedron
*I
= Polyhedron_Image(D
, T
, MaxRays
);
901 I
= DomainConstraintSimplify(I
, MaxRays
);
904 I
= Polyhedron_Image(D
, T
, MaxRays
);
906 interval_minmax(I
, min
, max
);
913 vector
<evalue
*> max
;
915 void print(ostream
& os
, char **p
) const;
916 void resolve_existential_vars() const;
917 void substitute(Matrix
*T
, unsigned MaxRays
);
918 Vector
*eval(Value
*val
, unsigned MaxRays
) const;
921 for (int i
= 0; i
< max
.size(); ++i
) {
922 free_evalue_refs(max
[i
]);
925 Polyhedron_Free(domain
);
929 static void print_varlist(ostream
& os
, int n
, char **names
)
933 for (i
= 0; i
< n
; ++i
) {
941 static void print_term(ostream
& os
, Value v
, int pos
, int dim
,
942 char **names
, int *first
)
944 if (value_zero_p(v
)) {
945 if (first
&& *first
&& pos
>= dim
)
951 if (!*first
&& value_pos_p(v
))
956 if (value_mone_p(v
)) {
958 } else if (!value_one_p(v
))
959 os
<< VALUE_TO_INT(v
);
962 os
<< VALUE_TO_INT(v
);
965 /* We put all possible existentially quantified variables at the back
966 * and so if any equalities exist between these variables and the
967 * other variables, then PolyLib will replace all occurrences of some
968 * of the other variables by some existentially quantified variables.
969 * We want the output to have as few as possible references to the
970 * existentially quantified variables, so we undo what PolyLib did here.
972 void resolve_existential_vars(Polyhedron
*domain
, unsigned dim
)
974 int last
= domain
->NbEq
- 1;
975 /* Matrix "view" of domain for ExchangeRows */
977 M
.NbRows
= domain
->NbConstraints
;
978 M
.NbColumns
= domain
->Dimension
+2;
979 M
.p_Init
= domain
->p_Init
;
980 M
.p
= domain
->Constraint
;
983 value_set_si(mone
, -1);
984 for (int e
= domain
->Dimension
-1; e
>= dim
; --e
) {
986 for (r
= last
; r
>= 0; --r
)
987 if (value_notzero_p(domain
->Constraint
[r
][1+e
]))
992 ExchangeRows(&M
, r
, last
);
994 /* Combine uses the coefficient as a multiplier, so it must
995 * be positive, since we are modifying an inequality.
997 if (value_neg_p(domain
->Constraint
[last
][1+e
]))
998 Vector_Scale(domain
->Constraint
[last
]+1, domain
->Constraint
[last
]+1,
999 mone
, domain
->Dimension
+1);
1001 for (int c
= 0; c
< domain
->NbConstraints
; ++c
) {
1004 if (value_notzero_p(domain
->Constraint
[c
][1+e
]))
1005 Combine(domain
->Constraint
[c
], domain
->Constraint
[last
],
1006 domain
->Constraint
[c
], 1+e
, domain
->Dimension
+1);
1013 void max_term::resolve_existential_vars() const
1015 ::resolve_existential_vars(domain
, dim
);
1018 void max_term::print(ostream
& os
, char **p
) const
1021 if (dim
< domain
->Dimension
) {
1022 resolve_existential_vars();
1023 names
= new char * [domain
->Dimension
];
1025 for (i
= 0; i
< dim
; ++i
)
1027 for ( ; i
< domain
->Dimension
; ++i
) {
1028 names
[i
] = new char[10];
1029 snprintf(names
[i
], 10, "a%d", i
- dim
);
1036 print_varlist(os
, dim
, p
);
1039 for (int i
= 0; i
< max
.size(); ++i
) {
1042 evalue_print(os
, max
[i
], p
);
1046 if (dim
< domain
->Dimension
) {
1048 print_varlist(os
, domain
->Dimension
-dim
, names
+dim
);
1051 for (int i
= 0; i
< domain
->NbConstraints
; ++i
) {
1053 int v
= First_Non_Zero(domain
->Constraint
[i
]+1, domain
->Dimension
);
1058 if (value_pos_p(domain
->Constraint
[i
][v
+1])) {
1059 print_term(os
, domain
->Constraint
[i
][v
+1], v
, domain
->Dimension
,
1061 if (value_zero_p(domain
->Constraint
[i
][0]))
1065 for (int j
= v
+1; j
<= domain
->Dimension
; ++j
) {
1066 value_oppose(tmp
, domain
->Constraint
[i
][1+j
]);
1067 print_term(os
, tmp
, j
, domain
->Dimension
,
1071 value_oppose(tmp
, domain
->Constraint
[i
][1+v
]);
1072 print_term(os
, tmp
, v
, domain
->Dimension
,
1074 if (value_zero_p(domain
->Constraint
[i
][0]))
1078 for (int j
= v
+1; j
<= domain
->Dimension
; ++j
)
1079 print_term(os
, domain
->Constraint
[i
][1+j
], j
, domain
->Dimension
,
1086 if (dim
< domain
->Dimension
) {
1087 for (int i
= dim
; i
< domain
->Dimension
; ++i
)
1093 static void evalue_substitute(evalue
*e
, evalue
**subs
)
1097 if (value_notzero_p(e
->d
))
1101 for (int i
= 0; i
< p
->size
; ++i
)
1102 evalue_substitute(&p
->arr
[i
], subs
);
1104 if (p
->type
== polynomial
)
1109 value_set_si(v
->d
, 0);
1110 v
->x
.p
= new_enode(p
->type
, 3, -1);
1111 value_clear(v
->x
.p
->arr
[0].d
);
1112 v
->x
.p
->arr
[0] = p
->arr
[0];
1113 evalue_set_si(&v
->x
.p
->arr
[1], 0, 1);
1114 evalue_set_si(&v
->x
.p
->arr
[2], 1, 1);
1117 int offset
= type_offset(p
);
1119 for (int i
= p
->size
-1; i
>= offset
+1; i
--) {
1120 emul(v
, &p
->arr
[i
]);
1121 eadd(&p
->arr
[i
], &p
->arr
[i
-1]);
1122 free_evalue_refs(&(p
->arr
[i
]));
1125 if (p
->type
!= polynomial
) {
1126 free_evalue_refs(v
);
1131 *e
= p
->arr
[offset
];
1135 /* "align" matrix to have nrows by inserting
1136 * the necessary number of rows and an equal number of columns at the end
1137 * right before the constant row/column
1139 static Matrix
*align_matrix_initial(Matrix
*M
, int nrows
)
1142 int newrows
= nrows
- M
->NbRows
;
1143 Matrix
*M2
= Matrix_Alloc(nrows
, newrows
+ M
->NbColumns
);
1144 for (i
= 0; i
< newrows
; ++i
)
1145 value_set_si(M2
->p
[M
->NbRows
-1+i
][M
->NbColumns
-1+i
], 1);
1146 for (i
= 0; i
< M
->NbRows
-1; ++i
) {
1147 Vector_Copy(M
->p
[i
], M2
->p
[i
], M
->NbColumns
-1);
1148 value_assign(M2
->p
[i
][M2
->NbColumns
-1], M
->p
[i
][M
->NbColumns
-1]);
1150 value_assign(M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1],
1151 M
->p
[M
->NbRows
-1][M
->NbColumns
-1]);
1155 /* T maps the compressed parameters to the original parameters,
1156 * while this max_term is based on the compressed parameters
1157 * and we want get the original parameters back.
1159 void max_term::substitute(Matrix
*T
, unsigned MaxRays
)
1161 int nexist
= domain
->Dimension
- (T
->NbColumns
-1);
1162 Matrix
*M
= align_matrix_initial(T
, T
->NbRows
+nexist
);
1164 Polyhedron
*D
= DomainImage(domain
, M
, MaxRays
);
1165 Polyhedron_Free(domain
);
1169 assert(T
->NbRows
== T
->NbColumns
);
1170 Matrix
*T2
= Matrix_Copy(T
);
1171 Matrix
*inv
= Matrix_Alloc(T
->NbColumns
, T
->NbRows
);
1172 int ok
= Matrix_Inverse(T2
, inv
);
1177 value_init(denom
.d
);
1178 value_init(denom
.x
.n
);
1179 value_set_si(denom
.x
.n
, 1);
1180 value_assign(denom
.d
, inv
->p
[inv
->NbRows
-1][inv
->NbColumns
-1]);
1183 v
.SetLength(inv
->NbColumns
);
1184 evalue
* subs
[inv
->NbRows
-1];
1185 for (int i
= 0; i
< inv
->NbRows
-1; ++i
) {
1186 values2zz(inv
->p
[i
], v
, v
.length());
1187 subs
[i
] = multi_monom(v
);
1188 emul(&denom
, subs
[i
]);
1190 free_evalue_refs(&denom
);
1192 for (int i
= 0; i
< max
.size(); ++i
) {
1193 evalue_substitute(max
[i
], subs
);
1194 reduce_evalue(max
[i
]);
1197 for (int i
= 0; i
< inv
->NbRows
-1; ++i
) {
1198 free_evalue_refs(subs
[i
]);
1204 int Last_Non_Zero(Value
*p
, unsigned len
)
1206 for (int i
= len
-1; i
>= 0; --i
)
1207 if (value_notzero_p(p
[i
]))
1212 static void SwapColumns(Value
**V
, int n
, int i
, int j
)
1214 for (int r
= 0; r
< n
; ++r
)
1215 value_swap(V
[r
][i
], V
[r
][j
]);
1218 static void SwapColumns(Polyhedron
*P
, int i
, int j
)
1220 SwapColumns(P
->Constraint
, P
->NbConstraints
, i
, j
);
1221 SwapColumns(P
->Ray
, P
->NbRays
, i
, j
);
1224 bool in_domain(Polyhedron
*P
, Value
*val
, unsigned dim
, unsigned MaxRays
)
1226 int nexist
= P
->Dimension
- dim
;
1227 int last
[P
->NbConstraints
];
1228 Value tmp
, min
, max
;
1229 Vector
*all_val
= Vector_Alloc(P
->Dimension
+1);
1234 resolve_existential_vars(P
, dim
);
1236 Vector_Copy(val
, all_val
->p
, dim
);
1237 value_set_si(all_val
->p
[P
->Dimension
], 1);
1240 for (int i
= 0; i
< P
->NbConstraints
; ++i
) {
1241 last
[i
] = Last_Non_Zero(P
->Constraint
[i
]+1+dim
, nexist
);
1242 if (last
[i
] == -1) {
1243 Inner_Product(P
->Constraint
[i
]+1, all_val
->p
, P
->Dimension
+1, &tmp
);
1244 if (value_neg_p(tmp
))
1246 if (i
< P
->NbEq
&& value_pos_p(tmp
))
1253 alternate
= nexist
- 1;
1254 for (i
= 0; i
< nexist
; ++i
) {
1255 bool min_set
= false;
1256 bool max_set
= false;
1257 for (int j
= 0; j
< P
->NbConstraints
; ++j
) {
1260 Inner_Product(P
->Constraint
[j
]+1, all_val
->p
, P
->Dimension
+1, &tmp
);
1261 value_oppose(tmp
, tmp
);
1263 if (!mpz_divisible_p(tmp
, P
->Constraint
[j
][1+dim
+i
]))
1265 value_division(tmp
, tmp
, P
->Constraint
[j
][1+dim
+i
]);
1266 if (!max_set
|| value_lt(tmp
, max
)) {
1268 value_assign(max
, tmp
);
1270 if (!min_set
|| value_gt(tmp
, min
)) {
1272 value_assign(min
, tmp
);
1275 if (value_pos_p(P
->Constraint
[j
][1+dim
+i
])) {
1276 mpz_cdiv_q(tmp
, tmp
, P
->Constraint
[j
][1+dim
+i
]);
1277 if (!min_set
|| value_gt(tmp
, min
)) {
1279 value_assign(min
, tmp
);
1282 mpz_fdiv_q(tmp
, tmp
, P
->Constraint
[j
][1+dim
+i
]);
1283 if (!max_set
|| value_lt(tmp
, max
)) {
1285 value_assign(max
, tmp
);
1290 /* Move another existential variable in current position */
1291 if (!max_set
|| !min_set
) {
1292 if (!(alternate
> i
)) {
1293 Matrix
*M
= Matrix_Alloc(dim
+i
, 1+P
->Dimension
+1);
1294 for (int j
= 0; j
< dim
+i
; ++j
) {
1295 value_set_si(M
->p
[j
][1+j
], -1);
1296 value_assign(M
->p
[j
][1+P
->Dimension
], all_val
->p
[j
]);
1298 Polyhedron
*Q
= AddConstraints(M
->p
[0], dim
+i
, P
, MaxRays
);
1300 Q
= DomainConstraintSimplify(Q
, MaxRays
);
1301 Vector
*sample
= Polyhedron_Sample(Q
, MaxRays
);
1304 Vector_Free(sample
);
1308 assert(alternate
> i
);
1309 SwapColumns(P
, 1+dim
+i
, 1+dim
+alternate
);
1310 resolve_existential_vars(P
, dim
);
1311 for (int j
= 0; j
< P
->NbConstraints
; ++j
) {
1312 if (j
>= P
->NbEq
&& last
[j
] < i
)
1314 last
[j
] = Last_Non_Zero(P
->Constraint
[j
]+1+dim
, nexist
);
1316 Inner_Product(P
->Constraint
[j
]+1, all_val
->p
, P
->Dimension
+1,
1318 if (value_neg_p(tmp
))
1320 if (j
< P
->NbEq
&& value_pos_p(tmp
))
1328 assert(max_set
&& min_set
);
1329 if (value_lt(max
, min
))
1331 if (value_ne(max
, min
)) {
1332 Matrix
*M
= Matrix_Alloc(dim
+i
, 1+P
->Dimension
+1);
1333 for (int j
= 0; j
< dim
+i
; ++j
) {
1334 value_set_si(M
->p
[j
][1+j
], -1);
1335 value_assign(M
->p
[j
][1+P
->Dimension
], all_val
->p
[j
]);
1337 Polyhedron
*Q
= AddConstraints(M
->p
[0], dim
+i
, P
, MaxRays
);
1339 Q
= DomainConstraintSimplify(Q
, MaxRays
);
1340 Vector
*sample
= Polyhedron_Sample(Q
, MaxRays
);
1343 Vector_Free(sample
);
1347 assert(value_eq(max
, min
));
1348 value_assign(all_val
->p
[dim
+i
], max
);
1349 alternate
= nexist
- 1;
1356 Vector_Free(all_val
);
1358 return in
|| (P
->next
&& in_domain(P
->next
, val
, dim
, MaxRays
));
1361 void compute_evalue(evalue
*e
, Value
*val
, Value
*res
)
1363 double d
= compute_evalue(e
, val
);
1368 value_set_double(*res
, d
);
1371 Vector
*max_term::eval(Value
*val
, unsigned MaxRays
) const
1373 if (dim
== domain
->Dimension
) {
1374 if (!in_domain(domain
, val
))
1377 if (!in_domain(domain
, val
, dim
, MaxRays
))
1380 Vector
*res
= Vector_Alloc(max
.size());
1381 for (int i
= 0; i
< max
.size(); ++i
) {
1382 compute_evalue(max
[i
], val
, &res
->p
[i
]);
1387 static Matrix
*add_ge_constraint(EDomain
*ED
, evalue
*constraint
,
1388 vector
<evalue
*>& new_floors
)
1390 Polyhedron
*D
= ED
->D
;
1393 evalue_set_si(&mone
, -1, 1);
1395 for (evalue
*e
= constraint
; value_zero_p(e
->d
);
1396 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)]) {
1398 if (e
->x
.p
->type
!= fractional
)
1400 for (i
= 0; i
< ED
->floors
.size(); ++i
)
1401 if (eequal(&e
->x
.p
->arr
[0], ED
->floors
[i
]))
1403 if (i
< ED
->floors
.size())
1408 int rows
= D
->NbConstraints
+2*fract
+1;
1409 int cols
= 2+D
->Dimension
+fract
;
1410 Matrix
*M
= Matrix_Alloc(rows
, cols
);
1411 for (int i
= 0; i
< D
->NbConstraints
; ++i
) {
1412 Vector_Copy(D
->Constraint
[i
], M
->p
[i
], 1+D
->Dimension
);
1413 value_assign(M
->p
[i
][1+D
->Dimension
+fract
],
1414 D
->Constraint
[i
][1+D
->Dimension
]);
1416 value_set_si(M
->p
[rows
-1][0], 1);
1419 for (e
= constraint
; value_zero_p(e
->d
); e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)]) {
1420 if (e
->x
.p
->type
== fractional
) {
1423 i
= ED
->find_floor(&e
->x
.p
->arr
[0]);
1425 pos
= D
->Dimension
-ED
->floors
.size()+i
;
1427 pos
= D
->Dimension
+fract
;
1429 add_fract(e
, M
->p
[rows
-1], cols
, 1+pos
);
1431 if (pos
< D
->Dimension
)
1434 /* constraints for the new floor */
1435 int row
= D
->NbConstraints
+2*fract
;
1436 value_set_si(M
->p
[row
][0], 1);
1437 evalue2constraint_r(NULL
, &e
->x
.p
->arr
[0], M
->p
[row
], cols
);
1438 value_oppose(M
->p
[row
][1+D
->Dimension
+fract
], M
->p
[row
][0]);
1439 value_set_si(M
->p
[row
][0], 1);
1441 Vector_Scale(M
->p
[row
]+1, M
->p
[row
+1]+1, mone
.x
.n
, cols
-1);
1442 value_set_si(M
->p
[row
+1][0], 1);
1443 value_addto(M
->p
[row
+1][cols
-1], M
->p
[row
+1][cols
-1],
1444 M
->p
[row
+1][1+D
->Dimension
+fract
]);
1445 value_decrement(M
->p
[row
+1][cols
-1], M
->p
[row
+1][cols
-1]);
1447 evalue
*arg
= new evalue
;
1449 evalue_copy(arg
, &e
->x
.p
->arr
[0]);
1450 new_floors
.push_back(arg
);
1454 assert(e
->x
.p
->type
== polynomial
);
1455 assert(e
->x
.p
->size
== 2);
1456 add_coeff(M
->p
[rows
-1], cols
, &e
->x
.p
->arr
[1], e
->x
.p
->pos
);
1459 add_coeff(M
->p
[rows
-1], cols
, e
, cols
-1);
1460 value_set_si(M
->p
[rows
-1][0], 1);
1461 free_evalue_refs(&mone
);
1465 Polyhedron
*unfringe (Polyhedron
*P
, unsigned MaxRays
)
1467 int len
= P
->Dimension
+2;
1468 Polyhedron
*T
, *R
= P
;
1471 Vector
*row
= Vector_Alloc(len
);
1472 value_set_si(row
->p
[0], 1);
1474 R
= DomainConstraintSimplify(Polyhedron_Copy(P
), MaxRays
);
1476 Matrix
*M
= Matrix_Alloc(2, len
-1);
1477 value_set_si(M
->p
[1][len
-2], 1);
1478 for (int v
= 0; v
< P
->Dimension
; ++v
) {
1479 value_set_si(M
->p
[0][v
], 1);
1480 Polyhedron
*I
= Polyhedron_Image(R
, M
, 2+1);
1481 value_set_si(M
->p
[0][v
], 0);
1482 for (int r
= 0; r
< I
->NbConstraints
; ++r
) {
1483 if (value_zero_p(I
->Constraint
[r
][0]))
1485 if (value_zero_p(I
->Constraint
[r
][1]))
1487 if (value_one_p(I
->Constraint
[r
][1]))
1489 if (value_mone_p(I
->Constraint
[r
][1]))
1491 value_absolute(g
, I
->Constraint
[r
][1]);
1492 Vector_Set(row
->p
+1, 0, len
-2);
1493 value_division(row
->p
[1+v
], I
->Constraint
[r
][1], g
);
1494 mpz_fdiv_q(row
->p
[len
-1], I
->Constraint
[r
][2], g
);
1496 R
= AddConstraints(row
->p
, 1, R
, MaxRays
);
1508 static Matrix
*remove_equalities(Polyhedron
**P
, unsigned nparam
, unsigned MaxRays
);
1510 Vector
*Polyhedron_not_empty(Polyhedron
*P
, unsigned MaxRays
)
1512 Polyhedron
*Porig
= P
;
1513 Vector
*sample
= NULL
;
1515 POL_ENSURE_VERTICES(P
);
1519 for (int i
= 0; i
< P
->NbRays
; ++i
)
1520 if (value_one_p(P
->Ray
[i
][1+P
->Dimension
])) {
1521 sample
= Vector_Alloc(P
->Dimension
+ 1);
1522 Vector_Copy(P
->Ray
[i
]+1, sample
->p
, P
->Dimension
+1);
1526 Matrix
*T
= remove_equalities(&P
, 0, MaxRays
);
1528 sample
= Polyhedron_Sample(P
, MaxRays
);
1531 Vector
*P_sample
= Vector_Alloc(Porig
->Dimension
+ 1);
1532 Matrix_Vector_Product(T
, sample
->p
, P_sample
->p
);
1533 Vector_Free(sample
);
1547 enum sign
{ le
, ge
, lge
} sign
;
1549 split (evalue
*c
, enum sign s
) : constraint(c
), sign(s
) {}
1552 static void split_on(const split
& sp
, EDomain
*D
,
1553 EDomain
**Dlt
, EDomain
**Deq
, EDomain
**Dgt
,
1557 EDomain
*EDlt
= NULL
, *EDeq
= NULL
, *EDgt
= NULL
;
1561 value_set_si(mone
, -1);
1565 vector
<evalue
*> new_floors
;
1566 M
= add_ge_constraint(D
, sp
.constraint
, new_floors
);
1567 if (sp
.sign
== split::lge
|| sp
.sign
== split::ge
) {
1568 M2
= Matrix_Copy(M
);
1569 value_decrement(M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1],
1570 M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1]);
1571 D2
= Constraints2Polyhedron(M2
, MaxRays
);
1572 EDgt
= new EDomain(D2
, D
, new_floors
);
1573 Polyhedron_Free(D2
);
1576 if (sp
.sign
== split::lge
|| sp
.sign
== split::le
) {
1577 M2
= Matrix_Copy(M
);
1578 Vector_Scale(M2
->p
[M2
->NbRows
-1]+1, M2
->p
[M2
->NbRows
-1]+1,
1579 mone
, M2
->NbColumns
-1);
1580 value_decrement(M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1],
1581 M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1]);
1582 D2
= Constraints2Polyhedron(M2
, MaxRays
);
1583 EDlt
= new EDomain(D2
, D
, new_floors
);
1584 Polyhedron_Free(D2
);
1588 assert(sp
.sign
== split::lge
|| sp
.sign
== split::ge
|| sp
.sign
== split::le
);
1589 value_set_si(M
->p
[M
->NbRows
-1][0], 0);
1590 D2
= Constraints2Polyhedron(M
, MaxRays
);
1591 EDeq
= new EDomain(D2
, D
, new_floors
);
1592 Polyhedron_Free(D2
);
1595 Vector
*sample
= D
->sample
;
1596 if (sample
&& new_floors
.size() > 0) {
1597 assert(sample
->Size
== D
->D
->Dimension
+1);
1598 sample
= Vector_Alloc(D
->D
->Dimension
+new_floors
.size()+1);
1599 Vector_Copy(D
->sample
->p
, sample
->p
, D
->D
->Dimension
);
1600 value_set_si(sample
->p
[D
->D
->Dimension
+new_floors
.size()], 1);
1601 for (int i
= 0; i
< new_floors
.size(); ++i
)
1602 compute_evalue(new_floors
[i
], sample
->p
, sample
->p
+D
->D
->Dimension
+i
);
1605 for (int i
= 0; i
< new_floors
.size(); ++i
) {
1606 free_evalue_refs(new_floors
[i
]);
1607 delete new_floors
[i
];
1611 if (sample
&& in_domain(EDeq
->D
, sample
->p
, sample
->Size
-1, MaxRays
)) {
1612 EDeq
->sample
= Vector_Alloc(sample
->Size
);
1613 Vector_Copy(sample
->p
, EDeq
->sample
->p
, sample
->Size
);
1614 } else if (!(EDeq
->sample
= Polyhedron_not_empty(EDeq
->D
, MaxRays
))) {
1620 if (sample
&& in_domain(EDgt
->D
, sample
->p
, sample
->Size
-1, MaxRays
)) {
1621 EDgt
->sample
= Vector_Alloc(sample
->Size
);
1622 Vector_Copy(sample
->p
, EDgt
->sample
->p
, sample
->Size
);
1623 } else if (!(EDgt
->sample
= Polyhedron_not_empty(EDgt
->D
, MaxRays
))) {
1629 if (sample
&& in_domain(EDlt
->D
, sample
->p
, sample
->Size
-1, MaxRays
)) {
1630 EDlt
->sample
= Vector_Alloc(sample
->Size
);
1631 Vector_Copy(sample
->p
, EDlt
->sample
->p
, sample
->Size
);
1632 } else if (!(EDlt
->sample
= Polyhedron_not_empty(EDlt
->D
, MaxRays
))) {
1641 if (sample
!= D
->sample
)
1642 Vector_Free(sample
);
1645 ostream
& operator<< (ostream
& os
, const vector
<int> & v
)
1648 for (int i
= 0; i
< v
.size(); ++i
) {
1658 * Project on first dim dimensions
1660 Polyhedron
* Polyhedron_Project_Initial(Polyhedron
*P
, int dim
)
1666 if (P
->Dimension
== dim
)
1667 return Polyhedron_Copy(P
);
1669 T
= Matrix_Alloc(dim
+1, P
->Dimension
+1);
1670 for (i
= 0; i
< dim
; ++i
)
1671 value_set_si(T
->p
[i
][i
], 1);
1672 value_set_si(T
->p
[dim
][P
->Dimension
], 1);
1673 I
= Polyhedron_Image(P
, T
, P
->NbConstraints
);
1678 static vector
<max_term
*> lexmin(indicator
& ind
, EDomain
*D
, unsigned nparam
,
1679 unsigned MaxRays
, vector
<int> loc
)
1681 vector
<max_term
*> maxima
;
1682 int len
= 1 + D
->D
->Dimension
+ 1;
1688 evalue_set_si(&mone
, -1, 1);
1692 Vector
*c
= Vector_Alloc(len
);
1693 Matrix
*T
= Matrix_Alloc(2, len
-1);
1694 for (int i
= 0; i
< ind
.term
.size(); ++i
) {
1695 bool restart
= false; /* true if we have modified ind from i up */
1696 bool stop
= false; /* true if i can never be smallest */
1697 int peel
= -1; /* term to peel against */
1698 vector
<split
> splits
;
1699 if (ind
.term
[i
]->sign
< 0)
1701 int dim
= ind
.term
[i
]->den
.NumCols();
1703 for (j
= 0; j
< ind
.term
.size(); ++j
) {
1707 for (k
= 0; k
< dim
; ++k
) {
1708 /* compute ind.term->[i]->vertex[k] - ind.term->[j]->vertex[k] */
1709 evalue
*diff
= new evalue
;
1710 value_init(diff
->d
);
1711 evalue_copy(diff
, ind
.term
[j
]->vertex
[k
]);
1713 eadd(ind
.term
[i
]->vertex
[k
], diff
);
1714 reduce_evalue(diff
);
1715 int fract
= evalue2constraint(D
, diff
, c
->p
, len
);
1716 Vector_Copy(c
->p
+1, T
->p
[0], len
-1);
1717 value_assign(T
->p
[1][len
-2], c
->p
[0]);
1720 interval_minmax(D
->D
, T
, &min
, &max
, MaxRays
);
1722 free_evalue_refs(diff
);
1728 evalue2constraint(D
, diff
, c
->p
, len
);
1730 Vector_Copy(c
->p
+1, T
->p
[0], len
-1);
1731 value_assign(T
->p
[1][len
-2], c
->p
[0]);
1734 interval_minmax(D
->D
, T
, &negmin
, &negmax
, MaxRays
);
1738 free_evalue_refs(diff
);
1743 if (max
== 0 && min
== 0) {
1744 if (!EVALUE_IS_ZERO(*diff
)) {
1745 ind
.substitute(diff
);
1749 free_evalue_refs(diff
);
1755 if (min
< 0 && max
== 0)
1756 splits
.push_back(split(diff
, split::le
));
1757 else if (max
> 0 && min
== 0)
1758 splits
.push_back(split(diff
, split::ge
));
1760 splits
.push_back(split(diff
, split::lge
));
1763 if (k
== dim
&& ind
.term
[j
]->sign
< 0)
1765 if (stop
|| restart
)
1769 /* The ith entry may have been removed, so we have to consider
1773 for (j
= 0; j
< splits
.size(); ++j
) {
1774 free_evalue_refs(splits
[j
].constraint
);
1775 delete splits
[j
].constraint
;
1780 for (j
= 0; j
< splits
.size(); ++j
) {
1781 free_evalue_refs(splits
[j
].constraint
);
1782 delete splits
[j
].constraint
;
1787 // ind.peel(i, peel);
1788 ind
.combine(i
, peel
);
1790 i
= -1; /* start over */
1791 for (j
= 0; j
< splits
.size(); ++j
) {
1792 free_evalue_refs(splits
[j
].constraint
);
1793 delete splits
[j
].constraint
;
1797 if (splits
.size() != 0) {
1798 for (j
= 0; j
< splits
.size(); ++j
)
1799 if (splits
[j
].sign
== split::le
)
1801 if (j
== splits
.size())
1803 EDomain
*Dlt
, *Deq
, *Dgt
;
1804 split_on(splits
[j
], D
, &Dlt
, &Deq
, &Dgt
, MaxRays
);
1805 assert(Dlt
|| Deq
|| Dgt
);
1808 indicator
indeq(ind
);
1809 indeq
.substitute(splits
[j
].constraint
);
1810 Polyhedron
*P
= Polyhedron_Project_Initial(Deq
->D
, nparam
);
1811 P
= DomainConstraintSimplify(P
, MaxRays
);
1812 indeq
.reduce_in_domain(P
);
1815 vector
<max_term
*> maxeq
= lexmin(indeq
, Deq
, nparam
,
1817 maxima
.insert(maxima
.end(), maxeq
.begin(), maxeq
.end());
1823 indicator
indgt(ind
);
1824 Polyhedron
*P
= Polyhedron_Project_Initial(Dgt
->D
, nparam
);
1825 P
= DomainConstraintSimplify(P
, MaxRays
);
1826 indgt
.reduce_in_domain(P
);
1829 vector
<max_term
*> maxeq
= lexmin(indgt
, Dgt
, nparam
,
1831 maxima
.insert(maxima
.end(), maxeq
.begin(), maxeq
.end());
1837 Polyhedron
*P
= Polyhedron_Project_Initial(Dlt
->D
, nparam
);
1838 P
= DomainConstraintSimplify(P
, MaxRays
);
1839 ind
.reduce_in_domain(P
);
1845 if (splits
.size() > 1) {
1846 vector
<max_term
*> maxeq
= lexmin(ind
, Dlt
, nparam
,
1848 maxima
.insert(maxima
.end(), maxeq
.begin(), maxeq
.end());
1849 for (j
= 0; j
< splits
.size(); ++j
) {
1850 free_evalue_refs(splits
[j
].constraint
);
1851 delete splits
[j
].constraint
;
1856 /* the vertex turned out not to be minimal */
1857 for (j
= 0; j
< splits
.size(); ++j
) {
1858 free_evalue_refs(splits
[j
].constraint
);
1859 delete splits
[j
].constraint
;
1864 max_term
*maximum
= new max_term
;
1865 maxima
.push_back(maximum
);
1866 maximum
->dim
= nparam
;
1867 maximum
->domain
= Polyhedron_Copy(D
->D
);
1868 for (int j
= 0; j
< dim
; ++j
) {
1869 evalue
*E
= new evalue
;
1871 evalue_copy(E
, ind
.term
[i
]->vertex
[j
]);
1872 if (evalue_frac2floor_in_domain(E
, D
->D
))
1874 maximum
->max
.push_back(E
);
1883 free_evalue_refs(&mone
);
1889 static bool isTranslation(Matrix
*M
)
1892 if (M
->NbRows
!= M
->NbColumns
)
1895 for (i
= 0;i
< M
->NbRows
; i
++)
1896 for (j
= 0; j
< M
->NbColumns
-1; j
++)
1898 if(value_notone_p(M
->p
[i
][j
]))
1901 if(value_notzero_p(M
->p
[i
][j
]))
1904 return value_one_p(M
->p
[M
->NbRows
-1][M
->NbColumns
-1]);
1907 static Matrix
*compress_parameters(Polyhedron
**P
, Polyhedron
**C
,
1908 unsigned nparam
, unsigned MaxRays
)
1912 /* compress_parms doesn't like equalities that only involve parameters */
1913 for (int i
= 0; i
< (*P
)->NbEq
; ++i
)
1914 assert(First_Non_Zero((*P
)->Constraint
[i
]+1, (*P
)->Dimension
-nparam
) != -1);
1916 M
= Matrix_Alloc((*P
)->NbEq
, (*P
)->Dimension
+2);
1917 Vector_Copy((*P
)->Constraint
[0], M
->p
[0], (*P
)->NbEq
* ((*P
)->Dimension
+2));
1918 CP
= compress_parms(M
, nparam
);
1921 if (isTranslation(CP
)) {
1926 T
= align_matrix(CP
, (*P
)->Dimension
+1);
1927 *P
= Polyhedron_Preimage(*P
, T
, MaxRays
);
1930 *C
= Polyhedron_Preimage(*C
, CP
, MaxRays
);
1935 static Matrix
*remove_equalities(Polyhedron
**P
, unsigned nparam
, unsigned MaxRays
)
1937 /* Matrix "view" of equalities */
1939 M
.NbRows
= (*P
)->NbEq
;
1940 M
.NbColumns
= (*P
)->Dimension
+2;
1941 M
.p_Init
= (*P
)->p_Init
;
1942 M
.p
= (*P
)->Constraint
;
1944 Matrix
*T
= compress_variables(&M
, nparam
);
1950 if (isIdentity(T
)) {
1954 *P
= Polyhedron_Preimage(*P
, T
, MaxRays
);
1959 static vector
<max_term
*> lexmin(Polyhedron
*P
, Polyhedron
*C
, unsigned MaxRays
)
1961 unsigned nparam
= C
->Dimension
;
1962 Param_Polyhedron
*PP
= NULL
;
1963 Polyhedron
*CEq
= NULL
, *pVD
;
1965 Matrix
*T
= NULL
, *CP
= NULL
;
1966 Param_Domain
*D
, *next
;
1968 Polyhedron
*Porig
= P
;
1969 Polyhedron
*Corig
= C
;
1971 vector
<max_term
*> all_max
;
1977 POL_ENSURE_VERTICES(P
);
1982 assert(P
->NbBid
== 0);
1986 CP
= compress_parameters(&P
, &C
, nparam
, MaxRays
);
1988 T
= remove_equalities(&P
, nparam
, MaxRays
);
1989 if (P
!= Q
&& Q
!= Porig
)
1999 PP
= Polyhedron2Param_SimplifiedDomain(&P
,C
,
2000 (MaxRays
& POL_NO_DUAL
) ? 0 : MaxRays
,
2002 if (P
!= Q
&& Q
!= Porig
)
2006 if (isIdentity(CT
)) {
2010 nparam
= CT
->NbRows
- 1;
2013 unsigned dim
= P
->Dimension
- nparam
;
2016 for (nd
= 0, D
=PP
->D
; D
; ++nd
, D
=D
->next
);
2017 Polyhedron
**fVD
= new Polyhedron
*[nd
];
2019 indicator_constructor
ic(P
, dim
, PP
->nbV
);
2021 for (i
= 0, V
= PP
->V
; V
; V
= V
->next
, i
++) {
2022 ic
.decompose_at_vertex(V
, i
, MaxRays
);
2029 for (nd
= 0, D
=PP
->D
; D
; D
=next
) {
2032 Polyhedron
*rVD
= reduce_domain(D
->Domain
, CT
, CEq
,
2037 pVD
= CT
? DomainImage(rVD
,CT
,MaxRays
) : rVD
;
2041 FORALL_PVertex_in_ParamPolyhedron(V
,D
,PP
) // _i is internal counter
2042 for (int j
= 0; j
< ic
.terms
[_i
].size(); ++j
) {
2043 indicator_term
*term
= new indicator_term(*ic
.terms
[_i
][j
]);
2044 term
->reduce_in_domain(pVD
);
2045 ind
.term
.push_back(term
);
2047 END_FORALL_PVertex_in_ParamPolyhedron
;
2053 vector
<max_term
*> maxima
= lexmin(ind
, &epVD
, nparam
, MaxRays
, loc
);
2055 for (int j
= 0; j
< maxima
.size(); ++j
)
2056 maxima
[j
]->substitute(CP
, MaxRays
);
2057 all_max
.insert(all_max
.end(), maxima
.begin(), maxima
.end());
2068 Param_Polyhedron_Free(PP
);
2070 Polyhedron_Free(CEq
);
2071 for (--nd
; nd
>= 0; --nd
) {
2072 Domain_Free(fVD
[nd
]);
2083 static void verify_results(Polyhedron
*A
, Polyhedron
*C
,
2084 vector
<max_term
*>& maxima
, int m
, int M
,
2085 int print_all
, unsigned MaxRays
);
2087 int main(int argc
, char **argv
)
2092 char **iter_names
, **param_names
;
2097 int m
= INT_MAX
, M
= INT_MIN
, r
;
2098 int print_solution
= 1;
2100 while ((c
= getopt_long(argc
, argv
, "TAm:M:r:V", options
, &ind
)) != -1) {
2122 printf(barvinok_version());
2129 C
= Constraints2Polyhedron(MA
, MAXRAYS
);
2131 fscanf(stdin
, " %d", &bignum
);
2132 assert(bignum
== -1);
2134 A
= Constraints2Polyhedron(MA
, MAXRAYS
);
2137 if (A
->Dimension
>= VBIGDIM
)
2139 else if (A
->Dimension
>= BIGDIM
)
2148 if (verify
&& m
> M
) {
2149 fprintf(stderr
,"Nothing to do: min > max !\n");
2155 iter_names
= util_generate_names(A
->Dimension
- C
->Dimension
, "i");
2156 param_names
= util_generate_names(C
->Dimension
, "p");
2157 if (print_solution
) {
2158 Polyhedron_Print(stdout
, P_VALUE_FMT
, A
);
2159 Polyhedron_Print(stdout
, P_VALUE_FMT
, C
);
2161 vector
<max_term
*> maxima
= lexmin(A
, C
, MAXRAYS
);
2163 for (int i
= 0; i
< maxima
.size(); ++i
)
2164 maxima
[i
]->print(cout
, param_names
);
2167 verify_results(A
, C
, maxima
, m
, M
, print_all
, MAXRAYS
);
2169 for (int i
= 0; i
< maxima
.size(); ++i
)
2172 util_free_names(A
->Dimension
- C
->Dimension
, iter_names
);
2173 util_free_names(C
->Dimension
, param_names
);
2180 static bool lexmin(int pos
, Polyhedron
*P
, Value
*context
)
2189 value_init(LB
); value_init(UB
); value_init(k
);
2192 lu_flags
= lower_upper_bounds(pos
,P
,context
,&LB
,&UB
);
2193 assert(!(lu_flags
& LB_INFINITY
));
2195 value_set_si(context
[pos
],0);
2196 if (!lu_flags
&& value_lt(UB
,LB
)) {
2197 value_clear(LB
); value_clear(UB
); value_clear(k
);
2201 value_assign(context
[pos
], LB
);
2202 value_clear(LB
); value_clear(UB
); value_clear(k
);
2205 for (value_assign(k
,LB
); lu_flags
|| value_le(k
,UB
); value_increment(k
,k
)) {
2206 value_assign(context
[pos
],k
);
2207 if ((found
= lexmin(pos
+1, P
->next
, context
)))
2211 value_set_si(context
[pos
],0);
2212 value_clear(LB
); value_clear(UB
); value_clear(k
);
2216 static void print_list(FILE *out
, Value
*z
, char* brackets
, int len
)
2218 fprintf(out
, "%c", brackets
[0]);
2219 value_print(out
, VALUE_FMT
,z
[0]);
2220 for (int k
= 1; k
< len
; ++k
) {
2222 value_print(out
, VALUE_FMT
,z
[k
]);
2224 fprintf(out
, "%c", brackets
[1]);
2227 static int check_poly(Polyhedron
*S
, Polyhedron
*CS
, vector
<max_term
*>& maxima
,
2228 int nparam
, int pos
, Value
*z
, int print_all
, int st
,
2231 if (pos
== nparam
) {
2233 bool found
= lexmin(1, S
, z
);
2237 print_list(stdout
, z
+S
->Dimension
-nparam
+1, "()", nparam
);
2240 print_list(stdout
, z
+1, "[]", S
->Dimension
-nparam
);
2245 for (int i
= 0; i
< maxima
.size(); ++i
)
2246 if ((min
= maxima
[i
]->eval(z
+S
->Dimension
-nparam
+1, MaxRays
)))
2249 int ok
= !(found
^ !!min
);
2251 for (int i
= 0; i
< S
->Dimension
-nparam
; ++i
)
2252 if (value_ne(z
[1+i
], min
->p
[i
])) {
2259 fprintf(stderr
, "Error !\n");
2260 fprintf(stderr
, "lexmin");
2261 print_list(stderr
, z
+S
->Dimension
-nparam
+1, "()", nparam
);
2262 fprintf(stderr
, " should be ");
2264 print_list(stderr
, z
+1, "[]", S
->Dimension
-nparam
);
2265 fprintf(stderr
, " while digging gives ");
2267 print_list(stderr
, min
->p
, "[]", S
->Dimension
-nparam
);
2268 fprintf(stderr
, ".\n");
2270 } else if (print_all
)
2275 for (k
= 1; k
<= S
->Dimension
-nparam
; ++k
)
2276 value_set_si(z
[k
], 0);
2284 !(lower_upper_bounds(1+pos
, CS
, &z
[S
->Dimension
-nparam
], &LB
, &UB
));
2285 for (value_assign(tmp
,LB
); value_le(tmp
,UB
); value_increment(tmp
,tmp
)) {
2287 int k
= VALUE_TO_INT(tmp
);
2288 if (!pos
&& !(k
%st
)) {
2293 value_assign(z
[pos
+S
->Dimension
-nparam
+1],tmp
);
2294 if (!check_poly(S
, CS
->next
, maxima
, nparam
, pos
+1, z
, print_all
, st
,
2302 value_set_si(z
[pos
+S
->Dimension
-nparam
+1],0);
2310 void verify_results(Polyhedron
*A
, Polyhedron
*C
, vector
<max_term
*>& maxima
,
2311 int m
, int M
, int print_all
, unsigned MaxRays
)
2313 Polyhedron
*CC
, *CC2
, *CS
, *S
;
2314 unsigned nparam
= C
->Dimension
;
2319 CC
= Polyhedron_Project(A
, nparam
);
2320 CC2
= DomainIntersection(C
, CC
, MAXRAYS
);
2324 /* Intersect context with range */
2329 MM
= Matrix_Alloc(2*C
->Dimension
, C
->Dimension
+2);
2330 for (int i
= 0; i
< C
->Dimension
; ++i
) {
2331 value_set_si(MM
->p
[2*i
][0], 1);
2332 value_set_si(MM
->p
[2*i
][1+i
], 1);
2333 value_set_si(MM
->p
[2*i
][1+C
->Dimension
], -m
);
2334 value_set_si(MM
->p
[2*i
+1][0], 1);
2335 value_set_si(MM
->p
[2*i
+1][1+i
], -1);
2336 value_set_si(MM
->p
[2*i
+1][1+C
->Dimension
], M
);
2338 CC2
= AddConstraints(MM
->p
[0], 2*CC
->Dimension
, CC
, MAXRAYS
);
2339 U
= Universe_Polyhedron(0);
2340 CS
= Polyhedron_Scan(CC2
, U
, MAXRAYS
& POL_NO_DUAL
? 0 : MAXRAYS
);
2342 Polyhedron_Free(CC2
);
2347 p
= ALLOCN(Value
, A
->Dimension
+2);
2348 for (i
=0; i
<= A
->Dimension
; i
++) {
2350 value_set_si(p
[i
],0);
2353 value_set_si(p
[i
], 1);
2355 S
= Polyhedron_Scan(A
, C
, MAXRAYS
& POL_NO_DUAL
? 0 : MAXRAYS
);
2357 if (!print_all
&& C
->Dimension
> 0) {
2362 for (int i
= m
; i
<= M
; i
+= st
)
2369 if (!(CS
&& emptyQ2(CS
)))
2370 check_poly(S
, CS
, maxima
, nparam
, 0, p
, print_all
, st
, MaxRays
);
2377 for (i
=0; i
<= (A
->Dimension
+1); i
++)
2382 Polyhedron_Free(CC
);