/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/External/isl/isl_sample.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2008-2009 Katholieke Universiteit Leuven |
3 | | * |
4 | | * Use of this software is governed by the MIT license |
5 | | * |
6 | | * Written by Sven Verdoolaege, K.U.Leuven, Departement |
7 | | * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium |
8 | | */ |
9 | | |
10 | | #include <isl_ctx_private.h> |
11 | | #include <isl_map_private.h> |
12 | | #include "isl_sample.h" |
13 | | #include <isl/vec.h> |
14 | | #include <isl/mat.h> |
15 | | #include <isl_seq.h> |
16 | | #include "isl_equalities.h" |
17 | | #include "isl_tab.h" |
18 | | #include "isl_basis_reduction.h" |
19 | | #include <isl_factorization.h> |
20 | | #include <isl_point_private.h> |
21 | | #include <isl_options_private.h> |
22 | | #include <isl_vec_private.h> |
23 | | |
24 | | #include <bset_from_bmap.c> |
25 | | #include <set_to_map.c> |
26 | | |
27 | | static __isl_give isl_vec *empty_sample(__isl_take isl_basic_set *bset) |
28 | 508 | { |
29 | 508 | struct isl_vec *vec; |
30 | 508 | |
31 | 508 | vec = isl_vec_alloc(bset->ctx, 0); |
32 | 508 | isl_basic_set_free(bset); |
33 | 508 | return vec; |
34 | 508 | } |
35 | | |
36 | | /* Construct a zero sample of the same dimension as bset. |
37 | | * As a special case, if bset is zero-dimensional, this |
38 | | * function creates a zero-dimensional sample point. |
39 | | */ |
40 | | static __isl_give isl_vec *zero_sample(__isl_take isl_basic_set *bset) |
41 | 62.1k | { |
42 | 62.1k | unsigned dim; |
43 | 62.1k | struct isl_vec *sample; |
44 | 62.1k | |
45 | 62.1k | dim = isl_basic_set_total_dim(bset); |
46 | 62.1k | sample = isl_vec_alloc(bset->ctx, 1 + dim); |
47 | 62.1k | if (sample) { |
48 | 62.1k | isl_int_set_si(sample->el[0], 1); |
49 | 62.1k | isl_seq_clr(sample->el + 1, dim); |
50 | 62.1k | } |
51 | 62.1k | isl_basic_set_free(bset); |
52 | 62.1k | return sample; |
53 | 62.1k | } |
54 | | |
55 | | static __isl_give isl_vec *interval_sample(__isl_take isl_basic_set *bset) |
56 | 280k | { |
57 | 280k | int i; |
58 | 280k | isl_int t; |
59 | 280k | struct isl_vec *sample; |
60 | 280k | |
61 | 280k | bset = isl_basic_set_simplify(bset); |
62 | 280k | if (!bset) |
63 | 0 | return NULL; |
64 | 280k | if (isl_basic_set_plain_is_empty(bset)) |
65 | 0 | return empty_sample(bset); |
66 | 280k | if (bset->n_eq == 0 && bset->n_ineq == 0279k ) |
67 | 8.19k | return zero_sample(bset); |
68 | 272k | |
69 | 272k | sample = isl_vec_alloc(bset->ctx, 2); |
70 | 272k | if (!sample) |
71 | 0 | goto error; |
72 | 272k | if (!bset) |
73 | 0 | return NULL; |
74 | 272k | isl_int_set_si(sample->block.data[0], 1); |
75 | 272k | |
76 | 272k | if (bset->n_eq > 0) { |
77 | 978 | isl_assert(bset->ctx, bset->n_eq == 1, goto error); |
78 | 978 | isl_assert(bset->ctx, bset->n_ineq == 0, goto error); |
79 | 978 | if (isl_int_is_one(bset->eq[0][1])) |
80 | 978 | isl_int_neg(sample->el[1], bset->eq[0][0]); |
81 | 978 | else { |
82 | 0 | isl_assert(bset->ctx, isl_int_is_negone(bset->eq[0][1]), |
83 | 0 | goto error); |
84 | 0 | isl_int_set(sample->el[1], bset->eq[0][0]); |
85 | 0 | } |
86 | 978 | isl_basic_set_free(bset); |
87 | 978 | return sample; |
88 | 271k | } |
89 | 271k | |
90 | 271k | isl_int_init(t); |
91 | 271k | if (isl_int_is_one(bset->ineq[0][1])) |
92 | 271k | isl_int_neg205k (sample->block.data[1], bset->ineq[0][0]); |
93 | 271k | else |
94 | 271k | isl_int_set65.2k (sample->block.data[1], bset->ineq[0][0]); |
95 | 532k | for (i = 1; i < bset->n_ineq; ++i261k ) { |
96 | 261k | isl_seq_inner_product(sample->block.data, |
97 | 261k | bset->ineq[i], 2, &t); |
98 | 261k | if (isl_int_is_neg(t)) |
99 | 261k | break0 ; |
100 | 261k | } |
101 | 271k | isl_int_clear(t); |
102 | 271k | if (i < bset->n_ineq) { |
103 | 0 | isl_vec_free(sample); |
104 | 0 | return empty_sample(bset); |
105 | 0 | } |
106 | 271k | |
107 | 271k | isl_basic_set_free(bset); |
108 | 271k | return sample; |
109 | 0 | error: |
110 | 0 | isl_basic_set_free(bset); |
111 | 0 | isl_vec_free(sample); |
112 | 0 | return NULL; |
113 | 271k | } |
114 | | |
115 | | /* Find a sample integer point, if any, in bset, which is known |
116 | | * to have equalities. If bset contains no integer points, then |
117 | | * return a zero-length vector. |
118 | | * We simply remove the known equalities, compute a sample |
119 | | * in the resulting bset, using the specified recurse function, |
120 | | * and then transform the sample back to the original space. |
121 | | */ |
122 | | static __isl_give isl_vec *sample_eq(__isl_take isl_basic_set *bset, |
123 | | __isl_give isl_vec *(*recurse)(__isl_take isl_basic_set *)) |
124 | 138k | { |
125 | 138k | struct isl_mat *T; |
126 | 138k | struct isl_vec *sample; |
127 | 138k | |
128 | 138k | if (!bset) |
129 | 0 | return NULL; |
130 | 138k | |
131 | 138k | bset = isl_basic_set_remove_equalities(bset, &T, NULL); |
132 | 138k | sample = recurse(bset); |
133 | 138k | if (!sample || sample->size == 0) |
134 | 1.76k | isl_mat_free(T); |
135 | 136k | else |
136 | 136k | sample = isl_mat_vec_product(T, sample); |
137 | 138k | return sample; |
138 | 138k | } |
139 | | |
140 | | /* Return a matrix containing the equalities of the tableau |
141 | | * in constraint form. The tableau is assumed to have |
142 | | * an associated bset that has been kept up-to-date. |
143 | | */ |
144 | | static struct isl_mat *tab_equalities(struct isl_tab *tab) |
145 | 2.28k | { |
146 | 2.28k | int i, j; |
147 | 2.28k | int n_eq; |
148 | 2.28k | struct isl_mat *eq; |
149 | 2.28k | struct isl_basic_set *bset; |
150 | 2.28k | |
151 | 2.28k | if (!tab) |
152 | 0 | return NULL; |
153 | 2.28k | |
154 | 2.28k | bset = isl_tab_peek_bset(tab); |
155 | 2.28k | isl_assert(tab->mat->ctx, bset, return NULL); |
156 | 2.28k | |
157 | 2.28k | n_eq = tab->n_var - tab->n_col + tab->n_dead; |
158 | 2.28k | if (tab->empty || n_eq == 0) |
159 | 412 | return isl_mat_alloc(tab->mat->ctx, 0, tab->n_var); |
160 | 1.87k | if (n_eq == tab->n_var) |
161 | 0 | return isl_mat_identity(tab->mat->ctx, tab->n_var); |
162 | 1.87k | |
163 | 1.87k | eq = isl_mat_alloc(tab->mat->ctx, n_eq, tab->n_var); |
164 | 1.87k | if (!eq) |
165 | 0 | return NULL; |
166 | 19.1k | for (i = 0, j = 0; 1.87k i < tab->n_con; ++i17.2k ) { |
167 | 17.2k | if (tab->con[i].is_row) |
168 | 10.5k | continue; |
169 | 6.67k | if (tab->con[i].index >= 0 && tab->con[i].index >= tab->n_dead4.22k ) |
170 | 3.18k | continue; |
171 | 3.48k | if (i < bset->n_eq) |
172 | 534 | isl_seq_cpy(eq->row[j], bset->eq[i] + 1, tab->n_var); |
173 | 2.95k | else |
174 | 2.95k | isl_seq_cpy(eq->row[j], |
175 | 2.95k | bset->ineq[i - bset->n_eq] + 1, tab->n_var); |
176 | 3.48k | ++j; |
177 | 3.48k | } |
178 | 1.87k | isl_assert(bset->ctx, j == n_eq, goto error); |
179 | 1.87k | return eq; |
180 | 0 | error: |
181 | 0 | isl_mat_free(eq); |
182 | 0 | return NULL; |
183 | 1.87k | } |
184 | | |
185 | | /* Compute and return an initial basis for the bounded tableau "tab". |
186 | | * |
187 | | * If the tableau is either full-dimensional or zero-dimensional, |
188 | | * the we simply return an identity matrix. |
189 | | * Otherwise, we construct a basis whose first directions correspond |
190 | | * to equalities. |
191 | | */ |
192 | | static struct isl_mat *initial_basis(struct isl_tab *tab) |
193 | 246k | { |
194 | 246k | int n_eq; |
195 | 246k | struct isl_mat *eq; |
196 | 246k | struct isl_mat *Q; |
197 | 246k | |
198 | 246k | tab->n_unbounded = 0; |
199 | 246k | tab->n_zero = n_eq = tab->n_var - tab->n_col + tab->n_dead; |
200 | 246k | if (tab->empty || n_eq == 0 || n_eq == tab->n_var1.63k ) |
201 | 245k | return isl_mat_identity(tab->mat->ctx, 1 + tab->n_var); |
202 | 1.19k | |
203 | 1.19k | eq = tab_equalities(tab); |
204 | 1.19k | eq = isl_mat_left_hermite(eq, 0, NULL, &Q); |
205 | 1.19k | if (!eq) |
206 | 0 | return NULL; |
207 | 1.19k | isl_mat_free(eq); |
208 | 1.19k | |
209 | 1.19k | Q = isl_mat_lin_to_aff(Q); |
210 | 1.19k | return Q; |
211 | 1.19k | } |
212 | | |
213 | | /* Compute the minimum of the current ("level") basis row over "tab" |
214 | | * and store the result in position "level" of "min". |
215 | | * |
216 | | * This function assumes that at least one more row and at least |
217 | | * one more element in the constraint array are available in the tableau. |
218 | | */ |
219 | | static enum isl_lp_result compute_min(isl_ctx *ctx, struct isl_tab *tab, |
220 | | __isl_keep isl_vec *min, int level) |
221 | 392k | { |
222 | 392k | return isl_tab_min(tab, tab->basis->row[1 + level], |
223 | 392k | ctx->one, &min->el[level], NULL, 0); |
224 | 392k | } |
225 | | |
226 | | /* Compute the maximum of the current ("level") basis row over "tab" |
227 | | * and store the result in position "level" of "max". |
228 | | * |
229 | | * This function assumes that at least one more row and at least |
230 | | * one more element in the constraint array are available in the tableau. |
231 | | */ |
232 | | static enum isl_lp_result compute_max(isl_ctx *ctx, struct isl_tab *tab, |
233 | | __isl_keep isl_vec *max, int level) |
234 | 176k | { |
235 | 176k | enum isl_lp_result res; |
236 | 176k | unsigned dim = tab->n_var; |
237 | 176k | |
238 | 176k | isl_seq_neg(tab->basis->row[1 + level] + 1, |
239 | 176k | tab->basis->row[1 + level] + 1, dim); |
240 | 176k | res = isl_tab_min(tab, tab->basis->row[1 + level], |
241 | 176k | ctx->one, &max->el[level], NULL, 0); |
242 | 176k | isl_seq_neg(tab->basis->row[1 + level] + 1, |
243 | 176k | tab->basis->row[1 + level] + 1, dim); |
244 | 176k | isl_int_neg(max->el[level], max->el[level]); |
245 | 176k | |
246 | 176k | return res; |
247 | 176k | } |
248 | | |
249 | | /* Perform a greedy search for an integer point in the set represented |
250 | | * by "tab", given that the minimal rational value (rounded up to the |
251 | | * nearest integer) at "level" is smaller than the maximal rational |
252 | | * value (rounded down to the nearest integer). |
253 | | * |
254 | | * Return 1 if we have found an integer point (if tab->n_unbounded > 0 |
255 | | * then we may have only found integer values for the bounded dimensions |
256 | | * and it is the responsibility of the caller to extend this solution |
257 | | * to the unbounded dimensions). |
258 | | * Return 0 if greedy search did not result in a solution. |
259 | | * Return -1 if some error occurred. |
260 | | * |
261 | | * We assign a value half-way between the minimum and the maximum |
262 | | * to the current dimension and check if the minimal value of the |
263 | | * next dimension is still smaller than (or equal) to the maximal value. |
264 | | * We continue this process until either |
265 | | * - the minimal value (rounded up) is greater than the maximal value |
266 | | * (rounded down). In this case, greedy search has failed. |
267 | | * - we have exhausted all bounded dimensions, meaning that we have |
268 | | * found a solution. |
269 | | * - the sample value of the tableau is integral. |
270 | | * - some error has occurred. |
271 | | */ |
272 | | static int greedy_search(isl_ctx *ctx, struct isl_tab *tab, |
273 | | __isl_keep isl_vec *min, __isl_keep isl_vec *max, int level) |
274 | 48.3k | { |
275 | 48.3k | struct isl_tab_undo *snap; |
276 | 48.3k | enum isl_lp_result res; |
277 | 48.3k | |
278 | 48.3k | snap = isl_tab_snap(tab); |
279 | 48.3k | |
280 | 154k | do { |
281 | 154k | isl_int_add(tab->basis->row[1 + level][0], |
282 | 154k | min->el[level], max->el[level]); |
283 | 154k | isl_int_fdiv_q_ui(tab->basis->row[1 + level][0], |
284 | 154k | tab->basis->row[1 + level][0], 2); |
285 | 154k | isl_int_neg(tab->basis->row[1 + level][0], |
286 | 154k | tab->basis->row[1 + level][0]); |
287 | 154k | if (isl_tab_add_valid_eq(tab, tab->basis->row[1 + level]) < 0) |
288 | 0 | return -1; |
289 | 154k | isl_int_set_si(tab->basis->row[1 + level][0], 0); |
290 | 154k | |
291 | 154k | if (++level >= tab->n_var - tab->n_unbounded) |
292 | 25.5k | return 1; |
293 | 128k | if (isl_tab_sample_is_integer(tab)) |
294 | 15.5k | return 1; |
295 | 113k | |
296 | 113k | res = compute_min(ctx, tab, min, level); |
297 | 113k | if (res == isl_lp_error) |
298 | 0 | return -1; |
299 | 113k | if (res != isl_lp_ok) |
300 | 113k | isl_die0 (ctx, isl_error_internal, |
301 | 113k | "expecting bounded rational solution", |
302 | 113k | return -1); |
303 | 113k | res = compute_max(ctx, tab, max, level); |
304 | 113k | if (res == isl_lp_error) |
305 | 0 | return -1; |
306 | 113k | if (res != isl_lp_ok) |
307 | 113k | isl_die0 (ctx, isl_error_internal, |
308 | 113k | "expecting bounded rational solution", |
309 | 113k | return -1); |
310 | 113k | } while (isl_int_le(min->el[level], max->el[level])); |
311 | 48.3k | |
312 | 48.3k | if (7.32k isl_tab_rollback(tab, snap) < 07.32k ) |
313 | 0 | return -1; |
314 | 7.32k | |
315 | 7.32k | return 0; |
316 | 7.32k | } |
317 | | |
318 | | /* Given a tableau representing a set, find and return |
319 | | * an integer point in the set, if there is any. |
320 | | * |
321 | | * We perform a depth first search |
322 | | * for an integer point, by scanning all possible values in the range |
323 | | * attained by a basis vector, where an initial basis may have been set |
324 | | * by the calling function. Otherwise an initial basis that exploits |
325 | | * the equalities in the tableau is created. |
326 | | * tab->n_zero is currently ignored and is clobbered by this function. |
327 | | * |
328 | | * The tableau is allowed to have unbounded direction, but then |
329 | | * the calling function needs to set an initial basis, with the |
330 | | * unbounded directions last and with tab->n_unbounded set |
331 | | * to the number of unbounded directions. |
332 | | * Furthermore, the calling functions needs to add shifted copies |
333 | | * of all constraints involving unbounded directions to ensure |
334 | | * that any feasible rational value in these directions can be rounded |
335 | | * up to yield a feasible integer value. |
336 | | * In particular, let B define the given basis x' = B x |
337 | | * and let T be the inverse of B, i.e., X = T x'. |
338 | | * Let a x + c >= 0 be a constraint of the set represented by the tableau, |
339 | | * or a T x' + c >= 0 in terms of the given basis. Assume that |
340 | | * the bounded directions have an integer value, then we can safely |
341 | | * round up the values for the unbounded directions if we make sure |
342 | | * that x' not only satisfies the original constraint, but also |
343 | | * the constraint "a T x' + c + s >= 0" with s the sum of all |
344 | | * negative values in the last n_unbounded entries of "a T". |
345 | | * The calling function therefore needs to add the constraint |
346 | | * a x + c + s >= 0. The current function then scans the first |
347 | | * directions for an integer value and once those have been found, |
348 | | * it can compute "T ceil(B x)" to yield an integer point in the set. |
349 | | * Note that during the search, the first rows of B may be changed |
350 | | * by a basis reduction, but the last n_unbounded rows of B remain |
351 | | * unaltered and are also not mixed into the first rows. |
352 | | * |
353 | | * The search is implemented iteratively. "level" identifies the current |
354 | | * basis vector. "init" is true if we want the first value at the current |
355 | | * level and false if we want the next value. |
356 | | * |
357 | | * At the start of each level, we first check if we can find a solution |
358 | | * using greedy search. If not, we continue with the exhaustive search. |
359 | | * |
360 | | * The initial basis is the identity matrix. If the range in some direction |
361 | | * contains more than one integer value, we perform basis reduction based |
362 | | * on the value of ctx->opt->gbr |
363 | | * - ISL_GBR_NEVER: never perform basis reduction |
364 | | * - ISL_GBR_ONCE: only perform basis reduction the first |
365 | | * time such a range is encountered |
366 | | * - ISL_GBR_ALWAYS: always perform basis reduction when |
367 | | * such a range is encountered |
368 | | * |
369 | | * When ctx->opt->gbr is set to ISL_GBR_ALWAYS, then we allow the basis |
370 | | * reduction computation to return early. That is, as soon as it |
371 | | * finds a reasonable first direction. |
372 | | */ |
373 | | struct isl_vec *isl_tab_sample(struct isl_tab *tab) |
374 | 278k | { |
375 | 278k | unsigned dim; |
376 | 278k | unsigned gbr; |
377 | 278k | struct isl_ctx *ctx; |
378 | 278k | struct isl_vec *sample; |
379 | 278k | struct isl_vec *min; |
380 | 278k | struct isl_vec *max; |
381 | 278k | enum isl_lp_result res; |
382 | 278k | int level; |
383 | 278k | int init; |
384 | 278k | int reduced; |
385 | 278k | struct isl_tab_undo **snap; |
386 | 278k | |
387 | 278k | if (!tab) |
388 | 0 | return NULL; |
389 | 278k | if (tab->empty) |
390 | 13.6k | return isl_vec_alloc(tab->mat->ctx, 0); |
391 | 264k | |
392 | 264k | if (!tab->basis) |
393 | 246k | tab->basis = initial_basis(tab); |
394 | 264k | if (!tab->basis) |
395 | 0 | return NULL; |
396 | 264k | isl_assert(tab->mat->ctx, tab->basis->n_row == tab->n_var + 1, |
397 | 264k | return NULL); |
398 | 264k | isl_assert(tab->mat->ctx, tab->basis->n_col == tab->n_var + 1, |
399 | 264k | return NULL); |
400 | 264k | |
401 | 264k | ctx = tab->mat->ctx; |
402 | 264k | dim = tab->n_var; |
403 | 264k | gbr = ctx->opt->gbr; |
404 | 264k | |
405 | 264k | if (tab->n_unbounded == tab->n_var) { |
406 | 0 | sample = isl_tab_get_sample_value(tab); |
407 | 0 | sample = isl_mat_vec_product(isl_mat_copy(tab->basis), sample); |
408 | 0 | sample = isl_vec_ceil(sample); |
409 | 0 | sample = isl_mat_vec_inverse_product(isl_mat_copy(tab->basis), |
410 | 0 | sample); |
411 | 0 | return sample; |
412 | 0 | } |
413 | 264k | |
414 | 264k | if (isl_tab_extend_cons(tab, dim + 1) < 0) |
415 | 0 | return NULL; |
416 | 264k | |
417 | 264k | min = isl_vec_alloc(ctx, dim); |
418 | 264k | max = isl_vec_alloc(ctx, dim); |
419 | 264k | snap = isl_alloc_array(ctx, struct isl_tab_undo *, dim); |
420 | 264k | |
421 | 264k | if (!min || !max || !snap) |
422 | 0 | goto error; |
423 | 264k | |
424 | 264k | level = 0; |
425 | 264k | init = 1; |
426 | 264k | reduced = 0; |
427 | 264k | |
428 | 281k | while (level >= 0) { |
429 | 280k | if (init) { |
430 | 279k | int choice; |
431 | 279k | |
432 | 279k | res = compute_min(ctx, tab, min, level); |
433 | 279k | if (res == isl_lp_error) |
434 | 0 | goto error; |
435 | 279k | if (res != isl_lp_ok) |
436 | 279k | isl_die0 (ctx, isl_error_internal, |
437 | 279k | "expecting bounded rational solution", |
438 | 279k | goto error); |
439 | 279k | if (isl_tab_sample_is_integer(tab)) |
440 | 216k | break; |
441 | 62.9k | res = compute_max(ctx, tab, max, level); |
442 | 62.9k | if (res == isl_lp_error) |
443 | 0 | goto error; |
444 | 62.9k | if (res != isl_lp_ok) |
445 | 62.9k | isl_die0 (ctx, isl_error_internal, |
446 | 62.9k | "expecting bounded rational solution", |
447 | 62.9k | goto error); |
448 | 62.9k | if (isl_tab_sample_is_integer(tab)) |
449 | 6.75k | break; |
450 | 56.1k | choice = isl_int_lt(min->el[level], max->el[level]); |
451 | 56.1k | if (choice) { |
452 | 48.3k | int g; |
453 | 48.3k | g = greedy_search(ctx, tab, min, max, level); |
454 | 48.3k | if (g < 0) |
455 | 0 | goto error; |
456 | 48.3k | if (g) |
457 | 41.0k | break; |
458 | 15.1k | } |
459 | 15.1k | if (!reduced && choice12.3k && |
460 | 15.1k | ctx->opt->gbr != 6.84k ISL_GBR_NEVER6.84k ) { |
461 | 6.84k | unsigned gbr_only_first; |
462 | 6.84k | if (ctx->opt->gbr == ISL_GBR_ONCE) |
463 | 6.84k | ctx->opt->gbr = 0 ISL_GBR_NEVER0 ; |
464 | 6.84k | tab->n_zero = level; |
465 | 6.84k | gbr_only_first = ctx->opt->gbr_only_first; |
466 | 6.84k | ctx->opt->gbr_only_first = |
467 | 6.84k | ctx->opt->gbr == ISL_GBR_ALWAYS; |
468 | 6.84k | tab = isl_tab_compute_reduced_basis(tab); |
469 | 6.84k | ctx->opt->gbr_only_first = gbr_only_first; |
470 | 6.84k | if (!tab || !tab->basis) |
471 | 0 | goto error; |
472 | 6.84k | reduced = 1; |
473 | 6.84k | continue; |
474 | 6.84k | } |
475 | 8.27k | reduced = 0; |
476 | 8.27k | snap[level] = isl_tab_snap(tab); |
477 | 8.27k | } else |
478 | 280k | isl_int_add_ui1.33k (min->el[level], min->el[level], 1); |
479 | 280k | |
480 | 280k | if (9.61k isl_int_gt9.61k (min->el[level], max->el[level])) { |
481 | 2.27k | level--; |
482 | 2.27k | init = 0; |
483 | 2.27k | if (level >= 0) |
484 | 1.33k | if (isl_tab_rollback(tab, snap[level]) < 0) |
485 | 0 | goto error; |
486 | 2.27k | continue; |
487 | 2.27k | } |
488 | 7.33k | isl_int_neg(tab->basis->row[1 + level][0], min->el[level]); |
489 | 7.33k | if (isl_tab_add_valid_eq(tab, tab->basis->row[1 + level]) < 0) |
490 | 0 | goto error; |
491 | 7.33k | isl_int_set_si(tab->basis->row[1 + level][0], 0); |
492 | 7.33k | if (level + tab->n_unbounded < dim - 1) { |
493 | 7.32k | ++level; |
494 | 7.32k | init = 1; |
495 | 7.32k | continue; |
496 | 7.32k | } |
497 | 11 | break; |
498 | 11 | } |
499 | 264k | |
500 | 264k | if (level >= 0) { |
501 | 263k | sample = isl_tab_get_sample_value(tab); |
502 | 263k | if (!sample) |
503 | 0 | goto error; |
504 | 263k | if (tab->n_unbounded && !1.01k isl_int_is_one1.01k (sample->el[0])) { |
505 | 437 | sample = isl_mat_vec_product(isl_mat_copy(tab->basis), |
506 | 437 | sample); |
507 | 437 | sample = isl_vec_ceil(sample); |
508 | 437 | sample = isl_mat_vec_inverse_product( |
509 | 437 | isl_mat_copy(tab->basis), sample); |
510 | 437 | } |
511 | 263k | } else |
512 | 939 | sample = isl_vec_alloc(ctx, 0); |
513 | 264k | |
514 | 264k | ctx->opt->gbr = gbr; |
515 | 264k | isl_vec_free(min); |
516 | 264k | isl_vec_free(max); |
517 | 264k | free(snap); |
518 | 264k | return sample; |
519 | 0 | error: |
520 | 0 | ctx->opt->gbr = gbr; |
521 | 0 | isl_vec_free(min); |
522 | 0 | isl_vec_free(max); |
523 | 0 | free(snap); |
524 | 0 | return NULL; |
525 | 264k | } |
526 | | |
527 | | static __isl_give isl_vec *sample_bounded(__isl_take isl_basic_set *bset); |
528 | | |
529 | | /* Compute a sample point of the given basic set, based on the given, |
530 | | * non-trivial factorization. |
531 | | */ |
532 | | static __isl_give isl_vec *factored_sample(__isl_take isl_basic_set *bset, |
533 | | __isl_take isl_factorizer *f) |
534 | 94.0k | { |
535 | 94.0k | int i, n; |
536 | 94.0k | isl_vec *sample = NULL; |
537 | 94.0k | isl_ctx *ctx; |
538 | 94.0k | unsigned nparam; |
539 | 94.0k | unsigned nvar; |
540 | 94.0k | |
541 | 94.0k | ctx = isl_basic_set_get_ctx(bset); |
542 | 94.0k | if (!ctx) |
543 | 0 | goto error; |
544 | 94.0k | |
545 | 94.0k | nparam = isl_basic_set_dim(bset, isl_dim_param); |
546 | 94.0k | nvar = isl_basic_set_dim(bset, isl_dim_set); |
547 | 94.0k | |
548 | 94.0k | sample = isl_vec_alloc(ctx, 1 + isl_basic_set_total_dim(bset)); |
549 | 94.0k | if (!sample) |
550 | 0 | goto error; |
551 | 94.0k | isl_int_set_si(sample->el[0], 1); |
552 | 94.0k | |
553 | 94.0k | bset = isl_morph_basic_set(isl_morph_copy(f->morph), bset); |
554 | 94.0k | |
555 | 417k | for (i = 0, n = 0; i < f->n_group; ++i323k ) { |
556 | 324k | isl_basic_set *bset_i; |
557 | 324k | isl_vec *sample_i; |
558 | 324k | |
559 | 324k | bset_i = isl_basic_set_copy(bset); |
560 | 324k | bset_i = isl_basic_set_drop_constraints_involving(bset_i, |
561 | 324k | nparam + n + f->len[i], nvar - n - f->len[i]); |
562 | 324k | bset_i = isl_basic_set_drop_constraints_involving(bset_i, |
563 | 324k | nparam, n); |
564 | 324k | bset_i = isl_basic_set_drop(bset_i, isl_dim_set, |
565 | 324k | n + f->len[i], nvar - n - f->len[i]); |
566 | 324k | bset_i = isl_basic_set_drop(bset_i, isl_dim_set, 0, n); |
567 | 324k | |
568 | 324k | sample_i = sample_bounded(bset_i); |
569 | 324k | if (!sample_i) |
570 | 0 | goto error; |
571 | 324k | if (sample_i->size == 0) { |
572 | 729 | isl_basic_set_free(bset); |
573 | 729 | isl_factorizer_free(f); |
574 | 729 | isl_vec_free(sample); |
575 | 729 | return sample_i; |
576 | 729 | } |
577 | 323k | isl_seq_cpy(sample->el + 1 + nparam + n, |
578 | 323k | sample_i->el + 1, f->len[i]); |
579 | 323k | isl_vec_free(sample_i); |
580 | 323k | |
581 | 323k | n += f->len[i]; |
582 | 323k | } |
583 | 94.0k | |
584 | 94.0k | f->morph = isl_morph_inverse(f->morph); |
585 | 93.2k | sample = isl_morph_vec(isl_morph_copy(f->morph), sample); |
586 | 93.2k | |
587 | 93.2k | isl_basic_set_free(bset); |
588 | 93.2k | isl_factorizer_free(f); |
589 | 93.2k | return sample; |
590 | 0 | error: |
591 | 0 | isl_basic_set_free(bset); |
592 | 0 | isl_factorizer_free(f); |
593 | 0 | isl_vec_free(sample); |
594 | 0 | return NULL; |
595 | 94.0k | } |
596 | | |
597 | | /* Given a basic set that is known to be bounded, find and return |
598 | | * an integer point in the basic set, if there is any. |
599 | | * |
600 | | * After handling some trivial cases, we construct a tableau |
601 | | * and then use isl_tab_sample to find a sample, passing it |
602 | | * the identity matrix as initial basis. |
603 | | */ |
604 | | static __isl_give isl_vec *sample_bounded(__isl_take isl_basic_set *bset) |
605 | 500k | { |
606 | 500k | unsigned dim; |
607 | 500k | struct isl_vec *sample; |
608 | 500k | struct isl_tab *tab = NULL; |
609 | 500k | isl_factorizer *f; |
610 | 500k | |
611 | 500k | if (!bset) |
612 | 0 | return NULL; |
613 | 500k | |
614 | 500k | if (isl_basic_set_plain_is_empty(bset)) |
615 | 45 | return empty_sample(bset); |
616 | 500k | |
617 | 500k | dim = isl_basic_set_total_dim(bset); |
618 | 500k | if (dim == 0) |
619 | 49.9k | return zero_sample(bset); |
620 | 450k | if (dim == 1) |
621 | 250k | return interval_sample(bset); |
622 | 199k | if (bset->n_eq > 0) |
623 | 1.64k | return sample_eq(bset, sample_bounded); |
624 | 198k | |
625 | 198k | f = isl_basic_set_factorizer(bset); |
626 | 198k | if (!f) |
627 | 0 | goto error; |
628 | 198k | if (f->n_group != 0) |
629 | 94.0k | return factored_sample(bset, f); |
630 | 104k | isl_factorizer_free(f); |
631 | 104k | |
632 | 104k | tab = isl_tab_from_basic_set(bset, 1); |
633 | 104k | if (tab && tab->empty) { |
634 | 4.27k | isl_tab_free(tab); |
635 | 4.27k | ISL_F_SET(bset, ISL_BASIC_SET_EMPTY); |
636 | 4.27k | sample = isl_vec_alloc(isl_basic_set_get_ctx(bset), 0); |
637 | 4.27k | isl_basic_set_free(bset); |
638 | 4.27k | return sample; |
639 | 4.27k | } |
640 | 99.8k | |
641 | 99.8k | if (!ISL_F_ISSET(bset, ISL_BASIC_SET_NO_IMPLICIT)) |
642 | 99.8k | if (99.7k isl_tab_detect_implicit_equalities(tab) < 099.7k ) |
643 | 0 | goto error; |
644 | 99.8k | |
645 | 99.8k | sample = isl_tab_sample(tab); |
646 | 99.8k | if (!sample) |
647 | 0 | goto error; |
648 | 99.8k | |
649 | 99.8k | if (sample->size > 0) { |
650 | 99.2k | isl_vec_free(bset->sample); |
651 | 99.2k | bset->sample = isl_vec_copy(sample); |
652 | 99.2k | } |
653 | 99.8k | |
654 | 99.8k | isl_basic_set_free(bset); |
655 | 99.8k | isl_tab_free(tab); |
656 | 99.8k | return sample; |
657 | 0 | error: |
658 | 0 | isl_basic_set_free(bset); |
659 | 0 | isl_tab_free(tab); |
660 | 0 | return NULL; |
661 | 99.8k | } |
662 | | |
663 | | /* Given a basic set "bset" and a value "sample" for the first coordinates |
664 | | * of bset, plug in these values and drop the corresponding coordinates. |
665 | | * |
666 | | * We do this by computing the preimage of the transformation |
667 | | * |
668 | | * [ 1 0 ] |
669 | | * x = [ s 0 ] x' |
670 | | * [ 0 I ] |
671 | | * |
672 | | * where [1 s] is the sample value and I is the identity matrix of the |
673 | | * appropriate dimension. |
674 | | */ |
675 | | static __isl_give isl_basic_set *plug_in(__isl_take isl_basic_set *bset, |
676 | | __isl_take isl_vec *sample) |
677 | 151k | { |
678 | 151k | int i; |
679 | 151k | unsigned total; |
680 | 151k | struct isl_mat *T; |
681 | 151k | |
682 | 151k | if (!bset || !sample) |
683 | 0 | goto error; |
684 | 151k | |
685 | 151k | total = isl_basic_set_total_dim(bset); |
686 | 151k | T = isl_mat_alloc(bset->ctx, 1 + total, 1 + total - (sample->size - 1)); |
687 | 151k | if (!T) |
688 | 0 | goto error; |
689 | 151k | |
690 | 704k | for (i = 0; 151k i < sample->size; ++i552k ) { |
691 | 552k | isl_int_set(T->row[i][0], sample->el[i]); |
692 | 552k | isl_seq_clr(T->row[i] + 1, T->n_col - 1); |
693 | 552k | } |
694 | 669k | for (i = 0; i < T->n_col - 1; ++i517k ) { |
695 | 517k | isl_seq_clr(T->row[sample->size + i], T->n_col); |
696 | 517k | isl_int_set_si(T->row[sample->size + i][1 + i], 1); |
697 | 517k | } |
698 | 151k | isl_vec_free(sample); |
699 | 151k | |
700 | 151k | bset = isl_basic_set_preimage(bset, T); |
701 | 151k | return bset; |
702 | 0 | error: |
703 | 0 | isl_basic_set_free(bset); |
704 | 0 | isl_vec_free(sample); |
705 | 0 | return NULL; |
706 | 151k | } |
707 | | |
708 | | /* Given a basic set "bset", return any (possibly non-integer) point |
709 | | * in the basic set. |
710 | | */ |
711 | | static __isl_give isl_vec *rational_sample(__isl_take isl_basic_set *bset) |
712 | 155k | { |
713 | 155k | struct isl_tab *tab; |
714 | 155k | struct isl_vec *sample; |
715 | 155k | |
716 | 155k | if (!bset) |
717 | 0 | return NULL; |
718 | 155k | |
719 | 155k | tab = isl_tab_from_basic_set(bset, 0); |
720 | 155k | sample = isl_tab_get_sample_value(tab); |
721 | 155k | isl_tab_free(tab); |
722 | 155k | |
723 | 155k | isl_basic_set_free(bset); |
724 | 155k | |
725 | 155k | return sample; |
726 | 155k | } |
727 | | |
728 | | /* Given a linear cone "cone" and a rational point "vec", |
729 | | * construct a polyhedron with shifted copies of the constraints in "cone", |
730 | | * i.e., a polyhedron with "cone" as its recession cone, such that each |
731 | | * point x in this polyhedron is such that the unit box positioned at x |
732 | | * lies entirely inside the affine cone 'vec + cone'. |
733 | | * Any rational point in this polyhedron may therefore be rounded up |
734 | | * to yield an integer point that lies inside said affine cone. |
735 | | * |
736 | | * Denote the constraints of cone by "<a_i, x> >= 0" and the rational |
737 | | * point "vec" by v/d. |
738 | | * Let b_i = <a_i, v>. Then the affine cone 'vec + cone' is given |
739 | | * by <a_i, x> - b/d >= 0. |
740 | | * The polyhedron <a_i, x> - ceil{b/d} >= 0 is a subset of this affine cone. |
741 | | * We prefer this polyhedron over the actual affine cone because it doesn't |
742 | | * require a scaling of the constraints. |
743 | | * If each of the vertices of the unit cube positioned at x lies inside |
744 | | * this polyhedron, then the whole unit cube at x lies inside the affine cone. |
745 | | * We therefore impose that x' = x + \sum e_i, for any selection of unit |
746 | | * vectors lies inside the polyhedron, i.e., |
747 | | * |
748 | | * <a_i, x'> - ceil{b/d} = <a_i, x> + sum a_i - ceil{b/d} >= 0 |
749 | | * |
750 | | * The most stringent of these constraints is the one that selects |
751 | | * all negative a_i, so the polyhedron we are looking for has constraints |
752 | | * |
753 | | * <a_i, x> + sum_{a_i < 0} a_i - ceil{b/d} >= 0 |
754 | | * |
755 | | * Note that if cone were known to have only non-negative rays |
756 | | * (which can be accomplished by a unimodular transformation), |
757 | | * then we would only have to check the points x' = x + e_i |
758 | | * and we only have to add the smallest negative a_i (if any) |
759 | | * instead of the sum of all negative a_i. |
760 | | */ |
761 | | static __isl_give isl_basic_set *shift_cone(__isl_take isl_basic_set *cone, |
762 | | __isl_take isl_vec *vec) |
763 | 3.44k | { |
764 | 3.44k | int i, j, k; |
765 | 3.44k | unsigned total; |
766 | 3.44k | |
767 | 3.44k | struct isl_basic_set *shift = NULL; |
768 | 3.44k | |
769 | 3.44k | if (!cone || !vec) |
770 | 0 | goto error; |
771 | 3.44k | |
772 | 3.44k | isl_assert(cone->ctx, cone->n_eq == 0, goto error); |
773 | 3.44k | |
774 | 3.44k | total = isl_basic_set_total_dim(cone); |
775 | 3.44k | |
776 | 3.44k | shift = isl_basic_set_alloc_space(isl_basic_set_get_space(cone), |
777 | 3.44k | 0, 0, cone->n_ineq); |
778 | 3.44k | |
779 | 11.2k | for (i = 0; i < cone->n_ineq; ++i7.84k ) { |
780 | 7.84k | k = isl_basic_set_alloc_inequality(shift); |
781 | 7.84k | if (k < 0) |
782 | 0 | goto error; |
783 | 7.84k | isl_seq_cpy(shift->ineq[k] + 1, cone->ineq[i] + 1, total); |
784 | 7.84k | isl_seq_inner_product(shift->ineq[k] + 1, vec->el + 1, total, |
785 | 7.84k | &shift->ineq[k][0]); |
786 | 7.84k | isl_int_cdiv_q(shift->ineq[k][0], |
787 | 7.84k | shift->ineq[k][0], vec->el[0]); |
788 | 7.84k | isl_int_neg(shift->ineq[k][0], shift->ineq[k][0]); |
789 | 33.3k | for (j = 0; j < total; ++j25.5k ) { |
790 | 25.5k | if (isl_int_is_nonneg(shift->ineq[k][1 + j])) |
791 | 25.5k | continue20.2k ; |
792 | 5.28k | isl_int_add(shift->ineq[k][0], |
793 | 5.28k | shift->ineq[k][0], shift->ineq[k][1 + j]); |
794 | 5.28k | } |
795 | 7.84k | } |
796 | 3.44k | |
797 | 3.44k | isl_basic_set_free(cone); |
798 | 3.44k | isl_vec_free(vec); |
799 | 3.44k | |
800 | 3.44k | return isl_basic_set_finalize(shift); |
801 | 0 | error: |
802 | 0 | isl_basic_set_free(shift); |
803 | 0 | isl_basic_set_free(cone); |
804 | 0 | isl_vec_free(vec); |
805 | 0 | return NULL; |
806 | 3.44k | } |
807 | | |
808 | | /* Given a rational point vec in a (transformed) basic set, |
809 | | * such that cone is the recession cone of the original basic set, |
810 | | * "round up" the rational point to an integer point. |
811 | | * |
812 | | * We first check if the rational point just happens to be integer. |
813 | | * If not, we transform the cone in the same way as the basic set, |
814 | | * pick a point x in this cone shifted to the rational point such that |
815 | | * the whole unit cube at x is also inside this affine cone. |
816 | | * Then we simply round up the coordinates of x and return the |
817 | | * resulting integer point. |
818 | | */ |
819 | | static __isl_give isl_vec *round_up_in_cone(__isl_take isl_vec *vec, |
820 | | __isl_take isl_basic_set *cone, __isl_take isl_mat *U) |
821 | 151k | { |
822 | 151k | unsigned total; |
823 | 151k | |
824 | 151k | if (!vec || !cone || !U) |
825 | 0 | goto error; |
826 | 151k | |
827 | 151k | isl_assert(vec->ctx, vec->size != 0, goto error); |
828 | 151k | if (isl_int_is_one(vec->el[0])) { |
829 | 148k | isl_mat_free(U); |
830 | 148k | isl_basic_set_free(cone); |
831 | 148k | return vec; |
832 | 148k | } |
833 | 3.44k | |
834 | 3.44k | total = isl_basic_set_total_dim(cone); |
835 | 3.44k | cone = isl_basic_set_preimage(cone, U); |
836 | 3.44k | cone = isl_basic_set_remove_dims(cone, isl_dim_set, |
837 | 3.44k | 0, total - (vec->size - 1)); |
838 | 3.44k | |
839 | 3.44k | cone = shift_cone(cone, vec); |
840 | 3.44k | |
841 | 3.44k | vec = rational_sample(cone); |
842 | 3.44k | vec = isl_vec_ceil(vec); |
843 | 3.44k | return vec; |
844 | 0 | error: |
845 | 0 | isl_mat_free(U); |
846 | 0 | isl_vec_free(vec); |
847 | 0 | isl_basic_set_free(cone); |
848 | 0 | return NULL; |
849 | 3.44k | } |
850 | | |
851 | | /* Concatenate two integer vectors, i.e., two vectors with denominator |
852 | | * (stored in element 0) equal to 1. |
853 | | */ |
854 | | static __isl_give isl_vec *vec_concat(__isl_take isl_vec *vec1, |
855 | | __isl_take isl_vec *vec2) |
856 | 151k | { |
857 | 151k | struct isl_vec *vec; |
858 | 151k | |
859 | 151k | if (!vec1 || !vec2) |
860 | 0 | goto error; |
861 | 151k | isl_assert(vec1->ctx, vec1->size > 0, goto error); |
862 | 151k | isl_assert(vec2->ctx, vec2->size > 0, goto error); |
863 | 151k | isl_assert(vec1->ctx, isl_int_is_one(vec1->el[0]), goto error); |
864 | 151k | isl_assert(vec2->ctx, isl_int_is_one(vec2->el[0]), goto error); |
865 | 151k | |
866 | 151k | vec = isl_vec_alloc(vec1->ctx, vec1->size + vec2->size - 1); |
867 | 151k | if (!vec) |
868 | 0 | goto error; |
869 | 151k | |
870 | 151k | isl_seq_cpy(vec->el, vec1->el, vec1->size); |
871 | 151k | isl_seq_cpy(vec->el + vec1->size, vec2->el + 1, vec2->size - 1); |
872 | 151k | |
873 | 151k | isl_vec_free(vec1); |
874 | 151k | isl_vec_free(vec2); |
875 | 151k | |
876 | 151k | return vec; |
877 | 0 | error: |
878 | 0 | isl_vec_free(vec1); |
879 | 0 | isl_vec_free(vec2); |
880 | 0 | return NULL; |
881 | 151k | } |
882 | | |
883 | | /* Give a basic set "bset" with recession cone "cone", compute and |
884 | | * return an integer point in bset, if any. |
885 | | * |
886 | | * If the recession cone is full-dimensional, then we know that |
887 | | * bset contains an infinite number of integer points and it is |
888 | | * fairly easy to pick one of them. |
889 | | * If the recession cone is not full-dimensional, then we first |
890 | | * transform bset such that the bounded directions appear as |
891 | | * the first dimensions of the transformed basic set. |
892 | | * We do this by using a unimodular transformation that transforms |
893 | | * the equalities in the recession cone to equalities on the first |
894 | | * dimensions. |
895 | | * |
896 | | * The transformed set is then projected onto its bounded dimensions. |
897 | | * Note that to compute this projection, we can simply drop all constraints |
898 | | * involving any of the unbounded dimensions since these constraints |
899 | | * cannot be combined to produce a constraint on the bounded dimensions. |
900 | | * To see this, assume that there is such a combination of constraints |
901 | | * that produces a constraint on the bounded dimensions. This means |
902 | | * that some combination of the unbounded dimensions has both an upper |
903 | | * bound and a lower bound in terms of the bounded dimensions, but then |
904 | | * this combination would be a bounded direction too and would have been |
905 | | * transformed into a bounded dimensions. |
906 | | * |
907 | | * We then compute a sample value in the bounded dimensions. |
908 | | * If no such value can be found, then the original set did not contain |
909 | | * any integer points and we are done. |
910 | | * Otherwise, we plug in the value we found in the bounded dimensions, |
911 | | * project out these bounded dimensions and end up with a set with |
912 | | * a full-dimensional recession cone. |
913 | | * A sample point in this set is computed by "rounding up" any |
914 | | * rational point in the set. |
915 | | * |
916 | | * The sample points in the bounded and unbounded dimensions are |
917 | | * then combined into a single sample point and transformed back |
918 | | * to the original space. |
919 | | */ |
920 | | __isl_give isl_vec *isl_basic_set_sample_with_cone( |
921 | | __isl_take isl_basic_set *bset, __isl_take isl_basic_set *cone) |
922 | 155k | { |
923 | 155k | unsigned total; |
924 | 155k | unsigned cone_dim; |
925 | 155k | struct isl_mat *M, *U; |
926 | 155k | struct isl_vec *sample; |
927 | 155k | struct isl_vec *cone_sample; |
928 | 155k | struct isl_ctx *ctx; |
929 | 155k | struct isl_basic_set *bounded; |
930 | 155k | |
931 | 155k | if (!bset || !cone) |
932 | 0 | goto error; |
933 | 155k | |
934 | 155k | ctx = isl_basic_set_get_ctx(bset); |
935 | 155k | total = isl_basic_set_total_dim(cone); |
936 | 155k | cone_dim = total - cone->n_eq; |
937 | 155k | |
938 | 155k | M = isl_mat_sub_alloc6(ctx, cone->eq, 0, cone->n_eq, 1, total); |
939 | 155k | M = isl_mat_left_hermite(M, 0, &U, NULL); |
940 | 155k | if (!M) |
941 | 0 | goto error; |
942 | 155k | isl_mat_free(M); |
943 | 155k | |
944 | 155k | U = isl_mat_lin_to_aff(U); |
945 | 155k | bset = isl_basic_set_preimage(bset, isl_mat_copy(U)); |
946 | 155k | |
947 | 155k | bounded = isl_basic_set_copy(bset); |
948 | 155k | bounded = isl_basic_set_drop_constraints_involving(bounded, |
949 | 155k | total - cone_dim, cone_dim); |
950 | 155k | bounded = isl_basic_set_drop_dims(bounded, total - cone_dim, cone_dim); |
951 | 155k | sample = sample_bounded(bounded); |
952 | 155k | if (!sample || sample->size == 0) { |
953 | 3.65k | isl_basic_set_free(bset); |
954 | 3.65k | isl_basic_set_free(cone); |
955 | 3.65k | isl_mat_free(U); |
956 | 3.65k | return sample; |
957 | 3.65k | } |
958 | 151k | bset = plug_in(bset, isl_vec_copy(sample)); |
959 | 151k | cone_sample = rational_sample(bset); |
960 | 151k | cone_sample = round_up_in_cone(cone_sample, cone, isl_mat_copy(U)); |
961 | 151k | sample = vec_concat(sample, cone_sample); |
962 | 151k | sample = isl_mat_vec_product(U, sample); |
963 | 151k | return sample; |
964 | 0 | error: |
965 | 0 | isl_basic_set_free(cone); |
966 | 0 | isl_basic_set_free(bset); |
967 | 0 | return NULL; |
968 | 151k | } |
969 | | |
970 | | static void vec_sum_of_neg(struct isl_vec *v, isl_int *s) |
971 | 1.00k | { |
972 | 1.00k | int i; |
973 | 1.00k | |
974 | 1.00k | isl_int_set_si(*s, 0); |
975 | 1.00k | |
976 | 3.43k | for (i = 0; i < v->size; ++i2.43k ) |
977 | 2.43k | if (isl_int_is_neg(v->el[i])) |
978 | 2.43k | isl_int_add246 (*s, *s, v->el[i]); |
979 | 1.00k | } |
980 | | |
981 | | /* Given a tableau "tab", a tableau "tab_cone" that corresponds |
982 | | * to the recession cone and the inverse of a new basis U = inv(B), |
983 | | * with the unbounded directions in B last, |
984 | | * add constraints to "tab" that ensure any rational value |
985 | | * in the unbounded directions can be rounded up to an integer value. |
986 | | * |
987 | | * The new basis is given by x' = B x, i.e., x = U x'. |
988 | | * For any rational value of the last tab->n_unbounded coordinates |
989 | | * in the update tableau, the value that is obtained by rounding |
990 | | * up this value should be contained in the original tableau. |
991 | | * For any constraint "a x + c >= 0", we therefore need to add |
992 | | * a constraint "a x + c + s >= 0", with s the sum of all negative |
993 | | * entries in the last elements of "a U". |
994 | | * |
995 | | * Since we are not interested in the first entries of any of the "a U", |
996 | | * we first drop the columns of U that correpond to bounded directions. |
997 | | */ |
998 | | static int tab_shift_cone(struct isl_tab *tab, |
999 | | struct isl_tab *tab_cone, struct isl_mat *U) |
1000 | 545 | { |
1001 | 545 | int i; |
1002 | 545 | isl_int v; |
1003 | 545 | struct isl_basic_set *bset = NULL; |
1004 | 545 | |
1005 | 545 | if (tab && tab->n_unbounded == 0) { |
1006 | 0 | isl_mat_free(U); |
1007 | 0 | return 0; |
1008 | 0 | } |
1009 | 545 | isl_int_init(v); |
1010 | 545 | if (!tab || !tab_cone || !U) |
1011 | 0 | goto error; |
1012 | 545 | bset = isl_tab_peek_bset(tab_cone); |
1013 | 545 | U = isl_mat_drop_cols(U, 0, tab->n_var - tab->n_unbounded); |
1014 | 5.10k | for (i = 0; i < bset->n_ineq; ++i4.55k ) { |
1015 | 4.55k | int ok; |
1016 | 4.55k | struct isl_vec *row = NULL; |
1017 | 4.55k | if (isl_tab_is_equality(tab_cone, tab_cone->n_eq + i)) |
1018 | 3.55k | continue; |
1019 | 1.00k | row = isl_vec_alloc(bset->ctx, tab_cone->n_var); |
1020 | 1.00k | if (!row) |
1021 | 0 | goto error; |
1022 | 1.00k | isl_seq_cpy(row->el, bset->ineq[i] + 1, tab_cone->n_var); |
1023 | 1.00k | row = isl_vec_mat_product(row, isl_mat_copy(U)); |
1024 | 1.00k | if (!row) |
1025 | 0 | goto error; |
1026 | 1.00k | vec_sum_of_neg(row, &v); |
1027 | 1.00k | isl_vec_free(row); |
1028 | 1.00k | if (isl_int_is_zero(v)) |
1029 | 1.00k | continue784 ; |
1030 | 221 | if (isl_tab_extend_cons(tab, 1) < 0) |
1031 | 0 | goto error; |
1032 | 221 | isl_int_add(bset->ineq[i][0], bset->ineq[i][0], v); |
1033 | 221 | ok = isl_tab_add_ineq(tab, bset->ineq[i]) >= 0; |
1034 | 221 | isl_int_sub(bset->ineq[i][0], bset->ineq[i][0], v); |
1035 | 221 | if (!ok) |
1036 | 0 | goto error; |
1037 | 221 | } |
1038 | 545 | |
1039 | 545 | isl_mat_free(U); |
1040 | 545 | isl_int_clear(v); |
1041 | 545 | return 0; |
1042 | 0 | error: |
1043 | 0 | isl_mat_free(U); |
1044 | 0 | isl_int_clear(v); |
1045 | 0 | return -1; |
1046 | 545 | } |
1047 | | |
1048 | | /* Compute and return an initial basis for the possibly |
1049 | | * unbounded tableau "tab". "tab_cone" is a tableau |
1050 | | * for the corresponding recession cone. |
1051 | | * Additionally, add constraints to "tab" that ensure |
1052 | | * that any rational value for the unbounded directions |
1053 | | * can be rounded up to an integer value. |
1054 | | * |
1055 | | * If the tableau is bounded, i.e., if the recession cone |
1056 | | * is zero-dimensional, then we just use inital_basis. |
1057 | | * Otherwise, we construct a basis whose first directions |
1058 | | * correspond to equalities, followed by bounded directions, |
1059 | | * i.e., equalities in the recession cone. |
1060 | | * The remaining directions are then unbounded. |
1061 | | */ |
1062 | | int isl_tab_set_initial_basis_with_cone(struct isl_tab *tab, |
1063 | | struct isl_tab *tab_cone) |
1064 | 692 | { |
1065 | 692 | struct isl_mat *eq; |
1066 | 692 | struct isl_mat *cone_eq; |
1067 | 692 | struct isl_mat *U, *Q; |
1068 | 692 | |
1069 | 692 | if (!tab || !tab_cone) |
1070 | 0 | return -1; |
1071 | 692 | |
1072 | 692 | if (tab_cone->n_col == tab_cone->n_dead) { |
1073 | 147 | tab->basis = initial_basis(tab); |
1074 | 147 | return tab->basis ? 0 : -10 ; |
1075 | 147 | } |
1076 | 545 | |
1077 | 545 | eq = tab_equalities(tab); |
1078 | 545 | if (!eq) |
1079 | 0 | return -1; |
1080 | 545 | tab->n_zero = eq->n_row; |
1081 | 545 | cone_eq = tab_equalities(tab_cone); |
1082 | 545 | eq = isl_mat_concat(eq, cone_eq); |
1083 | 545 | if (!eq) |
1084 | 0 | return -1; |
1085 | 545 | tab->n_unbounded = tab->n_var - (eq->n_row - tab->n_zero); |
1086 | 545 | eq = isl_mat_left_hermite(eq, 0, &U, &Q); |
1087 | 545 | if (!eq) |
1088 | 0 | return -1; |
1089 | 545 | isl_mat_free(eq); |
1090 | 545 | tab->basis = isl_mat_lin_to_aff(Q); |
1091 | 545 | if (tab_shift_cone(tab, tab_cone, U) < 0) |
1092 | 0 | return -1; |
1093 | 545 | if (!tab->basis) |
1094 | 0 | return -1; |
1095 | 545 | return 0; |
1096 | 545 | } |
1097 | | |
1098 | | /* Compute and return a sample point in bset using generalized basis |
1099 | | * reduction. We first check if the input set has a non-trivial |
1100 | | * recession cone. If so, we perform some extra preprocessing in |
1101 | | * sample_with_cone. Otherwise, we directly perform generalized basis |
1102 | | * reduction. |
1103 | | */ |
1104 | | static __isl_give isl_vec *gbr_sample(__isl_take isl_basic_set *bset) |
1105 | 173k | { |
1106 | 173k | unsigned dim; |
1107 | 173k | struct isl_basic_set *cone; |
1108 | 173k | |
1109 | 173k | dim = isl_basic_set_total_dim(bset); |
1110 | 173k | |
1111 | 173k | cone = isl_basic_set_recession_cone(isl_basic_set_copy(bset)); |
1112 | 173k | if (!cone) |
1113 | 0 | goto error; |
1114 | 173k | |
1115 | 173k | if (cone->n_eq < dim) |
1116 | 154k | return isl_basic_set_sample_with_cone(bset, cone); |
1117 | 18.9k | |
1118 | 18.9k | isl_basic_set_free(cone); |
1119 | 18.9k | return sample_bounded(bset); |
1120 | 0 | error: |
1121 | 0 | isl_basic_set_free(bset); |
1122 | 0 | return NULL; |
1123 | 18.9k | } |
1124 | | |
1125 | | static __isl_give isl_vec *basic_set_sample(__isl_take isl_basic_set *bset, |
1126 | | int bounded) |
1127 | 344k | { |
1128 | 344k | struct isl_ctx *ctx; |
1129 | 344k | unsigned dim; |
1130 | 344k | if (!bset) |
1131 | 0 | return NULL; |
1132 | 344k | |
1133 | 344k | ctx = bset->ctx; |
1134 | 344k | if (isl_basic_set_plain_is_empty(bset)) |
1135 | 463 | return empty_sample(bset); |
1136 | 343k | |
1137 | 343k | dim = isl_basic_set_n_dim(bset); |
1138 | 343k | isl_assert(ctx, isl_basic_set_n_param(bset) == 0, goto error); |
1139 | 343k | isl_assert(ctx, bset->n_div == 0, goto error); |
1140 | 343k | |
1141 | 343k | if (bset->sample && bset->sample->size == 1 + dim301 ) { |
1142 | 28 | int contains = isl_basic_set_contains(bset, bset->sample); |
1143 | 28 | if (contains < 0) |
1144 | 0 | goto error; |
1145 | 28 | if (contains) { |
1146 | 13 | struct isl_vec *sample = isl_vec_copy(bset->sample); |
1147 | 13 | isl_basic_set_free(bset); |
1148 | 13 | return sample; |
1149 | 13 | } |
1150 | 343k | } |
1151 | 343k | isl_vec_free(bset->sample); |
1152 | 343k | bset->sample = NULL; |
1153 | 343k | |
1154 | 343k | if (bset->n_eq > 0) |
1155 | 136k | return sample_eq(bset, bounded ? isl_basic_set_sample_bounded0 |
1156 | 136k | : isl_basic_set_sample_vec); |
1157 | 207k | if (dim == 0) |
1158 | 4.00k | return zero_sample(bset); |
1159 | 202k | if (dim == 1) |
1160 | 29.3k | return interval_sample(bset); |
1161 | 173k | |
1162 | 173k | return bounded ? sample_bounded(bset)0 : gbr_sample(bset); |
1163 | 0 | error: |
1164 | 0 | isl_basic_set_free(bset); |
1165 | 0 | return NULL; |
1166 | 173k | } |
1167 | | |
1168 | | __isl_give isl_vec *isl_basic_set_sample_vec(__isl_take isl_basic_set *bset) |
1169 | 344k | { |
1170 | 344k | return basic_set_sample(bset, 0); |
1171 | 344k | } |
1172 | | |
1173 | | /* Compute an integer sample in "bset", where the caller guarantees |
1174 | | * that "bset" is bounded. |
1175 | | */ |
1176 | | __isl_give isl_vec *isl_basic_set_sample_bounded(__isl_take isl_basic_set *bset) |
1177 | 0 | { |
1178 | 0 | return basic_set_sample(bset, 1); |
1179 | 0 | } |
1180 | | |
1181 | | __isl_give isl_basic_set *isl_basic_set_from_vec(__isl_take isl_vec *vec) |
1182 | 740k | { |
1183 | 740k | int i; |
1184 | 740k | int k; |
1185 | 740k | struct isl_basic_set *bset = NULL; |
1186 | 740k | struct isl_ctx *ctx; |
1187 | 740k | unsigned dim; |
1188 | 740k | |
1189 | 740k | if (!vec) |
1190 | 0 | return NULL; |
1191 | 740k | ctx = vec->ctx; |
1192 | 740k | isl_assert(ctx, vec->size != 0, goto error); |
1193 | 740k | |
1194 | 740k | bset = isl_basic_set_alloc(ctx, 0, vec->size - 1, 0, vec->size - 1, 0); |
1195 | 740k | if (!bset) |
1196 | 0 | goto error; |
1197 | 740k | dim = isl_basic_set_n_dim(bset); |
1198 | 3.82M | for (i = dim - 1; i >= 0; --i3.08M ) { |
1199 | 3.08M | k = isl_basic_set_alloc_equality(bset); |
1200 | 3.08M | if (k < 0) |
1201 | 0 | goto error; |
1202 | 3.08M | isl_seq_clr(bset->eq[k], 1 + dim); |
1203 | 3.08M | isl_int_neg(bset->eq[k][0], vec->el[1 + i]); |
1204 | 3.08M | isl_int_set(bset->eq[k][1 + i], vec->el[0]); |
1205 | 3.08M | } |
1206 | 740k | bset->sample = vec; |
1207 | 740k | |
1208 | 740k | return bset; |
1209 | 0 | error: |
1210 | 0 | isl_basic_set_free(bset); |
1211 | 0 | isl_vec_free(vec); |
1212 | 0 | return NULL; |
1213 | 740k | } |
1214 | | |
1215 | | __isl_give isl_basic_map *isl_basic_map_sample(__isl_take isl_basic_map *bmap) |
1216 | 1 | { |
1217 | 1 | struct isl_basic_set *bset; |
1218 | 1 | struct isl_vec *sample_vec; |
1219 | 1 | |
1220 | 1 | bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap)); |
1221 | 1 | sample_vec = isl_basic_set_sample_vec(bset); |
1222 | 1 | if (!sample_vec) |
1223 | 0 | goto error; |
1224 | 1 | if (sample_vec->size == 0) { |
1225 | 0 | isl_vec_free(sample_vec); |
1226 | 0 | return isl_basic_map_set_to_empty(bmap); |
1227 | 0 | } |
1228 | 1 | isl_vec_free(bmap->sample); |
1229 | 1 | bmap->sample = isl_vec_copy(sample_vec); |
1230 | 1 | bset = isl_basic_set_from_vec(sample_vec); |
1231 | 1 | return isl_basic_map_overlying_set(bset, bmap); |
1232 | 0 | error: |
1233 | 0 | isl_basic_map_free(bmap); |
1234 | 0 | return NULL; |
1235 | 1 | } |
1236 | | |
1237 | | __isl_give isl_basic_set *isl_basic_set_sample(__isl_take isl_basic_set *bset) |
1238 | 1 | { |
1239 | 1 | return isl_basic_map_sample(bset); |
1240 | 1 | } |
1241 | | |
1242 | | __isl_give isl_basic_map *isl_map_sample(__isl_take isl_map *map) |
1243 | 0 | { |
1244 | 0 | int i; |
1245 | 0 | isl_basic_map *sample = NULL; |
1246 | 0 |
|
1247 | 0 | if (!map) |
1248 | 0 | goto error; |
1249 | 0 | |
1250 | 0 | for (i = 0; i < map->n; ++i) { |
1251 | 0 | sample = isl_basic_map_sample(isl_basic_map_copy(map->p[i])); |
1252 | 0 | if (!sample) |
1253 | 0 | goto error; |
1254 | 0 | if (!ISL_F_ISSET(sample, ISL_BASIC_MAP_EMPTY)) |
1255 | 0 | break; |
1256 | 0 | isl_basic_map_free(sample); |
1257 | 0 | } |
1258 | 0 | if (i == map->n) |
1259 | 0 | sample = isl_basic_map_empty(isl_map_get_space(map)); |
1260 | 0 | isl_map_free(map); |
1261 | 0 | return sample; |
1262 | 0 | error: |
1263 | 0 | isl_map_free(map); |
1264 | 0 | return NULL; |
1265 | 0 | } |
1266 | | |
1267 | | __isl_give isl_basic_set *isl_set_sample(__isl_take isl_set *set) |
1268 | 0 | { |
1269 | 0 | return bset_from_bmap(isl_map_sample(set_to_map(set))); |
1270 | 0 | } |
1271 | | |
1272 | | __isl_give isl_point *isl_basic_set_sample_point(__isl_take isl_basic_set *bset) |
1273 | 22 | { |
1274 | 22 | isl_vec *vec; |
1275 | 22 | isl_space *dim; |
1276 | 22 | |
1277 | 22 | dim = isl_basic_set_get_space(bset); |
1278 | 22 | bset = isl_basic_set_underlying_set(bset); |
1279 | 22 | vec = isl_basic_set_sample_vec(bset); |
1280 | 22 | |
1281 | 22 | return isl_point_alloc(dim, vec); |
1282 | 22 | } |
1283 | | |
1284 | | __isl_give isl_point *isl_set_sample_point(__isl_take isl_set *set) |
1285 | 25 | { |
1286 | 25 | int i; |
1287 | 25 | isl_point *pnt; |
1288 | 25 | |
1289 | 25 | if (!set) |
1290 | 0 | return NULL; |
1291 | 25 | |
1292 | 25 | for (i = 0; i < set->n; ++i0 ) { |
1293 | 22 | pnt = isl_basic_set_sample_point(isl_basic_set_copy(set->p[i])); |
1294 | 22 | if (!pnt) |
1295 | 0 | goto error; |
1296 | 22 | if (!isl_point_is_void(pnt)) |
1297 | 22 | break; |
1298 | 0 | isl_point_free(pnt); |
1299 | 0 | } |
1300 | 25 | if (i == set->n) |
1301 | 3 | pnt = isl_point_void(isl_set_get_space(set)); |
1302 | 25 | |
1303 | 25 | isl_set_free(set); |
1304 | 25 | return pnt; |
1305 | 0 | error: |
1306 | 0 | isl_set_free(set); |
1307 | 0 | return NULL; |
1308 | 25 | } |