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 "conversion.h"
13 #include "decomposer.h"
14 #include "lattice_point.h"
15 #include "reduce_domain.h"
19 #include "evalue_util.h"
20 #include "remove_equalities.h"
35 /* RANGE : normal range for evalutations (-RANGE -> RANGE) */
38 /* SRANGE : small range for evalutations */
41 /* if dimension >= BIDDIM, use SRANGE */
44 /* VSRANGE : very small range for evalutations */
47 /* if dimension >= VBIDDIM, use VSRANGE */
50 #define EMPTINESS_CHECK 256
51 #define BASIS_REDUCTION_CDD 257
52 #define NO_REDUCTION 258
55 #define getopt_long(a,b,c,d,e) getopt(a,b,c)
58 struct option lexmin_options
[] = {
59 { "verify", no_argument
, 0, 'T' },
60 { "print-all", no_argument
, 0, 'A' },
61 { "emptiness-check", required_argument
, 0, EMPTINESS_CHECK
},
62 { "no-reduction", no_argument
, 0, NO_REDUCTION
},
63 { "cdd", no_argument
, 0, BASIS_REDUCTION_CDD
},
64 { "polysign", required_argument
, 0, POLYSIGN
},
65 { "min", required_argument
, 0, 'm' },
66 { "max", required_argument
, 0, 'M' },
67 { "range", required_argument
, 0, 'r' },
68 { "version", no_argument
, 0, 'V' },
73 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
75 static int type_offset(enode
*p
)
77 return p
->type
== fractional
? 1 :
78 p
->type
== flooring
? 1 : 0;
81 void compute_evalue(evalue
*e
, Value
*val
, Value
*res
)
83 double d
= compute_evalue(e
, val
);
88 value_set_double(*res
, d
);
91 struct indicator_term
{
93 int pos
; /* number of rational vertex */
94 int n
; /* number of cone associated to given rational vertex */
98 indicator_term(unsigned dim
, int pos
) {
100 vertex
= new evalue
* [dim
];
105 indicator_term(unsigned dim
, int pos
, int n
) {
106 den
.SetDims(dim
, dim
);
107 vertex
= new evalue
* [dim
];
111 indicator_term(const indicator_term
& src
) {
116 unsigned dim
= den
.NumCols();
117 vertex
= new evalue
* [dim
];
118 for (int i
= 0; i
< dim
; ++i
) {
119 vertex
[i
] = new evalue();
120 value_init(vertex
[i
]->d
);
121 evalue_copy(vertex
[i
], src
.vertex
[i
]);
124 void swap(indicator_term
*other
) {
126 tmp
= sign
; sign
= other
->sign
; other
->sign
= tmp
;
127 tmp
= pos
; pos
= other
->pos
; other
->pos
= tmp
;
128 tmp
= n
; n
= other
->n
; other
->n
= tmp
;
129 mat_ZZ tmp_den
= den
; den
= other
->den
; other
->den
= tmp_den
;
130 unsigned dim
= den
.NumCols();
131 for (int i
= 0; i
< dim
; ++i
) {
132 evalue
*tmp
= vertex
[i
];
133 vertex
[i
] = other
->vertex
[i
];
134 other
->vertex
[i
] = tmp
;
138 unsigned dim
= den
.NumCols();
139 for (int i
= 0; i
< dim
; ++i
) {
140 free_evalue_refs(vertex
[i
]);
145 void print(ostream
& os
, char **p
) const;
146 void substitute(Matrix
*T
);
148 void substitute(evalue
*fract
, evalue
*val
);
149 void substitute(int pos
, evalue
*val
);
150 void reduce_in_domain(Polyhedron
*D
);
151 bool is_opposite(const indicator_term
*neg
) const;
152 vec_ZZ
eval(Value
*val
) const {
154 unsigned dim
= den
.NumCols();
158 for (int i
= 0; i
< dim
; ++i
) {
159 compute_evalue(vertex
[i
], val
, &tmp
);
167 static int evalue_rational_cmp(const evalue
*e1
, const evalue
*e2
)
175 assert(value_notzero_p(e1
->d
));
176 assert(value_notzero_p(e2
->d
));
177 value_multiply(m
, e1
->x
.n
, e2
->d
);
178 value_multiply(m2
, e2
->x
.n
, e1
->d
);
181 else if (value_gt(m
, m2
))
191 static int evalue_cmp(const evalue
*e1
, const evalue
*e2
)
193 if (value_notzero_p(e1
->d
)) {
194 if (value_zero_p(e2
->d
))
196 return evalue_rational_cmp(e1
, e2
);
198 if (value_notzero_p(e2
->d
))
200 if (e1
->x
.p
->type
!= e2
->x
.p
->type
)
201 return e1
->x
.p
->type
- e2
->x
.p
->type
;
202 if (e1
->x
.p
->size
!= e2
->x
.p
->size
)
203 return e1
->x
.p
->size
- e2
->x
.p
->size
;
204 if (e1
->x
.p
->pos
!= e2
->x
.p
->pos
)
205 return e1
->x
.p
->pos
- e2
->x
.p
->pos
;
206 assert(e1
->x
.p
->type
== polynomial
||
207 e1
->x
.p
->type
== fractional
||
208 e1
->x
.p
->type
== flooring
);
209 for (int i
= 0; i
< e1
->x
.p
->size
; ++i
) {
210 int s
= evalue_cmp(&e1
->x
.p
->arr
[i
], &e2
->x
.p
->arr
[i
]);
217 void evalue_length(evalue
*e
, int len
[2])
222 while (value_zero_p(e
->d
)) {
223 assert(e
->x
.p
->type
== polynomial
||
224 e
->x
.p
->type
== fractional
||
225 e
->x
.p
->type
== flooring
);
226 if (e
->x
.p
->type
== polynomial
)
230 int offset
= type_offset(e
->x
.p
);
231 assert(e
->x
.p
->size
== offset
+2);
232 e
= &e
->x
.p
->arr
[offset
];
236 static bool it_smaller(const indicator_term
* it1
, const indicator_term
* it2
)
240 int len1
[2], len2
[2];
241 unsigned dim
= it1
->den
.NumCols();
242 for (int i
= 0; i
< dim
; ++i
) {
243 evalue_length(it1
->vertex
[i
], len1
);
244 evalue_length(it2
->vertex
[i
], len2
);
245 if (len1
[0] != len2
[0])
246 return len1
[0] < len2
[0];
247 if (len1
[1] != len2
[1])
248 return len1
[1] < len2
[1];
250 if (it1
->pos
!= it2
->pos
)
251 return it1
->pos
< it2
->pos
;
252 if (it1
->n
!= it2
->n
)
253 return it1
->n
< it2
->n
;
254 int s
= lex_cmp(it1
->den
, it2
->den
);
257 for (int i
= 0; i
< dim
; ++i
) {
258 s
= evalue_cmp(it1
->vertex
[i
], it2
->vertex
[i
]);
262 assert(it1
->sign
!= 0);
263 assert(it2
->sign
!= 0);
264 if (it1
->sign
!= it2
->sign
)
265 return it1
->sign
> 0;
270 static const int requires_resort
;
271 bool operator()(const indicator_term
* it1
, const indicator_term
* it2
) const {
272 return it_smaller(it1
, it2
);
275 const int smaller_it::requires_resort
= 1;
277 struct smaller_it_p
{
278 static const int requires_resort
;
279 bool operator()(const indicator_term
* it1
, const indicator_term
* it2
) const {
283 const int smaller_it_p::requires_resort
= 0;
285 /* Returns true if this and neg are opposite using the knowledge
286 * that they have the same numerator.
287 * In particular, we check that the signs are different and that
288 * the denominator is the same.
290 bool indicator_term::is_opposite(const indicator_term
*neg
) const
292 if (sign
+ neg
->sign
!= 0)
299 void indicator_term::reduce_in_domain(Polyhedron
*D
)
301 for (int k
= 0; k
< den
.NumCols(); ++k
) {
302 reduce_evalue_in_domain(vertex
[k
], D
);
303 if (evalue_range_reduction_in_domain(vertex
[k
], D
))
304 reduce_evalue(vertex
[k
]);
308 void indicator_term::print(ostream
& os
, char **p
) const
310 unsigned dim
= den
.NumCols();
311 unsigned factors
= den
.NumRows();
319 for (int i
= 0; i
< dim
; ++i
) {
322 evalue_print(os
, vertex
[i
], p
);
325 for (int i
= 0; i
< factors
; ++i
) {
326 os
<< " + t" << i
<< "*[";
327 for (int j
= 0; j
< dim
; ++j
) {
334 os
<< " ((" << pos
<< ", " << n
<< ", " << (void*)this << "))";
337 /* Perform the substitution specified by T on the variables.
338 * T has dimension (newdim+nparam+1) x (olddim + nparam + 1).
339 * The substitution is performed as in gen_fun::substitute
341 void indicator_term::substitute(Matrix
*T
)
343 unsigned dim
= den
.NumCols();
344 unsigned nparam
= T
->NbColumns
- dim
- 1;
345 unsigned newdim
= T
->NbRows
- nparam
- 1;
348 matrix2zz(T
, trans
, newdim
, dim
);
349 trans
= transpose(trans
);
351 newvertex
= new evalue
* [newdim
];
354 v
.SetLength(nparam
+1);
357 value_init(factor
.d
);
358 value_set_si(factor
.d
, 1);
359 value_init(factor
.x
.n
);
360 for (int i
= 0; i
< newdim
; ++i
) {
361 values2zz(T
->p
[i
]+dim
, v
, nparam
+1);
362 newvertex
[i
] = multi_monom(v
);
364 for (int j
= 0; j
< dim
; ++j
) {
365 if (value_zero_p(T
->p
[i
][j
]))
369 evalue_copy(&term
, vertex
[j
]);
370 value_assign(factor
.x
.n
, T
->p
[i
][j
]);
371 emul(&factor
, &term
);
372 eadd(&term
, newvertex
[i
]);
373 free_evalue_refs(&term
);
376 free_evalue_refs(&factor
);
377 for (int i
= 0; i
< dim
; ++i
) {
378 free_evalue_refs(vertex
[i
]);
385 static void evalue_add_constant(evalue
*e
, ZZ v
)
390 /* go down to constant term */
391 while (value_zero_p(e
->d
))
392 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)];
395 value_multiply(tmp
, tmp
, e
->d
);
396 value_addto(e
->x
.n
, e
->x
.n
, tmp
);
401 /* Make all powers in denominator lexico-positive */
402 void indicator_term::normalize()
405 extra_vertex
.SetLength(den
.NumCols());
406 for (int r
= 0; r
< den
.NumRows(); ++r
) {
407 for (int k
= 0; k
< den
.NumCols(); ++k
) {
414 extra_vertex
+= den
[r
];
418 for (int k
= 0; k
< extra_vertex
.length(); ++k
)
419 if (extra_vertex
[k
] != 0)
420 evalue_add_constant(vertex
[k
], extra_vertex
[k
]);
423 static void substitute(evalue
*e
, evalue
*fract
, evalue
*val
)
427 for (t
= e
; value_zero_p(t
->d
); t
= &t
->x
.p
->arr
[type_offset(t
->x
.p
)]) {
428 if (t
->x
.p
->type
== fractional
&& eequal(&t
->x
.p
->arr
[0], fract
))
431 if (value_notzero_p(t
->d
))
434 free_evalue_refs(&t
->x
.p
->arr
[0]);
435 evalue
*term
= &t
->x
.p
->arr
[2];
442 free_evalue_refs(term
);
448 void indicator_term::substitute(evalue
*fract
, evalue
*val
)
450 unsigned dim
= den
.NumCols();
451 for (int i
= 0; i
< dim
; ++i
) {
452 ::substitute(vertex
[i
], fract
, val
);
456 static void substitute(evalue
*e
, int pos
, evalue
*val
)
460 for (t
= e
; value_zero_p(t
->d
); t
= &t
->x
.p
->arr
[type_offset(t
->x
.p
)]) {
461 if (t
->x
.p
->type
== polynomial
&& t
->x
.p
->pos
== pos
)
464 if (value_notzero_p(t
->d
))
467 evalue
*term
= &t
->x
.p
->arr
[1];
474 free_evalue_refs(term
);
480 void indicator_term::substitute(int pos
, evalue
*val
)
482 unsigned dim
= den
.NumCols();
483 for (int i
= 0; i
< dim
; ++i
) {
484 ::substitute(vertex
[i
], pos
, val
);
488 struct indicator_constructor
: public polar_decomposer
, public vertex_decomposer
{
490 vector
<indicator_term
*> *terms
;
491 Matrix
*T
; /* Transformation to original space */
492 Param_Polyhedron
*PP
;
496 indicator_constructor(Polyhedron
*P
, unsigned dim
, Param_Polyhedron
*PP
,
498 vertex_decomposer(P
, PP
->nbV
, this), T(T
), PP(PP
) {
499 vertex
.SetLength(dim
);
500 terms
= new vector
<indicator_term
*>[nbV
];
502 ~indicator_constructor() {
503 for (int i
= 0; i
< nbV
; ++i
)
504 for (int j
= 0; j
< terms
[i
].size(); ++j
)
508 void substitute(Matrix
*T
);
510 void print(ostream
& os
, char **p
);
512 virtual void handle_polar(Polyhedron
*P
, int sign
);
513 void decompose_at_vertex(Param_Vertices
*V
, int _i
,
514 barvinok_options
*options
) {
517 vertex_decomposer::decompose_at_vertex(V
, _i
, options
);
521 void indicator_constructor::handle_polar(Polyhedron
*C
, int s
)
523 unsigned dim
= vertex
.length();
525 assert(C
->NbRays
-1 == dim
);
527 indicator_term
*term
= new indicator_term(dim
, pos
, n
++);
529 terms
[vert
].push_back(term
);
531 lattice_point(V
, C
, vertex
, term
->vertex
);
533 for (int r
= 0; r
< dim
; ++r
) {
534 values2zz(C
->Ray
[r
]+1, term
->den
[r
], dim
);
535 for (int j
= 0; j
< dim
; ++j
) {
536 if (term
->den
[r
][j
] == 0)
538 if (term
->den
[r
][j
] > 0)
540 term
->sign
= -term
->sign
;
541 term
->den
[r
] = -term
->den
[r
];
542 vertex
+= term
->den
[r
];
547 for (int i
= 0; i
< dim
; ++i
) {
548 if (!term
->vertex
[i
]) {
549 term
->vertex
[i
] = new evalue();
550 value_init(term
->vertex
[i
]->d
);
551 value_init(term
->vertex
[i
]->x
.n
);
552 zz2value(vertex
[i
], term
->vertex
[i
]->x
.n
);
553 value_set_si(term
->vertex
[i
]->d
, 1);
558 evalue_add_constant(term
->vertex
[i
], vertex
[i
]);
566 lex_order_rows(term
->den
);
569 void indicator_constructor::print(ostream
& os
, char **p
)
571 for (int i
= 0; i
< nbV
; ++i
)
572 for (int j
= 0; j
< terms
[i
].size(); ++j
) {
573 os
<< "i: " << i
<< ", j: " << j
<< endl
;
574 terms
[i
][j
]->print(os
, p
);
579 void indicator_constructor::normalize()
581 for (int i
= 0; i
< nbV
; ++i
)
582 for (int j
= 0; j
< terms
[i
].size(); ++j
) {
584 vertex
.SetLength(terms
[i
][j
]->den
.NumCols());
585 for (int r
= 0; r
< terms
[i
][j
]->den
.NumRows(); ++r
) {
586 for (int k
= 0; k
< terms
[i
][j
]->den
.NumCols(); ++k
) {
587 if (terms
[i
][j
]->den
[r
][k
] == 0)
589 if (terms
[i
][j
]->den
[r
][k
] > 0)
591 terms
[i
][j
]->sign
= -terms
[i
][j
]->sign
;
592 terms
[i
][j
]->den
[r
] = -terms
[i
][j
]->den
[r
];
593 vertex
+= terms
[i
][j
]->den
[r
];
597 lex_order_rows(terms
[i
][j
]->den
);
598 for (int k
= 0; k
< vertex
.length(); ++k
)
600 evalue_add_constant(terms
[i
][j
]->vertex
[k
], vertex
[k
]);
604 struct order_cache_el
{
606 order_cache_el
copy() const {
608 for (int i
= 0; i
< e
.size(); ++i
) {
609 evalue
*c
= new evalue
;
611 evalue_copy(c
, e
[i
]);
617 for (int i
= 0; i
< e
.size(); ++i
) {
618 free_evalue_refs(e
[i
]);
625 evalue_set_si(&mone
, -1, 1);
626 for (int i
= 0; i
< e
.size(); ++i
)
628 free_evalue_refs(&mone
);
630 void print(ostream
& os
, char **p
);
633 void order_cache_el::print(ostream
& os
, char **p
)
636 for (int i
= 0; i
< e
.size(); ++i
) {
639 evalue_print(os
, e
[i
], p
);
645 vector
<order_cache_el
> lt
;
646 vector
<order_cache_el
> le
;
647 vector
<order_cache_el
> unknown
;
649 void clear_transients() {
650 for (int i
= 0; i
< le
.size(); ++i
)
652 for (int i
= 0; i
< unknown
.size(); ++i
)
659 for (int i
= 0; i
< lt
.size(); ++i
)
663 void add(order_cache_el
& cache_el
, order_sign sign
);
664 order_sign
check_lt(vector
<order_cache_el
>* list
,
665 const indicator_term
*a
, const indicator_term
*b
,
666 order_cache_el
& cache_el
);
667 order_sign
check_lt(const indicator_term
*a
, const indicator_term
*b
,
668 order_cache_el
& cache_el
);
669 order_sign
check_direct(const indicator_term
*a
, const indicator_term
*b
,
670 order_cache_el
& cache_el
);
671 order_sign
check(const indicator_term
*a
, const indicator_term
*b
,
672 order_cache_el
& cache_el
);
673 void copy(const order_cache
& cache
);
674 void print(ostream
& os
, char **p
);
677 void order_cache::copy(const order_cache
& cache
)
679 for (int i
= 0; i
< cache
.lt
.size(); ++i
) {
680 order_cache_el n
= cache
.lt
[i
].copy();
685 void order_cache::add(order_cache_el
& cache_el
, order_sign sign
)
687 if (sign
== order_lt
) {
688 lt
.push_back(cache_el
);
689 } else if (sign
== order_gt
) {
691 lt
.push_back(cache_el
);
692 } else if (sign
== order_le
) {
693 le
.push_back(cache_el
);
694 } else if (sign
== order_ge
) {
696 le
.push_back(cache_el
);
697 } else if (sign
== order_unknown
) {
698 unknown
.push_back(cache_el
);
700 assert(sign
== order_eq
);
707 static evalue
*ediff(const evalue
*a
, const evalue
*b
)
711 evalue_set_si(&mone
, -1, 1);
712 evalue
*diff
= new evalue
;
714 evalue_copy(diff
, b
);
718 free_evalue_refs(&mone
);
722 static bool evalue_first_difference(const evalue
*e1
, const evalue
*e2
,
723 const evalue
**d1
, const evalue
**d2
)
728 if (value_ne(e1
->d
, e2
->d
))
731 if (value_notzero_p(e1
->d
)) {
732 if (value_eq(e1
->x
.n
, e2
->x
.n
))
736 if (e1
->x
.p
->type
!= e2
->x
.p
->type
)
738 if (e1
->x
.p
->size
!= e2
->x
.p
->size
)
740 if (e1
->x
.p
->pos
!= e2
->x
.p
->pos
)
743 assert(e1
->x
.p
->type
== polynomial
||
744 e1
->x
.p
->type
== fractional
||
745 e1
->x
.p
->type
== flooring
);
746 int offset
= type_offset(e1
->x
.p
);
747 assert(e1
->x
.p
->size
== offset
+2);
748 for (int i
= 0; i
< e1
->x
.p
->size
; ++i
)
749 if (i
!= type_offset(e1
->x
.p
) &&
750 !eequal(&e1
->x
.p
->arr
[i
], &e2
->x
.p
->arr
[i
]))
753 return evalue_first_difference(&e1
->x
.p
->arr
[offset
],
754 &e2
->x
.p
->arr
[offset
], d1
, d2
);
757 static order_sign
evalue_diff_constant_sign(const evalue
*e1
, const evalue
*e2
)
759 if (!evalue_first_difference(e1
, e2
, &e1
, &e2
))
761 if (value_zero_p(e1
->d
) || value_zero_p(e2
->d
))
762 return order_undefined
;
763 int s
= evalue_rational_cmp(e1
, e2
);
772 order_sign
order_cache::check_lt(vector
<order_cache_el
>* list
,
773 const indicator_term
*a
, const indicator_term
*b
,
774 order_cache_el
& cache_el
)
776 order_sign sign
= order_undefined
;
777 for (int i
= 0; i
< list
->size(); ++i
) {
779 for (j
= cache_el
.e
.size(); j
< (*list
)[i
].e
.size(); ++j
)
780 cache_el
.e
.push_back(ediff(a
->vertex
[j
], b
->vertex
[j
]));
781 for (j
= 0; j
< (*list
)[i
].e
.size(); ++j
) {
782 order_sign diff_sign
;
783 diff_sign
= evalue_diff_constant_sign((*list
)[i
].e
[j
], cache_el
.e
[j
]);
784 if (diff_sign
== order_gt
) {
787 } else if (diff_sign
== order_lt
)
789 else if (diff_sign
== order_undefined
)
792 assert(diff_sign
== order_eq
);
794 if (j
== (*list
)[i
].e
.size())
795 sign
= list
== <
? order_lt
: order_le
;
796 if (sign
!= order_undefined
)
802 order_sign
order_cache::check_direct(const indicator_term
*a
,
803 const indicator_term
*b
,
804 order_cache_el
& cache_el
)
806 order_sign sign
= check_lt(<
, a
, b
, cache_el
);
807 if (sign
!= order_undefined
)
809 sign
= check_lt(&le
, a
, b
, cache_el
);
810 if (sign
!= order_undefined
)
813 for (int i
= 0; i
< unknown
.size(); ++i
) {
815 for (j
= cache_el
.e
.size(); j
< unknown
[i
].e
.size(); ++j
)
816 cache_el
.e
.push_back(ediff(a
->vertex
[j
], b
->vertex
[j
]));
817 for (j
= 0; j
< unknown
[i
].e
.size(); ++j
) {
818 if (!eequal(unknown
[i
].e
[j
], cache_el
.e
[j
]))
821 if (j
== unknown
[i
].e
.size()) {
822 sign
= order_unknown
;
829 order_sign
order_cache::check(const indicator_term
*a
, const indicator_term
*b
,
830 order_cache_el
& cache_el
)
832 order_sign sign
= check_direct(a
, b
, cache_el
);
833 if (sign
!= order_undefined
)
835 int size
= cache_el
.e
.size();
837 sign
= check_direct(a
, b
, cache_el
);
839 assert(cache_el
.e
.size() == size
);
840 if (sign
== order_undefined
)
842 if (sign
== order_lt
)
844 else if (sign
== order_le
)
847 assert(sign
== order_unknown
);
853 struct partial_order
{
856 std::set
<const indicator_term
*, smaller_it
> head
;
857 map
<const indicator_term
*, int, smaller_it
> pred
;
858 map
<const indicator_term
*, vector
<const indicator_term
* >, smaller_it
> lt
;
859 map
<const indicator_term
*, vector
<const indicator_term
* >, smaller_it
> le
;
860 map
<const indicator_term
*, vector
<const indicator_term
* >, smaller_it
> eq
;
862 map
<const indicator_term
*, vector
<const indicator_term
* >, smaller_it
> pending
;
866 partial_order(indicator
*ind
) : ind(ind
) {}
867 void copy(const partial_order
& order
,
868 map
< const indicator_term
*, indicator_term
* > old2new
);
870 map
<const indicator_term
*, vector
<const indicator_term
* > >::iterator i
;
871 map
<const indicator_term
*, int >::iterator j
;
872 std::set
<const indicator_term
*>::iterator k
;
874 if (head
.key_comp().requires_resort
) {
875 typeof(head
) new_head
;
876 for (k
= head
.begin(); k
!= head
.end(); ++k
)
882 if (pred
.key_comp().requires_resort
) {
883 typeof(pred
) new_pred
;
884 for (j
= pred
.begin(); j
!= pred
.end(); ++j
)
885 new_pred
[(*j
).first
] = (*j
).second
;
890 if (lt
.key_comp().requires_resort
) {
892 for (i
= lt
.begin(); i
!= lt
.end(); ++i
)
893 m
[(*i
).first
] = (*i
).second
;
898 if (le
.key_comp().requires_resort
) {
900 for (i
= le
.begin(); i
!= le
.end(); ++i
)
901 m
[(*i
).first
] = (*i
).second
;
906 if (eq
.key_comp().requires_resort
) {
908 for (i
= eq
.begin(); i
!= eq
.end(); ++i
)
909 m
[(*i
).first
] = (*i
).second
;
914 if (pending
.key_comp().requires_resort
) {
916 for (i
= pending
.begin(); i
!= pending
.end(); ++i
)
917 m
[(*i
).first
] = (*i
).second
;
923 order_sign
compare(const indicator_term
*a
, const indicator_term
*b
);
924 void set_equal(const indicator_term
*a
, const indicator_term
*b
);
925 void unset_le(const indicator_term
*a
, const indicator_term
*b
);
926 void dec_pred(const indicator_term
*it
) {
927 if (--pred
[it
] == 0) {
932 void inc_pred(const indicator_term
*it
) {
933 if (head
.find(it
) != head
.end())
938 bool compared(const indicator_term
* a
, const indicator_term
* b
);
939 void add(const indicator_term
* it
, std::set
<const indicator_term
*> *filter
);
940 void remove(const indicator_term
* it
);
942 void print(ostream
& os
, char **p
);
944 /* replace references to orig to references to replacement */
945 void replace(const indicator_term
* orig
, indicator_term
* replacement
);
946 void sanity_check() const;
949 /* We actually replace the contents of orig by that of replacement,
950 * but we have to be careful since replacing the content changes
951 * the order of orig in the maps.
953 void partial_order::replace(const indicator_term
* orig
, indicator_term
* replacement
)
955 std::set
<const indicator_term
*>::iterator k
;
957 bool is_head
= k
!= head
.end();
962 orig_pred
= pred
[orig
];
965 vector
<const indicator_term
* > orig_lt
;
966 vector
<const indicator_term
* > orig_le
;
967 vector
<const indicator_term
* > orig_eq
;
968 vector
<const indicator_term
* > orig_pending
;
969 map
<const indicator_term
*, vector
<const indicator_term
* > >::iterator i
;
970 bool in_lt
= ((i
= lt
.find(orig
)) != lt
.end());
972 orig_lt
= (*i
).second
;
975 bool in_le
= ((i
= le
.find(orig
)) != le
.end());
977 orig_le
= (*i
).second
;
980 bool in_eq
= ((i
= eq
.find(orig
)) != eq
.end());
982 orig_eq
= (*i
).second
;
985 bool in_pending
= ((i
= pending
.find(orig
)) != pending
.end());
987 orig_pending
= (*i
).second
;
990 indicator_term
*old
= const_cast<indicator_term
*>(orig
);
991 old
->swap(replacement
);
995 pred
[old
] = orig_pred
;
1003 pending
[old
] = orig_pending
;
1006 void partial_order::unset_le(const indicator_term
*a
, const indicator_term
*b
)
1008 vector
<const indicator_term
*>::iterator i
;
1009 i
= find(le
[a
].begin(), le
[a
].end(), b
);
1011 if (le
[a
].size() == 0)
1014 i
= find(pending
[a
].begin(), pending
[a
].end(), b
);
1015 if (i
!= pending
[a
].end())
1016 pending
[a
].erase(i
);
1019 void partial_order::set_equal(const indicator_term
*a
, const indicator_term
*b
)
1021 if (eq
[a
].size() == 0)
1023 if (eq
[b
].size() == 0)
1028 if (pred
.key_comp()(b
, a
)) {
1029 const indicator_term
*c
= a
;
1034 const indicator_term
*base
= a
;
1036 map
<const indicator_term
*, vector
<const indicator_term
* > >::iterator i
;
1038 for (int j
= 0; j
< eq
[b
].size(); ++j
) {
1039 eq
[base
].push_back(eq
[b
][j
]);
1040 eq
[eq
[b
][j
]][0] = base
;
1045 if (i
!= lt
.end()) {
1046 for (int j
= 0; j
< lt
[b
].size(); ++j
) {
1047 if (find(eq
[base
].begin(), eq
[base
].end(), lt
[b
][j
]) != eq
[base
].end())
1049 else if (find(lt
[base
].begin(), lt
[base
].end(), lt
[b
][j
])
1053 lt
[base
].push_back(lt
[b
][j
]);
1059 if (i
!= le
.end()) {
1060 for (int j
= 0; j
< le
[b
].size(); ++j
) {
1061 if (find(eq
[base
].begin(), eq
[base
].end(), le
[b
][j
]) != eq
[base
].end())
1063 else if (find(le
[base
].begin(), le
[base
].end(), le
[b
][j
])
1067 le
[base
].push_back(le
[b
][j
]);
1072 i
= pending
.find(base
);
1073 if (i
!= pending
.end()) {
1074 vector
<const indicator_term
* > old
= pending
[base
];
1075 pending
[base
].clear();
1076 for (int j
= 0; j
< old
.size(); ++j
) {
1077 if (find(eq
[base
].begin(), eq
[base
].end(), old
[j
]) == eq
[base
].end())
1078 pending
[base
].push_back(old
[j
]);
1082 i
= pending
.find(b
);
1083 if (i
!= pending
.end()) {
1084 for (int j
= 0; j
< pending
[b
].size(); ++j
) {
1085 if (find(eq
[base
].begin(), eq
[base
].end(), pending
[b
][j
]) == eq
[base
].end())
1086 pending
[base
].push_back(pending
[b
][j
]);
1092 void partial_order::copy(const partial_order
& order
,
1093 map
< const indicator_term
*, indicator_term
* > old2new
)
1095 cache
.copy(order
.cache
);
1097 map
<const indicator_term
*, vector
<const indicator_term
* > >::const_iterator i
;
1098 map
<const indicator_term
*, int >::const_iterator j
;
1099 std::set
<const indicator_term
*>::const_iterator k
;
1101 for (k
= order
.head
.begin(); k
!= order
.head
.end(); ++k
)
1102 head
.insert(old2new
[*k
]);
1104 for (j
= order
.pred
.begin(); j
!= order
.pred
.end(); ++j
)
1105 pred
[old2new
[(*j
).first
]] = (*j
).second
;
1107 for (i
= order
.lt
.begin(); i
!= order
.lt
.end(); ++i
) {
1108 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
1109 lt
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
1111 for (i
= order
.le
.begin(); i
!= order
.le
.end(); ++i
) {
1112 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
1113 le
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
1115 for (i
= order
.eq
.begin(); i
!= order
.eq
.end(); ++i
) {
1116 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
1117 eq
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
1119 for (i
= order
.pending
.begin(); i
!= order
.pending
.end(); ++i
) {
1120 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
1121 pending
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
1127 vector
<evalue
*> max
;
1129 void print(ostream
& os
, char **p
, barvinok_options
*options
) const;
1130 void substitute(Matrix
*T
, barvinok_options
*options
);
1131 Vector
*eval(Value
*val
, unsigned MaxRays
) const;
1134 for (int i
= 0; i
< max
.size(); ++i
) {
1135 free_evalue_refs(max
[i
]);
1143 * Project on first dim dimensions
1145 Polyhedron
* Polyhedron_Project_Initial(Polyhedron
*P
, int dim
)
1151 if (P
->Dimension
== dim
)
1152 return Polyhedron_Copy(P
);
1154 T
= Matrix_Alloc(dim
+1, P
->Dimension
+1);
1155 for (i
= 0; i
< dim
; ++i
)
1156 value_set_si(T
->p
[i
][i
], 1);
1157 value_set_si(T
->p
[dim
][P
->Dimension
], 1);
1158 I
= Polyhedron_Image(P
, T
, P
->NbConstraints
);
1164 vector
<indicator_term
*> term
;
1165 indicator_constructor
& ic
;
1166 partial_order order
;
1170 barvinok_options
*options
;
1171 vector
<evalue
*> substitutions
;
1173 indicator(indicator_constructor
& ic
, Param_Domain
*PD
, EDomain
*D
,
1174 barvinok_options
*options
) :
1175 ic(ic
), PD(PD
), D(D
), order(this), options(options
), P(NULL
) {}
1176 indicator(const indicator
& ind
, EDomain
*D
) :
1177 ic(ind
.ic
), PD(ind
.PD
), D(NULL
), order(this), options(ind
.options
),
1178 P(Polyhedron_Copy(ind
.P
)) {
1179 map
< const indicator_term
*, indicator_term
* > old2new
;
1180 for (int i
= 0; i
< ind
.term
.size(); ++i
) {
1181 indicator_term
*it
= new indicator_term(*ind
.term
[i
]);
1182 old2new
[ind
.term
[i
]] = it
;
1185 order
.copy(ind
.order
, old2new
);
1189 for (int i
= 0; i
< term
.size(); ++i
)
1197 void set_domain(EDomain
*D
) {
1198 order
.cache
.clear_transients();
1202 int nparam
= ic
.P
->Dimension
- ic
.vertex
.length();
1203 if (options
->lexmin_reduce
) {
1204 Polyhedron
*Q
= Polyhedron_Project_Initial(D
->D
, nparam
);
1205 Q
= DomainConstraintSimplify(Q
, options
->MaxRays
);
1206 if (!P
|| !PolyhedronIncludes(Q
, P
))
1207 reduce_in_domain(Q
);
1215 void add(const indicator_term
* it
);
1216 void remove(const indicator_term
* it
);
1217 void remove_initial_rational_vertices();
1218 void expand_rational_vertex(const indicator_term
*initial
);
1220 void print(ostream
& os
, char **p
);
1222 void peel(int i
, int j
);
1223 void combine(const indicator_term
*a
, const indicator_term
*b
);
1224 void add_substitution(evalue
*equation
);
1225 void perform_pending_substitutions();
1226 void reduce_in_domain(Polyhedron
*D
);
1227 bool handle_equal_numerators(const indicator_term
*base
);
1229 max_term
* create_max_term(const indicator_term
*it
);
1231 void substitute(evalue
*equation
);
1234 void partial_order::sanity_check() const
1236 map
<const indicator_term
*, vector
<const indicator_term
* > >::const_iterator i
;
1237 map
<const indicator_term
*, vector
<const indicator_term
* > >::const_iterator prev
;
1238 map
<const indicator_term
*, vector
<const indicator_term
* > >::const_iterator l
;
1239 map
<const indicator_term
*, int >::const_iterator k
, prev_k
;
1241 for (k
= pred
.begin(); k
!= pred
.end(); prev_k
= k
, ++k
)
1242 if (k
!= pred
.begin())
1243 assert(pred
.key_comp()((*prev_k
).first
, (*k
).first
));
1244 for (i
= lt
.begin(); i
!= lt
.end(); prev
= i
, ++i
) {
1247 i_v
= (*i
).first
->eval(ind
->D
->sample
->p
);
1248 if (i
!= lt
.begin())
1249 assert(lt
.key_comp()((*prev
).first
, (*i
).first
));
1250 l
= eq
.find((*i
).first
);
1252 assert((*l
).second
.size() > 1);
1253 assert(head
.find((*i
).first
) != head
.end() ||
1254 pred
.find((*i
).first
) != pred
.end());
1255 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1256 k
= pred
.find((*i
).second
[j
]);
1257 assert(k
!= pred
.end());
1258 assert((*k
).second
!= 0);
1259 if ((*i
).first
->sign
!= 0 &&
1260 (*i
).second
[j
]->sign
!= 0 && ind
->D
->sample
) {
1261 vec_ZZ j_v
= (*i
).second
[j
]->eval(ind
->D
->sample
->p
);
1262 assert(lex_cmp(i_v
, j_v
) < 0);
1266 for (i
= le
.begin(); i
!= le
.end(); ++i
) {
1267 assert((*i
).second
.size() > 0);
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);
1276 for (i
= eq
.begin(); i
!= eq
.end(); ++i
) {
1277 assert(head
.find((*i
).first
) != head
.end() ||
1278 pred
.find((*i
).first
) != pred
.end());
1279 assert((*i
).second
.size() >= 1);
1281 for (i
= pending
.begin(); i
!= pending
.end(); ++i
) {
1282 assert(head
.find((*i
).first
) != head
.end() ||
1283 pred
.find((*i
).first
) != pred
.end());
1284 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
1285 assert(head
.find((*i
).second
[j
]) != head
.end() ||
1286 pred
.find((*i
).second
[j
]) != pred
.end());
1290 max_term
* indicator::create_max_term(const indicator_term
*it
)
1292 int dim
= it
->den
.NumCols();
1293 int nparam
= ic
.P
->Dimension
- ic
.vertex
.length();
1294 max_term
*maximum
= new max_term
;
1295 maximum
->domain
= new EDomain(D
);
1296 for (int j
= 0; j
< dim
; ++j
) {
1297 evalue
*E
= new evalue
;
1299 evalue_copy(E
, it
->vertex
[j
]);
1300 if (evalue_frac2floor_in_domain3(E
, D
->D
, 0))
1302 maximum
->max
.push_back(E
);
1307 static order_sign
evalue_sign(evalue
*diff
, EDomain
*D
, barvinok_options
*options
)
1309 order_sign sign
= order_eq
;
1312 evalue_set_si(&mone
, -1, 1);
1313 int len
= 1 + D
->D
->Dimension
+ 1;
1314 Vector
*c
= Vector_Alloc(len
);
1315 Matrix
*T
= Matrix_Alloc(2, len
-1);
1317 int fract
= evalue2constraint(D
, diff
, c
->p
, len
);
1318 Vector_Copy(c
->p
+1, T
->p
[0], len
-1);
1319 value_assign(T
->p
[1][len
-2], c
->p
[0]);
1321 order_sign upper_sign
= polyhedron_affine_sign(D
->D
, T
, options
);
1322 if (upper_sign
== order_lt
|| !fract
)
1326 evalue2constraint(D
, diff
, c
->p
, len
);
1328 Vector_Copy(c
->p
+1, T
->p
[0], len
-1);
1329 value_assign(T
->p
[1][len
-2], c
->p
[0]);
1331 order_sign neg_lower_sign
= polyhedron_affine_sign(D
->D
, T
, options
);
1333 if (neg_lower_sign
== order_lt
)
1335 else if (neg_lower_sign
== order_eq
|| neg_lower_sign
== order_le
) {
1336 if (upper_sign
== order_eq
|| upper_sign
== order_le
)
1341 if (upper_sign
== order_lt
|| upper_sign
== order_le
||
1342 upper_sign
== order_eq
)
1345 sign
= order_unknown
;
1351 free_evalue_refs(&mone
);
1356 /* An auxiliary class that keeps a reference to an evalue
1357 * and frees it when it goes out of scope.
1359 struct temp_evalue
{
1361 temp_evalue() : E(NULL
) {}
1362 temp_evalue(evalue
*e
) : E(e
) {}
1363 operator evalue
* () const { return E
; }
1364 evalue
*operator=(evalue
*e
) {
1366 free_evalue_refs(E
);
1374 free_evalue_refs(E
);
1380 static void substitute(vector
<indicator_term
*>& term
, evalue
*equation
)
1382 evalue
*fract
= NULL
;
1383 evalue
*val
= new evalue
;
1385 evalue_copy(val
, equation
);
1388 value_init(factor
.d
);
1389 value_init(factor
.x
.n
);
1392 for (e
= val
; value_zero_p(e
->d
) && e
->x
.p
->type
!= fractional
;
1393 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)])
1396 if (value_zero_p(e
->d
) && e
->x
.p
->type
== fractional
)
1397 fract
= &e
->x
.p
->arr
[0];
1399 for (e
= val
; value_zero_p(e
->d
) && e
->x
.p
->type
!= polynomial
;
1400 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)])
1402 assert(value_zero_p(e
->d
) && e
->x
.p
->type
== polynomial
);
1405 int offset
= type_offset(e
->x
.p
);
1407 assert(value_notzero_p(e
->x
.p
->arr
[offset
+1].d
));
1408 assert(value_notzero_p(e
->x
.p
->arr
[offset
+1].x
.n
));
1409 if (value_neg_p(e
->x
.p
->arr
[offset
+1].x
.n
)) {
1410 value_oppose(factor
.d
, e
->x
.p
->arr
[offset
+1].x
.n
);
1411 value_assign(factor
.x
.n
, e
->x
.p
->arr
[offset
+1].d
);
1413 value_assign(factor
.d
, e
->x
.p
->arr
[offset
+1].x
.n
);
1414 value_oppose(factor
.x
.n
, e
->x
.p
->arr
[offset
+1].d
);
1417 free_evalue_refs(&e
->x
.p
->arr
[offset
+1]);
1420 *e
= e
->x
.p
->arr
[offset
];
1425 for (int i
= 0; i
< term
.size(); ++i
)
1426 term
[i
]->substitute(fract
, val
);
1428 free_evalue_refs(&p
->arr
[0]);
1430 for (int i
= 0; i
< term
.size(); ++i
)
1431 term
[i
]->substitute(p
->pos
, val
);
1434 free_evalue_refs(&factor
);
1435 free_evalue_refs(val
);
1441 order_sign
partial_order::compare(const indicator_term
*a
, const indicator_term
*b
)
1443 unsigned dim
= a
->den
.NumCols();
1444 order_sign sign
= order_eq
;
1445 EDomain
*D
= ind
->D
;
1446 unsigned MaxRays
= ind
->options
->MaxRays
;
1447 bool rational
= a
->sign
== 0 || b
->sign
== 0;
1449 order_sign cached_sign
= order_eq
;
1450 for (int k
= 0; k
< dim
; ++k
) {
1451 cached_sign
= evalue_diff_constant_sign(a
->vertex
[k
], b
->vertex
[k
]);
1452 if (cached_sign
!= order_eq
)
1455 if (cached_sign
!= order_undefined
)
1458 order_cache_el cache_el
;
1459 cached_sign
= order_undefined
;
1461 cached_sign
= cache
.check(a
, b
, cache_el
);
1462 if (cached_sign
!= order_undefined
) {
1467 if (rational
&& POL_ISSET(ind
->options
->MaxRays
, POL_INTEGER
)) {
1468 ind
->options
->MaxRays
&= ~POL_INTEGER
;
1469 if (ind
->options
->MaxRays
)
1470 ind
->options
->MaxRays
|= POL_HIGH_BIT
;
1475 vector
<indicator_term
*> term
;
1477 for (int k
= 0; k
< dim
; ++k
) {
1478 /* compute a->vertex[k] - b->vertex[k] */
1480 if (cache_el
.e
.size() <= k
) {
1481 diff
= ediff(a
->vertex
[k
], b
->vertex
[k
]);
1482 cache_el
.e
.push_back(diff
);
1484 diff
= cache_el
.e
[k
];
1487 tdiff
= diff
= ediff(term
[0]->vertex
[k
], term
[1]->vertex
[k
]);
1488 order_sign diff_sign
;
1490 diff_sign
= order_undefined
;
1491 else if (eequal(a
->vertex
[k
], b
->vertex
[k
]))
1492 diff_sign
= order_eq
;
1494 diff_sign
= evalue_sign(diff
, D
, ind
->options
);
1496 if (diff_sign
== order_undefined
) {
1497 assert(sign
== order_le
|| sign
== order_ge
);
1498 if (sign
== order_le
)
1504 if (diff_sign
== order_lt
) {
1505 if (sign
== order_eq
|| sign
== order_le
)
1508 sign
= order_unknown
;
1511 if (diff_sign
== order_gt
) {
1512 if (sign
== order_eq
|| sign
== order_ge
)
1515 sign
= order_unknown
;
1518 if (diff_sign
== order_eq
) {
1519 if (D
== ind
->D
&& term
.size() == 0 && !rational
&&
1520 !EVALUE_IS_ZERO(*diff
))
1521 ind
->add_substitution(diff
);
1524 if ((diff_sign
== order_unknown
) ||
1525 ((diff_sign
== order_lt
|| diff_sign
== order_le
) && sign
== order_ge
) ||
1526 ((diff_sign
== order_gt
|| diff_sign
== order_ge
) && sign
== order_le
)) {
1527 sign
= order_unknown
;
1534 term
.push_back(new indicator_term(*a
));
1535 term
.push_back(new indicator_term(*b
));
1537 substitute(term
, diff
);
1541 cache
.add(cache_el
, sign
);
1545 if (D
&& D
!= ind
->D
)
1553 ind
->options
->MaxRays
= MaxRays
;
1557 bool partial_order::compared(const indicator_term
* a
, const indicator_term
* b
)
1559 map
<const indicator_term
*, vector
<const indicator_term
* > >::iterator j
;
1562 if (j
!= lt
.end() && find(lt
[a
].begin(), lt
[a
].end(), b
) != lt
[a
].end())
1566 if (j
!= le
.end() && find(le
[a
].begin(), le
[a
].end(), b
) != le
[a
].end())
1572 void partial_order::add(const indicator_term
* it
,
1573 std::set
<const indicator_term
*> *filter
)
1575 if (eq
.find(it
) != eq
.end() && eq
[it
].size() == 1)
1578 typeof(head
) head_copy(head
);
1583 std::set
<const indicator_term
*>::iterator i
;
1584 for (i
= head_copy
.begin(); i
!= head_copy
.end(); ++i
) {
1587 if (eq
.find(*i
) != eq
.end() && eq
[*i
].size() == 1)
1590 if (filter
->find(*i
) == filter
->end())
1592 if (compared(*i
, it
))
1595 order_sign sign
= compare(it
, *i
);
1596 if (sign
== order_lt
) {
1597 lt
[it
].push_back(*i
);
1599 } else if (sign
== order_le
) {
1600 le
[it
].push_back(*i
);
1602 } else if (sign
== order_eq
) {
1605 } else if (sign
== order_gt
) {
1606 pending
[*i
].push_back(it
);
1607 lt
[*i
].push_back(it
);
1609 } else if (sign
== order_ge
) {
1610 pending
[*i
].push_back(it
);
1611 le
[*i
].push_back(it
);
1617 void partial_order::remove(const indicator_term
* it
)
1619 std::set
<const indicator_term
*> filter
;
1620 map
<const indicator_term
*, vector
<const indicator_term
* > >::iterator i
;
1622 assert(head
.find(it
) != head
.end());
1625 if (i
!= eq
.end()) {
1626 assert(eq
[it
].size() >= 1);
1627 const indicator_term
*base
;
1628 if (eq
[it
].size() == 1) {
1632 vector
<const indicator_term
* >::iterator j
;
1633 j
= find(eq
[base
].begin(), eq
[base
].end(), it
);
1634 assert(j
!= eq
[base
].end());
1637 /* "it" may no longer be the smallest, since the order
1638 * structure may have been copied from another one.
1640 sort(eq
[it
].begin()+1, eq
[it
].end(), pred
.key_comp());
1641 assert(eq
[it
][0] == it
);
1642 eq
[it
].erase(eq
[it
].begin());
1647 for (int j
= 1; j
< eq
[base
].size(); ++j
)
1648 eq
[eq
[base
][j
]][0] = base
;
1651 if (i
!= lt
.end()) {
1657 if (i
!= le
.end()) {
1662 i
= pending
.find(it
);
1663 if (i
!= pending
.end()) {
1664 pending
[base
] = pending
[it
];
1669 if (eq
[base
].size() == 1)
1678 if (i
!= lt
.end()) {
1679 for (int j
= 0; j
< lt
[it
].size(); ++j
) {
1680 filter
.insert(lt
[it
][j
]);
1681 dec_pred(lt
[it
][j
]);
1687 if (i
!= le
.end()) {
1688 for (int j
= 0; j
< le
[it
].size(); ++j
) {
1689 filter
.insert(le
[it
][j
]);
1690 dec_pred(le
[it
][j
]);
1697 i
= pending
.find(it
);
1698 if (i
!= pending
.end()) {
1699 vector
<const indicator_term
*> it_pending
= pending
[it
];
1701 for (int j
= 0; j
< it_pending
.size(); ++j
) {
1702 filter
.erase(it_pending
[j
]);
1703 add(it_pending
[j
], &filter
);
1708 void partial_order::print(ostream
& os
, char **p
)
1710 map
<const indicator_term
*, vector
<const indicator_term
* > >::iterator i
;
1711 map
<const indicator_term
*, int >::iterator j
;
1712 std::set
<const indicator_term
*>::iterator k
;
1713 for (k
= head
.begin(); k
!= head
.end(); ++k
) {
1717 for (j
= pred
.begin(); j
!= pred
.end(); ++j
) {
1718 (*j
).first
->print(os
, p
);
1719 os
<< ": " << (*j
).second
<< endl
;
1721 for (i
= lt
.begin(); i
!= lt
.end(); ++i
) {
1722 (*i
).first
->print(os
, p
);
1723 assert(head
.find((*i
).first
) != head
.end() ||
1724 pred
.find((*i
).first
) != pred
.end());
1725 if (pred
.find((*i
).first
) != pred
.end())
1726 os
<< "(" << pred
[(*i
).first
] << ")";
1728 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1731 (*i
).second
[j
]->print(os
, p
);
1732 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1733 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1737 for (i
= le
.begin(); i
!= le
.end(); ++i
) {
1738 (*i
).first
->print(os
, p
);
1739 assert(head
.find((*i
).first
) != head
.end() ||
1740 pred
.find((*i
).first
) != pred
.end());
1741 if (pred
.find((*i
).first
) != pred
.end())
1742 os
<< "(" << pred
[(*i
).first
] << ")";
1744 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1747 (*i
).second
[j
]->print(os
, p
);
1748 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1749 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1753 for (i
= eq
.begin(); i
!= eq
.end(); ++i
) {
1754 if ((*i
).second
.size() <= 1)
1756 (*i
).first
->print(os
, p
);
1757 assert(head
.find((*i
).first
) != head
.end() ||
1758 pred
.find((*i
).first
) != pred
.end());
1759 if (pred
.find((*i
).first
) != pred
.end())
1760 os
<< "(" << pred
[(*i
).first
] << ")";
1761 for (int j
= 1; j
< (*i
).second
.size(); ++j
) {
1764 (*i
).second
[j
]->print(os
, p
);
1765 assert(head
.find((*i
).second
[j
]) != head
.end() ||
1766 pred
.find((*i
).second
[j
]) != pred
.end());
1767 if (pred
.find((*i
).second
[j
]) != pred
.end())
1768 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1772 for (i
= pending
.begin(); i
!= pending
.end(); ++i
) {
1773 os
<< "pending on ";
1774 (*i
).first
->print(os
, p
);
1775 assert(head
.find((*i
).first
) != head
.end() ||
1776 pred
.find((*i
).first
) != pred
.end());
1777 if (pred
.find((*i
).first
) != pred
.end())
1778 os
<< "(" << pred
[(*i
).first
] << ")";
1780 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1783 (*i
).second
[j
]->print(os
, p
);
1784 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1785 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1791 void indicator::add(const indicator_term
* it
)
1793 indicator_term
*nt
= new indicator_term(*it
);
1794 if (options
->lexmin_reduce
)
1795 nt
->reduce_in_domain(P
? P
: D
->D
);
1797 order
.add(nt
, NULL
);
1798 assert(term
.size() == order
.head
.size() + order
.pred
.size());
1801 void indicator::remove(const indicator_term
* it
)
1803 vector
<indicator_term
*>::iterator i
;
1804 i
= find(term
.begin(), term
.end(), it
);
1805 assert(i
!= term
.end());
1808 assert(term
.size() == order
.head
.size() + order
.pred
.size());
1812 void indicator::expand_rational_vertex(const indicator_term
*initial
)
1814 int pos
= initial
->pos
;
1816 if (ic
.terms
[pos
].size() == 0) {
1818 FORALL_PVertex_in_ParamPolyhedron(V
, PD
, ic
.PP
) // _i is internal counter
1820 ic
.decompose_at_vertex(V
, pos
, options
);
1823 END_FORALL_PVertex_in_ParamPolyhedron
;
1825 for (int j
= 0; j
< ic
.terms
[pos
].size(); ++j
)
1826 add(ic
.terms
[pos
][j
]);
1829 void indicator::remove_initial_rational_vertices()
1832 const indicator_term
*initial
= NULL
;
1833 std::set
<const indicator_term
*>::iterator i
;
1834 for (i
= order
.head
.begin(); i
!= order
.head
.end(); ++i
) {
1835 if ((*i
)->sign
!= 0)
1837 if (order
.eq
.find(*i
) != order
.eq
.end() && order
.eq
[*i
].size() <= 1)
1844 expand_rational_vertex(initial
);
1848 void indicator::reduce_in_domain(Polyhedron
*D
)
1850 for (int i
= 0; i
< term
.size(); ++i
)
1851 term
[i
]->reduce_in_domain(D
);
1854 void indicator::print(ostream
& os
, char **p
)
1856 assert(term
.size() == order
.head
.size() + order
.pred
.size());
1857 for (int i
= 0; i
< term
.size(); ++i
) {
1858 term
[i
]->print(os
, p
);
1860 os
<< ": " << term
[i
]->eval(D
->sample
->p
);
1867 /* Remove pairs of opposite terms */
1868 void indicator::simplify()
1870 for (int i
= 0; i
< term
.size(); ++i
) {
1871 for (int j
= i
+1; j
< term
.size(); ++j
) {
1872 if (term
[i
]->sign
+ term
[j
]->sign
!= 0)
1874 if (term
[i
]->den
!= term
[j
]->den
)
1877 for (k
= 0; k
< term
[i
]->den
.NumCols(); ++k
)
1878 if (!eequal(term
[i
]->vertex
[k
], term
[j
]->vertex
[k
]))
1880 if (k
< term
[i
]->den
.NumCols())
1884 term
.erase(term
.begin()+j
);
1885 term
.erase(term
.begin()+i
);
1892 void indicator::peel(int i
, int j
)
1900 int dim
= term
[i
]->den
.NumCols();
1905 int n_common
= 0, n_i
= 0, n_j
= 0;
1907 common
.SetDims(min(term
[i
]->den
.NumRows(), term
[j
]->den
.NumRows()), dim
);
1908 rest_i
.SetDims(term
[i
]->den
.NumRows(), dim
);
1909 rest_j
.SetDims(term
[j
]->den
.NumRows(), dim
);
1912 for (k
= 0, l
= 0; k
< term
[i
]->den
.NumRows() && l
< term
[j
]->den
.NumRows(); ) {
1913 int s
= lex_cmp(term
[i
]->den
[k
], term
[j
]->den
[l
]);
1915 common
[n_common
++] = term
[i
]->den
[k
];
1919 rest_i
[n_i
++] = term
[i
]->den
[k
++];
1921 rest_j
[n_j
++] = term
[j
]->den
[l
++];
1923 while (k
< term
[i
]->den
.NumRows())
1924 rest_i
[n_i
++] = term
[i
]->den
[k
++];
1925 while (l
< term
[j
]->den
.NumRows())
1926 rest_j
[n_j
++] = term
[j
]->den
[l
++];
1927 common
.SetDims(n_common
, dim
);
1928 rest_i
.SetDims(n_i
, dim
);
1929 rest_j
.SetDims(n_j
, dim
);
1931 for (k
= 0; k
<= n_i
; ++k
) {
1932 indicator_term
*it
= new indicator_term(*term
[i
]);
1933 it
->den
.SetDims(n_common
+ k
, dim
);
1934 for (l
= 0; l
< n_common
; ++l
)
1935 it
->den
[l
] = common
[l
];
1936 for (l
= 0; l
< k
; ++l
)
1937 it
->den
[n_common
+l
] = rest_i
[l
];
1938 lex_order_rows(it
->den
);
1940 for (l
= 0; l
< dim
; ++l
)
1941 evalue_add_constant(it
->vertex
[l
], rest_i
[k
-1][l
]);
1945 for (k
= 0; k
<= n_j
; ++k
) {
1946 indicator_term
*it
= new indicator_term(*term
[j
]);
1947 it
->den
.SetDims(n_common
+ k
, dim
);
1948 for (l
= 0; l
< n_common
; ++l
)
1949 it
->den
[l
] = common
[l
];
1950 for (l
= 0; l
< k
; ++l
)
1951 it
->den
[n_common
+l
] = rest_j
[l
];
1952 lex_order_rows(it
->den
);
1954 for (l
= 0; l
< dim
; ++l
)
1955 evalue_add_constant(it
->vertex
[l
], rest_j
[k
-1][l
]);
1958 term
.erase(term
.begin()+j
);
1959 term
.erase(term
.begin()+i
);
1962 void indicator::combine(const indicator_term
*a
, const indicator_term
*b
)
1964 int dim
= a
->den
.NumCols();
1967 mat_ZZ rest_i
; /* factors in a, but not in b */
1968 mat_ZZ rest_j
; /* factors in b, but not in a */
1969 int n_common
= 0, n_i
= 0, n_j
= 0;
1971 common
.SetDims(min(a
->den
.NumRows(), b
->den
.NumRows()), dim
);
1972 rest_i
.SetDims(a
->den
.NumRows(), dim
);
1973 rest_j
.SetDims(b
->den
.NumRows(), dim
);
1976 for (k
= 0, l
= 0; k
< a
->den
.NumRows() && l
< b
->den
.NumRows(); ) {
1977 int s
= lex_cmp(a
->den
[k
], b
->den
[l
]);
1979 common
[n_common
++] = a
->den
[k
];
1983 rest_i
[n_i
++] = a
->den
[k
++];
1985 rest_j
[n_j
++] = b
->den
[l
++];
1987 while (k
< a
->den
.NumRows())
1988 rest_i
[n_i
++] = a
->den
[k
++];
1989 while (l
< b
->den
.NumRows())
1990 rest_j
[n_j
++] = b
->den
[l
++];
1991 common
.SetDims(n_common
, dim
);
1992 rest_i
.SetDims(n_i
, dim
);
1993 rest_j
.SetDims(n_j
, dim
);
1995 assert(order
.eq
[a
].size() > 1);
1996 indicator_term
*prev
;
1999 for (int k
= n_i
-1; k
>= 0; --k
) {
2000 indicator_term
*it
= new indicator_term(*b
);
2001 it
->den
.SetDims(n_common
+ n_j
+ n_i
-k
, dim
);
2002 for (int l
= k
; l
< n_i
; ++l
)
2003 it
->den
[n_common
+n_j
+l
-k
] = rest_i
[l
];
2004 lex_order_rows(it
->den
);
2005 for (int m
= 0; m
< dim
; ++m
)
2006 evalue_add_constant(it
->vertex
[m
], rest_i
[k
][m
]);
2007 it
->sign
= -it
->sign
;
2009 order
.pending
[it
].push_back(prev
);
2010 order
.lt
[it
].push_back(prev
);
2011 order
.inc_pred(prev
);
2014 order
.head
.insert(it
);
2018 indicator_term
*it
= new indicator_term(*b
);
2019 it
->den
.SetDims(n_common
+ n_i
+ n_j
, dim
);
2020 for (l
= 0; l
< n_i
; ++l
)
2021 it
->den
[n_common
+n_j
+l
] = rest_i
[l
];
2022 lex_order_rows(it
->den
);
2024 order
.pending
[a
].push_back(prev
);
2025 order
.lt
[a
].push_back(prev
);
2026 order
.inc_pred(prev
);
2027 order
.replace(b
, it
);
2032 for (int k
= n_j
-1; k
>= 0; --k
) {
2033 indicator_term
*it
= new indicator_term(*a
);
2034 it
->den
.SetDims(n_common
+ n_i
+ n_j
-k
, dim
);
2035 for (int l
= k
; l
< n_j
; ++l
)
2036 it
->den
[n_common
+n_i
+l
-k
] = rest_j
[l
];
2037 lex_order_rows(it
->den
);
2038 for (int m
= 0; m
< dim
; ++m
)
2039 evalue_add_constant(it
->vertex
[m
], rest_j
[k
][m
]);
2040 it
->sign
= -it
->sign
;
2042 order
.pending
[it
].push_back(prev
);
2043 order
.lt
[it
].push_back(prev
);
2044 order
.inc_pred(prev
);
2047 order
.head
.insert(it
);
2051 indicator_term
*it
= new indicator_term(*a
);
2052 it
->den
.SetDims(n_common
+ n_i
+ n_j
, dim
);
2053 for (l
= 0; l
< n_j
; ++l
)
2054 it
->den
[n_common
+n_i
+l
] = rest_j
[l
];
2055 lex_order_rows(it
->den
);
2057 order
.pending
[a
].push_back(prev
);
2058 order
.lt
[a
].push_back(prev
);
2059 order
.inc_pred(prev
);
2060 order
.replace(a
, it
);
2064 assert(term
.size() == order
.head
.size() + order
.pred
.size());
2067 bool indicator::handle_equal_numerators(const indicator_term
*base
)
2069 for (int i
= 0; i
< order
.eq
[base
].size(); ++i
) {
2070 for (int j
= i
+1; j
< order
.eq
[base
].size(); ++j
) {
2071 if (order
.eq
[base
][i
]->is_opposite(order
.eq
[base
][j
])) {
2072 remove(order
.eq
[base
][j
]);
2073 remove(i
? order
.eq
[base
][i
] : base
);
2078 for (int j
= 1; j
< order
.eq
[base
].size(); ++j
)
2079 if (order
.eq
[base
][j
]->sign
!= base
->sign
) {
2080 combine(base
, order
.eq
[base
][j
]);
2086 void indicator::substitute(evalue
*equation
)
2088 ::substitute(term
, equation
);
2091 void indicator::add_substitution(evalue
*equation
)
2093 for (int i
= 0; i
< substitutions
.size(); ++i
)
2094 if (eequal(substitutions
[i
], equation
))
2096 evalue
*copy
= new evalue();
2097 value_init(copy
->d
);
2098 evalue_copy(copy
, equation
);
2099 substitutions
.push_back(copy
);
2102 void indicator::perform_pending_substitutions()
2104 if (substitutions
.size() == 0)
2107 for (int i
= 0; i
< substitutions
.size(); ++i
) {
2108 substitute(substitutions
[i
]);
2109 free_evalue_refs(substitutions
[i
]);
2110 delete substitutions
[i
];
2112 substitutions
.clear();
2116 static void print_varlist(ostream
& os
, int n
, char **names
)
2120 for (i
= 0; i
< n
; ++i
) {
2128 void max_term::print(ostream
& os
, char **p
, barvinok_options
*options
) const
2131 print_varlist(os
, domain
->dimension(), p
);
2134 for (int i
= 0; i
< max
.size(); ++i
) {
2137 evalue_print(os
, max
[i
], p
);
2141 domain
->print_constraints(os
, p
, options
);
2145 Matrix
*left_inverse(Matrix
*M
, Matrix
**Eq
)
2148 Matrix
*L
, *H
, *Q
, *U
, *ratH
, *invH
, *Ut
, *inv
;
2153 L
= Matrix_Alloc(M
->NbRows
-1, M
->NbColumns
-1);
2154 for (i
= 0; i
< L
->NbRows
; ++i
)
2155 Vector_Copy(M
->p
[i
], L
->p
[i
], L
->NbColumns
);
2156 right_hermite(L
, &H
, &U
, &Q
);
2159 t
= Vector_Alloc(U
->NbColumns
);
2160 for (i
= 0; i
< U
->NbColumns
; ++i
)
2161 value_oppose(t
->p
[i
], M
->p
[i
][M
->NbColumns
-1]);
2163 *Eq
= Matrix_Alloc(H
->NbRows
- H
->NbColumns
, 2 + U
->NbColumns
);
2164 for (i
= 0; i
< H
->NbRows
- H
->NbColumns
; ++i
) {
2165 Vector_Copy(U
->p
[H
->NbColumns
+i
], (*Eq
)->p
[i
]+1, U
->NbColumns
);
2166 Inner_Product(U
->p
[H
->NbColumns
+i
], t
->p
, U
->NbColumns
,
2167 (*Eq
)->p
[i
]+1+U
->NbColumns
);
2170 ratH
= Matrix_Alloc(H
->NbColumns
+1, H
->NbColumns
+1);
2171 invH
= Matrix_Alloc(H
->NbColumns
+1, H
->NbColumns
+1);
2172 for (i
= 0; i
< H
->NbColumns
; ++i
)
2173 Vector_Copy(H
->p
[i
], ratH
->p
[i
], H
->NbColumns
);
2174 value_set_si(ratH
->p
[ratH
->NbRows
-1][ratH
->NbColumns
-1], 1);
2176 ok
= Matrix_Inverse(ratH
, invH
);
2179 Ut
= Matrix_Alloc(invH
->NbRows
, U
->NbColumns
+1);
2180 for (i
= 0; i
< Ut
->NbRows
-1; ++i
) {
2181 Vector_Copy(U
->p
[i
], Ut
->p
[i
], U
->NbColumns
);
2182 Inner_Product(U
->p
[i
], t
->p
, U
->NbColumns
, &Ut
->p
[i
][Ut
->NbColumns
-1]);
2186 value_set_si(Ut
->p
[Ut
->NbRows
-1][Ut
->NbColumns
-1], 1);
2187 inv
= Matrix_Alloc(invH
->NbRows
, Ut
->NbColumns
);
2188 Matrix_Product(invH
, Ut
, inv
);
2194 /* T maps the compressed parameters to the original parameters,
2195 * while this max_term is based on the compressed parameters
2196 * and we want get the original parameters back.
2198 void max_term::substitute(Matrix
*T
, barvinok_options
*options
)
2200 assert(domain
->dimension() == T
->NbColumns
-1);
2201 int nexist
= domain
->D
->Dimension
- (T
->NbColumns
-1);
2203 Matrix
*inv
= left_inverse(T
, &Eq
);
2206 value_init(denom
.d
);
2207 value_init(denom
.x
.n
);
2208 value_set_si(denom
.x
.n
, 1);
2209 value_assign(denom
.d
, inv
->p
[inv
->NbRows
-1][inv
->NbColumns
-1]);
2212 v
.SetLength(inv
->NbColumns
);
2213 evalue
* subs
[inv
->NbRows
-1];
2214 for (int i
= 0; i
< inv
->NbRows
-1; ++i
) {
2215 values2zz(inv
->p
[i
], v
, v
.length());
2216 subs
[i
] = multi_monom(v
);
2217 emul(&denom
, subs
[i
]);
2219 free_evalue_refs(&denom
);
2221 domain
->substitute(subs
, inv
, Eq
, options
->MaxRays
);
2224 for (int i
= 0; i
< max
.size(); ++i
) {
2225 evalue_substitute(max
[i
], subs
);
2226 reduce_evalue(max
[i
]);
2229 for (int i
= 0; i
< inv
->NbRows
-1; ++i
) {
2230 free_evalue_refs(subs
[i
]);
2236 int Last_Non_Zero(Value
*p
, unsigned len
)
2238 for (int i
= len
-1; i
>= 0; --i
)
2239 if (value_notzero_p(p
[i
]))
2244 static void SwapColumns(Value
**V
, int n
, int i
, int j
)
2246 for (int r
= 0; r
< n
; ++r
)
2247 value_swap(V
[r
][i
], V
[r
][j
]);
2250 static void SwapColumns(Polyhedron
*P
, int i
, int j
)
2252 SwapColumns(P
->Constraint
, P
->NbConstraints
, i
, j
);
2253 SwapColumns(P
->Ray
, P
->NbRays
, i
, j
);
2256 Vector
*max_term::eval(Value
*val
, unsigned MaxRays
) const
2258 if (!domain
->contains(val
, domain
->dimension()))
2260 Vector
*res
= Vector_Alloc(max
.size());
2261 for (int i
= 0; i
< max
.size(); ++i
) {
2262 compute_evalue(max
[i
], val
, &res
->p
[i
]);
2269 enum sign
{ le
, ge
, lge
} sign
;
2271 split (evalue
*c
, enum sign s
) : constraint(c
), sign(s
) {}
2274 static void split_on(const split
& sp
, EDomain
*D
,
2275 EDomain
**Dlt
, EDomain
**Deq
, EDomain
**Dgt
,
2276 barvinok_options
*options
)
2282 ge_constraint
*ge
= D
->compute_ge_constraint(sp
.constraint
);
2283 if (sp
.sign
== split::lge
|| sp
.sign
== split::ge
)
2284 ED
[2] = EDomain::new_from_ge_constraint(ge
, 1, options
);
2287 if (sp
.sign
== split::lge
|| sp
.sign
== split::le
)
2288 ED
[0] = EDomain::new_from_ge_constraint(ge
, -1, options
);
2292 assert(sp
.sign
== split::lge
|| sp
.sign
== split::ge
|| sp
.sign
== split::le
);
2293 ED
[1] = EDomain::new_from_ge_constraint(ge
, 0, options
);
2297 for (int i
= 0; i
< 3; ++i
) {
2300 if (D
->sample
&& ED
[i
]->contains(D
->sample
->p
, D
->sample
->Size
-1)) {
2301 ED
[i
]->sample
= Vector_Alloc(D
->sample
->Size
);
2302 Vector_Copy(D
->sample
->p
, ED
[i
]->sample
->p
, D
->sample
->Size
);
2303 } else if (emptyQ2(ED
[i
]->D
) ||
2304 (options
->lexmin_emptiness_check
!= BV_LEXMIN_EMPTINESS_CHECK_NONE
&&
2305 !(ED
[i
]->not_empty(options
)))) {
2315 ostream
& operator<< (ostream
& os
, const vector
<int> & v
)
2318 for (int i
= 0; i
< v
.size(); ++i
) {
2327 static bool isTranslation(Matrix
*M
)
2330 if (M
->NbRows
!= M
->NbColumns
)
2333 for (i
= 0;i
< M
->NbRows
; i
++)
2334 for (j
= 0; j
< M
->NbColumns
-1; j
++)
2336 if(value_notone_p(M
->p
[i
][j
]))
2339 if(value_notzero_p(M
->p
[i
][j
]))
2342 return value_one_p(M
->p
[M
->NbRows
-1][M
->NbColumns
-1]);
2345 static Matrix
*compress_parameters(Polyhedron
**P
, Polyhedron
**C
,
2346 unsigned nparam
, unsigned MaxRays
)
2350 /* compress_parms doesn't like equalities that only involve parameters */
2351 for (int i
= 0; i
< (*P
)->NbEq
; ++i
)
2352 assert(First_Non_Zero((*P
)->Constraint
[i
]+1, (*P
)->Dimension
-nparam
) != -1);
2354 M
= Matrix_Alloc((*P
)->NbEq
, (*P
)->Dimension
+2);
2355 Vector_Copy((*P
)->Constraint
[0], M
->p
[0], (*P
)->NbEq
* ((*P
)->Dimension
+2));
2356 CP
= compress_parms(M
, nparam
);
2359 if (isTranslation(CP
)) {
2364 T
= align_matrix(CP
, (*P
)->Dimension
+1);
2365 *P
= Polyhedron_Preimage(*P
, T
, MaxRays
);
2368 *C
= Polyhedron_Preimage(*C
, CP
, MaxRays
);
2373 void construct_rational_vertices(Param_Polyhedron
*PP
, Matrix
*T
, unsigned dim
,
2374 int nparam
, vector
<indicator_term
*>& vertices
)
2383 v
.SetLength(nparam
+1);
2386 value_init(factor
.d
);
2387 value_init(factor
.x
.n
);
2388 value_set_si(factor
.x
.n
, 1);
2389 value_set_si(factor
.d
, 1);
2391 for (i
= 0, PV
= PP
->V
; PV
; ++i
, PV
= PV
->next
) {
2392 indicator_term
*term
= new indicator_term(dim
, i
);
2393 vertices
.push_back(term
);
2394 Matrix
*M
= Matrix_Alloc(PV
->Vertex
->NbRows
+nparam
+1, nparam
+1);
2395 value_set_si(lcm
, 1);
2396 for (int j
= 0; j
< PV
->Vertex
->NbRows
; ++j
)
2397 value_lcm(lcm
, PV
->Vertex
->p
[j
][nparam
+1], &lcm
);
2398 value_assign(M
->p
[M
->NbRows
-1][M
->NbColumns
-1], lcm
);
2399 for (int j
= 0; j
< PV
->Vertex
->NbRows
; ++j
) {
2400 value_division(tmp
, lcm
, PV
->Vertex
->p
[j
][nparam
+1]);
2401 Vector_Scale(PV
->Vertex
->p
[j
], M
->p
[j
], tmp
, nparam
+1);
2403 for (int j
= 0; j
< nparam
; ++j
)
2404 value_assign(M
->p
[PV
->Vertex
->NbRows
+j
][j
], lcm
);
2406 Matrix
*M2
= Matrix_Alloc(T
->NbRows
, M
->NbColumns
);
2407 Matrix_Product(T
, M
, M2
);
2411 for (int j
= 0; j
< dim
; ++j
) {
2412 values2zz(M
->p
[j
], v
, nparam
+1);
2413 term
->vertex
[j
] = multi_monom(v
);
2414 value_assign(factor
.d
, lcm
);
2415 emul(&factor
, term
->vertex
[j
]);
2419 assert(i
== PP
->nbV
);
2420 free_evalue_refs(&factor
);
2425 static vector
<max_term
*> lexmin(indicator
& ind
, unsigned nparam
,
2428 vector
<max_term
*> maxima
;
2429 std::set
<const indicator_term
*>::iterator i
;
2430 vector
<int> best_score
;
2431 vector
<int> second_score
;
2432 vector
<int> neg_score
;
2435 ind
.perform_pending_substitutions();
2436 const indicator_term
*best
= NULL
, *second
= NULL
, *neg
= NULL
,
2437 *neg_eq
= NULL
, *neg_le
= NULL
;
2438 for (i
= ind
.order
.head
.begin(); i
!= ind
.order
.head
.end(); ++i
) {
2440 const indicator_term
*term
= *i
;
2441 if (term
->sign
== 0) {
2442 ind
.expand_rational_vertex(term
);
2446 if (ind
.order
.eq
.find(term
) != ind
.order
.eq
.end()) {
2448 if (ind
.order
.eq
[term
].size() <= 1)
2450 for (j
= 1; j
< ind
.order
.eq
[term
].size(); ++j
)
2451 if (ind
.order
.pred
.find(ind
.order
.eq
[term
][j
]) !=
2452 ind
.order
.pred
.end())
2454 if (j
< ind
.order
.eq
[term
].size())
2456 score
.push_back(ind
.order
.eq
[term
].size());
2459 if (ind
.order
.le
.find(term
) != ind
.order
.le
.end())
2460 score
.push_back(ind
.order
.le
[term
].size());
2463 if (ind
.order
.lt
.find(term
) != ind
.order
.lt
.end())
2464 score
.push_back(-ind
.order
.lt
[term
].size());
2468 if (term
->sign
> 0) {
2469 if (!best
|| score
< best_score
) {
2471 second_score
= best_score
;
2474 } else if (!second
|| score
< second_score
) {
2476 second_score
= score
;
2479 if (!neg_eq
&& ind
.order
.eq
.find(term
) != ind
.order
.eq
.end()) {
2480 for (int j
= 1; j
< ind
.order
.eq
[term
].size(); ++j
)
2481 if (ind
.order
.eq
[term
][j
]->sign
!= term
->sign
) {
2486 if (!neg_le
&& ind
.order
.le
.find(term
) != ind
.order
.le
.end())
2488 if (!neg
|| score
< neg_score
) {
2494 if (i
!= ind
.order
.head
.end())
2497 if (!best
&& neg_eq
) {
2498 assert(ind
.order
.eq
[neg_eq
].size() != 0);
2499 bool handled
= ind
.handle_equal_numerators(neg_eq
);
2504 if (!best
&& neg_le
) {
2505 /* The smallest term is negative and <= some positive term */
2511 /* apparently there can be negative initial term on empty domains */
2512 if (ind
.options
->lexmin_emptiness_check
!=
2513 BV_LEXMIN_EMPTINESS_CHECK_NONE
&&
2514 ind
.options
->lexmin_polysign
== BV_LEXMIN_POLYSIGN_POLYLIB
)
2519 if (!second
&& !neg
) {
2520 const indicator_term
*rat
= NULL
;
2522 if (ind
.order
.le
.find(best
) == ind
.order
.le
.end()) {
2523 if (ind
.order
.eq
.find(best
) != ind
.order
.eq
.end()) {
2524 bool handled
= ind
.handle_equal_numerators(best
);
2525 if (ind
.options
->lexmin_emptiness_check
!=
2526 BV_LEXMIN_EMPTINESS_CHECK_NONE
&&
2527 ind
.options
->lexmin_polysign
== BV_LEXMIN_POLYSIGN_POLYLIB
)
2529 /* If !handled then the leading coefficient is bigger than one;
2530 * must be an empty domain
2537 maxima
.push_back(ind
.create_max_term(best
));
2540 for (int j
= 0; j
< ind
.order
.le
[best
].size(); ++j
) {
2541 if (ind
.order
.le
[best
][j
]->sign
== 0) {
2542 if (!rat
&& ind
.order
.pred
[ind
.order
.le
[best
][j
]] == 1)
2543 rat
= ind
.order
.le
[best
][j
];
2544 } else if (ind
.order
.le
[best
][j
]->sign
> 0) {
2545 second
= ind
.order
.le
[best
][j
];
2548 neg
= ind
.order
.le
[best
][j
];
2551 if (!second
&& !neg
) {
2553 ind
.order
.unset_le(best
, rat
);
2554 ind
.expand_rational_vertex(rat
);
2561 ind
.order
.unset_le(best
, second
);
2567 unsigned dim
= best
->den
.NumCols();
2570 for (int k
= 0; k
< dim
; ++k
) {
2571 diff
= ediff(best
->vertex
[k
], second
->vertex
[k
]);
2572 sign
= evalue_sign(diff
, ind
.D
, ind
.options
);
2574 /* neg can never be smaller than best, unless it may still cancel.
2575 * This can happen if positive terms have been determined to
2576 * be equal or less than or equal to some negative term.
2578 if (second
== neg
&& !neg_eq
&& !neg_le
) {
2579 if (sign
== order_ge
)
2581 if (sign
== order_unknown
)
2585 if (sign
!= order_eq
)
2587 if (!EVALUE_IS_ZERO(*diff
)) {
2588 ind
.add_substitution(diff
);
2589 ind
.perform_pending_substitutions();
2592 if (sign
== order_eq
) {
2593 ind
.order
.set_equal(best
, second
);
2596 if (sign
== order_lt
) {
2597 ind
.order
.lt
[best
].push_back(second
);
2598 ind
.order
.inc_pred(second
);
2601 if (sign
== order_gt
) {
2602 ind
.order
.lt
[second
].push_back(best
);
2603 ind
.order
.inc_pred(best
);
2607 split
sp(diff
, sign
== order_le
? split::le
:
2608 sign
== order_ge
? split::ge
: split::lge
);
2610 EDomain
*Dlt
, *Deq
, *Dgt
;
2611 split_on(sp
, ind
.D
, &Dlt
, &Deq
, &Dgt
, ind
.options
);
2612 if (ind
.options
->lexmin_emptiness_check
!= BV_LEXMIN_EMPTINESS_CHECK_NONE
)
2613 assert(Dlt
|| Deq
|| Dgt
);
2614 else if (!(Dlt
|| Deq
|| Dgt
))
2615 /* Must have been empty all along */
2618 if (Deq
&& (Dlt
|| Dgt
)) {
2619 int locsize
= loc
.size();
2621 indicator
indeq(ind
, Deq
);
2623 indeq
.add_substitution(diff
);
2624 indeq
.perform_pending_substitutions();
2625 vector
<max_term
*> maxeq
= lexmin(indeq
, nparam
, loc
);
2626 maxima
.insert(maxima
.end(), maxeq
.begin(), maxeq
.end());
2627 loc
.resize(locsize
);
2630 int locsize
= loc
.size();
2632 indicator
indgt(ind
, Dgt
);
2634 /* we don't know the new location of these terms in indgt */
2636 indgt.order.lt[second].push_back(best);
2637 indgt.order.inc_pred(best);
2639 vector
<max_term
*> maxgt
= lexmin(indgt
, nparam
, loc
);
2640 maxima
.insert(maxima
.end(), maxgt
.begin(), maxgt
.end());
2641 loc
.resize(locsize
);
2646 ind
.set_domain(Deq
);
2647 ind
.add_substitution(diff
);
2648 ind
.perform_pending_substitutions();
2652 ind
.set_domain(Dlt
);
2653 ind
.order
.lt
[best
].push_back(second
);
2654 ind
.order
.inc_pred(second
);
2658 ind
.set_domain(Dgt
);
2659 ind
.order
.lt
[second
].push_back(best
);
2660 ind
.order
.inc_pred(best
);
2667 static vector
<max_term
*> lexmin(Polyhedron
*P
, Polyhedron
*C
,
2668 barvinok_options
*options
)
2670 unsigned nparam
= C
->Dimension
;
2671 Param_Polyhedron
*PP
= NULL
;
2672 Polyhedron
*CEq
= NULL
, *pVD
;
2674 Matrix
*T
= NULL
, *CP
= NULL
;
2675 Param_Domain
*D
, *next
;
2677 Polyhedron
*Porig
= P
;
2678 Polyhedron
*Corig
= C
;
2679 vector
<max_term
*> all_max
;
2681 unsigned P2PSD_MaxRays
;
2686 POL_ENSURE_VERTICES(P
);
2691 assert(P
->NbBid
== 0);
2694 remove_all_equalities(&P
, &C
, &CP
, &T
, nparam
, options
->MaxRays
);
2696 nparam
= CP
->NbColumns
-1;
2704 if (options
->MaxRays
& POL_NO_DUAL
)
2707 P2PSD_MaxRays
= options
->MaxRays
;
2710 PP
= Polyhedron2Param_SimplifiedDomain(&P
, C
, P2PSD_MaxRays
, &CEq
, &CT
);
2711 if (P
!= Q
&& Q
!= Porig
)
2715 if (isIdentity(CT
)) {
2719 nparam
= CT
->NbRows
- 1;
2723 unsigned dim
= P
->Dimension
- nparam
;
2726 for (nd
= 0, D
=PP
->D
; D
; ++nd
, D
=D
->next
);
2727 Polyhedron
**fVD
= new Polyhedron
*[nd
];
2729 indicator_constructor
ic(P
, dim
, PP
, T
);
2731 vector
<indicator_term
*> all_vertices
;
2732 construct_rational_vertices(PP
, T
, T
? T
->NbRows
-nparam
-1 : dim
,
2733 nparam
, all_vertices
);
2735 for (nd
= 0, D
=PP
->D
; D
; D
=next
) {
2738 Polyhedron
*rVD
= reduce_domain(D
->Domain
, CT
, CEq
,
2739 fVD
, nd
, options
->MaxRays
);
2743 pVD
= CT
? DomainImage(rVD
,CT
,options
->MaxRays
) : rVD
;
2745 EDomain
*epVD
= new EDomain(pVD
);
2746 indicator
ind(ic
, D
, epVD
, options
);
2748 FORALL_PVertex_in_ParamPolyhedron(V
,D
,PP
) // _i is internal counter
2749 ind
.add(all_vertices
[_i
]);
2750 END_FORALL_PVertex_in_ParamPolyhedron
;
2752 ind
.remove_initial_rational_vertices();
2755 vector
<max_term
*> maxima
= lexmin(ind
, nparam
, loc
);
2757 for (int j
= 0; j
< maxima
.size(); ++j
)
2758 maxima
[j
]->substitute(CP
, options
);
2759 all_max
.insert(all_max
.end(), maxima
.begin(), maxima
.end());
2766 for (int i
= 0; i
< all_vertices
.size(); ++i
)
2767 delete all_vertices
[i
];
2772 Param_Polyhedron_Free(PP
);
2774 Polyhedron_Free(CEq
);
2775 for (--nd
; nd
>= 0; --nd
) {
2776 Domain_Free(fVD
[nd
]);
2787 static void verify_results(Polyhedron
*A
, Polyhedron
*C
,
2788 vector
<max_term
*>& maxima
, int m
, int M
,
2789 int print_all
, unsigned MaxRays
);
2791 int main(int argc
, char **argv
)
2796 char **iter_names
, **param_names
;
2801 int m
= INT_MAX
, M
= INT_MIN
, r
;
2802 int print_solution
= 1;
2803 struct barvinok_options
*options
;
2805 options
= barvinok_options_new_with_defaults();
2807 while ((c
= getopt_long(argc
, argv
, "TAm:M:r:V", lexmin_options
, &ind
)) != -1) {
2809 case EMPTINESS_CHECK
:
2810 if (!strcmp(optarg
, "none"))
2811 options
->lexmin_emptiness_check
= BV_LEXMIN_EMPTINESS_CHECK_NONE
;
2812 else if (!strcmp(optarg
, "count"))
2813 options
->lexmin_emptiness_check
= BV_LEXMIN_EMPTINESS_CHECK_COUNT
;
2816 options
->lexmin_reduce
= 0;
2818 case BASIS_REDUCTION_CDD
:
2819 options
->gbr_lp_solver
= BV_GBR_CDD
;
2822 if (!strcmp(optarg
, "cddf"))
2823 options
->lexmin_polysign
= BV_LEXMIN_POLYSIGN_CDDF
;
2824 else if (!strcmp(optarg
, "cdd"))
2825 options
->lexmin_polysign
= BV_LEXMIN_POLYSIGN_CDD
;
2847 printf(barvinok_version());
2854 C
= Constraints2Polyhedron(MA
, options
->MaxRays
);
2856 fscanf(stdin
, " %d", &bignum
);
2857 assert(bignum
== -1);
2859 A
= Constraints2Polyhedron(MA
, options
->MaxRays
);
2862 if (A
->Dimension
>= VBIGDIM
)
2864 else if (A
->Dimension
>= BIGDIM
)
2873 if (verify
&& m
> M
) {
2874 fprintf(stderr
,"Nothing to do: min > max !\n");
2880 iter_names
= util_generate_names(A
->Dimension
- C
->Dimension
, "i");
2881 param_names
= util_generate_names(C
->Dimension
, "p");
2882 if (print_solution
) {
2883 Polyhedron_Print(stdout
, P_VALUE_FMT
, A
);
2884 Polyhedron_Print(stdout
, P_VALUE_FMT
, C
);
2886 vector
<max_term
*> maxima
= lexmin(A
, C
, options
);
2888 for (int i
= 0; i
< maxima
.size(); ++i
)
2889 maxima
[i
]->print(cout
, param_names
, options
);
2892 verify_results(A
, C
, maxima
, m
, M
, print_all
, options
->MaxRays
);
2894 for (int i
= 0; i
< maxima
.size(); ++i
)
2897 util_free_names(A
->Dimension
- C
->Dimension
, iter_names
);
2898 util_free_names(C
->Dimension
, param_names
);
2907 static bool lexmin(int pos
, Polyhedron
*P
, Value
*context
)
2916 value_init(LB
); value_init(UB
); value_init(k
);
2919 lu_flags
= lower_upper_bounds(pos
,P
,context
,&LB
,&UB
);
2920 assert(!(lu_flags
& LB_INFINITY
));
2922 value_set_si(context
[pos
],0);
2923 if (!lu_flags
&& value_lt(UB
,LB
)) {
2924 value_clear(LB
); value_clear(UB
); value_clear(k
);
2928 value_assign(context
[pos
], LB
);
2929 value_clear(LB
); value_clear(UB
); value_clear(k
);
2932 for (value_assign(k
,LB
); lu_flags
|| value_le(k
,UB
); value_increment(k
,k
)) {
2933 value_assign(context
[pos
],k
);
2934 if ((found
= lexmin(pos
+1, P
->next
, context
)))
2938 value_set_si(context
[pos
],0);
2939 value_clear(LB
); value_clear(UB
); value_clear(k
);
2943 static void print_list(FILE *out
, Value
*z
, char* brackets
, int len
)
2945 fprintf(out
, "%c", brackets
[0]);
2946 value_print(out
, VALUE_FMT
,z
[0]);
2947 for (int k
= 1; k
< len
; ++k
) {
2949 value_print(out
, VALUE_FMT
,z
[k
]);
2951 fprintf(out
, "%c", brackets
[1]);
2954 static int check_poly(Polyhedron
*S
, Polyhedron
*CS
, vector
<max_term
*>& maxima
,
2955 int nparam
, int pos
, Value
*z
, int print_all
, int st
,
2958 if (pos
== nparam
) {
2960 bool found
= lexmin(1, S
, z
);
2964 print_list(stdout
, z
+S
->Dimension
-nparam
+1, "()", nparam
);
2967 print_list(stdout
, z
+1, "[]", S
->Dimension
-nparam
);
2972 for (int i
= 0; i
< maxima
.size(); ++i
)
2973 if ((min
= maxima
[i
]->eval(z
+S
->Dimension
-nparam
+1, MaxRays
)))
2976 int ok
= !(found
^ !!min
);
2978 for (int i
= 0; i
< S
->Dimension
-nparam
; ++i
)
2979 if (value_ne(z
[1+i
], min
->p
[i
])) {
2986 fprintf(stderr
, "Error !\n");
2987 fprintf(stderr
, "lexmin");
2988 print_list(stderr
, z
+S
->Dimension
-nparam
+1, "()", nparam
);
2989 fprintf(stderr
, " should be ");
2991 print_list(stderr
, z
+1, "[]", S
->Dimension
-nparam
);
2992 fprintf(stderr
, " while digging gives ");
2994 print_list(stderr
, min
->p
, "[]", S
->Dimension
-nparam
);
2995 fprintf(stderr
, ".\n");
2997 } else if (print_all
)
3002 for (k
= 1; k
<= S
->Dimension
-nparam
; ++k
)
3003 value_set_si(z
[k
], 0);
3011 !(lower_upper_bounds(1+pos
, CS
, &z
[S
->Dimension
-nparam
], &LB
, &UB
));
3012 for (value_assign(tmp
,LB
); value_le(tmp
,UB
); value_increment(tmp
,tmp
)) {
3014 int k
= VALUE_TO_INT(tmp
);
3015 if (!pos
&& !(k
%st
)) {
3020 value_assign(z
[pos
+S
->Dimension
-nparam
+1],tmp
);
3021 if (!check_poly(S
, CS
->next
, maxima
, nparam
, pos
+1, z
, print_all
, st
,
3029 value_set_si(z
[pos
+S
->Dimension
-nparam
+1],0);
3037 void verify_results(Polyhedron
*A
, Polyhedron
*C
, vector
<max_term
*>& maxima
,
3038 int m
, int M
, int print_all
, unsigned MaxRays
)
3040 Polyhedron
*CC
, *CC2
, *CS
, *S
;
3041 unsigned nparam
= C
->Dimension
;
3046 CC
= Polyhedron_Project(A
, nparam
);
3047 CC2
= DomainIntersection(C
, CC
, MaxRays
);
3051 /* Intersect context with range */
3056 MM
= Matrix_Alloc(2*C
->Dimension
, C
->Dimension
+2);
3057 for (int i
= 0; i
< C
->Dimension
; ++i
) {
3058 value_set_si(MM
->p
[2*i
][0], 1);
3059 value_set_si(MM
->p
[2*i
][1+i
], 1);
3060 value_set_si(MM
->p
[2*i
][1+C
->Dimension
], -m
);
3061 value_set_si(MM
->p
[2*i
+1][0], 1);
3062 value_set_si(MM
->p
[2*i
+1][1+i
], -1);
3063 value_set_si(MM
->p
[2*i
+1][1+C
->Dimension
], M
);
3065 CC2
= AddConstraints(MM
->p
[0], 2*CC
->Dimension
, CC
, MaxRays
);
3066 U
= Universe_Polyhedron(0);
3067 CS
= Polyhedron_Scan(CC2
, U
, MaxRays
& POL_NO_DUAL
? 0 : MaxRays
);
3069 Polyhedron_Free(CC2
);
3074 p
= ALLOCN(Value
, A
->Dimension
+2);
3075 for (i
=0; i
<= A
->Dimension
; i
++) {
3077 value_set_si(p
[i
],0);
3080 value_set_si(p
[i
], 1);
3082 S
= Polyhedron_Scan(A
, C
, MaxRays
& POL_NO_DUAL
? 0 : MaxRays
);
3084 if (!print_all
&& C
->Dimension
> 0) {
3089 for (int i
= m
; i
<= M
; i
+= st
)
3096 if (!(CS
&& emptyQ2(CS
)))
3097 check_poly(S
, CS
, maxima
, nparam
, 0, p
, print_all
, st
, MaxRays
);
3104 for (i
=0; i
<= (A
->Dimension
+1); i
++)
3109 Polyhedron_Free(CC
);