3 #include <barvinok/util.h>
4 #include <barvinok/sample.h>
5 #include <barvinok/barvinok.h>
7 #include "evalue_util.h"
13 EDomain
*EDomain::new_from_ge_constraint(ge_constraint
*ge
, int sign
,
14 barvinok_options
*options
)
16 if (ge
->simplified
&& sign
== 0)
21 M2
= Matrix_Copy(ge
->M
);
24 value_decrement(M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1],
25 M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1]);
26 } else if (sign
== -1) {
29 value_set_si(mone
, -1);
30 Vector_Scale(M2
->p
[M2
->NbRows
-1]+1, M2
->p
[M2
->NbRows
-1]+1,
31 mone
, M2
->NbColumns
-1);
32 value_decrement(M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1],
33 M2
->p
[M2
->NbRows
-1][M2
->NbColumns
-1]);
36 value_set_si(M2
->p
[M2
->NbRows
-1][0], 0);
38 Polyhedron
*D2
= Constraints2Polyhedron(M2
, options
->MaxRays
);
39 ED
= new EDomain(D2
, ge
->D
, ge
->new_floors
);
45 static void print_term(ostream
& os
, Value v
, int pos
, int dim
,
46 char **names
, int *first
)
48 if (value_zero_p(v
)) {
49 if (first
&& *first
&& pos
>= dim
)
55 if (!*first
&& value_pos_p(v
))
60 if (value_mone_p(v
)) {
62 } else if (!value_one_p(v
))
63 os
<< VALUE_TO_INT(v
);
66 os
<< VALUE_TO_INT(v
);
69 void EDomain_floor::print(ostream
& os
, char **p
) const
74 for (int i
= 0; i
< v
->Size
-2; ++i
)
75 print_term(os
, v
->p
[1+i
], i
, v
->Size
-2, p
, &first
);
78 print_term(os
, v
->p
[0], v
->Size
-2, v
->Size
-2, p
, NULL
);
82 void EDomain::print_constraints(ostream
& os
, char **p
,
83 barvinok_options
*options
) const
88 Matrix
*M
= Matrix_Alloc(2*floors
.size(), 1+D
->Dimension
+1);
89 value_set_si(tmp
, -1);
90 for (int i
= 0; i
< floors
.size(); ++i
) {
91 value_set_si(M
->p
[2*i
][0], 1);
92 Vector_Copy(floors
[i
]->v
->p
+1, M
->p
[2*i
]+1, dimension());
93 value_assign(M
->p
[2*i
][1+D
->Dimension
], floors
[i
]->v
->p
[1+dimension()]);
94 value_oppose(M
->p
[2*i
][1+dimension()+i
], floors
[i
]->v
->p
[0]);
96 Vector_Scale(M
->p
[2*i
]+1, M
->p
[2*i
+1]+1, tmp
, D
->Dimension
+1);
97 value_addto(M
->p
[2*i
+1][1+D
->Dimension
], M
->p
[2*i
+1][1+D
->Dimension
],
98 M
->p
[2*i
+1][1+dimension()+i
]);
99 value_decrement(M
->p
[2*i
+1][1+D
->Dimension
], M
->p
[2*i
+1][1+D
->Dimension
]);
100 value_set_si(M
->p
[2*i
+1][0], 1);
102 Polyhedron
*E
= Constraints2Polyhedron(M
, options
->MaxRays
);
104 Polyhedron
*SD
= DomainSimplify(D
, E
, options
->MaxRays
);
108 unsigned dim
= dimension();
109 if (dim
< SD
->Dimension
) {
110 names
= new char * [SD
->Dimension
];
112 for (i
= 0; i
< dim
; ++i
)
114 for ( ; i
< SD
->Dimension
; ++i
) {
115 std::ostringstream strm
;
116 floors
[i
-dim
]->print(strm
, p
);
117 names
[i
] = strdup(strm
.str().c_str());
121 for (int i
= 0; i
< SD
->NbConstraints
; ++i
) {
123 int v
= First_Non_Zero(SD
->Constraint
[i
]+1, SD
->Dimension
);
128 if (value_pos_p(SD
->Constraint
[i
][v
+1])) {
129 print_term(os
, SD
->Constraint
[i
][v
+1], v
, SD
->Dimension
,
131 if (value_zero_p(SD
->Constraint
[i
][0]))
135 for (int j
= v
+1; j
<= SD
->Dimension
; ++j
) {
136 value_oppose(tmp
, SD
->Constraint
[i
][1+j
]);
137 print_term(os
, tmp
, j
, SD
->Dimension
,
141 value_oppose(tmp
, SD
->Constraint
[i
][1+v
]);
142 print_term(os
, tmp
, v
, SD
->Dimension
,
144 if (value_zero_p(SD
->Constraint
[i
][0]))
148 for (int j
= v
+1; j
<= SD
->Dimension
; ++j
)
149 print_term(os
, SD
->Constraint
[i
][1+j
], j
, SD
->Dimension
,
156 if (dim
< D
->Dimension
) {
157 for (int i
= dim
; i
< D
->Dimension
; ++i
)
163 void EDomain::print(FILE *out
, char **p
)
165 fdostream
os(dup(fileno(out
)));
166 for (int i
= 0; i
< floors
.size(); ++i
) {
167 os
<< "floor " << i
<< ": [";
168 evalue_print(os
, floors
[i
]->e
, p
);
171 Polyhedron_Print(out
, P_VALUE_FMT
, D
);
174 static int type_offset(enode
*p
)
176 return p
->type
== fractional
? 1 :
177 p
->type
== flooring
? 1 : 0;
180 static void add_coeff(Value
*cons
, int len
, evalue
*coeff
, int pos
)
184 assert(value_notzero_p(coeff
->d
));
188 value_lcm(cons
[0], coeff
->d
, &tmp
);
189 value_division(tmp
, tmp
, cons
[0]);
190 Vector_Scale(cons
, cons
, tmp
, len
);
191 value_division(tmp
, cons
[0], coeff
->d
);
192 value_addmul(cons
[pos
], tmp
, coeff
->x
.n
);
197 static int evalue2constraint_r(EDomain
*D
, evalue
*E
, Value
*cons
, int len
);
199 static void add_fract(evalue
*e
, Value
*cons
, int len
, int pos
)
203 evalue_set_si(&mone
, -1, 1);
205 /* contribution of alpha * fract(X) is
208 assert(e
->x
.p
->size
== 3);
210 value_init(argument
.d
);
211 evalue_copy(&argument
, &e
->x
.p
->arr
[0]);
212 emul(&e
->x
.p
->arr
[2], &argument
);
213 evalue2constraint_r(NULL
, &argument
, cons
, len
);
214 free_evalue_refs(&argument
);
216 /* - alpha * floor(X) */
217 emul(&mone
, &e
->x
.p
->arr
[2]);
218 add_coeff(cons
, len
, &e
->x
.p
->arr
[2], pos
);
219 emul(&mone
, &e
->x
.p
->arr
[2]);
221 free_evalue_refs(&mone
);
224 static int evalue2constraint_r(EDomain
*D
, evalue
*E
, Value
*cons
, int len
)
227 if (value_zero_p(E
->d
) && E
->x
.p
->type
== fractional
) {
229 assert(E
->x
.p
->size
== 3);
230 r
= evalue2constraint_r(D
, &E
->x
.p
->arr
[1], cons
, len
);
231 assert(value_notzero_p(E
->x
.p
->arr
[2].d
));
232 if (D
&& (i
= D
->find_floor(&E
->x
.p
->arr
[0])) >= 0) {
233 add_fract(E
, cons
, len
, 1+D
->D
->Dimension
-D
->floors
.size()+i
);
235 if (value_pos_p(E
->x
.p
->arr
[2].x
.n
)) {
238 value_init(coeff
.x
.n
);
239 value_set_si(coeff
.d
, 1);
240 evalue_denom(&E
->x
.p
->arr
[0], &coeff
.d
);
241 value_decrement(coeff
.x
.n
, coeff
.d
);
242 emul(&E
->x
.p
->arr
[2], &coeff
);
243 add_coeff(cons
, len
, &coeff
, len
-1);
244 free_evalue_refs(&coeff
);
248 } else if (value_zero_p(E
->d
)) {
249 assert(E
->x
.p
->type
== polynomial
);
250 assert(E
->x
.p
->size
== 2);
251 r
= evalue2constraint_r(D
, &E
->x
.p
->arr
[0], cons
, len
) || r
;
252 add_coeff(cons
, len
, &E
->x
.p
->arr
[1], E
->x
.p
->pos
);
254 add_coeff(cons
, len
, E
, len
-1);
259 EDomain_floor::EDomain_floor(const evalue
*f
, int dim
)
264 v
= Vector_Alloc(1+dim
+1);
265 value_set_si(v
->p
[0], 1);
266 evalue2constraint_r(NULL
, e
, v
->p
, v
->Size
);
271 void EDomain_floor::eval(Value
*values
, Value
*res
) const
273 Inner_Product(v
->p
+1, values
, v
->Size
-2, res
);
274 value_addto(*res
, *res
, v
->p
[v
->Size
-1]);
275 value_pdivision(*res
, *res
, v
->p
[0]);
278 int evalue2constraint(EDomain
*D
, evalue
*E
, Value
*cons
, int len
)
280 Vector_Set(cons
, 0, len
);
281 value_set_si(cons
[0], 1);
282 return evalue2constraint_r(D
, E
, cons
, len
);
285 bool EDomain::contains(Value
*point
, int len
) const
287 assert(len
<= D
->Dimension
);
288 if (len
== D
->Dimension
)
289 return in_domain(D
, point
);
291 Vector
*all_val
= Vector_Alloc(D
->Dimension
);
292 Vector_Copy(point
, all_val
->p
, len
);
293 for (int i
= len
-dimension(); i
< floors
.size(); ++i
)
294 floors
[i
]->eval(all_val
->p
, &all_val
->p
[dimension()+i
]);
295 bool in
= in_domain(D
, all_val
->p
);
296 Vector_Free(all_val
);
300 ge_constraint
*EDomain::compute_ge_constraint(evalue
*constraint
) const
302 ge_constraint
*ge
= new ge_constraint(this);
305 evalue_set_si(&mone
, -1, 1);
307 for (evalue
*e
= constraint
; value_zero_p(e
->d
);
308 e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)]) {
310 if (e
->x
.p
->type
!= fractional
)
312 if (find_floor(&e
->x
.p
->arr
[0]) == -1)
316 int rows
= D
->NbConstraints
+2*fract
+1;
317 int cols
= 2+D
->Dimension
+fract
;
318 ge
->M
= Matrix_Alloc(rows
, cols
);
319 for (int i
= 0; i
< D
->NbConstraints
; ++i
) {
320 Vector_Copy(D
->Constraint
[i
], ge
->M
->p
[i
], 1+D
->Dimension
);
321 value_assign(ge
->M
->p
[i
][1+D
->Dimension
+fract
],
322 D
->Constraint
[i
][1+D
->Dimension
]);
324 value_set_si(ge
->M
->p
[rows
-1][0], 1);
327 for (e
= constraint
; value_zero_p(e
->d
); e
= &e
->x
.p
->arr
[type_offset(e
->x
.p
)]) {
328 if (e
->x
.p
->type
== fractional
) {
331 i
= find_floor(&e
->x
.p
->arr
[0]);
333 pos
= D
->Dimension
-floors
.size()+i
;
335 pos
= D
->Dimension
+fract
;
337 add_fract(e
, ge
->M
->p
[rows
-1], cols
, 1+pos
);
339 if (pos
< D
->Dimension
)
342 EDomain_floor
*new_floor
;
343 new_floor
= new EDomain_floor(&e
->x
.p
->arr
[0], dimension());
345 /* constraints for the new floor */
346 int row
= D
->NbConstraints
+2*fract
;
347 Vector_Copy(new_floor
->v
->p
+1, ge
->M
->p
[row
]+1, dimension());
348 value_assign(ge
->M
->p
[row
][cols
-1], new_floor
->v
->p
[1+dimension()]);
349 value_oppose(ge
->M
->p
[row
][1+D
->Dimension
+fract
], new_floor
->v
->p
[0]);
350 value_set_si(ge
->M
->p
[row
][0], 1);
351 assert(value_eq(ge
->M
->p
[row
][cols
-1], new_floor
->v
->p
[1+dimension()]));
352 assert(Vector_Equal(new_floor
->v
->p
+1, ge
->M
->p
[row
]+1, dimension()));
354 Vector_Scale(ge
->M
->p
[row
]+1, ge
->M
->p
[row
+1]+1, mone
.x
.n
, cols
-1);
355 value_set_si(ge
->M
->p
[row
+1][0], 1);
356 value_addto(ge
->M
->p
[row
+1][cols
-1], ge
->M
->p
[row
+1][cols
-1],
357 ge
->M
->p
[row
+1][1+D
->Dimension
+fract
]);
358 value_decrement(ge
->M
->p
[row
+1][cols
-1], ge
->M
->p
[row
+1][cols
-1]);
360 ge
->new_floors
.push_back(new_floor
);
364 assert(e
->x
.p
->type
== polynomial
);
365 assert(e
->x
.p
->size
== 2);
366 add_coeff(ge
->M
->p
[rows
-1], cols
, &e
->x
.p
->arr
[1], e
->x
.p
->pos
);
369 add_coeff(ge
->M
->p
[rows
-1], cols
, e
, cols
-1);
370 ge
->simplified
= ConstraintSimplify(ge
->M
->p
[rows
-1], ge
->M
->p
[rows
-1],
371 cols
, &ge
->M
->p
[rows
-1][0]);
372 value_set_si(ge
->M
->p
[rows
-1][0], 1);
373 free_evalue_refs(&mone
);
377 /* "align" matrix to have nrows by inserting
378 * the necessary number of rows and an equal number of columns at the end
379 * right before the constant row/column
381 static Matrix
*align_matrix_initial(Matrix
*M
, int nrows
)
384 int newrows
= nrows
- M
->NbRows
;
385 Matrix
*M2
= Matrix_Alloc(nrows
, newrows
+ M
->NbColumns
);
386 for (i
= 0; i
< M
->NbRows
-1; ++i
) {
387 Vector_Copy(M
->p
[i
], M2
->p
[i
], M
->NbColumns
-1);
388 value_assign(M2
->p
[i
][M2
->NbColumns
-1], M
->p
[i
][M
->NbColumns
-1]);
390 for (i
= 0; i
<= newrows
; ++i
)
391 value_assign(M2
->p
[M
->NbRows
-1+i
][M
->NbColumns
-1+i
],
392 M
->p
[M
->NbRows
-1][M
->NbColumns
-1]);
396 static Matrix
*InsertColumns(Matrix
*M
, int pos
, int n
)
401 R
= Matrix_Alloc(M
->NbRows
, M
->NbColumns
+n
);
402 for (i
= 0; i
< M
->NbRows
; ++i
) {
403 Vector_Copy(M
->p
[i
], R
->p
[i
], pos
);
404 Vector_Copy(M
->p
[i
]+pos
, R
->p
[i
]+pos
+n
, M
->NbColumns
-pos
);
409 void evalue_substitute(evalue
*e
, evalue
**subs
)
413 if (value_notzero_p(e
->d
))
417 for (int i
= 0; i
< p
->size
; ++i
)
418 evalue_substitute(&p
->arr
[i
], subs
);
420 if (p
->type
== polynomial
)
425 value_set_si(v
->d
, 0);
426 v
->x
.p
= new_enode(p
->type
, 3, -1);
427 value_clear(v
->x
.p
->arr
[0].d
);
428 v
->x
.p
->arr
[0] = p
->arr
[0];
429 evalue_set_si(&v
->x
.p
->arr
[1], 0, 1);
430 evalue_set_si(&v
->x
.p
->arr
[2], 1, 1);
433 int offset
= type_offset(p
);
435 for (int i
= p
->size
-1; i
>= offset
+1; i
--) {
437 eadd(&p
->arr
[i
], &p
->arr
[i
-1]);
438 free_evalue_refs(&(p
->arr
[i
]));
441 if (p
->type
!= polynomial
) {
451 void EDomain_floor::substitute(evalue
**subs
, Matrix
*T
)
453 /* This is a hack. The EDomain_floor elements are possibly shared
454 * by many EDomain structures and we want to perform the substitution
461 evalue_substitute(e
, subs
);
463 assert(T
->NbRows
== v
->Size
-1);
464 Vector
*tmp
= Vector_Alloc(1+T
->NbColumns
);
465 Vector_Matrix_Product(v
->p
+1, T
, tmp
->p
+1);
466 value_multiply(tmp
->p
[0], v
->p
[0], T
->p
[T
->NbRows
-1][T
->NbColumns
-1]);
471 /* T is a homogeneous matrix that maps the original variables to the new variables.
472 * this has constraints in the new variables and this method
473 * transforms this to constraints in the original variables.
475 void EDomain::substitute(evalue
**subs
, Matrix
*T
, Matrix
*Eq
, unsigned MaxRays
)
477 int nexist
= floors
.size();
478 Matrix
*M
= align_matrix_initial(T
, T
->NbRows
+nexist
);
479 Polyhedron
*new_D
= DomainPreimage(D
, M
, MaxRays
);
484 M
= nexist
? InsertColumns(Eq
, 1+dimension(), nexist
) : Eq
;
485 new_D
= DomainAddConstraints(D
, M
, MaxRays
);
490 for (int i
= 0; i
< floors
.size(); ++i
)
491 floors
[i
]->substitute(subs
, T
);
494 static Matrix
*remove_equalities(Polyhedron
**P
, unsigned nparam
, unsigned MaxRays
)
496 /* Matrix "view" of equalities */
498 M
.NbRows
= (*P
)->NbEq
;
499 M
.NbColumns
= (*P
)->Dimension
+2;
500 M
.p_Init
= (*P
)->p_Init
;
501 M
.p
= (*P
)->Constraint
;
503 Matrix
*T
= compress_variables(&M
, nparam
);
513 *P
= Polyhedron_Preimage(*P
, T
, MaxRays
);
518 bool EDomain::not_empty(barvinok_options
*options
)
521 Polyhedron
*Porig
= P
;
523 POL_ENSURE_VERTICES(P
);
527 for (int i
= 0; i
< P
->NbRays
; ++i
)
528 if (value_one_p(P
->Ray
[i
][1+P
->Dimension
])) {
529 sample
= Vector_Alloc(P
->Dimension
+ 1);
530 Vector_Copy(P
->Ray
[i
]+1, sample
->p
, P
->Dimension
+1);
534 if (options
->lexmin_emptiness_check
== BV_LEXMIN_EMPTINESS_CHECK_COUNT
) {
538 barvinok_count_with_options(P
, &cb
, options
);
539 notzero
= value_notzero_p(cb
);
545 while (P
&& !emptyQ2(P
) && P
->NbEq
> 0) {
547 Matrix
*T2
= remove_equalities(&P
, 0, options
->MaxRays
);
552 Matrix
*T3
= Matrix_Alloc(T
->NbRows
, T2
->NbColumns
);
553 Matrix_Product(T
, T2
, T3
);
563 sample
= Polyhedron_Sample(P
, options
);
566 Vector
*P_sample
= Vector_Alloc(Porig
->Dimension
+ 1);
567 Matrix_Vector_Product(T
, sample
->p
, P_sample
->p
);
578 assert(in_domain(Porig
, sample
->p
));
580 return sample
!= NULL
;