2 #include <isl_set_polylib.h>
3 #include <barvinok/util.h>
4 #include <barvinok/basis_reduction.h>
5 #include <barvinok/sample.h>
6 #include <barvinok/options.h>
9 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
11 /* If P has no rays, then we return NULL.
12 * Otherwise, look for the coordinate axis with the smallest maximal non-zero
13 * coefficient over all rays and a constraint that bounds the values on
14 * this axis to the maximal value over the vertices plus the above maximal
15 * non-zero coefficient times the number of rays minus 1.
16 * Any integer point x outside this region is the sum of a point inside
17 * the region and an integer multiple of the rays.
18 * Write x = \sum_i a_i v_i + \sum_j b_j r_j
19 * with \sum_i a_i = 1.
20 * Then x = \sum_i a_i v_i + \sum_j {b_j} r_j + \sum_j [b_j] r_j
21 * with y = \sum_i a_i v_i + \sum_j {b_j} r_j a point inside the region.
23 static Polyhedron
*remove_ray(Polyhedron
*P
, unsigned MaxRays
)
26 Vector
*min
, *max
, *c
;
33 POL_ENSURE_VERTICES(P
);
35 for (; r
< P
->NbRays
; ++r
)
36 if (value_zero_p(P
->Ray
[r
][P
->Dimension
+1]))
38 if (P
->NbBid
== 0 && r
== P
->NbRays
)
41 max
= Vector_Alloc(P
->Dimension
);
42 min
= Vector_Alloc(P
->Dimension
);
43 for (r
= 0; r
< P
->NbBid
; ++r
)
44 for (i
= 0 ; i
< P
->Dimension
; ++i
)
45 if (value_abs_gt(P
->Ray
[r
][1+i
], max
->p
[i
]))
46 value_absolute(max
->p
[i
], P
->Ray
[r
][1+i
]);
48 for (i
= 0 ; i
< P
->Dimension
; ++i
)
49 value_oppose(min
->p
[i
], max
->p
[i
]);
52 for (r
= P
->NbBid
; r
< P
->NbRays
; ++r
) {
53 if (value_notzero_p(P
->Ray
[r
][P
->Dimension
+1]))
55 for (i
= 0 ; i
< P
->Dimension
; ++i
) {
56 if (value_gt(P
->Ray
[r
][1+i
], max
->p
[i
]))
57 value_assign(max
->p
[i
], P
->Ray
[r
][1+i
]);
58 if (value_lt(P
->Ray
[r
][1+i
], min
->p
[i
]))
59 value_assign(min
->p
[i
], P
->Ray
[r
][1+i
]);
68 for (i
= 0 ; i
< P
->Dimension
; ++i
) {
69 if (value_notzero_p(min
->p
[i
]) &&
70 (value_zero_p(s
) || value_abs_lt(min
->p
[i
], s
))) {
71 value_assign(s
, min
->p
[i
]);
74 if (value_notzero_p(max
->p
[i
]) &&
75 (value_zero_p(s
) || value_abs_lt(max
->p
[i
], s
))) {
76 value_assign(s
, max
->p
[i
]);
81 for (r
= P
->NbBid
; r
< P
->NbRays
; ++r
)
82 if (value_notzero_p(P
->Ray
[r
][P
->Dimension
+1]))
86 mpz_cdiv_q(v
, P
->Ray
[r
][1+pos
], P
->Ray
[r
][P
->Dimension
+1]);
88 mpz_fdiv_q(v
, P
->Ray
[r
][1+pos
], P
->Ray
[r
][P
->Dimension
+1]);
90 for ( ; r
< P
->NbRays
; ++r
) {
91 if (value_zero_p(P
->Ray
[r
][P
->Dimension
+1]))
95 mpz_cdiv_q(tmp
, P
->Ray
[r
][1+pos
], P
->Ray
[r
][P
->Dimension
+1]);
99 mpz_fdiv_q(tmp
, P
->Ray
[r
][1+pos
], P
->Ray
[r
][P
->Dimension
+1]);
100 if (value_lt(tmp
, v
))
101 value_assign(v
, tmp
);
105 c
= Vector_Alloc(1+P
->Dimension
+1);
107 value_set_si(tmp
, rays
);
108 value_addmul(v
, tmp
, s
);
109 value_set_si(c
->p
[0], 1);
110 if (value_pos_p(s
)) {
111 value_set_si(c
->p
[1+pos
], -1);
112 value_assign(c
->p
[1+P
->Dimension
], v
);
114 value_set_si(c
->p
[1+pos
], 1);
115 value_oppose(c
->p
[1+P
->Dimension
], v
);
117 value_decrement(c
->p
[1+P
->Dimension
], c
->p
[1+P
->Dimension
]);
119 R
= AddConstraints(c
->p
, 1, P
, MaxRays
);
133 static void print_minmax(Polyhedron
*P
)
136 POL_ENSURE_VERTICES(P
);
137 Polyhedron_Print(stderr
, P_VALUE_FMT
, P
);
138 for (i
= 0; i
< P
->Dimension
; ++i
) {
144 mpz_cdiv_q(min
, P
->Ray
[0][1+i
], P
->Ray
[0][1+P
->Dimension
]);
145 mpz_fdiv_q(max
, P
->Ray
[0][1+i
], P
->Ray
[0][1+P
->Dimension
]);
147 for (j
= 1; j
< P
->NbRays
; ++j
) {
148 mpz_cdiv_q(tmp
, P
->Ray
[j
][1+i
], P
->Ray
[j
][1+P
->Dimension
]);
149 if (value_lt(tmp
, min
))
150 value_assign(min
, tmp
);
151 mpz_fdiv_q(tmp
, P
->Ray
[j
][1+i
], P
->Ray
[j
][1+P
->Dimension
]);
152 if (value_gt(tmp
, max
))
153 value_assign(max
, tmp
);
155 fprintf(stderr
, "i: %d, min: ", i
);
156 value_print(stderr
, VALUE_FMT
, min
);
157 fprintf(stderr
, ", max: ");
158 value_print(stderr
, VALUE_FMT
, max
);
159 fprintf(stderr
, "\n");
167 /* Remove coordinates that have a fixed value and return the matrix
168 * that adds these fixed coordinates again through T.
170 static Polyhedron
*Polyhedron_RemoveFixedColumns(Polyhedron
*P
, Matrix
**T
)
173 int dim
= P
->Dimension
;
174 int *remove
= ALLOCN(int, dim
);
178 assert(POL_HAS(P
, POL_INEQUALITIES
));
179 for (i
= 0; i
< dim
; ++i
)
182 for (i
= 0; i
< P
->NbEq
; ++i
) {
183 int pos
= First_Non_Zero(P
->Constraint
[i
]+1, dim
);
184 if (First_Non_Zero(P
->Constraint
[i
]+1+pos
+1, dim
-pos
-1) != -1)
190 Q
= Polyhedron_Alloc(P
->Dimension
-NbEq
, P
->NbConstraints
-NbEq
, P
->NbRays
);
191 Q
->NbEq
= P
->NbEq
- NbEq
;
192 for (i
= 0, k
= 0; i
< P
->NbConstraints
; ++i
) {
194 int pos
= First_Non_Zero(P
->Constraint
[i
]+1, dim
);
195 if (First_Non_Zero(P
->Constraint
[i
]+1+pos
+1, dim
-pos
-1) == -1)
198 value_assign(Q
->Constraint
[k
][0], P
->Constraint
[i
][0]);
199 for (j
= 0, n
= 0; j
< P
->Dimension
; ++j
) {
203 value_assign(Q
->Constraint
[k
][1+j
-n
], P
->Constraint
[i
][1+j
]);
205 value_assign(Q
->Constraint
[k
][1+j
-n
], P
->Constraint
[i
][1+j
]);
208 for (i
= 0; i
< Q
->NbRays
; ++i
) {
209 value_assign(Q
->Ray
[i
][0], P
->Ray
[i
][0]);
210 for (j
= 0, n
= 0; j
< P
->Dimension
; ++j
) {
214 value_assign(Q
->Ray
[i
][1+j
-n
], P
->Ray
[i
][1+j
]);
216 value_assign(Q
->Ray
[i
][1+j
-n
], P
->Ray
[i
][1+j
]);
218 *T
= Matrix_Alloc(P
->Dimension
+1, Q
->Dimension
+1);
219 for (i
= 0, n
= 0; i
< P
->Dimension
; ++i
) {
220 if (remove
[i
] != -1) {
221 value_oppose((*T
)->p
[i
][Q
->Dimension
],
222 P
->Constraint
[remove
[i
]][1+P
->Dimension
]);
225 value_set_si((*T
)->p
[i
][i
-n
], 1);
227 value_set_si((*T
)->p
[i
][i
-n
], 1);
228 POL_SET(Q
, POL_VALID
);
229 if (POL_HAS(P
, POL_INEQUALITIES
))
230 POL_SET(Q
, POL_INEQUALITIES
);
231 if (POL_HAS(P
, POL_FACETS
))
232 POL_SET(Q
, POL_FACETS
);
233 if (POL_HAS(P
, POL_POINTS
))
234 POL_SET(Q
, POL_POINTS
);
235 if (POL_HAS(P
, POL_VERTICES
))
236 POL_SET(Q
, POL_VERTICES
);
241 static Polyhedron
*remove_all_equalities(Polyhedron
*P
, Matrix
**T
,
245 Polyhedron_Matrix_View(P
, &M
, P
->NbEq
);
247 *T
= compress_variables(&M
, 0);
251 P
= Polyhedron_Preimage(P
, *T
, MaxRays
);
256 static Vector
*product_sample(Polyhedron
*P
, Matrix
*T
,
257 struct barvinok_options
*options
)
260 Vector
*sample
= NULL
;
261 Vector
*tmp
= Vector_Alloc(T
->NbRows
);
263 for (; P
; P
= P
->next
) {
265 Polyhedron
*next
= P
->next
;
267 P_sample
= Polyhedron_Sample(P
, options
);
274 Vector_Copy(P_sample
->p
, tmp
->p
+i
, P
->Dimension
);
275 Vector_Free(P_sample
);
279 sample
= Vector_Alloc(T
->NbRows
+ 1);
280 Matrix_Vector_Product(T
, tmp
->p
, sample
->p
);
281 value_set_si(sample
->p
[T
->NbRows
], 1);
287 static Vector
*isl_Polyhedron_Sample(Polyhedron
*P
,
288 struct barvinok_options
*options
)
291 isl_ctx
*ctx
= isl_ctx_alloc();
293 int nvar
= P
->Dimension
;
296 Vector
*sample
= NULL
;
298 dim
= isl_dim_set_alloc(ctx
, 0, nvar
);
299 bset
= isl_basic_set_new_from_polylib(P
, dim
);
300 pnt
= isl_basic_set_sample_point(bset
);
302 if (!isl_point_is_void(pnt
)) {
306 sample
= Vector_Alloc(1 + nvar
);
308 for (i
= 0; i
< nvar
; ++i
) {
309 isl_point_get_coordinate(pnt
, isl_dim_set
, i
, &v
);
310 isl_int_get_gmp(v
, sample
->p
[i
]);
312 value_set_si(sample
->p
[nvar
], 1);
323 /* This function implements the algorithm described in
324 * "An Implementation of the Generalized Basis Reduction Algorithm
325 * for Integer Programming" of Cook el al. to find an integer point
327 * If the polyhedron is unbounded, we first remove its rays.
329 Vector
*Polyhedron_Sample(Polyhedron
*P
, struct barvinok_options
*options
)
332 Vector
*sample
= NULL
, *obj
= NULL
;
341 if (options
->gbr_lp_solver
== BV_GBR_ISL
)
342 return isl_Polyhedron_Sample(P
, options
);
347 if (P
->Dimension
== 0) {
348 sample
= Vector_Alloc(1);
349 value_set_si(sample
->p
[0], 1);
353 if (P
->Dimension
== 1)
354 POL_ENSURE_VERTICES(P
);
356 for (i
= 0; i
< P
->NbRays
; ++i
)
357 if (value_one_p(P
->Ray
[i
][1+P
->Dimension
])) {
358 sample
= Vector_Alloc(P
->Dimension
+1);
359 Vector_Copy(P
->Ray
[i
]+1, sample
->p
, P
->Dimension
+1);
365 Polyhedron
*Q
= remove_all_equalities(P
, &T
, options
->MaxRays
);
368 Q_sample
= Polyhedron_Sample(Q
, options
);
371 sample
= Vector_Alloc(P
->Dimension
+ 1);
372 Matrix_Vector_Product(T
, Q_sample
->p
, sample
->p
);
373 Vector_Free(Q_sample
);
379 Q
= Polyhedron_Factor(P
, 0, &T
, options
->MaxRays
);
381 sample
= product_sample(Q
, T
, options
);
390 obj
= Vector_Alloc(P
->Dimension
+1);
391 value_set_si(obj
->p
[0], 1);
392 res
= polyhedron_range(P
, obj
->p
, obj
->p
[0], &min
, &max
, options
);
393 if (res
== lp_unbounded
) {
399 Q
= remove_ray(P
, options
->MaxRays
);
401 sample
= Polyhedron_Sample(Q
, options
);
407 assert(res
== lp_ok
);
409 if (value_eq(min
, max
)) {
415 options
->gbr_only_first
= 1;
416 basis
= Polyhedron_Reduced_Basis(P
, options
);
417 options
->gbr_only_first
= 0;
421 T
= Matrix_Alloc(P
->Dimension
+1, P
->Dimension
+1);
422 inv
= Matrix_Alloc(P
->Dimension
+1, P
->Dimension
+1);
423 for (i
= 0; i
< P
->Dimension
; ++i
)
424 for (j
= 0; j
< P
->Dimension
; ++j
)
425 value_assign(T
->p
[i
][j
], basis
->p
[i
][j
]);
426 value_set_si(T
->p
[P
->Dimension
][P
->Dimension
], 1);
430 ok
= Matrix_Inverse(M
, inv
);
434 Q
= Polyhedron_Image(P
, T
, options
->MaxRays
);
435 res
= polyhedron_range(Q
, obj
->p
, obj
->p
[0], &min
, &max
, options
);
440 assert(res
== lp_ok
);
445 v
= Vector_Alloc(1+Q
->Dimension
+1);
446 value_set_si(v
->p
[1], -1);
448 for (value_assign(tmp
, min
); value_le(tmp
, max
); value_increment(tmp
, tmp
)) {
452 value_assign(v
->p
[1+Q
->Dimension
], tmp
);
454 R
= AddConstraints(v
->p
, 1, Q
, options
->MaxRays
);
455 R
= DomainConstraintSimplify(R
, options
->MaxRays
);
461 S
= Polyhedron_RemoveFixedColumns(R
, &T
);
463 S_sample
= Polyhedron_Sample(S
, options
);
466 Vector
*Q_sample
= obj
;
468 Matrix_Vector_Product(T
, S_sample
->p
, Q_sample
->p
);
470 Vector_Free(S_sample
);
474 sample
= Vector_Alloc(P
->Dimension
+ 1);
475 Matrix_Vector_Product(inv
, Q_sample
->p
, sample
->p
);
476 Vector_Free(Q_sample
);