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 <barvinok/sample.h>
13 #include "conversion.h"
14 #include "decomposer.h"
15 #include "lattice_point.h"
16 #include "reduce_domain.h"
20 #include "evalue_util.h"
21 #include "remove_equalities.h"
36 /* RANGE : normal range for evalutations (-RANGE -> RANGE) */
39 /* SRANGE : small range for evalutations */
42 /* if dimension >= BIDDIM, use SRANGE */
45 /* VSRANGE : very small range for evalutations */
48 /* if dimension >= VBIDDIM, use VSRANGE */
52 #define getopt_long(a,b,c,d,e) getopt(a,b,c)
55 #define NO_EMPTINESS_CHECK 256
56 #define BASIS_REDUCTION_CDD 257
57 #define NO_REDUCTION 258
59 struct option lexmin_options
[] = {
60 { "verify", no_argument
, 0, 'T' },
61 { "print-all", no_argument
, 0, 'A' },
62 { "no-emptiness-check", no_argument
, 0, NO_EMPTINESS_CHECK
},
63 { "no-reduction", no_argument
, 0, NO_REDUCTION
},
64 { "cdd", no_argument
, 0, BASIS_REDUCTION_CDD
},
65 { "polysign", required_argument
, 0, POLYSIGN
},
66 { "min", required_argument
, 0, 'm' },
67 { "max", required_argument
, 0, 'M' },
68 { "range", required_argument
, 0, 'r' },
69 { "version", no_argument
, 0, 'V' },
74 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
76 static int type_offset(enode
*p
)
78 return p
->type
== fractional
? 1 :
79 p
->type
== flooring
? 1 : 0;
82 void compute_evalue(evalue
*e
, Value
*val
, Value
*res
)
84 double d
= compute_evalue(e
, val
);
89 value_set_double(*res
, d
);
92 struct indicator_term
{
94 int pos
; /* number of rational vertex */
95 int n
; /* number of cone associated to given rational vertex */
99 indicator_term(unsigned dim
, int pos
) {
101 vertex
= new evalue
* [dim
];
106 indicator_term(unsigned dim
, int pos
, int n
) {
107 den
.SetDims(dim
, dim
);
108 vertex
= new evalue
* [dim
];
112 indicator_term(const indicator_term
& src
) {
117 unsigned dim
= den
.NumCols();
118 vertex
= new evalue
* [dim
];
119 for (int i
= 0; i
< dim
; ++i
) {
120 vertex
[i
] = new evalue();
121 value_init(vertex
[i
]->d
);
122 evalue_copy(vertex
[i
], src
.vertex
[i
]);
125 void swap(indicator_term
*other
) {
127 tmp
= sign
; sign
= other
->sign
; other
->sign
= tmp
;
128 tmp
= pos
; pos
= other
->pos
; other
->pos
= tmp
;
129 tmp
= n
; n
= other
->n
; other
->n
= tmp
;
130 mat_ZZ tmp_den
= den
; den
= other
->den
; other
->den
= tmp_den
;
131 unsigned dim
= den
.NumCols();
132 for (int i
= 0; i
< dim
; ++i
) {
133 evalue
*tmp
= vertex
[i
];
134 vertex
[i
] = other
->vertex
[i
];
135 other
->vertex
[i
] = tmp
;
139 unsigned dim
= den
.NumCols();
140 for (int i
= 0; i
< dim
; ++i
) {
141 free_evalue_refs(vertex
[i
]);
146 void print(ostream
& os
, char **p
) const;
147 void substitute(Matrix
*T
);
149 void substitute(evalue
*fract
, evalue
*val
);
150 void substitute(int pos
, evalue
*val
);
151 void reduce_in_domain(Polyhedron
*D
);
152 bool is_opposite(const indicator_term
*neg
) const;
153 vec_ZZ
eval(Value
*val
) const {
155 unsigned dim
= den
.NumCols();
159 for (int i
= 0; i
< dim
; ++i
) {
160 compute_evalue(vertex
[i
], val
, &tmp
);
168 static int evalue_rational_cmp(const evalue
*e1
, const evalue
*e2
)
176 assert(value_notzero_p(e1
->d
));
177 assert(value_notzero_p(e2
->d
));
178 value_multiply(m
, e1
->x
.n
, e2
->d
);
179 value_multiply(m2
, e2
->x
.n
, e1
->d
);
182 else if (value_gt(m
, m2
))
192 static int evalue_cmp(const evalue
*e1
, const evalue
*e2
)
194 if (value_notzero_p(e1
->d
)) {
195 if (value_zero_p(e2
->d
))
197 return evalue_rational_cmp(e1
, e2
);
199 if (value_notzero_p(e2
->d
))
201 if (e1
->x
.p
->type
!= e2
->x
.p
->type
)
202 return e1
->x
.p
->type
- e2
->x
.p
->type
;
203 if (e1
->x
.p
->size
!= e2
->x
.p
->size
)
204 return e1
->x
.p
->size
- e2
->x
.p
->size
;
205 if (e1
->x
.p
->pos
!= e2
->x
.p
->pos
)
206 return e1
->x
.p
->pos
- e2
->x
.p
->pos
;
207 assert(e1
->x
.p
->type
== polynomial
||
208 e1
->x
.p
->type
== fractional
||
209 e1
->x
.p
->type
== flooring
);
210 for (int i
= 0; i
< e1
->x
.p
->size
; ++i
) {
211 int s
= evalue_cmp(&e1
->x
.p
->arr
[i
], &e2
->x
.p
->arr
[i
]);
218 void evalue_length(evalue
*e
, int len
[2])
223 while (value_zero_p(e
->d
)) {
224 assert(e
->x
.p
->type
== polynomial
||
225 e
->x
.p
->type
== fractional
||
226 e
->x
.p
->type
== flooring
);
227 if (e
->x
.p
->type
== polynomial
)
231 int offset
= type_offset(e
->x
.p
);
232 assert(e
->x
.p
->size
== offset
+2);
233 e
= &e
->x
.p
->arr
[offset
];
237 static bool it_smaller(const indicator_term
* it1
, const indicator_term
* it2
)
241 int len1
[2], len2
[2];
242 unsigned dim
= it1
->den
.NumCols();
243 for (int i
= 0; i
< dim
; ++i
) {
244 evalue_length(it1
->vertex
[i
], len1
);
245 evalue_length(it2
->vertex
[i
], len2
);
246 if (len1
[0] != len2
[0])
247 return len1
[0] < len2
[0];
248 if (len1
[1] != len2
[1])
249 return len1
[1] < len2
[1];
251 if (it1
->pos
!= it2
->pos
)
252 return it1
->pos
< it2
->pos
;
253 if (it1
->n
!= it2
->n
)
254 return it1
->n
< it2
->n
;
255 int s
= lex_cmp(it1
->den
, it2
->den
);
258 for (int i
= 0; i
< dim
; ++i
) {
259 s
= evalue_cmp(it1
->vertex
[i
], it2
->vertex
[i
]);
263 assert(it1
->sign
!= 0);
264 assert(it2
->sign
!= 0);
265 if (it1
->sign
!= it2
->sign
)
266 return it1
->sign
> 0;
271 static const int requires_resort
;
272 bool operator()(const indicator_term
* it1
, const indicator_term
* it2
) const {
273 return it_smaller(it1
, it2
);
276 const int smaller_it::requires_resort
= 1;
278 struct smaller_it_p
{
279 static const int requires_resort
;
280 bool operator()(const indicator_term
* it1
, const indicator_term
* it2
) const {
284 const int smaller_it_p::requires_resort
= 0;
286 /* Returns true if this and neg are opposite using the knowledge
287 * that they have the same numerator.
288 * In particular, we check that the signs are different and that
289 * the denominator is the same.
291 bool indicator_term::is_opposite(const indicator_term
*neg
) const
293 if (sign
+ neg
->sign
!= 0)
300 void indicator_term::reduce_in_domain(Polyhedron
*D
)
302 for (int k
= 0; k
< den
.NumCols(); ++k
) {
303 reduce_evalue_in_domain(vertex
[k
], D
);
304 if (evalue_range_reduction_in_domain(vertex
[k
], D
))
305 reduce_evalue(vertex
[k
]);
309 void indicator_term::print(ostream
& os
, char **p
) const
311 unsigned dim
= den
.NumCols();
312 unsigned factors
= den
.NumRows();
320 for (int i
= 0; i
< dim
; ++i
) {
323 evalue_print(os
, vertex
[i
], p
);
326 for (int i
= 0; i
< factors
; ++i
) {
327 os
<< " + t" << i
<< "*[";
328 for (int j
= 0; j
< dim
; ++j
) {
335 os
<< " ((" << pos
<< ", " << n
<< ", " << (void*)this << "))";
338 /* Perform the substitution specified by T on the variables.
339 * T has dimension (newdim+nparam+1) x (olddim + nparam + 1).
340 * The substitution is performed as in gen_fun::substitute
342 void indicator_term::substitute(Matrix
*T
)
344 unsigned dim
= den
.NumCols();
345 unsigned nparam
= T
->NbColumns
- dim
- 1;
346 unsigned newdim
= T
->NbRows
- nparam
- 1;
349 matrix2zz(T
, trans
, newdim
, dim
);
350 trans
= transpose(trans
);
352 newvertex
= new evalue
* [newdim
];
355 v
.SetLength(nparam
+1);
358 value_init(factor
.d
);
359 value_set_si(factor
.d
, 1);
360 value_init(factor
.x
.n
);
361 for (int i
= 0; i
< newdim
; ++i
) {
362 values2zz(T
->p
[i
]+dim
, v
, nparam
+1);
363 newvertex
[i
] = multi_monom(v
);
365 for (int j
= 0; j
< dim
; ++j
) {
366 if (value_zero_p(T
->p
[i
][j
]))
370 evalue_copy(&term
, vertex
[j
]);
371 value_assign(factor
.x
.n
, T
->p
[i
][j
]);
372 emul(&factor
, &term
);
373 eadd(&term
, newvertex
[i
]);
374 free_evalue_refs(&term
);
377 free_evalue_refs(&factor
);
378 for (int i
= 0; i
< dim
; ++i
) {
379 free_evalue_refs(vertex
[i
]);
386 static void evalue_add_constant(evalue
*e
, ZZ v
)
391 /* go down to constant term */
392 while (value_zero_p(e
->d
))
393 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)];
396 value_multiply(tmp
, tmp
, e
->d
);
397 value_addto(e
->x
.n
, e
->x
.n
, tmp
);
402 /* Make all powers in denominator lexico-positive */
403 void indicator_term::normalize()
406 extra_vertex
.SetLength(den
.NumCols());
407 for (int r
= 0; r
< den
.NumRows(); ++r
) {
408 for (int k
= 0; k
< den
.NumCols(); ++k
) {
415 extra_vertex
+= den
[r
];
419 for (int k
= 0; k
< extra_vertex
.length(); ++k
)
420 if (extra_vertex
[k
] != 0)
421 evalue_add_constant(vertex
[k
], extra_vertex
[k
]);
424 static void substitute(evalue
*e
, evalue
*fract
, 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
== fractional
&& eequal(&t
->x
.p
->arr
[0], fract
))
432 if (value_notzero_p(t
->d
))
435 free_evalue_refs(&t
->x
.p
->arr
[0]);
436 evalue
*term
= &t
->x
.p
->arr
[2];
443 free_evalue_refs(term
);
449 void indicator_term::substitute(evalue
*fract
, evalue
*val
)
451 unsigned dim
= den
.NumCols();
452 for (int i
= 0; i
< dim
; ++i
) {
453 ::substitute(vertex
[i
], fract
, val
);
457 static void substitute(evalue
*e
, int pos
, evalue
*val
)
461 for (t
= e
; value_zero_p(t
->d
); t
= &t
->x
.p
->arr
[type_offset(t
->x
.p
)]) {
462 if (t
->x
.p
->type
== polynomial
&& t
->x
.p
->pos
== pos
)
465 if (value_notzero_p(t
->d
))
468 evalue
*term
= &t
->x
.p
->arr
[1];
475 free_evalue_refs(term
);
481 void indicator_term::substitute(int pos
, evalue
*val
)
483 unsigned dim
= den
.NumCols();
484 for (int i
= 0; i
< dim
; ++i
) {
485 ::substitute(vertex
[i
], pos
, val
);
489 struct indicator_constructor
: public polar_decomposer
, public vertex_decomposer
{
491 vector
<indicator_term
*> *terms
;
492 Matrix
*T
; /* Transformation to original space */
493 Param_Polyhedron
*PP
;
497 indicator_constructor(Polyhedron
*P
, unsigned dim
, Param_Polyhedron
*PP
,
499 vertex_decomposer(P
, PP
->nbV
, this), T(T
), PP(PP
) {
500 vertex
.SetLength(dim
);
501 terms
= new vector
<indicator_term
*>[nbV
];
503 ~indicator_constructor() {
504 for (int i
= 0; i
< nbV
; ++i
)
505 for (int j
= 0; j
< terms
[i
].size(); ++j
)
509 void substitute(Matrix
*T
);
511 void print(ostream
& os
, char **p
);
513 virtual void handle_polar(Polyhedron
*P
, int sign
);
514 void decompose_at_vertex(Param_Vertices
*V
, int _i
,
515 barvinok_options
*options
) {
518 vertex_decomposer::decompose_at_vertex(V
, _i
, options
);
522 void indicator_constructor::handle_polar(Polyhedron
*C
, int s
)
524 unsigned dim
= vertex
.length();
526 assert(C
->NbRays
-1 == dim
);
528 indicator_term
*term
= new indicator_term(dim
, pos
, n
++);
530 terms
[vert
].push_back(term
);
532 lattice_point(V
, C
, vertex
, term
->vertex
);
534 for (int r
= 0; r
< dim
; ++r
) {
535 values2zz(C
->Ray
[r
]+1, term
->den
[r
], dim
);
536 for (int j
= 0; j
< dim
; ++j
) {
537 if (term
->den
[r
][j
] == 0)
539 if (term
->den
[r
][j
] > 0)
541 term
->sign
= -term
->sign
;
542 term
->den
[r
] = -term
->den
[r
];
543 vertex
+= term
->den
[r
];
548 for (int i
= 0; i
< dim
; ++i
) {
549 if (!term
->vertex
[i
]) {
550 term
->vertex
[i
] = new evalue();
551 value_init(term
->vertex
[i
]->d
);
552 value_init(term
->vertex
[i
]->x
.n
);
553 zz2value(vertex
[i
], term
->vertex
[i
]->x
.n
);
554 value_set_si(term
->vertex
[i
]->d
, 1);
559 evalue_add_constant(term
->vertex
[i
], vertex
[i
]);
567 lex_order_rows(term
->den
);
570 void indicator_constructor::print(ostream
& os
, char **p
)
572 for (int i
= 0; i
< nbV
; ++i
)
573 for (int j
= 0; j
< terms
[i
].size(); ++j
) {
574 os
<< "i: " << i
<< ", j: " << j
<< endl
;
575 terms
[i
][j
]->print(os
, p
);
580 void indicator_constructor::normalize()
582 for (int i
= 0; i
< nbV
; ++i
)
583 for (int j
= 0; j
< terms
[i
].size(); ++j
) {
585 vertex
.SetLength(terms
[i
][j
]->den
.NumCols());
586 for (int r
= 0; r
< terms
[i
][j
]->den
.NumRows(); ++r
) {
587 for (int k
= 0; k
< terms
[i
][j
]->den
.NumCols(); ++k
) {
588 if (terms
[i
][j
]->den
[r
][k
] == 0)
590 if (terms
[i
][j
]->den
[r
][k
] > 0)
592 terms
[i
][j
]->sign
= -terms
[i
][j
]->sign
;
593 terms
[i
][j
]->den
[r
] = -terms
[i
][j
]->den
[r
];
594 vertex
+= terms
[i
][j
]->den
[r
];
598 lex_order_rows(terms
[i
][j
]->den
);
599 for (int k
= 0; k
< vertex
.length(); ++k
)
601 evalue_add_constant(terms
[i
][j
]->vertex
[k
], vertex
[k
]);
607 struct partial_order
{
610 map
<const indicator_term
*, int, smaller_it
> pred
;
611 map
<const indicator_term
*, vector
<const indicator_term
* >, smaller_it
> lt
;
612 map
<const indicator_term
*, vector
<const indicator_term
* >, smaller_it
> le
;
613 map
<const indicator_term
*, vector
<const indicator_term
* >, smaller_it
> eq
;
615 map
<const indicator_term
*, vector
<const indicator_term
* >, smaller_it
> pending
;
617 partial_order(indicator
*ind
) : ind(ind
) {}
618 void copy(const partial_order
& order
,
619 map
< const indicator_term
*, indicator_term
* > old2new
);
621 map
<const indicator_term
*, vector
<const indicator_term
* > >::iterator i
;
622 map
<const indicator_term
*, int >::iterator j
;
624 if (pred
.key_comp().requires_resort
) {
625 typeof(pred
) new_pred
;
626 for (j
= pred
.begin(); j
!= pred
.end(); ++j
)
627 new_pred
[(*j
).first
] = (*j
).second
;
632 if (lt
.key_comp().requires_resort
) {
634 for (i
= lt
.begin(); i
!= lt
.end(); ++i
)
635 m
[(*i
).first
] = (*i
).second
;
640 if (le
.key_comp().requires_resort
) {
642 for (i
= le
.begin(); i
!= le
.end(); ++i
)
643 m
[(*i
).first
] = (*i
).second
;
648 if (eq
.key_comp().requires_resort
) {
650 for (i
= eq
.begin(); i
!= eq
.end(); ++i
)
651 m
[(*i
).first
] = (*i
).second
;
656 if (pending
.key_comp().requires_resort
) {
658 for (i
= pending
.begin(); i
!= pending
.end(); ++i
)
659 m
[(*i
).first
] = (*i
).second
;
665 order_sign
compare(const indicator_term
*a
, const indicator_term
*b
);
666 void set_equal(const indicator_term
*a
, const indicator_term
*b
);
667 void unset_le(const indicator_term
*a
, const indicator_term
*b
);
669 bool compared(const indicator_term
* a
, const indicator_term
* b
);
670 void add(const indicator_term
* it
, std::set
<const indicator_term
*> *filter
);
671 void remove(const indicator_term
* it
);
673 void print(ostream
& os
, char **p
);
675 /* replace references to orig to references to replacement */
676 void replace(const indicator_term
* orig
, indicator_term
* replacement
);
677 void sanity_check() const;
680 /* We actually replace the contents of orig by that of replacement,
681 * but we have to be careful since replacing the content changes
682 * the order of orig in the maps.
684 void partial_order::replace(const indicator_term
* orig
, indicator_term
* replacement
)
686 int orig_pred
= pred
[orig
];
688 vector
<const indicator_term
* > orig_lt
;
689 vector
<const indicator_term
* > orig_le
;
690 vector
<const indicator_term
* > orig_eq
;
691 vector
<const indicator_term
* > orig_pending
;
692 map
<const indicator_term
*, vector
<const indicator_term
* > >::iterator i
;
693 bool in_lt
= ((i
= lt
.find(orig
)) != lt
.end());
695 orig_lt
= (*i
).second
;
698 bool in_le
= ((i
= le
.find(orig
)) != le
.end());
700 orig_le
= (*i
).second
;
703 bool in_eq
= ((i
= eq
.find(orig
)) != eq
.end());
705 orig_eq
= (*i
).second
;
708 bool in_pending
= ((i
= pending
.find(orig
)) != pending
.end());
710 orig_pending
= (*i
).second
;
713 indicator_term
*old
= const_cast<indicator_term
*>(orig
);
714 old
->swap(replacement
);
715 pred
[old
] = orig_pred
;
723 pending
[old
] = orig_pending
;
726 void partial_order::unset_le(const indicator_term
*a
, const indicator_term
*b
)
728 vector
<const indicator_term
*>::iterator i
;
729 i
= find(le
[a
].begin(), le
[a
].end(), b
);
731 if (le
[a
].size() == 0)
734 i
= find(pending
[a
].begin(), pending
[a
].end(), b
);
735 if (i
!= pending
[a
].end())
739 void partial_order::set_equal(const indicator_term
*a
, const indicator_term
*b
)
741 if (eq
[a
].size() == 0)
743 if (eq
[b
].size() == 0)
748 if (pred
.key_comp()(b
, a
)) {
749 const indicator_term
*c
= a
;
754 const indicator_term
*base
= a
;
756 map
<const indicator_term
*, vector
<const indicator_term
* > >::iterator i
;
758 for (int j
= 0; j
< eq
[b
].size(); ++j
) {
759 eq
[base
].push_back(eq
[b
][j
]);
760 eq
[eq
[b
][j
]][0] = base
;
766 for (int j
= 0; j
< lt
[b
].size(); ++j
) {
767 if (find(eq
[base
].begin(), eq
[base
].end(), lt
[b
][j
]) != eq
[base
].end())
769 else if (find(lt
[base
].begin(), lt
[base
].end(), lt
[b
][j
])
773 lt
[base
].push_back(lt
[b
][j
]);
780 for (int j
= 0; j
< le
[b
].size(); ++j
) {
781 if (find(eq
[base
].begin(), eq
[base
].end(), le
[b
][j
]) != eq
[base
].end())
783 else if (find(le
[base
].begin(), le
[base
].end(), le
[b
][j
])
787 le
[base
].push_back(le
[b
][j
]);
792 i
= pending
.find(base
);
793 if (i
!= pending
.end()) {
794 vector
<const indicator_term
* > old
= pending
[base
];
795 pending
[base
].clear();
796 for (int j
= 0; j
< old
.size(); ++j
) {
797 if (find(eq
[base
].begin(), eq
[base
].end(), old
[j
]) == eq
[base
].end())
798 pending
[base
].push_back(old
[j
]);
803 if (i
!= pending
.end()) {
804 for (int j
= 0; j
< pending
[b
].size(); ++j
) {
805 if (find(eq
[base
].begin(), eq
[base
].end(), pending
[b
][j
]) == eq
[base
].end())
806 pending
[base
].push_back(pending
[b
][j
]);
812 void partial_order::copy(const partial_order
& order
,
813 map
< const indicator_term
*, indicator_term
* > old2new
)
815 map
<const indicator_term
*, vector
<const indicator_term
* > >::const_iterator i
;
816 map
<const indicator_term
*, int >::const_iterator j
;
818 for (j
= order
.pred
.begin(); j
!= order
.pred
.end(); ++j
)
819 pred
[old2new
[(*j
).first
]] = (*j
).second
;
821 for (i
= order
.lt
.begin(); i
!= order
.lt
.end(); ++i
) {
822 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
823 lt
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
825 for (i
= order
.le
.begin(); i
!= order
.le
.end(); ++i
) {
826 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
827 le
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
829 for (i
= order
.eq
.begin(); i
!= order
.eq
.end(); ++i
) {
830 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
831 eq
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
833 for (i
= order
.pending
.begin(); i
!= order
.pending
.end(); ++i
) {
834 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
835 pending
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
841 vector
<evalue
*> max
;
843 void print(ostream
& os
, char **p
, barvinok_options
*options
) const;
844 void substitute(Matrix
*T
, barvinok_options
*options
);
845 Vector
*eval(Value
*val
, unsigned MaxRays
) const;
848 for (int i
= 0; i
< max
.size(); ++i
) {
849 free_evalue_refs(max
[i
]);
857 * Project on first dim dimensions
859 Polyhedron
* Polyhedron_Project_Initial(Polyhedron
*P
, int dim
)
865 if (P
->Dimension
== dim
)
866 return Polyhedron_Copy(P
);
868 T
= Matrix_Alloc(dim
+1, P
->Dimension
+1);
869 for (i
= 0; i
< dim
; ++i
)
870 value_set_si(T
->p
[i
][i
], 1);
871 value_set_si(T
->p
[dim
][P
->Dimension
], 1);
872 I
= Polyhedron_Image(P
, T
, P
->NbConstraints
);
878 vector
<indicator_term
*> term
;
879 indicator_constructor
& ic
;
884 barvinok_options
*options
;
885 vector
<evalue
*> substitutions
;
887 indicator(indicator_constructor
& ic
, Param_Domain
*PD
, EDomain
*D
,
888 barvinok_options
*options
) :
889 ic(ic
), PD(PD
), D(D
), order(this), options(options
), P(NULL
) {}
890 indicator(const indicator
& ind
, EDomain
*D
) :
891 ic(ind
.ic
), PD(ind
.PD
), D(NULL
), order(this), options(ind
.options
),
892 P(Polyhedron_Copy(ind
.P
)) {
893 map
< const indicator_term
*, indicator_term
* > old2new
;
894 for (int i
= 0; i
< ind
.term
.size(); ++i
) {
895 indicator_term
*it
= new indicator_term(*ind
.term
[i
]);
896 old2new
[ind
.term
[i
]] = it
;
899 order
.copy(ind
.order
, old2new
);
903 for (int i
= 0; i
< term
.size(); ++i
)
911 void set_domain(EDomain
*D
) {
915 int nparam
= ic
.P
->Dimension
- ic
.vertex
.length();
916 if (options
->lexmin_reduce
) {
917 Polyhedron
*Q
= Polyhedron_Project_Initial(D
->D
, nparam
);
918 Q
= DomainConstraintSimplify(Q
, options
->MaxRays
);
919 if (!P
|| !PolyhedronIncludes(Q
, P
))
928 void add(const indicator_term
* it
);
929 void remove(const indicator_term
* it
);
930 void remove_initial_rational_vertices();
931 void expand_rational_vertex(const indicator_term
*initial
);
933 void print(ostream
& os
, char **p
);
935 void peel(int i
, int j
);
936 void combine(const indicator_term
*a
, const indicator_term
*b
);
937 void add_substitution(evalue
*equation
);
938 void perform_pending_substitutions();
939 void reduce_in_domain(Polyhedron
*D
);
940 bool handle_equal_numerators(const indicator_term
*base
);
942 max_term
* create_max_term(const indicator_term
*it
);
944 void substitute(evalue
*equation
);
947 void partial_order::sanity_check() const
949 map
<const indicator_term
*, vector
<const indicator_term
* > >::const_iterator i
;
950 map
<const indicator_term
*, vector
<const indicator_term
* > >::const_iterator prev
;
951 map
<const indicator_term
*, vector
<const indicator_term
* > >::const_iterator l
;
952 map
<const indicator_term
*, int >::const_iterator k
, prev_k
;
954 for (k
= pred
.begin(); k
!= pred
.end(); prev_k
= k
, ++k
)
955 if (k
!= pred
.begin())
956 assert(pred
.key_comp()((*prev_k
).first
, (*k
).first
));
957 for (i
= lt
.begin(); i
!= lt
.end(); prev
= i
, ++i
) {
960 i_v
= (*i
).first
->eval(ind
->D
->sample
->p
);
962 assert(lt
.key_comp()((*prev
).first
, (*i
).first
));
963 l
= eq
.find((*i
).first
);
965 assert((*l
).second
.size() > 1);
966 assert(pred
.find((*i
).first
) != pred
.end());
967 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
968 k
= pred
.find((*i
).second
[j
]);
969 assert(k
!= pred
.end());
970 assert((*k
).second
!= 0);
971 if ((*i
).first
->sign
!= 0 &&
972 (*i
).second
[j
]->sign
!= 0 && ind
->D
->sample
) {
973 vec_ZZ j_v
= (*i
).second
[j
]->eval(ind
->D
->sample
->p
);
974 assert(lex_cmp(i_v
, j_v
) < 0);
978 for (i
= le
.begin(); i
!= le
.end(); ++i
) {
979 assert((*i
).second
.size() > 0);
980 assert(pred
.find((*i
).first
) != pred
.end());
981 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
982 k
= pred
.find((*i
).second
[j
]);
983 assert(k
!= pred
.end());
984 assert((*k
).second
!= 0);
987 for (i
= eq
.begin(); i
!= eq
.end(); ++i
) {
988 assert(pred
.find((*i
).first
) != pred
.end());
989 assert((*i
).second
.size() >= 1);
991 for (i
= pending
.begin(); i
!= pending
.end(); ++i
) {
992 assert(pred
.find((*i
).first
) != pred
.end());
993 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
994 assert(pred
.find((*i
).second
[j
]) != pred
.end());
998 max_term
* indicator::create_max_term(const indicator_term
*it
)
1000 int dim
= it
->den
.NumCols();
1001 int nparam
= ic
.P
->Dimension
- ic
.vertex
.length();
1002 max_term
*maximum
= new max_term
;
1003 maximum
->domain
= new EDomain(D
);
1004 for (int j
= 0; j
< dim
; ++j
) {
1005 evalue
*E
= new evalue
;
1007 evalue_copy(E
, it
->vertex
[j
]);
1008 if (evalue_frac2floor_in_domain3(E
, D
->D
, 0))
1010 maximum
->max
.push_back(E
);
1016 static evalue
*ediff(const evalue
*a
, const evalue
*b
)
1020 evalue_set_si(&mone
, -1, 1);
1021 evalue
*diff
= new evalue
;
1022 value_init(diff
->d
);
1023 evalue_copy(diff
, b
);
1026 reduce_evalue(diff
);
1027 free_evalue_refs(&mone
);
1031 static order_sign
evalue_sign(evalue
*diff
, EDomain
*D
, barvinok_options
*options
)
1033 order_sign sign
= order_eq
;
1036 evalue_set_si(&mone
, -1, 1);
1037 int len
= 1 + D
->D
->Dimension
+ 1;
1038 Vector
*c
= Vector_Alloc(len
);
1039 Matrix
*T
= Matrix_Alloc(2, len
-1);
1041 int fract
= evalue2constraint(D
, diff
, c
->p
, len
);
1042 Vector_Copy(c
->p
+1, T
->p
[0], len
-1);
1043 value_assign(T
->p
[1][len
-2], c
->p
[0]);
1045 order_sign upper_sign
= polyhedron_affine_sign(D
->D
, T
, options
);
1046 if (upper_sign
== order_lt
|| !fract
)
1050 evalue2constraint(D
, diff
, c
->p
, len
);
1052 Vector_Copy(c
->p
+1, T
->p
[0], len
-1);
1053 value_assign(T
->p
[1][len
-2], c
->p
[0]);
1055 order_sign neg_lower_sign
= polyhedron_affine_sign(D
->D
, T
, options
);
1057 if (neg_lower_sign
== order_lt
)
1059 else if (neg_lower_sign
== order_eq
|| neg_lower_sign
== order_le
) {
1060 if (upper_sign
== order_eq
|| upper_sign
== order_le
)
1065 if (upper_sign
== order_lt
|| upper_sign
== order_le
||
1066 upper_sign
== order_eq
)
1069 sign
= order_unknown
;
1075 free_evalue_refs(&mone
);
1080 order_sign
partial_order::compare(const indicator_term
*a
, const indicator_term
*b
)
1082 unsigned dim
= a
->den
.NumCols();
1083 order_sign sign
= order_eq
;
1084 EDomain
*D
= ind
->D
;
1085 unsigned MaxRays
= ind
->options
->MaxRays
;
1086 bool rational
= a
->sign
== 0 || b
->sign
== 0;
1087 if (rational
&& POL_ISSET(ind
->options
->MaxRays
, POL_INTEGER
)) {
1088 ind
->options
->MaxRays
&= ~POL_INTEGER
;
1089 if (ind
->options
->MaxRays
)
1090 ind
->options
->MaxRays
|= POL_HIGH_BIT
;
1093 for (int k
= 0; k
< dim
; ++k
) {
1094 /* compute a->vertex[k] - b->vertex[k] */
1095 evalue
*diff
= ediff(a
->vertex
[k
], b
->vertex
[k
]);
1096 order_sign diff_sign
= evalue_sign(diff
, D
, ind
->options
);
1098 if (diff_sign
== order_undefined
) {
1099 assert(sign
== order_le
|| sign
== order_ge
);
1100 if (sign
== order_le
)
1104 free_evalue_refs(diff
);
1108 if (diff_sign
== order_lt
) {
1109 if (sign
== order_eq
|| sign
== order_le
)
1112 sign
= order_unknown
;
1113 free_evalue_refs(diff
);
1117 if (diff_sign
== order_gt
) {
1118 if (sign
== order_eq
|| sign
== order_ge
)
1121 sign
= order_unknown
;
1122 free_evalue_refs(diff
);
1126 if (diff_sign
== order_eq
) {
1127 if (D
== ind
->D
&& !EVALUE_IS_ZERO(*diff
))
1128 ind
->add_substitution(diff
);
1129 free_evalue_refs(diff
);
1133 if ((diff_sign
== order_unknown
) ||
1134 ((diff_sign
== order_lt
|| diff_sign
== order_le
) && sign
== order_ge
) ||
1135 ((diff_sign
== order_gt
|| diff_sign
== order_ge
) && sign
== order_le
)) {
1136 free_evalue_refs(diff
);
1138 sign
= order_unknown
;
1145 vector
<EDomain_floor
*> new_floors
;
1146 M
= D
->add_ge_constraint(diff
, new_floors
);
1147 value_set_si(M
->p
[M
->NbRows
-1][0], 0);
1148 Polyhedron
*D2
= Constraints2Polyhedron(M
, MaxRays
);
1149 EDomain
*EDeq
= new EDomain(D2
, D
, new_floors
);
1150 Polyhedron_Free(D2
);
1152 for (int i
= 0; i
< new_floors
.size(); ++i
)
1153 EDomain_floor::unref(new_floors
[i
]);
1159 free_evalue_refs(diff
);
1166 ind
->options
->MaxRays
= MaxRays
;
1170 bool partial_order::compared(const indicator_term
* a
, const indicator_term
* b
)
1172 map
<const indicator_term
*, vector
<const indicator_term
* > >::iterator j
;
1175 if (j
!= lt
.end() && find(lt
[a
].begin(), lt
[a
].end(), b
) != lt
[a
].end())
1179 if (j
!= le
.end() && find(le
[a
].begin(), le
[a
].end(), b
) != le
[a
].end())
1185 void partial_order::add(const indicator_term
* it
,
1186 std::set
<const indicator_term
*> *filter
)
1188 if (eq
.find(it
) != eq
.end() && eq
[it
].size() == 1)
1194 map
<const indicator_term
*, int >::iterator i
;
1195 for (i
= pred
.begin(); i
!= pred
.end(); ++i
) {
1196 if ((*i
).first
== it
)
1198 if ((*i
).second
!= 0)
1200 if (eq
.find((*i
).first
) != eq
.end() && eq
[(*i
).first
].size() == 1)
1203 if (filter
->find((*i
).first
) == filter
->end())
1205 if (compared((*i
).first
, it
))
1208 order_sign sign
= compare(it
, (*i
).first
);
1209 if (sign
== order_lt
) {
1210 lt
[it
].push_back((*i
).first
);
1212 } else if (sign
== order_le
) {
1213 le
[it
].push_back((*i
).first
);
1215 } else if (sign
== order_eq
) {
1216 set_equal(it
, (*i
).first
);
1218 } else if (sign
== order_gt
) {
1219 pending
[(*i
).first
].push_back(it
);
1220 lt
[(*i
).first
].push_back(it
);
1222 } else if (sign
== order_ge
) {
1223 pending
[(*i
).first
].push_back(it
);
1224 le
[(*i
).first
].push_back(it
);
1230 void partial_order::remove(const indicator_term
* it
)
1232 std::set
<const indicator_term
*> filter
;
1233 map
<const indicator_term
*, vector
<const indicator_term
* > >::iterator i
;
1235 assert(pred
[it
] == 0);
1238 if (i
!= eq
.end()) {
1239 assert(eq
[it
].size() >= 1);
1240 const indicator_term
*base
;
1241 if (eq
[it
].size() == 1) {
1245 vector
<const indicator_term
* >::iterator j
;
1246 j
= find(eq
[base
].begin(), eq
[base
].end(), it
);
1247 assert(j
!= eq
[base
].end());
1250 /* "it" may no longer be the smallest, since the order
1251 * structure may have been copied from another one.
1253 sort(eq
[it
].begin()+1, eq
[it
].end(), pred
.key_comp());
1254 assert(eq
[it
][0] == it
);
1255 eq
[it
].erase(eq
[it
].begin());
1260 for (int j
= 1; j
< eq
[base
].size(); ++j
)
1261 eq
[eq
[base
][j
]][0] = base
;
1264 if (i
!= lt
.end()) {
1270 if (i
!= le
.end()) {
1275 i
= pending
.find(it
);
1276 if (i
!= pending
.end()) {
1277 pending
[base
] = pending
[it
];
1282 if (eq
[base
].size() == 1)
1291 if (i
!= lt
.end()) {
1292 for (int j
= 0; j
< lt
[it
].size(); ++j
) {
1293 filter
.insert(lt
[it
][j
]);
1300 if (i
!= le
.end()) {
1301 for (int j
= 0; j
< le
[it
].size(); ++j
) {
1302 filter
.insert(le
[it
][j
]);
1310 i
= pending
.find(it
);
1311 if (i
!= pending
.end()) {
1312 vector
<const indicator_term
*> it_pending
= pending
[it
];
1314 for (int j
= 0; j
< it_pending
.size(); ++j
) {
1315 filter
.erase(it_pending
[j
]);
1316 add(it_pending
[j
], &filter
);
1321 void partial_order::print(ostream
& os
, char **p
)
1323 map
<const indicator_term
*, vector
<const indicator_term
* > >::iterator i
;
1324 map
<const indicator_term
*, int >::iterator j
;
1325 for (j
= pred
.begin(); j
!= pred
.end(); ++j
) {
1326 (*j
).first
->print(os
, p
);
1327 os
<< ": " << (*j
).second
<< endl
;
1329 for (i
= lt
.begin(); i
!= lt
.end(); ++i
) {
1330 (*i
).first
->print(os
, p
);
1331 assert(pred
.find((*i
).first
) != pred
.end());
1332 os
<< "(" << pred
[(*i
).first
] << ")";
1334 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1337 (*i
).second
[j
]->print(os
, p
);
1338 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1339 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1343 for (i
= le
.begin(); i
!= le
.end(); ++i
) {
1344 (*i
).first
->print(os
, p
);
1345 assert(pred
.find((*i
).first
) != pred
.end());
1346 os
<< "(" << pred
[(*i
).first
] << ")";
1348 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1351 (*i
).second
[j
]->print(os
, p
);
1352 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1353 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1357 for (i
= eq
.begin(); i
!= eq
.end(); ++i
) {
1358 if ((*i
).second
.size() <= 1)
1360 (*i
).first
->print(os
, p
);
1361 assert(pred
.find((*i
).first
) != pred
.end());
1362 os
<< "(" << pred
[(*i
).first
] << ")";
1363 for (int j
= 1; j
< (*i
).second
.size(); ++j
) {
1366 (*i
).second
[j
]->print(os
, p
);
1367 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1368 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1372 for (i
= pending
.begin(); i
!= pending
.end(); ++i
) {
1373 os
<< "pending on ";
1374 (*i
).first
->print(os
, p
);
1375 assert(pred
.find((*i
).first
) != pred
.end());
1376 os
<< "(" << pred
[(*i
).first
] << ")";
1378 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1381 (*i
).second
[j
]->print(os
, p
);
1382 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1383 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1389 void indicator::add(const indicator_term
* it
)
1391 indicator_term
*nt
= new indicator_term(*it
);
1392 if (options
->lexmin_reduce
)
1393 nt
->reduce_in_domain(P
? P
: D
->D
);
1395 order
.add(nt
, NULL
);
1396 assert(term
.size() == order
.pred
.size());
1399 void indicator::remove(const indicator_term
* it
)
1401 vector
<indicator_term
*>::iterator i
;
1402 i
= find(term
.begin(), term
.end(), it
);
1403 assert(i
!= term
.end());
1406 assert(term
.size() == order
.pred
.size());
1410 void indicator::expand_rational_vertex(const indicator_term
*initial
)
1412 int pos
= initial
->pos
;
1414 if (ic
.terms
[pos
].size() == 0) {
1416 FORALL_PVertex_in_ParamPolyhedron(V
, PD
, ic
.PP
) // _i is internal counter
1418 ic
.decompose_at_vertex(V
, pos
, options
);
1421 END_FORALL_PVertex_in_ParamPolyhedron
;
1423 for (int j
= 0; j
< ic
.terms
[pos
].size(); ++j
)
1424 add(ic
.terms
[pos
][j
]);
1427 void indicator::remove_initial_rational_vertices()
1430 const indicator_term
*initial
= NULL
;
1431 map
<const indicator_term
*, int >::iterator i
;
1432 for (i
= order
.pred
.begin(); i
!= order
.pred
.end(); ++i
) {
1433 if ((*i
).second
!= 0)
1435 if ((*i
).first
->sign
!= 0)
1437 if (order
.eq
.find((*i
).first
) != order
.eq
.end() &&
1438 order
.eq
[(*i
).first
].size() <= 1)
1440 initial
= (*i
).first
;
1445 expand_rational_vertex(initial
);
1449 void indicator::reduce_in_domain(Polyhedron
*D
)
1451 for (int i
= 0; i
< term
.size(); ++i
)
1452 term
[i
]->reduce_in_domain(D
);
1455 void indicator::print(ostream
& os
, char **p
)
1457 assert(term
.size() == order
.pred
.size());
1458 for (int i
= 0; i
< term
.size(); ++i
) {
1459 term
[i
]->print(os
, p
);
1461 os
<< ": " << term
[i
]->eval(D
->sample
->p
);
1468 /* Remove pairs of opposite terms */
1469 void indicator::simplify()
1471 for (int i
= 0; i
< term
.size(); ++i
) {
1472 for (int j
= i
+1; j
< term
.size(); ++j
) {
1473 if (term
[i
]->sign
+ term
[j
]->sign
!= 0)
1475 if (term
[i
]->den
!= term
[j
]->den
)
1478 for (k
= 0; k
< term
[i
]->den
.NumCols(); ++k
)
1479 if (!eequal(term
[i
]->vertex
[k
], term
[j
]->vertex
[k
]))
1481 if (k
< term
[i
]->den
.NumCols())
1485 term
.erase(term
.begin()+j
);
1486 term
.erase(term
.begin()+i
);
1493 void indicator::peel(int i
, int j
)
1501 int dim
= term
[i
]->den
.NumCols();
1506 int n_common
= 0, n_i
= 0, n_j
= 0;
1508 common
.SetDims(min(term
[i
]->den
.NumRows(), term
[j
]->den
.NumRows()), dim
);
1509 rest_i
.SetDims(term
[i
]->den
.NumRows(), dim
);
1510 rest_j
.SetDims(term
[j
]->den
.NumRows(), dim
);
1513 for (k
= 0, l
= 0; k
< term
[i
]->den
.NumRows() && l
< term
[j
]->den
.NumRows(); ) {
1514 int s
= lex_cmp(term
[i
]->den
[k
], term
[j
]->den
[l
]);
1516 common
[n_common
++] = term
[i
]->den
[k
];
1520 rest_i
[n_i
++] = term
[i
]->den
[k
++];
1522 rest_j
[n_j
++] = term
[j
]->den
[l
++];
1524 while (k
< term
[i
]->den
.NumRows())
1525 rest_i
[n_i
++] = term
[i
]->den
[k
++];
1526 while (l
< term
[j
]->den
.NumRows())
1527 rest_j
[n_j
++] = term
[j
]->den
[l
++];
1528 common
.SetDims(n_common
, dim
);
1529 rest_i
.SetDims(n_i
, dim
);
1530 rest_j
.SetDims(n_j
, dim
);
1532 for (k
= 0; k
<= n_i
; ++k
) {
1533 indicator_term
*it
= new indicator_term(*term
[i
]);
1534 it
->den
.SetDims(n_common
+ k
, dim
);
1535 for (l
= 0; l
< n_common
; ++l
)
1536 it
->den
[l
] = common
[l
];
1537 for (l
= 0; l
< k
; ++l
)
1538 it
->den
[n_common
+l
] = rest_i
[l
];
1539 lex_order_rows(it
->den
);
1541 for (l
= 0; l
< dim
; ++l
)
1542 evalue_add_constant(it
->vertex
[l
], rest_i
[k
-1][l
]);
1546 for (k
= 0; k
<= n_j
; ++k
) {
1547 indicator_term
*it
= new indicator_term(*term
[j
]);
1548 it
->den
.SetDims(n_common
+ k
, dim
);
1549 for (l
= 0; l
< n_common
; ++l
)
1550 it
->den
[l
] = common
[l
];
1551 for (l
= 0; l
< k
; ++l
)
1552 it
->den
[n_common
+l
] = rest_j
[l
];
1553 lex_order_rows(it
->den
);
1555 for (l
= 0; l
< dim
; ++l
)
1556 evalue_add_constant(it
->vertex
[l
], rest_j
[k
-1][l
]);
1559 term
.erase(term
.begin()+j
);
1560 term
.erase(term
.begin()+i
);
1563 void indicator::combine(const indicator_term
*a
, const indicator_term
*b
)
1565 int dim
= a
->den
.NumCols();
1570 int n_common
= 0, n_i
= 0, n_j
= 0;
1572 common
.SetDims(min(a
->den
.NumRows(), b
->den
.NumRows()), dim
);
1573 rest_i
.SetDims(a
->den
.NumRows(), dim
);
1574 rest_j
.SetDims(b
->den
.NumRows(), dim
);
1577 for (k
= 0, l
= 0; k
< a
->den
.NumRows() && l
< b
->den
.NumRows(); ) {
1578 int s
= lex_cmp(a
->den
[k
], b
->den
[l
]);
1580 common
[n_common
++] = a
->den
[k
];
1584 rest_i
[n_i
++] = a
->den
[k
++];
1586 rest_j
[n_j
++] = b
->den
[l
++];
1588 while (k
< a
->den
.NumRows())
1589 rest_i
[n_i
++] = a
->den
[k
++];
1590 while (l
< b
->den
.NumRows())
1591 rest_j
[n_j
++] = b
->den
[l
++];
1592 common
.SetDims(n_common
, dim
);
1593 rest_i
.SetDims(n_i
, dim
);
1594 rest_j
.SetDims(n_j
, dim
);
1599 int n
= n_i
> n_j
? n_i
: n_j
;
1600 indicator_term
**new_term
= new indicator_term
* [1 << n
];
1601 assert(order
.eq
[a
].size() > 1);
1603 for (k
= (1 << n_i
)-1; k
>= 0; --k
) {
1604 indicator_term
*it
= new indicator_term(*b
);
1605 it
->den
.SetDims(n_common
+ n_i
+ n_j
, dim
);
1606 for (l
= 0; l
< n_common
; ++l
)
1607 it
->den
[l
] = common
[l
];
1608 for (l
= 0; l
< n_i
; ++l
)
1609 it
->den
[n_common
+l
] = rest_i
[l
];
1610 for (l
= 0; l
< n_j
; ++l
)
1611 it
->den
[n_common
+n_i
+l
] = rest_j
[l
];
1612 lex_order_rows(it
->den
);
1614 for (l
= 0; l
< n_i
; ++l
) {
1618 for (int m
= 0; m
< dim
; ++m
)
1619 evalue_add_constant(it
->vertex
[m
], rest_i
[l
][m
]);
1622 it
->sign
= -it
->sign
;
1623 for (l
= 0; l
< n_i
; ++l
) {
1626 order
.pending
[k
== 0 ? a
: it
].push_back(new_term
[k
+(1<<l
)]);
1627 order
.lt
[k
== 0 ? a
: it
].push_back(new_term
[k
+(1<<l
)]);
1628 order
.pred
[new_term
[k
+(1<<l
)]]++;
1631 order
.replace(b
, it
);
1640 for (k
= (1 << n_j
)-1; k
>= 0; --k
) {
1641 indicator_term
*it
= new indicator_term(*a
);
1642 it
->den
.SetDims(n_common
+ n_i
+ n_j
, dim
);
1643 for (l
= 0; l
< n_common
; ++l
)
1644 it
->den
[l
] = common
[l
];
1645 for (l
= 0; l
< n_i
; ++l
)
1646 it
->den
[n_common
+l
] = rest_i
[l
];
1647 for (l
= 0; l
< n_j
; ++l
)
1648 it
->den
[n_common
+n_i
+l
] = rest_j
[l
];
1649 lex_order_rows(it
->den
);
1651 for (l
= 0; l
< n_j
; ++l
) {
1655 for (int m
= 0; m
< dim
; ++m
)
1656 evalue_add_constant(it
->vertex
[m
], rest_j
[l
][m
]);
1659 it
->sign
= -it
->sign
;
1660 for (l
= 0; l
< n_j
; ++l
) {
1663 order
.pending
[k
== 0 ? a
: it
].push_back(new_term
[k
+(1<<l
)]);
1664 order
.lt
[k
== 0 ? a
: it
].push_back(new_term
[k
+(1<<l
)]);
1665 assert(order
.pred
.find(new_term
[k
+(1<<l
)]) != order
.pred
.end());
1666 order
.pred
[new_term
[k
+(1<<l
)]]++;
1669 order
.replace(a
, it
);
1679 assert(term
.size() == order
.pred
.size());
1682 bool indicator::handle_equal_numerators(const indicator_term
*base
)
1684 for (int i
= 0; i
< order
.eq
[base
].size(); ++i
) {
1685 for (int j
= i
+1; j
< order
.eq
[base
].size(); ++j
) {
1686 if (order
.eq
[base
][i
]->is_opposite(order
.eq
[base
][j
])) {
1687 remove(order
.eq
[base
][j
]);
1688 remove(i
? order
.eq
[base
][i
] : base
);
1693 for (int j
= 1; j
< order
.eq
[base
].size(); ++j
)
1694 if (order
.eq
[base
][j
]->sign
!= base
->sign
) {
1695 combine(base
, order
.eq
[base
][j
]);
1701 void indicator::substitute(evalue
*equation
)
1703 evalue
*fract
= NULL
;
1704 evalue
*val
= new evalue
;
1706 evalue_copy(val
, equation
);
1709 value_init(factor
.d
);
1710 value_init(factor
.x
.n
);
1713 for (e
= val
; value_zero_p(e
->d
) && e
->x
.p
->type
!= fractional
;
1714 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)])
1717 if (value_zero_p(e
->d
) && e
->x
.p
->type
== fractional
)
1718 fract
= &e
->x
.p
->arr
[0];
1720 for (e
= val
; value_zero_p(e
->d
) && e
->x
.p
->type
!= polynomial
;
1721 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)])
1723 assert(value_zero_p(e
->d
) && e
->x
.p
->type
== polynomial
);
1726 int offset
= type_offset(e
->x
.p
);
1728 assert(value_notzero_p(e
->x
.p
->arr
[offset
+1].d
));
1729 assert(value_notzero_p(e
->x
.p
->arr
[offset
+1].x
.n
));
1730 if (value_neg_p(e
->x
.p
->arr
[offset
+1].x
.n
)) {
1731 value_oppose(factor
.d
, e
->x
.p
->arr
[offset
+1].x
.n
);
1732 value_assign(factor
.x
.n
, e
->x
.p
->arr
[offset
+1].d
);
1734 value_assign(factor
.d
, e
->x
.p
->arr
[offset
+1].x
.n
);
1735 value_oppose(factor
.x
.n
, e
->x
.p
->arr
[offset
+1].d
);
1738 free_evalue_refs(&e
->x
.p
->arr
[offset
+1]);
1741 *e
= e
->x
.p
->arr
[offset
];
1746 for (int i
= 0; i
< term
.size(); ++i
)
1747 term
[i
]->substitute(fract
, val
);
1749 free_evalue_refs(&p
->arr
[0]);
1751 for (int i
= 0; i
< term
.size(); ++i
)
1752 term
[i
]->substitute(p
->pos
, val
);
1755 free_evalue_refs(&factor
);
1756 free_evalue_refs(val
);
1762 void indicator::add_substitution(evalue
*equation
)
1764 for (int i
= 0; i
< substitutions
.size(); ++i
)
1765 if (eequal(substitutions
[i
], equation
))
1767 evalue
*copy
= new evalue();
1768 value_init(copy
->d
);
1769 evalue_copy(copy
, equation
);
1770 substitutions
.push_back(copy
);
1773 void indicator::perform_pending_substitutions()
1775 if (substitutions
.size() == 0)
1778 for (int i
= 0; i
< substitutions
.size(); ++i
) {
1779 substitute(substitutions
[i
]);
1780 free_evalue_refs(substitutions
[i
]);
1781 delete substitutions
[i
];
1783 substitutions
.clear();
1787 static void print_varlist(ostream
& os
, int n
, char **names
)
1791 for (i
= 0; i
< n
; ++i
) {
1799 void max_term::print(ostream
& os
, char **p
, barvinok_options
*options
) const
1802 print_varlist(os
, domain
->dimension(), p
);
1805 for (int i
= 0; i
< max
.size(); ++i
) {
1808 evalue_print(os
, max
[i
], p
);
1812 domain
->print_constraints(os
, p
, options
);
1816 Matrix
*left_inverse(Matrix
*M
, Matrix
**Eq
)
1819 Matrix
*L
, *H
, *Q
, *U
, *ratH
, *invH
, *Ut
, *inv
;
1824 L
= Matrix_Alloc(M
->NbRows
-1, M
->NbColumns
-1);
1825 for (i
= 0; i
< L
->NbRows
; ++i
)
1826 Vector_Copy(M
->p
[i
], L
->p
[i
], L
->NbColumns
);
1827 right_hermite(L
, &H
, &U
, &Q
);
1830 t
= Vector_Alloc(U
->NbColumns
);
1831 for (i
= 0; i
< U
->NbColumns
; ++i
)
1832 value_oppose(t
->p
[i
], M
->p
[i
][M
->NbColumns
-1]);
1834 *Eq
= Matrix_Alloc(H
->NbRows
- H
->NbColumns
, 2 + U
->NbColumns
);
1835 for (i
= 0; i
< H
->NbRows
- H
->NbColumns
; ++i
) {
1836 Vector_Copy(U
->p
[H
->NbColumns
+i
], (*Eq
)->p
[i
]+1, U
->NbColumns
);
1837 Inner_Product(U
->p
[H
->NbColumns
+i
], t
->p
, U
->NbColumns
,
1838 (*Eq
)->p
[i
]+1+U
->NbColumns
);
1841 ratH
= Matrix_Alloc(H
->NbColumns
+1, H
->NbColumns
+1);
1842 invH
= Matrix_Alloc(H
->NbColumns
+1, H
->NbColumns
+1);
1843 for (i
= 0; i
< H
->NbColumns
; ++i
)
1844 Vector_Copy(H
->p
[i
], ratH
->p
[i
], H
->NbColumns
);
1845 value_set_si(ratH
->p
[ratH
->NbRows
-1][ratH
->NbColumns
-1], 1);
1847 ok
= Matrix_Inverse(ratH
, invH
);
1850 Ut
= Matrix_Alloc(invH
->NbRows
, U
->NbColumns
+1);
1851 for (i
= 0; i
< Ut
->NbRows
-1; ++i
) {
1852 Vector_Copy(U
->p
[i
], Ut
->p
[i
], U
->NbColumns
);
1853 Inner_Product(U
->p
[i
], t
->p
, U
->NbColumns
, &Ut
->p
[i
][Ut
->NbColumns
-1]);
1857 value_set_si(Ut
->p
[Ut
->NbRows
-1][Ut
->NbColumns
-1], 1);
1858 inv
= Matrix_Alloc(invH
->NbRows
, Ut
->NbColumns
);
1859 Matrix_Product(invH
, Ut
, inv
);
1865 /* T maps the compressed parameters to the original parameters,
1866 * while this max_term is based on the compressed parameters
1867 * and we want get the original parameters back.
1869 void max_term::substitute(Matrix
*T
, barvinok_options
*options
)
1871 assert(domain
->dimension() == T
->NbColumns
-1);
1872 int nexist
= domain
->D
->Dimension
- (T
->NbColumns
-1);
1874 Matrix
*inv
= left_inverse(T
, &Eq
);
1877 value_init(denom
.d
);
1878 value_init(denom
.x
.n
);
1879 value_set_si(denom
.x
.n
, 1);
1880 value_assign(denom
.d
, inv
->p
[inv
->NbRows
-1][inv
->NbColumns
-1]);
1883 v
.SetLength(inv
->NbColumns
);
1884 evalue
* subs
[inv
->NbRows
-1];
1885 for (int i
= 0; i
< inv
->NbRows
-1; ++i
) {
1886 values2zz(inv
->p
[i
], v
, v
.length());
1887 subs
[i
] = multi_monom(v
);
1888 emul(&denom
, subs
[i
]);
1890 free_evalue_refs(&denom
);
1892 domain
->substitute(subs
, inv
, Eq
, options
->MaxRays
);
1895 for (int i
= 0; i
< max
.size(); ++i
) {
1896 evalue_substitute(max
[i
], subs
);
1897 reduce_evalue(max
[i
]);
1900 for (int i
= 0; i
< inv
->NbRows
-1; ++i
) {
1901 free_evalue_refs(subs
[i
]);
1907 int Last_Non_Zero(Value
*p
, unsigned len
)
1909 for (int i
= len
-1; i
>= 0; --i
)
1910 if (value_notzero_p(p
[i
]))
1915 static void SwapColumns(Value
**V
, int n
, int i
, int j
)
1917 for (int r
= 0; r
< n
; ++r
)
1918 value_swap(V
[r
][i
], V
[r
][j
]);
1921 static void SwapColumns(Polyhedron
*P
, int i
, int j
)
1923 SwapColumns(P
->Constraint
, P
->NbConstraints
, i
, j
);
1924 SwapColumns(P
->Ray
, P
->NbRays
, i
, j
);
1927 Vector
*max_term::eval(Value
*val
, unsigned MaxRays
) const
1929 if (!domain
->contains(val
, domain
->dimension()))
1931 Vector
*res
= Vector_Alloc(max
.size());
1932 for (int i
= 0; i
< max
.size(); ++i
) {
1933 compute_evalue(max
[i
], val
, &res
->p
[i
]);
1938 static Matrix
*remove_equalities(Polyhedron
**P
, unsigned nparam
, unsigned MaxRays
);
1940 Vector
*Polyhedron_not_empty(Polyhedron
*P
, barvinok_options
*options
)
1942 Polyhedron
*Porig
= P
;
1943 Vector
*sample
= NULL
;
1945 POL_ENSURE_VERTICES(P
);
1949 for (int i
= 0; i
< P
->NbRays
; ++i
)
1950 if (value_one_p(P
->Ray
[i
][1+P
->Dimension
])) {
1951 sample
= Vector_Alloc(P
->Dimension
+ 1);
1952 Vector_Copy(P
->Ray
[i
]+1, sample
->p
, P
->Dimension
+1);
1957 while (P
&& !emptyQ2(P
) && P
->NbEq
> 0) {
1959 Matrix
*T2
= remove_equalities(&P
, 0, options
->MaxRays
);
1964 Matrix
*T3
= Matrix_Alloc(T
->NbRows
, T2
->NbColumns
);
1965 Matrix_Product(T
, T2
, T3
);
1975 sample
= Polyhedron_Sample(P
, options
);
1978 Vector
*P_sample
= Vector_Alloc(Porig
->Dimension
+ 1);
1979 Matrix_Vector_Product(T
, sample
->p
, P_sample
->p
);
1980 Vector_Free(sample
);
1990 assert(in_domain(Porig
, sample
->p
));
1996 enum sign
{ le
, ge
, lge
} sign
;
1998 split (evalue
*c
, enum sign s
) : constraint(c
), sign(s
) {}
2001 static void split_on(const split
& sp
, EDomain
*D
,
2002 EDomain
**Dlt
, EDomain
**Deq
, EDomain
**Dgt
,
2003 barvinok_options
*options
)
2010 value_set_si(mone
, -1);
2014 vector
<EDomain_floor
*> new_floors
;
2015 M
= D
->add_ge_constraint(sp
.constraint
, new_floors
);
2016 if (sp
.sign
== split::lge
|| sp
.sign
== split::ge
) {
2017 M2
= Matrix_Copy(M
);
2018 value_decrement(M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1],
2019 M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1]);
2020 D2
= Constraints2Polyhedron(M2
, options
->MaxRays
);
2021 ED
[2] = new EDomain(D2
, D
, new_floors
);
2022 Polyhedron_Free(D2
);
2026 if (sp
.sign
== split::lge
|| sp
.sign
== split::le
) {
2027 M2
= Matrix_Copy(M
);
2028 Vector_Scale(M2
->p
[M2
->NbRows
-1]+1, M2
->p
[M2
->NbRows
-1]+1,
2029 mone
, M2
->NbColumns
-1);
2030 value_decrement(M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1],
2031 M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1]);
2032 D2
= Constraints2Polyhedron(M2
, options
->MaxRays
);
2033 ED
[0] = new EDomain(D2
, D
, new_floors
);
2034 Polyhedron_Free(D2
);
2039 assert(sp
.sign
== split::lge
|| sp
.sign
== split::ge
|| sp
.sign
== split::le
);
2040 value_set_si(M
->p
[M
->NbRows
-1][0], 0);
2041 D2
= Constraints2Polyhedron(M
, options
->MaxRays
);
2042 ED
[1] = new EDomain(D2
, D
, new_floors
);
2043 Polyhedron_Free(D2
);
2046 Vector
*sample
= D
->sample
;
2047 if (sample
&& new_floors
.size() > 0) {
2048 assert(sample
->Size
== D
->D
->Dimension
+1);
2049 sample
= Vector_Alloc(D
->D
->Dimension
+new_floors
.size()+1);
2050 Vector_Copy(D
->sample
->p
, sample
->p
, D
->D
->Dimension
);
2051 value_set_si(sample
->p
[D
->D
->Dimension
+new_floors
.size()], 1);
2052 for (int i
= 0; i
< new_floors
.size(); ++i
)
2053 new_floors
[i
]->eval(sample
->p
, &sample
->p
[D
->D
->Dimension
+i
]);
2056 for (int i
= 0; i
< new_floors
.size(); ++i
)
2057 EDomain_floor::unref(new_floors
[i
]);
2059 for (int i
= 0; i
< 3; ++i
) {
2062 if (sample
&& ED
[i
]->contains(sample
->p
, sample
->Size
-1)) {
2063 ED
[i
]->sample
= Vector_Alloc(sample
->Size
);
2064 Vector_Copy(sample
->p
, ED
[i
]->sample
->p
, sample
->Size
);
2065 } else if (emptyQ2(ED
[i
]->D
) ||
2066 (options
->lexmin_emptiness_check
== 1 &&
2067 !(ED
[i
]->sample
= Polyhedron_not_empty(ED
[i
]->D
, options
)))) {
2076 if (sample
!= D
->sample
)
2077 Vector_Free(sample
);
2080 ostream
& operator<< (ostream
& os
, const vector
<int> & v
)
2083 for (int i
= 0; i
< v
.size(); ++i
) {
2092 static bool isTranslation(Matrix
*M
)
2095 if (M
->NbRows
!= M
->NbColumns
)
2098 for (i
= 0;i
< M
->NbRows
; i
++)
2099 for (j
= 0; j
< M
->NbColumns
-1; j
++)
2101 if(value_notone_p(M
->p
[i
][j
]))
2104 if(value_notzero_p(M
->p
[i
][j
]))
2107 return value_one_p(M
->p
[M
->NbRows
-1][M
->NbColumns
-1]);
2110 static Matrix
*compress_parameters(Polyhedron
**P
, Polyhedron
**C
,
2111 unsigned nparam
, unsigned MaxRays
)
2115 /* compress_parms doesn't like equalities that only involve parameters */
2116 for (int i
= 0; i
< (*P
)->NbEq
; ++i
)
2117 assert(First_Non_Zero((*P
)->Constraint
[i
]+1, (*P
)->Dimension
-nparam
) != -1);
2119 M
= Matrix_Alloc((*P
)->NbEq
, (*P
)->Dimension
+2);
2120 Vector_Copy((*P
)->Constraint
[0], M
->p
[0], (*P
)->NbEq
* ((*P
)->Dimension
+2));
2121 CP
= compress_parms(M
, nparam
);
2124 if (isTranslation(CP
)) {
2129 T
= align_matrix(CP
, (*P
)->Dimension
+1);
2130 *P
= Polyhedron_Preimage(*P
, T
, MaxRays
);
2133 *C
= Polyhedron_Preimage(*C
, CP
, MaxRays
);
2138 static Matrix
*remove_equalities(Polyhedron
**P
, unsigned nparam
, unsigned MaxRays
)
2140 /* Matrix "view" of equalities */
2142 M
.NbRows
= (*P
)->NbEq
;
2143 M
.NbColumns
= (*P
)->Dimension
+2;
2144 M
.p_Init
= (*P
)->p_Init
;
2145 M
.p
= (*P
)->Constraint
;
2147 Matrix
*T
= compress_variables(&M
, nparam
);
2153 if (isIdentity(T
)) {
2157 *P
= Polyhedron_Preimage(*P
, T
, MaxRays
);
2162 void construct_rational_vertices(Param_Polyhedron
*PP
, Matrix
*T
, unsigned dim
,
2163 int nparam
, vector
<indicator_term
*>& vertices
)
2172 v
.SetLength(nparam
+1);
2175 value_init(factor
.d
);
2176 value_init(factor
.x
.n
);
2177 value_set_si(factor
.x
.n
, 1);
2178 value_set_si(factor
.d
, 1);
2180 for (i
= 0, PV
= PP
->V
; PV
; ++i
, PV
= PV
->next
) {
2181 indicator_term
*term
= new indicator_term(dim
, i
);
2182 vertices
.push_back(term
);
2183 Matrix
*M
= Matrix_Alloc(PV
->Vertex
->NbRows
+nparam
+1, nparam
+1);
2184 value_set_si(lcm
, 1);
2185 for (int j
= 0; j
< PV
->Vertex
->NbRows
; ++j
)
2186 value_lcm(lcm
, PV
->Vertex
->p
[j
][nparam
+1], &lcm
);
2187 value_assign(M
->p
[M
->NbRows
-1][M
->NbColumns
-1], lcm
);
2188 for (int j
= 0; j
< PV
->Vertex
->NbRows
; ++j
) {
2189 value_division(tmp
, lcm
, PV
->Vertex
->p
[j
][nparam
+1]);
2190 Vector_Scale(PV
->Vertex
->p
[j
], M
->p
[j
], tmp
, nparam
+1);
2192 for (int j
= 0; j
< nparam
; ++j
)
2193 value_assign(M
->p
[PV
->Vertex
->NbRows
+j
][j
], lcm
);
2195 Matrix
*M2
= Matrix_Alloc(T
->NbRows
, M
->NbColumns
);
2196 Matrix_Product(T
, M
, M2
);
2200 for (int j
= 0; j
< dim
; ++j
) {
2201 values2zz(M
->p
[j
], v
, nparam
+1);
2202 term
->vertex
[j
] = multi_monom(v
);
2203 value_assign(factor
.d
, lcm
);
2204 emul(&factor
, term
->vertex
[j
]);
2208 assert(i
== PP
->nbV
);
2209 free_evalue_refs(&factor
);
2214 /* An auxiliary class that keeps a reference to an evalue
2215 * and frees it when it goes out of scope.
2217 struct temp_evalue
{
2219 temp_evalue() : E(NULL
) {}
2220 temp_evalue(evalue
*e
) : E(e
) {}
2221 operator evalue
* () const { return E
; }
2222 evalue
*operator=(evalue
*e
) {
2224 free_evalue_refs(E
);
2232 free_evalue_refs(E
);
2238 static vector
<max_term
*> lexmin(indicator
& ind
, unsigned nparam
,
2241 vector
<max_term
*> maxima
;
2242 map
<const indicator_term
*, int >::iterator i
;
2243 vector
<int> best_score
;
2244 vector
<int> second_score
;
2245 vector
<int> neg_score
;
2248 ind
.perform_pending_substitutions();
2249 const indicator_term
*best
= NULL
, *second
= NULL
, *neg
= NULL
,
2250 *neg_eq
= NULL
, *neg_le
= NULL
;
2251 for (i
= ind
.order
.pred
.begin(); i
!= ind
.order
.pred
.end(); ++i
) {
2253 if ((*i
).second
!= 0)
2255 const indicator_term
*term
= (*i
).first
;
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
[ind
.order
.eq
[term
][j
]] != 0)
2268 if (j
< ind
.order
.eq
[term
].size())
2270 score
.push_back(ind
.order
.eq
[term
].size());
2273 if (ind
.order
.le
.find(term
) != ind
.order
.le
.end())
2274 score
.push_back(ind
.order
.le
[term
].size());
2277 if (ind
.order
.lt
.find(term
) != ind
.order
.lt
.end())
2278 score
.push_back(-ind
.order
.lt
[term
].size());
2282 if (term
->sign
> 0) {
2283 if (!best
|| score
< best_score
) {
2285 second_score
= best_score
;
2288 } else if (!second
|| score
< second_score
) {
2290 second_score
= score
;
2293 if (!neg_eq
&& ind
.order
.eq
.find(term
) != ind
.order
.eq
.end()) {
2294 for (int j
= 1; j
< ind
.order
.eq
[term
].size(); ++j
)
2295 if (ind
.order
.eq
[term
][j
]->sign
!= term
->sign
) {
2300 if (!neg_le
&& ind
.order
.le
.find(term
) != ind
.order
.le
.end())
2302 if (!neg
|| score
< neg_score
) {
2308 if (i
!= ind
.order
.pred
.end())
2311 if (!best
&& neg_eq
) {
2312 assert(ind
.order
.eq
[neg_eq
].size() != 0);
2313 bool handled
= ind
.handle_equal_numerators(neg_eq
);
2318 if (!best
&& neg_le
) {
2319 /* The smallest term is negative and <= some positive term */
2325 /* apparently there can be negative initial term on empty domains */
2326 if (ind
.options
->lexmin_emptiness_check
== 1 &&
2327 ind
.options
->lexmin_polysign
== BV_LEXMIN_POLYSIGN_POLYLIB
)
2332 if (!second
&& !neg
) {
2333 const indicator_term
*rat
= NULL
;
2335 if (ind
.order
.le
.find(best
) == ind
.order
.le
.end()) {
2336 if (ind
.order
.eq
.find(best
) != ind
.order
.eq
.end()) {
2337 bool handled
= ind
.handle_equal_numerators(best
);
2338 if (ind
.options
->lexmin_emptiness_check
== 1 &&
2339 ind
.options
->lexmin_polysign
== BV_LEXMIN_POLYSIGN_POLYLIB
)
2341 /* If !handled then the leading coefficient is bigger than one;
2342 * must be an empty domain
2349 maxima
.push_back(ind
.create_max_term(best
));
2352 for (int j
= 0; j
< ind
.order
.le
[best
].size(); ++j
) {
2353 if (ind
.order
.le
[best
][j
]->sign
== 0) {
2354 if (!rat
&& ind
.order
.pred
[ind
.order
.le
[best
][j
]] == 1)
2355 rat
= ind
.order
.le
[best
][j
];
2356 } else if (ind
.order
.le
[best
][j
]->sign
> 0) {
2357 second
= ind
.order
.le
[best
][j
];
2360 neg
= ind
.order
.le
[best
][j
];
2363 if (!second
&& !neg
) {
2365 ind
.order
.unset_le(best
, rat
);
2366 ind
.expand_rational_vertex(rat
);
2373 ind
.order
.unset_le(best
, second
);
2379 unsigned dim
= best
->den
.NumCols();
2382 for (int k
= 0; k
< dim
; ++k
) {
2383 diff
= ediff(best
->vertex
[k
], second
->vertex
[k
]);
2384 sign
= evalue_sign(diff
, ind
.D
, ind
.options
);
2386 /* neg can never be smaller than best, unless it may still cancel.
2387 * This can happen if positive terms have been determined to
2388 * be equal or less than or equal to some negative term.
2390 if (second
== neg
&& !neg_eq
&& !neg_le
) {
2391 if (sign
== order_ge
)
2393 if (sign
== order_unknown
)
2397 if (sign
!= order_eq
)
2399 if (!EVALUE_IS_ZERO(*diff
)) {
2400 ind
.add_substitution(diff
);
2401 ind
.perform_pending_substitutions();
2404 if (sign
== order_eq
) {
2405 ind
.order
.set_equal(best
, second
);
2408 if (sign
== order_lt
) {
2409 ind
.order
.lt
[best
].push_back(second
);
2410 ind
.order
.pred
[second
]++;
2413 if (sign
== order_gt
) {
2414 ind
.order
.lt
[second
].push_back(best
);
2415 ind
.order
.pred
[best
]++;
2419 split
sp(diff
, sign
== order_le
? split::le
:
2420 sign
== order_ge
? split::ge
: split::lge
);
2422 EDomain
*Dlt
, *Deq
, *Dgt
;
2423 split_on(sp
, ind
.D
, &Dlt
, &Deq
, &Dgt
, ind
.options
);
2424 if (ind
.options
->lexmin_emptiness_check
== 1)
2425 assert(Dlt
|| Deq
|| Dgt
);
2426 else if (!(Dlt
|| Deq
|| Dgt
))
2427 /* Must have been empty all along */
2430 if (Deq
&& (Dlt
|| Dgt
)) {
2431 int locsize
= loc
.size();
2433 indicator
indeq(ind
, Deq
);
2435 indeq
.add_substitution(diff
);
2436 indeq
.perform_pending_substitutions();
2437 vector
<max_term
*> maxeq
= lexmin(indeq
, nparam
, loc
);
2438 maxima
.insert(maxima
.end(), maxeq
.begin(), maxeq
.end());
2439 loc
.resize(locsize
);
2442 int locsize
= loc
.size();
2444 indicator
indgt(ind
, Dgt
);
2446 /* we don't know the new location of these terms in indgt */
2448 indgt.order.lt[second].push_back(best);
2449 indgt.order.pred[best]++;
2451 vector
<max_term
*> maxgt
= lexmin(indgt
, nparam
, loc
);
2452 maxima
.insert(maxima
.end(), maxgt
.begin(), maxgt
.end());
2453 loc
.resize(locsize
);
2458 ind
.set_domain(Deq
);
2459 ind
.add_substitution(diff
);
2460 ind
.perform_pending_substitutions();
2464 ind
.set_domain(Dlt
);
2465 ind
.order
.lt
[best
].push_back(second
);
2466 ind
.order
.pred
[second
]++;
2470 ind
.set_domain(Dgt
);
2471 ind
.order
.lt
[second
].push_back(best
);
2472 ind
.order
.pred
[best
]++;
2479 static vector
<max_term
*> lexmin(Polyhedron
*P
, Polyhedron
*C
,
2480 barvinok_options
*options
)
2482 unsigned nparam
= C
->Dimension
;
2483 Param_Polyhedron
*PP
= NULL
;
2484 Polyhedron
*CEq
= NULL
, *pVD
;
2486 Matrix
*T
= NULL
, *CP
= NULL
;
2487 Param_Domain
*D
, *next
;
2489 Polyhedron
*Porig
= P
;
2490 Polyhedron
*Corig
= C
;
2491 vector
<max_term
*> all_max
;
2493 unsigned P2PSD_MaxRays
;
2498 POL_ENSURE_VERTICES(P
);
2503 assert(P
->NbBid
== 0);
2506 remove_all_equalities(&P
, &C
, &CP
, &T
, nparam
, options
->MaxRays
);
2508 nparam
= CP
->NbColumns
-1;
2516 if (options
->MaxRays
& POL_NO_DUAL
)
2519 P2PSD_MaxRays
= options
->MaxRays
;
2522 PP
= Polyhedron2Param_SimplifiedDomain(&P
, C
, P2PSD_MaxRays
, &CEq
, &CT
);
2523 if (P
!= Q
&& Q
!= Porig
)
2527 if (isIdentity(CT
)) {
2531 nparam
= CT
->NbRows
- 1;
2535 unsigned dim
= P
->Dimension
- nparam
;
2538 for (nd
= 0, D
=PP
->D
; D
; ++nd
, D
=D
->next
);
2539 Polyhedron
**fVD
= new Polyhedron
*[nd
];
2541 indicator_constructor
ic(P
, dim
, PP
, T
);
2543 vector
<indicator_term
*> all_vertices
;
2544 construct_rational_vertices(PP
, T
, T
? T
->NbRows
-nparam
-1 : dim
,
2545 nparam
, all_vertices
);
2547 for (nd
= 0, D
=PP
->D
; D
; D
=next
) {
2550 Polyhedron
*rVD
= reduce_domain(D
->Domain
, CT
, CEq
,
2551 fVD
, nd
, options
->MaxRays
);
2555 pVD
= CT
? DomainImage(rVD
,CT
,options
->MaxRays
) : rVD
;
2557 EDomain
*epVD
= new EDomain(pVD
);
2558 indicator
ind(ic
, D
, epVD
, options
);
2560 FORALL_PVertex_in_ParamPolyhedron(V
,D
,PP
) // _i is internal counter
2561 ind
.add(all_vertices
[_i
]);
2562 END_FORALL_PVertex_in_ParamPolyhedron
;
2564 ind
.remove_initial_rational_vertices();
2567 vector
<max_term
*> maxima
= lexmin(ind
, nparam
, loc
);
2569 for (int j
= 0; j
< maxima
.size(); ++j
)
2570 maxima
[j
]->substitute(CP
, options
);
2571 all_max
.insert(all_max
.end(), maxima
.begin(), maxima
.end());
2578 for (int i
= 0; i
< all_vertices
.size(); ++i
)
2579 delete all_vertices
[i
];
2584 Param_Polyhedron_Free(PP
);
2586 Polyhedron_Free(CEq
);
2587 for (--nd
; nd
>= 0; --nd
) {
2588 Domain_Free(fVD
[nd
]);
2599 static void verify_results(Polyhedron
*A
, Polyhedron
*C
,
2600 vector
<max_term
*>& maxima
, int m
, int M
,
2601 int print_all
, unsigned MaxRays
);
2603 int main(int argc
, char **argv
)
2608 char **iter_names
, **param_names
;
2613 int m
= INT_MAX
, M
= INT_MIN
, r
;
2614 int print_solution
= 1;
2615 struct barvinok_options
*options
;
2617 options
= barvinok_options_new_with_defaults();
2619 while ((c
= getopt_long(argc
, argv
, "TAm:M:r:V", lexmin_options
, &ind
)) != -1) {
2621 case NO_EMPTINESS_CHECK
:
2622 options
->lexmin_emptiness_check
= 0;
2625 options
->lexmin_reduce
= 0;
2627 case BASIS_REDUCTION_CDD
:
2628 options
->gbr_lp_solver
= BV_GBR_CDD
;
2631 if (!strcmp(optarg
, "cddf"))
2632 options
->lexmin_polysign
= BV_LEXMIN_POLYSIGN_CDDF
;
2633 else if (!strcmp(optarg
, "cdd"))
2634 options
->lexmin_polysign
= BV_LEXMIN_POLYSIGN_CDD
;
2656 printf(barvinok_version());
2663 C
= Constraints2Polyhedron(MA
, options
->MaxRays
);
2665 fscanf(stdin
, " %d", &bignum
);
2666 assert(bignum
== -1);
2668 A
= Constraints2Polyhedron(MA
, options
->MaxRays
);
2671 if (A
->Dimension
>= VBIGDIM
)
2673 else if (A
->Dimension
>= BIGDIM
)
2682 if (verify
&& m
> M
) {
2683 fprintf(stderr
,"Nothing to do: min > max !\n");
2689 iter_names
= util_generate_names(A
->Dimension
- C
->Dimension
, "i");
2690 param_names
= util_generate_names(C
->Dimension
, "p");
2691 if (print_solution
) {
2692 Polyhedron_Print(stdout
, P_VALUE_FMT
, A
);
2693 Polyhedron_Print(stdout
, P_VALUE_FMT
, C
);
2695 vector
<max_term
*> maxima
= lexmin(A
, C
, options
);
2697 for (int i
= 0; i
< maxima
.size(); ++i
)
2698 maxima
[i
]->print(cout
, param_names
, options
);
2701 verify_results(A
, C
, maxima
, m
, M
, print_all
, options
->MaxRays
);
2703 for (int i
= 0; i
< maxima
.size(); ++i
)
2706 util_free_names(A
->Dimension
- C
->Dimension
, iter_names
);
2707 util_free_names(C
->Dimension
, param_names
);
2716 static bool lexmin(int pos
, Polyhedron
*P
, Value
*context
)
2725 value_init(LB
); value_init(UB
); value_init(k
);
2728 lu_flags
= lower_upper_bounds(pos
,P
,context
,&LB
,&UB
);
2729 assert(!(lu_flags
& LB_INFINITY
));
2731 value_set_si(context
[pos
],0);
2732 if (!lu_flags
&& value_lt(UB
,LB
)) {
2733 value_clear(LB
); value_clear(UB
); value_clear(k
);
2737 value_assign(context
[pos
], LB
);
2738 value_clear(LB
); value_clear(UB
); value_clear(k
);
2741 for (value_assign(k
,LB
); lu_flags
|| value_le(k
,UB
); value_increment(k
,k
)) {
2742 value_assign(context
[pos
],k
);
2743 if ((found
= lexmin(pos
+1, P
->next
, context
)))
2747 value_set_si(context
[pos
],0);
2748 value_clear(LB
); value_clear(UB
); value_clear(k
);
2752 static void print_list(FILE *out
, Value
*z
, char* brackets
, int len
)
2754 fprintf(out
, "%c", brackets
[0]);
2755 value_print(out
, VALUE_FMT
,z
[0]);
2756 for (int k
= 1; k
< len
; ++k
) {
2758 value_print(out
, VALUE_FMT
,z
[k
]);
2760 fprintf(out
, "%c", brackets
[1]);
2763 static int check_poly(Polyhedron
*S
, Polyhedron
*CS
, vector
<max_term
*>& maxima
,
2764 int nparam
, int pos
, Value
*z
, int print_all
, int st
,
2767 if (pos
== nparam
) {
2769 bool found
= lexmin(1, S
, z
);
2773 print_list(stdout
, z
+S
->Dimension
-nparam
+1, "()", nparam
);
2776 print_list(stdout
, z
+1, "[]", S
->Dimension
-nparam
);
2781 for (int i
= 0; i
< maxima
.size(); ++i
)
2782 if ((min
= maxima
[i
]->eval(z
+S
->Dimension
-nparam
+1, MaxRays
)))
2785 int ok
= !(found
^ !!min
);
2787 for (int i
= 0; i
< S
->Dimension
-nparam
; ++i
)
2788 if (value_ne(z
[1+i
], min
->p
[i
])) {
2795 fprintf(stderr
, "Error !\n");
2796 fprintf(stderr
, "lexmin");
2797 print_list(stderr
, z
+S
->Dimension
-nparam
+1, "()", nparam
);
2798 fprintf(stderr
, " should be ");
2800 print_list(stderr
, z
+1, "[]", S
->Dimension
-nparam
);
2801 fprintf(stderr
, " while digging gives ");
2803 print_list(stderr
, min
->p
, "[]", S
->Dimension
-nparam
);
2804 fprintf(stderr
, ".\n");
2806 } else if (print_all
)
2811 for (k
= 1; k
<= S
->Dimension
-nparam
; ++k
)
2812 value_set_si(z
[k
], 0);
2820 !(lower_upper_bounds(1+pos
, CS
, &z
[S
->Dimension
-nparam
], &LB
, &UB
));
2821 for (value_assign(tmp
,LB
); value_le(tmp
,UB
); value_increment(tmp
,tmp
)) {
2823 int k
= VALUE_TO_INT(tmp
);
2824 if (!pos
&& !(k
%st
)) {
2829 value_assign(z
[pos
+S
->Dimension
-nparam
+1],tmp
);
2830 if (!check_poly(S
, CS
->next
, maxima
, nparam
, pos
+1, z
, print_all
, st
,
2838 value_set_si(z
[pos
+S
->Dimension
-nparam
+1],0);
2846 void verify_results(Polyhedron
*A
, Polyhedron
*C
, vector
<max_term
*>& maxima
,
2847 int m
, int M
, int print_all
, unsigned MaxRays
)
2849 Polyhedron
*CC
, *CC2
, *CS
, *S
;
2850 unsigned nparam
= C
->Dimension
;
2855 CC
= Polyhedron_Project(A
, nparam
);
2856 CC2
= DomainIntersection(C
, CC
, MaxRays
);
2860 /* Intersect context with range */
2865 MM
= Matrix_Alloc(2*C
->Dimension
, C
->Dimension
+2);
2866 for (int i
= 0; i
< C
->Dimension
; ++i
) {
2867 value_set_si(MM
->p
[2*i
][0], 1);
2868 value_set_si(MM
->p
[2*i
][1+i
], 1);
2869 value_set_si(MM
->p
[2*i
][1+C
->Dimension
], -m
);
2870 value_set_si(MM
->p
[2*i
+1][0], 1);
2871 value_set_si(MM
->p
[2*i
+1][1+i
], -1);
2872 value_set_si(MM
->p
[2*i
+1][1+C
->Dimension
], M
);
2874 CC2
= AddConstraints(MM
->p
[0], 2*CC
->Dimension
, CC
, MaxRays
);
2875 U
= Universe_Polyhedron(0);
2876 CS
= Polyhedron_Scan(CC2
, U
, MaxRays
& POL_NO_DUAL
? 0 : MaxRays
);
2878 Polyhedron_Free(CC2
);
2883 p
= ALLOCN(Value
, A
->Dimension
+2);
2884 for (i
=0; i
<= A
->Dimension
; i
++) {
2886 value_set_si(p
[i
],0);
2889 value_set_si(p
[i
], 1);
2891 S
= Polyhedron_Scan(A
, C
, MaxRays
& POL_NO_DUAL
? 0 : MaxRays
);
2893 if (!print_all
&& C
->Dimension
> 0) {
2898 for (int i
= m
; i
<= M
; i
+= st
)
2905 if (!(CS
&& emptyQ2(CS
)))
2906 check_poly(S
, CS
, maxima
, nparam
, 0, p
, print_all
, st
, MaxRays
);
2913 for (i
=0; i
<= (A
->Dimension
+1); i
++)
2918 Polyhedron_Free(CC
);