6 #include <NTL/vec_ZZ.h>
7 #include <NTL/mat_ZZ.h>
9 #include <polylib/polylibgmp.h>
11 #include <barvinok/barvinok.h>
12 #include <barvinok/evalue.h>
13 #include <barvinok/options.h>
14 #include <barvinok/util.h>
15 #include "conversion.h"
16 #include "decomposer.h"
17 #include "lattice_point.h"
18 #include "reduce_domain.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 struct option lexmin_options
[] = {
56 { "verify", no_argument
, 0, 'T' },
57 { "print-all", no_argument
, 0, 'A' },
58 { "min", required_argument
, 0, 'm' },
59 { "max", required_argument
, 0, 'M' },
60 { "range", required_argument
, 0, 'r' },
61 { "version", no_argument
, 0, 'V' },
66 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
68 static int type_offset(enode
*p
)
70 return p
->type
== fractional
? 1 :
71 p
->type
== flooring
? 1 : 0;
74 static void evalue_denom(evalue
*e
, Value
*d
)
76 if (value_notzero_p(e
->d
)) {
77 value_lcm(*d
, e
->d
, d
);
80 int offset
= type_offset(e
->x
.p
);
81 for (int i
= e
->x
.p
->size
-1; i
>= offset
; --i
)
82 evalue_denom(&e
->x
.p
->arr
[i
], d
);
85 static void evalue_print(std::ostream
& o
, evalue
*e
, char **p
);
86 static void evalue_print(std::ostream
& o
, evalue
*e
, char **p
, int d
)
88 if (value_notzero_p(e
->d
)) {
89 o
<< VALUE_TO_INT(e
->x
.n
) * (d
/ VALUE_TO_INT(e
->d
));
92 assert(e
->x
.p
->type
== polynomial
|| e
->x
.p
->type
== flooring
||
93 e
->x
.p
->type
== fractional
);
94 int offset
= type_offset(e
->x
.p
);
95 for (int i
= e
->x
.p
->size
-1; i
>= offset
; --i
) {
96 if (EVALUE_IS_ZERO(e
->x
.p
->arr
[i
]))
98 if (i
!= e
->x
.p
->size
-1 &&
99 (value_zero_p(e
->x
.p
->arr
[i
].d
) ||
100 value_pos_p(e
->x
.p
->arr
[i
].x
.n
)))
102 if (i
== offset
|| !(value_one_p(e
->x
.p
->arr
[i
].x
.n
) &&
103 d
== VALUE_TO_INT(e
->x
.p
->arr
[i
].d
))) {
104 if (value_zero_p(e
->x
.p
->arr
[i
].d
))
106 evalue_print(o
, &e
->x
.p
->arr
[i
], p
, d
);
107 if (value_zero_p(e
->x
.p
->arr
[i
].d
))
112 for (int j
= 0; j
< i
-offset
; ++j
) {
115 if (e
->x
.p
->type
== flooring
) {
117 evalue_print(o
, &e
->x
.p
->arr
[0], p
);
119 } else if (e
->x
.p
->type
== fractional
) {
121 evalue_print(o
, &e
->x
.p
->arr
[0], p
);
124 o
<< p
[e
->x
.p
->pos
-1];
129 static void evalue_print(std::ostream
& o
, evalue
*e
, char **p
)
135 if (value_notone_p(d
))
137 evalue_print(o
, e
, p
, VALUE_TO_INT(d
));
138 if (value_notone_p(d
))
139 o
<< ")/" << VALUE_TO_INT(d
);
143 struct indicator_term
{
149 indicator_term(unsigned dim
, int pos
) {
151 vertex
= new evalue
* [dim
];
155 indicator_term(unsigned dim
) {
156 den
.SetDims(dim
, dim
);
157 vertex
= new evalue
* [dim
];
160 indicator_term(const indicator_term
& src
) {
164 unsigned dim
= den
.NumCols();
165 vertex
= new evalue
* [dim
];
166 for (int i
= 0; i
< dim
; ++i
) {
167 vertex
[i
] = new evalue();
168 value_init(vertex
[i
]->d
);
169 evalue_copy(vertex
[i
], src
.vertex
[i
]);
173 unsigned dim
= den
.NumCols();
174 for (int i
= 0; i
< dim
; ++i
) {
175 free_evalue_refs(vertex
[i
]);
180 void print(ostream
& os
, char **p
) const;
181 void substitute(Matrix
*T
);
183 void substitute(evalue
*fract
, evalue
*val
);
184 void substitute(int pos
, evalue
*val
);
185 void reduce_in_domain(Polyhedron
*D
);
186 bool is_opposite(indicator_term
*neg
);
189 bool indicator_term::is_opposite(indicator_term
*neg
)
191 if (sign
+ neg
->sign
!= 0)
195 for (int k
= 0; k
< den
.NumCols(); ++k
)
196 if (!eequal(vertex
[k
], neg
->vertex
[k
]))
201 void indicator_term::reduce_in_domain(Polyhedron
*D
)
203 for (int k
= 0; k
< den
.NumCols(); ++k
) {
204 reduce_evalue_in_domain(vertex
[k
], D
);
205 if (evalue_range_reduction_in_domain(vertex
[k
], D
))
206 reduce_evalue(vertex
[k
]);
210 void indicator_term::print(ostream
& os
, char **p
) const
212 unsigned dim
= den
.NumCols();
213 unsigned factors
= den
.NumRows();
221 for (int i
= 0; i
< dim
; ++i
) {
224 evalue_print(os
, vertex
[i
], p
);
227 for (int i
= 0; i
< factors
; ++i
) {
228 os
<< " + t" << i
<< "*[";
229 for (int j
= 0; j
< dim
; ++j
) {
237 os
<< " (" << pos
<< ")";
240 /* Perform the substitution specified by T on the variables.
241 * T has dimension (newdim+nparam+1) x (olddim + nparam + 1).
242 * The substitution is performed as in gen_fun::substitute
244 void indicator_term::substitute(Matrix
*T
)
246 unsigned dim
= den
.NumCols();
247 unsigned nparam
= T
->NbColumns
- dim
- 1;
248 unsigned newdim
= T
->NbRows
- nparam
- 1;
251 matrix2zz(T
, trans
, newdim
, dim
);
252 trans
= transpose(trans
);
254 newvertex
= new evalue
* [newdim
];
257 v
.SetLength(nparam
+1);
260 value_init(factor
.d
);
261 value_set_si(factor
.d
, 1);
262 value_init(factor
.x
.n
);
263 for (int i
= 0; i
< newdim
; ++i
) {
264 values2zz(T
->p
[i
]+dim
, v
, nparam
+1);
265 newvertex
[i
] = multi_monom(v
);
267 for (int j
= 0; j
< dim
; ++j
) {
268 if (value_zero_p(T
->p
[i
][j
]))
272 evalue_copy(&term
, vertex
[j
]);
273 value_assign(factor
.x
.n
, T
->p
[i
][j
]);
274 emul(&factor
, &term
);
275 eadd(&term
, newvertex
[i
]);
276 free_evalue_refs(&term
);
279 free_evalue_refs(&factor
);
280 for (int i
= 0; i
< dim
; ++i
) {
281 free_evalue_refs(vertex
[i
]);
288 static void evalue_add_constant(evalue
*e
, ZZ v
)
293 /* go down to constant term */
294 while (value_zero_p(e
->d
))
295 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)];
298 value_multiply(tmp
, tmp
, e
->d
);
299 value_addto(e
->x
.n
, e
->x
.n
, tmp
);
304 /* Make all powers in denominator lexico-positive */
305 void indicator_term::normalize()
308 extra_vertex
.SetLength(den
.NumCols());
309 for (int r
= 0; r
< den
.NumRows(); ++r
) {
310 for (int k
= 0; k
< den
.NumCols(); ++k
) {
317 extra_vertex
+= den
[r
];
321 for (int k
= 0; k
< extra_vertex
.length(); ++k
)
322 if (extra_vertex
[k
] != 0)
323 evalue_add_constant(vertex
[k
], extra_vertex
[k
]);
326 static void substitute(evalue
*e
, evalue
*fract
, evalue
*val
)
330 for (t
= e
; value_zero_p(t
->d
); t
= &t
->x
.p
->arr
[type_offset(t
->x
.p
)]) {
331 if (t
->x
.p
->type
== fractional
&& eequal(&t
->x
.p
->arr
[0], fract
))
334 if (value_notzero_p(t
->d
))
337 free_evalue_refs(&t
->x
.p
->arr
[0]);
338 evalue
*term
= &t
->x
.p
->arr
[2];
345 free_evalue_refs(term
);
351 void indicator_term::substitute(evalue
*fract
, evalue
*val
)
353 unsigned dim
= den
.NumCols();
354 for (int i
= 0; i
< dim
; ++i
) {
355 ::substitute(vertex
[i
], fract
, val
);
359 static void substitute(evalue
*e
, int pos
, evalue
*val
)
363 for (t
= e
; value_zero_p(t
->d
); t
= &t
->x
.p
->arr
[type_offset(t
->x
.p
)]) {
364 if (t
->x
.p
->type
== polynomial
&& t
->x
.p
->pos
== pos
)
367 if (value_notzero_p(t
->d
))
370 evalue
*term
= &t
->x
.p
->arr
[1];
377 free_evalue_refs(term
);
383 void indicator_term::substitute(int pos
, evalue
*val
)
385 unsigned dim
= den
.NumCols();
386 for (int i
= 0; i
< dim
; ++i
) {
387 ::substitute(vertex
[i
], pos
, val
);
391 struct indicator_constructor
: public polar_decomposer
, public vertex_decomposer
{
393 vector
<indicator_term
*> *terms
;
394 Matrix
*T
; /* Transformation to original space */
395 Param_Polyhedron
*PP
;
397 indicator_constructor(Polyhedron
*P
, unsigned dim
, Param_Polyhedron
*PP
,
399 vertex_decomposer(P
, PP
->nbV
, this), T(T
), PP(PP
) {
400 vertex
.SetLength(dim
);
401 terms
= new vector
<indicator_term
*>[nbV
];
403 ~indicator_constructor() {
404 for (int i
= 0; i
< nbV
; ++i
)
405 for (int j
= 0; j
< terms
[i
].size(); ++j
)
409 void substitute(Matrix
*T
);
411 void print(ostream
& os
, char **p
);
413 virtual void handle_polar(Polyhedron
*P
, int sign
);
416 void indicator_constructor::handle_polar(Polyhedron
*C
, int s
)
418 unsigned dim
= vertex
.length();
420 assert(C
->NbRays
-1 == dim
);
422 indicator_term
*term
= new indicator_term(dim
);
424 terms
[vert
].push_back(term
);
426 lattice_point(V
, C
, vertex
, term
->vertex
);
428 for (int r
= 0; r
< dim
; ++r
) {
429 values2zz(C
->Ray
[r
]+1, term
->den
[r
], dim
);
430 for (int j
= 0; j
< dim
; ++j
) {
431 if (term
->den
[r
][j
] == 0)
433 if (term
->den
[r
][j
] > 0)
435 term
->sign
= -term
->sign
;
436 term
->den
[r
] = -term
->den
[r
];
437 vertex
+= term
->den
[r
];
442 for (int i
= 0; i
< dim
; ++i
) {
443 if (!term
->vertex
[i
]) {
444 term
->vertex
[i
] = new evalue();
445 value_init(term
->vertex
[i
]->d
);
446 value_init(term
->vertex
[i
]->x
.n
);
447 zz2value(vertex
[i
], term
->vertex
[i
]->x
.n
);
448 value_set_si(term
->vertex
[i
]->d
, 1);
453 evalue_add_constant(term
->vertex
[i
], vertex
[i
]);
461 lex_order_rows(term
->den
);
464 void indicator_constructor::print(ostream
& os
, char **p
)
466 for (int i
= 0; i
< nbV
; ++i
)
467 for (int j
= 0; j
< terms
[i
].size(); ++j
) {
468 os
<< "i: " << i
<< ", j: " << j
<< endl
;
469 terms
[i
][j
]->print(os
, p
);
474 void indicator_constructor::normalize()
476 for (int i
= 0; i
< nbV
; ++i
)
477 for (int j
= 0; j
< terms
[i
].size(); ++j
) {
479 vertex
.SetLength(terms
[i
][j
]->den
.NumCols());
480 for (int r
= 0; r
< terms
[i
][j
]->den
.NumRows(); ++r
) {
481 for (int k
= 0; k
< terms
[i
][j
]->den
.NumCols(); ++k
) {
482 if (terms
[i
][j
]->den
[r
][k
] == 0)
484 if (terms
[i
][j
]->den
[r
][k
] > 0)
486 terms
[i
][j
]->sign
= -terms
[i
][j
]->sign
;
487 terms
[i
][j
]->den
[r
] = -terms
[i
][j
]->den
[r
];
488 vertex
+= terms
[i
][j
]->den
[r
];
492 lex_order_rows(terms
[i
][j
]->den
);
493 for (int k
= 0; k
< vertex
.length(); ++k
)
495 evalue_add_constant(terms
[i
][j
]->vertex
[k
], vertex
[k
]);
502 vector
<evalue
*> floors
;
504 EDomain(Polyhedron
*D
) {
505 this->D
= Polyhedron_Copy(D
);
508 EDomain(Polyhedron
*D
, vector
<evalue
*>floors
) {
509 this->D
= Polyhedron_Copy(D
);
513 EDomain(EDomain
*ED
) {
514 this->D
= Polyhedron_Copy(ED
->D
);
515 add_floors(ED
->floors
);
518 EDomain(Polyhedron
*D
, EDomain
*ED
, vector
<evalue
*>floors
) {
519 this->D
= Polyhedron_Copy(D
);
520 add_floors(ED
->floors
);
524 void add_floors(vector
<evalue
*>floors
) {
525 for (int i
= 0; i
< floors
.size(); ++i
) {
526 evalue
*f
= new evalue
;
528 evalue_copy(f
, floors
[i
]);
529 this->floors
.push_back(f
);
532 int find_floor(evalue
*needle
) {
533 for (int i
= 0; i
< floors
.size(); ++i
)
534 if (eequal(needle
, floors
[i
]))
538 void print(FILE *out
, char **p
);
540 for (int i
= 0; i
< floors
.size(); ++i
) {
541 free_evalue_refs(floors
[i
]);
550 void EDomain::print(FILE *out
, char **p
)
552 fdostream
os(dup(fileno(out
)));
553 for (int i
= 0; i
< floors
.size(); ++i
) {
554 os
<< "floor " << i
<< ": [";
555 evalue_print(os
, floors
[i
], p
);
558 Polyhedron_Print(out
, P_VALUE_FMT
, D
);
563 enum order_sign
{ order_lt
, order_le
, order_eq
, order_ge
, order_gt
, order_unknown
};
565 struct partial_order
{
568 map
<indicator_term
*, int > pred
;
569 map
<indicator_term
*, vector
<indicator_term
* > > lt
;
570 map
<indicator_term
*, vector
<indicator_term
* > > le
;
571 map
<indicator_term
*, vector
<indicator_term
* > > eq
;
573 map
<indicator_term
*, vector
<indicator_term
* > > pending
;
575 partial_order(indicator
*ind
) : ind(ind
) {}
576 void copy(const partial_order
& order
,
577 map
< indicator_term
*, indicator_term
* > old2new
);
579 order_sign
compare(indicator_term
*a
, indicator_term
*b
);
580 void set_equal(indicator_term
*a
, indicator_term
*b
);
581 void unset_le(indicator_term
*a
, indicator_term
*b
);
583 bool compared(indicator_term
* a
, indicator_term
* b
);
584 void add(indicator_term
* it
, std::set
<indicator_term
*> *filter
);
585 void remove(indicator_term
* it
);
587 void print(ostream
& os
, char **p
);
590 void partial_order::unset_le(indicator_term
*a
, indicator_term
*b
)
592 vector
<indicator_term
*>::iterator i
;
593 i
= find(le
[a
].begin(), le
[a
].end(), b
);
596 i
= find(pending
[a
].begin(), pending
[a
].end(), b
);
597 if (i
!= pending
[a
].end())
601 void partial_order::set_equal(indicator_term
*a
, indicator_term
*b
)
603 if (eq
[a
].size() == 0)
605 if (eq
[b
].size() == 0)
611 indicator_term
*c
= a
;
616 indicator_term
*base
= a
;
618 map
<indicator_term
*, vector
<indicator_term
* > >::iterator i
;
620 for (int j
= 0; j
< eq
[b
].size(); ++j
) {
621 eq
[base
].push_back(eq
[b
][j
]);
622 eq
[eq
[b
][j
]][0] = base
;
628 for (int j
= 0; j
< lt
[b
].size(); ++j
) {
629 if (find(eq
[base
].begin(), eq
[base
].end(), lt
[b
][j
]) != eq
[base
].end())
631 else if (find(lt
[base
].begin(), lt
[base
].end(), lt
[b
][j
])
635 lt
[base
].push_back(lt
[b
][j
]);
642 for (int j
= 0; j
< le
[b
].size(); ++j
) {
643 if (find(eq
[base
].begin(), eq
[base
].end(), le
[b
][j
]) != eq
[base
].end())
645 else if (find(le
[base
].begin(), le
[base
].end(), le
[b
][j
])
649 le
[base
].push_back(le
[b
][j
]);
654 i
= pending
.find(base
);
655 if (i
!= pending
.end()) {
656 vector
<indicator_term
* > old
= pending
[base
];
657 pending
[base
].clear();
658 for (int j
= 0; j
< old
.size(); ++j
) {
659 if (find(eq
[base
].begin(), eq
[base
].end(), old
[j
]) == eq
[base
].end())
660 pending
[base
].push_back(old
[j
]);
665 if (i
!= pending
.end()) {
666 for (int j
= 0; j
< pending
[b
].size(); ++j
) {
667 if (find(eq
[base
].begin(), eq
[base
].end(), pending
[b
][j
]) == eq
[base
].end())
668 pending
[base
].push_back(pending
[b
][j
]);
674 void partial_order::copy(const partial_order
& order
,
675 map
< indicator_term
*, indicator_term
* > old2new
)
677 map
<indicator_term
*, vector
<indicator_term
* > >::const_iterator i
;
678 map
<indicator_term
*, int >::const_iterator j
;
680 for (j
= order
.pred
.begin(); j
!= order
.pred
.end(); ++j
)
681 pred
[old2new
[(*j
).first
]] = (*j
).second
;
683 for (i
= order
.lt
.begin(); i
!= order
.lt
.end(); ++i
) {
684 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
685 lt
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
687 for (i
= order
.le
.begin(); i
!= order
.le
.end(); ++i
) {
688 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
689 le
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
691 for (i
= order
.eq
.begin(); i
!= order
.eq
.end(); ++i
) {
692 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
693 eq
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
695 for (i
= order
.pending
.begin(); i
!= order
.pending
.end(); ++i
) {
696 for (int j
= 0; j
< (*i
).second
.size(); ++j
)
697 pending
[old2new
[(*i
).first
]].push_back(old2new
[(*i
).second
[j
]]);
701 static void add_coeff(Value
*cons
, int len
, evalue
*coeff
, int pos
)
705 assert(value_notzero_p(coeff
->d
));
709 value_lcm(cons
[0], coeff
->d
, &tmp
);
710 value_division(tmp
, tmp
, cons
[0]);
711 Vector_Scale(cons
, cons
, tmp
, len
);
712 value_division(tmp
, cons
[0], coeff
->d
);
713 value_addmul(cons
[pos
], tmp
, coeff
->x
.n
);
718 static int evalue2constraint_r(EDomain
*D
, evalue
*E
, Value
*cons
, int len
);
720 static void add_fract(evalue
*e
, Value
*cons
, int len
, int pos
)
724 evalue_set_si(&mone
, -1, 1);
726 /* contribution of alpha * fract(X) is
729 assert(e
->x
.p
->size
== 3);
731 value_init(argument
.d
);
732 evalue_copy(&argument
, &e
->x
.p
->arr
[0]);
733 emul(&e
->x
.p
->arr
[2], &argument
);
734 evalue2constraint_r(NULL
, &argument
, cons
, len
);
735 free_evalue_refs(&argument
);
737 /* - alpha * floor(X) */
738 emul(&mone
, &e
->x
.p
->arr
[2]);
739 add_coeff(cons
, len
, &e
->x
.p
->arr
[2], pos
);
740 emul(&mone
, &e
->x
.p
->arr
[2]);
742 free_evalue_refs(&mone
);
745 static int evalue2constraint_r(EDomain
*D
, evalue
*E
, Value
*cons
, int len
)
748 if (value_zero_p(E
->d
) && E
->x
.p
->type
== fractional
) {
750 assert(E
->x
.p
->size
== 3);
751 r
= evalue2constraint_r(D
, &E
->x
.p
->arr
[1], cons
, len
);
752 assert(value_notzero_p(E
->x
.p
->arr
[2].d
));
753 if (D
&& (i
= D
->find_floor(&E
->x
.p
->arr
[0])) >= 0) {
754 add_fract(E
, cons
, len
, 1+D
->D
->Dimension
-D
->floors
.size()+i
);
756 if (value_pos_p(E
->x
.p
->arr
[2].x
.n
)) {
759 value_init(coeff
.x
.n
);
760 value_set_si(coeff
.d
, 1);
761 evalue_denom(&E
->x
.p
->arr
[0], &coeff
.d
);
762 value_decrement(coeff
.x
.n
, coeff
.d
);
763 emul(&E
->x
.p
->arr
[2], &coeff
);
764 add_coeff(cons
, len
, &coeff
, len
-1);
765 free_evalue_refs(&coeff
);
769 } else if (value_zero_p(E
->d
)) {
770 assert(E
->x
.p
->type
== polynomial
);
771 assert(E
->x
.p
->size
== 2);
772 r
= evalue2constraint_r(D
, &E
->x
.p
->arr
[0], cons
, len
) || r
;
773 add_coeff(cons
, len
, &E
->x
.p
->arr
[1], E
->x
.p
->pos
);
775 add_coeff(cons
, len
, E
, len
-1);
780 static int evalue2constraint(EDomain
*D
, evalue
*E
, Value
*cons
, int len
)
782 Vector_Set(cons
, 0, len
);
783 value_set_si(cons
[0], 1);
784 return evalue2constraint_r(D
, E
, cons
, len
);
787 static void interval_minmax(Polyhedron
*I
, int *min
, int *max
)
789 assert(I
->Dimension
== 1);
792 POL_ENSURE_VERTICES(I
);
793 for (int i
= 0; i
< I
->NbRays
; ++i
) {
794 if (value_pos_p(I
->Ray
[i
][1]))
796 else if (value_neg_p(I
->Ray
[i
][1]))
807 static void interval_minmax(Polyhedron
*D
, Matrix
*T
, int *min
, int *max
,
810 Polyhedron
*I
= Polyhedron_Image(D
, T
, MaxRays
);
811 if (MaxRays
& POL_INTEGER
)
812 I
= DomainConstraintSimplify(I
, MaxRays
);
815 I
= Polyhedron_Image(D
, T
, MaxRays
);
817 interval_minmax(I
, min
, max
);
824 vector
<evalue
*> max
;
826 void print(ostream
& os
, char **p
) const;
827 void resolve_existential_vars() const;
828 void substitute(Matrix
*T
, unsigned MaxRays
);
829 Vector
*eval(Value
*val
, unsigned MaxRays
) const;
832 for (int i
= 0; i
< max
.size(); ++i
) {
833 free_evalue_refs(max
[i
]);
836 Polyhedron_Free(domain
);
841 * Project on first dim dimensions
843 Polyhedron
* Polyhedron_Project_Initial(Polyhedron
*P
, int dim
)
849 if (P
->Dimension
== dim
)
850 return Polyhedron_Copy(P
);
852 T
= Matrix_Alloc(dim
+1, P
->Dimension
+1);
853 for (i
= 0; i
< dim
; ++i
)
854 value_set_si(T
->p
[i
][i
], 1);
855 value_set_si(T
->p
[dim
][P
->Dimension
], 1);
856 I
= Polyhedron_Image(P
, T
, P
->NbConstraints
);
862 vector
<indicator_term
*> term
;
863 indicator_constructor
& ic
;
868 barvinok_options
*options
;
870 indicator(indicator_constructor
& ic
, Param_Domain
*PD
, EDomain
*D
,
871 barvinok_options
*options
) :
872 ic(ic
), PD(PD
), D(D
), order(this), options(options
), P(NULL
) {}
873 indicator(const indicator
& ind
, EDomain
*D
) :
874 ic(ind
.ic
), PD(ind
.PD
), D(NULL
), order(this), options(ind
.options
),
875 P(Polyhedron_Copy(ind
.P
)) {
876 map
< indicator_term
*, indicator_term
* > old2new
;
877 for (int i
= 0; i
< ind
.term
.size(); ++i
) {
878 indicator_term
*it
= new indicator_term(*ind
.term
[i
]);
879 old2new
[ind
.term
[i
]] = it
;
882 order
.copy(ind
.order
, old2new
);
886 for (int i
= 0; i
< term
.size(); ++i
)
894 void set_domain(EDomain
*D
) {
898 int nparam
= ic
.P
->Dimension
- ic
.vertex
.length();
899 Polyhedron
*Q
= Polyhedron_Project_Initial(D
->D
, nparam
);
900 Q
= DomainConstraintSimplify(Q
, options
->MaxRays
);
901 if (!P
|| !PolyhedronIncludes(Q
, P
))
908 void add(const indicator_term
* it
);
909 void remove(indicator_term
* it
);
910 void remove_initial_rational_vertices();
911 void expand_rational_vertex(indicator_term
*initial
);
913 void print(ostream
& os
, char **p
);
915 void peel(int i
, int j
);
916 void combine(indicator_term
*a
, indicator_term
*b
);
917 void substitute(evalue
*equation
);
918 void reduce_in_domain(Polyhedron
*D
);
919 void handle_equal_numerators(indicator_term
*base
);
921 max_term
* create_max_term(indicator_term
*it
);
924 max_term
* indicator::create_max_term(indicator_term
*it
)
926 int dim
= it
->den
.NumCols();
927 int nparam
= ic
.P
->Dimension
- ic
.vertex
.length();
928 max_term
*maximum
= new max_term
;
929 maximum
->dim
= nparam
;
930 maximum
->domain
= Polyhedron_Copy(D
->D
);
931 for (int j
= 0; j
< dim
; ++j
) {
932 evalue
*E
= new evalue
;
934 evalue_copy(E
, it
->vertex
[j
]);
935 if (evalue_frac2floor_in_domain(E
, D
->D
))
937 maximum
->max
.push_back(E
);
942 static Matrix
*add_ge_constraint(EDomain
*ED
, evalue
*constraint
,
943 vector
<evalue
*>& new_floors
)
945 Polyhedron
*D
= ED
->D
;
948 evalue_set_si(&mone
, -1, 1);
950 for (evalue
*e
= constraint
; value_zero_p(e
->d
);
951 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)]) {
953 if (e
->x
.p
->type
!= fractional
)
955 for (i
= 0; i
< ED
->floors
.size(); ++i
)
956 if (eequal(&e
->x
.p
->arr
[0], ED
->floors
[i
]))
958 if (i
< ED
->floors
.size())
963 int rows
= D
->NbConstraints
+2*fract
+1;
964 int cols
= 2+D
->Dimension
+fract
;
965 Matrix
*M
= Matrix_Alloc(rows
, cols
);
966 for (int i
= 0; i
< D
->NbConstraints
; ++i
) {
967 Vector_Copy(D
->Constraint
[i
], M
->p
[i
], 1+D
->Dimension
);
968 value_assign(M
->p
[i
][1+D
->Dimension
+fract
],
969 D
->Constraint
[i
][1+D
->Dimension
]);
971 value_set_si(M
->p
[rows
-1][0], 1);
974 for (e
= constraint
; value_zero_p(e
->d
); e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)]) {
975 if (e
->x
.p
->type
== fractional
) {
978 i
= ED
->find_floor(&e
->x
.p
->arr
[0]);
980 pos
= D
->Dimension
-ED
->floors
.size()+i
;
982 pos
= D
->Dimension
+fract
;
984 add_fract(e
, M
->p
[rows
-1], cols
, 1+pos
);
986 if (pos
< D
->Dimension
)
989 /* constraints for the new floor */
990 int row
= D
->NbConstraints
+2*fract
;
991 value_set_si(M
->p
[row
][0], 1);
992 evalue2constraint_r(NULL
, &e
->x
.p
->arr
[0], M
->p
[row
], cols
);
993 value_oppose(M
->p
[row
][1+D
->Dimension
+fract
], M
->p
[row
][0]);
994 value_set_si(M
->p
[row
][0], 1);
996 Vector_Scale(M
->p
[row
]+1, M
->p
[row
+1]+1, mone
.x
.n
, cols
-1);
997 value_set_si(M
->p
[row
+1][0], 1);
998 value_addto(M
->p
[row
+1][cols
-1], M
->p
[row
+1][cols
-1],
999 M
->p
[row
+1][1+D
->Dimension
+fract
]);
1000 value_decrement(M
->p
[row
+1][cols
-1], M
->p
[row
+1][cols
-1]);
1002 evalue
*arg
= new evalue
;
1004 evalue_copy(arg
, &e
->x
.p
->arr
[0]);
1005 new_floors
.push_back(arg
);
1009 assert(e
->x
.p
->type
== polynomial
);
1010 assert(e
->x
.p
->size
== 2);
1011 add_coeff(M
->p
[rows
-1], cols
, &e
->x
.p
->arr
[1], e
->x
.p
->pos
);
1014 add_coeff(M
->p
[rows
-1], cols
, e
, cols
-1);
1015 value_set_si(M
->p
[rows
-1][0], 1);
1016 free_evalue_refs(&mone
);
1021 static evalue
*ediff(const evalue
*a
, const evalue
*b
)
1025 evalue_set_si(&mone
, -1, 1);
1026 evalue
*diff
= new evalue
;
1027 value_init(diff
->d
);
1028 evalue_copy(diff
, b
);
1031 reduce_evalue(diff
);
1032 free_evalue_refs(&mone
);
1036 static order_sign
evalue_sign(evalue
*diff
, EDomain
*D
, unsigned MaxRays
)
1038 order_sign sign
= order_eq
;
1041 evalue_set_si(&mone
, -1, 1);
1042 int len
= 1 + D
->D
->Dimension
+ 1;
1043 Vector
*c
= Vector_Alloc(len
);
1044 Matrix
*T
= Matrix_Alloc(2, len
-1);
1046 int fract
= evalue2constraint(D
, diff
, c
->p
, len
);
1047 Vector_Copy(c
->p
+1, T
->p
[0], len
-1);
1048 value_assign(T
->p
[1][len
-2], c
->p
[0]);
1051 interval_minmax(D
->D
, T
, &min
, &max
, MaxRays
);
1057 evalue2constraint(D
, diff
, c
->p
, len
);
1059 Vector_Copy(c
->p
+1, T
->p
[0], len
-1);
1060 value_assign(T
->p
[1][len
-2], c
->p
[0]);
1063 interval_minmax(D
->D
, T
, &negmin
, &negmax
, MaxRays
);
1068 else if (max
== 0 && min
== 0)
1070 else if (min
< 0 && max
> 0)
1071 sign
= order_unknown
;
1080 free_evalue_refs(&mone
);
1085 order_sign
partial_order::compare(indicator_term
*a
, indicator_term
*b
)
1087 unsigned dim
= a
->den
.NumCols();
1088 order_sign sign
= order_eq
;
1089 EDomain
*D
= ind
->D
;
1090 unsigned MaxRays
= ind
->options
->MaxRays
;
1091 if (MaxRays
& POL_INTEGER
&& (a
->sign
== 0 || b
->sign
== 0))
1094 for (int k
= 0; k
< dim
; ++k
) {
1095 /* compute a->vertex[k] - b->vertex[k] */
1096 evalue
*diff
= ediff(a
->vertex
[k
], b
->vertex
[k
]);
1097 order_sign diff_sign
= evalue_sign(diff
, D
, MaxRays
);
1099 if (diff_sign
== order_lt
) {
1100 if (sign
== order_eq
|| sign
== order_le
)
1103 sign
= order_unknown
;
1104 free_evalue_refs(diff
);
1108 if (diff_sign
== order_gt
) {
1109 if (sign
== order_eq
|| sign
== order_ge
)
1112 sign
= order_unknown
;
1113 free_evalue_refs(diff
);
1117 if (diff_sign
== order_eq
) {
1118 if (D
== ind
->D
&& !EVALUE_IS_ZERO(*diff
))
1119 ind
->substitute(diff
);
1120 free_evalue_refs(diff
);
1124 if ((diff_sign
== order_unknown
) ||
1125 ((diff_sign
== order_lt
|| diff_sign
== order_le
) && sign
== order_ge
) ||
1126 ((diff_sign
== order_gt
|| diff_sign
== order_ge
) && sign
== order_le
)) {
1127 free_evalue_refs(diff
);
1129 sign
= order_unknown
;
1136 vector
<evalue
*> new_floors
;
1137 M
= add_ge_constraint(D
, diff
, new_floors
);
1138 value_set_si(M
->p
[M
->NbRows
-1][0], 0);
1139 Polyhedron
*D2
= Constraints2Polyhedron(M
, MaxRays
);
1140 EDomain
*EDeq
= new EDomain(D2
, D
, new_floors
);
1141 Polyhedron_Free(D2
);
1143 for (int i
= 0; i
< new_floors
.size(); ++i
) {
1144 free_evalue_refs(new_floors
[i
]);
1145 delete new_floors
[i
];
1152 free_evalue_refs(diff
);
1162 bool partial_order::compared(indicator_term
* a
, indicator_term
* b
)
1164 map
<indicator_term
*, vector
<indicator_term
* > >::iterator j
;
1167 if (j
!= lt
.end() && find(lt
[a
].begin(), lt
[a
].end(), b
) != lt
[a
].end())
1171 if (j
!= le
.end() && find(le
[a
].begin(), le
[a
].end(), b
) != le
[a
].end())
1177 void partial_order::add(indicator_term
* it
, std::set
<indicator_term
*> *filter
)
1179 if (eq
.find(it
) != eq
.end() && eq
[it
].size() == 1)
1182 int it_pred
= filter
? pred
[it
] : 0;
1184 map
<indicator_term
*, int >::iterator i
;
1185 for (i
= pred
.begin(); i
!= pred
.end(); ++i
) {
1186 if ((*i
).second
!= 0)
1188 if (eq
.find((*i
).first
) != eq
.end() && eq
[(*i
).first
].size() == 1)
1191 if ((*i
).first
== it
)
1193 if (filter
->find((*i
).first
) == filter
->end())
1195 if (compared((*i
).first
, it
))
1198 order_sign sign
= compare(it
, (*i
).first
);
1199 if (sign
== order_lt
) {
1200 lt
[it
].push_back((*i
).first
);
1202 } else if (sign
== order_le
) {
1203 le
[it
].push_back((*i
).first
);
1205 } else if (sign
== order_eq
) {
1207 set_equal(it
, (*i
).first
);
1209 } else if (sign
== order_gt
) {
1210 pending
[(*i
).first
].push_back(it
);
1211 lt
[(*i
).first
].push_back(it
);
1213 } else if (sign
== order_ge
) {
1214 pending
[(*i
).first
].push_back(it
);
1215 le
[(*i
).first
].push_back(it
);
1222 void partial_order::remove(indicator_term
* it
)
1224 std::set
<indicator_term
*> filter
;
1225 map
<indicator_term
*, vector
<indicator_term
* > >::iterator i
;
1227 assert(pred
[it
] == 0);
1230 if (i
!= eq
.end()) {
1231 assert(eq
[it
].size() >= 1);
1232 indicator_term
*base
;
1233 if (eq
[it
].size() == 1) {
1237 vector
<indicator_term
* >::iterator j
;
1238 j
= find(eq
[base
].begin(), eq
[base
].end(), it
);
1239 assert(j
!= eq
[base
].end());
1242 /* "it" may no longer be the smallest, since the order
1243 * structure may have been copied from another one.
1245 sort(eq
[it
].begin()+1, eq
[it
].end());
1246 assert(eq
[it
][0] == it
);
1247 eq
[it
].erase(eq
[it
].begin());
1252 for (int j
= 1; j
< eq
[base
].size(); ++j
)
1253 eq
[eq
[base
][j
]][0] = base
;
1256 if (i
!= lt
.end()) {
1262 if (i
!= le
.end()) {
1267 i
= pending
.find(it
);
1268 if (i
!= pending
.end()) {
1269 pending
[base
] = pending
[it
];
1274 if (eq
[base
].size() == 1)
1277 map
<indicator_term
*, int >::iterator j
;
1285 if (i
!= lt
.end()) {
1286 for (int j
= 0; j
< lt
[it
].size(); ++j
) {
1287 filter
.insert(lt
[it
][j
]);
1294 if (i
!= le
.end()) {
1295 for (int j
= 0; j
< le
[it
].size(); ++j
) {
1296 filter
.insert(le
[it
][j
]);
1302 map
<indicator_term
*, int >::iterator j
;
1306 i
= pending
.find(it
);
1307 if (i
!= pending
.end()) {
1308 for (int j
= 0; j
< pending
[it
].size(); ++j
) {
1309 filter
.erase(pending
[it
][j
]);
1310 add(pending
[it
][j
], &filter
);
1316 void partial_order::print(ostream
& os
, char **p
)
1318 map
<indicator_term
*, vector
<indicator_term
* > >::iterator i
;
1319 for (i
= lt
.begin(); i
!= lt
.end(); ++i
) {
1320 (*i
).first
->print(os
, p
);
1321 assert(pred
.find((*i
).first
) != pred
.end());
1322 os
<< "(" << pred
[(*i
).first
] << ")";
1324 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1327 (*i
).second
[j
]->print(os
, p
);
1328 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1329 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1333 for (i
= le
.begin(); i
!= le
.end(); ++i
) {
1334 (*i
).first
->print(os
, p
);
1335 assert(pred
.find((*i
).first
) != pred
.end());
1336 os
<< "(" << pred
[(*i
).first
] << ")";
1338 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1341 (*i
).second
[j
]->print(os
, p
);
1342 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1343 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1347 for (i
= eq
.begin(); i
!= eq
.end(); ++i
) {
1348 if ((*i
).second
.size() <= 1)
1350 (*i
).first
->print(os
, p
);
1351 assert(pred
.find((*i
).first
) != pred
.end());
1352 os
<< "(" << pred
[(*i
).first
] << ")";
1353 for (int j
= 1; j
< (*i
).second
.size(); ++j
) {
1356 (*i
).second
[j
]->print(os
, p
);
1357 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1358 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1362 for (i
= pending
.begin(); i
!= pending
.end(); ++i
) {
1363 os
<< "pending on ";
1364 (*i
).first
->print(os
, p
);
1365 assert(pred
.find((*i
).first
) != pred
.end());
1366 os
<< "(" << pred
[(*i
).first
] << ")";
1368 for (int j
= 0; j
< (*i
).second
.size(); ++j
) {
1371 (*i
).second
[j
]->print(os
, p
);
1372 assert(pred
.find((*i
).second
[j
]) != pred
.end());
1373 os
<< "(" << pred
[(*i
).second
[j
]] << ")";
1379 void indicator::add(const indicator_term
* it
)
1381 indicator_term
*nt
= new indicator_term(*it
);
1382 nt
->reduce_in_domain(P
? P
: D
->D
);
1384 order
.add(nt
, NULL
);
1385 assert(term
.size() == order
.pred
.size());
1388 void indicator::remove(indicator_term
* it
)
1390 vector
<indicator_term
*>::iterator i
;
1391 i
= find(term
.begin(), term
.end(), it
);
1392 assert(i
!= term
.end());
1395 assert(term
.size() == order
.pred
.size());
1399 void indicator::expand_rational_vertex(indicator_term
*initial
)
1401 int pos
= initial
->pos
;
1403 if (ic
.terms
[pos
].size() == 0) {
1405 FORALL_PVertex_in_ParamPolyhedron(V
, PD
, ic
.PP
) // _i is internal counter
1407 ic
.decompose_at_vertex(V
, pos
, options
->MaxRays
);
1410 END_FORALL_PVertex_in_ParamPolyhedron
;
1412 for (int j
= 0; j
< ic
.terms
[pos
].size(); ++j
)
1413 add(ic
.terms
[pos
][j
]);
1416 void indicator::remove_initial_rational_vertices()
1419 indicator_term
*initial
= NULL
;
1420 map
<indicator_term
*, int >::iterator i
;
1421 for (i
= order
.pred
.begin(); i
!= order
.pred
.end(); ++i
) {
1422 if ((*i
).second
!= 0)
1424 if ((*i
).first
->sign
!= 0)
1426 if (order
.eq
.find((*i
).first
) != order
.eq
.end() &&
1427 order
.eq
[(*i
).first
].size() <= 1)
1429 initial
= (*i
).first
;
1434 expand_rational_vertex(initial
);
1438 void indicator::reduce_in_domain(Polyhedron
*D
)
1440 for (int i
= 0; i
< term
.size(); ++i
)
1441 term
[i
]->reduce_in_domain(D
);
1444 void indicator::print(ostream
& os
, char **p
)
1446 assert(term
.size() == order
.pred
.size());
1447 for (int i
= 0; i
< term
.size(); ++i
) {
1448 term
[i
]->print(os
, p
);
1454 /* Remove pairs of opposite terms */
1455 void indicator::simplify()
1457 for (int i
= 0; i
< term
.size(); ++i
) {
1458 for (int j
= i
+1; j
< term
.size(); ++j
) {
1459 if (term
[i
]->sign
+ term
[j
]->sign
!= 0)
1461 if (term
[i
]->den
!= term
[j
]->den
)
1464 for (k
= 0; k
< term
[i
]->den
.NumCols(); ++k
)
1465 if (!eequal(term
[i
]->vertex
[k
], term
[j
]->vertex
[k
]))
1467 if (k
< term
[i
]->den
.NumCols())
1471 term
.erase(term
.begin()+j
);
1472 term
.erase(term
.begin()+i
);
1479 void indicator::peel(int i
, int j
)
1487 int dim
= term
[i
]->den
.NumCols();
1492 int n_common
= 0, n_i
= 0, n_j
= 0;
1494 common
.SetDims(min(term
[i
]->den
.NumRows(), term
[j
]->den
.NumRows()), dim
);
1495 rest_i
.SetDims(term
[i
]->den
.NumRows(), dim
);
1496 rest_j
.SetDims(term
[j
]->den
.NumRows(), dim
);
1499 for (k
= 0, l
= 0; k
< term
[i
]->den
.NumRows() && l
< term
[j
]->den
.NumRows(); ) {
1500 int s
= lex_cmp(term
[i
]->den
[k
], term
[j
]->den
[l
]);
1502 common
[n_common
++] = term
[i
]->den
[k
];
1506 rest_i
[n_i
++] = term
[i
]->den
[k
++];
1508 rest_j
[n_j
++] = term
[j
]->den
[l
++];
1510 while (k
< term
[i
]->den
.NumRows())
1511 rest_i
[n_i
++] = term
[i
]->den
[k
++];
1512 while (l
< term
[j
]->den
.NumRows())
1513 rest_j
[n_j
++] = term
[j
]->den
[l
++];
1514 common
.SetDims(n_common
, dim
);
1515 rest_i
.SetDims(n_i
, dim
);
1516 rest_j
.SetDims(n_j
, dim
);
1518 for (k
= 0; k
<= n_i
; ++k
) {
1519 indicator_term
*it
= new indicator_term(*term
[i
]);
1520 it
->den
.SetDims(n_common
+ k
, dim
);
1521 for (l
= 0; l
< n_common
; ++l
)
1522 it
->den
[l
] = common
[l
];
1523 for (l
= 0; l
< k
; ++l
)
1524 it
->den
[n_common
+l
] = rest_i
[l
];
1525 lex_order_rows(it
->den
);
1527 for (l
= 0; l
< dim
; ++l
)
1528 evalue_add_constant(it
->vertex
[l
], rest_i
[k
-1][l
]);
1532 for (k
= 0; k
<= n_j
; ++k
) {
1533 indicator_term
*it
= new indicator_term(*term
[j
]);
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_j
[l
];
1539 lex_order_rows(it
->den
);
1541 for (l
= 0; l
< dim
; ++l
)
1542 evalue_add_constant(it
->vertex
[l
], rest_j
[k
-1][l
]);
1545 term
.erase(term
.begin()+j
);
1546 term
.erase(term
.begin()+i
);
1549 void indicator::combine(indicator_term
*a
, indicator_term
*b
)
1551 int dim
= a
->den
.NumCols();
1556 int n_common
= 0, n_i
= 0, n_j
= 0;
1558 common
.SetDims(min(a
->den
.NumRows(), b
->den
.NumRows()), dim
);
1559 rest_i
.SetDims(a
->den
.NumRows(), dim
);
1560 rest_j
.SetDims(b
->den
.NumRows(), dim
);
1563 for (k
= 0, l
= 0; k
< a
->den
.NumRows() && l
< b
->den
.NumRows(); ) {
1564 int s
= lex_cmp(a
->den
[k
], b
->den
[l
]);
1566 common
[n_common
++] = a
->den
[k
];
1570 rest_i
[n_i
++] = a
->den
[k
++];
1572 rest_j
[n_j
++] = b
->den
[l
++];
1574 while (k
< a
->den
.NumRows())
1575 rest_i
[n_i
++] = a
->den
[k
++];
1576 while (l
< b
->den
.NumRows())
1577 rest_j
[n_j
++] = b
->den
[l
++];
1578 common
.SetDims(n_common
, dim
);
1579 rest_i
.SetDims(n_i
, dim
);
1580 rest_j
.SetDims(n_j
, dim
);
1585 for (k
= (1 << n_i
)-1; k
>= 0; --k
) {
1586 indicator_term
*it
= k
? new indicator_term(*b
) : b
;
1587 it
->den
.SetDims(n_common
+ n_i
+ n_j
, dim
);
1588 for (l
= 0; l
< n_common
; ++l
)
1589 it
->den
[l
] = common
[l
];
1590 for (l
= 0; l
< n_i
; ++l
)
1591 it
->den
[n_common
+l
] = rest_i
[l
];
1592 for (l
= 0; l
< n_j
; ++l
)
1593 it
->den
[n_common
+n_i
+l
] = rest_j
[l
];
1594 lex_order_rows(it
->den
);
1596 for (l
= 0; l
< n_i
; ++l
) {
1600 for (int m
= 0; m
< dim
; ++m
)
1601 evalue_add_constant(it
->vertex
[m
], rest_i
[l
][m
]);
1604 it
->sign
= -it
->sign
;
1607 order
.add(it
, NULL
);
1611 for (k
= (1 << n_j
)-1; k
>= 0; --k
) {
1612 indicator_term
*it
= k
? new indicator_term(*a
) : a
;
1613 it
->den
.SetDims(n_common
+ n_i
+ n_j
, dim
);
1614 for (l
= 0; l
< n_common
; ++l
)
1615 it
->den
[l
] = common
[l
];
1616 for (l
= 0; l
< n_i
; ++l
)
1617 it
->den
[n_common
+l
] = rest_i
[l
];
1618 for (l
= 0; l
< n_j
; ++l
)
1619 it
->den
[n_common
+n_i
+l
] = rest_j
[l
];
1620 lex_order_rows(it
->den
);
1622 for (l
= 0; l
< n_j
; ++l
) {
1626 for (int m
= 0; m
< dim
; ++m
)
1627 evalue_add_constant(it
->vertex
[m
], rest_j
[l
][m
]);
1630 it
->sign
= -it
->sign
;
1633 order
.add(it
, NULL
);
1638 void indicator::handle_equal_numerators(indicator_term
*base
)
1640 for (int i
= 0; i
< order
.eq
[base
].size(); ++i
) {
1641 for (int j
= i
+1; j
< order
.eq
[base
].size(); ++j
) {
1642 if (order
.eq
[base
][i
]->is_opposite(order
.eq
[base
][j
])) {
1643 remove(order
.eq
[base
][j
]);
1644 remove(i
? order
.eq
[base
][i
] : base
);
1649 for (int j
= 1; j
< order
.eq
[base
].size(); ++j
)
1650 if (order
.eq
[base
][j
]->sign
!= base
->sign
) {
1651 combine(base
, order
.eq
[base
][j
]);
1657 void indicator::substitute(evalue
*equation
)
1659 evalue
*fract
= NULL
;
1660 evalue
*val
= new evalue
;
1662 evalue_copy(val
, equation
);
1665 value_init(factor
.d
);
1666 value_init(factor
.x
.n
);
1669 for (e
= val
; value_zero_p(e
->d
) && e
->x
.p
->type
!= fractional
;
1670 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)])
1673 if (value_zero_p(e
->d
) && e
->x
.p
->type
== fractional
)
1674 fract
= &e
->x
.p
->arr
[0];
1676 for (e
= val
; value_zero_p(e
->d
) && e
->x
.p
->type
!= polynomial
;
1677 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)])
1679 assert(value_zero_p(e
->d
) && e
->x
.p
->type
== polynomial
);
1682 int offset
= type_offset(e
->x
.p
);
1684 assert(value_notzero_p(e
->x
.p
->arr
[offset
+1].d
));
1685 assert(value_notzero_p(e
->x
.p
->arr
[offset
+1].x
.n
));
1686 if (value_neg_p(e
->x
.p
->arr
[offset
+1].x
.n
)) {
1687 value_oppose(factor
.d
, e
->x
.p
->arr
[offset
+1].x
.n
);
1688 value_assign(factor
.x
.n
, e
->x
.p
->arr
[offset
+1].d
);
1690 value_assign(factor
.d
, e
->x
.p
->arr
[offset
+1].x
.n
);
1691 value_oppose(factor
.x
.n
, e
->x
.p
->arr
[offset
+1].d
);
1694 free_evalue_refs(&e
->x
.p
->arr
[offset
+1]);
1697 *e
= e
->x
.p
->arr
[offset
];
1702 for (int i
= 0; i
< term
.size(); ++i
)
1703 term
[i
]->substitute(fract
, val
);
1705 free_evalue_refs(&p
->arr
[0]);
1707 for (int i
= 0; i
< term
.size(); ++i
)
1708 term
[i
]->substitute(p
->pos
, val
);
1711 free_evalue_refs(&factor
);
1712 free_evalue_refs(val
);
1718 static void print_varlist(ostream
& os
, int n
, char **names
)
1722 for (i
= 0; i
< n
; ++i
) {
1730 static void print_term(ostream
& os
, Value v
, int pos
, int dim
,
1731 char **names
, int *first
)
1733 if (value_zero_p(v
)) {
1734 if (first
&& *first
&& pos
>= dim
)
1740 if (!*first
&& value_pos_p(v
))
1745 if (value_mone_p(v
)) {
1747 } else if (!value_one_p(v
))
1748 os
<< VALUE_TO_INT(v
);
1751 os
<< VALUE_TO_INT(v
);
1754 /* We put all possible existentially quantified variables at the back
1755 * and so if any equalities exist between these variables and the
1756 * other variables, then PolyLib will replace all occurrences of some
1757 * of the other variables by some existentially quantified variables.
1758 * We want the output to have as few as possible references to the
1759 * existentially quantified variables, so we undo what PolyLib did here.
1761 void resolve_existential_vars(Polyhedron
*domain
, unsigned dim
)
1763 int last
= domain
->NbEq
- 1;
1764 /* Matrix "view" of domain for ExchangeRows */
1766 M
.NbRows
= domain
->NbConstraints
;
1767 M
.NbColumns
= domain
->Dimension
+2;
1768 M
.p_Init
= domain
->p_Init
;
1769 M
.p
= domain
->Constraint
;
1772 value_set_si(mone
, -1);
1773 for (int e
= domain
->Dimension
-1; e
>= dim
; --e
) {
1775 for (r
= last
; r
>= 0; --r
)
1776 if (value_notzero_p(domain
->Constraint
[r
][1+e
]))
1781 ExchangeRows(&M
, r
, last
);
1783 /* Combine uses the coefficient as a multiplier, so it must
1784 * be positive, since we are modifying an inequality.
1786 if (value_neg_p(domain
->Constraint
[last
][1+e
]))
1787 Vector_Scale(domain
->Constraint
[last
]+1, domain
->Constraint
[last
]+1,
1788 mone
, domain
->Dimension
+1);
1790 for (int c
= 0; c
< domain
->NbConstraints
; ++c
) {
1793 if (value_notzero_p(domain
->Constraint
[c
][1+e
]))
1794 Combine(domain
->Constraint
[c
], domain
->Constraint
[last
],
1795 domain
->Constraint
[c
], 1+e
, domain
->Dimension
+1);
1802 void max_term::resolve_existential_vars() const
1804 ::resolve_existential_vars(domain
, dim
);
1807 void max_term::print(ostream
& os
, char **p
) const
1810 if (dim
< domain
->Dimension
) {
1811 resolve_existential_vars();
1812 names
= new char * [domain
->Dimension
];
1814 for (i
= 0; i
< dim
; ++i
)
1816 for ( ; i
< domain
->Dimension
; ++i
) {
1817 names
[i
] = new char[10];
1818 snprintf(names
[i
], 10, "a%d", i
- dim
);
1825 print_varlist(os
, dim
, p
);
1828 for (int i
= 0; i
< max
.size(); ++i
) {
1831 evalue_print(os
, max
[i
], p
);
1835 if (dim
< domain
->Dimension
) {
1837 print_varlist(os
, domain
->Dimension
-dim
, names
+dim
);
1840 for (int i
= 0; i
< domain
->NbConstraints
; ++i
) {
1842 int v
= First_Non_Zero(domain
->Constraint
[i
]+1, domain
->Dimension
);
1847 if (value_pos_p(domain
->Constraint
[i
][v
+1])) {
1848 print_term(os
, domain
->Constraint
[i
][v
+1], v
, domain
->Dimension
,
1850 if (value_zero_p(domain
->Constraint
[i
][0]))
1854 for (int j
= v
+1; j
<= domain
->Dimension
; ++j
) {
1855 value_oppose(tmp
, domain
->Constraint
[i
][1+j
]);
1856 print_term(os
, tmp
, j
, domain
->Dimension
,
1860 value_oppose(tmp
, domain
->Constraint
[i
][1+v
]);
1861 print_term(os
, tmp
, v
, domain
->Dimension
,
1863 if (value_zero_p(domain
->Constraint
[i
][0]))
1867 for (int j
= v
+1; j
<= domain
->Dimension
; ++j
)
1868 print_term(os
, domain
->Constraint
[i
][1+j
], j
, domain
->Dimension
,
1875 if (dim
< domain
->Dimension
) {
1876 for (int i
= dim
; i
< domain
->Dimension
; ++i
)
1882 static void evalue_substitute(evalue
*e
, evalue
**subs
)
1886 if (value_notzero_p(e
->d
))
1890 for (int i
= 0; i
< p
->size
; ++i
)
1891 evalue_substitute(&p
->arr
[i
], subs
);
1893 if (p
->type
== polynomial
)
1898 value_set_si(v
->d
, 0);
1899 v
->x
.p
= new_enode(p
->type
, 3, -1);
1900 value_clear(v
->x
.p
->arr
[0].d
);
1901 v
->x
.p
->arr
[0] = p
->arr
[0];
1902 evalue_set_si(&v
->x
.p
->arr
[1], 0, 1);
1903 evalue_set_si(&v
->x
.p
->arr
[2], 1, 1);
1906 int offset
= type_offset(p
);
1908 for (int i
= p
->size
-1; i
>= offset
+1; i
--) {
1909 emul(v
, &p
->arr
[i
]);
1910 eadd(&p
->arr
[i
], &p
->arr
[i
-1]);
1911 free_evalue_refs(&(p
->arr
[i
]));
1914 if (p
->type
!= polynomial
) {
1915 free_evalue_refs(v
);
1920 *e
= p
->arr
[offset
];
1924 /* "align" matrix to have nrows by inserting
1925 * the necessary number of rows and an equal number of columns at the end
1926 * right before the constant row/column
1928 static Matrix
*align_matrix_initial(Matrix
*M
, int nrows
)
1931 int newrows
= nrows
- M
->NbRows
;
1932 Matrix
*M2
= Matrix_Alloc(nrows
, newrows
+ M
->NbColumns
);
1933 for (i
= 0; i
< newrows
; ++i
)
1934 value_set_si(M2
->p
[M
->NbRows
-1+i
][M
->NbColumns
-1+i
], 1);
1935 for (i
= 0; i
< M
->NbRows
-1; ++i
) {
1936 Vector_Copy(M
->p
[i
], M2
->p
[i
], M
->NbColumns
-1);
1937 value_assign(M2
->p
[i
][M2
->NbColumns
-1], M
->p
[i
][M
->NbColumns
-1]);
1939 value_assign(M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1],
1940 M
->p
[M
->NbRows
-1][M
->NbColumns
-1]);
1944 /* T maps the compressed parameters to the original parameters,
1945 * while this max_term is based on the compressed parameters
1946 * and we want get the original parameters back.
1948 void max_term::substitute(Matrix
*T
, unsigned MaxRays
)
1950 int nexist
= domain
->Dimension
- (T
->NbColumns
-1);
1951 Matrix
*M
= align_matrix_initial(T
, T
->NbRows
+nexist
);
1953 Polyhedron
*D
= DomainImage(domain
, M
, MaxRays
);
1954 Polyhedron_Free(domain
);
1958 assert(T
->NbRows
== T
->NbColumns
);
1959 Matrix
*T2
= Matrix_Copy(T
);
1960 Matrix
*inv
= Matrix_Alloc(T
->NbColumns
, T
->NbRows
);
1961 int ok
= Matrix_Inverse(T2
, inv
);
1966 value_init(denom
.d
);
1967 value_init(denom
.x
.n
);
1968 value_set_si(denom
.x
.n
, 1);
1969 value_assign(denom
.d
, inv
->p
[inv
->NbRows
-1][inv
->NbColumns
-1]);
1972 v
.SetLength(inv
->NbColumns
);
1973 evalue
* subs
[inv
->NbRows
-1];
1974 for (int i
= 0; i
< inv
->NbRows
-1; ++i
) {
1975 values2zz(inv
->p
[i
], v
, v
.length());
1976 subs
[i
] = multi_monom(v
);
1977 emul(&denom
, subs
[i
]);
1979 free_evalue_refs(&denom
);
1981 for (int i
= 0; i
< max
.size(); ++i
) {
1982 evalue_substitute(max
[i
], subs
);
1983 reduce_evalue(max
[i
]);
1986 for (int i
= 0; i
< inv
->NbRows
-1; ++i
) {
1987 free_evalue_refs(subs
[i
]);
1993 int Last_Non_Zero(Value
*p
, unsigned len
)
1995 for (int i
= len
-1; i
>= 0; --i
)
1996 if (value_notzero_p(p
[i
]))
2001 static void SwapColumns(Value
**V
, int n
, int i
, int j
)
2003 for (int r
= 0; r
< n
; ++r
)
2004 value_swap(V
[r
][i
], V
[r
][j
]);
2007 static void SwapColumns(Polyhedron
*P
, int i
, int j
)
2009 SwapColumns(P
->Constraint
, P
->NbConstraints
, i
, j
);
2010 SwapColumns(P
->Ray
, P
->NbRays
, i
, j
);
2013 bool in_domain(Polyhedron
*P
, Value
*val
, unsigned dim
, unsigned MaxRays
)
2015 int nexist
= P
->Dimension
- dim
;
2016 int last
[P
->NbConstraints
];
2017 Value tmp
, min
, max
;
2018 Vector
*all_val
= Vector_Alloc(P
->Dimension
+1);
2023 resolve_existential_vars(P
, dim
);
2025 Vector_Copy(val
, all_val
->p
, dim
);
2026 value_set_si(all_val
->p
[P
->Dimension
], 1);
2029 for (int i
= 0; i
< P
->NbConstraints
; ++i
) {
2030 last
[i
] = Last_Non_Zero(P
->Constraint
[i
]+1+dim
, nexist
);
2031 if (last
[i
] == -1) {
2032 Inner_Product(P
->Constraint
[i
]+1, all_val
->p
, P
->Dimension
+1, &tmp
);
2033 if (value_neg_p(tmp
))
2035 if (i
< P
->NbEq
&& value_pos_p(tmp
))
2042 alternate
= nexist
- 1;
2043 for (i
= 0; i
< nexist
; ++i
) {
2044 bool min_set
= false;
2045 bool max_set
= false;
2046 for (int j
= 0; j
< P
->NbConstraints
; ++j
) {
2049 Inner_Product(P
->Constraint
[j
]+1, all_val
->p
, P
->Dimension
+1, &tmp
);
2050 value_oppose(tmp
, tmp
);
2052 if (!mpz_divisible_p(tmp
, P
->Constraint
[j
][1+dim
+i
]))
2054 value_division(tmp
, tmp
, P
->Constraint
[j
][1+dim
+i
]);
2055 if (!max_set
|| value_lt(tmp
, max
)) {
2057 value_assign(max
, tmp
);
2059 if (!min_set
|| value_gt(tmp
, min
)) {
2061 value_assign(min
, tmp
);
2064 if (value_pos_p(P
->Constraint
[j
][1+dim
+i
])) {
2065 mpz_cdiv_q(tmp
, tmp
, P
->Constraint
[j
][1+dim
+i
]);
2066 if (!min_set
|| value_gt(tmp
, min
)) {
2068 value_assign(min
, tmp
);
2071 mpz_fdiv_q(tmp
, tmp
, P
->Constraint
[j
][1+dim
+i
]);
2072 if (!max_set
|| value_lt(tmp
, max
)) {
2074 value_assign(max
, tmp
);
2079 /* Move another existential variable in current position */
2080 if (!max_set
|| !min_set
) {
2081 if (!(alternate
> i
)) {
2082 Matrix
*M
= Matrix_Alloc(dim
+i
, 1+P
->Dimension
+1);
2083 for (int j
= 0; j
< dim
+i
; ++j
) {
2084 value_set_si(M
->p
[j
][1+j
], -1);
2085 value_assign(M
->p
[j
][1+P
->Dimension
], all_val
->p
[j
]);
2087 Polyhedron
*Q
= AddConstraints(M
->p
[0], dim
+i
, P
, MaxRays
);
2089 Q
= DomainConstraintSimplify(Q
, MaxRays
);
2090 Vector
*sample
= Polyhedron_Sample(Q
, MaxRays
);
2093 Vector_Free(sample
);
2097 assert(alternate
> i
);
2098 SwapColumns(P
, 1+dim
+i
, 1+dim
+alternate
);
2099 resolve_existential_vars(P
, dim
);
2100 for (int j
= 0; j
< P
->NbConstraints
; ++j
) {
2101 if (j
>= P
->NbEq
&& last
[j
] < i
)
2103 last
[j
] = Last_Non_Zero(P
->Constraint
[j
]+1+dim
, nexist
);
2105 Inner_Product(P
->Constraint
[j
]+1, all_val
->p
, P
->Dimension
+1,
2107 if (value_neg_p(tmp
))
2109 if (j
< P
->NbEq
&& value_pos_p(tmp
))
2117 assert(max_set
&& min_set
);
2118 if (value_lt(max
, min
))
2120 if (value_ne(max
, min
)) {
2121 Matrix
*M
= Matrix_Alloc(dim
+i
, 1+P
->Dimension
+1);
2122 for (int j
= 0; j
< dim
+i
; ++j
) {
2123 value_set_si(M
->p
[j
][1+j
], -1);
2124 value_assign(M
->p
[j
][1+P
->Dimension
], all_val
->p
[j
]);
2126 Polyhedron
*Q
= AddConstraints(M
->p
[0], dim
+i
, P
, MaxRays
);
2128 Q
= DomainConstraintSimplify(Q
, MaxRays
);
2129 Vector
*sample
= Polyhedron_Sample(Q
, MaxRays
);
2132 Vector_Free(sample
);
2136 assert(value_eq(max
, min
));
2137 value_assign(all_val
->p
[dim
+i
], max
);
2138 alternate
= nexist
- 1;
2145 Vector_Free(all_val
);
2147 return in
|| (P
->next
&& in_domain(P
->next
, val
, dim
, MaxRays
));
2150 void compute_evalue(evalue
*e
, Value
*val
, Value
*res
)
2152 double d
= compute_evalue(e
, val
);
2157 value_set_double(*res
, d
);
2160 Vector
*max_term::eval(Value
*val
, unsigned MaxRays
) const
2162 if (dim
== domain
->Dimension
) {
2163 if (!in_domain(domain
, val
))
2166 if (!in_domain(domain
, val
, dim
, MaxRays
))
2169 Vector
*res
= Vector_Alloc(max
.size());
2170 for (int i
= 0; i
< max
.size(); ++i
) {
2171 compute_evalue(max
[i
], val
, &res
->p
[i
]);
2176 static Matrix
*remove_equalities(Polyhedron
**P
, unsigned nparam
, unsigned MaxRays
);
2178 Vector
*Polyhedron_not_empty(Polyhedron
*P
, unsigned MaxRays
)
2180 Polyhedron
*Porig
= P
;
2181 Vector
*sample
= NULL
;
2183 POL_ENSURE_VERTICES(P
);
2187 for (int i
= 0; i
< P
->NbRays
; ++i
)
2188 if (value_one_p(P
->Ray
[i
][1+P
->Dimension
])) {
2189 sample
= Vector_Alloc(P
->Dimension
+ 1);
2190 Vector_Copy(P
->Ray
[i
]+1, sample
->p
, P
->Dimension
+1);
2194 Matrix
*T
= remove_equalities(&P
, 0, MaxRays
);
2196 sample
= Polyhedron_Sample(P
, MaxRays
);
2199 Vector
*P_sample
= Vector_Alloc(Porig
->Dimension
+ 1);
2200 Matrix_Vector_Product(T
, sample
->p
, P_sample
->p
);
2201 Vector_Free(sample
);
2215 enum sign
{ le
, ge
, lge
} sign
;
2217 split (evalue
*c
, enum sign s
) : constraint(c
), sign(s
) {}
2220 static void split_on(const split
& sp
, EDomain
*D
,
2221 EDomain
**Dlt
, EDomain
**Deq
, EDomain
**Dgt
,
2225 EDomain
*EDlt
= NULL
, *EDeq
= NULL
, *EDgt
= NULL
;
2229 value_set_si(mone
, -1);
2233 vector
<evalue
*> new_floors
;
2234 M
= add_ge_constraint(D
, sp
.constraint
, new_floors
);
2235 if (sp
.sign
== split::lge
|| sp
.sign
== split::ge
) {
2236 M2
= Matrix_Copy(M
);
2237 value_decrement(M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1],
2238 M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1]);
2239 D2
= Constraints2Polyhedron(M2
, MaxRays
);
2240 EDgt
= new EDomain(D2
, D
, new_floors
);
2241 Polyhedron_Free(D2
);
2244 if (sp
.sign
== split::lge
|| sp
.sign
== split::le
) {
2245 M2
= Matrix_Copy(M
);
2246 Vector_Scale(M2
->p
[M2
->NbRows
-1]+1, M2
->p
[M2
->NbRows
-1]+1,
2247 mone
, M2
->NbColumns
-1);
2248 value_decrement(M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1],
2249 M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1]);
2250 D2
= Constraints2Polyhedron(M2
, MaxRays
);
2251 EDlt
= new EDomain(D2
, D
, new_floors
);
2252 Polyhedron_Free(D2
);
2256 assert(sp
.sign
== split::lge
|| sp
.sign
== split::ge
|| sp
.sign
== split::le
);
2257 value_set_si(M
->p
[M
->NbRows
-1][0], 0);
2258 D2
= Constraints2Polyhedron(M
, MaxRays
);
2259 EDeq
= new EDomain(D2
, D
, new_floors
);
2260 Polyhedron_Free(D2
);
2263 Vector
*sample
= D
->sample
;
2264 if (sample
&& new_floors
.size() > 0) {
2265 assert(sample
->Size
== D
->D
->Dimension
+1);
2266 sample
= Vector_Alloc(D
->D
->Dimension
+new_floors
.size()+1);
2267 Vector_Copy(D
->sample
->p
, sample
->p
, D
->D
->Dimension
);
2268 value_set_si(sample
->p
[D
->D
->Dimension
+new_floors
.size()], 1);
2269 for (int i
= 0; i
< new_floors
.size(); ++i
)
2270 compute_evalue(new_floors
[i
], sample
->p
, sample
->p
+D
->D
->Dimension
+i
);
2273 for (int i
= 0; i
< new_floors
.size(); ++i
) {
2274 free_evalue_refs(new_floors
[i
]);
2275 delete new_floors
[i
];
2279 if (sample
&& in_domain(EDeq
->D
, sample
->p
, sample
->Size
-1, MaxRays
)) {
2280 EDeq
->sample
= Vector_Alloc(sample
->Size
);
2281 Vector_Copy(sample
->p
, EDeq
->sample
->p
, sample
->Size
);
2282 } else if (!(EDeq
->sample
= Polyhedron_not_empty(EDeq
->D
, MaxRays
))) {
2288 if (sample
&& in_domain(EDgt
->D
, sample
->p
, sample
->Size
-1, MaxRays
)) {
2289 EDgt
->sample
= Vector_Alloc(sample
->Size
);
2290 Vector_Copy(sample
->p
, EDgt
->sample
->p
, sample
->Size
);
2291 } else if (!(EDgt
->sample
= Polyhedron_not_empty(EDgt
->D
, MaxRays
))) {
2297 if (sample
&& in_domain(EDlt
->D
, sample
->p
, sample
->Size
-1, MaxRays
)) {
2298 EDlt
->sample
= Vector_Alloc(sample
->Size
);
2299 Vector_Copy(sample
->p
, EDlt
->sample
->p
, sample
->Size
);
2300 } else if (!(EDlt
->sample
= Polyhedron_not_empty(EDlt
->D
, MaxRays
))) {
2309 if (sample
!= D
->sample
)
2310 Vector_Free(sample
);
2313 ostream
& operator<< (ostream
& os
, const vector
<int> & v
)
2316 for (int i
= 0; i
< v
.size(); ++i
) {
2325 static bool isTranslation(Matrix
*M
)
2328 if (M
->NbRows
!= M
->NbColumns
)
2331 for (i
= 0;i
< M
->NbRows
; i
++)
2332 for (j
= 0; j
< M
->NbColumns
-1; j
++)
2334 if(value_notone_p(M
->p
[i
][j
]))
2337 if(value_notzero_p(M
->p
[i
][j
]))
2340 return value_one_p(M
->p
[M
->NbRows
-1][M
->NbColumns
-1]);
2343 static Matrix
*compress_parameters(Polyhedron
**P
, Polyhedron
**C
,
2344 unsigned nparam
, unsigned MaxRays
)
2348 /* compress_parms doesn't like equalities that only involve parameters */
2349 for (int i
= 0; i
< (*P
)->NbEq
; ++i
)
2350 assert(First_Non_Zero((*P
)->Constraint
[i
]+1, (*P
)->Dimension
-nparam
) != -1);
2352 M
= Matrix_Alloc((*P
)->NbEq
, (*P
)->Dimension
+2);
2353 Vector_Copy((*P
)->Constraint
[0], M
->p
[0], (*P
)->NbEq
* ((*P
)->Dimension
+2));
2354 CP
= compress_parms(M
, nparam
);
2357 if (isTranslation(CP
)) {
2362 T
= align_matrix(CP
, (*P
)->Dimension
+1);
2363 *P
= Polyhedron_Preimage(*P
, T
, MaxRays
);
2366 *C
= Polyhedron_Preimage(*C
, CP
, MaxRays
);
2371 static Matrix
*remove_equalities(Polyhedron
**P
, unsigned nparam
, unsigned MaxRays
)
2373 /* Matrix "view" of equalities */
2375 M
.NbRows
= (*P
)->NbEq
;
2376 M
.NbColumns
= (*P
)->Dimension
+2;
2377 M
.p_Init
= (*P
)->p_Init
;
2378 M
.p
= (*P
)->Constraint
;
2380 Matrix
*T
= compress_variables(&M
, nparam
);
2386 if (isIdentity(T
)) {
2390 *P
= Polyhedron_Preimage(*P
, T
, MaxRays
);
2395 void construct_rational_vertices(Param_Polyhedron
*PP
, Matrix
*T
, unsigned dim
,
2396 int nparam
, vector
<indicator_term
*>& vertices
)
2405 v
.SetLength(nparam
+1);
2408 value_init(factor
.d
);
2409 value_init(factor
.x
.n
);
2410 value_set_si(factor
.x
.n
, 1);
2411 value_set_si(factor
.d
, 1);
2413 for (i
= 0, PV
= PP
->V
; PV
; ++i
, PV
= PV
->next
) {
2414 indicator_term
*term
= new indicator_term(dim
, i
);
2415 vertices
.push_back(term
);
2416 Matrix
*M
= Matrix_Alloc(PV
->Vertex
->NbRows
+nparam
+1, nparam
+1);
2417 value_set_si(lcm
, 1);
2418 for (int j
= 0; j
< PV
->Vertex
->NbRows
; ++j
)
2419 value_lcm(lcm
, PV
->Vertex
->p
[j
][nparam
+1], &lcm
);
2420 value_assign(M
->p
[M
->NbRows
-1][M
->NbColumns
-1], lcm
);
2421 for (int j
= 0; j
< PV
->Vertex
->NbRows
; ++j
) {
2422 value_division(tmp
, lcm
, PV
->Vertex
->p
[j
][nparam
+1]);
2423 Vector_Scale(PV
->Vertex
->p
[j
], M
->p
[j
], tmp
, nparam
+1);
2425 for (int j
= 0; j
< nparam
; ++j
)
2426 value_assign(M
->p
[PV
->Vertex
->NbRows
+j
][j
], lcm
);
2428 Matrix
*M2
= Matrix_Alloc(T
->NbRows
, M
->NbColumns
);
2429 Matrix_Product(T
, M
, M2
);
2433 for (int j
= 0; j
< dim
; ++j
) {
2434 values2zz(M
->p
[j
], v
, nparam
+1);
2435 term
->vertex
[j
] = multi_monom(v
);
2436 value_assign(factor
.d
, lcm
);
2437 emul(&factor
, term
->vertex
[j
]);
2441 assert(i
== PP
->nbV
);
2442 free_evalue_refs(&factor
);
2447 /* An auxiliary class that keeps a reference to an evalue
2448 * and frees it when it goes out of scope.
2450 struct temp_evalue
{
2452 temp_evalue() : E(NULL
) {}
2453 temp_evalue(evalue
*e
) : E(e
) {}
2454 operator evalue
* () const { return E
; }
2455 evalue
*operator=(evalue
*e
) {
2457 free_evalue_refs(E
);
2465 free_evalue_refs(E
);
2471 static vector
<max_term
*> lexmin(indicator
& ind
, unsigned nparam
,
2474 vector
<max_term
*> maxima
;
2475 map
<indicator_term
*, int >::iterator i
;
2476 vector
<int> best_score
;
2477 vector
<int> second_score
;
2478 vector
<int> neg_score
;
2481 indicator_term
*best
= NULL
, *second
= NULL
, *neg
= NULL
,
2482 *neg_eq
= NULL
, *neg_le
= NULL
;
2483 for (i
= ind
.order
.pred
.begin(); i
!= ind
.order
.pred
.end(); ++i
) {
2485 if ((*i
).second
!= 0)
2487 indicator_term
*term
= (*i
).first
;
2488 if (term
->sign
== 0) {
2489 ind
.expand_rational_vertex(term
);
2493 if (ind
.order
.eq
.find(term
) != ind
.order
.eq
.end()) {
2495 if (ind
.order
.eq
[term
].size() <= 1)
2497 for (j
= 1; j
< ind
.order
.eq
[term
].size(); ++j
)
2498 if (ind
.order
.pred
[ind
.order
.eq
[term
][j
]] != 0)
2500 if (j
< ind
.order
.eq
[term
].size())
2502 score
.push_back(ind
.order
.eq
[term
].size());
2505 if (ind
.order
.le
.find(term
) != ind
.order
.le
.end())
2506 score
.push_back(ind
.order
.le
[term
].size());
2509 if (ind
.order
.lt
.find(term
) != ind
.order
.lt
.end())
2510 score
.push_back(-ind
.order
.lt
[term
].size());
2514 if (term
->sign
> 0) {
2515 if (!best
|| score
< best_score
) {
2517 second_score
= best_score
;
2520 } else if (!second
|| score
< second_score
) {
2522 second_score
= score
;
2525 if (!neg_eq
&& ind
.order
.eq
.find(term
) != ind
.order
.eq
.end()) {
2526 for (int j
= 1; j
< ind
.order
.eq
[term
].size(); ++j
)
2527 if (ind
.order
.eq
[term
][j
]->sign
!= term
->sign
) {
2532 if (!neg_le
&& ind
.order
.le
.find(term
) != ind
.order
.le
.end())
2534 if (!neg
|| score
< neg_score
) {
2540 if (i
!= ind
.order
.pred
.end())
2543 if (!best
&& neg_eq
) {
2544 assert(ind
.order
.eq
[neg_eq
].size() != 0);
2545 ind
.handle_equal_numerators(neg_eq
);
2549 if (!best
&& neg_le
) {
2550 /* The smallest term is negative and <= some positive term */
2560 if (!second
&& !neg
) {
2561 indicator_term
*rat
= NULL
;
2563 if (ind
.order
.le
[best
].size() == 0) {
2564 if (ind
.order
.eq
[best
].size() != 0) {
2565 ind
.handle_equal_numerators(best
);
2568 maxima
.push_back(ind
.create_max_term(best
));
2571 for (int j
= 0; j
< ind
.order
.le
[best
].size(); ++j
) {
2572 if (ind
.order
.le
[best
][j
]->sign
== 0) {
2573 if (!rat
&& ind
.order
.pred
[ind
.order
.le
[best
][j
]] == 1)
2574 rat
= ind
.order
.le
[best
][j
];
2575 } else if (ind
.order
.le
[best
][j
]->sign
> 0) {
2576 second
= ind
.order
.le
[best
][j
];
2579 neg
= ind
.order
.le
[best
][j
];
2582 if (!second
&& !neg
) {
2584 ind
.order
.unset_le(best
, rat
);
2585 ind
.expand_rational_vertex(rat
);
2592 ind
.order
.unset_le(best
, second
);
2598 unsigned dim
= best
->den
.NumCols();
2601 for (int k
= 0; k
< dim
; ++k
) {
2602 diff
= ediff(best
->vertex
[k
], second
->vertex
[k
]);
2603 sign
= evalue_sign(diff
, ind
.D
, ind
.options
->MaxRays
);
2605 /* neg can never be smaller than best, unless it may still cancel */
2606 if (second
== neg
&&
2607 ind
.order
.eq
.find(neg
) == ind
.order
.eq
.end() &&
2608 ind
.order
.le
.find(neg
) == ind
.order
.le
.end()) {
2609 if (sign
== order_ge
)
2611 if (sign
== order_unknown
)
2615 if (sign
!= order_eq
)
2617 if (!EVALUE_IS_ZERO(*diff
))
2618 ind
.substitute(diff
);
2620 if (sign
== order_eq
) {
2621 ind
.order
.set_equal(best
, second
);
2624 if (sign
== order_lt
) {
2625 ind
.order
.lt
[best
].push_back(second
);
2626 ind
.order
.pred
[second
]++;
2629 if (sign
== order_gt
) {
2630 ind
.order
.lt
[second
].push_back(best
);
2631 ind
.order
.pred
[best
]++;
2635 split
sp(diff
, sign
== order_le
? split::le
:
2636 sign
== order_ge
? split::ge
: split::lge
);
2638 EDomain
*Dlt
, *Deq
, *Dgt
;
2639 split_on(sp
, ind
.D
, &Dlt
, &Deq
, &Dgt
, ind
.options
->MaxRays
);
2640 assert(Dlt
|| Deq
|| Dgt
);
2641 if (Deq
&& (Dlt
|| Dgt
)) {
2642 int locsize
= loc
.size();
2644 indicator
indeq(ind
, Deq
);
2646 indeq
.substitute(diff
);
2647 vector
<max_term
*> maxeq
= lexmin(indeq
, nparam
, loc
);
2648 maxima
.insert(maxima
.end(), maxeq
.begin(), maxeq
.end());
2649 loc
.resize(locsize
);
2652 int locsize
= loc
.size();
2654 indicator
indgt(ind
, Dgt
);
2656 /* we don't know the new location of these terms in indgt */
2658 indgt.order.lt[second].push_back(best);
2659 indgt.order.pred[best]++;
2661 vector
<max_term
*> maxgt
= lexmin(indgt
, nparam
, loc
);
2662 maxima
.insert(maxima
.end(), maxgt
.begin(), maxgt
.end());
2663 loc
.resize(locsize
);
2668 ind
.substitute(diff
);
2669 ind
.set_domain(Deq
);
2673 ind
.order
.lt
[best
].push_back(second
);
2674 ind
.order
.pred
[second
]++;
2675 ind
.set_domain(Dlt
);
2679 ind
.order
.lt
[second
].push_back(best
);
2680 ind
.order
.pred
[best
]++;
2681 ind
.set_domain(Dgt
);
2688 static vector
<max_term
*> lexmin(Polyhedron
*P
, Polyhedron
*C
,
2689 barvinok_options
*options
)
2691 unsigned nparam
= C
->Dimension
;
2692 Param_Polyhedron
*PP
= NULL
;
2693 Polyhedron
*CEq
= NULL
, *pVD
;
2695 Matrix
*T
= NULL
, *CP
= NULL
;
2696 Param_Domain
*D
, *next
;
2698 Polyhedron
*Porig
= P
;
2699 Polyhedron
*Corig
= C
;
2700 vector
<max_term
*> all_max
;
2702 unsigned P2PSD_MaxRays
;
2707 POL_ENSURE_VERTICES(P
);
2712 assert(P
->NbBid
== 0);
2716 CP
= compress_parameters(&P
, &C
, nparam
, options
->MaxRays
);
2718 T
= remove_equalities(&P
, nparam
, options
->MaxRays
);
2719 if (P
!= Q
&& Q
!= Porig
)
2728 if (options
->MaxRays
& POL_NO_DUAL
)
2731 P2PSD_MaxRays
= options
->MaxRays
;
2734 PP
= Polyhedron2Param_SimplifiedDomain(&P
, C
, P2PSD_MaxRays
, &CEq
, &CT
);
2735 if (P
!= Q
&& Q
!= Porig
)
2739 if (isIdentity(CT
)) {
2743 nparam
= CT
->NbRows
- 1;
2747 unsigned dim
= P
->Dimension
- nparam
;
2750 for (nd
= 0, D
=PP
->D
; D
; ++nd
, D
=D
->next
);
2751 Polyhedron
**fVD
= new Polyhedron
*[nd
];
2753 indicator_constructor
ic(P
, dim
, PP
, T
);
2755 vector
<indicator_term
*> all_vertices
;
2756 construct_rational_vertices(PP
, T
, T
? T
->NbRows
-nparam
-1 : dim
,
2757 nparam
, all_vertices
);
2759 for (nd
= 0, D
=PP
->D
; D
; D
=next
) {
2762 Polyhedron
*rVD
= reduce_domain(D
->Domain
, CT
, CEq
,
2763 fVD
, nd
, options
->MaxRays
);
2767 pVD
= CT
? DomainImage(rVD
,CT
,options
->MaxRays
) : rVD
;
2769 EDomain
*epVD
= new EDomain(pVD
);
2770 indicator
ind(ic
, D
, epVD
, options
);
2772 FORALL_PVertex_in_ParamPolyhedron(V
,D
,PP
) // _i is internal counter
2773 ind
.add(all_vertices
[_i
]);
2774 END_FORALL_PVertex_in_ParamPolyhedron
;
2776 ind
.remove_initial_rational_vertices();
2779 vector
<max_term
*> maxima
= lexmin(ind
, nparam
, loc
);
2781 for (int j
= 0; j
< maxima
.size(); ++j
)
2782 maxima
[j
]->substitute(CP
, options
->MaxRays
);
2783 all_max
.insert(all_max
.end(), maxima
.begin(), maxima
.end());
2790 for (int i
= 0; i
< all_vertices
.size(); ++i
)
2791 delete all_vertices
[i
];
2796 Param_Polyhedron_Free(PP
);
2798 Polyhedron_Free(CEq
);
2799 for (--nd
; nd
>= 0; --nd
) {
2800 Domain_Free(fVD
[nd
]);
2811 static void verify_results(Polyhedron
*A
, Polyhedron
*C
,
2812 vector
<max_term
*>& maxima
, int m
, int M
,
2813 int print_all
, unsigned MaxRays
);
2815 int main(int argc
, char **argv
)
2820 char **iter_names
, **param_names
;
2825 int m
= INT_MAX
, M
= INT_MIN
, r
;
2826 int print_solution
= 1;
2827 struct barvinok_options
*options
;
2829 options
= barvinok_options_new_with_defaults();
2831 while ((c
= getopt_long(argc
, argv
, "TAm:M:r:V", lexmin_options
, &ind
)) != -1) {
2853 printf(barvinok_version());
2860 C
= Constraints2Polyhedron(MA
, options
->MaxRays
);
2862 fscanf(stdin
, " %d", &bignum
);
2863 assert(bignum
== -1);
2865 A
= Constraints2Polyhedron(MA
, options
->MaxRays
);
2868 if (A
->Dimension
>= VBIGDIM
)
2870 else if (A
->Dimension
>= BIGDIM
)
2879 if (verify
&& m
> M
) {
2880 fprintf(stderr
,"Nothing to do: min > max !\n");
2886 iter_names
= util_generate_names(A
->Dimension
- C
->Dimension
, "i");
2887 param_names
= util_generate_names(C
->Dimension
, "p");
2888 if (print_solution
) {
2889 Polyhedron_Print(stdout
, P_VALUE_FMT
, A
);
2890 Polyhedron_Print(stdout
, P_VALUE_FMT
, C
);
2892 vector
<max_term
*> maxima
= lexmin(A
, C
, options
);
2894 for (int i
= 0; i
< maxima
.size(); ++i
)
2895 maxima
[i
]->print(cout
, param_names
);
2898 verify_results(A
, C
, maxima
, m
, M
, print_all
, options
->MaxRays
);
2900 for (int i
= 0; i
< maxima
.size(); ++i
)
2903 util_free_names(A
->Dimension
- C
->Dimension
, iter_names
);
2904 util_free_names(C
->Dimension
, param_names
);
2913 static bool lexmin(int pos
, Polyhedron
*P
, Value
*context
)
2922 value_init(LB
); value_init(UB
); value_init(k
);
2925 lu_flags
= lower_upper_bounds(pos
,P
,context
,&LB
,&UB
);
2926 assert(!(lu_flags
& LB_INFINITY
));
2928 value_set_si(context
[pos
],0);
2929 if (!lu_flags
&& value_lt(UB
,LB
)) {
2930 value_clear(LB
); value_clear(UB
); value_clear(k
);
2934 value_assign(context
[pos
], LB
);
2935 value_clear(LB
); value_clear(UB
); value_clear(k
);
2938 for (value_assign(k
,LB
); lu_flags
|| value_le(k
,UB
); value_increment(k
,k
)) {
2939 value_assign(context
[pos
],k
);
2940 if ((found
= lexmin(pos
+1, P
->next
, context
)))
2944 value_set_si(context
[pos
],0);
2945 value_clear(LB
); value_clear(UB
); value_clear(k
);
2949 static void print_list(FILE *out
, Value
*z
, char* brackets
, int len
)
2951 fprintf(out
, "%c", brackets
[0]);
2952 value_print(out
, VALUE_FMT
,z
[0]);
2953 for (int k
= 1; k
< len
; ++k
) {
2955 value_print(out
, VALUE_FMT
,z
[k
]);
2957 fprintf(out
, "%c", brackets
[1]);
2960 static int check_poly(Polyhedron
*S
, Polyhedron
*CS
, vector
<max_term
*>& maxima
,
2961 int nparam
, int pos
, Value
*z
, int print_all
, int st
,
2964 if (pos
== nparam
) {
2966 bool found
= lexmin(1, S
, z
);
2970 print_list(stdout
, z
+S
->Dimension
-nparam
+1, "()", nparam
);
2973 print_list(stdout
, z
+1, "[]", S
->Dimension
-nparam
);
2978 for (int i
= 0; i
< maxima
.size(); ++i
)
2979 if ((min
= maxima
[i
]->eval(z
+S
->Dimension
-nparam
+1, MaxRays
)))
2982 int ok
= !(found
^ !!min
);
2984 for (int i
= 0; i
< S
->Dimension
-nparam
; ++i
)
2985 if (value_ne(z
[1+i
], min
->p
[i
])) {
2992 fprintf(stderr
, "Error !\n");
2993 fprintf(stderr
, "lexmin");
2994 print_list(stderr
, z
+S
->Dimension
-nparam
+1, "()", nparam
);
2995 fprintf(stderr
, " should be ");
2997 print_list(stderr
, z
+1, "[]", S
->Dimension
-nparam
);
2998 fprintf(stderr
, " while digging gives ");
3000 print_list(stderr
, min
->p
, "[]", S
->Dimension
-nparam
);
3001 fprintf(stderr
, ".\n");
3003 } else if (print_all
)
3008 for (k
= 1; k
<= S
->Dimension
-nparam
; ++k
)
3009 value_set_si(z
[k
], 0);
3017 !(lower_upper_bounds(1+pos
, CS
, &z
[S
->Dimension
-nparam
], &LB
, &UB
));
3018 for (value_assign(tmp
,LB
); value_le(tmp
,UB
); value_increment(tmp
,tmp
)) {
3020 int k
= VALUE_TO_INT(tmp
);
3021 if (!pos
&& !(k
%st
)) {
3026 value_assign(z
[pos
+S
->Dimension
-nparam
+1],tmp
);
3027 if (!check_poly(S
, CS
->next
, maxima
, nparam
, pos
+1, z
, print_all
, st
,
3035 value_set_si(z
[pos
+S
->Dimension
-nparam
+1],0);
3043 void verify_results(Polyhedron
*A
, Polyhedron
*C
, vector
<max_term
*>& maxima
,
3044 int m
, int M
, int print_all
, unsigned MaxRays
)
3046 Polyhedron
*CC
, *CC2
, *CS
, *S
;
3047 unsigned nparam
= C
->Dimension
;
3052 CC
= Polyhedron_Project(A
, nparam
);
3053 CC2
= DomainIntersection(C
, CC
, MaxRays
);
3057 /* Intersect context with range */
3062 MM
= Matrix_Alloc(2*C
->Dimension
, C
->Dimension
+2);
3063 for (int i
= 0; i
< C
->Dimension
; ++i
) {
3064 value_set_si(MM
->p
[2*i
][0], 1);
3065 value_set_si(MM
->p
[2*i
][1+i
], 1);
3066 value_set_si(MM
->p
[2*i
][1+C
->Dimension
], -m
);
3067 value_set_si(MM
->p
[2*i
+1][0], 1);
3068 value_set_si(MM
->p
[2*i
+1][1+i
], -1);
3069 value_set_si(MM
->p
[2*i
+1][1+C
->Dimension
], M
);
3071 CC2
= AddConstraints(MM
->p
[0], 2*CC
->Dimension
, CC
, MaxRays
);
3072 U
= Universe_Polyhedron(0);
3073 CS
= Polyhedron_Scan(CC2
, U
, MaxRays
& POL_NO_DUAL
? 0 : MaxRays
);
3075 Polyhedron_Free(CC2
);
3080 p
= ALLOCN(Value
, A
->Dimension
+2);
3081 for (i
=0; i
<= A
->Dimension
; i
++) {
3083 value_set_si(p
[i
],0);
3086 value_set_si(p
[i
], 1);
3088 S
= Polyhedron_Scan(A
, C
, MaxRays
& POL_NO_DUAL
? 0 : MaxRays
);
3090 if (!print_all
&& C
->Dimension
> 0) {
3095 for (int i
= m
; i
<= M
; i
+= st
)
3102 if (!(CS
&& emptyQ2(CS
)))
3103 check_poly(S
, CS
, maxima
, nparam
, 0, p
, print_all
, st
, MaxRays
);
3110 for (i
=0; i
<= (A
->Dimension
+1); i
++)
3115 Polyhedron_Free(CC
);