7 #define partition STL_PARTITION
11 #include <NTL/vec_ZZ.h>
12 #include <NTL/mat_ZZ.h>
15 #include <isl_set_polylib.h>
16 #include <barvinok/polylib.h>
17 #include <barvinok/evalue.h>
18 #include <barvinok/options.h>
19 #include <barvinok/util.h>
20 #include "conversion.h"
21 #include "decomposer.h"
22 #include "lattice_point.h"
23 #include "reduce_domain.h"
26 #include "evalue_util.h"
27 #include "remove_equalities.h"
31 #include "param_util.h"
33 #undef CS /* for Solaris 10 */
44 #define ALLOC(type) (type*)malloc(sizeof(type))
45 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
47 static int type_offset(enode
*p
)
49 return p
->type
== fractional
? 1 :
50 p
->type
== flooring
? 1 : 0;
53 void compute_evalue(evalue
*e
, Value
*val
, Value
*res
)
55 double d
= compute_evalue(e
, val
);
60 value_set_double(*res
, d
);
63 struct indicator_term
{
65 int pos
; /* number of rational vertex */
66 int n
; /* number of cone associated to given rational vertex */
70 indicator_term(unsigned dim
, int pos
) {
72 vertex
= new evalue
* [dim
];
77 indicator_term(unsigned dim
, int pos
, int n
) {
78 den
.SetDims(dim
, dim
);
79 vertex
= new evalue
* [dim
];
83 indicator_term(const indicator_term
& src
) {
88 unsigned dim
= den
.NumCols();
89 vertex
= new evalue
* [dim
];
90 for (int i
= 0; i
< dim
; ++i
) {
91 vertex
[i
] = ALLOC(evalue
);
92 value_init(vertex
[i
]->d
);
93 evalue_copy(vertex
[i
], src
.vertex
[i
]);
96 void swap(indicator_term
*other
) {
98 tmp
= sign
; sign
= other
->sign
; other
->sign
= tmp
;
99 tmp
= pos
; pos
= other
->pos
; other
->pos
= tmp
;
100 tmp
= n
; n
= other
->n
; other
->n
= tmp
;
101 mat_ZZ tmp_den
= den
; den
= other
->den
; other
->den
= tmp_den
;
102 unsigned dim
= den
.NumCols();
103 for (int i
= 0; i
< dim
; ++i
) {
104 evalue
*tmp
= vertex
[i
];
105 vertex
[i
] = other
->vertex
[i
];
106 other
->vertex
[i
] = tmp
;
110 unsigned dim
= den
.NumCols();
111 for (int i
= 0; i
< dim
; ++i
)
112 evalue_free(vertex
[i
]);
115 void print(ostream
& os
, char **p
) const;
116 void substitute(Matrix
*T
);
118 void substitute(evalue
*fract
, evalue
*val
);
119 void substitute(int pos
, evalue
*val
);
120 void reduce_in_domain(Polyhedron
*D
);
121 bool is_opposite(const indicator_term
*neg
) const;
122 vec_ZZ
eval(Value
*val
) const {
124 unsigned dim
= den
.NumCols();
128 for (int i
= 0; i
< dim
; ++i
) {
129 compute_evalue(vertex
[i
], val
, &tmp
);
137 static int evalue_rational_cmp(const evalue
*e1
, const evalue
*e2
)
145 assert(value_notzero_p(e1
->d
));
146 assert(value_notzero_p(e2
->d
));
147 value_multiply(m
, e1
->x
.n
, e2
->d
);
148 value_multiply(m2
, e2
->x
.n
, e1
->d
);
151 else if (value_gt(m
, m2
))
161 static int evalue_cmp(const evalue
*e1
, const evalue
*e2
)
163 if (value_notzero_p(e1
->d
)) {
164 if (value_zero_p(e2
->d
))
166 return evalue_rational_cmp(e1
, e2
);
168 if (value_notzero_p(e2
->d
))
170 if (e1
->x
.p
->type
!= e2
->x
.p
->type
)
171 return e1
->x
.p
->type
- e2
->x
.p
->type
;
172 if (e1
->x
.p
->size
!= e2
->x
.p
->size
)
173 return e1
->x
.p
->size
- e2
->x
.p
->size
;
174 if (e1
->x
.p
->pos
!= e2
->x
.p
->pos
)
175 return e1
->x
.p
->pos
- e2
->x
.p
->pos
;
176 assert(e1
->x
.p
->type
== polynomial
||
177 e1
->x
.p
->type
== fractional
||
178 e1
->x
.p
->type
== flooring
);
179 for (int i
= 0; i
< e1
->x
.p
->size
; ++i
) {
180 int s
= evalue_cmp(&e1
->x
.p
->arr
[i
], &e2
->x
.p
->arr
[i
]);
187 void evalue_length(evalue
*e
, int len
[2])
192 while (value_zero_p(e
->d
)) {
193 assert(e
->x
.p
->type
== polynomial
||
194 e
->x
.p
->type
== fractional
||
195 e
->x
.p
->type
== flooring
);
196 if (e
->x
.p
->type
== polynomial
)
200 int offset
= type_offset(e
->x
.p
);
201 assert(e
->x
.p
->size
== offset
+2);
202 e
= &e
->x
.p
->arr
[offset
];
206 static bool it_smaller(const indicator_term
* it1
, const indicator_term
* it2
)
210 int len1
[2], len2
[2];
211 unsigned dim
= it1
->den
.NumCols();
212 for (int i
= 0; i
< dim
; ++i
) {
213 evalue_length(it1
->vertex
[i
], len1
);
214 evalue_length(it2
->vertex
[i
], len2
);
215 if (len1
[0] != len2
[0])
216 return len1
[0] < len2
[0];
217 if (len1
[1] != len2
[1])
218 return len1
[1] < len2
[1];
220 if (it1
->pos
!= it2
->pos
)
221 return it1
->pos
< it2
->pos
;
222 if (it1
->n
!= it2
->n
)
223 return it1
->n
< it2
->n
;
224 int s
= lex_cmp(it1
->den
, it2
->den
);
227 for (int i
= 0; i
< dim
; ++i
) {
228 s
= evalue_cmp(it1
->vertex
[i
], it2
->vertex
[i
]);
232 assert(it1
->sign
!= 0);
233 assert(it2
->sign
!= 0);
234 if (it1
->sign
!= it2
->sign
)
235 return it1
->sign
> 0;
240 static const int requires_resort
;
241 bool operator()(const indicator_term
* it1
, const indicator_term
* it2
) const {
242 return it_smaller(it1
, it2
);
245 const int smaller_it::requires_resort
= 1;
247 struct smaller_it_p
{
248 static const int requires_resort
;
249 bool operator()(const indicator_term
* it1
, const indicator_term
* it2
) const {
253 const int smaller_it_p::requires_resort
= 0;
255 /* Returns true if this and neg are opposite using the knowledge
256 * that they have the same numerator.
257 * In particular, we check that the signs are different and that
258 * the denominator is the same.
260 bool indicator_term::is_opposite(const indicator_term
*neg
) const
262 if (sign
+ neg
->sign
!= 0)
269 void indicator_term::reduce_in_domain(Polyhedron
*D
)
271 for (int k
= 0; k
< den
.NumCols(); ++k
) {
272 reduce_evalue_in_domain(vertex
[k
], D
);
273 if (evalue_range_reduction_in_domain(vertex
[k
], D
))
274 reduce_evalue(vertex
[k
]);
278 void indicator_term::print(ostream
& os
, char **p
) const
280 unsigned dim
= den
.NumCols();
281 unsigned factors
= den
.NumRows();
289 for (int i
= 0; i
< dim
; ++i
) {
292 evalue_print(os
, vertex
[i
], p
);
295 for (int i
= 0; i
< factors
; ++i
) {
296 os
<< " + t" << i
<< "*[";
297 for (int j
= 0; j
< dim
; ++j
) {
304 os
<< " ((" << pos
<< ", " << n
<< ", " << (void*)this << "))";
307 /* Perform the substitution specified by T on the variables.
308 * T has dimension (newdim+nparam+1) x (olddim + nparam + 1).
309 * The substitution is performed as in gen_fun::substitute
311 void indicator_term::substitute(Matrix
*T
)
313 unsigned dim
= den
.NumCols();
314 unsigned nparam
= T
->NbColumns
- dim
- 1;
315 unsigned newdim
= T
->NbRows
- nparam
- 1;
318 matrix2zz(T
, trans
, newdim
, dim
);
319 trans
= transpose(trans
);
321 newvertex
= new evalue
* [newdim
];
324 v
.SetLength(nparam
+1);
327 value_init(factor
.d
);
328 value_set_si(factor
.d
, 1);
329 value_init(factor
.x
.n
);
330 for (int i
= 0; i
< newdim
; ++i
) {
331 values2zz(T
->p
[i
]+dim
, v
, nparam
+1);
332 newvertex
[i
] = multi_monom(v
);
334 for (int j
= 0; j
< dim
; ++j
) {
335 if (value_zero_p(T
->p
[i
][j
]))
339 evalue_copy(&term
, vertex
[j
]);
340 value_assign(factor
.x
.n
, T
->p
[i
][j
]);
341 emul(&factor
, &term
);
342 eadd(&term
, newvertex
[i
]);
343 free_evalue_refs(&term
);
346 free_evalue_refs(&factor
);
347 for (int i
= 0; i
< dim
; ++i
)
348 evalue_free(vertex
[i
]);
353 static void evalue_add_constant(evalue
*e
, ZZ v
)
358 /* go down to constant term */
359 while (value_zero_p(e
->d
))
360 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)];
363 value_multiply(tmp
, tmp
, e
->d
);
364 value_addto(e
->x
.n
, e
->x
.n
, tmp
);
369 /* Make all powers in denominator lexico-positive */
370 void indicator_term::normalize()
373 extra_vertex
.SetLength(den
.NumCols());
374 for (int r
= 0; r
< den
.NumRows(); ++r
) {
375 for (int k
= 0; k
< den
.NumCols(); ++k
) {
382 extra_vertex
+= den
[r
];
386 for (int k
= 0; k
< extra_vertex
.length(); ++k
)
387 if (extra_vertex
[k
] != 0)
388 evalue_add_constant(vertex
[k
], extra_vertex
[k
]);
391 static void substitute(evalue
*e
, evalue
*fract
, evalue
*val
)
395 for (t
= e
; value_zero_p(t
->d
); t
= &t
->x
.p
->arr
[type_offset(t
->x
.p
)]) {
396 if (t
->x
.p
->type
== fractional
&& eequal(&t
->x
.p
->arr
[0], fract
))
399 if (value_notzero_p(t
->d
))
402 free_evalue_refs(&t
->x
.p
->arr
[0]);
403 evalue
*term
= &t
->x
.p
->arr
[2];
410 free_evalue_refs(term
);
416 void indicator_term::substitute(evalue
*fract
, evalue
*val
)
418 unsigned dim
= den
.NumCols();
419 for (int i
= 0; i
< dim
; ++i
) {
420 ::substitute(vertex
[i
], fract
, val
);
424 static void substitute(evalue
*e
, int pos
, evalue
*val
)
428 for (t
= e
; value_zero_p(t
->d
); t
= &t
->x
.p
->arr
[type_offset(t
->x
.p
)]) {
429 if (t
->x
.p
->type
== polynomial
&& t
->x
.p
->pos
== pos
)
432 if (value_notzero_p(t
->d
))
435 evalue
*term
= &t
->x
.p
->arr
[1];
442 free_evalue_refs(term
);
448 void indicator_term::substitute(int pos
, evalue
*val
)
450 unsigned dim
= den
.NumCols();
451 for (int i
= 0; i
< dim
; ++i
) {
452 ::substitute(vertex
[i
], pos
, val
);
456 struct indicator_constructor
: public signed_cone_consumer
,
457 public vertex_decomposer
{
459 vector
<indicator_term
*> *terms
;
460 Matrix
*T
; /* Transformation to original space */
465 indicator_constructor(unsigned dim
, Param_Polyhedron
*PP
, Matrix
*T
) :
466 vertex_decomposer(PP
, *this), T(T
), nbV(PP
->nbV
) {
467 vertex
.SetLength(dim
);
468 terms
= new vector
<indicator_term
*>[PP
->nbV
];
470 ~indicator_constructor() {
471 for (int i
= 0; i
< nbV
; ++i
)
472 for (int j
= 0; j
< terms
[i
].size(); ++j
)
476 void print(ostream
& os
, char **p
);
478 virtual void handle(const signed_cone
& sc
, barvinok_options
*options
);
479 void decompose_at_vertex(Param_Vertices
*V
, int _i
,
480 barvinok_options
*options
) {
483 vertex_decomposer::decompose_at_vertex(V
, _i
, options
);
487 void indicator_constructor::handle(const signed_cone
& sc
, barvinok_options
*options
)
490 unsigned dim
= vertex
.length();
492 assert(sc
.rays
.NumRows() == dim
);
494 indicator_term
*term
= new indicator_term(dim
, pos
, n
++);
495 term
->sign
= sc
.sign
;
496 terms
[vert
].push_back(term
);
498 lattice_point(V
, sc
.rays
, vertex
, term
->vertex
, options
);
501 for (int r
= 0; r
< dim
; ++r
) {
502 for (int j
= 0; j
< dim
; ++j
) {
503 if (term
->den
[r
][j
] == 0)
505 if (term
->den
[r
][j
] > 0)
507 term
->sign
= -term
->sign
;
508 term
->den
[r
] = -term
->den
[r
];
509 vertex
+= term
->den
[r
];
514 for (int i
= 0; i
< dim
; ++i
) {
515 if (!term
->vertex
[i
]) {
516 term
->vertex
[i
] = ALLOC(evalue
);
517 value_init(term
->vertex
[i
]->d
);
518 value_init(term
->vertex
[i
]->x
.n
);
519 zz2value(vertex
[i
], term
->vertex
[i
]->x
.n
);
520 value_set_si(term
->vertex
[i
]->d
, 1);
525 evalue_add_constant(term
->vertex
[i
], vertex
[i
]);
533 lex_order_rows(term
->den
);
536 void indicator_constructor::print(ostream
& os
, char **p
)
538 for (int i
= 0; i
< PP
->nbV
; ++i
)
539 for (int j
= 0; j
< terms
[i
].size(); ++j
) {
540 os
<< "i: " << i
<< ", j: " << j
<< endl
;
541 terms
[i
][j
]->print(os
, p
);
546 struct order_cache_el
{
548 order_cache_el
copy() const {
550 for (int i
= 0; i
< e
.size(); ++i
) {
551 evalue
*c
= new evalue
;
553 evalue_copy(c
, e
[i
]);
559 for (int i
= 0; i
< e
.size(); ++i
) {
560 free_evalue_refs(e
[i
]);
567 evalue_set_si(&mone
, -1, 1);
568 for (int i
= 0; i
< e
.size(); ++i
)
570 free_evalue_refs(&mone
);
572 void print(ostream
& os
, char **p
);
575 void order_cache_el::print(ostream
& os
, char **p
)
578 for (int i
= 0; i
< e
.size(); ++i
) {
581 evalue_print(os
, e
[i
], p
);
587 vector
<order_cache_el
> lt
;
588 vector
<order_cache_el
> le
;
589 vector
<order_cache_el
> unknown
;
591 void clear_transients() {
592 for (int i
= 0; i
< le
.size(); ++i
)
594 for (int i
= 0; i
< unknown
.size(); ++i
)
601 for (int i
= 0; i
< lt
.size(); ++i
)
605 void add(order_cache_el
& cache_el
, order_sign sign
);
606 order_sign
check_lt(vector
<order_cache_el
>* list
,
607 const indicator_term
*a
, const indicator_term
*b
,
608 order_cache_el
& cache_el
);
609 order_sign
check_lt(const indicator_term
*a
, const indicator_term
*b
,
610 order_cache_el
& cache_el
);
611 order_sign
check_direct(const indicator_term
*a
, const indicator_term
*b
,
612 order_cache_el
& cache_el
);
613 order_sign
check(const indicator_term
*a
, const indicator_term
*b
,
614 order_cache_el
& cache_el
);
615 void copy(const order_cache
& cache
);
616 void print(ostream
& os
, char **p
);
619 void order_cache::copy(const order_cache
& cache
)
621 for (int i
= 0; i
< cache
.lt
.size(); ++i
) {
622 order_cache_el n
= cache
.lt
[i
].copy();
627 void order_cache::add(order_cache_el
& cache_el
, order_sign sign
)
629 if (sign
== order_lt
) {
630 lt
.push_back(cache_el
);
631 } else if (sign
== order_gt
) {
633 lt
.push_back(cache_el
);
634 } else if (sign
== order_le
) {
635 le
.push_back(cache_el
);
636 } else if (sign
== order_ge
) {
638 le
.push_back(cache_el
);
639 } else if (sign
== order_unknown
) {
640 unknown
.push_back(cache_el
);
642 assert(sign
== order_eq
);
649 static evalue
*ediff(const evalue
*a
, const evalue
*b
)
653 evalue_set_si(&mone
, -1, 1);
654 evalue
*diff
= new evalue
;
656 evalue_copy(diff
, b
);
660 free_evalue_refs(&mone
);
664 static bool evalue_first_difference(const evalue
*e1
, const evalue
*e2
,
665 const evalue
**d1
, const evalue
**d2
)
670 if (value_ne(e1
->d
, e2
->d
))
673 if (value_notzero_p(e1
->d
)) {
674 if (value_eq(e1
->x
.n
, e2
->x
.n
))
678 if (e1
->x
.p
->type
!= e2
->x
.p
->type
)
680 if (e1
->x
.p
->size
!= e2
->x
.p
->size
)
682 if (e1
->x
.p
->pos
!= e2
->x
.p
->pos
)
685 assert(e1
->x
.p
->type
== polynomial
||
686 e1
->x
.p
->type
== fractional
||
687 e1
->x
.p
->type
== flooring
);
688 int offset
= type_offset(e1
->x
.p
);
689 assert(e1
->x
.p
->size
== offset
+2);
690 for (int i
= 0; i
< e1
->x
.p
->size
; ++i
)
691 if (i
!= type_offset(e1
->x
.p
) &&
692 !eequal(&e1
->x
.p
->arr
[i
], &e2
->x
.p
->arr
[i
]))
695 return evalue_first_difference(&e1
->x
.p
->arr
[offset
],
696 &e2
->x
.p
->arr
[offset
], d1
, d2
);
699 static order_sign
evalue_diff_constant_sign(const evalue
*e1
, const evalue
*e2
)
701 if (!evalue_first_difference(e1
, e2
, &e1
, &e2
))
703 if (value_zero_p(e1
->d
) || value_zero_p(e2
->d
))
704 return order_undefined
;
705 int s
= evalue_rational_cmp(e1
, e2
);
714 order_sign
order_cache::check_lt(vector
<order_cache_el
>* list
,
715 const indicator_term
*a
, const indicator_term
*b
,
716 order_cache_el
& cache_el
)
718 order_sign sign
= order_undefined
;
719 for (int i
= 0; i
< list
->size(); ++i
) {
721 for (j
= cache_el
.e
.size(); j
< (*list
)[i
].e
.size(); ++j
)
722 cache_el
.e
.push_back(ediff(a
->vertex
[j
], b
->vertex
[j
]));
723 for (j
= 0; j
< (*list
)[i
].e
.size(); ++j
) {
724 order_sign diff_sign
;
725 diff_sign
= evalue_diff_constant_sign((*list
)[i
].e
[j
], cache_el
.e
[j
]);
726 if (diff_sign
== order_gt
) {
729 } else if (diff_sign
== order_lt
)
731 else if (diff_sign
== order_undefined
)
734 assert(diff_sign
== order_eq
);
736 if (j
== (*list
)[i
].e
.size())
737 sign
= list
== <
? order_lt
: order_le
;
738 if (sign
!= order_undefined
)
744 order_sign
order_cache::check_direct(const indicator_term
*a
,
745 const indicator_term
*b
,
746 order_cache_el
& cache_el
)
748 order_sign sign
= check_lt(<
, a
, b
, cache_el
);
749 if (sign
!= order_undefined
)
751 sign
= check_lt(&le
, a
, b
, cache_el
);
752 if (sign
!= order_undefined
)
755 for (int i
= 0; i
< unknown
.size(); ++i
) {
757 for (j
= cache_el
.e
.size(); j
< unknown
[i
].e
.size(); ++j
)
758 cache_el
.e
.push_back(ediff(a
->vertex
[j
], b
->vertex
[j
]));
759 for (j
= 0; j
< unknown
[i
].e
.size(); ++j
) {
760 if (!eequal(unknown
[i
].e
[j
], cache_el
.e
[j
]))
763 if (j
== unknown
[i
].e
.size()) {
764 sign
= order_unknown
;
771 order_sign
order_cache::check(const indicator_term
*a
, const indicator_term
*b
,
772 order_cache_el
& cache_el
)
774 order_sign sign
= check_direct(a
, b
, cache_el
);
775 if (sign
!= order_undefined
)
777 int size
= cache_el
.e
.size();
779 sign
= check_direct(a
, b
, cache_el
);
781 assert(cache_el
.e
.size() == size
);
782 if (sign
== order_undefined
)
784 if (sign
== order_lt
)
786 else if (sign
== order_le
)
789 assert(sign
== order_unknown
);
795 struct partial_order
{
798 typedef std::set
<const indicator_term
*, smaller_it
> head_type
;
800 typedef map
<const indicator_term
*, int, smaller_it
> pred_type
;
802 typedef map
<const indicator_term
*, vector
<const indicator_term
* >, smaller_it
> order_type
;
811 partial_order(indicator
*ind
) : ind(ind
) {}
812 void copy(const partial_order
& order
,
813 map
< const indicator_term
*, indicator_term
* > old2new
);
815 order_type::iterator i
;
816 pred_type::iterator j
;
817 head_type::iterator k
;
819 if (head
.key_comp().requires_resort
) {
821 for (k
= head
.begin(); k
!= head
.end(); ++k
)
827 if (pred
.key_comp().requires_resort
) {
829 for (j
= pred
.begin(); j
!= pred
.end(); ++j
)
830 new_pred
[(*j
).first
] = (*j
).second
;
835 if (lt
.key_comp().requires_resort
) {
837 for (i
= lt
.begin(); i
!= lt
.end(); ++i
)
838 m
[(*i
).first
] = (*i
).second
;
843 if (le
.key_comp().requires_resort
) {
845 for (i
= le
.begin(); i
!= le
.end(); ++i
)
846 m
[(*i
).first
] = (*i
).second
;
851 if (eq
.key_comp().requires_resort
) {
853 for (i
= eq
.begin(); i
!= eq
.end(); ++i
)
854 m
[(*i
).first
] = (*i
).second
;
859 if (pending
.key_comp().requires_resort
) {
861 for (i
= pending
.begin(); i
!= pending
.end(); ++i
)
862 m
[(*i
).first
] = (*i
).second
;
868 order_sign
compare(const indicator_term
*a
, const indicator_term
*b
);
869 void set_equal(const indicator_term
*a
, const indicator_term
*b
);
870 void unset_le(const indicator_term
*a
, const indicator_term
*b
);
871 void dec_pred(const indicator_term
*it
) {
872 if (--pred
[it
] == 0) {
877 void inc_pred(const indicator_term
*it
) {
878 if (head
.find(it
) != head
.end())
883 bool compared(const indicator_term
* a
, const indicator_term
* b
);
884 void add(const indicator_term
* it
, std::set
<const indicator_term
*> *filter
);
885 void remove(const indicator_term
* it
);
887 void print(ostream
& os
, char **p
);
889 /* replace references to orig to references to replacement */
890 void replace(const indicator_term
* orig
, indicator_term
* replacement
);
891 void sanity_check() const;
894 /* We actually replace the contents of orig by that of replacement,
895 * but we have to be careful since replacing the content changes
896 * the order of orig in the maps.
898 void partial_order::replace(const indicator_term
* orig
, indicator_term
* replacement
)
900 head_type::iterator k
;
902 bool is_head
= k
!= head
.end();
907 orig_pred
= pred
[orig
];
910 vector
<const indicator_term
* > orig_lt
;
911 vector
<const indicator_term
* > orig_le
;
912 vector
<const indicator_term
* > orig_eq
;
913 vector
<const indicator_term
* > orig_pending
;
914 order_type::iterator i
;
915 bool in_lt
= ((i
= lt
.find(orig
)) != lt
.end());
917 orig_lt
= (*i
).second
;
920 bool in_le
= ((i
= le
.find(orig
)) != le
.end());
922 orig_le
= (*i
).second
;
925 bool in_eq
= ((i
= eq
.find(orig
)) != eq
.end());
927 orig_eq
= (*i
).second
;
930 bool in_pending
= ((i
= pending
.find(orig
)) != pending
.end());
932 orig_pending
= (*i
).second
;
935 indicator_term
*old
= const_cast<indicator_term
*>(orig
);
936 old
->swap(replacement
);
940 pred
[old
] = orig_pred
;
948 pending
[old
] = orig_pending
;
951 void partial_order::unset_le(const indicator_term
*a
, const indicator_term
*b
)
953 vector
<const indicator_term
*>::iterator i
;
954 i
= std::find(le
[a
].begin(), le
[a
].end(), b
);
956 if (le
[a
].size() == 0)
959 i
= std::find(pending
[a
].begin(), pending
[a
].end(), b
);
960 if (i
!= pending
[a
].end())
964 void partial_order::set_equal(const indicator_term
*a
, const indicator_term
*b
)
966 if (eq
[a
].size() == 0)
968 if (eq
[b
].size() == 0)
973 if (pred
.key_comp()(b
, a
)) {
974 const indicator_term
*c
= a
;
979 const indicator_term
*base
= a
;
981 order_type::iterator i
;
983 for (int j
= 0; j
< eq
[b
].size(); ++j
) {
984 eq
[base
].push_back(eq
[b
][j
]);
985 eq
[eq
[b
][j
]][0] = base
;
991 for (int j
= 0; j
< lt
[b
].size(); ++j
) {
992 if (std::find(eq
[base
].begin(), eq
[base
].end(), lt
[b
][j
]) != eq
[base
].end())
994 else if (std::find(lt
[base
].begin(), lt
[base
].end(), lt
[b
][j
])
998 lt
[base
].push_back(lt
[b
][j
]);
1004 if (i
!= le
.end()) {
1005 for (int j
= 0; j
< le
[b
].size(); ++j
) {
1006 if (std::find(eq
[base
].begin(), eq
[base
].end(), le
[b
][j
]) != eq
[base
].end())
1008 else if (std::find(le
[base
].begin(), le
[base
].end(), le
[b
][j
])
1012 le
[base
].push_back(le
[b
][j
]);
1017 i
= pending
.find(base
);
1018 if (i
!= pending
.end()) {
1019 vector
<const indicator_term
* > old
= pending
[base
];
1020 pending
[base
].clear();
1021 for (int j
= 0; j
< old
.size(); ++j
) {
1022 if (std::find(eq
[base
].begin(), eq
[base
].end(), old
[j
]) == eq
[base
].end())
1023 pending
[base
].push_back(old
[j
]);
1027 i
= pending
.find(b
);
1028 if (i
!= pending
.end()) {
1029 for (int j
= 0; j
< pending
[b
].size(); ++j
) {
1030 if (std::find(eq
[base
].begin(), eq
[base
].end(), pending
[b
][j
]) == eq
[base
].end())
1031 pending
[base
].push_back(pending
[b
][j
]);
1037 void partial_order::copy(const partial_order
& order
,
1038 map
< const indicator_term
*, indicator_term
* > old2new
)
1040 cache
.copy(order
.cache
);
1042 order_type::const_iterator i
;
1043 pred_type::const_iterator j
;
1044 head_type::const_iterator k
;
1046 for (k
= order
.head
.begin(); k
!= order
.head
.end(); ++k
)
1047 head
.insert(old2new
[*k
]);
1049 for (j
= order
.pred
.begin(); j
!= order
.pred
.end(); ++j
)
1050 pred
[old2new
[(*j
).first
]] = (*j
).second
;
1052 for (i
= order
.lt
.begin(); i
!= order
.lt
.end(); ++i
) {
1053 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
1054 lt
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
1056 for (i
= order
.le
.begin(); i
!= order
.le
.end(); ++i
) {
1057 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
1058 le
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
1060 for (i
= order
.eq
.begin(); i
!= order
.eq
.end(); ++i
) {
1061 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
1062 eq
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
1064 for (i
= order
.pending
.begin(); i
!= order
.pending
.end(); ++i
) {
1065 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
1066 pending
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
1072 vector
<evalue
*> max
;
1074 void print(ostream
& os
, char **p
, barvinok_options
*options
) const;
1075 void substitute(Matrix
*T
, barvinok_options
*options
);
1076 Vector
*eval(Value
*val
, unsigned MaxRays
) const;
1079 for (int i
= 0; i
< max
.size(); ++i
) {
1080 free_evalue_refs(max
[i
]);
1088 * Project on first dim dimensions
1090 Polyhedron
* Polyhedron_Project_Initial(Polyhedron
*P
, int dim
)
1096 if (P
->Dimension
== dim
)
1097 return Polyhedron_Copy(P
);
1099 T
= Matrix_Alloc(dim
+1, P
->Dimension
+1);
1100 for (i
= 0; i
< dim
; ++i
)
1101 value_set_si(T
->p
[i
][i
], 1);
1102 value_set_si(T
->p
[dim
][P
->Dimension
], 1);
1103 I
= Polyhedron_Image(P
, T
, P
->NbConstraints
);
1109 vector
<indicator_term
*> term
;
1110 indicator_constructor
& ic
;
1111 partial_order order
;
1115 lexmin_options
*options
;
1116 vector
<evalue
*> substitutions
;
1118 indicator(indicator_constructor
& ic
, Param_Domain
*PD
, EDomain
*D
,
1119 lexmin_options
*options
) :
1120 ic(ic
), order(this), D(D
), P(NULL
), PD(PD
), options(options
) {}
1121 indicator(const indicator
& ind
, EDomain
*D
) :
1122 ic(ind
.ic
), order(this), D(NULL
), P(Polyhedron_Copy(ind
.P
)),
1123 PD(ind
.PD
), options(ind
.options
) {
1124 map
< const indicator_term
*, indicator_term
* > old2new
;
1125 for (int i
= 0; i
< ind
.term
.size(); ++i
) {
1126 indicator_term
*it
= new indicator_term(*ind
.term
[i
]);
1127 old2new
[ind
.term
[i
]] = it
;
1130 order
.copy(ind
.order
, old2new
);
1134 for (int i
= 0; i
< term
.size(); ++i
)
1142 void set_domain(EDomain
*D
) {
1143 order
.cache
.clear_transients();
1147 int nparam
= ic
.PP
->Constraints
->NbColumns
-2 - ic
.vertex
.length();
1148 if (options
->reduce
) {
1149 Polyhedron
*Q
= Polyhedron_Project_Initial(D
->D
, nparam
);
1150 Q
= DomainConstraintSimplify(Q
, options
->verify
->barvinok
->MaxRays
);
1151 if (!P
|| !PolyhedronIncludes(Q
, P
))
1152 reduce_in_domain(Q
);
1160 void add(const indicator_term
* it
);
1161 void remove(const indicator_term
* it
);
1162 void remove_initial_rational_vertices();
1163 void expand_rational_vertex(const indicator_term
*initial
);
1165 void print(ostream
& os
, char **p
);
1167 void peel(int i
, int j
);
1168 void combine(const indicator_term
*a
, const indicator_term
*b
);
1169 void add_substitution(evalue
*equation
);
1170 void perform_pending_substitutions();
1171 void reduce_in_domain(Polyhedron
*D
);
1172 bool handle_equal_numerators(const indicator_term
*base
);
1174 max_term
* create_max_term(const indicator_term
*it
);
1176 void substitute(evalue
*equation
);
1179 void partial_order::sanity_check() const
1181 order_type::const_iterator i
;
1182 order_type::const_iterator prev
;
1183 order_type::const_iterator l
;
1184 pred_type::const_iterator k
, prev_k
;
1186 for (k
= pred
.begin(); k
!= pred
.end(); prev_k
= k
, ++k
)
1187 if (k
!= pred
.begin())
1188 assert(pred
.key_comp()((*prev_k
).first
, (*k
).first
));
1189 for (i
= lt
.begin(); i
!= lt
.end(); prev
= i
, ++i
) {
1192 i_v
= (*i
).first
->eval(ind
->D
->sample
->p
);
1193 if (i
!= lt
.begin())
1194 assert(lt
.key_comp()((*prev
).first
, (*i
).first
));
1195 l
= eq
.find((*i
).first
);
1197 assert((*l
).second
.size() > 1);
1198 assert(head
.find((*i
).first
) != head
.end() ||
1199 pred
.find((*i
).first
) != pred
.end());
1200 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1201 k
= pred
.find((*i
).second
[j
]);
1202 assert(k
!= pred
.end());
1203 assert((*k
).second
!= 0);
1204 if ((*i
).first
->sign
!= 0 &&
1205 (*i
).second
[j
]->sign
!= 0 && ind
->D
->sample
) {
1206 vec_ZZ j_v
= (*i
).second
[j
]->eval(ind
->D
->sample
->p
);
1207 assert(lex_cmp(i_v
, j_v
) < 0);
1211 for (i
= le
.begin(); i
!= le
.end(); ++i
) {
1212 assert((*i
).second
.size() > 0);
1213 assert(head
.find((*i
).first
) != head
.end() ||
1214 pred
.find((*i
).first
) != pred
.end());
1215 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1216 k
= pred
.find((*i
).second
[j
]);
1217 assert(k
!= pred
.end());
1218 assert((*k
).second
!= 0);
1221 for (i
= eq
.begin(); i
!= eq
.end(); ++i
) {
1222 assert(head
.find((*i
).first
) != head
.end() ||
1223 pred
.find((*i
).first
) != pred
.end());
1224 assert((*i
).second
.size() >= 1);
1226 for (i
= pending
.begin(); i
!= pending
.end(); ++i
) {
1227 assert(head
.find((*i
).first
) != head
.end() ||
1228 pred
.find((*i
).first
) != pred
.end());
1229 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
1230 assert(head
.find((*i
).second
[j
]) != head
.end() ||
1231 pred
.find((*i
).second
[j
]) != pred
.end());
1235 max_term
* indicator::create_max_term(const indicator_term
*it
)
1237 int dim
= it
->den
.NumCols();
1238 max_term
*maximum
= new max_term
;
1239 maximum
->domain
= new EDomain(D
);
1240 for (int j
= 0; j
< dim
; ++j
) {
1241 evalue
*E
= new evalue
;
1243 evalue_copy(E
, it
->vertex
[j
]);
1244 if (evalue_frac2floor_in_domain(E
, D
->D
))
1246 maximum
->max
.push_back(E
);
1251 static order_sign
evalue_sign(evalue
*diff
, EDomain
*D
, barvinok_options
*options
)
1253 order_sign sign
= order_eq
;
1256 evalue_set_si(&mone
, -1, 1);
1257 int len
= 1 + D
->D
->Dimension
+ 1;
1258 Vector
*c
= Vector_Alloc(len
);
1259 Matrix
*T
= Matrix_Alloc(2, len
-1);
1261 int fract
= evalue2constraint(D
, diff
, c
->p
, len
);
1262 Vector_Copy(c
->p
+1, T
->p
[0], len
-1);
1263 value_assign(T
->p
[1][len
-2], c
->p
[0]);
1265 order_sign upper_sign
= polyhedron_affine_sign(D
->D
, T
, options
);
1266 if (upper_sign
== order_lt
|| !fract
)
1270 evalue2constraint(D
, diff
, c
->p
, len
);
1272 Vector_Copy(c
->p
+1, T
->p
[0], len
-1);
1273 value_assign(T
->p
[1][len
-2], c
->p
[0]);
1275 order_sign neg_lower_sign
= polyhedron_affine_sign(D
->D
, T
, options
);
1277 if (neg_lower_sign
== order_lt
)
1279 else if (neg_lower_sign
== order_eq
|| neg_lower_sign
== order_le
) {
1280 if (upper_sign
== order_eq
|| upper_sign
== order_le
)
1285 if (upper_sign
== order_lt
|| upper_sign
== order_le
||
1286 upper_sign
== order_eq
)
1289 sign
= order_unknown
;
1295 free_evalue_refs(&mone
);
1300 /* An auxiliary class that keeps a reference to an evalue
1301 * and frees it when it goes out of scope.
1303 struct temp_evalue
{
1305 temp_evalue() : E(NULL
) {}
1306 temp_evalue(evalue
*e
) : E(e
) {}
1307 operator evalue
* () const { return E
; }
1308 evalue
*operator=(evalue
*e
) {
1310 free_evalue_refs(E
);
1318 free_evalue_refs(E
);
1324 static void substitute(vector
<indicator_term
*>& term
, evalue
*equation
)
1326 evalue
*fract
= NULL
;
1327 evalue
*val
= new evalue
;
1329 evalue_copy(val
, equation
);
1332 value_init(factor
.d
);
1333 value_init(factor
.x
.n
);
1336 for (e
= val
; value_zero_p(e
->d
) && e
->x
.p
->type
!= fractional
;
1337 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)])
1340 if (value_zero_p(e
->d
) && e
->x
.p
->type
== fractional
)
1341 fract
= &e
->x
.p
->arr
[0];
1343 for (e
= val
; value_zero_p(e
->d
) && e
->x
.p
->type
!= polynomial
;
1344 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)])
1346 assert(value_zero_p(e
->d
) && e
->x
.p
->type
== polynomial
);
1349 int offset
= type_offset(e
->x
.p
);
1351 assert(value_notzero_p(e
->x
.p
->arr
[offset
+1].d
));
1352 assert(value_notzero_p(e
->x
.p
->arr
[offset
+1].x
.n
));
1353 if (value_neg_p(e
->x
.p
->arr
[offset
+1].x
.n
)) {
1354 value_oppose(factor
.d
, e
->x
.p
->arr
[offset
+1].x
.n
);
1355 value_assign(factor
.x
.n
, e
->x
.p
->arr
[offset
+1].d
);
1357 value_assign(factor
.d
, e
->x
.p
->arr
[offset
+1].x
.n
);
1358 value_oppose(factor
.x
.n
, e
->x
.p
->arr
[offset
+1].d
);
1361 free_evalue_refs(&e
->x
.p
->arr
[offset
+1]);
1364 *e
= e
->x
.p
->arr
[offset
];
1369 for (int i
= 0; i
< term
.size(); ++i
)
1370 term
[i
]->substitute(fract
, val
);
1372 free_evalue_refs(&p
->arr
[0]);
1374 for (int i
= 0; i
< term
.size(); ++i
)
1375 term
[i
]->substitute(p
->pos
, val
);
1378 free_evalue_refs(&factor
);
1379 free_evalue_refs(val
);
1385 order_sign
partial_order::compare(const indicator_term
*a
, const indicator_term
*b
)
1387 unsigned dim
= a
->den
.NumCols();
1388 order_sign sign
= order_eq
;
1389 bool rational
= a
->sign
== 0 || b
->sign
== 0;
1391 order_sign cached_sign
= order_eq
;
1392 for (int k
= 0; k
< dim
; ++k
) {
1393 cached_sign
= evalue_diff_constant_sign(a
->vertex
[k
], b
->vertex
[k
]);
1394 if (cached_sign
!= order_eq
)
1397 if (cached_sign
!= order_undefined
)
1400 order_cache_el cache_el
;
1401 cached_sign
= order_undefined
;
1403 cached_sign
= cache
.check(a
, b
, cache_el
);
1404 if (cached_sign
!= order_undefined
) {
1411 vector
<indicator_term
*> term
;
1413 for (int k
= 0; k
< dim
; ++k
) {
1414 /* compute a->vertex[k] - b->vertex[k] */
1416 if (cache_el
.e
.size() <= k
) {
1417 diff
= ediff(a
->vertex
[k
], b
->vertex
[k
]);
1418 cache_el
.e
.push_back(diff
);
1420 diff
= cache_el
.e
[k
];
1423 tdiff
= diff
= ediff(term
[0]->vertex
[k
], term
[1]->vertex
[k
]);
1424 order_sign diff_sign
;
1425 if (eequal(a
->vertex
[k
], b
->vertex
[k
]))
1426 diff_sign
= order_eq
;
1428 diff_sign
= evalue_sign(diff
, ind
->D
,
1429 ind
->options
->verify
->barvinok
);
1431 if (diff_sign
== order_undefined
) {
1432 assert(sign
== order_le
|| sign
== order_ge
);
1433 if (sign
== order_le
)
1439 if (diff_sign
== order_lt
) {
1440 if (sign
== order_eq
|| sign
== order_le
)
1443 sign
= order_unknown
;
1446 if (diff_sign
== order_gt
) {
1447 if (sign
== order_eq
|| sign
== order_ge
)
1450 sign
= order_unknown
;
1453 if (diff_sign
== order_eq
) {
1454 if (term
.size() == 0 && !rational
&& !EVALUE_IS_ZERO(*diff
))
1455 ind
->add_substitution(diff
);
1458 if ((diff_sign
== order_unknown
) ||
1459 ((diff_sign
== order_lt
|| diff_sign
== order_le
) && sign
== order_ge
) ||
1460 ((diff_sign
== order_gt
|| diff_sign
== order_ge
) && sign
== order_le
)) {
1461 sign
= order_unknown
;
1468 term
.push_back(new indicator_term(*a
));
1469 term
.push_back(new indicator_term(*b
));
1471 substitute(term
, diff
);
1475 cache
.add(cache_el
, sign
);
1487 bool partial_order::compared(const indicator_term
* a
, const indicator_term
* b
)
1489 order_type::iterator j
;
1492 if (j
!= lt
.end() && std::find(lt
[a
].begin(), lt
[a
].end(), b
) != lt
[a
].end())
1496 if (j
!= le
.end() && std::find(le
[a
].begin(), le
[a
].end(), b
) != le
[a
].end())
1502 void partial_order::add(const indicator_term
* it
,
1503 std::set
<const indicator_term
*> *filter
)
1505 if (eq
.find(it
) != eq
.end() && eq
[it
].size() == 1)
1508 head_type
head_copy(head
);
1513 head_type::iterator i
;
1514 for (i
= head_copy
.begin(); i
!= head_copy
.end(); ++i
) {
1517 if (eq
.find(*i
) != eq
.end() && eq
[*i
].size() == 1)
1520 if (filter
->find(*i
) == filter
->end())
1522 if (compared(*i
, it
))
1525 order_sign sign
= compare(it
, *i
);
1526 if (sign
== order_lt
) {
1527 lt
[it
].push_back(*i
);
1529 } else if (sign
== order_le
) {
1530 le
[it
].push_back(*i
);
1532 } else if (sign
== order_eq
) {
1535 } else if (sign
== order_gt
) {
1536 pending
[*i
].push_back(it
);
1537 lt
[*i
].push_back(it
);
1539 } else if (sign
== order_ge
) {
1540 pending
[*i
].push_back(it
);
1541 le
[*i
].push_back(it
);
1547 void partial_order::remove(const indicator_term
* it
)
1549 std::set
<const indicator_term
*> filter
;
1550 order_type::iterator i
;
1552 assert(head
.find(it
) != head
.end());
1555 if (i
!= eq
.end()) {
1556 assert(eq
[it
].size() >= 1);
1557 const indicator_term
*base
;
1558 if (eq
[it
].size() == 1) {
1562 vector
<const indicator_term
* >::iterator j
;
1563 j
= std::find(eq
[base
].begin(), eq
[base
].end(), it
);
1564 assert(j
!= eq
[base
].end());
1567 /* "it" may no longer be the smallest, since the order
1568 * structure may have been copied from another one.
1570 std::sort(eq
[it
].begin()+1, eq
[it
].end(), pred
.key_comp());
1571 assert(eq
[it
][0] == it
);
1572 eq
[it
].erase(eq
[it
].begin());
1577 for (int j
= 1; j
< eq
[base
].size(); ++j
)
1578 eq
[eq
[base
][j
]][0] = base
;
1581 if (i
!= lt
.end()) {
1587 if (i
!= le
.end()) {
1592 i
= pending
.find(it
);
1593 if (i
!= pending
.end()) {
1594 pending
[base
] = pending
[it
];
1599 if (eq
[base
].size() == 1)
1608 if (i
!= lt
.end()) {
1609 for (int j
= 0; j
< lt
[it
].size(); ++j
) {
1610 filter
.insert(lt
[it
][j
]);
1611 dec_pred(lt
[it
][j
]);
1617 if (i
!= le
.end()) {
1618 for (int j
= 0; j
< le
[it
].size(); ++j
) {
1619 filter
.insert(le
[it
][j
]);
1620 dec_pred(le
[it
][j
]);
1627 i
= pending
.find(it
);
1628 if (i
!= pending
.end()) {
1629 vector
<const indicator_term
*> it_pending
= pending
[it
];
1631 for (int j
= 0; j
< it_pending
.size(); ++j
) {
1632 filter
.erase(it_pending
[j
]);
1633 add(it_pending
[j
], &filter
);
1638 void partial_order::print(ostream
& os
, char **p
)
1640 order_type::iterator i
;
1641 pred_type::iterator j
;
1642 head_type::iterator k
;
1643 for (k
= head
.begin(); k
!= head
.end(); ++k
) {
1647 for (j
= pred
.begin(); j
!= pred
.end(); ++j
) {
1648 (*j
).first
->print(os
, p
);
1649 os
<< ": " << (*j
).second
<< endl
;
1651 for (i
= lt
.begin(); i
!= lt
.end(); ++i
) {
1652 (*i
).first
->print(os
, p
);
1653 assert(head
.find((*i
).first
) != head
.end() ||
1654 pred
.find((*i
).first
) != pred
.end());
1655 if (pred
.find((*i
).first
) != pred
.end())
1656 os
<< "(" << pred
[(*i
).first
] << ")";
1658 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1661 (*i
).second
[j
]->print(os
, p
);
1662 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1663 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1667 for (i
= le
.begin(); i
!= le
.end(); ++i
) {
1668 (*i
).first
->print(os
, p
);
1669 assert(head
.find((*i
).first
) != head
.end() ||
1670 pred
.find((*i
).first
) != pred
.end());
1671 if (pred
.find((*i
).first
) != pred
.end())
1672 os
<< "(" << pred
[(*i
).first
] << ")";
1674 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1677 (*i
).second
[j
]->print(os
, p
);
1678 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1679 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1683 for (i
= eq
.begin(); i
!= eq
.end(); ++i
) {
1684 if ((*i
).second
.size() <= 1)
1686 (*i
).first
->print(os
, p
);
1687 assert(head
.find((*i
).first
) != head
.end() ||
1688 pred
.find((*i
).first
) != pred
.end());
1689 if (pred
.find((*i
).first
) != pred
.end())
1690 os
<< "(" << pred
[(*i
).first
] << ")";
1691 for (int j
= 1; j
< (*i
).second
.size(); ++j
) {
1694 (*i
).second
[j
]->print(os
, p
);
1695 assert(head
.find((*i
).second
[j
]) != head
.end() ||
1696 pred
.find((*i
).second
[j
]) != pred
.end());
1697 if (pred
.find((*i
).second
[j
]) != pred
.end())
1698 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1702 for (i
= pending
.begin(); i
!= pending
.end(); ++i
) {
1703 os
<< "pending on ";
1704 (*i
).first
->print(os
, p
);
1705 assert(head
.find((*i
).first
) != head
.end() ||
1706 pred
.find((*i
).first
) != pred
.end());
1707 if (pred
.find((*i
).first
) != pred
.end())
1708 os
<< "(" << pred
[(*i
).first
] << ")";
1710 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1713 (*i
).second
[j
]->print(os
, p
);
1714 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1715 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1721 void indicator::add(const indicator_term
* it
)
1723 indicator_term
*nt
= new indicator_term(*it
);
1724 if (options
->reduce
)
1725 nt
->reduce_in_domain(P
? P
: D
->D
);
1727 order
.add(nt
, NULL
);
1728 assert(term
.size() == order
.head
.size() + order
.pred
.size());
1731 void indicator::remove(const indicator_term
* it
)
1733 vector
<indicator_term
*>::iterator i
;
1734 i
= std::find(term
.begin(), term
.end(), it
);
1735 assert(i
!= term
.end());
1738 assert(term
.size() == order
.head
.size() + order
.pred
.size());
1742 void indicator::expand_rational_vertex(const indicator_term
*initial
)
1744 int pos
= initial
->pos
;
1746 if (ic
.terms
[pos
].size() == 0) {
1748 FORALL_PVertex_in_ParamPolyhedron(V
, PD
, ic
.PP
) // _i is internal counter
1750 ic
.decompose_at_vertex(V
, pos
, options
->verify
->barvinok
);
1753 END_FORALL_PVertex_in_ParamPolyhedron
;
1755 for (int j
= 0; j
< ic
.terms
[pos
].size(); ++j
)
1756 add(ic
.terms
[pos
][j
]);
1759 void indicator::remove_initial_rational_vertices()
1762 const indicator_term
*initial
= NULL
;
1763 partial_order::head_type::iterator i
;
1764 for (i
= order
.head
.begin(); i
!= order
.head
.end(); ++i
) {
1765 if ((*i
)->sign
!= 0)
1767 if (order
.eq
.find(*i
) != order
.eq
.end() && order
.eq
[*i
].size() <= 1)
1774 expand_rational_vertex(initial
);
1778 void indicator::reduce_in_domain(Polyhedron
*D
)
1780 for (int i
= 0; i
< term
.size(); ++i
)
1781 term
[i
]->reduce_in_domain(D
);
1784 void indicator::print(ostream
& os
, char **p
)
1786 assert(term
.size() == order
.head
.size() + order
.pred
.size());
1787 for (int i
= 0; i
< term
.size(); ++i
) {
1788 term
[i
]->print(os
, p
);
1790 os
<< ": " << term
[i
]->eval(D
->sample
->p
);
1797 /* Remove pairs of opposite terms */
1798 void indicator::simplify()
1800 for (int i
= 0; i
< term
.size(); ++i
) {
1801 for (int j
= i
+1; j
< term
.size(); ++j
) {
1802 if (term
[i
]->sign
+ term
[j
]->sign
!= 0)
1804 if (term
[i
]->den
!= term
[j
]->den
)
1807 for (k
= 0; k
< term
[i
]->den
.NumCols(); ++k
)
1808 if (!eequal(term
[i
]->vertex
[k
], term
[j
]->vertex
[k
]))
1810 if (k
< term
[i
]->den
.NumCols())
1814 term
.erase(term
.begin()+j
);
1815 term
.erase(term
.begin()+i
);
1822 void indicator::peel(int i
, int j
)
1830 int dim
= term
[i
]->den
.NumCols();
1835 int n_common
= 0, n_i
= 0, n_j
= 0;
1837 common
.SetDims(min(term
[i
]->den
.NumRows(), term
[j
]->den
.NumRows()), dim
);
1838 rest_i
.SetDims(term
[i
]->den
.NumRows(), dim
);
1839 rest_j
.SetDims(term
[j
]->den
.NumRows(), dim
);
1842 for (k
= 0, l
= 0; k
< term
[i
]->den
.NumRows() && l
< term
[j
]->den
.NumRows(); ) {
1843 int s
= lex_cmp(term
[i
]->den
[k
], term
[j
]->den
[l
]);
1845 common
[n_common
++] = term
[i
]->den
[k
];
1849 rest_i
[n_i
++] = term
[i
]->den
[k
++];
1851 rest_j
[n_j
++] = term
[j
]->den
[l
++];
1853 while (k
< term
[i
]->den
.NumRows())
1854 rest_i
[n_i
++] = term
[i
]->den
[k
++];
1855 while (l
< term
[j
]->den
.NumRows())
1856 rest_j
[n_j
++] = term
[j
]->den
[l
++];
1857 common
.SetDims(n_common
, dim
);
1858 rest_i
.SetDims(n_i
, dim
);
1859 rest_j
.SetDims(n_j
, dim
);
1861 for (k
= 0; k
<= n_i
; ++k
) {
1862 indicator_term
*it
= new indicator_term(*term
[i
]);
1863 it
->den
.SetDims(n_common
+ k
, dim
);
1864 for (l
= 0; l
< n_common
; ++l
)
1865 it
->den
[l
] = common
[l
];
1866 for (l
= 0; l
< k
; ++l
)
1867 it
->den
[n_common
+l
] = rest_i
[l
];
1868 lex_order_rows(it
->den
);
1870 for (l
= 0; l
< dim
; ++l
)
1871 evalue_add_constant(it
->vertex
[l
], rest_i
[k
-1][l
]);
1875 for (k
= 0; k
<= n_j
; ++k
) {
1876 indicator_term
*it
= new indicator_term(*term
[j
]);
1877 it
->den
.SetDims(n_common
+ k
, dim
);
1878 for (l
= 0; l
< n_common
; ++l
)
1879 it
->den
[l
] = common
[l
];
1880 for (l
= 0; l
< k
; ++l
)
1881 it
->den
[n_common
+l
] = rest_j
[l
];
1882 lex_order_rows(it
->den
);
1884 for (l
= 0; l
< dim
; ++l
)
1885 evalue_add_constant(it
->vertex
[l
], rest_j
[k
-1][l
]);
1888 term
.erase(term
.begin()+j
);
1889 term
.erase(term
.begin()+i
);
1892 void indicator::combine(const indicator_term
*a
, const indicator_term
*b
)
1894 int dim
= a
->den
.NumCols();
1897 mat_ZZ rest_i
; /* factors in a, but not in b */
1898 mat_ZZ rest_j
; /* factors in b, but not in a */
1899 int n_common
= 0, n_i
= 0, n_j
= 0;
1901 common
.SetDims(min(a
->den
.NumRows(), b
->den
.NumRows()), dim
);
1902 rest_i
.SetDims(a
->den
.NumRows(), dim
);
1903 rest_j
.SetDims(b
->den
.NumRows(), dim
);
1906 for (k
= 0, l
= 0; k
< a
->den
.NumRows() && l
< b
->den
.NumRows(); ) {
1907 int s
= lex_cmp(a
->den
[k
], b
->den
[l
]);
1909 common
[n_common
++] = a
->den
[k
];
1913 rest_i
[n_i
++] = a
->den
[k
++];
1915 rest_j
[n_j
++] = b
->den
[l
++];
1917 while (k
< a
->den
.NumRows())
1918 rest_i
[n_i
++] = a
->den
[k
++];
1919 while (l
< b
->den
.NumRows())
1920 rest_j
[n_j
++] = b
->den
[l
++];
1921 common
.SetDims(n_common
, dim
);
1922 rest_i
.SetDims(n_i
, dim
);
1923 rest_j
.SetDims(n_j
, dim
);
1925 assert(order
.eq
[a
].size() > 1);
1926 indicator_term
*prev
;
1929 for (int k
= n_i
-1; k
>= 0; --k
) {
1930 indicator_term
*it
= new indicator_term(*b
);
1931 it
->den
.SetDims(n_common
+ n_j
+ n_i
-k
, dim
);
1932 for (int l
= k
; l
< n_i
; ++l
)
1933 it
->den
[n_common
+n_j
+l
-k
] = rest_i
[l
];
1934 lex_order_rows(it
->den
);
1935 for (int m
= 0; m
< dim
; ++m
)
1936 evalue_add_constant(it
->vertex
[m
], rest_i
[k
][m
]);
1937 it
->sign
= -it
->sign
;
1939 order
.pending
[it
].push_back(prev
);
1940 order
.lt
[it
].push_back(prev
);
1941 order
.inc_pred(prev
);
1944 order
.head
.insert(it
);
1948 indicator_term
*it
= new indicator_term(*b
);
1949 it
->den
.SetDims(n_common
+ n_i
+ n_j
, dim
);
1950 for (l
= 0; l
< n_i
; ++l
)
1951 it
->den
[n_common
+n_j
+l
] = rest_i
[l
];
1952 lex_order_rows(it
->den
);
1954 order
.pending
[a
].push_back(prev
);
1955 order
.lt
[a
].push_back(prev
);
1956 order
.inc_pred(prev
);
1957 order
.replace(b
, it
);
1962 for (int k
= n_j
-1; k
>= 0; --k
) {
1963 indicator_term
*it
= new indicator_term(*a
);
1964 it
->den
.SetDims(n_common
+ n_i
+ n_j
-k
, dim
);
1965 for (int l
= k
; l
< n_j
; ++l
)
1966 it
->den
[n_common
+n_i
+l
-k
] = rest_j
[l
];
1967 lex_order_rows(it
->den
);
1968 for (int m
= 0; m
< dim
; ++m
)
1969 evalue_add_constant(it
->vertex
[m
], rest_j
[k
][m
]);
1970 it
->sign
= -it
->sign
;
1972 order
.pending
[it
].push_back(prev
);
1973 order
.lt
[it
].push_back(prev
);
1974 order
.inc_pred(prev
);
1977 order
.head
.insert(it
);
1981 indicator_term
*it
= new indicator_term(*a
);
1982 it
->den
.SetDims(n_common
+ n_i
+ n_j
, dim
);
1983 for (l
= 0; l
< n_j
; ++l
)
1984 it
->den
[n_common
+n_i
+l
] = rest_j
[l
];
1985 lex_order_rows(it
->den
);
1987 order
.pending
[a
].push_back(prev
);
1988 order
.lt
[a
].push_back(prev
);
1989 order
.inc_pred(prev
);
1990 order
.replace(a
, it
);
1994 assert(term
.size() == order
.head
.size() + order
.pred
.size());
1997 bool indicator::handle_equal_numerators(const indicator_term
*base
)
1999 for (int i
= 0; i
< order
.eq
[base
].size(); ++i
) {
2000 for (int j
= i
+1; j
< order
.eq
[base
].size(); ++j
) {
2001 if (order
.eq
[base
][i
]->is_opposite(order
.eq
[base
][j
])) {
2002 remove(order
.eq
[base
][j
]);
2003 remove(i
? order
.eq
[base
][i
] : base
);
2008 for (int j
= 1; j
< order
.eq
[base
].size(); ++j
)
2009 if (order
.eq
[base
][j
]->sign
!= base
->sign
) {
2010 combine(base
, order
.eq
[base
][j
]);
2016 void indicator::substitute(evalue
*equation
)
2018 ::substitute(term
, equation
);
2021 void indicator::add_substitution(evalue
*equation
)
2023 for (int i
= 0; i
< substitutions
.size(); ++i
)
2024 if (eequal(substitutions
[i
], equation
))
2026 evalue
*copy
= new evalue();
2027 value_init(copy
->d
);
2028 evalue_copy(copy
, equation
);
2029 substitutions
.push_back(copy
);
2032 void indicator::perform_pending_substitutions()
2034 if (substitutions
.size() == 0)
2037 for (int i
= 0; i
< substitutions
.size(); ++i
) {
2038 substitute(substitutions
[i
]);
2039 free_evalue_refs(substitutions
[i
]);
2040 delete substitutions
[i
];
2042 substitutions
.clear();
2046 static void print_varlist(ostream
& os
, int n
, char **names
)
2050 for (i
= 0; i
< n
; ++i
) {
2058 void max_term::print(ostream
& os
, char **p
, barvinok_options
*options
) const
2061 print_varlist(os
, domain
->dimension(), p
);
2064 for (int i
= 0; i
< max
.size(); ++i
) {
2067 evalue_print(os
, max
[i
], p
);
2071 domain
->print_constraints(os
, p
, options
);
2075 /* T maps the compressed parameters to the original parameters,
2076 * while this max_term is based on the compressed parameters
2077 * and we want get the original parameters back.
2079 void max_term::substitute(Matrix
*T
, barvinok_options
*options
)
2081 assert(domain
->dimension() == T
->NbColumns
-1);
2083 Matrix
*inv
= left_inverse(T
, &Eq
);
2086 value_init(denom
.d
);
2087 value_init(denom
.x
.n
);
2088 value_set_si(denom
.x
.n
, 1);
2089 value_assign(denom
.d
, inv
->p
[inv
->NbRows
-1][inv
->NbColumns
-1]);
2092 v
.SetLength(inv
->NbColumns
);
2093 evalue
**subs
= new evalue
*[inv
->NbRows
-1];
2094 for (int i
= 0; i
< inv
->NbRows
-1; ++i
) {
2095 values2zz(inv
->p
[i
], v
, v
.length());
2096 subs
[i
] = multi_monom(v
);
2097 emul(&denom
, subs
[i
]);
2099 free_evalue_refs(&denom
);
2101 domain
->substitute(subs
, inv
, Eq
, options
->MaxRays
);
2104 for (int i
= 0; i
< max
.size(); ++i
) {
2105 evalue_substitute(max
[i
], subs
);
2106 reduce_evalue(max
[i
]);
2109 for (int i
= 0; i
< inv
->NbRows
-1; ++i
) {
2110 free_evalue_refs(subs
[i
]);
2117 Vector
*max_term::eval(Value
*val
, unsigned MaxRays
) const
2119 if (!domain
->contains(val
, domain
->dimension()))
2121 Vector
*res
= Vector_Alloc(max
.size());
2122 for (int i
= 0; i
< max
.size(); ++i
) {
2123 compute_evalue(max
[i
], val
, &res
->p
[i
]);
2130 enum sign
{ le
, ge
, lge
} sign
;
2132 split (evalue
*c
, enum sign s
) : constraint(c
), sign(s
) {}
2135 static void split_on(const split
& sp
, EDomain
*D
,
2136 EDomain
**Dlt
, EDomain
**Deq
, EDomain
**Dgt
,
2137 lexmin_options
*options
)
2143 ge_constraint
*ge
= D
->compute_ge_constraint(sp
.constraint
);
2144 if (sp
.sign
== split::lge
|| sp
.sign
== split::ge
)
2145 ED
[2] = EDomain::new_from_ge_constraint(ge
, 1, options
->verify
->barvinok
);
2148 if (sp
.sign
== split::lge
|| sp
.sign
== split::le
)
2149 ED
[0] = EDomain::new_from_ge_constraint(ge
, -1, options
->verify
->barvinok
);
2153 assert(sp
.sign
== split::lge
|| sp
.sign
== split::ge
|| sp
.sign
== split::le
);
2154 ED
[1] = EDomain::new_from_ge_constraint(ge
, 0, options
->verify
->barvinok
);
2158 for (int i
= 0; i
< 3; ++i
) {
2161 if (D
->sample
&& ED
[i
]->contains(D
->sample
->p
, D
->sample
->Size
-1)) {
2162 ED
[i
]->sample
= Vector_Alloc(D
->sample
->Size
);
2163 Vector_Copy(D
->sample
->p
, ED
[i
]->sample
->p
, D
->sample
->Size
);
2164 } else if (emptyQ2(ED
[i
]->D
) ||
2165 (options
->emptiness_check
!= BV_LEXMIN_EMPTINESS_CHECK_NONE
&&
2166 !(ED
[i
]->not_empty(options
)))) {
2176 ostream
& operator<< (ostream
& os
, const vector
<int> & v
)
2179 for (int i
= 0; i
< v
.size(); ++i
) {
2188 void construct_rational_vertices(Param_Polyhedron
*PP
, Matrix
*T
, unsigned dim
,
2189 int nparam
, vector
<indicator_term
*>& vertices
)
2198 v
.SetLength(nparam
+1);
2201 value_init(factor
.d
);
2202 value_init(factor
.x
.n
);
2203 value_set_si(factor
.x
.n
, 1);
2204 value_set_si(factor
.d
, 1);
2206 for (i
= 0, PV
= PP
->V
; PV
; ++i
, PV
= PV
->next
) {
2207 indicator_term
*term
= new indicator_term(dim
, i
);
2208 vertices
.push_back(term
);
2209 Matrix
*M
= Matrix_Alloc(PV
->Vertex
->NbRows
+nparam
+1, nparam
+1);
2210 value_set_si(lcm
, 1);
2211 for (int j
= 0; j
< PV
->Vertex
->NbRows
; ++j
)
2212 value_lcm(lcm
, lcm
, PV
->Vertex
->p
[j
][nparam
+1]);
2213 value_assign(M
->p
[M
->NbRows
-1][M
->NbColumns
-1], lcm
);
2214 for (int j
= 0; j
< PV
->Vertex
->NbRows
; ++j
) {
2215 value_division(tmp
, lcm
, PV
->Vertex
->p
[j
][nparam
+1]);
2216 Vector_Scale(PV
->Vertex
->p
[j
], M
->p
[j
], tmp
, nparam
+1);
2218 for (int j
= 0; j
< nparam
; ++j
)
2219 value_assign(M
->p
[PV
->Vertex
->NbRows
+j
][j
], lcm
);
2221 Matrix
*M2
= Matrix_Alloc(T
->NbRows
, M
->NbColumns
);
2222 Matrix_Product(T
, M
, M2
);
2226 for (int j
= 0; j
< dim
; ++j
) {
2227 values2zz(M
->p
[j
], v
, nparam
+1);
2228 term
->vertex
[j
] = multi_monom(v
);
2229 value_assign(factor
.d
, lcm
);
2230 emul(&factor
, term
->vertex
[j
]);
2234 assert(i
== PP
->nbV
);
2235 free_evalue_refs(&factor
);
2240 static vector
<max_term
*> lexmin(indicator
& ind
, unsigned nparam
,
2243 vector
<max_term
*> maxima
;
2244 partial_order::head_type::iterator i
;
2245 vector
<int> best_score
;
2246 vector
<int> second_score
;
2247 vector
<int> neg_score
;
2250 ind
.perform_pending_substitutions();
2251 const indicator_term
*best
= NULL
, *second
= NULL
, *neg
= NULL
,
2252 *neg_eq
= NULL
, *neg_le
= NULL
;
2253 for (i
= ind
.order
.head
.begin(); i
!= ind
.order
.head
.end(); ++i
) {
2255 const indicator_term
*term
= *i
;
2256 if (term
->sign
== 0) {
2257 ind
.expand_rational_vertex(term
);
2261 if (ind
.order
.eq
.find(term
) != ind
.order
.eq
.end()) {
2263 if (ind
.order
.eq
[term
].size() <= 1)
2265 for (j
= 1; j
< ind
.order
.eq
[term
].size(); ++j
)
2266 if (ind
.order
.pred
.find(ind
.order
.eq
[term
][j
]) !=
2267 ind
.order
.pred
.end())
2269 if (j
< ind
.order
.eq
[term
].size())
2271 score
.push_back(ind
.order
.eq
[term
].size());
2274 if (ind
.order
.le
.find(term
) != ind
.order
.le
.end())
2275 score
.push_back(ind
.order
.le
[term
].size());
2278 if (ind
.order
.lt
.find(term
) != ind
.order
.lt
.end())
2279 score
.push_back(-ind
.order
.lt
[term
].size());
2283 if (term
->sign
> 0) {
2284 if (!best
|| score
< best_score
) {
2286 second_score
= best_score
;
2289 } else if (!second
|| score
< second_score
) {
2291 second_score
= score
;
2294 if (!neg_eq
&& ind
.order
.eq
.find(term
) != ind
.order
.eq
.end()) {
2295 for (int j
= 1; j
< ind
.order
.eq
[term
].size(); ++j
)
2296 if (ind
.order
.eq
[term
][j
]->sign
!= term
->sign
) {
2301 if (!neg_le
&& ind
.order
.le
.find(term
) != ind
.order
.le
.end())
2303 if (!neg
|| score
< neg_score
) {
2309 if (i
!= ind
.order
.head
.end())
2312 if (!best
&& neg_eq
) {
2313 assert(ind
.order
.eq
[neg_eq
].size() != 0);
2314 bool handled
= ind
.handle_equal_numerators(neg_eq
);
2319 if (!best
&& neg_le
) {
2320 /* The smallest term is negative and <= some positive term */
2326 /* apparently there can be negative initial term on empty domains */
2327 if (ind
.options
->emptiness_check
!= BV_LEXMIN_EMPTINESS_CHECK_NONE
&&
2328 ind
.options
->verify
->barvinok
->lp_solver
== BV_LP_POLYLIB
)
2333 if (!second
&& !neg
) {
2334 const indicator_term
*rat
= NULL
;
2336 if (ind
.order
.le
.find(best
) == ind
.order
.le
.end()) {
2337 if (ind
.order
.eq
.find(best
) != ind
.order
.eq
.end()) {
2338 bool handled
= ind
.handle_equal_numerators(best
);
2339 if (ind
.options
->emptiness_check
!=
2340 BV_LEXMIN_EMPTINESS_CHECK_NONE
&&
2341 ind
.options
->verify
->barvinok
->lp_solver
== BV_LP_POLYLIB
)
2343 /* If !handled then the leading coefficient is bigger than one;
2344 * must be an empty domain
2351 maxima
.push_back(ind
.create_max_term(best
));
2354 for (int j
= 0; j
< ind
.order
.le
[best
].size(); ++j
) {
2355 if (ind
.order
.le
[best
][j
]->sign
== 0) {
2356 if (!rat
&& ind
.order
.pred
[ind
.order
.le
[best
][j
]] == 1)
2357 rat
= ind
.order
.le
[best
][j
];
2358 } else if (ind
.order
.le
[best
][j
]->sign
> 0) {
2359 second
= ind
.order
.le
[best
][j
];
2362 neg
= ind
.order
.le
[best
][j
];
2365 if (!second
&& !neg
) {
2367 ind
.order
.unset_le(best
, rat
);
2368 ind
.expand_rational_vertex(rat
);
2375 ind
.order
.unset_le(best
, second
);
2381 unsigned dim
= best
->den
.NumCols();
2384 for (int k
= 0; k
< dim
; ++k
) {
2385 diff
= ediff(best
->vertex
[k
], second
->vertex
[k
]);
2386 sign
= evalue_sign(diff
, ind
.D
, ind
.options
->verify
->barvinok
);
2388 /* neg can never be smaller than best, unless it may still cancel.
2389 * This can happen if positive terms have been determined to
2390 * be equal or less than or equal to some negative term.
2392 if (second
== neg
&& !neg_eq
&& !neg_le
) {
2393 if (sign
== order_ge
)
2395 if (sign
== order_unknown
)
2399 if (sign
!= order_eq
)
2401 if (!EVALUE_IS_ZERO(*diff
)) {
2402 ind
.add_substitution(diff
);
2403 ind
.perform_pending_substitutions();
2406 if (sign
== order_eq
) {
2407 ind
.order
.set_equal(best
, second
);
2410 if (sign
== order_lt
) {
2411 ind
.order
.lt
[best
].push_back(second
);
2412 ind
.order
.inc_pred(second
);
2415 if (sign
== order_gt
) {
2416 ind
.order
.lt
[second
].push_back(best
);
2417 ind
.order
.inc_pred(best
);
2421 split
sp(diff
, sign
== order_le
? split::le
:
2422 sign
== order_ge
? split::ge
: split::lge
);
2424 EDomain
*Dlt
, *Deq
, *Dgt
;
2425 split_on(sp
, ind
.D
, &Dlt
, &Deq
, &Dgt
, ind
.options
);
2426 if (ind
.options
->emptiness_check
!= BV_LEXMIN_EMPTINESS_CHECK_NONE
)
2427 assert(Dlt
|| Deq
|| Dgt
);
2428 else if (!(Dlt
|| Deq
|| Dgt
))
2429 /* Must have been empty all along */
2432 if (Deq
&& (Dlt
|| Dgt
)) {
2433 int locsize
= loc
.size();
2435 indicator
indeq(ind
, Deq
);
2437 indeq
.add_substitution(diff
);
2438 indeq
.perform_pending_substitutions();
2439 vector
<max_term
*> maxeq
= lexmin(indeq
, nparam
, loc
);
2440 maxima
.insert(maxima
.end(), maxeq
.begin(), maxeq
.end());
2441 loc
.resize(locsize
);
2444 int locsize
= loc
.size();
2446 indicator
indgt(ind
, Dgt
);
2448 /* we don't know the new location of these terms in indgt */
2450 indgt.order.lt[second].push_back(best);
2451 indgt.order.inc_pred(best);
2453 vector
<max_term
*> maxgt
= lexmin(indgt
, nparam
, loc
);
2454 maxima
.insert(maxima
.end(), maxgt
.begin(), maxgt
.end());
2455 loc
.resize(locsize
);
2460 ind
.set_domain(Deq
);
2461 ind
.add_substitution(diff
);
2462 ind
.perform_pending_substitutions();
2466 ind
.set_domain(Dlt
);
2467 ind
.order
.lt
[best
].push_back(second
);
2468 ind
.order
.inc_pred(second
);
2472 ind
.set_domain(Dgt
);
2473 ind
.order
.lt
[second
].push_back(best
);
2474 ind
.order
.inc_pred(best
);
2481 static void lexmin_base(Polyhedron
*P
, Polyhedron
*C
,
2482 Matrix
*CP
, Matrix
*T
,
2483 vector
<max_term
*>& all_max
,
2484 lexmin_options
*options
)
2486 unsigned nparam
= C
->Dimension
;
2487 Param_Polyhedron
*PP
= NULL
;
2489 PP
= Polyhedron2Param_Polyhedron(P
, C
, options
->verify
->barvinok
);
2491 unsigned dim
= P
->Dimension
- nparam
;
2495 indicator_constructor
ic(dim
, PP
, T
);
2497 vector
<indicator_term
*> all_vertices
;
2498 construct_rational_vertices(PP
, T
, T
? T
->NbRows
-nparam
-1 : dim
,
2499 nparam
, all_vertices
);
2501 Polyhedron
*TC
= true_context(P
, C
, options
->verify
->barvinok
->MaxRays
);
2502 FORALL_REDUCED_DOMAIN(PP
, TC
, nd
, options
->verify
->barvinok
, i
, D
, rVD
)
2505 EDomain
*epVD
= new EDomain(rVD
);
2506 indicator
ind(ic
, D
, epVD
, options
);
2508 FORALL_PVertex_in_ParamPolyhedron(V
,D
,PP
) // _i is internal counter
2509 ind
.add(all_vertices
[_i
]);
2510 END_FORALL_PVertex_in_ParamPolyhedron
;
2512 ind
.remove_initial_rational_vertices();
2515 vector
<max_term
*> maxima
= lexmin(ind
, nparam
, loc
);
2517 for (int j
= 0; j
< maxima
.size(); ++j
)
2518 maxima
[j
]->substitute(CP
, options
->verify
->barvinok
);
2519 all_max
.insert(all_max
.end(), maxima
.begin(), maxima
.end());
2522 END_FORALL_REDUCED_DOMAIN
2523 Polyhedron_Free(TC
);
2524 for (int i
= 0; i
< all_vertices
.size(); ++i
)
2525 delete all_vertices
[i
];
2526 Param_Polyhedron_Free(PP
);
2529 static vector
<max_term
*> lexmin(Polyhedron
*P
, Polyhedron
*C
,
2530 lexmin_options
*options
)
2532 unsigned nparam
= C
->Dimension
;
2533 Matrix
*T
= NULL
, *CP
= NULL
;
2534 Polyhedron
*Porig
= P
;
2535 Polyhedron
*Corig
= C
;
2536 vector
<max_term
*> all_max
;
2541 POL_ENSURE_VERTICES(P
);
2546 assert(P
->NbBid
== 0);
2549 remove_all_equalities(&P
, &C
, &CP
, &T
, nparam
,
2550 options
->verify
->barvinok
->MaxRays
);
2552 lexmin_base(P
, C
, CP
, T
, all_max
, options
);
2565 static void verify_results(Polyhedron
*A
, Polyhedron
*C
,
2566 vector
<max_term
*>& maxima
,
2567 struct verify_options
*options
);
2569 /* Turn the set dimensions of "context" into parameters and return
2570 * the corresponding parameter domain.
2572 static struct isl_basic_set
*to_parameter_domain(struct isl_basic_set
*context
)
2574 context
= isl_basic_set_move_dims(context
, isl_dim_param
, 0,
2575 isl_dim_set
, 0, isl_basic_set_dim(context
, isl_dim_set
));
2576 context
= isl_basic_set_params(context
);
2580 int main(int argc
, char **argv
)
2583 isl_basic_set
*context
, *bset
;
2588 int urs_unknowns
= 0;
2589 int print_solution
= 1;
2590 struct lexmin_options
*options
= lexmin_options_new_with_defaults();
2592 options
->verify
->barvinok
->lookup_table
= 0;
2594 argc
= lexmin_options_parse(options
, argc
, argv
, ISL_ARG_ALL
);
2595 ctx
= isl_ctx_alloc_with_options(&lexmin_options_args
, options
);
2597 context
= isl_basic_set_read_from_file(ctx
, stdin
);
2599 n
= fscanf(stdin
, "%d", &neg_one
);
2601 assert(neg_one
== -1);
2602 bset
= isl_basic_set_read_from_file(ctx
, stdin
);
2604 while (fgets(s
, sizeof(s
), stdin
)) {
2605 if (strncasecmp(s
, "Maximize", 8) == 0) {
2606 fprintf(stderr
, "Maximize option not supported\n");
2609 if (strncasecmp(s
, "Rational", 8) == 0) {
2610 fprintf(stderr
, "Rational option not supported\n");
2613 if (strncasecmp(s
, "Urs_parms", 9) == 0)
2615 if (strncasecmp(s
, "Urs_unknowns", 12) == 0)
2619 context
= isl_basic_set_intersect(context
,
2620 isl_basic_set_positive_orthant(isl_basic_set_get_space(context
)));
2621 context
= to_parameter_domain(context
);
2622 nparam
= isl_basic_set_dim(context
, isl_dim_param
);
2623 if (nparam
!= isl_basic_set_dim(bset
, isl_dim_param
)) {
2624 int dim
= isl_basic_set_dim(bset
, isl_dim_set
);
2625 bset
= isl_basic_set_move_dims(bset
, isl_dim_param
, 0,
2626 isl_dim_set
, dim
- nparam
, nparam
);
2629 bset
= isl_basic_set_intersect(bset
,
2630 isl_basic_set_positive_orthant(isl_basic_set_get_space(bset
)));
2632 if (options
->verify
->verify
)
2635 A
= isl_basic_set_to_polylib(bset
);
2636 verify_options_set_range(options
->verify
, A
->Dimension
);
2637 C
= isl_basic_set_to_polylib(context
);
2638 vector
<max_term
*> maxima
= lexmin(A
, C
, options
);
2639 if (print_solution
) {
2641 param_names
= util_generate_names(C
->Dimension
, "p");
2642 for (int i
= 0; i
< maxima
.size(); ++i
)
2643 maxima
[i
]->print(cout
, param_names
,
2644 options
->verify
->barvinok
);
2645 util_free_names(C
->Dimension
, param_names
);
2648 if (options
->verify
->verify
)
2649 verify_results(A
, C
, maxima
, options
->verify
);
2651 for (int i
= 0; i
< maxima
.size(); ++i
)
2657 isl_basic_set_free(bset
);
2658 isl_basic_set_free(context
);
2664 static bool lexmin(int pos
, Polyhedron
*P
, Value
*context
)
2673 value_init(LB
); value_init(UB
); value_init(k
);
2676 lu_flags
= lower_upper_bounds(pos
,P
,context
,&LB
,&UB
);
2677 assert(!(lu_flags
& LB_INFINITY
));
2679 value_set_si(context
[pos
],0);
2680 if (!lu_flags
&& value_lt(UB
,LB
)) {
2681 value_clear(LB
); value_clear(UB
); value_clear(k
);
2685 value_assign(context
[pos
], LB
);
2686 value_clear(LB
); value_clear(UB
); value_clear(k
);
2689 for (value_assign(k
,LB
); lu_flags
|| value_le(k
,UB
); value_increment(k
,k
)) {
2690 value_assign(context
[pos
],k
);
2691 if ((found
= lexmin(pos
+1, P
->next
, context
)))
2695 value_set_si(context
[pos
],0);
2696 value_clear(LB
); value_clear(UB
); value_clear(k
);
2700 static void print_list(FILE *out
, Value
*z
, const char* brackets
, int len
)
2702 fprintf(out
, "%c", brackets
[0]);
2703 value_print(out
, VALUE_FMT
,z
[0]);
2704 for (int k
= 1; k
< len
; ++k
) {
2706 value_print(out
, VALUE_FMT
,z
[k
]);
2708 fprintf(out
, "%c", brackets
[1]);
2711 static int check_poly_lexmin(const struct check_poly_data
*data
,
2712 int nparam
, Value
*z
,
2713 const struct verify_options
*options
);
2715 struct check_poly_lexmin_data
: public check_poly_data
{
2717 vector
<max_term
*>& maxima
;
2719 check_poly_lexmin_data(Polyhedron
*S
, Value
*z
,
2720 vector
<max_term
*>& maxima
) : S(S
), maxima(maxima
) {
2722 this->check
= &check_poly_lexmin
;
2726 static int check_poly_lexmin(const struct check_poly_data
*data
,
2727 int nparam
, Value
*z
,
2728 const struct verify_options
*options
)
2730 const check_poly_lexmin_data
*lexmin_data
;
2731 lexmin_data
= static_cast<const check_poly_lexmin_data
*>(data
);
2732 Polyhedron
*S
= lexmin_data
->S
;
2733 vector
<max_term
*>& maxima
= lexmin_data
->maxima
;
2735 bool found
= lexmin(1, S
, lexmin_data
->z
);
2737 if (options
->print_all
) {
2739 print_list(stdout
, z
, "()", nparam
);
2742 print_list(stdout
, lexmin_data
->z
+1, "[]", S
->Dimension
-nparam
);
2747 for (int i
= 0; i
< maxima
.size(); ++i
)
2748 if ((min
= maxima
[i
]->eval(z
, options
->barvinok
->MaxRays
)))
2751 int ok
= !(found
^ !!min
);
2753 for (int i
= 0; i
< S
->Dimension
-nparam
; ++i
)
2754 if (value_ne(lexmin_data
->z
[1+i
], min
->p
[i
])) {
2761 fprintf(stderr
, "Error !\n");
2762 fprintf(stderr
, "lexmin");
2763 print_list(stderr
, z
, "()", nparam
);
2764 fprintf(stderr
, " should be ");
2766 print_list(stderr
, lexmin_data
->z
+1, "[]", S
->Dimension
-nparam
);
2767 fprintf(stderr
, " while digging gives ");
2769 print_list(stderr
, min
->p
, "[]", S
->Dimension
-nparam
);
2770 fprintf(stderr
, ".\n");
2772 } else if (options
->print_all
)
2777 for (k
= 1; k
<= S
->Dimension
-nparam
; ++k
)
2778 value_set_si(lexmin_data
->z
[k
], 0);
2783 void verify_results(Polyhedron
*A
, Polyhedron
*C
, vector
<max_term
*>& maxima
,
2784 struct verify_options
*options
)
2787 unsigned nparam
= C
->Dimension
;
2788 unsigned MaxRays
= options
->barvinok
->MaxRays
;
2791 CS
= check_poly_context_scan(A
, &C
, nparam
, options
);
2793 p
= Vector_Alloc(A
->Dimension
+2);
2794 value_set_si(p
->p
[A
->Dimension
+1], 1);
2796 S
= Polyhedron_Scan(A
, C
, MaxRays
& POL_NO_DUAL
? 0 : MaxRays
);
2798 check_poly_init(C
, options
);
2801 if (!(CS
&& emptyQ2(CS
))) {
2802 check_poly_lexmin_data
data(S
, p
->p
, maxima
);
2803 check_poly(CS
, &data
, nparam
, 0, p
->p
+S
->Dimension
-nparam
+1, options
);
2808 if (!options
->print_all
)