LCOV - code coverage report
Current view: top level - metalib_isl - isl_vertices.c (source / functions) Hit Total Coverage
Test: 2018-10-31_point_maint_greina16.lcov Lines: 0 807 0.0 %
Date: 2018-11-01 11:27:00 Functions: 0 45 0.0 %

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

Generated by: LCOV version 1.12