Coverage Report

Created: 2017-11-21 16:49

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