Coverage Report

Created: 2018-04-23 18:20

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/External/isl/isl_fold.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_union_map_private.h>
13
#include <isl_polynomial_private.h>
14
#include <isl_point_private.h>
15
#include <isl_space_private.h>
16
#include <isl_lp_private.h>
17
#include <isl_seq.h>
18
#include <isl_mat_private.h>
19
#include <isl_val_private.h>
20
#include <isl_vec_private.h>
21
#include <isl_config.h>
22
23
enum isl_fold isl_fold_type_negate(enum isl_fold type)
24
0
{
25
0
  switch (type) {
26
0
  case isl_fold_min:
27
0
    return isl_fold_max;
28
0
  case isl_fold_max:
29
0
    return isl_fold_min;
30
0
  case isl_fold_list:
31
0
    return isl_fold_list;
32
0
  }
33
0
34
0
  isl_die(NULL, isl_error_internal, "unhandled isl_fold type", abort());
35
0
}
36
37
static __isl_give isl_qpolynomial_fold *qpolynomial_fold_alloc(
38
  enum isl_fold type, __isl_take isl_space *dim, int n)
39
19
{
40
19
  isl_qpolynomial_fold *fold;
41
19
42
19
  if (!dim)
43
0
    goto error;
44
19
45
19
  isl_assert(dim->ctx, n >= 0, goto error);
46
19
  fold = isl_calloc(dim->ctx, struct isl_qpolynomial_fold,
47
19
      sizeof(struct isl_qpolynomial_fold) +
48
19
      (n - 1) * sizeof(struct isl_qpolynomial *));
49
19
  if (!fold)
50
0
    goto error;
51
19
52
19
  fold->ref = 1;
53
19
  fold->size = n;
54
19
  fold->n = 0;
55
19
  fold->type = type;
56
19
  fold->dim = dim;
57
19
58
19
  return fold;
59
0
error:
60
0
  isl_space_free(dim);
61
0
  return NULL;
62
19
}
63
64
isl_ctx *isl_qpolynomial_fold_get_ctx(__isl_keep isl_qpolynomial_fold *fold)
65
0
{
66
0
  return fold ? fold->dim->ctx : NULL;
67
0
}
68
69
__isl_give isl_space *isl_qpolynomial_fold_get_domain_space(
70
  __isl_keep isl_qpolynomial_fold *fold)
71
0
{
72
0
  return fold ? isl_space_copy(fold->dim) : NULL;
73
0
}
74
75
__isl_give isl_space *isl_qpolynomial_fold_get_space(
76
  __isl_keep isl_qpolynomial_fold *fold)
77
42
{
78
42
  isl_space *space;
79
42
  if (!fold)
80
0
    return NULL;
81
42
  space = isl_space_copy(fold->dim);
82
42
  space = isl_space_from_domain(space);
83
42
  space = isl_space_add_dims(space, isl_dim_out, 1);
84
42
  return space;
85
42
}
86
87
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space(
88
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim)
89
3
{
90
3
  int i;
91
3
92
3
  fold = isl_qpolynomial_fold_cow(fold);
93
3
  if (!fold || !dim)
94
0
    goto error;
95
3
96
6
  
for (i = 0; 3
i < fold->n;
++i3
) {
97
3
    fold->qp[i] = isl_qpolynomial_reset_domain_space(fold->qp[i],
98
3
              isl_space_copy(dim));
99
3
    if (!fold->qp[i])
100
0
      goto error;
101
3
  }
102
3
103
3
  isl_space_free(fold->dim);
104
3
  fold->dim = dim;
105
3
106
3
  return fold;
107
0
error:
108
0
  isl_qpolynomial_fold_free(fold);
109
0
  isl_space_free(dim);
110
0
  return NULL;
111
3
}
112
113
/* Reset the space of "fold".  This function is called from isl_pw_templ.c
114
 * and doesn't know if the space of an element object is represented
115
 * directly or through its domain.  It therefore passes along both.
116
 */
117
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_space_and_domain(
118
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space,
119
  __isl_take isl_space *domain)
120
3
{
121
3
  isl_space_free(space);
122
3
  return isl_qpolynomial_fold_reset_domain_space(fold, domain);
123
3
}
124
125
int isl_qpolynomial_fold_involves_dims(__isl_keep isl_qpolynomial_fold *fold,
126
  enum isl_dim_type type, unsigned first, unsigned n)
127
0
{
128
0
  int i;
129
0
130
0
  if (!fold)
131
0
    return -1;
132
0
  if (fold->n == 0 || n == 0)
133
0
    return 0;
134
0
135
0
  for (i = 0; i < fold->n; ++i) {
136
0
    int involves = isl_qpolynomial_involves_dims(fold->qp[i],
137
0
                  type, first, n);
138
0
    if (involves < 0 || involves)
139
0
      return involves;
140
0
  }
141
0
  return 0;
142
0
}
143
144
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_set_dim_name(
145
  __isl_take isl_qpolynomial_fold *fold,
146
  enum isl_dim_type type, unsigned pos, const char *s)
147
0
{
148
0
  int i;
149
0
150
0
  fold = isl_qpolynomial_fold_cow(fold);
151
0
  if (!fold)
152
0
    return NULL;
153
0
  fold->dim = isl_space_set_dim_name(fold->dim, type, pos, s);
154
0
  if (!fold->dim)
155
0
    goto error;
156
0
157
0
  for (i = 0; i < fold->n; ++i) {
158
0
    fold->qp[i] = isl_qpolynomial_set_dim_name(fold->qp[i],
159
0
                  type, pos, s);
160
0
    if (!fold->qp[i])
161
0
      goto error;
162
0
  }
163
0
164
0
  return fold;
165
0
error:
166
0
  isl_qpolynomial_fold_free(fold);
167
0
  return NULL;
168
0
}
169
170
/* Given a dimension type for an isl_qpolynomial_fold,
171
 * return the corresponding type for the domain.
172
 */
173
static enum isl_dim_type domain_type(enum isl_dim_type type)
174
0
{
175
0
  if (type == isl_dim_in)
176
0
    return isl_dim_set;
177
0
  return type;
178
0
}
179
180
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_drop_dims(
181
  __isl_take isl_qpolynomial_fold *fold,
182
  enum isl_dim_type type, unsigned first, unsigned n)
183
1
{
184
1
  int i;
185
1
  enum isl_dim_type set_type;
186
1
187
1
  if (!fold)
188
0
    return NULL;
189
1
  if (n == 0)
190
1
    return fold;
191
0
192
0
  set_type = domain_type(type);
193
0
194
0
  fold = isl_qpolynomial_fold_cow(fold);
195
0
  if (!fold)
196
0
    return NULL;
197
0
  fold->dim = isl_space_drop_dims(fold->dim, set_type, first, n);
198
0
  if (!fold->dim)
199
0
    goto error;
200
0
201
0
  for (i = 0; i < fold->n; ++i) {
202
0
    fold->qp[i] = isl_qpolynomial_drop_dims(fold->qp[i],
203
0
                  type, first, n);
204
0
    if (!fold->qp[i])
205
0
      goto error;
206
0
  }
207
0
208
0
  return fold;
209
0
error:
210
0
  isl_qpolynomial_fold_free(fold);
211
0
  return NULL;
212
0
}
213
214
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_insert_dims(
215
  __isl_take isl_qpolynomial_fold *fold,
216
  enum isl_dim_type type, unsigned first, unsigned n)
217
0
{
218
0
  int i;
219
0
220
0
  if (!fold)
221
0
    return NULL;
222
0
  if (n == 0 && !isl_space_is_named_or_nested(fold->dim, type))
223
0
    return fold;
224
0
225
0
  fold = isl_qpolynomial_fold_cow(fold);
226
0
  if (!fold)
227
0
    return NULL;
228
0
  fold->dim = isl_space_insert_dims(fold->dim, type, first, n);
229
0
  if (!fold->dim)
230
0
    goto error;
231
0
232
0
  for (i = 0; i < fold->n; ++i) {
233
0
    fold->qp[i] = isl_qpolynomial_insert_dims(fold->qp[i],
234
0
                  type, first, n);
235
0
    if (!fold->qp[i])
236
0
      goto error;
237
0
  }
238
0
239
0
  return fold;
240
0
error:
241
0
  isl_qpolynomial_fold_free(fold);
242
0
  return NULL;
243
0
}
244
245
/* Determine the sign of the constant quasipolynomial "qp".
246
 *
247
 * Return
248
 *  -1 if qp <= 0
249
 *   1 if qp >= 0
250
 *   0 if unknown
251
 *
252
 * For qp == 0, we can return either -1 or 1.  In practice, we return 1.
253
 * For qp == NaN, the sign is undefined, so we return 0.
254
 */
255
static int isl_qpolynomial_cst_sign(__isl_keep isl_qpolynomial *qp)
256
2
{
257
2
  struct isl_upoly_cst *cst;
258
2
259
2
  if (isl_qpolynomial_is_nan(qp))
260
0
    return 0;
261
2
262
2
  cst = isl_upoly_as_cst(qp->upoly);
263
2
  if (!cst)
264
0
    return 0;
265
2
266
2
  return isl_int_sgn(cst->n) < 0 ? 
-11
:
11
;
267
2
}
268
269
static int isl_qpolynomial_aff_sign(__isl_keep isl_set *set,
270
  __isl_keep isl_qpolynomial *qp)
271
0
{
272
0
  enum isl_lp_result res;
273
0
  isl_vec *aff;
274
0
  isl_int opt;
275
0
  int sgn = 0;
276
0
277
0
  aff = isl_qpolynomial_extract_affine(qp);
278
0
  if (!aff)
279
0
    return 0;
280
0
281
0
  isl_int_init(opt);
282
0
283
0
  res = isl_set_solve_lp(set, 0, aff->el + 1, aff->el[0],
284
0
        &opt, NULL, NULL);
285
0
  if (res == isl_lp_error)
286
0
    goto done;
287
0
  if (res == isl_lp_empty ||
288
0
      (res == isl_lp_ok && !isl_int_is_neg(opt))) {
289
0
    sgn = 1;
290
0
    goto done;
291
0
  }
292
0
293
0
  res = isl_set_solve_lp(set, 1, aff->el + 1, aff->el[0],
294
0
        &opt, NULL, NULL);
295
0
  if (res == isl_lp_ok && !isl_int_is_pos(opt))
296
0
    sgn = -1;
297
0
298
0
done:
299
0
  isl_int_clear(opt);
300
0
  isl_vec_free(aff);
301
0
  return sgn;
302
0
}
303
304
/* Determine, if possible, the sign of the quasipolynomial "qp" on
305
 * the domain "set".
306
 *
307
 * If qp is a constant, then the problem is trivial.
308
 * If qp is linear, then we check if the minimum of the corresponding
309
 * affine constraint is non-negative or if the maximum is non-positive.
310
 *
311
 * Otherwise, we check if the outermost variable "v" has a lower bound "l"
312
 * in "set".  If so, we write qp(v,v') as
313
 *
314
 *  q(v,v') * (v - l) + r(v')
315
 *
316
 * if q(v,v') and r(v') have the same known sign, then the original
317
 * quasipolynomial has the same sign as well.
318
 *
319
 * Return
320
 *  -1 if qp <= 0
321
 *   1 if qp >= 0
322
 *   0 if unknown
323
 */
324
static int isl_qpolynomial_sign(__isl_keep isl_set *set,
325
  __isl_keep isl_qpolynomial *qp)
326
2
{
327
2
  int d;
328
2
  int i;
329
2
  int is;
330
2
  struct isl_upoly_rec *rec;
331
2
  isl_vec *v;
332
2
  isl_int l;
333
2
  enum isl_lp_result res;
334
2
  int sgn = 0;
335
2
336
2
  is = isl_qpolynomial_is_cst(qp, NULL, NULL);
337
2
  if (is < 0)
338
0
    return 0;
339
2
  if (is)
340
2
    return isl_qpolynomial_cst_sign(qp);
341
0
342
0
  is = isl_qpolynomial_is_affine(qp);
343
0
  if (is < 0)
344
0
    return 0;
345
0
  if (is)
346
0
    return isl_qpolynomial_aff_sign(set, qp);
347
0
348
0
  if (qp->div->n_row > 0)
349
0
    return 0;
350
0
351
0
  rec = isl_upoly_as_rec(qp->upoly);
352
0
  if (!rec)
353
0
    return 0;
354
0
355
0
  d = isl_space_dim(qp->dim, isl_dim_all);
356
0
  v = isl_vec_alloc(set->ctx, 2 + d);
357
0
  if (!v)
358
0
    return 0;
359
0
360
0
  isl_seq_clr(v->el + 1, 1 + d);
361
0
  isl_int_set_si(v->el[0], 1);
362
0
  isl_int_set_si(v->el[2 + qp->upoly->var], 1);
363
0
364
0
  isl_int_init(l);
365
0
366
0
  res = isl_set_solve_lp(set, 0, v->el + 1, v->el[0], &l, NULL, NULL);
367
0
  if (res == isl_lp_ok) {
368
0
    isl_qpolynomial *min;
369
0
    isl_qpolynomial *base;
370
0
    isl_qpolynomial *r, *q;
371
0
    isl_qpolynomial *t;
372
0
373
0
    min = isl_qpolynomial_cst_on_domain(isl_space_copy(qp->dim), l);
374
0
    base = isl_qpolynomial_var_pow_on_domain(isl_space_copy(qp->dim),
375
0
            qp->upoly->var, 1);
376
0
377
0
    r = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0,
378
0
            isl_upoly_copy(rec->p[rec->n - 1]));
379
0
    q = isl_qpolynomial_copy(r);
380
0
381
0
    for (i = rec->n - 2; i >= 0; --i) {
382
0
      r = isl_qpolynomial_mul(r, isl_qpolynomial_copy(min));
383
0
      t = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0,
384
0
              isl_upoly_copy(rec->p[i]));
385
0
      r = isl_qpolynomial_add(r, t);
386
0
      if (i == 0)
387
0
        break;
388
0
      q = isl_qpolynomial_mul(q, isl_qpolynomial_copy(base));
389
0
      q = isl_qpolynomial_add(q, isl_qpolynomial_copy(r));
390
0
    }
391
0
392
0
    if (isl_qpolynomial_is_zero(q))
393
0
      sgn = isl_qpolynomial_sign(set, r);
394
0
    else if (isl_qpolynomial_is_zero(r))
395
0
      sgn = isl_qpolynomial_sign(set, q);
396
0
    else {
397
0
      int sgn_q, sgn_r;
398
0
      sgn_r = isl_qpolynomial_sign(set, r);
399
0
      sgn_q = isl_qpolynomial_sign(set, q);
400
0
      if (sgn_r == sgn_q)
401
0
        sgn = sgn_r;
402
0
    }
403
0
404
0
    isl_qpolynomial_free(min);
405
0
    isl_qpolynomial_free(base);
406
0
    isl_qpolynomial_free(q);
407
0
    isl_qpolynomial_free(r);
408
0
  }
409
0
410
0
  isl_int_clear(l);
411
0
412
0
  isl_vec_free(v);
413
0
414
0
  return sgn;
415
0
}
416
417
/* Combine "fold1" and "fold2" into a single reduction, eliminating
418
 * those elements of one reduction that are already covered by the other
419
 * reduction on "set".
420
 *
421
 * If "fold1" or "fold2" is an empty reduction, then return
422
 * the other reduction.
423
 * If "fold1" or "fold2" is a NaN, then return this NaN.
424
 */
425
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain(
426
  __isl_keep isl_set *set,
427
  __isl_take isl_qpolynomial_fold *fold1,
428
  __isl_take isl_qpolynomial_fold *fold2)
429
3
{
430
3
  int i, j;
431
3
  int n1;
432
3
  struct isl_qpolynomial_fold *res = NULL;
433
3
  int better;
434
3
435
3
  if (!fold1 || !fold2)
436
0
    goto error;
437
3
438
3
  isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error);
439
3
  isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim),
440
3
      goto error);
441
3
442
3
  better = fold1->type == isl_fold_max ? -1 : 
10
;
443
3
444
3
  if (isl_qpolynomial_fold_is_empty(fold1) ||
445
3
      isl_qpolynomial_fold_is_nan(fold2)) {
446
0
    isl_qpolynomial_fold_free(fold1);
447
0
    return fold2;
448
0
  }
449
3
450
3
  if (isl_qpolynomial_fold_is_empty(fold2) ||
451
3
      isl_qpolynomial_fold_is_nan(fold1)) {
452
0
    isl_qpolynomial_fold_free(fold2);
453
0
    return fold1;
454
0
  }
455
3
456
3
  res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim),
457
3
          fold1->n + fold2->n);
458
3
  if (!res)
459
0
    goto error;
460
3
461
6
  
for (i = 0; 3
i < fold1->n;
++i3
) {
462
3
    res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]);
463
3
    if (!res->qp[res->n])
464
0
      goto error;
465
3
    res->n++;
466
3
  }
467
3
  n1 = res->n;
468
3
469
6
  for (i = 0; i < fold2->n; 
++i3
) {
470
4
    for (j = n1 - 1; j >= 0; 
--j1
) {
471
3
      isl_qpolynomial *d;
472
3
      int sgn, equal;
473
3
      equal = isl_qpolynomial_plain_is_equal(res->qp[j],
474
3
                fold2->qp[i]);
475
3
      if (equal < 0)
476
0
        goto error;
477
3
      if (equal)
478
1
        break;
479
2
      d = isl_qpolynomial_sub(
480
2
        isl_qpolynomial_copy(res->qp[j]),
481
2
        isl_qpolynomial_copy(fold2->qp[i]));
482
2
      sgn = isl_qpolynomial_sign(set, d);
483
2
      isl_qpolynomial_free(d);
484
2
      if (sgn == 0)
485
0
        continue;
486
2
      if (sgn != better)
487
1
        break;
488
1
      isl_qpolynomial_free(res->qp[j]);
489
1
      if (j != n1 - 1)
490
0
        res->qp[j] = res->qp[n1 - 1];
491
1
      n1--;
492
1
      if (n1 != res->n - 1)
493
0
        res->qp[n1] = res->qp[res->n - 1];
494
1
      res->n--;
495
1
    }
496
3
    if (j >= 0)
497
2
      continue;
498
1
    res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]);
499
1
    if (!res->qp[res->n])
500
0
      goto error;
501
1
    res->n++;
502
1
  }
503
3
504
3
  isl_qpolynomial_fold_free(fold1);
505
3
  isl_qpolynomial_fold_free(fold2);
506
3
507
3
  return res;
508
0
error:
509
0
  isl_qpolynomial_fold_free(res);
510
0
  isl_qpolynomial_fold_free(fold1);
511
0
  isl_qpolynomial_fold_free(fold2);
512
0
  return NULL;
513
3
}
514
515
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_qpolynomial(
516
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_qpolynomial *qp)
517
0
{
518
0
  int i;
519
0
520
0
  if (!fold || !qp)
521
0
    goto error;
522
0
523
0
  if (isl_qpolynomial_is_zero(qp)) {
524
0
    isl_qpolynomial_free(qp);
525
0
    return fold;
526
0
  }
527
0
528
0
  fold = isl_qpolynomial_fold_cow(fold);
529
0
  if (!fold)
530
0
    goto error;
531
0
532
0
  for (i = 0; i < fold->n; ++i) {
533
0
    fold->qp[i] = isl_qpolynomial_add(fold->qp[i],
534
0
            isl_qpolynomial_copy(qp));
535
0
    if (!fold->qp[i])
536
0
      goto error;
537
0
  }
538
0
539
0
  isl_qpolynomial_free(qp);
540
0
  return fold;
541
0
error:
542
0
  isl_qpolynomial_fold_free(fold);
543
0
  isl_qpolynomial_free(qp);
544
0
  return NULL;
545
0
}
546
547
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain(
548
  __isl_keep isl_set *dom,
549
  __isl_take isl_qpolynomial_fold *fold1,
550
  __isl_take isl_qpolynomial_fold *fold2)
551
0
{
552
0
  int i;
553
0
  isl_qpolynomial_fold *res = NULL;
554
0
555
0
  if (!fold1 || !fold2)
556
0
    goto error;
557
0
558
0
  if (isl_qpolynomial_fold_is_empty(fold1)) {
559
0
    isl_qpolynomial_fold_free(fold1);
560
0
    return fold2;
561
0
  }
562
0
563
0
  if (isl_qpolynomial_fold_is_empty(fold2)) {
564
0
    isl_qpolynomial_fold_free(fold2);
565
0
    return fold1;
566
0
  }
567
0
568
0
  if (fold1->n == 1 && fold2->n != 1)
569
0
    return isl_qpolynomial_fold_add_on_domain(dom, fold2, fold1);
570
0
571
0
  if (fold2->n == 1) {
572
0
    res = isl_qpolynomial_fold_add_qpolynomial(fold1,
573
0
          isl_qpolynomial_copy(fold2->qp[0]));
574
0
    isl_qpolynomial_fold_free(fold2);
575
0
    return res;
576
0
  }
577
0
578
0
  res = isl_qpolynomial_fold_add_qpolynomial(
579
0
        isl_qpolynomial_fold_copy(fold1),
580
0
        isl_qpolynomial_copy(fold2->qp[0]));
581
0
582
0
  for (i = 1; i < fold2->n; ++i) {
583
0
    isl_qpolynomial_fold *res_i;
584
0
    res_i = isl_qpolynomial_fold_add_qpolynomial(
585
0
          isl_qpolynomial_fold_copy(fold1),
586
0
          isl_qpolynomial_copy(fold2->qp[i]));
587
0
    res = isl_qpolynomial_fold_fold_on_domain(dom, res, res_i);
588
0
  }
589
0
590
0
  isl_qpolynomial_fold_free(fold1);
591
0
  isl_qpolynomial_fold_free(fold2);
592
0
  return res;
593
0
error:
594
0
  isl_qpolynomial_fold_free(res);
595
0
  isl_qpolynomial_fold_free(fold1);
596
0
  isl_qpolynomial_fold_free(fold2);
597
0
  return NULL;
598
0
}
599
600
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities(
601
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq)
602
0
{
603
0
  int i;
604
0
605
0
  if (!fold || !eq)
606
0
    goto error;
607
0
608
0
  fold = isl_qpolynomial_fold_cow(fold);
609
0
  if (!fold)
610
0
    return NULL;
611
0
612
0
  for (i = 0; i < fold->n; ++i) {
613
0
    fold->qp[i] = isl_qpolynomial_substitute_equalities(fold->qp[i],
614
0
              isl_basic_set_copy(eq));
615
0
    if (!fold->qp[i])
616
0
      goto error;
617
0
  }
618
0
619
0
  isl_basic_set_free(eq);
620
0
  return fold;
621
0
error:
622
0
  isl_basic_set_free(eq);
623
0
  isl_qpolynomial_fold_free(fold);
624
0
  return NULL;
625
0
}
626
627
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
628
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
629
0
{
630
0
  int i;
631
0
632
0
  if (!fold || !context)
633
0
    goto error;
634
0
635
0
  fold = isl_qpolynomial_fold_cow(fold);
636
0
  if (!fold)
637
0
    return NULL;
638
0
639
0
  for (i = 0; i < fold->n; ++i) {
640
0
    fold->qp[i] = isl_qpolynomial_gist(fold->qp[i],
641
0
              isl_set_copy(context));
642
0
    if (!fold->qp[i])
643
0
      goto error;
644
0
  }
645
0
646
0
  isl_set_free(context);
647
0
  return fold;
648
0
error:
649
0
  isl_set_free(context);
650
0
  isl_qpolynomial_fold_free(fold);
651
0
  return NULL;
652
0
}
653
654
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params(
655
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
656
0
{
657
0
  isl_space *space = isl_qpolynomial_fold_get_domain_space(fold);
658
0
  isl_set *dom_context = isl_set_universe(space);
659
0
  dom_context = isl_set_intersect_params(dom_context, context);
660
0
  return isl_qpolynomial_fold_gist(fold, dom_context);
661
0
}
662
663
2
#define isl_qpolynomial_fold_involves_nan isl_qpolynomial_fold_is_nan
664
665
#define HAS_TYPE
666
667
#undef PW
668
12
#define PW isl_pw_qpolynomial_fold
669
#undef EL
670
3
#define EL isl_qpolynomial_fold
671
#undef EL_IS_ZERO
672
#define EL_IS_ZERO is_empty
673
#undef ZERO
674
#define ZERO zero
675
#undef IS_ZERO
676
#define IS_ZERO is_zero
677
#undef FIELD
678
64
#define FIELD fold
679
#undef DEFAULT_IS_ZERO
680
0
#define DEFAULT_IS_ZERO 1
681
682
#define NO_NEG
683
#define NO_SUB
684
#define NO_PULLBACK
685
686
#include <isl_pw_templ.c>
687
#include <isl_pw_eval.c>
688
689
#undef UNION
690
0
#define UNION isl_union_pw_qpolynomial_fold
691
#undef PART
692
0
#define PART isl_pw_qpolynomial_fold
693
#undef PARTS
694
#define PARTS pw_qpolynomial_fold
695
696
#define NO_SUB
697
698
#include <isl_union_single.c>
699
#include <isl_union_eval.c>
700
701
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type,
702
  __isl_take isl_space *dim)
703
0
{
704
0
  return qpolynomial_fold_alloc(type, dim, 0);
705
0
}
706
707
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_alloc(
708
  enum isl_fold type, __isl_take isl_qpolynomial *qp)
709
15
{
710
15
  isl_qpolynomial_fold *fold;
711
15
712
15
  if (!qp)
713
0
    return NULL;
714
15
715
15
  fold = qpolynomial_fold_alloc(type, isl_space_copy(qp->dim), 1);
716
15
  if (!fold)
717
0
    goto error;
718
15
719
15
  fold->qp[0] = qp;
720
15
  fold->n++;
721
15
722
15
  return fold;
723
0
error:
724
0
  isl_qpolynomial_fold_free(fold);
725
0
  isl_qpolynomial_free(qp);
726
0
  return NULL;
727
15
}
728
729
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_copy(
730
  __isl_keep isl_qpolynomial_fold *fold)
731
22
{
732
22
  if (!fold)
733
0
    return NULL;
734
22
735
22
  fold->ref++;
736
22
  return fold;
737
22
}
738
739
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup(
740
  __isl_keep isl_qpolynomial_fold *fold)
741
1
{
742
1
  int i;
743
1
  isl_qpolynomial_fold *dup;
744
1
745
1
  if (!fold)
746
0
    return NULL;
747
1
  dup = qpolynomial_fold_alloc(fold->type,
748
1
          isl_space_copy(fold->dim), fold->n);
749
1
  if (!dup)
750
0
    return NULL;
751
1
  
752
1
  dup->n = fold->n;
753
2
  for (i = 0; i < fold->n; 
++i1
) {
754
1
    dup->qp[i] = isl_qpolynomial_copy(fold->qp[i]);
755
1
    if (!dup->qp[i])
756
0
      goto error;
757
1
  }
758
1
759
1
  return dup;
760
0
error:
761
0
  isl_qpolynomial_fold_free(dup);
762
0
  return NULL;
763
1
}
764
765
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow(
766
  __isl_take isl_qpolynomial_fold *fold)
767
5
{
768
5
  if (!fold)
769
0
    return NULL;
770
5
771
5
  if (fold->ref == 1)
772
4
    return fold;
773
1
  fold->ref--;
774
1
  return isl_qpolynomial_fold_dup(fold);
775
1
}
776
777
void isl_qpolynomial_fold_free(__isl_take isl_qpolynomial_fold *fold)
778
40
{
779
40
  int i;
780
40
781
40
  if (!fold)
782
0
    return;
783
40
  if (--fold->ref > 0)
784
21
    return;
785
19
786
38
  
for (i = 0; 19
i < fold->n;
++i19
)
787
19
    isl_qpolynomial_free(fold->qp[i]);
788
19
  isl_space_free(fold->dim);
789
19
  free(fold);
790
19
}
791
792
int isl_qpolynomial_fold_is_empty(__isl_keep isl_qpolynomial_fold *fold)
793
24
{
794
24
  if (!fold)
795
0
    return -1;
796
24
797
24
  return fold->n == 0;
798
24
}
799
800
/* Does "fold" represent max(NaN) or min(NaN)?
801
 */
802
isl_bool isl_qpolynomial_fold_is_nan(__isl_keep isl_qpolynomial_fold *fold)
803
8
{
804
8
  if (!fold)
805
0
    return isl_bool_error;
806
8
  if (fold->n != 1)
807
0
    return isl_bool_false;
808
8
  return isl_qpolynomial_is_nan(fold->qp[0]);
809
8
}
810
811
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold(
812
  __isl_take isl_qpolynomial_fold *fold1,
813
  __isl_take isl_qpolynomial_fold *fold2)
814
0
{
815
0
  int i;
816
0
  struct isl_qpolynomial_fold *res = NULL;
817
0
818
0
  if (!fold1 || !fold2)
819
0
    goto error;
820
0
821
0
  isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error);
822
0
  isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim),
823
0
      goto error);
824
0
825
0
  if (isl_qpolynomial_fold_is_empty(fold1)) {
826
0
    isl_qpolynomial_fold_free(fold1);
827
0
    return fold2;
828
0
  }
829
0
830
0
  if (isl_qpolynomial_fold_is_empty(fold2)) {
831
0
    isl_qpolynomial_fold_free(fold2);
832
0
    return fold1;
833
0
  }
834
0
835
0
  res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim),
836
0
          fold1->n + fold2->n);
837
0
  if (!res)
838
0
    goto error;
839
0
840
0
  for (i = 0; i < fold1->n; ++i) {
841
0
    res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]);
842
0
    if (!res->qp[res->n])
843
0
      goto error;
844
0
    res->n++;
845
0
  }
846
0
847
0
  for (i = 0; i < fold2->n; ++i) {
848
0
    res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]);
849
0
    if (!res->qp[res->n])
850
0
      goto error;
851
0
    res->n++;
852
0
  }
853
0
854
0
  isl_qpolynomial_fold_free(fold1);
855
0
  isl_qpolynomial_fold_free(fold2);
856
0
857
0
  return res;
858
0
error:
859
0
  isl_qpolynomial_fold_free(res);
860
0
  isl_qpolynomial_fold_free(fold1);
861
0
  isl_qpolynomial_fold_free(fold2);
862
0
  return NULL;
863
0
}
864
865
__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold(
866
  __isl_take isl_pw_qpolynomial_fold *pw1,
867
  __isl_take isl_pw_qpolynomial_fold *pw2)
868
18
{
869
18
  int i, j, n;
870
18
  struct isl_pw_qpolynomial_fold *res;
871
18
  isl_set *set;
872
18
873
18
  if (!pw1 || !pw2)
874
0
    goto error;
875
18
876
18
  isl_assert(pw1->dim->ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
877
18
878
18
  if (isl_pw_qpolynomial_fold_is_zero(pw1)) {
879
13
    isl_pw_qpolynomial_fold_free(pw1);
880
13
    return pw2;
881
13
  }
882
5
883
5
  if (isl_pw_qpolynomial_fold_is_zero(pw2)) {
884
2
    isl_pw_qpolynomial_fold_free(pw2);
885
2
    return pw1;
886
2
  }
887
3
888
3
  if (pw1->type != pw2->type)
889
3
    
isl_die0
(pw1->dim->ctx, isl_error_invalid,
890
3
      "fold types don't match", goto error);
891
3
892
3
  n = (pw1->n + 1) * (pw2->n + 1);
893
3
  res = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pw1->dim),
894
3
            pw1->type, n);
895
3
896
6
  for (i = 0; i < pw1->n; 
++i3
) {
897
3
    set = isl_set_copy(pw1->p[i].set);
898
6
    for (j = 0; j < pw2->n; 
++j3
) {
899
3
      struct isl_set *common;
900
3
      isl_qpolynomial_fold *sum;
901
3
      set = isl_set_subtract(set,
902
3
          isl_set_copy(pw2->p[j].set));
903
3
      common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
904
3
            isl_set_copy(pw2->p[j].set));
905
3
      if (isl_set_plain_is_empty(common)) {
906
0
        isl_set_free(common);
907
0
        continue;
908
0
      }
909
3
910
3
      sum = isl_qpolynomial_fold_fold_on_domain(common,
911
3
             isl_qpolynomial_fold_copy(pw1->p[i].fold),
912
3
             isl_qpolynomial_fold_copy(pw2->p[j].fold));
913
3
914
3
      res = isl_pw_qpolynomial_fold_add_piece(res, common, sum);
915
3
    }
916
3
    res = isl_pw_qpolynomial_fold_add_piece(res, set,
917
3
      isl_qpolynomial_fold_copy(pw1->p[i].fold));
918
3
  }
919
3
920
6
  for (j = 0; j < pw2->n; 
++j3
) {
921
3
    set = isl_set_copy(pw2->p[j].set);
922
6
    for (i = 0; i < pw1->n; 
++i3
)
923
3
      set = isl_set_subtract(set, isl_set_copy(pw1->p[i].set));
924
3
    res = isl_pw_qpolynomial_fold_add_piece(res, set,
925
3
            isl_qpolynomial_fold_copy(pw2->p[j].fold));
926
3
  }
927
3
928
3
  isl_pw_qpolynomial_fold_free(pw1);
929
3
  isl_pw_qpolynomial_fold_free(pw2);
930
3
931
3
  return res;
932
0
error:
933
0
  isl_pw_qpolynomial_fold_free(pw1);
934
0
  isl_pw_qpolynomial_fold_free(pw2);
935
0
  return NULL;
936
3
}
937
938
__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
939
  __isl_take isl_union_pw_qpolynomial_fold *u,
940
  __isl_take isl_pw_qpolynomial_fold *part)
941
0
{
942
0
  struct isl_hash_table_entry *entry;
943
0
944
0
  u = isl_union_pw_qpolynomial_fold_cow(u);
945
0
946
0
  if (!part || !u)
947
0
    goto error;
948
0
  if (isl_space_check_equal_params(part->dim, u->space) < 0)
949
0
    goto error;
950
0
951
0
  entry = isl_union_pw_qpolynomial_fold_find_part_entry(u, part->dim, 1);
952
0
  if (!entry)
953
0
    goto error;
954
0
955
0
  if (!entry->data)
956
0
    entry->data = part;
957
0
  else {
958
0
    entry->data = isl_pw_qpolynomial_fold_fold(entry->data,
959
0
              isl_pw_qpolynomial_fold_copy(part));
960
0
    if (!entry->data)
961
0
      goto error;
962
0
    isl_pw_qpolynomial_fold_free(part);
963
0
  }
964
0
965
0
  return u;
966
0
error:
967
0
  isl_pw_qpolynomial_fold_free(part);
968
0
  isl_union_pw_qpolynomial_fold_free(u);
969
0
  return NULL;
970
0
}
971
972
static isl_stat fold_part(__isl_take isl_pw_qpolynomial_fold *part, void *user)
973
0
{
974
0
  isl_union_pw_qpolynomial_fold **u;
975
0
  u = (isl_union_pw_qpolynomial_fold **)user;
976
0
977
0
  *u = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(*u, part);
978
0
979
0
  return isl_stat_ok;
980
0
}
981
982
__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold(
983
  __isl_take isl_union_pw_qpolynomial_fold *u1,
984
  __isl_take isl_union_pw_qpolynomial_fold *u2)
985
0
{
986
0
  u1 = isl_union_pw_qpolynomial_fold_cow(u1);
987
0
988
0
  if (!u1 || !u2)
989
0
    goto error;
990
0
991
0
  if (isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(u2,
992
0
              &fold_part, &u1) < 0)
993
0
    goto error;
994
0
995
0
  isl_union_pw_qpolynomial_fold_free(u2);
996
0
997
0
  return u1;
998
0
error:
999
0
  isl_union_pw_qpolynomial_fold_free(u1);
1000
0
  isl_union_pw_qpolynomial_fold_free(u2);
1001
0
  return NULL;
1002
0
}
1003
1004
__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial(
1005
  enum isl_fold type, __isl_take isl_pw_qpolynomial *pwqp)
1006
4
{
1007
4
  int i;
1008
4
  isl_pw_qpolynomial_fold *pwf;
1009
4
1010
4
  if (!pwqp)
1011
0
    return NULL;
1012
4
  
1013
4
  pwf = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pwqp->dim),
1014
4
            type, pwqp->n);
1015
4
1016
7
  for (i = 0; i < pwqp->n; 
++i3
)
1017
3
    pwf = isl_pw_qpolynomial_fold_add_piece(pwf,
1018
3
      isl_set_copy(pwqp->p[i].set),
1019
3
      isl_qpolynomial_fold_alloc(type,
1020
3
        isl_qpolynomial_copy(pwqp->p[i].qp)));
1021
4
1022
4
  isl_pw_qpolynomial_free(pwqp);
1023
4
1024
4
  return pwf;
1025
4
}
1026
1027
__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add(
1028
  __isl_take isl_pw_qpolynomial_fold *pwf1,
1029
  __isl_take isl_pw_qpolynomial_fold *pwf2)
1030
0
{
1031
0
  return isl_pw_qpolynomial_fold_union_add_(pwf1, pwf2);
1032
0
}
1033
1034
/* Compare two quasi-polynomial reductions.
1035
 *
1036
 * Return -1 if "fold1" is "smaller" than "fold2", 1 if "fold1" is "greater"
1037
 * than "fold2" and 0 if they are equal.
1038
 */
1039
int isl_qpolynomial_fold_plain_cmp(__isl_keep isl_qpolynomial_fold *fold1,
1040
  __isl_keep isl_qpolynomial_fold *fold2)
1041
0
{
1042
0
  int i;
1043
0
1044
0
  if (fold1 == fold2)
1045
0
    return 0;
1046
0
  if (!fold1)
1047
0
    return -1;
1048
0
  if (!fold2)
1049
0
    return 1;
1050
0
1051
0
  if (fold1->n != fold2->n)
1052
0
    return fold1->n - fold2->n;
1053
0
1054
0
  for (i = 0; i < fold1->n; ++i) {
1055
0
    int cmp;
1056
0
1057
0
    cmp = isl_qpolynomial_plain_cmp(fold1->qp[i], fold2->qp[i]);
1058
0
    if (cmp != 0)
1059
0
      return cmp;
1060
0
  }
1061
0
1062
0
  return 0;
1063
0
}
1064
1065
int isl_qpolynomial_fold_plain_is_equal(__isl_keep isl_qpolynomial_fold *fold1,
1066
  __isl_keep isl_qpolynomial_fold *fold2)
1067
1
{
1068
1
  int i;
1069
1
1070
1
  if (!fold1 || !fold2)
1071
0
    return -1;
1072
1
1073
1
  if (fold1->n != fold2->n)
1074
0
    return 0;
1075
1
1076
1
  /* We probably want to sort the qps first... */
1077
2
  
for (i = 0; 1
i < fold1->n;
++i1
) {
1078
1
    int eq = isl_qpolynomial_plain_is_equal(fold1->qp[i], fold2->qp[i]);
1079
1
    if (eq < 0 || !eq)
1080
0
      return eq;
1081
1
  }
1082
1
1083
1
  return 1;
1084
1
}
1085
1086
__isl_give isl_val *isl_qpolynomial_fold_eval(
1087
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_point *pnt)
1088
0
{
1089
0
  isl_ctx *ctx;
1090
0
  isl_val *v;
1091
0
1092
0
  if (!fold || !pnt)
1093
0
    goto error;
1094
0
  ctx = isl_point_get_ctx(pnt);
1095
0
  isl_assert(pnt->dim->ctx, isl_space_is_equal(pnt->dim, fold->dim), goto error);
1096
0
  isl_assert(pnt->dim->ctx,
1097
0
    fold->type == isl_fold_max || fold->type == isl_fold_min,
1098
0
    goto error);
1099
0
1100
0
  if (fold->n == 0)
1101
0
    v = isl_val_zero(ctx);
1102
0
  else {
1103
0
    int i;
1104
0
    v = isl_qpolynomial_eval(isl_qpolynomial_copy(fold->qp[0]),
1105
0
            isl_point_copy(pnt));
1106
0
    for (i = 1; i < fold->n; ++i) {
1107
0
      isl_val *v_i;
1108
0
      v_i = isl_qpolynomial_eval(
1109
0
              isl_qpolynomial_copy(fold->qp[i]),
1110
0
              isl_point_copy(pnt));
1111
0
      if (fold->type == isl_fold_max)
1112
0
        v = isl_val_max(v, v_i);
1113
0
      else
1114
0
        v = isl_val_min(v, v_i);
1115
0
    }
1116
0
  }
1117
0
  isl_qpolynomial_fold_free(fold);
1118
0
  isl_point_free(pnt);
1119
0
1120
0
  return v;
1121
0
error:
1122
0
  isl_qpolynomial_fold_free(fold);
1123
0
  isl_point_free(pnt);
1124
0
  return NULL;
1125
0
}
1126
1127
size_t isl_pw_qpolynomial_fold_size(__isl_keep isl_pw_qpolynomial_fold *pwf)
1128
0
{
1129
0
  int i;
1130
0
  size_t n = 0;
1131
0
1132
0
  for (i = 0; i < pwf->n; ++i)
1133
0
    n += pwf->p[i].fold->n;
1134
0
1135
0
  return n;
1136
0
}
1137
1138
__isl_give isl_val *isl_qpolynomial_fold_opt_on_domain(
1139
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *set, int max)
1140
7
{
1141
7
  int i;
1142
7
  isl_val *opt;
1143
7
1144
7
  if (!set || !fold)
1145
0
    goto error;
1146
7
1147
7
  if (fold->n == 0) {
1148
0
    opt = isl_val_zero(isl_set_get_ctx(set));
1149
0
    isl_set_free(set);
1150
0
    isl_qpolynomial_fold_free(fold);
1151
0
    return opt;
1152
0
  }
1153
7
1154
7
  opt = isl_qpolynomial_opt_on_domain(isl_qpolynomial_copy(fold->qp[0]),
1155
7
            isl_set_copy(set), max);
1156
7
  for (i = 1; i < fold->n; 
++i0
) {
1157
0
    isl_val *opt_i;
1158
0
    opt_i = isl_qpolynomial_opt_on_domain(
1159
0
        isl_qpolynomial_copy(fold->qp[i]),
1160
0
        isl_set_copy(set), max);
1161
0
    if (max)
1162
0
      opt = isl_val_max(opt, opt_i);
1163
0
    else
1164
0
      opt = isl_val_min(opt, opt_i);
1165
0
  }
1166
7
1167
7
  isl_set_free(set);
1168
7
  isl_qpolynomial_fold_free(fold);
1169
7
1170
7
  return opt;
1171
0
error:
1172
0
  isl_set_free(set);
1173
0
  isl_qpolynomial_fold_free(fold);
1174
0
  return NULL;
1175
7
}
1176
1177
/* Check whether for each quasi-polynomial in "fold2" there is
1178
 * a quasi-polynomial in "fold1" that dominates it on "set".
1179
 */
1180
static int qpolynomial_fold_covers_on_domain(__isl_keep isl_set *set,
1181
  __isl_keep isl_qpolynomial_fold *fold1,
1182
  __isl_keep isl_qpolynomial_fold *fold2)
1183
0
{
1184
0
  int i, j;
1185
0
  int covers;
1186
0
1187
0
  if (!set || !fold1 || !fold2)
1188
0
    return -1;
1189
0
1190
0
  covers = fold1->type == isl_fold_max ? 1 : -1;
1191
0
1192
0
  for (i = 0; i < fold2->n; ++i) {
1193
0
    for (j = 0; j < fold1->n; ++j) {
1194
0
      isl_qpolynomial *d;
1195
0
      int sgn;
1196
0
1197
0
      d = isl_qpolynomial_sub(
1198
0
        isl_qpolynomial_copy(fold1->qp[j]),
1199
0
        isl_qpolynomial_copy(fold2->qp[i]));
1200
0
      sgn = isl_qpolynomial_sign(set, d);
1201
0
      isl_qpolynomial_free(d);
1202
0
      if (sgn == covers)
1203
0
        break;
1204
0
    }
1205
0
    if (j >= fold1->n)
1206
0
      return 0;
1207
0
  }
1208
0
1209
0
  return 1;
1210
0
}
1211
1212
/* Check whether "pwf1" dominated "pwf2", i.e., the domain of "pwf1" contains
1213
 * that of "pwf2" and on each cell, the corresponding fold from pwf1 dominates
1214
 * that of pwf2.
1215
 */
1216
int isl_pw_qpolynomial_fold_covers(__isl_keep isl_pw_qpolynomial_fold *pwf1,
1217
  __isl_keep isl_pw_qpolynomial_fold *pwf2)
1218
2
{
1219
2
  int i, j;
1220
2
  isl_set *dom1, *dom2;
1221
2
  int is_subset;
1222
2
1223
2
  if (!pwf1 || !pwf2)
1224
0
    return -1;
1225
2
1226
2
  if (pwf2->n == 0)
1227
0
    return 1;
1228
2
  if (pwf1->n == 0)
1229
2
    return 0;
1230
0
1231
0
  dom1 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf1));
1232
0
  dom2 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf2));
1233
0
  is_subset = isl_set_is_subset(dom2, dom1);
1234
0
  isl_set_free(dom1);
1235
0
  isl_set_free(dom2);
1236
0
1237
0
  if (is_subset < 0 || !is_subset)
1238
0
    return is_subset;
1239
0
1240
0
  for (i = 0; i < pwf2->n; ++i) {
1241
0
    for (j = 0; j < pwf1->n; ++j) {
1242
0
      int is_empty;
1243
0
      isl_set *common;
1244
0
      int covers;
1245
0
1246
0
      common = isl_set_intersect(isl_set_copy(pwf1->p[j].set),
1247
0
               isl_set_copy(pwf2->p[i].set));
1248
0
      is_empty = isl_set_is_empty(common);
1249
0
      if (is_empty < 0 || is_empty) {
1250
0
        isl_set_free(common);
1251
0
        if (is_empty < 0)
1252
0
          return -1;
1253
0
        continue;
1254
0
      }
1255
0
      covers = qpolynomial_fold_covers_on_domain(common,
1256
0
          pwf1->p[j].fold, pwf2->p[i].fold);
1257
0
      isl_set_free(common);
1258
0
      if (covers < 0 || !covers)
1259
0
        return covers;
1260
0
    }
1261
0
  }
1262
0
1263
0
  return 1;
1264
0
}
1265
1266
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain(
1267
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph)
1268
1
{
1269
1
  int i;
1270
1
  isl_ctx *ctx;
1271
1
1272
1
  if (!fold || !morph)
1273
0
    goto error;
1274
1
1275
1
  ctx = fold->dim->ctx;
1276
1
  isl_assert(ctx, isl_space_is_equal(fold->dim, morph->dom->dim), goto error);
1277
1
1278
1
  fold = isl_qpolynomial_fold_cow(fold);
1279
1
  if (!fold)
1280
0
    goto error;
1281
1
1282
1
  isl_space_free(fold->dim);
1283
1
  fold->dim = isl_space_copy(morph->ran->dim);
1284
1
  if (!fold->dim)
1285
0
    goto error;
1286
1
1287
2
  
for (i = 0; 1
i < fold->n;
++i1
) {
1288
1
    fold->qp[i] = isl_qpolynomial_morph_domain(fold->qp[i],
1289
1
            isl_morph_copy(morph));
1290
1
    if (!fold->qp[i])
1291
0
      goto error;
1292
1
  }
1293
1
1294
1
  isl_morph_free(morph);
1295
1
1296
1
  return fold;
1297
0
error:
1298
0
  isl_qpolynomial_fold_free(fold);
1299
0
  isl_morph_free(morph);
1300
0
  return NULL;
1301
1
}
1302
1303
enum isl_fold isl_qpolynomial_fold_get_type(__isl_keep isl_qpolynomial_fold *fold)
1304
2
{
1305
2
  if (!fold)
1306
0
    return isl_fold_list;
1307
2
  return fold->type;
1308
2
}
1309
1310
enum isl_fold isl_union_pw_qpolynomial_fold_get_type(
1311
  __isl_keep isl_union_pw_qpolynomial_fold *upwf)
1312
0
{
1313
0
  if (!upwf)
1314
0
    return isl_fold_list;
1315
0
  return upwf->type;
1316
0
}
1317
1318
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift(
1319
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim)
1320
1
{
1321
1
  int i;
1322
1
1323
1
  if (!fold || !dim)
1324
0
    goto error;
1325
1
1326
1
  if (isl_space_is_equal(fold->dim, dim)) {
1327
0
    isl_space_free(dim);
1328
0
    return fold;
1329
0
  }
1330
1
1331
1
  fold = isl_qpolynomial_fold_cow(fold);
1332
1
  if (!fold)
1333
0
    goto error;
1334
1
1335
1
  isl_space_free(fold->dim);
1336
1
  fold->dim = isl_space_copy(dim);
1337
1
  if (!fold->dim)
1338
0
    goto error;
1339
1
1340
2
  
for (i = 0; 1
i < fold->n;
++i1
) {
1341
1
    fold->qp[i] = isl_qpolynomial_lift(fold->qp[i],
1342
1
            isl_space_copy(dim));
1343
1
    if (!fold->qp[i])
1344
0
      goto error;
1345
1
  }
1346
1
1347
1
  isl_space_free(dim);
1348
1
1349
1
  return fold;
1350
0
error:
1351
0
  isl_qpolynomial_fold_free(fold);
1352
0
  isl_space_free(dim);
1353
0
  return NULL;
1354
1
}
1355
1356
isl_stat isl_qpolynomial_fold_foreach_qpolynomial(
1357
  __isl_keep isl_qpolynomial_fold *fold,
1358
  isl_stat (*fn)(__isl_take isl_qpolynomial *qp, void *user), void *user)
1359
2
{
1360
2
  int i;
1361
2
1362
2
  if (!fold)
1363
0
    return isl_stat_error;
1364
2
1365
4
  
for (i = 0; 2
i < fold->n;
++i2
)
1366
2
    if (fn(isl_qpolynomial_copy(fold->qp[i]), user) < 0)
1367
0
      return isl_stat_error;
1368
2
1369
2
  return isl_stat_ok;
1370
2
}
1371
1372
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims(
1373
  __isl_take isl_qpolynomial_fold *fold,
1374
  enum isl_dim_type dst_type, unsigned dst_pos,
1375
  enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1376
0
{
1377
0
  int i;
1378
0
  enum isl_dim_type set_src_type, set_dst_type;
1379
0
1380
0
  if (n == 0)
1381
0
    return fold;
1382
0
1383
0
  fold = isl_qpolynomial_fold_cow(fold);
1384
0
  if (!fold)
1385
0
    return NULL;
1386
0
1387
0
  set_src_type = domain_type(src_type);
1388
0
  set_dst_type = domain_type(dst_type);
1389
0
1390
0
  fold->dim = isl_space_move_dims(fold->dim, set_dst_type, dst_pos,
1391
0
            set_src_type, src_pos, n);
1392
0
  if (!fold->dim)
1393
0
    goto error;
1394
0
1395
0
  for (i = 0; i < fold->n; ++i) {
1396
0
    fold->qp[i] = isl_qpolynomial_move_dims(fold->qp[i],
1397
0
        dst_type, dst_pos, src_type, src_pos, n);
1398
0
    if (!fold->qp[i])
1399
0
      goto error;
1400
0
  }
1401
0
1402
0
  return fold;
1403
0
error:
1404
0
  isl_qpolynomial_fold_free(fold);
1405
0
  return NULL;
1406
0
}
1407
1408
/* For each 0 <= i < "n", replace variable "first" + i of type "type"
1409
 * in fold->qp[k] by subs[i].
1410
 */
1411
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute(
1412
  __isl_take isl_qpolynomial_fold *fold,
1413
  enum isl_dim_type type, unsigned first, unsigned n,
1414
  __isl_keep isl_qpolynomial **subs)
1415
0
{
1416
0
  int i;
1417
0
1418
0
  if (n == 0)
1419
0
    return fold;
1420
0
1421
0
  fold = isl_qpolynomial_fold_cow(fold);
1422
0
  if (!fold)
1423
0
    return NULL;
1424
0
1425
0
  for (i = 0; i < fold->n; ++i) {
1426
0
    fold->qp[i] = isl_qpolynomial_substitute(fold->qp[i],
1427
0
        type, first, n, subs);
1428
0
    if (!fold->qp[i])
1429
0
      goto error;
1430
0
  }
1431
0
1432
0
  return fold;
1433
0
error:
1434
0
  isl_qpolynomial_fold_free(fold);
1435
0
  return NULL;
1436
0
}
1437
1438
static isl_stat add_pwqp(__isl_take isl_pw_qpolynomial *pwqp, void *user)
1439
0
{
1440
0
  isl_pw_qpolynomial_fold *pwf;
1441
0
  isl_union_pw_qpolynomial_fold **upwf;
1442
0
  struct isl_hash_table_entry *entry;
1443
0
1444
0
  upwf = (isl_union_pw_qpolynomial_fold **)user;
1445
0
1446
0
  entry = isl_union_pw_qpolynomial_fold_find_part_entry(*upwf,
1447
0
       pwqp->dim, 1);
1448
0
  if (!entry)
1449
0
    goto error;
1450
0
1451
0
  pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial((*upwf)->type, pwqp);
1452
0
  if (!entry->data)
1453
0
    entry->data = pwf;
1454
0
  else {
1455
0
    entry->data = isl_pw_qpolynomial_fold_add(entry->data, pwf);
1456
0
    if (!entry->data)
1457
0
      return isl_stat_error;
1458
0
    if (isl_pw_qpolynomial_fold_is_zero(entry->data))
1459
0
      *upwf = isl_union_pw_qpolynomial_fold_remove_part_entry(
1460
0
                *upwf, entry);
1461
0
  }
1462
0
1463
0
  return isl_stat_ok;
1464
0
error:
1465
0
  isl_pw_qpolynomial_free(pwqp);
1466
0
  return isl_stat_error;
1467
0
}
1468
1469
__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial(
1470
  __isl_take isl_union_pw_qpolynomial_fold *upwf,
1471
  __isl_take isl_union_pw_qpolynomial *upwqp)
1472
0
{
1473
0
  upwf = isl_union_pw_qpolynomial_fold_align_params(upwf,
1474
0
        isl_union_pw_qpolynomial_get_space(upwqp));
1475
0
  upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1476
0
        isl_union_pw_qpolynomial_fold_get_space(upwf));
1477
0
1478
0
  upwf = isl_union_pw_qpolynomial_fold_cow(upwf);
1479
0
  if (!upwf || !upwqp)
1480
0
    goto error;
1481
0
1482
0
  if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &add_pwqp,
1483
0
               &upwf) < 0)
1484
0
    goto error;
1485
0
1486
0
  isl_union_pw_qpolynomial_free(upwqp);
1487
0
1488
0
  return upwf;
1489
0
error:
1490
0
  isl_union_pw_qpolynomial_fold_free(upwf);
1491
0
  isl_union_pw_qpolynomial_free(upwqp);
1492
0
  return NULL;
1493
0
}
1494
1495
static isl_bool join_compatible(__isl_keep isl_space *space1,
1496
  __isl_keep isl_space *space2)
1497
0
{
1498
0
  isl_bool m;
1499
0
  m = isl_space_has_equal_params(space1, space2);
1500
0
  if (m < 0 || !m)
1501
0
    return m;
1502
0
  return isl_space_tuple_is_equal(space1, isl_dim_out,
1503
0
          space2, isl_dim_in);
1504
0
}
1505
1506
/* Compute the intersection of the range of the map and the domain
1507
 * of the piecewise quasipolynomial reduction and then compute a bound
1508
 * on the associated quasipolynomial reduction over all elements
1509
 * in this intersection.
1510
 *
1511
 * We first introduce some unconstrained dimensions in the
1512
 * piecewise quasipolynomial, intersect the resulting domain
1513
 * with the wrapped map and the compute the sum.
1514
 */
1515
__isl_give isl_pw_qpolynomial_fold *isl_map_apply_pw_qpolynomial_fold(
1516
  __isl_take isl_map *map, __isl_take isl_pw_qpolynomial_fold *pwf,
1517
  int *tight)
1518
0
{
1519
0
  isl_ctx *ctx;
1520
0
  isl_set *dom;
1521
0
  isl_space *map_dim;
1522
0
  isl_space *pwf_dim;
1523
0
  unsigned n_in;
1524
0
  isl_bool ok;
1525
0
1526
0
  ctx = isl_map_get_ctx(map);
1527
0
  if (!ctx)
1528
0
    goto error;
1529
0
1530
0
  map_dim = isl_map_get_space(map);
1531
0
  pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf);
1532
0
  ok = join_compatible(map_dim, pwf_dim);
1533
0
  isl_space_free(map_dim);
1534
0
  isl_space_free(pwf_dim);
1535
0
  if (ok < 0)
1536
0
    goto error;
1537
0
  if (!ok)
1538
0
    isl_die(ctx, isl_error_invalid, "incompatible dimensions",
1539
0
      goto error);
1540
0
1541
0
  n_in = isl_map_dim(map, isl_dim_in);
1542
0
  pwf = isl_pw_qpolynomial_fold_insert_dims(pwf, isl_dim_in, 0, n_in);
1543
0
1544
0
  dom = isl_map_wrap(map);
1545
0
  pwf = isl_pw_qpolynomial_fold_reset_domain_space(pwf,
1546
0
            isl_set_get_space(dom));
1547
0
1548
0
  pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, dom);
1549
0
  pwf = isl_pw_qpolynomial_fold_bound(pwf, tight);
1550
0
  
1551
0
  return pwf;
1552
0
error:
1553
0
  isl_map_free(map);
1554
0
  isl_pw_qpolynomial_fold_free(pwf);
1555
0
  return NULL;
1556
0
}
1557
1558
__isl_give isl_pw_qpolynomial_fold *isl_set_apply_pw_qpolynomial_fold(
1559
  __isl_take isl_set *set, __isl_take isl_pw_qpolynomial_fold *pwf,
1560
  int *tight)
1561
0
{
1562
0
  return isl_map_apply_pw_qpolynomial_fold(set, pwf, tight);
1563
0
}
1564
1565
struct isl_apply_fold_data {
1566
  isl_union_pw_qpolynomial_fold *upwf;
1567
  isl_union_pw_qpolynomial_fold *res;
1568
  isl_map *map;
1569
  int tight;
1570
};
1571
1572
static isl_stat pw_qpolynomial_fold_apply(
1573
  __isl_take isl_pw_qpolynomial_fold *pwf, void *user)
1574
0
{
1575
0
  isl_space *map_dim;
1576
0
  isl_space *pwf_dim;
1577
0
  struct isl_apply_fold_data *data = user;
1578
0
  isl_bool ok;
1579
0
1580
0
  map_dim = isl_map_get_space(data->map);
1581
0
  pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf);
1582
0
  ok = join_compatible(map_dim, pwf_dim);
1583
0
  isl_space_free(map_dim);
1584
0
  isl_space_free(pwf_dim);
1585
0
1586
0
  if (ok < 0)
1587
0
    return isl_stat_error;
1588
0
  if (ok) {
1589
0
    pwf = isl_map_apply_pw_qpolynomial_fold(isl_map_copy(data->map),
1590
0
            pwf, data->tight ? &data->tight : NULL);
1591
0
    data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
1592
0
              data->res, pwf);
1593
0
  } else
1594
0
    isl_pw_qpolynomial_fold_free(pwf);
1595
0
1596
0
  return isl_stat_ok;
1597
0
}
1598
1599
static isl_stat map_apply(__isl_take isl_map *map, void *user)
1600
0
{
1601
0
  struct isl_apply_fold_data *data = user;
1602
0
  isl_stat r;
1603
0
1604
0
  data->map = map;
1605
0
  r = isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(
1606
0
        data->upwf, &pw_qpolynomial_fold_apply, data);
1607
0
1608
0
  isl_map_free(map);
1609
0
  return r;
1610
0
}
1611
1612
__isl_give isl_union_pw_qpolynomial_fold *isl_union_map_apply_union_pw_qpolynomial_fold(
1613
  __isl_take isl_union_map *umap,
1614
  __isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight)
1615
0
{
1616
0
  isl_space *dim;
1617
0
  enum isl_fold type;
1618
0
  struct isl_apply_fold_data data;
1619
0
1620
0
  upwf = isl_union_pw_qpolynomial_fold_align_params(upwf,
1621
0
        isl_union_map_get_space(umap));
1622
0
  umap = isl_union_map_align_params(umap,
1623
0
        isl_union_pw_qpolynomial_fold_get_space(upwf));
1624
0
1625
0
  data.upwf = upwf;
1626
0
  data.tight = tight ? 1 : 0;
1627
0
  dim = isl_union_pw_qpolynomial_fold_get_space(upwf);
1628
0
  type = isl_union_pw_qpolynomial_fold_get_type(upwf);
1629
0
  data.res = isl_union_pw_qpolynomial_fold_zero(dim, type);
1630
0
  if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
1631
0
    goto error;
1632
0
1633
0
  isl_union_map_free(umap);
1634
0
  isl_union_pw_qpolynomial_fold_free(upwf);
1635
0
1636
0
  if (tight)
1637
0
    *tight = data.tight;
1638
0
1639
0
  return data.res;
1640
0
error:
1641
0
  isl_union_map_free(umap);
1642
0
  isl_union_pw_qpolynomial_fold_free(upwf);
1643
0
  isl_union_pw_qpolynomial_fold_free(data.res);
1644
0
  return NULL;
1645
0
}
1646
1647
__isl_give isl_union_pw_qpolynomial_fold *isl_union_set_apply_union_pw_qpolynomial_fold(
1648
  __isl_take isl_union_set *uset,
1649
  __isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight)
1650
0
{
1651
0
  return isl_union_map_apply_union_pw_qpolynomial_fold(uset, upwf, tight);
1652
0
}
1653
1654
/* Reorder the dimension of "fold" according to the given reordering.
1655
 */
1656
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain(
1657
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r)
1658
0
{
1659
0
  int i;
1660
0
1661
0
  fold = isl_qpolynomial_fold_cow(fold);
1662
0
  if (!fold || !r)
1663
0
    goto error;
1664
0
1665
0
  for (i = 0; i < fold->n; ++i) {
1666
0
    fold->qp[i] = isl_qpolynomial_realign_domain(fold->qp[i],
1667
0
                isl_reordering_copy(r));
1668
0
    if (!fold->qp[i])
1669
0
      goto error;
1670
0
  }
1671
0
1672
0
  fold = isl_qpolynomial_fold_reset_domain_space(fold,
1673
0
                isl_space_copy(r->dim));
1674
0
1675
0
  isl_reordering_free(r);
1676
0
1677
0
  return fold;
1678
0
error:
1679
0
  isl_qpolynomial_fold_free(fold);
1680
0
  isl_reordering_free(r);
1681
0
  return NULL;
1682
0
}
1683
1684
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int(
1685
  __isl_take isl_qpolynomial_fold *fold, isl_int v)
1686
0
{
1687
0
  int i;
1688
0
1689
0
  if (isl_int_is_one(v))
1690
0
    return fold;
1691
0
  if (fold && isl_int_is_zero(v)) {
1692
0
    isl_qpolynomial_fold *zero;
1693
0
    isl_space *dim = isl_space_copy(fold->dim);
1694
0
    zero = isl_qpolynomial_fold_empty(fold->type, dim);
1695
0
    isl_qpolynomial_fold_free(fold);
1696
0
    return zero;
1697
0
  }
1698
0
1699
0
  fold = isl_qpolynomial_fold_cow(fold);
1700
0
  if (!fold)
1701
0
    return NULL;
1702
0
1703
0
  if (isl_int_is_neg(v))
1704
0
    fold->type = isl_fold_type_negate(fold->type);
1705
0
  for (i = 0; i < fold->n; ++i) {
1706
0
    fold->qp[i] = isl_qpolynomial_mul_isl_int(fold->qp[i], v);
1707
0
    if (!fold->qp[i])
1708
0
      goto error;
1709
0
  }
1710
0
1711
0
  return fold;
1712
0
error:
1713
0
  isl_qpolynomial_fold_free(fold);
1714
0
  return NULL;
1715
0
}
1716
1717
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale(
1718
  __isl_take isl_qpolynomial_fold *fold, isl_int v)
1719
0
{
1720
0
  return isl_qpolynomial_fold_mul_isl_int(fold, v);
1721
0
}
1722
1723
/* Multiply "fold" by "v".
1724
 */
1725
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_val(
1726
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
1727
0
{
1728
0
  int i;
1729
0
1730
0
  if (!fold || !v)
1731
0
    goto error;
1732
0
1733
0
  if (isl_val_is_one(v)) {
1734
0
    isl_val_free(v);
1735
0
    return fold;
1736
0
  }
1737
0
  if (isl_val_is_zero(v)) {
1738
0
    isl_qpolynomial_fold *zero;
1739
0
    isl_space *space = isl_qpolynomial_fold_get_domain_space(fold);
1740
0
    zero = isl_qpolynomial_fold_empty(fold->type, space);
1741
0
    isl_qpolynomial_fold_free(fold);
1742
0
    isl_val_free(v);
1743
0
    return zero;
1744
0
  }
1745
0
  if (!isl_val_is_rat(v))
1746
0
    isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid,
1747
0
      "expecting rational factor", goto error);
1748
0
1749
0
  fold = isl_qpolynomial_fold_cow(fold);
1750
0
  if (!fold)
1751
0
    goto error;
1752
0
1753
0
  if (isl_val_is_neg(v))
1754
0
    fold->type = isl_fold_type_negate(fold->type);
1755
0
  for (i = 0; i < fold->n; ++i) {
1756
0
    fold->qp[i] = isl_qpolynomial_scale_val(fold->qp[i],
1757
0
              isl_val_copy(v));
1758
0
    if (!fold->qp[i])
1759
0
      goto error;
1760
0
  }
1761
0
1762
0
  isl_val_free(v);
1763
0
  return fold;
1764
0
error:
1765
0
  isl_val_free(v);
1766
0
  isl_qpolynomial_fold_free(fold);
1767
0
  return NULL;
1768
0
}
1769
1770
/* Divide "fold" by "v".
1771
 */
1772
__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_down_val(
1773
  __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
1774
0
{
1775
0
  if (!fold || !v)
1776
0
    goto error;
1777
0
1778
0
  if (isl_val_is_one(v)) {
1779
0
    isl_val_free(v);
1780
0
    return fold;
1781
0
  }
1782
0
  if (!isl_val_is_rat(v))
1783
0
    isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid,
1784
0
      "expecting rational factor", goto error);
1785
0
  if (isl_val_is_zero(v))
1786
0
    isl_die(isl_val_get_ctx(v), isl_error_invalid,
1787
0
      "cannot scale down by zero", goto error);
1788
0
1789
0
  return isl_qpolynomial_fold_scale_val(fold, isl_val_inv(v));
1790
0
error:
1791
0
  isl_val_free(v);
1792
0
  isl_qpolynomial_fold_free(fold);
1793
0
  return NULL;
1794
0
}