isl_vertices.c revision 1.1 1 1.1 mrg /*
2 1.1 mrg * Copyright 2010 INRIA Saclay
3 1.1 mrg *
4 1.1 mrg * Use of this software is governed by the MIT license
5 1.1 mrg *
6 1.1 mrg * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
7 1.1 mrg * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
8 1.1 mrg * 91893 Orsay, France
9 1.1 mrg */
10 1.1 mrg
11 1.1 mrg #include <isl_map_private.h>
12 1.1 mrg #include <isl_aff_private.h>
13 1.1 mrg #include <isl/set.h>
14 1.1 mrg #include <isl_seq.h>
15 1.1 mrg #include <isl_tab.h>
16 1.1 mrg #include <isl_space_private.h>
17 1.1 mrg #include <isl_morph.h>
18 1.1 mrg #include <isl_vertices_private.h>
19 1.1 mrg #include <isl_mat_private.h>
20 1.1 mrg #include <isl_vec_private.h>
21 1.1 mrg
22 1.1 mrg #define SELECTED 1
23 1.1 mrg #define DESELECTED -1
24 1.1 mrg #define UNSELECTED 0
25 1.1 mrg
26 1.1 mrg static __isl_give isl_vertices *compute_chambers(__isl_take isl_basic_set *bset,
27 1.1 mrg __isl_take isl_vertices *vertices);
28 1.1 mrg
29 1.1 mrg __isl_give isl_vertices *isl_vertices_copy(__isl_keep isl_vertices *vertices)
30 1.1 mrg {
31 1.1 mrg if (!vertices)
32 1.1 mrg return NULL;
33 1.1 mrg
34 1.1 mrg vertices->ref++;
35 1.1 mrg return vertices;
36 1.1 mrg }
37 1.1 mrg
38 1.1 mrg __isl_null isl_vertices *isl_vertices_free(__isl_take isl_vertices *vertices)
39 1.1 mrg {
40 1.1 mrg int i;
41 1.1 mrg
42 1.1 mrg if (!vertices)
43 1.1 mrg return NULL;
44 1.1 mrg
45 1.1 mrg if (--vertices->ref > 0)
46 1.1 mrg return NULL;
47 1.1 mrg
48 1.1 mrg for (i = 0; i < vertices->n_vertices; ++i) {
49 1.1 mrg isl_basic_set_free(vertices->v[i].vertex);
50 1.1 mrg isl_basic_set_free(vertices->v[i].dom);
51 1.1 mrg }
52 1.1 mrg free(vertices->v);
53 1.1 mrg
54 1.1 mrg for (i = 0; i < vertices->n_chambers; ++i) {
55 1.1 mrg free(vertices->c[i].vertices);
56 1.1 mrg isl_basic_set_free(vertices->c[i].dom);
57 1.1 mrg }
58 1.1 mrg free(vertices->c);
59 1.1 mrg
60 1.1 mrg isl_basic_set_free(vertices->bset);
61 1.1 mrg free(vertices);
62 1.1 mrg
63 1.1 mrg return NULL;
64 1.1 mrg }
65 1.1 mrg
66 1.1 mrg struct isl_vertex_list {
67 1.1 mrg struct isl_vertex v;
68 1.1 mrg struct isl_vertex_list *next;
69 1.1 mrg };
70 1.1 mrg
71 1.1 mrg static struct isl_vertex_list *free_vertex_list(struct isl_vertex_list *list)
72 1.1 mrg {
73 1.1 mrg struct isl_vertex_list *next;
74 1.1 mrg
75 1.1 mrg for (; list; list = next) {
76 1.1 mrg next = list->next;
77 1.1 mrg isl_basic_set_free(list->v.vertex);
78 1.1 mrg isl_basic_set_free(list->v.dom);
79 1.1 mrg free(list);
80 1.1 mrg }
81 1.1 mrg
82 1.1 mrg return NULL;
83 1.1 mrg }
84 1.1 mrg
85 1.1 mrg static __isl_give isl_vertices *vertices_from_list(__isl_keep isl_basic_set *bset,
86 1.1 mrg int n_vertices, struct isl_vertex_list *list)
87 1.1 mrg {
88 1.1 mrg int i;
89 1.1 mrg struct isl_vertex_list *next;
90 1.1 mrg isl_vertices *vertices;
91 1.1 mrg
92 1.1 mrg vertices = isl_calloc_type(bset->ctx, isl_vertices);
93 1.1 mrg if (!vertices)
94 1.1 mrg goto error;
95 1.1 mrg vertices->ref = 1;
96 1.1 mrg vertices->bset = isl_basic_set_copy(bset);
97 1.1 mrg vertices->v = isl_alloc_array(bset->ctx, struct isl_vertex, n_vertices);
98 1.1 mrg if (n_vertices && !vertices->v)
99 1.1 mrg goto error;
100 1.1 mrg vertices->n_vertices = n_vertices;
101 1.1 mrg
102 1.1 mrg for (i = 0; list; list = next, i++) {
103 1.1 mrg next = list->next;
104 1.1 mrg vertices->v[i] = list->v;
105 1.1 mrg free(list);
106 1.1 mrg }
107 1.1 mrg
108 1.1 mrg return vertices;
109 1.1 mrg error:
110 1.1 mrg isl_vertices_free(vertices);
111 1.1 mrg free_vertex_list(list);
112 1.1 mrg return NULL;
113 1.1 mrg }
114 1.1 mrg
115 1.1 mrg /* Prepend a vertex to the linked list "list" based on the equalities in "tab".
116 1.1 mrg * Return isl_bool_true if the vertex was actually added and
117 1.1 mrg * isl_bool_false otherwise.
118 1.1 mrg * In particular, vertices with a lower-dimensional activity domain are
119 1.1 mrg * not added to the list because they would not be included in any chamber.
120 1.1 mrg * Return isl_bool_error on error.
121 1.1 mrg */
122 1.1 mrg static isl_bool add_vertex(struct isl_vertex_list **list,
123 1.1 mrg __isl_keep isl_basic_set *bset, struct isl_tab *tab)
124 1.1 mrg {
125 1.1 mrg isl_size nvar;
126 1.1 mrg struct isl_vertex_list *v = NULL;
127 1.1 mrg
128 1.1 mrg if (isl_tab_detect_implicit_equalities(tab) < 0)
129 1.1 mrg return isl_bool_error;
130 1.1 mrg
131 1.1 mrg nvar = isl_basic_set_dim(bset, isl_dim_set);
132 1.1 mrg if (nvar < 0)
133 1.1 mrg return isl_bool_error;
134 1.1 mrg
135 1.1 mrg v = isl_calloc_type(tab->mat->ctx, struct isl_vertex_list);
136 1.1 mrg if (!v)
137 1.1 mrg goto error;
138 1.1 mrg
139 1.1 mrg v->v.vertex = isl_basic_set_copy(bset);
140 1.1 mrg v->v.vertex = isl_basic_set_cow(v->v.vertex);
141 1.1 mrg v->v.vertex = isl_basic_set_update_from_tab(v->v.vertex, tab);
142 1.1 mrg v->v.vertex = isl_basic_set_simplify(v->v.vertex);
143 1.1 mrg v->v.vertex = isl_basic_set_finalize(v->v.vertex);
144 1.1 mrg if (!v->v.vertex)
145 1.1 mrg goto error;
146 1.1 mrg isl_assert(bset->ctx, v->v.vertex->n_eq >= nvar, goto error);
147 1.1 mrg v->v.dom = isl_basic_set_copy(v->v.vertex);
148 1.1 mrg v->v.dom = isl_basic_set_params(v->v.dom);
149 1.1 mrg if (!v->v.dom)
150 1.1 mrg goto error;
151 1.1 mrg
152 1.1 mrg if (v->v.dom->n_eq > 0) {
153 1.1 mrg free_vertex_list(v);
154 1.1 mrg return isl_bool_false;
155 1.1 mrg }
156 1.1 mrg
157 1.1 mrg v->next = *list;
158 1.1 mrg *list = v;
159 1.1 mrg
160 1.1 mrg return isl_bool_true;
161 1.1 mrg error:
162 1.1 mrg free_vertex_list(v);
163 1.1 mrg return isl_bool_error;
164 1.1 mrg }
165 1.1 mrg
166 1.1 mrg /* Compute the parametric vertices and the chamber decomposition
167 1.1 mrg * of an empty parametric polytope.
168 1.1 mrg */
169 1.1 mrg static __isl_give isl_vertices *vertices_empty(__isl_keep isl_basic_set *bset)
170 1.1 mrg {
171 1.1 mrg isl_vertices *vertices;
172 1.1 mrg
173 1.1 mrg if (!bset)
174 1.1 mrg return NULL;
175 1.1 mrg
176 1.1 mrg vertices = isl_calloc_type(bset->ctx, isl_vertices);
177 1.1 mrg if (!vertices)
178 1.1 mrg return NULL;
179 1.1 mrg vertices->bset = isl_basic_set_copy(bset);
180 1.1 mrg vertices->ref = 1;
181 1.1 mrg
182 1.1 mrg vertices->n_vertices = 0;
183 1.1 mrg vertices->n_chambers = 0;
184 1.1 mrg
185 1.1 mrg return vertices;
186 1.1 mrg }
187 1.1 mrg
188 1.1 mrg /* Compute the parametric vertices and the chamber decomposition
189 1.1 mrg * of the parametric polytope defined using the same constraints
190 1.1 mrg * as "bset" in the 0D case.
191 1.1 mrg * There is exactly one 0D vertex and a single chamber containing
192 1.1 mrg * the vertex.
193 1.1 mrg */
194 1.1 mrg static __isl_give isl_vertices *vertices_0D(__isl_keep isl_basic_set *bset)
195 1.1 mrg {
196 1.1 mrg isl_vertices *vertices;
197 1.1 mrg
198 1.1 mrg if (!bset)
199 1.1 mrg return NULL;
200 1.1 mrg
201 1.1 mrg vertices = isl_calloc_type(bset->ctx, isl_vertices);
202 1.1 mrg if (!vertices)
203 1.1 mrg return NULL;
204 1.1 mrg vertices->ref = 1;
205 1.1 mrg vertices->bset = isl_basic_set_copy(bset);
206 1.1 mrg
207 1.1 mrg vertices->v = isl_calloc_array(bset->ctx, struct isl_vertex, 1);
208 1.1 mrg if (!vertices->v)
209 1.1 mrg goto error;
210 1.1 mrg vertices->n_vertices = 1;
211 1.1 mrg vertices->v[0].vertex = isl_basic_set_copy(bset);
212 1.1 mrg vertices->v[0].dom = isl_basic_set_params(isl_basic_set_copy(bset));
213 1.1 mrg if (!vertices->v[0].vertex || !vertices->v[0].dom)
214 1.1 mrg goto error;
215 1.1 mrg
216 1.1 mrg vertices->c = isl_calloc_array(bset->ctx, struct isl_chamber, 1);
217 1.1 mrg if (!vertices->c)
218 1.1 mrg goto error;
219 1.1 mrg vertices->n_chambers = 1;
220 1.1 mrg vertices->c[0].n_vertices = 1;
221 1.1 mrg vertices->c[0].vertices = isl_calloc_array(bset->ctx, int, 1);
222 1.1 mrg if (!vertices->c[0].vertices)
223 1.1 mrg goto error;
224 1.1 mrg vertices->c[0].dom = isl_basic_set_copy(vertices->v[0].dom);
225 1.1 mrg if (!vertices->c[0].dom)
226 1.1 mrg goto error;
227 1.1 mrg
228 1.1 mrg return vertices;
229 1.1 mrg error:
230 1.1 mrg isl_vertices_free(vertices);
231 1.1 mrg return NULL;
232 1.1 mrg }
233 1.1 mrg
234 1.1 mrg /* Is the row pointed to by "f" linearly independent of the "n" first
235 1.1 mrg * rows in "facets"?
236 1.1 mrg */
237 1.1 mrg static isl_bool is_independent(__isl_keep isl_mat *facets, int n, isl_int *f)
238 1.1 mrg {
239 1.1 mrg isl_size rank;
240 1.1 mrg
241 1.1 mrg if (isl_seq_first_non_zero(f, facets->n_col) < 0)
242 1.1 mrg return isl_bool_false;
243 1.1 mrg
244 1.1 mrg isl_seq_cpy(facets->row[n], f, facets->n_col);
245 1.1 mrg facets->n_row = n + 1;
246 1.1 mrg rank = isl_mat_rank(facets);
247 1.1 mrg if (rank < 0)
248 1.1 mrg return isl_bool_error;
249 1.1 mrg
250 1.1 mrg return isl_bool_ok(rank == n + 1);
251 1.1 mrg }
252 1.1 mrg
253 1.1 mrg /* Check whether we can select constraint "level", given the current selection
254 1.1 mrg * reflected by facets in "tab", the rows of "facets" and the earlier
255 1.1 mrg * "selected" elements of "selection".
256 1.1 mrg *
257 1.1 mrg * If the constraint is (strictly) redundant in the tableau, selecting it would
258 1.1 mrg * result in an empty tableau, so it can't be selected.
259 1.1 mrg * If the set variable part of the constraint is not linearly independent
260 1.1 mrg * of the set variable parts of the already selected constraints,
261 1.1 mrg * the constraint cannot be selected.
262 1.1 mrg * If selecting the constraint results in an empty tableau, the constraint
263 1.1 mrg * cannot be selected.
264 1.1 mrg * Finally, if selecting the constraint results in some explicitly
265 1.1 mrg * deselected constraints turning into equalities, then the corresponding
266 1.1 mrg * vertices have already been generated, so the constraint cannot be selected.
267 1.1 mrg */
268 1.1 mrg static isl_bool can_select(__isl_keep isl_basic_set *bset, int level,
269 1.1 mrg struct isl_tab *tab, __isl_keep isl_mat *facets, int selected,
270 1.1 mrg int *selection)
271 1.1 mrg {
272 1.1 mrg int i;
273 1.1 mrg isl_bool indep;
274 1.1 mrg isl_size ovar;
275 1.1 mrg struct isl_tab_undo *snap;
276 1.1 mrg
277 1.1 mrg if (isl_tab_is_redundant(tab, level))
278 1.1 mrg return isl_bool_false;
279 1.1 mrg
280 1.1 mrg ovar = isl_space_offset(bset->dim, isl_dim_set);
281 1.1 mrg if (ovar < 0)
282 1.1 mrg return isl_bool_error;
283 1.1 mrg
284 1.1 mrg indep = is_independent(facets, selected, bset->ineq[level] + 1 + ovar);
285 1.1 mrg if (indep < 0 || !indep)
286 1.1 mrg return indep;
287 1.1 mrg
288 1.1 mrg snap = isl_tab_snap(tab);
289 1.1 mrg if (isl_tab_select_facet(tab, level) < 0)
290 1.1 mrg return isl_bool_error;
291 1.1 mrg
292 1.1 mrg if (tab->empty) {
293 1.1 mrg if (isl_tab_rollback(tab, snap) < 0)
294 1.1 mrg return isl_bool_error;
295 1.1 mrg return isl_bool_false;
296 1.1 mrg }
297 1.1 mrg
298 1.1 mrg for (i = 0; i < level; ++i) {
299 1.1 mrg int sgn;
300 1.1 mrg
301 1.1 mrg if (selection[i] != DESELECTED)
302 1.1 mrg continue;
303 1.1 mrg
304 1.1 mrg if (isl_tab_is_equality(tab, i))
305 1.1 mrg sgn = 0;
306 1.1 mrg else if (isl_tab_is_redundant(tab, i))
307 1.1 mrg sgn = 1;
308 1.1 mrg else
309 1.1 mrg sgn = isl_tab_sign_of_max(tab, i);
310 1.1 mrg if (sgn < -1)
311 1.1 mrg return isl_bool_error;
312 1.1 mrg if (sgn <= 0) {
313 1.1 mrg if (isl_tab_rollback(tab, snap) < 0)
314 1.1 mrg return isl_bool_error;
315 1.1 mrg return isl_bool_false;
316 1.1 mrg }
317 1.1 mrg }
318 1.1 mrg
319 1.1 mrg return isl_bool_true;
320 1.1 mrg }
321 1.1 mrg
322 1.1 mrg /* Compute the parametric vertices and the chamber decomposition
323 1.1 mrg * of a parametric polytope that is not full-dimensional.
324 1.1 mrg *
325 1.1 mrg * Simply map the parametric polytope to a lower dimensional space
326 1.1 mrg * and map the resulting vertices back.
327 1.1 mrg */
328 1.1 mrg static __isl_give isl_vertices *lower_dim_vertices(
329 1.1 mrg __isl_take isl_basic_set *bset)
330 1.1 mrg {
331 1.1 mrg isl_morph *morph;
332 1.1 mrg isl_vertices *vertices;
333 1.1 mrg
334 1.1 mrg morph = isl_basic_set_full_compression(bset);
335 1.1 mrg bset = isl_morph_basic_set(isl_morph_copy(morph), bset);
336 1.1 mrg
337 1.1 mrg vertices = isl_basic_set_compute_vertices(bset);
338 1.1 mrg isl_basic_set_free(bset);
339 1.1 mrg
340 1.1 mrg morph = isl_morph_inverse(morph);
341 1.1 mrg
342 1.1 mrg vertices = isl_morph_vertices(morph, vertices);
343 1.1 mrg
344 1.1 mrg return vertices;
345 1.1 mrg }
346 1.1 mrg
347 1.1 mrg /* Compute the parametric vertices and the chamber decomposition
348 1.1 mrg * of a parametric polytope "bset" that is not full-dimensional.
349 1.1 mrg * Additionally, free both "copy" and "tab".
350 1.1 mrg */
351 1.1 mrg static __isl_give isl_vertices *lower_dim_vertices_free(
352 1.1 mrg __isl_take isl_basic_set *bset, __isl_take isl_basic_set *copy,
353 1.1 mrg struct isl_tab *tab)
354 1.1 mrg {
355 1.1 mrg isl_basic_set_free(copy);
356 1.1 mrg isl_tab_free(tab);
357 1.1 mrg return lower_dim_vertices(bset);
358 1.1 mrg }
359 1.1 mrg
360 1.1 mrg /* Detect implicit equality constraints in "bset" using the tableau
361 1.1 mrg * representation "tab".
362 1.1 mrg * Return a copy of "bset" with the implicit equality constraints
363 1.1 mrg * made explicit, leaving the original "bset" unmodified.
364 1.1 mrg */
365 1.1 mrg static __isl_give isl_basic_set *detect_implicit_equality_constraints(
366 1.1 mrg __isl_keep isl_basic_set *bset, struct isl_tab *tab)
367 1.1 mrg {
368 1.1 mrg if (isl_tab_detect_implicit_equalities(tab) < 0)
369 1.1 mrg return NULL;
370 1.1 mrg
371 1.1 mrg bset = isl_basic_set_copy(bset);
372 1.1 mrg bset = isl_basic_set_cow(bset);
373 1.1 mrg bset = isl_basic_set_update_from_tab(bset, tab);
374 1.1 mrg
375 1.1 mrg return bset;
376 1.1 mrg }
377 1.1 mrg
378 1.1 mrg /* Compute the parametric vertices and the chamber decomposition
379 1.1 mrg * of the parametric polytope defined using the same constraints
380 1.1 mrg * as "bset". "bset" is assumed to have no existentially quantified
381 1.1 mrg * variables.
382 1.1 mrg *
383 1.1 mrg * The vertices themselves are computed in a fairly simplistic way.
384 1.1 mrg * We simply run through all combinations of d constraints,
385 1.1 mrg * with d the number of set variables, and check if those d constraints
386 1.1 mrg * define a vertex. To avoid the generation of duplicate vertices,
387 1.1 mrg * which may happen if a vertex is defined by more than d constraints,
388 1.1 mrg * we make sure we only generate the vertex for the d constraints with
389 1.1 mrg * smallest index.
390 1.1 mrg *
391 1.1 mrg * Only potential vertices with a full-dimensional activity domain
392 1.1 mrg * are considered. However, if the input has (implicit) equality
393 1.1 mrg * constraints among the parameters, then activity domain
394 1.1 mrg * should be considered full-dimensional if it does not satisfy
395 1.1 mrg * any extra equality constraints beyond those of the input.
396 1.1 mrg * The implicit equality constraints of the input are therefore first detected.
397 1.1 mrg * If there are any, then the input is mapped to a lower dimensional space
398 1.1 mrg * such that the check for full-dimensional activity domains
399 1.1 mrg * can be performed with respect to a full-dimensional space.
400 1.1 mrg * Note that it is important to leave "bset" unmodified while detecting
401 1.1 mrg * equality constraints since the inequality constraints of "bset"
402 1.1 mrg * are assumed to correspond to those of the tableau.
403 1.1 mrg *
404 1.1 mrg * We set up a tableau and keep track of which facets have been
405 1.1 mrg * selected. The tableau is marked strict_redundant so that we can be
406 1.1 mrg * sure that any constraint that is marked redundant (and that is not
407 1.1 mrg * also marked zero) is not an equality.
408 1.1 mrg * If a constraint is marked DESELECTED, it means the constraint was
409 1.1 mrg * SELECTED before (in combination with the same selection of earlier
410 1.1 mrg * constraints). If such a deselected constraint turns out to be an
411 1.1 mrg * equality, then any vertex that may still be found with the current
412 1.1 mrg * selection has already been generated when the constraint was selected.
413 1.1 mrg * A constraint is marked UNSELECTED when there is no way selecting
414 1.1 mrg * the constraint could lead to a vertex (in combination with the current
415 1.1 mrg * selection of earlier constraints).
416 1.1 mrg *
417 1.1 mrg * The set variable coefficients of the selected constraints are stored
418 1.1 mrg * in the facets matrix.
419 1.1 mrg */
420 1.1 mrg __isl_give isl_vertices *isl_basic_set_compute_vertices(
421 1.1 mrg __isl_keep isl_basic_set *bset)
422 1.1 mrg {
423 1.1 mrg struct isl_tab *tab;
424 1.1 mrg int level;
425 1.1 mrg int init;
426 1.1 mrg isl_size n_eq;
427 1.1 mrg isl_size nvar;
428 1.1 mrg int *selection = NULL;
429 1.1 mrg int selected;
430 1.1 mrg struct isl_tab_undo **snap = NULL;
431 1.1 mrg isl_mat *facets = NULL;
432 1.1 mrg struct isl_vertex_list *list = NULL;
433 1.1 mrg int n_vertices = 0;
434 1.1 mrg isl_vertices *vertices;
435 1.1 mrg isl_basic_set *copy;
436 1.1 mrg isl_basic_set *test;
437 1.1 mrg
438 1.1 mrg if (!bset)
439 1.1 mrg return NULL;
440 1.1 mrg
441 1.1 mrg if (isl_basic_set_plain_is_empty(bset))
442 1.1 mrg return vertices_empty(bset);
443 1.1 mrg
444 1.1 mrg if (bset->n_eq != 0)
445 1.1 mrg return lower_dim_vertices(isl_basic_set_copy(bset));
446 1.1 mrg
447 1.1 mrg if (isl_basic_set_check_no_locals(bset) < 0)
448 1.1 mrg return NULL;
449 1.1 mrg
450 1.1 mrg nvar = isl_basic_set_dim(bset, isl_dim_set);
451 1.1 mrg if (nvar < 0)
452 1.1 mrg return NULL;
453 1.1 mrg if (nvar == 0)
454 1.1 mrg return vertices_0D(bset);
455 1.1 mrg
456 1.1 mrg copy = isl_basic_set_copy(bset);
457 1.1 mrg copy = isl_basic_set_set_rational(copy);
458 1.1 mrg if (!copy)
459 1.1 mrg return NULL;
460 1.1 mrg
461 1.1 mrg tab = isl_tab_from_basic_set(copy, 0);
462 1.1 mrg if (!tab)
463 1.1 mrg goto error;
464 1.1 mrg tab->strict_redundant = 1;
465 1.1 mrg
466 1.1 mrg if (tab->empty) {
467 1.1 mrg vertices = vertices_empty(copy);
468 1.1 mrg isl_basic_set_free(copy);
469 1.1 mrg isl_tab_free(tab);
470 1.1 mrg return vertices;
471 1.1 mrg }
472 1.1 mrg
473 1.1 mrg test = detect_implicit_equality_constraints(bset, tab);
474 1.1 mrg n_eq = isl_basic_set_n_equality(test);
475 1.1 mrg if (n_eq < 0)
476 1.1 mrg test = isl_basic_set_free(test);
477 1.1 mrg if (n_eq < 0 || n_eq > 0)
478 1.1 mrg return lower_dim_vertices_free(test, copy, tab);
479 1.1 mrg isl_basic_set_free(test);
480 1.1 mrg
481 1.1 mrg selection = isl_alloc_array(copy->ctx, int, copy->n_ineq);
482 1.1 mrg snap = isl_alloc_array(copy->ctx, struct isl_tab_undo *, copy->n_ineq);
483 1.1 mrg facets = isl_mat_alloc(copy->ctx, nvar, nvar);
484 1.1 mrg if ((copy->n_ineq && (!selection || !snap)) || !facets)
485 1.1 mrg goto error;
486 1.1 mrg
487 1.1 mrg level = 0;
488 1.1 mrg init = 1;
489 1.1 mrg selected = 0;
490 1.1 mrg
491 1.1 mrg while (level >= 0) {
492 1.1 mrg if (level >= copy->n_ineq ||
493 1.1 mrg (!init && selection[level] != SELECTED)) {
494 1.1 mrg --level;
495 1.1 mrg init = 0;
496 1.1 mrg continue;
497 1.1 mrg }
498 1.1 mrg if (init) {
499 1.1 mrg isl_bool ok;
500 1.1 mrg snap[level] = isl_tab_snap(tab);
501 1.1 mrg ok = can_select(copy, level, tab, facets, selected,
502 1.1 mrg selection);
503 1.1 mrg if (ok < 0)
504 1.1 mrg goto error;
505 1.1 mrg if (ok) {
506 1.1 mrg selection[level] = SELECTED;
507 1.1 mrg selected++;
508 1.1 mrg } else
509 1.1 mrg selection[level] = UNSELECTED;
510 1.1 mrg } else {
511 1.1 mrg selection[level] = DESELECTED;
512 1.1 mrg selected--;
513 1.1 mrg if (isl_tab_rollback(tab, snap[level]) < 0)
514 1.1 mrg goto error;
515 1.1 mrg }
516 1.1 mrg if (selected == nvar) {
517 1.1 mrg if (tab->n_dead == nvar) {
518 1.1 mrg isl_bool added = add_vertex(&list, copy, tab);
519 1.1 mrg if (added < 0)
520 1.1 mrg goto error;
521 1.1 mrg if (added)
522 1.1 mrg n_vertices++;
523 1.1 mrg }
524 1.1 mrg init = 0;
525 1.1 mrg continue;
526 1.1 mrg }
527 1.1 mrg ++level;
528 1.1 mrg init = 1;
529 1.1 mrg }
530 1.1 mrg
531 1.1 mrg isl_mat_free(facets);
532 1.1 mrg free(selection);
533 1.1 mrg free(snap);
534 1.1 mrg
535 1.1 mrg isl_tab_free(tab);
536 1.1 mrg
537 1.1 mrg vertices = vertices_from_list(copy, n_vertices, list);
538 1.1 mrg
539 1.1 mrg vertices = compute_chambers(copy, vertices);
540 1.1 mrg
541 1.1 mrg return vertices;
542 1.1 mrg error:
543 1.1 mrg free_vertex_list(list);
544 1.1 mrg isl_mat_free(facets);
545 1.1 mrg free(selection);
546 1.1 mrg free(snap);
547 1.1 mrg isl_tab_free(tab);
548 1.1 mrg isl_basic_set_free(copy);
549 1.1 mrg return NULL;
550 1.1 mrg }
551 1.1 mrg
552 1.1 mrg struct isl_chamber_list {
553 1.1 mrg struct isl_chamber c;
554 1.1 mrg struct isl_chamber_list *next;
555 1.1 mrg };
556 1.1 mrg
557 1.1 mrg static void free_chamber_list(struct isl_chamber_list *list)
558 1.1 mrg {
559 1.1 mrg struct isl_chamber_list *next;
560 1.1 mrg
561 1.1 mrg for (; list; list = next) {
562 1.1 mrg next = list->next;
563 1.1 mrg isl_basic_set_free(list->c.dom);
564 1.1 mrg free(list->c.vertices);
565 1.1 mrg free(list);
566 1.1 mrg }
567 1.1 mrg }
568 1.1 mrg
569 1.1 mrg /* Check whether the basic set "bset" is a superset of the basic set described
570 1.1 mrg * by "tab", i.e., check whether all constraints of "bset" are redundant.
571 1.1 mrg */
572 1.1 mrg static isl_bool bset_covers_tab(__isl_keep isl_basic_set *bset,
573 1.1 mrg struct isl_tab *tab)
574 1.1 mrg {
575 1.1 mrg int i;
576 1.1 mrg
577 1.1 mrg if (!bset || !tab)
578 1.1 mrg return isl_bool_error;
579 1.1 mrg
580 1.1 mrg for (i = 0; i < bset->n_ineq; ++i) {
581 1.1 mrg enum isl_ineq_type type = isl_tab_ineq_type(tab, bset->ineq[i]);
582 1.1 mrg switch (type) {
583 1.1 mrg case isl_ineq_error: return isl_bool_error;
584 1.1 mrg case isl_ineq_redundant: continue;
585 1.1 mrg default: return isl_bool_false;
586 1.1 mrg }
587 1.1 mrg }
588 1.1 mrg
589 1.1 mrg return isl_bool_true;
590 1.1 mrg }
591 1.1 mrg
592 1.1 mrg static __isl_give isl_vertices *vertices_add_chambers(
593 1.1 mrg __isl_take isl_vertices *vertices, int n_chambers,
594 1.1 mrg struct isl_chamber_list *list)
595 1.1 mrg {
596 1.1 mrg int i;
597 1.1 mrg isl_ctx *ctx;
598 1.1 mrg struct isl_chamber_list *next;
599 1.1 mrg
600 1.1 mrg ctx = isl_vertices_get_ctx(vertices);
601 1.1 mrg vertices->c = isl_alloc_array(ctx, struct isl_chamber, n_chambers);
602 1.1 mrg if (!vertices->c)
603 1.1 mrg goto error;
604 1.1 mrg vertices->n_chambers = n_chambers;
605 1.1 mrg
606 1.1 mrg for (i = 0; list; list = next, i++) {
607 1.1 mrg next = list->next;
608 1.1 mrg vertices->c[i] = list->c;
609 1.1 mrg free(list);
610 1.1 mrg }
611 1.1 mrg
612 1.1 mrg return vertices;
613 1.1 mrg error:
614 1.1 mrg isl_vertices_free(vertices);
615 1.1 mrg free_chamber_list(list);
616 1.1 mrg return NULL;
617 1.1 mrg }
618 1.1 mrg
619 1.1 mrg /* Can "tab" be intersected with "bset" without resulting in
620 1.1 mrg * a lower-dimensional set.
621 1.1 mrg * "bset" itself is assumed to be full-dimensional.
622 1.1 mrg */
623 1.1 mrg static isl_bool can_intersect(struct isl_tab *tab,
624 1.1 mrg __isl_keep isl_basic_set *bset)
625 1.1 mrg {
626 1.1 mrg int i;
627 1.1 mrg struct isl_tab_undo *snap;
628 1.1 mrg
629 1.1 mrg if (bset->n_eq > 0)
630 1.1 mrg isl_die(isl_basic_set_get_ctx(bset), isl_error_internal,
631 1.1 mrg "expecting full-dimensional input",
632 1.1 mrg return isl_bool_error);
633 1.1 mrg
634 1.1 mrg if (isl_tab_extend_cons(tab, bset->n_ineq) < 0)
635 1.1 mrg return isl_bool_error;
636 1.1 mrg
637 1.1 mrg snap = isl_tab_snap(tab);
638 1.1 mrg
639 1.1 mrg for (i = 0; i < bset->n_ineq; ++i) {
640 1.1 mrg enum isl_ineq_type type;
641 1.1 mrg
642 1.1 mrg type = isl_tab_ineq_type(tab, bset->ineq[i]);
643 1.1 mrg if (type < 0)
644 1.1 mrg return isl_bool_error;
645 1.1 mrg if (type == isl_ineq_redundant)
646 1.1 mrg continue;
647 1.1 mrg if (isl_tab_add_ineq(tab, bset->ineq[i]) < 0)
648 1.1 mrg return isl_bool_error;
649 1.1 mrg }
650 1.1 mrg
651 1.1 mrg if (isl_tab_detect_implicit_equalities(tab) < 0)
652 1.1 mrg return isl_bool_error;
653 1.1 mrg if (tab->n_dead) {
654 1.1 mrg if (isl_tab_rollback(tab, snap) < 0)
655 1.1 mrg return isl_bool_error;
656 1.1 mrg return isl_bool_false;
657 1.1 mrg }
658 1.1 mrg
659 1.1 mrg return isl_bool_true;
660 1.1 mrg }
661 1.1 mrg
662 1.1 mrg static int add_chamber(struct isl_chamber_list **list,
663 1.1 mrg __isl_keep isl_vertices *vertices, struct isl_tab *tab, int *selection)
664 1.1 mrg {
665 1.1 mrg int n_frozen;
666 1.1 mrg int i, j;
667 1.1 mrg int n_vertices = 0;
668 1.1 mrg struct isl_tab_undo *snap;
669 1.1 mrg struct isl_chamber_list *c = NULL;
670 1.1 mrg
671 1.1 mrg for (i = 0; i < vertices->n_vertices; ++i)
672 1.1 mrg if (selection[i])
673 1.1 mrg n_vertices++;
674 1.1 mrg
675 1.1 mrg snap = isl_tab_snap(tab);
676 1.1 mrg
677 1.1 mrg for (i = 0; i < tab->n_con && tab->con[i].frozen; ++i)
678 1.1 mrg tab->con[i].frozen = 0;
679 1.1 mrg n_frozen = i;
680 1.1 mrg
681 1.1 mrg if (isl_tab_detect_redundant(tab) < 0)
682 1.1 mrg return -1;
683 1.1 mrg
684 1.1 mrg c = isl_calloc_type(tab->mat->ctx, struct isl_chamber_list);
685 1.1 mrg if (!c)
686 1.1 mrg goto error;
687 1.1 mrg c->c.vertices = isl_alloc_array(tab->mat->ctx, int, n_vertices);
688 1.1 mrg if (n_vertices && !c->c.vertices)
689 1.1 mrg goto error;
690 1.1 mrg c->c.dom = isl_basic_set_copy(isl_tab_peek_bset(tab));
691 1.1 mrg c->c.dom = isl_basic_set_set_rational(c->c.dom);
692 1.1 mrg c->c.dom = isl_basic_set_cow(c->c.dom);
693 1.1 mrg c->c.dom = isl_basic_set_update_from_tab(c->c.dom, tab);
694 1.1 mrg c->c.dom = isl_basic_set_simplify(c->c.dom);
695 1.1 mrg c->c.dom = isl_basic_set_finalize(c->c.dom);
696 1.1 mrg if (!c->c.dom)
697 1.1 mrg goto error;
698 1.1 mrg
699 1.1 mrg c->c.n_vertices = n_vertices;
700 1.1 mrg
701 1.1 mrg for (i = 0, j = 0; i < vertices->n_vertices; ++i)
702 1.1 mrg if (selection[i]) {
703 1.1 mrg c->c.vertices[j] = i;
704 1.1 mrg j++;
705 1.1 mrg }
706 1.1 mrg
707 1.1 mrg c->next = *list;
708 1.1 mrg *list = c;
709 1.1 mrg
710 1.1 mrg for (i = 0; i < n_frozen; ++i)
711 1.1 mrg tab->con[i].frozen = 1;
712 1.1 mrg
713 1.1 mrg if (isl_tab_rollback(tab, snap) < 0)
714 1.1 mrg return -1;
715 1.1 mrg
716 1.1 mrg return 0;
717 1.1 mrg error:
718 1.1 mrg free_chamber_list(c);
719 1.1 mrg return -1;
720 1.1 mrg }
721 1.1 mrg
722 1.1 mrg struct isl_facet_todo {
723 1.1 mrg struct isl_tab *tab; /* A tableau representation of the facet */
724 1.1 mrg isl_basic_set *bset; /* A normalized basic set representation */
725 1.1 mrg isl_vec *constraint; /* Constraint pointing to the other side */
726 1.1 mrg struct isl_facet_todo *next;
727 1.1 mrg };
728 1.1 mrg
729 1.1 mrg static void free_todo(struct isl_facet_todo *todo)
730 1.1 mrg {
731 1.1 mrg while (todo) {
732 1.1 mrg struct isl_facet_todo *next = todo->next;
733 1.1 mrg
734 1.1 mrg isl_tab_free(todo->tab);
735 1.1 mrg isl_basic_set_free(todo->bset);
736 1.1 mrg isl_vec_free(todo->constraint);
737 1.1 mrg free(todo);
738 1.1 mrg
739 1.1 mrg todo = next;
740 1.1 mrg }
741 1.1 mrg }
742 1.1 mrg
743 1.1 mrg static struct isl_facet_todo *create_todo(struct isl_tab *tab, int con)
744 1.1 mrg {
745 1.1 mrg int i;
746 1.1 mrg int n_frozen;
747 1.1 mrg struct isl_tab_undo *snap;
748 1.1 mrg struct isl_facet_todo *todo;
749 1.1 mrg
750 1.1 mrg snap = isl_tab_snap(tab);
751 1.1 mrg
752 1.1 mrg for (i = 0; i < tab->n_con && tab->con[i].frozen; ++i)
753 1.1 mrg tab->con[i].frozen = 0;
754 1.1 mrg n_frozen = i;
755 1.1 mrg
756 1.1 mrg if (isl_tab_detect_redundant(tab) < 0)
757 1.1 mrg return NULL;
758 1.1 mrg
759 1.1 mrg todo = isl_calloc_type(tab->mat->ctx, struct isl_facet_todo);
760 1.1 mrg if (!todo)
761 1.1 mrg return NULL;
762 1.1 mrg
763 1.1 mrg todo->constraint = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var);
764 1.1 mrg if (!todo->constraint)
765 1.1 mrg goto error;
766 1.1 mrg isl_seq_neg(todo->constraint->el, tab->bmap->ineq[con], 1 + tab->n_var);
767 1.1 mrg todo->bset = isl_basic_set_copy(isl_tab_peek_bset(tab));
768 1.1 mrg todo->bset = isl_basic_set_set_rational(todo->bset);
769 1.1 mrg todo->bset = isl_basic_set_cow(todo->bset);
770 1.1 mrg todo->bset = isl_basic_set_update_from_tab(todo->bset, tab);
771 1.1 mrg todo->bset = isl_basic_set_simplify(todo->bset);
772 1.1 mrg todo->bset = isl_basic_set_sort_constraints(todo->bset);
773 1.1 mrg if (!todo->bset)
774 1.1 mrg goto error;
775 1.1 mrg ISL_F_SET(todo->bset, ISL_BASIC_SET_NO_REDUNDANT);
776 1.1 mrg todo->tab = isl_tab_dup(tab);
777 1.1 mrg if (!todo->tab)
778 1.1 mrg goto error;
779 1.1 mrg
780 1.1 mrg for (i = 0; i < n_frozen; ++i)
781 1.1 mrg tab->con[i].frozen = 1;
782 1.1 mrg
783 1.1 mrg if (isl_tab_rollback(tab, snap) < 0)
784 1.1 mrg goto error;
785 1.1 mrg
786 1.1 mrg return todo;
787 1.1 mrg error:
788 1.1 mrg free_todo(todo);
789 1.1 mrg return NULL;
790 1.1 mrg }
791 1.1 mrg
792 1.1 mrg /* Create todo items for all interior facets of the chamber represented
793 1.1 mrg * by "tab" and collect them in "next".
794 1.1 mrg */
795 1.1 mrg static int init_todo(struct isl_facet_todo **next, struct isl_tab *tab)
796 1.1 mrg {
797 1.1 mrg int i;
798 1.1 mrg struct isl_tab_undo *snap;
799 1.1 mrg struct isl_facet_todo *todo;
800 1.1 mrg
801 1.1 mrg snap = isl_tab_snap(tab);
802 1.1 mrg
803 1.1 mrg for (i = 0; i < tab->n_con; ++i) {
804 1.1 mrg if (tab->con[i].frozen)
805 1.1 mrg continue;
806 1.1 mrg if (tab->con[i].is_redundant)
807 1.1 mrg continue;
808 1.1 mrg
809 1.1 mrg if (isl_tab_select_facet(tab, i) < 0)
810 1.1 mrg return -1;
811 1.1 mrg
812 1.1 mrg todo = create_todo(tab, i);
813 1.1 mrg if (!todo)
814 1.1 mrg return -1;
815 1.1 mrg
816 1.1 mrg todo->next = *next;
817 1.1 mrg *next = todo;
818 1.1 mrg
819 1.1 mrg if (isl_tab_rollback(tab, snap) < 0)
820 1.1 mrg return -1;
821 1.1 mrg }
822 1.1 mrg
823 1.1 mrg return 0;
824 1.1 mrg }
825 1.1 mrg
826 1.1 mrg /* Does the linked list contain a todo item that is the opposite of "todo".
827 1.1 mrg * If so, return 1 and remove the opposite todo item.
828 1.1 mrg */
829 1.1 mrg static int has_opposite(struct isl_facet_todo *todo,
830 1.1 mrg struct isl_facet_todo **list)
831 1.1 mrg {
832 1.1 mrg for (; *list; list = &(*list)->next) {
833 1.1 mrg int eq;
834 1.1 mrg eq = isl_basic_set_plain_is_equal(todo->bset, (*list)->bset);
835 1.1 mrg if (eq < 0)
836 1.1 mrg return -1;
837 1.1 mrg if (!eq)
838 1.1 mrg continue;
839 1.1 mrg todo = *list;
840 1.1 mrg *list = todo->next;
841 1.1 mrg todo->next = NULL;
842 1.1 mrg free_todo(todo);
843 1.1 mrg return 1;
844 1.1 mrg }
845 1.1 mrg
846 1.1 mrg return 0;
847 1.1 mrg }
848 1.1 mrg
849 1.1 mrg /* Create todo items for all interior facets of the chamber represented
850 1.1 mrg * by "tab" and collect them in first->next, taking care to cancel
851 1.1 mrg * opposite todo items.
852 1.1 mrg */
853 1.1 mrg static int update_todo(struct isl_facet_todo *first, struct isl_tab *tab)
854 1.1 mrg {
855 1.1 mrg int i;
856 1.1 mrg struct isl_tab_undo *snap;
857 1.1 mrg struct isl_facet_todo *todo;
858 1.1 mrg
859 1.1 mrg snap = isl_tab_snap(tab);
860 1.1 mrg
861 1.1 mrg for (i = 0; i < tab->n_con; ++i) {
862 1.1 mrg int drop;
863 1.1 mrg
864 1.1 mrg if (tab->con[i].frozen)
865 1.1 mrg continue;
866 1.1 mrg if (tab->con[i].is_redundant)
867 1.1 mrg continue;
868 1.1 mrg
869 1.1 mrg if (isl_tab_select_facet(tab, i) < 0)
870 1.1 mrg return -1;
871 1.1 mrg
872 1.1 mrg todo = create_todo(tab, i);
873 1.1 mrg if (!todo)
874 1.1 mrg return -1;
875 1.1 mrg
876 1.1 mrg drop = has_opposite(todo, &first->next);
877 1.1 mrg if (drop < 0)
878 1.1 mrg return -1;
879 1.1 mrg
880 1.1 mrg if (drop)
881 1.1 mrg free_todo(todo);
882 1.1 mrg else {
883 1.1 mrg todo->next = first->next;
884 1.1 mrg first->next = todo;
885 1.1 mrg }
886 1.1 mrg
887 1.1 mrg if (isl_tab_rollback(tab, snap) < 0)
888 1.1 mrg return -1;
889 1.1 mrg }
890 1.1 mrg
891 1.1 mrg return 0;
892 1.1 mrg }
893 1.1 mrg
894 1.1 mrg /* Compute the chamber decomposition of the parametric polytope respresented
895 1.1 mrg * by "bset" given the parametric vertices and their activity domains.
896 1.1 mrg *
897 1.1 mrg * We are only interested in full-dimensional chambers.
898 1.1 mrg * Each of these chambers is the intersection of the activity domains of
899 1.1 mrg * one or more vertices and the union of all chambers is equal to the
900 1.1 mrg * projection of the entire parametric polytope onto the parameter space.
901 1.1 mrg *
902 1.1 mrg * We first create an initial chamber by intersecting as many activity
903 1.1 mrg * domains as possible without ending up with an empty or lower-dimensional
904 1.1 mrg * set. As a minor optimization, we only consider those activity domains
905 1.1 mrg * that contain some arbitrary point.
906 1.1 mrg *
907 1.1 mrg * For each of the interior facets of the chamber, we construct a todo item,
908 1.1 mrg * containing the facet and a constraint containing the other side of the facet,
909 1.1 mrg * for constructing the chamber on the other side.
910 1.1 mrg * While their are any todo items left, we pick a todo item and
911 1.1 mrg * create the required chamber by intersecting all activity domains
912 1.1 mrg * that contain the facet and have a full-dimensional intersection with
913 1.1 mrg * the other side of the facet. For each of the interior facets, we
914 1.1 mrg * again create todo items, taking care to cancel opposite todo items.
915 1.1 mrg */
916 1.1 mrg static __isl_give isl_vertices *compute_chambers(__isl_take isl_basic_set *bset,
917 1.1 mrg __isl_take isl_vertices *vertices)
918 1.1 mrg {
919 1.1 mrg int i;
920 1.1 mrg isl_ctx *ctx;
921 1.1 mrg isl_size n_eq;
922 1.1 mrg isl_vec *sample = NULL;
923 1.1 mrg struct isl_tab *tab = NULL;
924 1.1 mrg struct isl_tab_undo *snap;
925 1.1 mrg int *selection = NULL;
926 1.1 mrg int n_chambers = 0;
927 1.1 mrg struct isl_chamber_list *list = NULL;
928 1.1 mrg struct isl_facet_todo *todo = NULL;
929 1.1 mrg
930 1.1 mrg if (!bset || !vertices)
931 1.1 mrg goto error;
932 1.1 mrg
933 1.1 mrg ctx = isl_vertices_get_ctx(vertices);
934 1.1 mrg selection = isl_alloc_array(ctx, int, vertices->n_vertices);
935 1.1 mrg if (vertices->n_vertices && !selection)
936 1.1 mrg goto error;
937 1.1 mrg
938 1.1 mrg bset = isl_basic_set_params(bset);
939 1.1 mrg n_eq = isl_basic_set_n_equality(bset);
940 1.1 mrg if (n_eq < 0)
941 1.1 mrg goto error;
942 1.1 mrg if (n_eq > 0)
943 1.1 mrg isl_die(isl_basic_set_get_ctx(bset), isl_error_internal,
944 1.1 mrg "expecting full-dimensional input", goto error);
945 1.1 mrg
946 1.1 mrg tab = isl_tab_from_basic_set(bset, 1);
947 1.1 mrg if (!tab)
948 1.1 mrg goto error;
949 1.1 mrg for (i = 0; i < bset->n_ineq; ++i)
950 1.1 mrg if (isl_tab_freeze_constraint(tab, i) < 0)
951 1.1 mrg goto error;
952 1.1 mrg isl_basic_set_free(bset);
953 1.1 mrg
954 1.1 mrg snap = isl_tab_snap(tab);
955 1.1 mrg
956 1.1 mrg sample = isl_tab_get_sample_value(tab);
957 1.1 mrg
958 1.1 mrg for (i = 0; i < vertices->n_vertices; ++i) {
959 1.1 mrg selection[i] = isl_basic_set_contains(vertices->v[i].dom, sample);
960 1.1 mrg if (selection[i] < 0)
961 1.1 mrg goto error;
962 1.1 mrg if (!selection[i])
963 1.1 mrg continue;
964 1.1 mrg selection[i] = can_intersect(tab, vertices->v[i].dom);
965 1.1 mrg if (selection[i] < 0)
966 1.1 mrg goto error;
967 1.1 mrg }
968 1.1 mrg
969 1.1 mrg if (isl_tab_detect_redundant(tab) < 0)
970 1.1 mrg goto error;
971 1.1 mrg
972 1.1 mrg if (add_chamber(&list, vertices, tab, selection) < 0)
973 1.1 mrg goto error;
974 1.1 mrg n_chambers++;
975 1.1 mrg
976 1.1 mrg if (init_todo(&todo, tab) < 0)
977 1.1 mrg goto error;
978 1.1 mrg
979 1.1 mrg while (todo) {
980 1.1 mrg struct isl_facet_todo *next;
981 1.1 mrg
982 1.1 mrg if (isl_tab_rollback(tab, snap) < 0)
983 1.1 mrg goto error;
984 1.1 mrg
985 1.1 mrg if (isl_tab_add_ineq(tab, todo->constraint->el) < 0)
986 1.1 mrg goto error;
987 1.1 mrg if (isl_tab_freeze_constraint(tab, tab->n_con - 1) < 0)
988 1.1 mrg goto error;
989 1.1 mrg
990 1.1 mrg for (i = 0; i < vertices->n_vertices; ++i) {
991 1.1 mrg selection[i] = bset_covers_tab(vertices->v[i].dom,
992 1.1 mrg todo->tab);
993 1.1 mrg if (selection[i] < 0)
994 1.1 mrg goto error;
995 1.1 mrg if (!selection[i])
996 1.1 mrg continue;
997 1.1 mrg selection[i] = can_intersect(tab, vertices->v[i].dom);
998 1.1 mrg if (selection[i] < 0)
999 1.1 mrg goto error;
1000 1.1 mrg }
1001 1.1 mrg
1002 1.1 mrg if (isl_tab_detect_redundant(tab) < 0)
1003 1.1 mrg goto error;
1004 1.1 mrg
1005 1.1 mrg if (add_chamber(&list, vertices, tab, selection) < 0)
1006 1.1 mrg goto error;
1007 1.1 mrg n_chambers++;
1008 1.1 mrg
1009 1.1 mrg if (update_todo(todo, tab) < 0)
1010 1.1 mrg goto error;
1011 1.1 mrg
1012 1.1 mrg next = todo->next;
1013 1.1 mrg todo->next = NULL;
1014 1.1 mrg free_todo(todo);
1015 1.1 mrg todo = next;
1016 1.1 mrg }
1017 1.1 mrg
1018 1.1 mrg isl_vec_free(sample);
1019 1.1 mrg
1020 1.1 mrg isl_tab_free(tab);
1021 1.1 mrg free(selection);
1022 1.1 mrg
1023 1.1 mrg vertices = vertices_add_chambers(vertices, n_chambers, list);
1024 1.1 mrg
1025 1.1 mrg for (i = 0; vertices && i < vertices->n_vertices; ++i) {
1026 1.1 mrg isl_basic_set_free(vertices->v[i].dom);
1027 1.1 mrg vertices->v[i].dom = NULL;
1028 1.1 mrg }
1029 1.1 mrg
1030 1.1 mrg return vertices;
1031 1.1 mrg error:
1032 1.1 mrg free_chamber_list(list);
1033 1.1 mrg free_todo(todo);
1034 1.1 mrg isl_vec_free(sample);
1035 1.1 mrg isl_tab_free(tab);
1036 1.1 mrg free(selection);
1037 1.1 mrg if (!tab)
1038 1.1 mrg isl_basic_set_free(bset);
1039 1.1 mrg isl_vertices_free(vertices);
1040 1.1 mrg return NULL;
1041 1.1 mrg }
1042 1.1 mrg
1043 1.1 mrg isl_ctx *isl_vertex_get_ctx(__isl_keep isl_vertex *vertex)
1044 1.1 mrg {
1045 1.1 mrg return vertex ? isl_vertices_get_ctx(vertex->vertices) : NULL;
1046 1.1 mrg }
1047 1.1 mrg
1048 1.1 mrg isl_size isl_vertex_get_id(__isl_keep isl_vertex *vertex)
1049 1.1 mrg {
1050 1.1 mrg return vertex ? vertex->id : isl_size_error;
1051 1.1 mrg }
1052 1.1 mrg
1053 1.1 mrg /* Return the activity domain of the vertex "vertex".
1054 1.1 mrg */
1055 1.1 mrg __isl_give isl_basic_set *isl_vertex_get_domain(__isl_keep isl_vertex *vertex)
1056 1.1 mrg {
1057 1.1 mrg struct isl_vertex *v;
1058 1.1 mrg
1059 1.1 mrg if (!vertex)
1060 1.1 mrg return NULL;
1061 1.1 mrg
1062 1.1 mrg v = &vertex->vertices->v[vertex->id];
1063 1.1 mrg if (!v->dom) {
1064 1.1 mrg v->dom = isl_basic_set_copy(v->vertex);
1065 1.1 mrg v->dom = isl_basic_set_params(v->dom);
1066 1.1 mrg v->dom = isl_basic_set_set_integral(v->dom);
1067 1.1 mrg }
1068 1.1 mrg
1069 1.1 mrg return isl_basic_set_copy(v->dom);
1070 1.1 mrg }
1071 1.1 mrg
1072 1.1 mrg /* Return a multiple quasi-affine expression describing the vertex "vertex"
1073 1.1 mrg * in terms of the parameters,
1074 1.1 mrg */
1075 1.1 mrg __isl_give isl_multi_aff *isl_vertex_get_expr(__isl_keep isl_vertex *vertex)
1076 1.1 mrg {
1077 1.1 mrg struct isl_vertex *v;
1078 1.1 mrg isl_basic_set *bset;
1079 1.1 mrg
1080 1.1 mrg if (!vertex)
1081 1.1 mrg return NULL;
1082 1.1 mrg
1083 1.1 mrg v = &vertex->vertices->v[vertex->id];
1084 1.1 mrg
1085 1.1 mrg bset = isl_basic_set_copy(v->vertex);
1086 1.1 mrg return isl_multi_aff_from_basic_set_equalities(bset);
1087 1.1 mrg }
1088 1.1 mrg
1089 1.1 mrg static __isl_give isl_vertex *isl_vertex_alloc(__isl_take isl_vertices *vertices,
1090 1.1 mrg int id)
1091 1.1 mrg {
1092 1.1 mrg isl_ctx *ctx;
1093 1.1 mrg isl_vertex *vertex;
1094 1.1 mrg
1095 1.1 mrg if (!vertices)
1096 1.1 mrg return NULL;
1097 1.1 mrg
1098 1.1 mrg ctx = isl_vertices_get_ctx(vertices);
1099 1.1 mrg vertex = isl_alloc_type(ctx, isl_vertex);
1100 1.1 mrg if (!vertex)
1101 1.1 mrg goto error;
1102 1.1 mrg
1103 1.1 mrg vertex->vertices = vertices;
1104 1.1 mrg vertex->id = id;
1105 1.1 mrg
1106 1.1 mrg return vertex;
1107 1.1 mrg error:
1108 1.1 mrg isl_vertices_free(vertices);
1109 1.1 mrg return NULL;
1110 1.1 mrg }
1111 1.1 mrg
1112 1.1 mrg __isl_null isl_vertex *isl_vertex_free(__isl_take isl_vertex *vertex)
1113 1.1 mrg {
1114 1.1 mrg if (!vertex)
1115 1.1 mrg return NULL;
1116 1.1 mrg isl_vertices_free(vertex->vertices);
1117 1.1 mrg free(vertex);
1118 1.1 mrg
1119 1.1 mrg return NULL;
1120 1.1 mrg }
1121 1.1 mrg
1122 1.1 mrg isl_ctx *isl_cell_get_ctx(__isl_keep isl_cell *cell)
1123 1.1 mrg {
1124 1.1 mrg return cell ? cell->dom->ctx : NULL;
1125 1.1 mrg }
1126 1.1 mrg
1127 1.1 mrg __isl_give isl_basic_set *isl_cell_get_domain(__isl_keep isl_cell *cell)
1128 1.1 mrg {
1129 1.1 mrg return cell ? isl_basic_set_copy(cell->dom) : NULL;
1130 1.1 mrg }
1131 1.1 mrg
1132 1.1 mrg static __isl_give isl_cell *isl_cell_alloc(__isl_take isl_vertices *vertices,
1133 1.1 mrg __isl_take isl_basic_set *dom, int id)
1134 1.1 mrg {
1135 1.1 mrg int i;
1136 1.1 mrg isl_cell *cell = NULL;
1137 1.1 mrg
1138 1.1 mrg if (!vertices || !dom)
1139 1.1 mrg goto error;
1140 1.1 mrg
1141 1.1 mrg cell = isl_calloc_type(dom->ctx, isl_cell);
1142 1.1 mrg if (!cell)
1143 1.1 mrg goto error;
1144 1.1 mrg
1145 1.1 mrg cell->n_vertices = vertices->c[id].n_vertices;
1146 1.1 mrg cell->ids = isl_alloc_array(dom->ctx, int, cell->n_vertices);
1147 1.1 mrg if (cell->n_vertices && !cell->ids)
1148 1.1 mrg goto error;
1149 1.1 mrg for (i = 0; i < cell->n_vertices; ++i)
1150 1.1 mrg cell->ids[i] = vertices->c[id].vertices[i];
1151 1.1 mrg cell->vertices = vertices;
1152 1.1 mrg cell->dom = dom;
1153 1.1 mrg
1154 1.1 mrg return cell;
1155 1.1 mrg error:
1156 1.1 mrg isl_cell_free(cell);
1157 1.1 mrg isl_vertices_free(vertices);
1158 1.1 mrg isl_basic_set_free(dom);
1159 1.1 mrg return NULL;
1160 1.1 mrg }
1161 1.1 mrg
1162 1.1 mrg __isl_null isl_cell *isl_cell_free(__isl_take isl_cell *cell)
1163 1.1 mrg {
1164 1.1 mrg if (!cell)
1165 1.1 mrg return NULL;
1166 1.1 mrg
1167 1.1 mrg isl_vertices_free(cell->vertices);
1168 1.1 mrg free(cell->ids);
1169 1.1 mrg isl_basic_set_free(cell->dom);
1170 1.1 mrg free(cell);
1171 1.1 mrg
1172 1.1 mrg return NULL;
1173 1.1 mrg }
1174 1.1 mrg
1175 1.1 mrg /* Create a tableau of the cone obtained by first homogenizing the given
1176 1.1 mrg * polytope and then making all inequalities strict by setting the
1177 1.1 mrg * constant term to -1.
1178 1.1 mrg */
1179 1.1 mrg static struct isl_tab *tab_for_shifted_cone(__isl_keep isl_basic_set *bset)
1180 1.1 mrg {
1181 1.1 mrg int i;
1182 1.1 mrg isl_vec *c = NULL;
1183 1.1 mrg struct isl_tab *tab;
1184 1.1 mrg isl_size total;
1185 1.1 mrg
1186 1.1 mrg total = isl_basic_set_dim(bset, isl_dim_all);
1187 1.1 mrg if (total < 0)
1188 1.1 mrg return NULL;
1189 1.1 mrg tab = isl_tab_alloc(bset->ctx, bset->n_eq + bset->n_ineq + 1,
1190 1.1 mrg 1 + total, 0);
1191 1.1 mrg if (!tab)
1192 1.1 mrg return NULL;
1193 1.1 mrg tab->rational = ISL_F_ISSET(bset, ISL_BASIC_SET_RATIONAL);
1194 1.1 mrg if (ISL_F_ISSET(bset, ISL_BASIC_MAP_EMPTY)) {
1195 1.1 mrg if (isl_tab_mark_empty(tab) < 0)
1196 1.1 mrg goto error;
1197 1.1 mrg return tab;
1198 1.1 mrg }
1199 1.1 mrg
1200 1.1 mrg c = isl_vec_alloc(bset->ctx, 1 + 1 + total);
1201 1.1 mrg if (!c)
1202 1.1 mrg goto error;
1203 1.1 mrg
1204 1.1 mrg isl_int_set_si(c->el[0], 0);
1205 1.1 mrg for (i = 0; i < bset->n_eq; ++i) {
1206 1.1 mrg isl_seq_cpy(c->el + 1, bset->eq[i], c->size - 1);
1207 1.1 mrg if (isl_tab_add_eq(tab, c->el) < 0)
1208 1.1 mrg goto error;
1209 1.1 mrg }
1210 1.1 mrg
1211 1.1 mrg isl_int_set_si(c->el[0], -1);
1212 1.1 mrg for (i = 0; i < bset->n_ineq; ++i) {
1213 1.1 mrg isl_seq_cpy(c->el + 1, bset->ineq[i], c->size - 1);
1214 1.1 mrg if (isl_tab_add_ineq(tab, c->el) < 0)
1215 1.1 mrg goto error;
1216 1.1 mrg if (tab->empty) {
1217 1.1 mrg isl_vec_free(c);
1218 1.1 mrg return tab;
1219 1.1 mrg }
1220 1.1 mrg }
1221 1.1 mrg
1222 1.1 mrg isl_seq_clr(c->el + 1, c->size - 1);
1223 1.1 mrg isl_int_set_si(c->el[1], 1);
1224 1.1 mrg if (isl_tab_add_ineq(tab, c->el) < 0)
1225 1.1 mrg goto error;
1226 1.1 mrg
1227 1.1 mrg isl_vec_free(c);
1228 1.1 mrg return tab;
1229 1.1 mrg error:
1230 1.1 mrg isl_vec_free(c);
1231 1.1 mrg isl_tab_free(tab);
1232 1.1 mrg return NULL;
1233 1.1 mrg }
1234 1.1 mrg
1235 1.1 mrg /* Compute an interior point of "bset" by selecting an interior
1236 1.1 mrg * point in homogeneous space and projecting the point back down.
1237 1.1 mrg */
1238 1.1 mrg static __isl_give isl_vec *isl_basic_set_interior_point(
1239 1.1 mrg __isl_keep isl_basic_set *bset)
1240 1.1 mrg {
1241 1.1 mrg isl_vec *vec;
1242 1.1 mrg struct isl_tab *tab;
1243 1.1 mrg
1244 1.1 mrg tab = tab_for_shifted_cone(bset);
1245 1.1 mrg vec = isl_tab_get_sample_value(tab);
1246 1.1 mrg isl_tab_free(tab);
1247 1.1 mrg if (!vec)
1248 1.1 mrg return NULL;
1249 1.1 mrg
1250 1.1 mrg isl_seq_cpy(vec->el, vec->el + 1, vec->size - 1);
1251 1.1 mrg vec->size--;
1252 1.1 mrg
1253 1.1 mrg return vec;
1254 1.1 mrg }
1255 1.1 mrg
1256 1.1 mrg /* Call "fn" on all chambers of the parametric polytope with the shared
1257 1.1 mrg * facets of neighboring chambers only appearing in one of the chambers.
1258 1.1 mrg *
1259 1.1 mrg * We pick an interior point from one of the chambers and then make
1260 1.1 mrg * all constraints that do not satisfy this point strict.
1261 1.1 mrg * For constraints that saturate the interior point, the sign
1262 1.1 mrg * of the first non-zero coefficient is used to determine which
1263 1.1 mrg * of the two (internal) constraints should be tightened.
1264 1.1 mrg */
1265 1.1 mrg isl_stat isl_vertices_foreach_disjoint_cell(__isl_keep isl_vertices *vertices,
1266 1.1 mrg isl_stat (*fn)(__isl_take isl_cell *cell, void *user), void *user)
1267 1.1 mrg {
1268 1.1 mrg int i;
1269 1.1 mrg isl_vec *vec;
1270 1.1 mrg isl_cell *cell;
1271 1.1 mrg
1272 1.1 mrg if (!vertices)
1273 1.1 mrg return isl_stat_error;
1274 1.1 mrg
1275 1.1 mrg if (vertices->n_chambers == 0)
1276 1.1 mrg return isl_stat_ok;
1277 1.1 mrg
1278 1.1 mrg if (vertices->n_chambers == 1) {
1279 1.1 mrg isl_basic_set *dom = isl_basic_set_copy(vertices->c[0].dom);
1280 1.1 mrg dom = isl_basic_set_set_integral(dom);
1281 1.1 mrg cell = isl_cell_alloc(isl_vertices_copy(vertices), dom, 0);
1282 1.1 mrg if (!cell)
1283 1.1 mrg return isl_stat_error;
1284 1.1 mrg return fn(cell, user);
1285 1.1 mrg }
1286 1.1 mrg
1287 1.1 mrg vec = isl_basic_set_interior_point(vertices->c[0].dom);
1288 1.1 mrg if (!vec)
1289 1.1 mrg return isl_stat_error;
1290 1.1 mrg
1291 1.1 mrg for (i = 0; i < vertices->n_chambers; ++i) {
1292 1.1 mrg int r;
1293 1.1 mrg isl_basic_set *dom = isl_basic_set_copy(vertices->c[i].dom);
1294 1.1 mrg if (i)
1295 1.1 mrg dom = isl_basic_set_tighten_outward(dom, vec);
1296 1.1 mrg dom = isl_basic_set_set_integral(dom);
1297 1.1 mrg cell = isl_cell_alloc(isl_vertices_copy(vertices), dom, i);
1298 1.1 mrg if (!cell)
1299 1.1 mrg goto error;
1300 1.1 mrg r = fn(cell, user);
1301 1.1 mrg if (r < 0)
1302 1.1 mrg goto error;
1303 1.1 mrg }
1304 1.1 mrg
1305 1.1 mrg isl_vec_free(vec);
1306 1.1 mrg
1307 1.1 mrg return isl_stat_ok;
1308 1.1 mrg error:
1309 1.1 mrg isl_vec_free(vec);
1310 1.1 mrg return isl_stat_error;
1311 1.1 mrg }
1312 1.1 mrg
1313 1.1 mrg isl_stat isl_vertices_foreach_cell(__isl_keep isl_vertices *vertices,
1314 1.1 mrg isl_stat (*fn)(__isl_take isl_cell *cell, void *user), void *user)
1315 1.1 mrg {
1316 1.1 mrg int i;
1317 1.1 mrg isl_cell *cell;
1318 1.1 mrg
1319 1.1 mrg if (!vertices)
1320 1.1 mrg return isl_stat_error;
1321 1.1 mrg
1322 1.1 mrg if (vertices->n_chambers == 0)
1323 1.1 mrg return isl_stat_ok;
1324 1.1 mrg
1325 1.1 mrg for (i = 0; i < vertices->n_chambers; ++i) {
1326 1.1 mrg isl_stat r;
1327 1.1 mrg isl_basic_set *dom = isl_basic_set_copy(vertices->c[i].dom);
1328 1.1 mrg
1329 1.1 mrg cell = isl_cell_alloc(isl_vertices_copy(vertices), dom, i);
1330 1.1 mrg if (!cell)
1331 1.1 mrg return isl_stat_error;
1332 1.1 mrg
1333 1.1 mrg r = fn(cell, user);
1334 1.1 mrg if (r < 0)
1335 1.1 mrg return isl_stat_error;
1336 1.1 mrg }
1337 1.1 mrg
1338 1.1 mrg return isl_stat_ok;
1339 1.1 mrg }
1340 1.1 mrg
1341 1.1 mrg isl_stat isl_vertices_foreach_vertex(__isl_keep isl_vertices *vertices,
1342 1.1 mrg isl_stat (*fn)(__isl_take isl_vertex *vertex, void *user), void *user)
1343 1.1 mrg {
1344 1.1 mrg int i;
1345 1.1 mrg isl_vertex *vertex;
1346 1.1 mrg
1347 1.1 mrg if (!vertices)
1348 1.1 mrg return isl_stat_error;
1349 1.1 mrg
1350 1.1 mrg if (vertices->n_vertices == 0)
1351 1.1 mrg return isl_stat_ok;
1352 1.1 mrg
1353 1.1 mrg for (i = 0; i < vertices->n_vertices; ++i) {
1354 1.1 mrg isl_stat r;
1355 1.1 mrg
1356 1.1 mrg vertex = isl_vertex_alloc(isl_vertices_copy(vertices), i);
1357 1.1 mrg if (!vertex)
1358 1.1 mrg return isl_stat_error;
1359 1.1 mrg
1360 1.1 mrg r = fn(vertex, user);
1361 1.1 mrg if (r < 0)
1362 1.1 mrg return isl_stat_error;
1363 1.1 mrg }
1364 1.1 mrg
1365 1.1 mrg return isl_stat_ok;
1366 1.1 mrg }
1367 1.1 mrg
1368 1.1 mrg isl_stat isl_cell_foreach_vertex(__isl_keep isl_cell *cell,
1369 1.1 mrg isl_stat (*fn)(__isl_take isl_vertex *vertex, void *user), void *user)
1370 1.1 mrg {
1371 1.1 mrg int i;
1372 1.1 mrg isl_vertex *vertex;
1373 1.1 mrg
1374 1.1 mrg if (!cell)
1375 1.1 mrg return isl_stat_error;
1376 1.1 mrg
1377 1.1 mrg if (cell->n_vertices == 0)
1378 1.1 mrg return isl_stat_ok;
1379 1.1 mrg
1380 1.1 mrg for (i = 0; i < cell->n_vertices; ++i) {
1381 1.1 mrg isl_stat r;
1382 1.1 mrg
1383 1.1 mrg vertex = isl_vertex_alloc(isl_vertices_copy(cell->vertices),
1384 1.1 mrg cell->ids[i]);
1385 1.1 mrg if (!vertex)
1386 1.1 mrg return isl_stat_error;
1387 1.1 mrg
1388 1.1 mrg r = fn(vertex, user);
1389 1.1 mrg if (r < 0)
1390 1.1 mrg return isl_stat_error;
1391 1.1 mrg }
1392 1.1 mrg
1393 1.1 mrg return isl_stat_ok;
1394 1.1 mrg }
1395 1.1 mrg
1396 1.1 mrg isl_ctx *isl_vertices_get_ctx(__isl_keep isl_vertices *vertices)
1397 1.1 mrg {
1398 1.1 mrg return vertices ? vertices->bset->ctx : NULL;
1399 1.1 mrg }
1400 1.1 mrg
1401 1.1 mrg isl_size isl_vertices_get_n_vertices(__isl_keep isl_vertices *vertices)
1402 1.1 mrg {
1403 1.1 mrg return vertices ? vertices->n_vertices : isl_size_error;
1404 1.1 mrg }
1405 1.1 mrg
1406 1.1 mrg __isl_give isl_vertices *isl_morph_vertices(__isl_take isl_morph *morph,
1407 1.1 mrg __isl_take isl_vertices *vertices)
1408 1.1 mrg {
1409 1.1 mrg int i;
1410 1.1 mrg isl_morph *param_morph = NULL;
1411 1.1 mrg
1412 1.1 mrg if (!morph || !vertices)
1413 1.1 mrg goto error;
1414 1.1 mrg
1415 1.1 mrg isl_assert(vertices->bset->ctx, vertices->ref == 1, goto error);
1416 1.1 mrg
1417 1.1 mrg param_morph = isl_morph_copy(morph);
1418 1.1 mrg param_morph = isl_morph_dom_params(param_morph);
1419 1.1 mrg param_morph = isl_morph_ran_params(param_morph);
1420 1.1 mrg
1421 1.1 mrg for (i = 0; i < vertices->n_vertices; ++i) {
1422 1.1 mrg vertices->v[i].dom = isl_morph_basic_set(
1423 1.1 mrg isl_morph_copy(param_morph), vertices->v[i].dom);
1424 1.1 mrg vertices->v[i].vertex = isl_morph_basic_set(
1425 1.1 mrg isl_morph_copy(morph), vertices->v[i].vertex);
1426 1.1 mrg if (!vertices->v[i].vertex)
1427 1.1 mrg goto error;
1428 1.1 mrg }
1429 1.1 mrg
1430 1.1 mrg for (i = 0; i < vertices->n_chambers; ++i) {
1431 1.1 mrg vertices->c[i].dom = isl_morph_basic_set(
1432 1.1 mrg isl_morph_copy(param_morph), vertices->c[i].dom);
1433 1.1 mrg if (!vertices->c[i].dom)
1434 1.1 mrg goto error;
1435 1.1 mrg }
1436 1.1 mrg
1437 1.1 mrg isl_morph_free(param_morph);
1438 1.1 mrg isl_morph_free(morph);
1439 1.1 mrg return vertices;
1440 1.1 mrg error:
1441 1.1 mrg isl_morph_free(param_morph);
1442 1.1 mrg isl_morph_free(morph);
1443 1.1 mrg isl_vertices_free(vertices);
1444 1.1 mrg return NULL;
1445 1.1 mrg }
1446 1.1 mrg
1447 1.1 mrg /* Construct a simplex isl_cell spanned by the vertices with indices in
1448 1.1 mrg * "simplex_ids" and "other_ids" and call "fn" on this isl_cell.
1449 1.1 mrg */
1450 1.1 mrg static isl_stat call_on_simplex(__isl_keep isl_cell *cell,
1451 1.1 mrg int *simplex_ids, int n_simplex, int *other_ids, int n_other,
1452 1.1 mrg isl_stat (*fn)(__isl_take isl_cell *simplex, void *user), void *user)
1453 1.1 mrg {
1454 1.1 mrg int i;
1455 1.1 mrg isl_ctx *ctx;
1456 1.1 mrg struct isl_cell *simplex;
1457 1.1 mrg
1458 1.1 mrg ctx = isl_cell_get_ctx(cell);
1459 1.1 mrg
1460 1.1 mrg simplex = isl_calloc_type(ctx, struct isl_cell);
1461 1.1 mrg if (!simplex)
1462 1.1 mrg return isl_stat_error;
1463 1.1 mrg simplex->vertices = isl_vertices_copy(cell->vertices);
1464 1.1 mrg if (!simplex->vertices)
1465 1.1 mrg goto error;
1466 1.1 mrg simplex->dom = isl_basic_set_copy(cell->dom);
1467 1.1 mrg if (!simplex->dom)
1468 1.1 mrg goto error;
1469 1.1 mrg simplex->n_vertices = n_simplex + n_other;
1470 1.1 mrg simplex->ids = isl_alloc_array(ctx, int, simplex->n_vertices);
1471 1.1 mrg if (!simplex->ids)
1472 1.1 mrg goto error;
1473 1.1 mrg
1474 1.1 mrg for (i = 0; i < n_simplex; ++i)
1475 1.1 mrg simplex->ids[i] = simplex_ids[i];
1476 1.1 mrg for (i = 0; i < n_other; ++i)
1477 1.1 mrg simplex->ids[n_simplex + i] = other_ids[i];
1478 1.1 mrg
1479 1.1 mrg return fn(simplex, user);
1480 1.1 mrg error:
1481 1.1 mrg isl_cell_free(simplex);
1482 1.1 mrg return isl_stat_error;
1483 1.1 mrg }
1484 1.1 mrg
1485 1.1 mrg /* Check whether the parametric vertex described by "vertex"
1486 1.1 mrg * lies on the facet corresponding to constraint "facet" of "bset".
1487 1.1 mrg * The isl_vec "v" is a temporary vector than can be used by this function.
1488 1.1 mrg *
1489 1.1 mrg * We eliminate the variables from the facet constraint using the
1490 1.1 mrg * equalities defining the vertex and check if the result is identical
1491 1.1 mrg * to zero.
1492 1.1 mrg *
1493 1.1 mrg * It would probably be better to keep track of the constraints defining
1494 1.1 mrg * a vertex during the vertex construction so that we could simply look
1495 1.1 mrg * it up here.
1496 1.1 mrg */
1497 1.1 mrg static int vertex_on_facet(__isl_keep isl_basic_set *vertex,
1498 1.1 mrg __isl_keep isl_basic_set *bset, int facet, __isl_keep isl_vec *v)
1499 1.1 mrg {
1500 1.1 mrg int i;
1501 1.1 mrg isl_int m;
1502 1.1 mrg
1503 1.1 mrg isl_seq_cpy(v->el, bset->ineq[facet], v->size);
1504 1.1 mrg
1505 1.1 mrg isl_int_init(m);
1506 1.1 mrg for (i = 0; i < vertex->n_eq; ++i) {
1507 1.1 mrg int k = isl_seq_last_non_zero(vertex->eq[i], v->size);
1508 1.1 mrg isl_seq_elim(v->el, vertex->eq[i], k, v->size, &m);
1509 1.1 mrg }
1510 1.1 mrg isl_int_clear(m);
1511 1.1 mrg
1512 1.1 mrg return isl_seq_first_non_zero(v->el, v->size) == -1;
1513 1.1 mrg }
1514 1.1 mrg
1515 1.1 mrg /* Triangulate the polytope spanned by the vertices with ids
1516 1.1 mrg * in "simplex_ids" and "other_ids" and call "fn" on each of
1517 1.1 mrg * the resulting simplices.
1518 1.1 mrg * If the input polytope is already a simplex, we simply call "fn".
1519 1.1 mrg * Otherwise, we pick a point from "other_ids" and add it to "simplex_ids".
1520 1.1 mrg * Then we consider each facet of "bset" that does not contain the point
1521 1.1 mrg * we just picked, but does contain some of the other points in "other_ids"
1522 1.1 mrg * and call ourselves recursively on the polytope spanned by the new
1523 1.1 mrg * "simplex_ids" and those points in "other_ids" that lie on the facet.
1524 1.1 mrg */
1525 1.1 mrg static isl_stat triangulate(__isl_keep isl_cell *cell, __isl_keep isl_vec *v,
1526 1.1 mrg int *simplex_ids, int n_simplex, int *other_ids, int n_other,
1527 1.1 mrg isl_stat (*fn)(__isl_take isl_cell *simplex, void *user), void *user)
1528 1.1 mrg {
1529 1.1 mrg int i, j, k;
1530 1.1 mrg isl_size d, nparam;
1531 1.1 mrg int *ids;
1532 1.1 mrg isl_ctx *ctx;
1533 1.1 mrg isl_basic_set *vertex;
1534 1.1 mrg isl_basic_set *bset;
1535 1.1 mrg
1536 1.1 mrg ctx = isl_cell_get_ctx(cell);
1537 1.1 mrg d = isl_basic_set_dim(cell->vertices->bset, isl_dim_set);
1538 1.1 mrg nparam = isl_basic_set_dim(cell->vertices->bset, isl_dim_param);
1539 1.1 mrg if (d < 0 || nparam < 0)
1540 1.1 mrg return isl_stat_error;
1541 1.1 mrg
1542 1.1 mrg if (n_simplex + n_other == d + 1)
1543 1.1 mrg return call_on_simplex(cell, simplex_ids, n_simplex,
1544 1.1 mrg other_ids, n_other, fn, user);
1545 1.1 mrg
1546 1.1 mrg simplex_ids[n_simplex] = other_ids[0];
1547 1.1 mrg vertex = cell->vertices->v[other_ids[0]].vertex;
1548 1.1 mrg bset = cell->vertices->bset;
1549 1.1 mrg
1550 1.1 mrg ids = isl_alloc_array(ctx, int, n_other - 1);
1551 1.1 mrg if (!ids)
1552 1.1 mrg goto error;
1553 1.1 mrg for (i = 0; i < bset->n_ineq; ++i) {
1554 1.1 mrg if (isl_seq_first_non_zero(bset->ineq[i] + 1 + nparam, d) == -1)
1555 1.1 mrg continue;
1556 1.1 mrg if (vertex_on_facet(vertex, bset, i, v))
1557 1.1 mrg continue;
1558 1.1 mrg
1559 1.1 mrg for (j = 1, k = 0; j < n_other; ++j) {
1560 1.1 mrg isl_basic_set *ov;
1561 1.1 mrg ov = cell->vertices->v[other_ids[j]].vertex;
1562 1.1 mrg if (vertex_on_facet(ov, bset, i, v))
1563 1.1 mrg ids[k++] = other_ids[j];
1564 1.1 mrg }
1565 1.1 mrg if (k == 0)
1566 1.1 mrg continue;
1567 1.1 mrg
1568 1.1 mrg if (triangulate(cell, v, simplex_ids, n_simplex + 1,
1569 1.1 mrg ids, k, fn, user) < 0)
1570 1.1 mrg goto error;
1571 1.1 mrg }
1572 1.1 mrg free(ids);
1573 1.1 mrg
1574 1.1 mrg return isl_stat_ok;
1575 1.1 mrg error:
1576 1.1 mrg free(ids);
1577 1.1 mrg return isl_stat_error;
1578 1.1 mrg }
1579 1.1 mrg
1580 1.1 mrg /* Triangulate the given cell and call "fn" on each of the resulting
1581 1.1 mrg * simplices.
1582 1.1 mrg */
1583 1.1 mrg isl_stat isl_cell_foreach_simplex(__isl_take isl_cell *cell,
1584 1.1 mrg isl_stat (*fn)(__isl_take isl_cell *simplex, void *user), void *user)
1585 1.1 mrg {
1586 1.1 mrg isl_size d, total;
1587 1.1 mrg isl_stat r;
1588 1.1 mrg isl_ctx *ctx;
1589 1.1 mrg isl_vec *v = NULL;
1590 1.1 mrg int *simplex_ids = NULL;
1591 1.1 mrg
1592 1.1 mrg if (!cell)
1593 1.1 mrg return isl_stat_error;
1594 1.1 mrg
1595 1.1 mrg d = isl_basic_set_dim(cell->vertices->bset, isl_dim_set);
1596 1.1 mrg total = isl_basic_set_dim(cell->vertices->bset, isl_dim_all);
1597 1.1 mrg if (d < 0 || total < 0)
1598 1.1 mrg return isl_stat_error;
1599 1.1 mrg
1600 1.1 mrg if (cell->n_vertices == d + 1)
1601 1.1 mrg return fn(cell, user);
1602 1.1 mrg
1603 1.1 mrg ctx = isl_cell_get_ctx(cell);
1604 1.1 mrg simplex_ids = isl_alloc_array(ctx, int, d + 1);
1605 1.1 mrg if (!simplex_ids)
1606 1.1 mrg goto error;
1607 1.1 mrg
1608 1.1 mrg v = isl_vec_alloc(ctx, 1 + total);
1609 1.1 mrg if (!v)
1610 1.1 mrg goto error;
1611 1.1 mrg
1612 1.1 mrg r = triangulate(cell, v, simplex_ids, 0,
1613 1.1 mrg cell->ids, cell->n_vertices, fn, user);
1614 1.1 mrg
1615 1.1 mrg isl_vec_free(v);
1616 1.1 mrg free(simplex_ids);
1617 1.1 mrg
1618 1.1 mrg isl_cell_free(cell);
1619 1.1 mrg
1620 1.1 mrg return r;
1621 1.1 mrg error:
1622 1.1 mrg free(simplex_ids);
1623 1.1 mrg isl_vec_free(v);
1624 1.1 mrg isl_cell_free(cell);
1625 1.1 mrg return isl_stat_error;
1626 1.1 mrg }
1627