1 #include <polylib/polylibgmp.h>
2 #include <barvinok/util.h>
3 #include "basis_reduction.h"
6 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
8 /* If P has no rays, then we return NULL.
9 * Otherwise, look for the coordinate axis with the smallest maximal non-zero
10 * coefficient over all rays and a constraint that bounds the values on
11 * this axis to the maximal value over the vertices plus the above maximal
12 * non-zero coefficient times the number of rays minus 1.
13 * Any integer point x outside this region is the sum of a point inside
14 * the region and an integer multiple of the rays.
15 * Write x = \sum_i a_i v_i + \sum_j b_j r_j
16 * with \sum_i a_i = 1.
17 * Then x = \sum_i a_i v_i + \sum_j {b_j} r_j + \sum_j [b_j] r_j
18 * with y = \sum_i a_i v_i + \sum_j {b_j} r_j a point inside the region.
20 static Polyhedron
*remove_ray(Polyhedron
*P
, unsigned MaxRays
)
23 Vector
*min
, *max
, *c
;
31 for (; r
< P
->NbRays
; ++r
)
32 if (value_zero_p(P
->Ray
[r
][P
->Dimension
+1]))
34 if (P
->NbBid
== 0 && r
== P
->NbRays
)
37 max
= Vector_Alloc(P
->Dimension
);
38 min
= Vector_Alloc(P
->Dimension
);
39 for (r
= 0; r
< P
->NbBid
; ++r
)
40 for (i
= 0 ; i
< P
->Dimension
; ++i
)
41 if (value_abs_gt(P
->Ray
[r
][1+i
], max
->p
[i
]))
42 value_absolute(max
->p
[i
], P
->Ray
[r
][1+i
]);
44 for (i
= 0 ; i
< P
->Dimension
; ++i
)
45 value_oppose(min
->p
[i
], max
->p
[i
]);
48 for (r
= P
->NbBid
; r
< P
->NbRays
; ++r
) {
49 if (value_notzero_p(P
->Ray
[r
][P
->Dimension
+1]))
51 for (i
= 0 ; i
< P
->Dimension
; ++i
) {
52 if (value_gt(P
->Ray
[r
][1+i
], max
->p
[i
]))
53 value_assign(max
->p
[i
], P
->Ray
[r
][1+i
]);
54 if (value_lt(P
->Ray
[r
][1+i
], min
->p
[i
]))
55 value_assign(min
->p
[i
], P
->Ray
[r
][1+i
]);
64 for (i
= 0 ; i
< P
->Dimension
; ++i
) {
65 if (value_notzero_p(min
->p
[i
]) &&
66 (value_zero_p(s
) || value_abs_lt(min
->p
[i
], s
))) {
67 value_assign(s
, min
->p
[i
]);
70 if (value_notzero_p(max
->p
[i
]) &&
71 (value_zero_p(s
) || value_abs_lt(max
->p
[i
], s
))) {
72 value_assign(s
, max
->p
[i
]);
77 for (r
= P
->NbBid
; r
< P
->NbRays
; ++r
)
78 if (value_notzero_p(P
->Ray
[r
][P
->Dimension
+1]))
82 mpz_cdiv_q(v
, P
->Ray
[r
][1+pos
], P
->Ray
[r
][P
->Dimension
+1]);
84 mpz_fdiv_q(v
, P
->Ray
[r
][1+pos
], P
->Ray
[r
][P
->Dimension
+1]);
86 for ( ; r
< P
->NbRays
; ++r
) {
87 if (value_zero_p(P
->Ray
[r
][P
->Dimension
+1]))
91 mpz_cdiv_q(tmp
, P
->Ray
[r
][1+pos
], P
->Ray
[r
][P
->Dimension
+1]);
95 mpz_fdiv_q(tmp
, P
->Ray
[r
][1+pos
], P
->Ray
[r
][P
->Dimension
+1]);
101 c
= Vector_Alloc(1+P
->Dimension
+1);
103 value_set_si(tmp
, rays
);
104 value_addmul(v
, tmp
, s
);
105 value_set_si(c
->p
[0], 1);
106 if (value_pos_p(s
)) {
107 value_set_si(c
->p
[1+pos
], -1);
108 value_assign(c
->p
[1+P
->Dimension
], v
);
110 value_set_si(c
->p
[1+pos
], 1);
111 value_oppose(c
->p
[1+P
->Dimension
], v
);
113 value_decrement(c
->p
[1+P
->Dimension
], c
->p
[1+P
->Dimension
]);
115 R
= AddConstraints(c
->p
, 1, P
, MaxRays
);
129 static void print_minmax(Polyhedron
*P
)
132 POL_ENSURE_VERTICES(P
);
133 Polyhedron_Print(stderr
, P_VALUE_FMT
, P
);
134 for (i
= 0; i
< P
->Dimension
; ++i
) {
140 mpz_cdiv_q(min
, P
->Ray
[0][1+i
], P
->Ray
[0][1+P
->Dimension
]);
141 mpz_fdiv_q(max
, P
->Ray
[0][1+i
], P
->Ray
[0][1+P
->Dimension
]);
143 for (j
= 1; j
< P
->NbRays
; ++j
) {
144 mpz_cdiv_q(tmp
, P
->Ray
[j
][1+i
], P
->Ray
[j
][1+P
->Dimension
]);
145 if (value_lt(tmp
, min
))
146 value_assign(min
, tmp
);
147 mpz_fdiv_q(tmp
, P
->Ray
[j
][1+i
], P
->Ray
[j
][1+P
->Dimension
]);
148 if (value_gt(tmp
, max
))
149 value_assign(max
, tmp
);
151 fprintf(stderr
, "i: %d, min: ", i
);
152 value_print(stderr
, VALUE_FMT
, min
);
153 fprintf(stderr
, ", max: ");
154 value_print(stderr
, VALUE_FMT
, max
);
155 fprintf(stderr
, "\n");
163 /* Remove coordinates that have a fixed value and return the matrix
164 * that adds these fixed coordinates again through T.
166 static Polyhedron
*Polyhedron_RemoveFixedColumns(Polyhedron
*P
, Matrix
**T
)
169 int dim
= P
->Dimension
;
170 int *remove
= ALLOCN(int, dim
);
174 assert(POL_HAS(P
, POL_INEQUALITIES
));
175 for (i
= 0; i
< dim
; ++i
)
178 for (i
= 0; i
< P
->NbEq
; ++i
) {
179 int pos
= First_Non_Zero(P
->Constraint
[i
]+1, dim
);
180 if (First_Non_Zero(P
->Constraint
[i
]+1+pos
+1, dim
-pos
-1) != -1)
186 Q
= Polyhedron_Alloc(P
->Dimension
-NbEq
, P
->NbConstraints
-NbEq
, P
->NbRays
);
187 for (i
= 0, k
= 0; i
< P
->NbConstraints
; ++i
) {
189 int pos
= First_Non_Zero(P
->Constraint
[i
]+1, dim
);
190 if (First_Non_Zero(P
->Constraint
[i
]+1+pos
+1, dim
-pos
-1) == -1)
193 value_assign(Q
->Constraint
[k
][0], P
->Constraint
[i
][0]);
194 for (j
= 0, n
= 0; j
< P
->Dimension
; ++j
) {
198 value_assign(Q
->Constraint
[k
][1+j
-n
], P
->Constraint
[i
][1+j
]);
200 value_assign(Q
->Constraint
[k
][1+j
-n
], P
->Constraint
[i
][1+j
]);
203 for (i
= 0; i
< Q
->NbRays
; ++i
) {
204 value_assign(Q
->Ray
[i
][0], P
->Ray
[i
][0]);
205 for (j
= 0, n
= 0; j
< P
->Dimension
; ++j
) {
209 value_assign(Q
->Ray
[i
][1+j
-n
], P
->Ray
[i
][1+j
]);
211 value_assign(Q
->Ray
[i
][1+j
-n
], P
->Ray
[i
][1+j
]);
213 *T
= Matrix_Alloc(P
->Dimension
+1, Q
->Dimension
+1);
214 for (i
= 0, n
= 0; i
< P
->Dimension
; ++i
) {
216 value_oppose((*T
)->p
[i
][Q
->Dimension
], P
->Constraint
[n
][1+P
->Dimension
]);
219 value_set_si((*T
)->p
[i
][i
-n
], 1);
221 value_set_si((*T
)->p
[i
][i
-n
], 1);
222 POL_SET(Q
, POL_VALID
);
223 if (POL_HAS(P
, POL_INEQUALITIES
))
224 POL_SET(Q
, POL_INEQUALITIES
);
225 if (POL_HAS(P
, POL_FACETS
))
226 POL_SET(Q
, POL_FACETS
);
227 if (POL_HAS(P
, POL_POINTS
))
228 POL_SET(Q
, POL_POINTS
);
229 if (POL_HAS(P
, POL_VERTICES
))
230 POL_SET(Q
, POL_VERTICES
);
235 /* This function implements the algorithm described in
236 * "An Implementation of the Generalized Basis Reduction Algorithm
237 * for Integer Programming" of Cook el al. to find an integer point
239 * If the polyhedron is unbounded, we first remove its rays.
241 Vector
*Polyhedron_Sample(Polyhedron
*P
, unsigned MaxRays
)
244 Vector
*sample
= NULL
;
251 POL_ENSURE_VERTICES(P
);
255 if (P
->Dimension
== 0) {
256 sample
= Vector_Alloc(1);
257 value_set_si(sample
->p
[0], 1);
261 for (i
= 0; i
< P
->NbRays
; ++i
)
262 if (value_one_p(P
->Ray
[i
][1+P
->Dimension
])) {
263 sample
= Vector_Alloc(P
->Dimension
+1);
264 Vector_Copy(P
->Ray
[i
]+1, sample
->p
, P
->Dimension
+1);
268 Q
= remove_ray(P
, MaxRays
);
270 sample
= Polyhedron_Sample(Q
, MaxRays
);
275 Matrix
*basis
= reduced_basis(P
);
277 T
= Matrix_Alloc(P
->Dimension
+1, P
->Dimension
+1);
278 inv
= Matrix_Alloc(P
->Dimension
+1, P
->Dimension
+1);
279 for (i
= 0; i
< P
->Dimension
; ++i
)
280 for (j
= 0; j
< P
->Dimension
; ++j
)
281 value_assign(T
->p
[i
][j
], basis
->p
[i
][j
]);
282 value_set_si(T
->p
[P
->Dimension
][P
->Dimension
], 1);
286 ok
= Matrix_Inverse(M
, inv
);
290 Q
= Polyhedron_Image(P
, T
, MaxRays
);
292 POL_ENSURE_VERTICES(Q
);
298 mpz_cdiv_q(min
, Q
->Ray
[0][1], Q
->Ray
[0][1+Q
->Dimension
]);
299 mpz_fdiv_q(max
, Q
->Ray
[0][1], Q
->Ray
[0][1+Q
->Dimension
]);
301 for (j
= 1; j
< Q
->NbRays
; ++j
) {
302 mpz_cdiv_q(tmp
, Q
->Ray
[j
][1], Q
->Ray
[j
][1+Q
->Dimension
]);
303 if (value_lt(tmp
, min
))
304 value_assign(min
, tmp
);
305 mpz_fdiv_q(tmp
, Q
->Ray
[j
][1], Q
->Ray
[j
][1+Q
->Dimension
]);
306 if (value_gt(tmp
, max
))
307 value_assign(max
, tmp
);
310 v
= Vector_Alloc(1+Q
->Dimension
+1);
311 value_set_si(v
->p
[1], -1);
313 for (value_assign(tmp
, min
); value_le(tmp
, max
); value_increment(tmp
, tmp
)) {
317 value_assign(v
->p
[1+Q
->Dimension
], tmp
);
319 R
= AddConstraints(v
->p
, 1, Q
, MaxRays
);
320 R
= DomainConstraintSimplify(R
, MaxRays
);
326 S
= Polyhedron_RemoveFixedColumns(R
, &T
);
328 S_sample
= Polyhedron_Sample(S
, MaxRays
);
331 Vector
*Q_sample
= Vector_Alloc(Q
->Dimension
+ 1);
332 Matrix_Vector_Product(T
, S_sample
->p
, Q_sample
->p
);
334 Vector_Free(S_sample
);
335 sample
= Vector_Alloc(P
->Dimension
+ 1);
336 Matrix_Vector_Product(inv
, Q_sample
->p
, sample
->p
);
337 Vector_Free(Q_sample
);