Line data Source code
1 : /*
2 : * Copyright 2011 INRIA Saclay
3 : * Copyright 2011 Sven Verdoolaege
4 : * Copyright 2012-2014 Ecole Normale Superieure
5 : * Copyright 2014 INRIA Rocquencourt
6 : *
7 : * Use of this software is governed by the MIT license
8 : *
9 : * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
10 : * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
11 : * 91893 Orsay, France
12 : * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
13 : * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
14 : * B.P. 105 - 78153 Le Chesnay, France
15 : */
16 :
17 : #include <isl_ctx_private.h>
18 : #include <isl_map_private.h>
19 : #include <isl_union_map_private.h>
20 : #include <isl_aff_private.h>
21 : #include <isl_space_private.h>
22 : #include <isl_local_space_private.h>
23 : #include <isl_vec_private.h>
24 : #include <isl_mat_private.h>
25 : #include <isl/id.h>
26 : #include <isl/constraint.h>
27 : #include <isl_seq.h>
28 : #include <isl/set.h>
29 : #include <isl_val_private.h>
30 : #include <isl_point_private.h>
31 : #include <isl_config.h>
32 :
33 : #undef BASE
34 : #define BASE aff
35 :
36 : #include <isl_list_templ.c>
37 :
38 : #undef BASE
39 : #define BASE pw_aff
40 :
41 : #include <isl_list_templ.c>
42 :
43 : #undef BASE
44 : #define BASE pw_multi_aff
45 :
46 : #include <isl_list_templ.c>
47 :
48 : #undef BASE
49 : #define BASE union_pw_aff
50 :
51 : #include <isl_list_templ.c>
52 :
53 : #undef BASE
54 : #define BASE union_pw_multi_aff
55 :
56 : #include <isl_list_templ.c>
57 :
58 0 : __isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls,
59 : __isl_take isl_vec *v)
60 : {
61 : isl_aff *aff;
62 :
63 0 : if (!ls || !v)
64 : goto error;
65 :
66 0 : aff = isl_calloc_type(v->ctx, struct isl_aff);
67 0 : if (!aff)
68 0 : goto error;
69 :
70 0 : aff->ref = 1;
71 0 : aff->ls = ls;
72 0 : aff->v = v;
73 :
74 0 : return aff;
75 : error:
76 0 : isl_local_space_free(ls);
77 0 : isl_vec_free(v);
78 0 : return NULL;
79 : }
80 :
81 0 : __isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls)
82 : {
83 : isl_ctx *ctx;
84 : isl_vec *v;
85 : unsigned total;
86 :
87 0 : if (!ls)
88 0 : return NULL;
89 :
90 0 : ctx = isl_local_space_get_ctx(ls);
91 0 : if (!isl_local_space_divs_known(ls))
92 0 : isl_die(ctx, isl_error_invalid, "local space has unknown divs",
93 : goto error);
94 0 : if (!isl_local_space_is_set(ls))
95 0 : isl_die(ctx, isl_error_invalid,
96 : "domain of affine expression should be a set",
97 : goto error);
98 :
99 0 : total = isl_local_space_dim(ls, isl_dim_all);
100 0 : v = isl_vec_alloc(ctx, 1 + 1 + total);
101 0 : return isl_aff_alloc_vec(ls, v);
102 : error:
103 0 : isl_local_space_free(ls);
104 0 : return NULL;
105 : }
106 :
107 0 : __isl_give isl_aff *isl_aff_zero_on_domain(__isl_take isl_local_space *ls)
108 : {
109 : isl_aff *aff;
110 :
111 0 : aff = isl_aff_alloc(ls);
112 0 : if (!aff)
113 0 : return NULL;
114 :
115 0 : isl_int_set_si(aff->v->el[0], 1);
116 0 : isl_seq_clr(aff->v->el + 1, aff->v->size - 1);
117 :
118 0 : return aff;
119 : }
120 :
121 : /* Return a piecewise affine expression defined on the specified domain
122 : * that is equal to zero.
123 : */
124 0 : __isl_give isl_pw_aff *isl_pw_aff_zero_on_domain(__isl_take isl_local_space *ls)
125 : {
126 0 : return isl_pw_aff_from_aff(isl_aff_zero_on_domain(ls));
127 : }
128 :
129 : /* Return an affine expression defined on the specified domain
130 : * that represents NaN.
131 : */
132 0 : __isl_give isl_aff *isl_aff_nan_on_domain(__isl_take isl_local_space *ls)
133 : {
134 : isl_aff *aff;
135 :
136 0 : aff = isl_aff_alloc(ls);
137 0 : if (!aff)
138 0 : return NULL;
139 :
140 0 : isl_seq_clr(aff->v->el, aff->v->size);
141 :
142 0 : return aff;
143 : }
144 :
145 : /* Return a piecewise affine expression defined on the specified domain
146 : * that represents NaN.
147 : */
148 0 : __isl_give isl_pw_aff *isl_pw_aff_nan_on_domain(__isl_take isl_local_space *ls)
149 : {
150 0 : return isl_pw_aff_from_aff(isl_aff_nan_on_domain(ls));
151 : }
152 :
153 : /* Return an affine expression that is equal to "val" on
154 : * domain local space "ls".
155 : */
156 0 : __isl_give isl_aff *isl_aff_val_on_domain(__isl_take isl_local_space *ls,
157 : __isl_take isl_val *val)
158 : {
159 : isl_aff *aff;
160 :
161 0 : if (!ls || !val)
162 : goto error;
163 0 : if (!isl_val_is_rat(val))
164 0 : isl_die(isl_val_get_ctx(val), isl_error_invalid,
165 : "expecting rational value", goto error);
166 :
167 0 : aff = isl_aff_alloc(isl_local_space_copy(ls));
168 0 : if (!aff)
169 0 : goto error;
170 :
171 0 : isl_seq_clr(aff->v->el + 2, aff->v->size - 2);
172 0 : isl_int_set(aff->v->el[1], val->n);
173 0 : isl_int_set(aff->v->el[0], val->d);
174 :
175 0 : isl_local_space_free(ls);
176 0 : isl_val_free(val);
177 0 : return aff;
178 : error:
179 0 : isl_local_space_free(ls);
180 0 : isl_val_free(val);
181 0 : return NULL;
182 : }
183 :
184 : /* Return an affine expression that is equal to the specified dimension
185 : * in "ls".
186 : */
187 0 : __isl_give isl_aff *isl_aff_var_on_domain(__isl_take isl_local_space *ls,
188 : enum isl_dim_type type, unsigned pos)
189 : {
190 : isl_space *space;
191 : isl_aff *aff;
192 :
193 0 : if (!ls)
194 0 : return NULL;
195 :
196 0 : space = isl_local_space_get_space(ls);
197 0 : if (!space)
198 0 : goto error;
199 0 : if (isl_space_is_map(space))
200 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
201 : "expecting (parameter) set space", goto error);
202 0 : if (pos >= isl_local_space_dim(ls, type))
203 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
204 : "position out of bounds", goto error);
205 :
206 0 : isl_space_free(space);
207 0 : aff = isl_aff_alloc(ls);
208 0 : if (!aff)
209 0 : return NULL;
210 :
211 0 : pos += isl_local_space_offset(aff->ls, type);
212 :
213 0 : isl_int_set_si(aff->v->el[0], 1);
214 0 : isl_seq_clr(aff->v->el + 1, aff->v->size - 1);
215 0 : isl_int_set_si(aff->v->el[1 + pos], 1);
216 :
217 0 : return aff;
218 : error:
219 0 : isl_local_space_free(ls);
220 0 : isl_space_free(space);
221 0 : return NULL;
222 : }
223 :
224 : /* Return a piecewise affine expression that is equal to
225 : * the specified dimension in "ls".
226 : */
227 0 : __isl_give isl_pw_aff *isl_pw_aff_var_on_domain(__isl_take isl_local_space *ls,
228 : enum isl_dim_type type, unsigned pos)
229 : {
230 0 : return isl_pw_aff_from_aff(isl_aff_var_on_domain(ls, type, pos));
231 : }
232 :
233 : /* Return an affine expression that is equal to the parameter
234 : * in the domain space "space" with identifier "id".
235 : */
236 0 : __isl_give isl_aff *isl_aff_param_on_domain_space_id(
237 : __isl_take isl_space *space, __isl_take isl_id *id)
238 : {
239 : int pos;
240 : isl_local_space *ls;
241 :
242 0 : if (!space || !id)
243 : goto error;
244 0 : pos = isl_space_find_dim_by_id(space, isl_dim_param, id);
245 0 : if (pos < 0)
246 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
247 : "parameter not found in space", goto error);
248 0 : isl_id_free(id);
249 0 : ls = isl_local_space_from_space(space);
250 0 : return isl_aff_var_on_domain(ls, isl_dim_param, pos);
251 : error:
252 0 : isl_space_free(space);
253 0 : isl_id_free(id);
254 0 : return NULL;
255 : }
256 :
257 0 : __isl_give isl_aff *isl_aff_copy(__isl_keep isl_aff *aff)
258 : {
259 0 : if (!aff)
260 0 : return NULL;
261 :
262 0 : aff->ref++;
263 0 : return aff;
264 : }
265 :
266 0 : __isl_give isl_aff *isl_aff_dup(__isl_keep isl_aff *aff)
267 : {
268 0 : if (!aff)
269 0 : return NULL;
270 :
271 0 : return isl_aff_alloc_vec(isl_local_space_copy(aff->ls),
272 : isl_vec_copy(aff->v));
273 : }
274 :
275 0 : __isl_give isl_aff *isl_aff_cow(__isl_take isl_aff *aff)
276 : {
277 0 : if (!aff)
278 0 : return NULL;
279 :
280 0 : if (aff->ref == 1)
281 0 : return aff;
282 0 : aff->ref--;
283 0 : return isl_aff_dup(aff);
284 : }
285 :
286 0 : __isl_null isl_aff *isl_aff_free(__isl_take isl_aff *aff)
287 : {
288 0 : if (!aff)
289 0 : return NULL;
290 :
291 0 : if (--aff->ref > 0)
292 0 : return NULL;
293 :
294 0 : isl_local_space_free(aff->ls);
295 0 : isl_vec_free(aff->v);
296 :
297 0 : free(aff);
298 :
299 0 : return NULL;
300 : }
301 :
302 0 : isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff)
303 : {
304 0 : return aff ? isl_local_space_get_ctx(aff->ls) : NULL;
305 : }
306 :
307 : /* Return a hash value that digests "aff".
308 : */
309 0 : uint32_t isl_aff_get_hash(__isl_keep isl_aff *aff)
310 : {
311 : uint32_t hash, ls_hash, v_hash;
312 :
313 0 : if (!aff)
314 0 : return 0;
315 :
316 0 : hash = isl_hash_init();
317 0 : ls_hash = isl_local_space_get_hash(aff->ls);
318 0 : isl_hash_hash(hash, ls_hash);
319 0 : v_hash = isl_vec_get_hash(aff->v);
320 0 : isl_hash_hash(hash, v_hash);
321 :
322 0 : return hash;
323 : }
324 :
325 : /* Externally, an isl_aff has a map space, but internally, the
326 : * ls field corresponds to the domain of that space.
327 : */
328 0 : int isl_aff_dim(__isl_keep isl_aff *aff, enum isl_dim_type type)
329 : {
330 0 : if (!aff)
331 0 : return 0;
332 0 : if (type == isl_dim_out)
333 0 : return 1;
334 0 : if (type == isl_dim_in)
335 0 : type = isl_dim_set;
336 0 : return isl_local_space_dim(aff->ls, type);
337 : }
338 :
339 : /* Return the position of the dimension of the given type and name
340 : * in "aff".
341 : * Return -1 if no such dimension can be found.
342 : */
343 0 : int isl_aff_find_dim_by_name(__isl_keep isl_aff *aff, enum isl_dim_type type,
344 : const char *name)
345 : {
346 0 : if (!aff)
347 0 : return -1;
348 0 : if (type == isl_dim_out)
349 0 : return -1;
350 0 : if (type == isl_dim_in)
351 0 : type = isl_dim_set;
352 0 : return isl_local_space_find_dim_by_name(aff->ls, type, name);
353 : }
354 :
355 : /* Return the domain space of "aff".
356 : */
357 0 : static __isl_keep isl_space *isl_aff_peek_domain_space(__isl_keep isl_aff *aff)
358 : {
359 0 : return aff ? isl_local_space_peek_space(aff->ls) : NULL;
360 : }
361 :
362 0 : __isl_give isl_space *isl_aff_get_domain_space(__isl_keep isl_aff *aff)
363 : {
364 0 : return isl_space_copy(isl_aff_peek_domain_space(aff));
365 : }
366 :
367 0 : __isl_give isl_space *isl_aff_get_space(__isl_keep isl_aff *aff)
368 : {
369 : isl_space *space;
370 0 : if (!aff)
371 0 : return NULL;
372 0 : space = isl_local_space_get_space(aff->ls);
373 0 : space = isl_space_from_domain(space);
374 0 : space = isl_space_add_dims(space, isl_dim_out, 1);
375 0 : return space;
376 : }
377 :
378 0 : __isl_give isl_local_space *isl_aff_get_domain_local_space(
379 : __isl_keep isl_aff *aff)
380 : {
381 0 : return aff ? isl_local_space_copy(aff->ls) : NULL;
382 : }
383 :
384 0 : __isl_give isl_local_space *isl_aff_get_local_space(__isl_keep isl_aff *aff)
385 : {
386 : isl_local_space *ls;
387 0 : if (!aff)
388 0 : return NULL;
389 0 : ls = isl_local_space_copy(aff->ls);
390 0 : ls = isl_local_space_from_domain(ls);
391 0 : ls = isl_local_space_add_dims(ls, isl_dim_out, 1);
392 0 : return ls;
393 : }
394 :
395 : /* Return the local space of the domain of "aff".
396 : * This may be either a copy or the local space itself
397 : * if there is only one reference to "aff".
398 : * This allows the local space to be modified inplace
399 : * if both the expression and its local space have only a single reference.
400 : * The caller is not allowed to modify "aff" between this call and
401 : * a subsequent call to isl_aff_restore_domain_local_space.
402 : * The only exception is that isl_aff_free can be called instead.
403 : */
404 0 : __isl_give isl_local_space *isl_aff_take_domain_local_space(
405 : __isl_keep isl_aff *aff)
406 : {
407 : isl_local_space *ls;
408 :
409 0 : if (!aff)
410 0 : return NULL;
411 0 : if (aff->ref != 1)
412 0 : return isl_aff_get_domain_local_space(aff);
413 0 : ls = aff->ls;
414 0 : aff->ls = NULL;
415 0 : return ls;
416 : }
417 :
418 : /* Set the local space of the domain of "aff" to "ls",
419 : * where the local space of "aff" may be missing
420 : * due to a preceding call to isl_aff_take_domain_local_space.
421 : * However, in this case, "aff" only has a single reference and
422 : * then the call to isl_aff_cow has no effect.
423 : */
424 0 : __isl_give isl_aff *isl_aff_restore_domain_local_space(
425 : __isl_keep isl_aff *aff, __isl_take isl_local_space *ls)
426 : {
427 0 : if (!aff || !ls)
428 : goto error;
429 :
430 0 : if (aff->ls == ls) {
431 0 : isl_local_space_free(ls);
432 0 : return aff;
433 : }
434 :
435 0 : aff = isl_aff_cow(aff);
436 0 : if (!aff)
437 0 : goto error;
438 0 : isl_local_space_free(aff->ls);
439 0 : aff->ls = ls;
440 :
441 0 : return aff;
442 : error:
443 0 : isl_aff_free(aff);
444 0 : isl_local_space_free(ls);
445 0 : return NULL;
446 : }
447 :
448 : /* Externally, an isl_aff has a map space, but internally, the
449 : * ls field corresponds to the domain of that space.
450 : */
451 0 : const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff,
452 : enum isl_dim_type type, unsigned pos)
453 : {
454 0 : if (!aff)
455 0 : return NULL;
456 0 : if (type == isl_dim_out)
457 0 : return NULL;
458 0 : if (type == isl_dim_in)
459 0 : type = isl_dim_set;
460 0 : return isl_local_space_get_dim_name(aff->ls, type, pos);
461 : }
462 :
463 0 : __isl_give isl_aff *isl_aff_reset_domain_space(__isl_take isl_aff *aff,
464 : __isl_take isl_space *dim)
465 : {
466 0 : aff = isl_aff_cow(aff);
467 0 : if (!aff || !dim)
468 : goto error;
469 :
470 0 : aff->ls = isl_local_space_reset_space(aff->ls, dim);
471 0 : if (!aff->ls)
472 0 : return isl_aff_free(aff);
473 :
474 0 : return aff;
475 : error:
476 0 : isl_aff_free(aff);
477 0 : isl_space_free(dim);
478 0 : return NULL;
479 : }
480 :
481 : /* Reset the space of "aff". This function is called from isl_pw_templ.c
482 : * and doesn't know if the space of an element object is represented
483 : * directly or through its domain. It therefore passes along both.
484 : */
485 0 : __isl_give isl_aff *isl_aff_reset_space_and_domain(__isl_take isl_aff *aff,
486 : __isl_take isl_space *space, __isl_take isl_space *domain)
487 : {
488 0 : isl_space_free(space);
489 0 : return isl_aff_reset_domain_space(aff, domain);
490 : }
491 :
492 : /* Reorder the coefficients of the affine expression based
493 : * on the given reordering.
494 : * The reordering r is assumed to have been extended with the local
495 : * variables.
496 : */
497 0 : static __isl_give isl_vec *vec_reorder(__isl_take isl_vec *vec,
498 : __isl_take isl_reordering *r, int n_div)
499 : {
500 : isl_space *space;
501 : isl_vec *res;
502 : int i;
503 :
504 0 : if (!vec || !r)
505 : goto error;
506 :
507 0 : space = isl_reordering_peek_space(r);
508 0 : res = isl_vec_alloc(vec->ctx,
509 0 : 2 + isl_space_dim(space, isl_dim_all) + n_div);
510 0 : if (!res)
511 0 : goto error;
512 0 : isl_seq_cpy(res->el, vec->el, 2);
513 0 : isl_seq_clr(res->el + 2, res->size - 2);
514 0 : for (i = 0; i < r->len; ++i)
515 0 : isl_int_set(res->el[2 + r->pos[i]], vec->el[2 + i]);
516 :
517 0 : isl_reordering_free(r);
518 0 : isl_vec_free(vec);
519 0 : return res;
520 : error:
521 0 : isl_vec_free(vec);
522 0 : isl_reordering_free(r);
523 0 : return NULL;
524 : }
525 :
526 : /* Reorder the dimensions of the domain of "aff" according
527 : * to the given reordering.
528 : */
529 0 : __isl_give isl_aff *isl_aff_realign_domain(__isl_take isl_aff *aff,
530 : __isl_take isl_reordering *r)
531 : {
532 0 : aff = isl_aff_cow(aff);
533 0 : if (!aff)
534 0 : goto error;
535 :
536 0 : r = isl_reordering_extend(r, aff->ls->div->n_row);
537 0 : aff->v = vec_reorder(aff->v, isl_reordering_copy(r),
538 0 : aff->ls->div->n_row);
539 0 : aff->ls = isl_local_space_realign(aff->ls, r);
540 :
541 0 : if (!aff->v || !aff->ls)
542 0 : return isl_aff_free(aff);
543 :
544 0 : return aff;
545 : error:
546 0 : isl_aff_free(aff);
547 0 : isl_reordering_free(r);
548 0 : return NULL;
549 : }
550 :
551 0 : __isl_give isl_aff *isl_aff_align_params(__isl_take isl_aff *aff,
552 : __isl_take isl_space *model)
553 : {
554 : isl_bool equal_params;
555 :
556 0 : if (!aff || !model)
557 : goto error;
558 :
559 0 : equal_params = isl_space_has_equal_params(aff->ls->dim, model);
560 0 : if (equal_params < 0)
561 0 : goto error;
562 0 : if (!equal_params) {
563 : isl_reordering *exp;
564 :
565 0 : exp = isl_parameter_alignment_reordering(aff->ls->dim, model);
566 0 : exp = isl_reordering_extend_space(exp,
567 : isl_aff_get_domain_space(aff));
568 0 : aff = isl_aff_realign_domain(aff, exp);
569 : }
570 :
571 0 : isl_space_free(model);
572 0 : return aff;
573 : error:
574 0 : isl_space_free(model);
575 0 : isl_aff_free(aff);
576 0 : return NULL;
577 : }
578 :
579 : /* Is "aff" obviously equal to zero?
580 : *
581 : * If the denominator is zero, then "aff" is not equal to zero.
582 : */
583 0 : isl_bool isl_aff_plain_is_zero(__isl_keep isl_aff *aff)
584 : {
585 0 : if (!aff)
586 0 : return isl_bool_error;
587 :
588 0 : if (isl_int_is_zero(aff->v->el[0]))
589 0 : return isl_bool_false;
590 0 : return isl_seq_first_non_zero(aff->v->el + 1, aff->v->size - 1) < 0;
591 : }
592 :
593 : /* Does "aff" represent NaN?
594 : */
595 0 : isl_bool isl_aff_is_nan(__isl_keep isl_aff *aff)
596 : {
597 0 : if (!aff)
598 0 : return isl_bool_error;
599 :
600 0 : return isl_seq_first_non_zero(aff->v->el, 2) < 0;
601 : }
602 :
603 : /* Are "aff1" and "aff2" obviously equal?
604 : *
605 : * NaN is not equal to anything, not even to another NaN.
606 : */
607 0 : isl_bool isl_aff_plain_is_equal(__isl_keep isl_aff *aff1,
608 : __isl_keep isl_aff *aff2)
609 : {
610 : isl_bool equal;
611 :
612 0 : if (!aff1 || !aff2)
613 0 : return isl_bool_error;
614 :
615 0 : if (isl_aff_is_nan(aff1) || isl_aff_is_nan(aff2))
616 0 : return isl_bool_false;
617 :
618 0 : equal = isl_local_space_is_equal(aff1->ls, aff2->ls);
619 0 : if (equal < 0 || !equal)
620 0 : return equal;
621 :
622 0 : return isl_vec_is_equal(aff1->v, aff2->v);
623 : }
624 :
625 : /* Return the common denominator of "aff" in "v".
626 : *
627 : * We cannot return anything meaningful in case of a NaN.
628 : */
629 0 : isl_stat isl_aff_get_denominator(__isl_keep isl_aff *aff, isl_int *v)
630 : {
631 0 : if (!aff)
632 0 : return isl_stat_error;
633 0 : if (isl_aff_is_nan(aff))
634 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
635 : "cannot get denominator of NaN", return isl_stat_error);
636 0 : isl_int_set(*v, aff->v->el[0]);
637 0 : return isl_stat_ok;
638 : }
639 :
640 : /* Return the common denominator of "aff".
641 : */
642 0 : __isl_give isl_val *isl_aff_get_denominator_val(__isl_keep isl_aff *aff)
643 : {
644 : isl_ctx *ctx;
645 :
646 0 : if (!aff)
647 0 : return NULL;
648 :
649 0 : ctx = isl_aff_get_ctx(aff);
650 0 : if (isl_aff_is_nan(aff))
651 0 : return isl_val_nan(ctx);
652 0 : return isl_val_int_from_isl_int(ctx, aff->v->el[0]);
653 : }
654 :
655 : /* Return the constant term of "aff".
656 : */
657 0 : __isl_give isl_val *isl_aff_get_constant_val(__isl_keep isl_aff *aff)
658 : {
659 : isl_ctx *ctx;
660 : isl_val *v;
661 :
662 0 : if (!aff)
663 0 : return NULL;
664 :
665 0 : ctx = isl_aff_get_ctx(aff);
666 0 : if (isl_aff_is_nan(aff))
667 0 : return isl_val_nan(ctx);
668 0 : v = isl_val_rat_from_isl_int(ctx, aff->v->el[1], aff->v->el[0]);
669 0 : return isl_val_normalize(v);
670 : }
671 :
672 : /* Return the coefficient of the variable of type "type" at position "pos"
673 : * of "aff".
674 : */
675 0 : __isl_give isl_val *isl_aff_get_coefficient_val(__isl_keep isl_aff *aff,
676 : enum isl_dim_type type, int pos)
677 : {
678 : isl_ctx *ctx;
679 : isl_val *v;
680 :
681 0 : if (!aff)
682 0 : return NULL;
683 :
684 0 : ctx = isl_aff_get_ctx(aff);
685 0 : if (type == isl_dim_out)
686 0 : isl_die(ctx, isl_error_invalid,
687 : "output/set dimension does not have a coefficient",
688 : return NULL);
689 0 : if (type == isl_dim_in)
690 0 : type = isl_dim_set;
691 :
692 0 : if (pos >= isl_local_space_dim(aff->ls, type))
693 0 : isl_die(ctx, isl_error_invalid,
694 : "position out of bounds", return NULL);
695 :
696 0 : if (isl_aff_is_nan(aff))
697 0 : return isl_val_nan(ctx);
698 0 : pos += isl_local_space_offset(aff->ls, type);
699 0 : v = isl_val_rat_from_isl_int(ctx, aff->v->el[1 + pos], aff->v->el[0]);
700 0 : return isl_val_normalize(v);
701 : }
702 :
703 : /* Return the sign of the coefficient of the variable of type "type"
704 : * at position "pos" of "aff".
705 : */
706 0 : int isl_aff_coefficient_sgn(__isl_keep isl_aff *aff, enum isl_dim_type type,
707 : int pos)
708 : {
709 : isl_ctx *ctx;
710 :
711 0 : if (!aff)
712 0 : return 0;
713 :
714 0 : ctx = isl_aff_get_ctx(aff);
715 0 : if (type == isl_dim_out)
716 0 : isl_die(ctx, isl_error_invalid,
717 : "output/set dimension does not have a coefficient",
718 : return 0);
719 0 : if (type == isl_dim_in)
720 0 : type = isl_dim_set;
721 :
722 0 : if (pos >= isl_local_space_dim(aff->ls, type))
723 0 : isl_die(ctx, isl_error_invalid,
724 : "position out of bounds", return 0);
725 :
726 0 : pos += isl_local_space_offset(aff->ls, type);
727 0 : return isl_int_sgn(aff->v->el[1 + pos]);
728 : }
729 :
730 : /* Replace the numerator of the constant term of "aff" by "v".
731 : *
732 : * A NaN is unaffected by this operation.
733 : */
734 0 : __isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_int v)
735 : {
736 0 : if (!aff)
737 0 : return NULL;
738 0 : if (isl_aff_is_nan(aff))
739 0 : return aff;
740 0 : aff = isl_aff_cow(aff);
741 0 : if (!aff)
742 0 : return NULL;
743 :
744 0 : aff->v = isl_vec_cow(aff->v);
745 0 : if (!aff->v)
746 0 : return isl_aff_free(aff);
747 :
748 0 : isl_int_set(aff->v->el[1], v);
749 :
750 0 : return aff;
751 : }
752 :
753 : /* Replace the constant term of "aff" by "v".
754 : *
755 : * A NaN is unaffected by this operation.
756 : */
757 0 : __isl_give isl_aff *isl_aff_set_constant_val(__isl_take isl_aff *aff,
758 : __isl_take isl_val *v)
759 : {
760 0 : if (!aff || !v)
761 : goto error;
762 :
763 0 : if (isl_aff_is_nan(aff)) {
764 0 : isl_val_free(v);
765 0 : return aff;
766 : }
767 :
768 0 : if (!isl_val_is_rat(v))
769 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
770 : "expecting rational value", goto error);
771 :
772 0 : if (isl_int_eq(aff->v->el[1], v->n) &&
773 0 : isl_int_eq(aff->v->el[0], v->d)) {
774 0 : isl_val_free(v);
775 0 : return aff;
776 : }
777 :
778 0 : aff = isl_aff_cow(aff);
779 0 : if (!aff)
780 0 : goto error;
781 0 : aff->v = isl_vec_cow(aff->v);
782 0 : if (!aff->v)
783 0 : goto error;
784 :
785 0 : if (isl_int_eq(aff->v->el[0], v->d)) {
786 0 : isl_int_set(aff->v->el[1], v->n);
787 0 : } else if (isl_int_is_one(v->d)) {
788 0 : isl_int_mul(aff->v->el[1], aff->v->el[0], v->n);
789 : } else {
790 0 : isl_seq_scale(aff->v->el + 1,
791 0 : aff->v->el + 1, v->d, aff->v->size - 1);
792 0 : isl_int_mul(aff->v->el[1], aff->v->el[0], v->n);
793 0 : isl_int_mul(aff->v->el[0], aff->v->el[0], v->d);
794 0 : aff->v = isl_vec_normalize(aff->v);
795 0 : if (!aff->v)
796 0 : goto error;
797 : }
798 :
799 0 : isl_val_free(v);
800 0 : return aff;
801 : error:
802 0 : isl_aff_free(aff);
803 0 : isl_val_free(v);
804 0 : return NULL;
805 : }
806 :
807 : /* Add "v" to the constant term of "aff".
808 : *
809 : * A NaN is unaffected by this operation.
810 : */
811 0 : __isl_give isl_aff *isl_aff_add_constant(__isl_take isl_aff *aff, isl_int v)
812 : {
813 0 : if (isl_int_is_zero(v))
814 0 : return aff;
815 :
816 0 : if (!aff)
817 0 : return NULL;
818 0 : if (isl_aff_is_nan(aff))
819 0 : return aff;
820 0 : aff = isl_aff_cow(aff);
821 0 : if (!aff)
822 0 : return NULL;
823 :
824 0 : aff->v = isl_vec_cow(aff->v);
825 0 : if (!aff->v)
826 0 : return isl_aff_free(aff);
827 :
828 0 : isl_int_addmul(aff->v->el[1], aff->v->el[0], v);
829 :
830 0 : return aff;
831 : }
832 :
833 : /* Add "v" to the constant term of "aff".
834 : *
835 : * A NaN is unaffected by this operation.
836 : */
837 0 : __isl_give isl_aff *isl_aff_add_constant_val(__isl_take isl_aff *aff,
838 : __isl_take isl_val *v)
839 : {
840 0 : if (!aff || !v)
841 : goto error;
842 :
843 0 : if (isl_aff_is_nan(aff) || isl_val_is_zero(v)) {
844 0 : isl_val_free(v);
845 0 : return aff;
846 : }
847 :
848 0 : if (!isl_val_is_rat(v))
849 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
850 : "expecting rational value", goto error);
851 :
852 0 : aff = isl_aff_cow(aff);
853 0 : if (!aff)
854 0 : goto error;
855 :
856 0 : aff->v = isl_vec_cow(aff->v);
857 0 : if (!aff->v)
858 0 : goto error;
859 :
860 0 : if (isl_int_is_one(v->d)) {
861 0 : isl_int_addmul(aff->v->el[1], aff->v->el[0], v->n);
862 0 : } else if (isl_int_eq(aff->v->el[0], v->d)) {
863 0 : isl_int_add(aff->v->el[1], aff->v->el[1], v->n);
864 0 : aff->v = isl_vec_normalize(aff->v);
865 0 : if (!aff->v)
866 0 : goto error;
867 : } else {
868 0 : isl_seq_scale(aff->v->el + 1,
869 0 : aff->v->el + 1, v->d, aff->v->size - 1);
870 0 : isl_int_addmul(aff->v->el[1], aff->v->el[0], v->n);
871 0 : isl_int_mul(aff->v->el[0], aff->v->el[0], v->d);
872 0 : aff->v = isl_vec_normalize(aff->v);
873 0 : if (!aff->v)
874 0 : goto error;
875 : }
876 :
877 0 : isl_val_free(v);
878 0 : return aff;
879 : error:
880 0 : isl_aff_free(aff);
881 0 : isl_val_free(v);
882 0 : return NULL;
883 : }
884 :
885 0 : __isl_give isl_aff *isl_aff_add_constant_si(__isl_take isl_aff *aff, int v)
886 : {
887 : isl_int t;
888 :
889 0 : isl_int_init(t);
890 0 : isl_int_set_si(t, v);
891 0 : aff = isl_aff_add_constant(aff, t);
892 0 : isl_int_clear(t);
893 :
894 0 : return aff;
895 : }
896 :
897 : /* Add "v" to the numerator of the constant term of "aff".
898 : *
899 : * A NaN is unaffected by this operation.
900 : */
901 0 : __isl_give isl_aff *isl_aff_add_constant_num(__isl_take isl_aff *aff, isl_int v)
902 : {
903 0 : if (isl_int_is_zero(v))
904 0 : return aff;
905 :
906 0 : if (!aff)
907 0 : return NULL;
908 0 : if (isl_aff_is_nan(aff))
909 0 : return aff;
910 0 : aff = isl_aff_cow(aff);
911 0 : if (!aff)
912 0 : return NULL;
913 :
914 0 : aff->v = isl_vec_cow(aff->v);
915 0 : if (!aff->v)
916 0 : return isl_aff_free(aff);
917 :
918 0 : isl_int_add(aff->v->el[1], aff->v->el[1], v);
919 :
920 0 : return aff;
921 : }
922 :
923 : /* Add "v" to the numerator of the constant term of "aff".
924 : *
925 : * A NaN is unaffected by this operation.
926 : */
927 0 : __isl_give isl_aff *isl_aff_add_constant_num_si(__isl_take isl_aff *aff, int v)
928 : {
929 : isl_int t;
930 :
931 0 : if (v == 0)
932 0 : return aff;
933 :
934 0 : isl_int_init(t);
935 0 : isl_int_set_si(t, v);
936 0 : aff = isl_aff_add_constant_num(aff, t);
937 0 : isl_int_clear(t);
938 :
939 0 : return aff;
940 : }
941 :
942 : /* Replace the numerator of the constant term of "aff" by "v".
943 : *
944 : * A NaN is unaffected by this operation.
945 : */
946 0 : __isl_give isl_aff *isl_aff_set_constant_si(__isl_take isl_aff *aff, int v)
947 : {
948 0 : if (!aff)
949 0 : return NULL;
950 0 : if (isl_aff_is_nan(aff))
951 0 : return aff;
952 0 : aff = isl_aff_cow(aff);
953 0 : if (!aff)
954 0 : return NULL;
955 :
956 0 : aff->v = isl_vec_cow(aff->v);
957 0 : if (!aff->v)
958 0 : return isl_aff_free(aff);
959 :
960 0 : isl_int_set_si(aff->v->el[1], v);
961 :
962 0 : return aff;
963 : }
964 :
965 : /* Replace the numerator of the coefficient of the variable of type "type"
966 : * at position "pos" of "aff" by "v".
967 : *
968 : * A NaN is unaffected by this operation.
969 : */
970 0 : __isl_give isl_aff *isl_aff_set_coefficient(__isl_take isl_aff *aff,
971 : enum isl_dim_type type, int pos, isl_int v)
972 : {
973 0 : if (!aff)
974 0 : return NULL;
975 :
976 0 : if (type == isl_dim_out)
977 0 : isl_die(aff->v->ctx, isl_error_invalid,
978 : "output/set dimension does not have a coefficient",
979 : return isl_aff_free(aff));
980 0 : if (type == isl_dim_in)
981 0 : type = isl_dim_set;
982 :
983 0 : if (pos >= isl_local_space_dim(aff->ls, type))
984 0 : isl_die(aff->v->ctx, isl_error_invalid,
985 : "position out of bounds", return isl_aff_free(aff));
986 :
987 0 : if (isl_aff_is_nan(aff))
988 0 : return aff;
989 0 : aff = isl_aff_cow(aff);
990 0 : if (!aff)
991 0 : return NULL;
992 :
993 0 : aff->v = isl_vec_cow(aff->v);
994 0 : if (!aff->v)
995 0 : return isl_aff_free(aff);
996 :
997 0 : pos += isl_local_space_offset(aff->ls, type);
998 0 : isl_int_set(aff->v->el[1 + pos], v);
999 :
1000 0 : return aff;
1001 : }
1002 :
1003 : /* Replace the numerator of the coefficient of the variable of type "type"
1004 : * at position "pos" of "aff" by "v".
1005 : *
1006 : * A NaN is unaffected by this operation.
1007 : */
1008 0 : __isl_give isl_aff *isl_aff_set_coefficient_si(__isl_take isl_aff *aff,
1009 : enum isl_dim_type type, int pos, int v)
1010 : {
1011 0 : if (!aff)
1012 0 : return NULL;
1013 :
1014 0 : if (type == isl_dim_out)
1015 0 : isl_die(aff->v->ctx, isl_error_invalid,
1016 : "output/set dimension does not have a coefficient",
1017 : return isl_aff_free(aff));
1018 0 : if (type == isl_dim_in)
1019 0 : type = isl_dim_set;
1020 :
1021 0 : if (pos < 0 || pos >= isl_local_space_dim(aff->ls, type))
1022 0 : isl_die(aff->v->ctx, isl_error_invalid,
1023 : "position out of bounds", return isl_aff_free(aff));
1024 :
1025 0 : if (isl_aff_is_nan(aff))
1026 0 : return aff;
1027 0 : pos += isl_local_space_offset(aff->ls, type);
1028 0 : if (isl_int_cmp_si(aff->v->el[1 + pos], v) == 0)
1029 0 : return aff;
1030 :
1031 0 : aff = isl_aff_cow(aff);
1032 0 : if (!aff)
1033 0 : return NULL;
1034 :
1035 0 : aff->v = isl_vec_cow(aff->v);
1036 0 : if (!aff->v)
1037 0 : return isl_aff_free(aff);
1038 :
1039 0 : isl_int_set_si(aff->v->el[1 + pos], v);
1040 :
1041 0 : return aff;
1042 : }
1043 :
1044 : /* Replace the coefficient of the variable of type "type" at position "pos"
1045 : * of "aff" by "v".
1046 : *
1047 : * A NaN is unaffected by this operation.
1048 : */
1049 0 : __isl_give isl_aff *isl_aff_set_coefficient_val(__isl_take isl_aff *aff,
1050 : enum isl_dim_type type, int pos, __isl_take isl_val *v)
1051 : {
1052 0 : if (!aff || !v)
1053 : goto error;
1054 :
1055 0 : if (type == isl_dim_out)
1056 0 : isl_die(aff->v->ctx, isl_error_invalid,
1057 : "output/set dimension does not have a coefficient",
1058 : goto error);
1059 0 : if (type == isl_dim_in)
1060 0 : type = isl_dim_set;
1061 :
1062 0 : if (pos >= isl_local_space_dim(aff->ls, type))
1063 0 : isl_die(aff->v->ctx, isl_error_invalid,
1064 : "position out of bounds", goto error);
1065 :
1066 0 : if (isl_aff_is_nan(aff)) {
1067 0 : isl_val_free(v);
1068 0 : return aff;
1069 : }
1070 0 : if (!isl_val_is_rat(v))
1071 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
1072 : "expecting rational value", goto error);
1073 :
1074 0 : pos += isl_local_space_offset(aff->ls, type);
1075 0 : if (isl_int_eq(aff->v->el[1 + pos], v->n) &&
1076 0 : isl_int_eq(aff->v->el[0], v->d)) {
1077 0 : isl_val_free(v);
1078 0 : return aff;
1079 : }
1080 :
1081 0 : aff = isl_aff_cow(aff);
1082 0 : if (!aff)
1083 0 : goto error;
1084 0 : aff->v = isl_vec_cow(aff->v);
1085 0 : if (!aff->v)
1086 0 : goto error;
1087 :
1088 0 : if (isl_int_eq(aff->v->el[0], v->d)) {
1089 0 : isl_int_set(aff->v->el[1 + pos], v->n);
1090 0 : } else if (isl_int_is_one(v->d)) {
1091 0 : isl_int_mul(aff->v->el[1 + pos], aff->v->el[0], v->n);
1092 : } else {
1093 0 : isl_seq_scale(aff->v->el + 1,
1094 0 : aff->v->el + 1, v->d, aff->v->size - 1);
1095 0 : isl_int_mul(aff->v->el[1 + pos], aff->v->el[0], v->n);
1096 0 : isl_int_mul(aff->v->el[0], aff->v->el[0], v->d);
1097 0 : aff->v = isl_vec_normalize(aff->v);
1098 0 : if (!aff->v)
1099 0 : goto error;
1100 : }
1101 :
1102 0 : isl_val_free(v);
1103 0 : return aff;
1104 : error:
1105 0 : isl_aff_free(aff);
1106 0 : isl_val_free(v);
1107 0 : return NULL;
1108 : }
1109 :
1110 : /* Add "v" to the coefficient of the variable of type "type"
1111 : * at position "pos" of "aff".
1112 : *
1113 : * A NaN is unaffected by this operation.
1114 : */
1115 0 : __isl_give isl_aff *isl_aff_add_coefficient(__isl_take isl_aff *aff,
1116 : enum isl_dim_type type, int pos, isl_int v)
1117 : {
1118 0 : if (!aff)
1119 0 : return NULL;
1120 :
1121 0 : if (type == isl_dim_out)
1122 0 : isl_die(aff->v->ctx, isl_error_invalid,
1123 : "output/set dimension does not have a coefficient",
1124 : return isl_aff_free(aff));
1125 0 : if (type == isl_dim_in)
1126 0 : type = isl_dim_set;
1127 :
1128 0 : if (pos >= isl_local_space_dim(aff->ls, type))
1129 0 : isl_die(aff->v->ctx, isl_error_invalid,
1130 : "position out of bounds", return isl_aff_free(aff));
1131 :
1132 0 : if (isl_aff_is_nan(aff))
1133 0 : return aff;
1134 0 : aff = isl_aff_cow(aff);
1135 0 : if (!aff)
1136 0 : return NULL;
1137 :
1138 0 : aff->v = isl_vec_cow(aff->v);
1139 0 : if (!aff->v)
1140 0 : return isl_aff_free(aff);
1141 :
1142 0 : pos += isl_local_space_offset(aff->ls, type);
1143 0 : isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v);
1144 :
1145 0 : return aff;
1146 : }
1147 :
1148 : /* Add "v" to the coefficient of the variable of type "type"
1149 : * at position "pos" of "aff".
1150 : *
1151 : * A NaN is unaffected by this operation.
1152 : */
1153 0 : __isl_give isl_aff *isl_aff_add_coefficient_val(__isl_take isl_aff *aff,
1154 : enum isl_dim_type type, int pos, __isl_take isl_val *v)
1155 : {
1156 0 : if (!aff || !v)
1157 : goto error;
1158 :
1159 0 : if (isl_val_is_zero(v)) {
1160 0 : isl_val_free(v);
1161 0 : return aff;
1162 : }
1163 :
1164 0 : if (type == isl_dim_out)
1165 0 : isl_die(aff->v->ctx, isl_error_invalid,
1166 : "output/set dimension does not have a coefficient",
1167 : goto error);
1168 0 : if (type == isl_dim_in)
1169 0 : type = isl_dim_set;
1170 :
1171 0 : if (pos >= isl_local_space_dim(aff->ls, type))
1172 0 : isl_die(aff->v->ctx, isl_error_invalid,
1173 : "position out of bounds", goto error);
1174 :
1175 0 : if (isl_aff_is_nan(aff)) {
1176 0 : isl_val_free(v);
1177 0 : return aff;
1178 : }
1179 0 : if (!isl_val_is_rat(v))
1180 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
1181 : "expecting rational value", goto error);
1182 :
1183 0 : aff = isl_aff_cow(aff);
1184 0 : if (!aff)
1185 0 : goto error;
1186 :
1187 0 : aff->v = isl_vec_cow(aff->v);
1188 0 : if (!aff->v)
1189 0 : goto error;
1190 :
1191 0 : pos += isl_local_space_offset(aff->ls, type);
1192 0 : if (isl_int_is_one(v->d)) {
1193 0 : isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v->n);
1194 0 : } else if (isl_int_eq(aff->v->el[0], v->d)) {
1195 0 : isl_int_add(aff->v->el[1 + pos], aff->v->el[1 + pos], v->n);
1196 0 : aff->v = isl_vec_normalize(aff->v);
1197 0 : if (!aff->v)
1198 0 : goto error;
1199 : } else {
1200 0 : isl_seq_scale(aff->v->el + 1,
1201 0 : aff->v->el + 1, v->d, aff->v->size - 1);
1202 0 : isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v->n);
1203 0 : isl_int_mul(aff->v->el[0], aff->v->el[0], v->d);
1204 0 : aff->v = isl_vec_normalize(aff->v);
1205 0 : if (!aff->v)
1206 0 : goto error;
1207 : }
1208 :
1209 0 : isl_val_free(v);
1210 0 : return aff;
1211 : error:
1212 0 : isl_aff_free(aff);
1213 0 : isl_val_free(v);
1214 0 : return NULL;
1215 : }
1216 :
1217 0 : __isl_give isl_aff *isl_aff_add_coefficient_si(__isl_take isl_aff *aff,
1218 : enum isl_dim_type type, int pos, int v)
1219 : {
1220 : isl_int t;
1221 :
1222 0 : isl_int_init(t);
1223 0 : isl_int_set_si(t, v);
1224 0 : aff = isl_aff_add_coefficient(aff, type, pos, t);
1225 0 : isl_int_clear(t);
1226 :
1227 0 : return aff;
1228 : }
1229 :
1230 0 : __isl_give isl_aff *isl_aff_get_div(__isl_keep isl_aff *aff, int pos)
1231 : {
1232 0 : if (!aff)
1233 0 : return NULL;
1234 :
1235 0 : return isl_local_space_get_div(aff->ls, pos);
1236 : }
1237 :
1238 : /* Return the negation of "aff".
1239 : *
1240 : * As a special case, -NaN = NaN.
1241 : */
1242 0 : __isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff)
1243 : {
1244 0 : if (!aff)
1245 0 : return NULL;
1246 0 : if (isl_aff_is_nan(aff))
1247 0 : return aff;
1248 0 : aff = isl_aff_cow(aff);
1249 0 : if (!aff)
1250 0 : return NULL;
1251 0 : aff->v = isl_vec_cow(aff->v);
1252 0 : if (!aff->v)
1253 0 : return isl_aff_free(aff);
1254 :
1255 0 : isl_seq_neg(aff->v->el + 1, aff->v->el + 1, aff->v->size - 1);
1256 :
1257 0 : return aff;
1258 : }
1259 :
1260 : /* Remove divs from the local space that do not appear in the affine
1261 : * expression.
1262 : * We currently only remove divs at the end.
1263 : * Some intermediate divs may also not appear directly in the affine
1264 : * expression, but we would also need to check that no other divs are
1265 : * defined in terms of them.
1266 : */
1267 0 : __isl_give isl_aff *isl_aff_remove_unused_divs(__isl_take isl_aff *aff)
1268 : {
1269 : int pos;
1270 : int off;
1271 : int n;
1272 :
1273 0 : if (!aff)
1274 0 : return NULL;
1275 :
1276 0 : n = isl_local_space_dim(aff->ls, isl_dim_div);
1277 0 : off = isl_local_space_offset(aff->ls, isl_dim_div);
1278 :
1279 0 : pos = isl_seq_last_non_zero(aff->v->el + 1 + off, n) + 1;
1280 0 : if (pos == n)
1281 0 : return aff;
1282 :
1283 0 : aff = isl_aff_cow(aff);
1284 0 : if (!aff)
1285 0 : return NULL;
1286 :
1287 0 : aff->ls = isl_local_space_drop_dims(aff->ls, isl_dim_div, pos, n - pos);
1288 0 : aff->v = isl_vec_drop_els(aff->v, 1 + off + pos, n - pos);
1289 0 : if (!aff->ls || !aff->v)
1290 0 : return isl_aff_free(aff);
1291 :
1292 0 : return aff;
1293 : }
1294 :
1295 : /* Look for any divs in the aff->ls with a denominator equal to one
1296 : * and plug them into the affine expression and any subsequent divs
1297 : * that may reference the div.
1298 : */
1299 0 : static __isl_give isl_aff *plug_in_integral_divs(__isl_take isl_aff *aff)
1300 : {
1301 : int i, n;
1302 : int len;
1303 : isl_int v;
1304 : isl_vec *vec;
1305 : isl_local_space *ls;
1306 : unsigned pos;
1307 :
1308 0 : if (!aff)
1309 0 : return NULL;
1310 :
1311 0 : n = isl_local_space_dim(aff->ls, isl_dim_div);
1312 0 : len = aff->v->size;
1313 0 : for (i = 0; i < n; ++i) {
1314 0 : if (!isl_int_is_one(aff->ls->div->row[i][0]))
1315 0 : continue;
1316 0 : ls = isl_local_space_copy(aff->ls);
1317 0 : ls = isl_local_space_substitute_seq(ls, isl_dim_div, i,
1318 0 : aff->ls->div->row[i], len, i + 1, n - (i + 1));
1319 0 : vec = isl_vec_copy(aff->v);
1320 0 : vec = isl_vec_cow(vec);
1321 0 : if (!ls || !vec)
1322 : goto error;
1323 :
1324 0 : isl_int_init(v);
1325 :
1326 0 : pos = isl_local_space_offset(aff->ls, isl_dim_div) + i;
1327 0 : isl_seq_substitute(vec->el, pos, aff->ls->div->row[i],
1328 : len, len, v);
1329 :
1330 0 : isl_int_clear(v);
1331 :
1332 0 : isl_vec_free(aff->v);
1333 0 : aff->v = vec;
1334 0 : isl_local_space_free(aff->ls);
1335 0 : aff->ls = ls;
1336 : }
1337 :
1338 0 : return aff;
1339 : error:
1340 0 : isl_vec_free(vec);
1341 0 : isl_local_space_free(ls);
1342 0 : return isl_aff_free(aff);
1343 : }
1344 :
1345 : /* Look for any divs j that appear with a unit coefficient inside
1346 : * the definitions of other divs i and plug them into the definitions
1347 : * of the divs i.
1348 : *
1349 : * In particular, an expression of the form
1350 : *
1351 : * floor((f(..) + floor(g(..)/n))/m)
1352 : *
1353 : * is simplified to
1354 : *
1355 : * floor((n * f(..) + g(..))/(n * m))
1356 : *
1357 : * This simplification is correct because we can move the expression
1358 : * f(..) into the inner floor in the original expression to obtain
1359 : *
1360 : * floor(floor((n * f(..) + g(..))/n)/m)
1361 : *
1362 : * from which we can derive the simplified expression.
1363 : */
1364 0 : static __isl_give isl_aff *plug_in_unit_divs(__isl_take isl_aff *aff)
1365 : {
1366 : int i, j, n;
1367 : int off;
1368 :
1369 0 : if (!aff)
1370 0 : return NULL;
1371 :
1372 0 : n = isl_local_space_dim(aff->ls, isl_dim_div);
1373 0 : off = isl_local_space_offset(aff->ls, isl_dim_div);
1374 0 : for (i = 1; i < n; ++i) {
1375 0 : for (j = 0; j < i; ++j) {
1376 0 : if (!isl_int_is_one(aff->ls->div->row[i][1 + off + j]))
1377 0 : continue;
1378 0 : aff->ls = isl_local_space_substitute_seq(aff->ls,
1379 0 : isl_dim_div, j, aff->ls->div->row[j],
1380 0 : aff->v->size, i, 1);
1381 0 : if (!aff->ls)
1382 0 : return isl_aff_free(aff);
1383 : }
1384 : }
1385 :
1386 0 : return aff;
1387 : }
1388 :
1389 : /* Swap divs "a" and "b" in "aff", which is assumed to be non-NULL.
1390 : *
1391 : * Even though this function is only called on isl_affs with a single
1392 : * reference, we are careful to only change aff->v and aff->ls together.
1393 : */
1394 0 : static __isl_give isl_aff *swap_div(__isl_take isl_aff *aff, int a, int b)
1395 : {
1396 0 : unsigned off = isl_local_space_offset(aff->ls, isl_dim_div);
1397 : isl_local_space *ls;
1398 : isl_vec *v;
1399 :
1400 0 : ls = isl_local_space_copy(aff->ls);
1401 0 : ls = isl_local_space_swap_div(ls, a, b);
1402 0 : v = isl_vec_copy(aff->v);
1403 0 : v = isl_vec_cow(v);
1404 0 : if (!ls || !v)
1405 : goto error;
1406 :
1407 0 : isl_int_swap(v->el[1 + off + a], v->el[1 + off + b]);
1408 0 : isl_vec_free(aff->v);
1409 0 : aff->v = v;
1410 0 : isl_local_space_free(aff->ls);
1411 0 : aff->ls = ls;
1412 :
1413 0 : return aff;
1414 : error:
1415 0 : isl_vec_free(v);
1416 0 : isl_local_space_free(ls);
1417 0 : return isl_aff_free(aff);
1418 : }
1419 :
1420 : /* Merge divs "a" and "b" in "aff", which is assumed to be non-NULL.
1421 : *
1422 : * We currently do not actually remove div "b", but simply add its
1423 : * coefficient to that of "a" and then zero it out.
1424 : */
1425 0 : static __isl_give isl_aff *merge_divs(__isl_take isl_aff *aff, int a, int b)
1426 : {
1427 0 : unsigned off = isl_local_space_offset(aff->ls, isl_dim_div);
1428 :
1429 0 : if (isl_int_is_zero(aff->v->el[1 + off + b]))
1430 0 : return aff;
1431 :
1432 0 : aff->v = isl_vec_cow(aff->v);
1433 0 : if (!aff->v)
1434 0 : return isl_aff_free(aff);
1435 :
1436 0 : isl_int_add(aff->v->el[1 + off + a],
1437 : aff->v->el[1 + off + a], aff->v->el[1 + off + b]);
1438 0 : isl_int_set_si(aff->v->el[1 + off + b], 0);
1439 :
1440 0 : return aff;
1441 : }
1442 :
1443 : /* Sort the divs in the local space of "aff" according to
1444 : * the comparison function "cmp_row" in isl_local_space.c,
1445 : * combining the coefficients of identical divs.
1446 : *
1447 : * Reordering divs does not change the semantics of "aff",
1448 : * so there is no need to call isl_aff_cow.
1449 : * Moreover, this function is currently only called on isl_affs
1450 : * with a single reference.
1451 : */
1452 0 : static __isl_give isl_aff *sort_divs(__isl_take isl_aff *aff)
1453 : {
1454 : int i, j, n;
1455 :
1456 0 : if (!aff)
1457 0 : return NULL;
1458 :
1459 0 : n = isl_aff_dim(aff, isl_dim_div);
1460 0 : for (i = 1; i < n; ++i) {
1461 0 : for (j = i - 1; j >= 0; --j) {
1462 0 : int cmp = isl_mat_cmp_div(aff->ls->div, j, j + 1);
1463 0 : if (cmp < 0)
1464 0 : break;
1465 0 : if (cmp == 0)
1466 0 : aff = merge_divs(aff, j, j + 1);
1467 : else
1468 0 : aff = swap_div(aff, j, j + 1);
1469 0 : if (!aff)
1470 0 : return NULL;
1471 : }
1472 : }
1473 :
1474 0 : return aff;
1475 : }
1476 :
1477 : /* Normalize the representation of "aff".
1478 : *
1479 : * This function should only be called of "new" isl_affs, i.e.,
1480 : * with only a single reference. We therefore do not need to
1481 : * worry about affecting other instances.
1482 : */
1483 0 : __isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff)
1484 : {
1485 0 : if (!aff)
1486 0 : return NULL;
1487 0 : aff->v = isl_vec_normalize(aff->v);
1488 0 : if (!aff->v)
1489 0 : return isl_aff_free(aff);
1490 0 : aff = plug_in_integral_divs(aff);
1491 0 : aff = plug_in_unit_divs(aff);
1492 0 : aff = sort_divs(aff);
1493 0 : aff = isl_aff_remove_unused_divs(aff);
1494 0 : return aff;
1495 : }
1496 :
1497 : /* Given f, return floor(f).
1498 : * If f is an integer expression, then just return f.
1499 : * If f is a constant, then return the constant floor(f).
1500 : * Otherwise, if f = g/m, write g = q m + r,
1501 : * create a new div d = [r/m] and return the expression q + d.
1502 : * The coefficients in r are taken to lie between -m/2 and m/2.
1503 : *
1504 : * reduce_div_coefficients performs the same normalization.
1505 : *
1506 : * As a special case, floor(NaN) = NaN.
1507 : */
1508 0 : __isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff)
1509 : {
1510 : int i;
1511 : int size;
1512 : isl_ctx *ctx;
1513 : isl_vec *div;
1514 :
1515 0 : if (!aff)
1516 0 : return NULL;
1517 :
1518 0 : if (isl_aff_is_nan(aff))
1519 0 : return aff;
1520 0 : if (isl_int_is_one(aff->v->el[0]))
1521 0 : return aff;
1522 :
1523 0 : aff = isl_aff_cow(aff);
1524 0 : if (!aff)
1525 0 : return NULL;
1526 :
1527 0 : aff->v = isl_vec_cow(aff->v);
1528 0 : if (!aff->v)
1529 0 : return isl_aff_free(aff);
1530 :
1531 0 : if (isl_aff_is_cst(aff)) {
1532 0 : isl_int_fdiv_q(aff->v->el[1], aff->v->el[1], aff->v->el[0]);
1533 0 : isl_int_set_si(aff->v->el[0], 1);
1534 0 : return aff;
1535 : }
1536 :
1537 0 : div = isl_vec_copy(aff->v);
1538 0 : div = isl_vec_cow(div);
1539 0 : if (!div)
1540 0 : return isl_aff_free(aff);
1541 :
1542 0 : ctx = isl_aff_get_ctx(aff);
1543 0 : isl_int_fdiv_q(aff->v->el[0], aff->v->el[0], ctx->two);
1544 0 : for (i = 1; i < aff->v->size; ++i) {
1545 0 : isl_int_fdiv_r(div->el[i], div->el[i], div->el[0]);
1546 0 : isl_int_fdiv_q(aff->v->el[i], aff->v->el[i], div->el[0]);
1547 0 : if (isl_int_gt(div->el[i], aff->v->el[0])) {
1548 0 : isl_int_sub(div->el[i], div->el[i], div->el[0]);
1549 0 : isl_int_add_ui(aff->v->el[i], aff->v->el[i], 1);
1550 : }
1551 : }
1552 :
1553 0 : aff->ls = isl_local_space_add_div(aff->ls, div);
1554 0 : if (!aff->ls)
1555 0 : return isl_aff_free(aff);
1556 :
1557 0 : size = aff->v->size;
1558 0 : aff->v = isl_vec_extend(aff->v, size + 1);
1559 0 : if (!aff->v)
1560 0 : return isl_aff_free(aff);
1561 0 : isl_int_set_si(aff->v->el[0], 1);
1562 0 : isl_int_set_si(aff->v->el[size], 1);
1563 :
1564 0 : aff = isl_aff_normalize(aff);
1565 :
1566 0 : return aff;
1567 : }
1568 :
1569 : /* Compute
1570 : *
1571 : * aff mod m = aff - m * floor(aff/m)
1572 : *
1573 : * with m an integer value.
1574 : */
1575 0 : __isl_give isl_aff *isl_aff_mod_val(__isl_take isl_aff *aff,
1576 : __isl_take isl_val *m)
1577 : {
1578 : isl_aff *res;
1579 :
1580 0 : if (!aff || !m)
1581 : goto error;
1582 :
1583 0 : if (!isl_val_is_int(m))
1584 0 : isl_die(isl_val_get_ctx(m), isl_error_invalid,
1585 : "expecting integer modulo", goto error);
1586 :
1587 0 : res = isl_aff_copy(aff);
1588 0 : aff = isl_aff_scale_down_val(aff, isl_val_copy(m));
1589 0 : aff = isl_aff_floor(aff);
1590 0 : aff = isl_aff_scale_val(aff, m);
1591 0 : res = isl_aff_sub(res, aff);
1592 :
1593 0 : return res;
1594 : error:
1595 0 : isl_aff_free(aff);
1596 0 : isl_val_free(m);
1597 0 : return NULL;
1598 : }
1599 :
1600 : /* Compute
1601 : *
1602 : * pwaff mod m = pwaff - m * floor(pwaff/m)
1603 : */
1604 0 : __isl_give isl_pw_aff *isl_pw_aff_mod(__isl_take isl_pw_aff *pwaff, isl_int m)
1605 : {
1606 : isl_pw_aff *res;
1607 :
1608 0 : res = isl_pw_aff_copy(pwaff);
1609 0 : pwaff = isl_pw_aff_scale_down(pwaff, m);
1610 0 : pwaff = isl_pw_aff_floor(pwaff);
1611 0 : pwaff = isl_pw_aff_scale(pwaff, m);
1612 0 : res = isl_pw_aff_sub(res, pwaff);
1613 :
1614 0 : return res;
1615 : }
1616 :
1617 : /* Compute
1618 : *
1619 : * pa mod m = pa - m * floor(pa/m)
1620 : *
1621 : * with m an integer value.
1622 : */
1623 0 : __isl_give isl_pw_aff *isl_pw_aff_mod_val(__isl_take isl_pw_aff *pa,
1624 : __isl_take isl_val *m)
1625 : {
1626 0 : if (!pa || !m)
1627 : goto error;
1628 0 : if (!isl_val_is_int(m))
1629 0 : isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
1630 : "expecting integer modulo", goto error);
1631 0 : pa = isl_pw_aff_mod(pa, m->n);
1632 0 : isl_val_free(m);
1633 0 : return pa;
1634 : error:
1635 0 : isl_pw_aff_free(pa);
1636 0 : isl_val_free(m);
1637 0 : return NULL;
1638 : }
1639 :
1640 : /* Given f, return ceil(f).
1641 : * If f is an integer expression, then just return f.
1642 : * Otherwise, let f be the expression
1643 : *
1644 : * e/m
1645 : *
1646 : * then return
1647 : *
1648 : * floor((e + m - 1)/m)
1649 : *
1650 : * As a special case, ceil(NaN) = NaN.
1651 : */
1652 0 : __isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff)
1653 : {
1654 0 : if (!aff)
1655 0 : return NULL;
1656 :
1657 0 : if (isl_aff_is_nan(aff))
1658 0 : return aff;
1659 0 : if (isl_int_is_one(aff->v->el[0]))
1660 0 : return aff;
1661 :
1662 0 : aff = isl_aff_cow(aff);
1663 0 : if (!aff)
1664 0 : return NULL;
1665 0 : aff->v = isl_vec_cow(aff->v);
1666 0 : if (!aff->v)
1667 0 : return isl_aff_free(aff);
1668 :
1669 0 : isl_int_add(aff->v->el[1], aff->v->el[1], aff->v->el[0]);
1670 0 : isl_int_sub_ui(aff->v->el[1], aff->v->el[1], 1);
1671 0 : aff = isl_aff_floor(aff);
1672 :
1673 0 : return aff;
1674 : }
1675 :
1676 : /* Apply the expansion computed by isl_merge_divs.
1677 : * The expansion itself is given by "exp" while the resulting
1678 : * list of divs is given by "div".
1679 : */
1680 0 : __isl_give isl_aff *isl_aff_expand_divs(__isl_take isl_aff *aff,
1681 : __isl_take isl_mat *div, int *exp)
1682 : {
1683 : int old_n_div;
1684 : int new_n_div;
1685 : int offset;
1686 :
1687 0 : aff = isl_aff_cow(aff);
1688 0 : if (!aff || !div)
1689 : goto error;
1690 :
1691 0 : old_n_div = isl_local_space_dim(aff->ls, isl_dim_div);
1692 0 : new_n_div = isl_mat_rows(div);
1693 0 : offset = 1 + isl_local_space_offset(aff->ls, isl_dim_div);
1694 :
1695 0 : aff->v = isl_vec_expand(aff->v, offset, old_n_div, exp, new_n_div);
1696 0 : aff->ls = isl_local_space_replace_divs(aff->ls, div);
1697 0 : if (!aff->v || !aff->ls)
1698 0 : return isl_aff_free(aff);
1699 0 : return aff;
1700 : error:
1701 0 : isl_aff_free(aff);
1702 0 : isl_mat_free(div);
1703 0 : return NULL;
1704 : }
1705 :
1706 : /* Add two affine expressions that live in the same local space.
1707 : */
1708 0 : static __isl_give isl_aff *add_expanded(__isl_take isl_aff *aff1,
1709 : __isl_take isl_aff *aff2)
1710 : {
1711 : isl_int gcd, f;
1712 :
1713 0 : aff1 = isl_aff_cow(aff1);
1714 0 : if (!aff1 || !aff2)
1715 : goto error;
1716 :
1717 0 : aff1->v = isl_vec_cow(aff1->v);
1718 0 : if (!aff1->v)
1719 0 : goto error;
1720 :
1721 0 : isl_int_init(gcd);
1722 0 : isl_int_init(f);
1723 0 : isl_int_gcd(gcd, aff1->v->el[0], aff2->v->el[0]);
1724 0 : isl_int_divexact(f, aff2->v->el[0], gcd);
1725 0 : isl_seq_scale(aff1->v->el + 1, aff1->v->el + 1, f, aff1->v->size - 1);
1726 0 : isl_int_divexact(f, aff1->v->el[0], gcd);
1727 0 : isl_seq_addmul(aff1->v->el + 1, f, aff2->v->el + 1, aff1->v->size - 1);
1728 0 : isl_int_divexact(f, aff2->v->el[0], gcd);
1729 0 : isl_int_mul(aff1->v->el[0], aff1->v->el[0], f);
1730 0 : isl_int_clear(f);
1731 0 : isl_int_clear(gcd);
1732 :
1733 0 : isl_aff_free(aff2);
1734 0 : return aff1;
1735 : error:
1736 0 : isl_aff_free(aff1);
1737 0 : isl_aff_free(aff2);
1738 0 : return NULL;
1739 : }
1740 :
1741 : /* Return the sum of "aff1" and "aff2".
1742 : *
1743 : * If either of the two is NaN, then the result is NaN.
1744 : */
1745 0 : __isl_give isl_aff *isl_aff_add(__isl_take isl_aff *aff1,
1746 : __isl_take isl_aff *aff2)
1747 : {
1748 : isl_ctx *ctx;
1749 0 : int *exp1 = NULL;
1750 0 : int *exp2 = NULL;
1751 : isl_mat *div;
1752 : int n_div1, n_div2;
1753 :
1754 0 : if (!aff1 || !aff2)
1755 : goto error;
1756 :
1757 0 : ctx = isl_aff_get_ctx(aff1);
1758 0 : if (!isl_space_is_equal(aff1->ls->dim, aff2->ls->dim))
1759 0 : isl_die(ctx, isl_error_invalid,
1760 : "spaces don't match", goto error);
1761 :
1762 0 : if (isl_aff_is_nan(aff1)) {
1763 0 : isl_aff_free(aff2);
1764 0 : return aff1;
1765 : }
1766 0 : if (isl_aff_is_nan(aff2)) {
1767 0 : isl_aff_free(aff1);
1768 0 : return aff2;
1769 : }
1770 :
1771 0 : n_div1 = isl_aff_dim(aff1, isl_dim_div);
1772 0 : n_div2 = isl_aff_dim(aff2, isl_dim_div);
1773 0 : if (n_div1 == 0 && n_div2 == 0)
1774 0 : return add_expanded(aff1, aff2);
1775 :
1776 0 : exp1 = isl_alloc_array(ctx, int, n_div1);
1777 0 : exp2 = isl_alloc_array(ctx, int, n_div2);
1778 0 : if ((n_div1 && !exp1) || (n_div2 && !exp2))
1779 : goto error;
1780 :
1781 0 : div = isl_merge_divs(aff1->ls->div, aff2->ls->div, exp1, exp2);
1782 0 : aff1 = isl_aff_expand_divs(aff1, isl_mat_copy(div), exp1);
1783 0 : aff2 = isl_aff_expand_divs(aff2, div, exp2);
1784 0 : free(exp1);
1785 0 : free(exp2);
1786 :
1787 0 : return add_expanded(aff1, aff2);
1788 : error:
1789 0 : free(exp1);
1790 0 : free(exp2);
1791 0 : isl_aff_free(aff1);
1792 0 : isl_aff_free(aff2);
1793 0 : return NULL;
1794 : }
1795 :
1796 0 : __isl_give isl_aff *isl_aff_sub(__isl_take isl_aff *aff1,
1797 : __isl_take isl_aff *aff2)
1798 : {
1799 0 : return isl_aff_add(aff1, isl_aff_neg(aff2));
1800 : }
1801 :
1802 : /* Return the result of scaling "aff" by a factor of "f".
1803 : *
1804 : * As a special case, f * NaN = NaN.
1805 : */
1806 0 : __isl_give isl_aff *isl_aff_scale(__isl_take isl_aff *aff, isl_int f)
1807 : {
1808 : isl_int gcd;
1809 :
1810 0 : if (!aff)
1811 0 : return NULL;
1812 0 : if (isl_aff_is_nan(aff))
1813 0 : return aff;
1814 :
1815 0 : if (isl_int_is_one(f))
1816 0 : return aff;
1817 :
1818 0 : aff = isl_aff_cow(aff);
1819 0 : if (!aff)
1820 0 : return NULL;
1821 0 : aff->v = isl_vec_cow(aff->v);
1822 0 : if (!aff->v)
1823 0 : return isl_aff_free(aff);
1824 :
1825 0 : if (isl_int_is_pos(f) && isl_int_is_divisible_by(aff->v->el[0], f)) {
1826 0 : isl_int_divexact(aff->v->el[0], aff->v->el[0], f);
1827 0 : return aff;
1828 : }
1829 :
1830 0 : isl_int_init(gcd);
1831 0 : isl_int_gcd(gcd, aff->v->el[0], f);
1832 0 : isl_int_divexact(aff->v->el[0], aff->v->el[0], gcd);
1833 0 : isl_int_divexact(gcd, f, gcd);
1834 0 : isl_seq_scale(aff->v->el + 1, aff->v->el + 1, gcd, aff->v->size - 1);
1835 0 : isl_int_clear(gcd);
1836 :
1837 0 : return aff;
1838 : }
1839 :
1840 : /* Multiple "aff" by "v".
1841 : */
1842 0 : __isl_give isl_aff *isl_aff_scale_val(__isl_take isl_aff *aff,
1843 : __isl_take isl_val *v)
1844 : {
1845 0 : if (!aff || !v)
1846 : goto error;
1847 :
1848 0 : if (isl_val_is_one(v)) {
1849 0 : isl_val_free(v);
1850 0 : return aff;
1851 : }
1852 :
1853 0 : if (!isl_val_is_rat(v))
1854 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
1855 : "expecting rational factor", goto error);
1856 :
1857 0 : aff = isl_aff_scale(aff, v->n);
1858 0 : aff = isl_aff_scale_down(aff, v->d);
1859 :
1860 0 : isl_val_free(v);
1861 0 : return aff;
1862 : error:
1863 0 : isl_aff_free(aff);
1864 0 : isl_val_free(v);
1865 0 : return NULL;
1866 : }
1867 :
1868 : /* Return the result of scaling "aff" down by a factor of "f".
1869 : *
1870 : * As a special case, NaN/f = NaN.
1871 : */
1872 0 : __isl_give isl_aff *isl_aff_scale_down(__isl_take isl_aff *aff, isl_int f)
1873 : {
1874 : isl_int gcd;
1875 :
1876 0 : if (!aff)
1877 0 : return NULL;
1878 0 : if (isl_aff_is_nan(aff))
1879 0 : return aff;
1880 :
1881 0 : if (isl_int_is_one(f))
1882 0 : return aff;
1883 :
1884 0 : aff = isl_aff_cow(aff);
1885 0 : if (!aff)
1886 0 : return NULL;
1887 :
1888 0 : if (isl_int_is_zero(f))
1889 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
1890 : "cannot scale down by zero", return isl_aff_free(aff));
1891 :
1892 0 : aff->v = isl_vec_cow(aff->v);
1893 0 : if (!aff->v)
1894 0 : return isl_aff_free(aff);
1895 :
1896 0 : isl_int_init(gcd);
1897 0 : isl_seq_gcd(aff->v->el + 1, aff->v->size - 1, &gcd);
1898 0 : isl_int_gcd(gcd, gcd, f);
1899 0 : isl_seq_scale_down(aff->v->el + 1, aff->v->el + 1, gcd, aff->v->size - 1);
1900 0 : isl_int_divexact(gcd, f, gcd);
1901 0 : isl_int_mul(aff->v->el[0], aff->v->el[0], gcd);
1902 0 : isl_int_clear(gcd);
1903 :
1904 0 : return aff;
1905 : }
1906 :
1907 : /* Divide "aff" by "v".
1908 : */
1909 0 : __isl_give isl_aff *isl_aff_scale_down_val(__isl_take isl_aff *aff,
1910 : __isl_take isl_val *v)
1911 : {
1912 0 : if (!aff || !v)
1913 : goto error;
1914 :
1915 0 : if (isl_val_is_one(v)) {
1916 0 : isl_val_free(v);
1917 0 : return aff;
1918 : }
1919 :
1920 0 : if (!isl_val_is_rat(v))
1921 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
1922 : "expecting rational factor", goto error);
1923 0 : if (!isl_val_is_pos(v))
1924 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
1925 : "factor needs to be positive", goto error);
1926 :
1927 0 : aff = isl_aff_scale(aff, v->d);
1928 0 : aff = isl_aff_scale_down(aff, v->n);
1929 :
1930 0 : isl_val_free(v);
1931 0 : return aff;
1932 : error:
1933 0 : isl_aff_free(aff);
1934 0 : isl_val_free(v);
1935 0 : return NULL;
1936 : }
1937 :
1938 0 : __isl_give isl_aff *isl_aff_scale_down_ui(__isl_take isl_aff *aff, unsigned f)
1939 : {
1940 : isl_int v;
1941 :
1942 0 : if (f == 1)
1943 0 : return aff;
1944 :
1945 0 : isl_int_init(v);
1946 0 : isl_int_set_ui(v, f);
1947 0 : aff = isl_aff_scale_down(aff, v);
1948 0 : isl_int_clear(v);
1949 :
1950 0 : return aff;
1951 : }
1952 :
1953 0 : __isl_give isl_aff *isl_aff_set_dim_name(__isl_take isl_aff *aff,
1954 : enum isl_dim_type type, unsigned pos, const char *s)
1955 : {
1956 0 : aff = isl_aff_cow(aff);
1957 0 : if (!aff)
1958 0 : return NULL;
1959 0 : if (type == isl_dim_out)
1960 0 : isl_die(aff->v->ctx, isl_error_invalid,
1961 : "cannot set name of output/set dimension",
1962 : return isl_aff_free(aff));
1963 0 : if (type == isl_dim_in)
1964 0 : type = isl_dim_set;
1965 0 : aff->ls = isl_local_space_set_dim_name(aff->ls, type, pos, s);
1966 0 : if (!aff->ls)
1967 0 : return isl_aff_free(aff);
1968 :
1969 0 : return aff;
1970 : }
1971 :
1972 0 : __isl_give isl_aff *isl_aff_set_dim_id(__isl_take isl_aff *aff,
1973 : enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
1974 : {
1975 0 : aff = isl_aff_cow(aff);
1976 0 : if (!aff)
1977 0 : goto error;
1978 0 : if (type == isl_dim_out)
1979 0 : isl_die(aff->v->ctx, isl_error_invalid,
1980 : "cannot set name of output/set dimension",
1981 : goto error);
1982 0 : if (type == isl_dim_in)
1983 0 : type = isl_dim_set;
1984 0 : aff->ls = isl_local_space_set_dim_id(aff->ls, type, pos, id);
1985 0 : if (!aff->ls)
1986 0 : return isl_aff_free(aff);
1987 :
1988 0 : return aff;
1989 : error:
1990 0 : isl_id_free(id);
1991 0 : isl_aff_free(aff);
1992 0 : return NULL;
1993 : }
1994 :
1995 : /* Replace the identifier of the input tuple of "aff" by "id".
1996 : * type is currently required to be equal to isl_dim_in
1997 : */
1998 0 : __isl_give isl_aff *isl_aff_set_tuple_id(__isl_take isl_aff *aff,
1999 : enum isl_dim_type type, __isl_take isl_id *id)
2000 : {
2001 0 : aff = isl_aff_cow(aff);
2002 0 : if (!aff)
2003 0 : goto error;
2004 0 : if (type != isl_dim_in)
2005 0 : isl_die(aff->v->ctx, isl_error_invalid,
2006 : "cannot only set id of input tuple", goto error);
2007 0 : aff->ls = isl_local_space_set_tuple_id(aff->ls, isl_dim_set, id);
2008 0 : if (!aff->ls)
2009 0 : return isl_aff_free(aff);
2010 :
2011 0 : return aff;
2012 : error:
2013 0 : isl_id_free(id);
2014 0 : isl_aff_free(aff);
2015 0 : return NULL;
2016 : }
2017 :
2018 : /* Exploit the equalities in "eq" to simplify the affine expression
2019 : * and the expressions of the integer divisions in the local space.
2020 : * The integer divisions in this local space are assumed to appear
2021 : * as regular dimensions in "eq".
2022 : */
2023 0 : static __isl_give isl_aff *isl_aff_substitute_equalities_lifted(
2024 : __isl_take isl_aff *aff, __isl_take isl_basic_set *eq)
2025 : {
2026 : int i, j;
2027 : unsigned total;
2028 : unsigned n_div;
2029 :
2030 0 : if (!eq)
2031 0 : goto error;
2032 0 : if (eq->n_eq == 0) {
2033 0 : isl_basic_set_free(eq);
2034 0 : return aff;
2035 : }
2036 :
2037 0 : aff = isl_aff_cow(aff);
2038 0 : if (!aff)
2039 0 : goto error;
2040 :
2041 0 : aff->ls = isl_local_space_substitute_equalities(aff->ls,
2042 : isl_basic_set_copy(eq));
2043 0 : aff->v = isl_vec_cow(aff->v);
2044 0 : if (!aff->ls || !aff->v)
2045 : goto error;
2046 :
2047 0 : total = 1 + isl_space_dim(eq->dim, isl_dim_all);
2048 0 : n_div = eq->n_div;
2049 0 : for (i = 0; i < eq->n_eq; ++i) {
2050 0 : j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
2051 0 : if (j < 0 || j == 0 || j >= total)
2052 0 : continue;
2053 :
2054 0 : isl_seq_elim(aff->v->el + 1, eq->eq[i], j, total,
2055 0 : &aff->v->el[0]);
2056 : }
2057 :
2058 0 : isl_basic_set_free(eq);
2059 0 : aff = isl_aff_normalize(aff);
2060 0 : return aff;
2061 : error:
2062 0 : isl_basic_set_free(eq);
2063 0 : isl_aff_free(aff);
2064 0 : return NULL;
2065 : }
2066 :
2067 : /* Exploit the equalities in "eq" to simplify the affine expression
2068 : * and the expressions of the integer divisions in the local space.
2069 : */
2070 0 : __isl_give isl_aff *isl_aff_substitute_equalities(__isl_take isl_aff *aff,
2071 : __isl_take isl_basic_set *eq)
2072 : {
2073 : int n_div;
2074 :
2075 0 : if (!aff || !eq)
2076 : goto error;
2077 0 : n_div = isl_local_space_dim(aff->ls, isl_dim_div);
2078 0 : if (n_div > 0)
2079 0 : eq = isl_basic_set_add_dims(eq, isl_dim_set, n_div);
2080 0 : return isl_aff_substitute_equalities_lifted(aff, eq);
2081 : error:
2082 0 : isl_basic_set_free(eq);
2083 0 : isl_aff_free(aff);
2084 0 : return NULL;
2085 : }
2086 :
2087 : /* Look for equalities among the variables shared by context and aff
2088 : * and the integer divisions of aff, if any.
2089 : * The equalities are then used to eliminate coefficients and/or integer
2090 : * divisions from aff.
2091 : */
2092 0 : __isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff,
2093 : __isl_take isl_set *context)
2094 : {
2095 : isl_basic_set *hull;
2096 : int n_div;
2097 :
2098 0 : if (!aff)
2099 0 : goto error;
2100 0 : n_div = isl_local_space_dim(aff->ls, isl_dim_div);
2101 0 : if (n_div > 0) {
2102 : isl_basic_set *bset;
2103 : isl_local_space *ls;
2104 0 : context = isl_set_add_dims(context, isl_dim_set, n_div);
2105 0 : ls = isl_aff_get_domain_local_space(aff);
2106 0 : bset = isl_basic_set_from_local_space(ls);
2107 0 : bset = isl_basic_set_lift(bset);
2108 0 : bset = isl_basic_set_flatten(bset);
2109 0 : context = isl_set_intersect(context,
2110 : isl_set_from_basic_set(bset));
2111 : }
2112 :
2113 0 : hull = isl_set_affine_hull(context);
2114 0 : return isl_aff_substitute_equalities_lifted(aff, hull);
2115 : error:
2116 0 : isl_aff_free(aff);
2117 0 : isl_set_free(context);
2118 0 : return NULL;
2119 : }
2120 :
2121 0 : __isl_give isl_aff *isl_aff_gist_params(__isl_take isl_aff *aff,
2122 : __isl_take isl_set *context)
2123 : {
2124 0 : isl_set *dom_context = isl_set_universe(isl_aff_get_domain_space(aff));
2125 0 : dom_context = isl_set_intersect_params(dom_context, context);
2126 0 : return isl_aff_gist(aff, dom_context);
2127 : }
2128 :
2129 : /* Return a basic set containing those elements in the space
2130 : * of aff where it is positive. "rational" should not be set.
2131 : *
2132 : * If "aff" is NaN, then it is not positive.
2133 : */
2134 0 : static __isl_give isl_basic_set *aff_pos_basic_set(__isl_take isl_aff *aff,
2135 : int rational)
2136 : {
2137 : isl_constraint *ineq;
2138 : isl_basic_set *bset;
2139 : isl_val *c;
2140 :
2141 0 : if (!aff)
2142 0 : return NULL;
2143 0 : if (isl_aff_is_nan(aff)) {
2144 0 : isl_space *space = isl_aff_get_domain_space(aff);
2145 0 : isl_aff_free(aff);
2146 0 : return isl_basic_set_empty(space);
2147 : }
2148 0 : if (rational)
2149 0 : isl_die(isl_aff_get_ctx(aff), isl_error_unsupported,
2150 : "rational sets not supported", goto error);
2151 :
2152 0 : ineq = isl_inequality_from_aff(aff);
2153 0 : c = isl_constraint_get_constant_val(ineq);
2154 0 : c = isl_val_sub_ui(c, 1);
2155 0 : ineq = isl_constraint_set_constant_val(ineq, c);
2156 :
2157 0 : bset = isl_basic_set_from_constraint(ineq);
2158 0 : bset = isl_basic_set_simplify(bset);
2159 0 : return bset;
2160 : error:
2161 0 : isl_aff_free(aff);
2162 0 : return NULL;
2163 : }
2164 :
2165 : /* Return a basic set containing those elements in the space
2166 : * of aff where it is non-negative.
2167 : * If "rational" is set, then return a rational basic set.
2168 : *
2169 : * If "aff" is NaN, then it is not non-negative (it's not negative either).
2170 : */
2171 0 : static __isl_give isl_basic_set *aff_nonneg_basic_set(
2172 : __isl_take isl_aff *aff, int rational)
2173 : {
2174 : isl_constraint *ineq;
2175 : isl_basic_set *bset;
2176 :
2177 0 : if (!aff)
2178 0 : return NULL;
2179 0 : if (isl_aff_is_nan(aff)) {
2180 0 : isl_space *space = isl_aff_get_domain_space(aff);
2181 0 : isl_aff_free(aff);
2182 0 : return isl_basic_set_empty(space);
2183 : }
2184 :
2185 0 : ineq = isl_inequality_from_aff(aff);
2186 :
2187 0 : bset = isl_basic_set_from_constraint(ineq);
2188 0 : if (rational)
2189 0 : bset = isl_basic_set_set_rational(bset);
2190 0 : bset = isl_basic_set_simplify(bset);
2191 0 : return bset;
2192 : }
2193 :
2194 : /* Return a basic set containing those elements in the space
2195 : * of aff where it is non-negative.
2196 : */
2197 0 : __isl_give isl_basic_set *isl_aff_nonneg_basic_set(__isl_take isl_aff *aff)
2198 : {
2199 0 : return aff_nonneg_basic_set(aff, 0);
2200 : }
2201 :
2202 : /* Return a basic set containing those elements in the domain space
2203 : * of "aff" where it is positive.
2204 : */
2205 0 : __isl_give isl_basic_set *isl_aff_pos_basic_set(__isl_take isl_aff *aff)
2206 : {
2207 0 : aff = isl_aff_add_constant_num_si(aff, -1);
2208 0 : return isl_aff_nonneg_basic_set(aff);
2209 : }
2210 :
2211 : /* Return a basic set containing those elements in the domain space
2212 : * of aff where it is negative.
2213 : */
2214 0 : __isl_give isl_basic_set *isl_aff_neg_basic_set(__isl_take isl_aff *aff)
2215 : {
2216 0 : aff = isl_aff_neg(aff);
2217 0 : return isl_aff_pos_basic_set(aff);
2218 : }
2219 :
2220 : /* Return a basic set containing those elements in the space
2221 : * of aff where it is zero.
2222 : * If "rational" is set, then return a rational basic set.
2223 : *
2224 : * If "aff" is NaN, then it is not zero.
2225 : */
2226 0 : static __isl_give isl_basic_set *aff_zero_basic_set(__isl_take isl_aff *aff,
2227 : int rational)
2228 : {
2229 : isl_constraint *ineq;
2230 : isl_basic_set *bset;
2231 :
2232 0 : if (!aff)
2233 0 : return NULL;
2234 0 : if (isl_aff_is_nan(aff)) {
2235 0 : isl_space *space = isl_aff_get_domain_space(aff);
2236 0 : isl_aff_free(aff);
2237 0 : return isl_basic_set_empty(space);
2238 : }
2239 :
2240 0 : ineq = isl_equality_from_aff(aff);
2241 :
2242 0 : bset = isl_basic_set_from_constraint(ineq);
2243 0 : if (rational)
2244 0 : bset = isl_basic_set_set_rational(bset);
2245 0 : bset = isl_basic_set_simplify(bset);
2246 0 : return bset;
2247 : }
2248 :
2249 : /* Return a basic set containing those elements in the space
2250 : * of aff where it is zero.
2251 : */
2252 0 : __isl_give isl_basic_set *isl_aff_zero_basic_set(__isl_take isl_aff *aff)
2253 : {
2254 0 : return aff_zero_basic_set(aff, 0);
2255 : }
2256 :
2257 : /* Return a basic set containing those elements in the shared space
2258 : * of aff1 and aff2 where aff1 is greater than or equal to aff2.
2259 : */
2260 0 : __isl_give isl_basic_set *isl_aff_ge_basic_set(__isl_take isl_aff *aff1,
2261 : __isl_take isl_aff *aff2)
2262 : {
2263 0 : aff1 = isl_aff_sub(aff1, aff2);
2264 :
2265 0 : return isl_aff_nonneg_basic_set(aff1);
2266 : }
2267 :
2268 : /* Return a basic set containing those elements in the shared domain space
2269 : * of "aff1" and "aff2" where "aff1" is greater than "aff2".
2270 : */
2271 0 : __isl_give isl_basic_set *isl_aff_gt_basic_set(__isl_take isl_aff *aff1,
2272 : __isl_take isl_aff *aff2)
2273 : {
2274 0 : aff1 = isl_aff_sub(aff1, aff2);
2275 :
2276 0 : return isl_aff_pos_basic_set(aff1);
2277 : }
2278 :
2279 : /* Return a set containing those elements in the shared space
2280 : * of aff1 and aff2 where aff1 is greater than or equal to aff2.
2281 : */
2282 0 : __isl_give isl_set *isl_aff_ge_set(__isl_take isl_aff *aff1,
2283 : __isl_take isl_aff *aff2)
2284 : {
2285 0 : return isl_set_from_basic_set(isl_aff_ge_basic_set(aff1, aff2));
2286 : }
2287 :
2288 : /* Return a set containing those elements in the shared domain space
2289 : * of aff1 and aff2 where aff1 is greater than aff2.
2290 : *
2291 : * If either of the two inputs is NaN, then the result is empty,
2292 : * as comparisons with NaN always return false.
2293 : */
2294 0 : __isl_give isl_set *isl_aff_gt_set(__isl_take isl_aff *aff1,
2295 : __isl_take isl_aff *aff2)
2296 : {
2297 0 : return isl_set_from_basic_set(isl_aff_gt_basic_set(aff1, aff2));
2298 : }
2299 :
2300 : /* Return a basic set containing those elements in the shared space
2301 : * of aff1 and aff2 where aff1 is smaller than or equal to aff2.
2302 : */
2303 0 : __isl_give isl_basic_set *isl_aff_le_basic_set(__isl_take isl_aff *aff1,
2304 : __isl_take isl_aff *aff2)
2305 : {
2306 0 : return isl_aff_ge_basic_set(aff2, aff1);
2307 : }
2308 :
2309 : /* Return a basic set containing those elements in the shared domain space
2310 : * of "aff1" and "aff2" where "aff1" is smaller than "aff2".
2311 : */
2312 0 : __isl_give isl_basic_set *isl_aff_lt_basic_set(__isl_take isl_aff *aff1,
2313 : __isl_take isl_aff *aff2)
2314 : {
2315 0 : return isl_aff_gt_basic_set(aff2, aff1);
2316 : }
2317 :
2318 : /* Return a set containing those elements in the shared space
2319 : * of aff1 and aff2 where aff1 is smaller than or equal to aff2.
2320 : */
2321 0 : __isl_give isl_set *isl_aff_le_set(__isl_take isl_aff *aff1,
2322 : __isl_take isl_aff *aff2)
2323 : {
2324 0 : return isl_aff_ge_set(aff2, aff1);
2325 : }
2326 :
2327 : /* Return a set containing those elements in the shared domain space
2328 : * of "aff1" and "aff2" where "aff1" is smaller than "aff2".
2329 : */
2330 0 : __isl_give isl_set *isl_aff_lt_set(__isl_take isl_aff *aff1,
2331 : __isl_take isl_aff *aff2)
2332 : {
2333 0 : return isl_set_from_basic_set(isl_aff_lt_basic_set(aff1, aff2));
2334 : }
2335 :
2336 : /* Return a basic set containing those elements in the shared space
2337 : * of aff1 and aff2 where aff1 and aff2 are equal.
2338 : */
2339 0 : __isl_give isl_basic_set *isl_aff_eq_basic_set(__isl_take isl_aff *aff1,
2340 : __isl_take isl_aff *aff2)
2341 : {
2342 0 : aff1 = isl_aff_sub(aff1, aff2);
2343 :
2344 0 : return isl_aff_zero_basic_set(aff1);
2345 : }
2346 :
2347 : /* Return a set containing those elements in the shared space
2348 : * of aff1 and aff2 where aff1 and aff2 are equal.
2349 : */
2350 0 : __isl_give isl_set *isl_aff_eq_set(__isl_take isl_aff *aff1,
2351 : __isl_take isl_aff *aff2)
2352 : {
2353 0 : return isl_set_from_basic_set(isl_aff_eq_basic_set(aff1, aff2));
2354 : }
2355 :
2356 : /* Return a set containing those elements in the shared domain space
2357 : * of aff1 and aff2 where aff1 and aff2 are not equal.
2358 : *
2359 : * If either of the two inputs is NaN, then the result is empty,
2360 : * as comparisons with NaN always return false.
2361 : */
2362 0 : __isl_give isl_set *isl_aff_ne_set(__isl_take isl_aff *aff1,
2363 : __isl_take isl_aff *aff2)
2364 : {
2365 : isl_set *set_lt, *set_gt;
2366 :
2367 0 : set_lt = isl_aff_lt_set(isl_aff_copy(aff1),
2368 : isl_aff_copy(aff2));
2369 0 : set_gt = isl_aff_gt_set(aff1, aff2);
2370 0 : return isl_set_union_disjoint(set_lt, set_gt);
2371 : }
2372 :
2373 0 : __isl_give isl_aff *isl_aff_add_on_domain(__isl_keep isl_set *dom,
2374 : __isl_take isl_aff *aff1, __isl_take isl_aff *aff2)
2375 : {
2376 0 : aff1 = isl_aff_add(aff1, aff2);
2377 0 : aff1 = isl_aff_gist(aff1, isl_set_copy(dom));
2378 0 : return aff1;
2379 : }
2380 :
2381 0 : int isl_aff_is_empty(__isl_keep isl_aff *aff)
2382 : {
2383 0 : if (!aff)
2384 0 : return -1;
2385 :
2386 0 : return 0;
2387 : }
2388 :
2389 : /* Check whether the given affine expression has non-zero coefficient
2390 : * for any dimension in the given range or if any of these dimensions
2391 : * appear with non-zero coefficients in any of the integer divisions
2392 : * involved in the affine expression.
2393 : */
2394 0 : isl_bool isl_aff_involves_dims(__isl_keep isl_aff *aff,
2395 : enum isl_dim_type type, unsigned first, unsigned n)
2396 : {
2397 : int i;
2398 : isl_ctx *ctx;
2399 0 : int *active = NULL;
2400 0 : isl_bool involves = isl_bool_false;
2401 :
2402 0 : if (!aff)
2403 0 : return isl_bool_error;
2404 0 : if (n == 0)
2405 0 : return isl_bool_false;
2406 :
2407 0 : ctx = isl_aff_get_ctx(aff);
2408 0 : if (first + n > isl_aff_dim(aff, type))
2409 0 : isl_die(ctx, isl_error_invalid,
2410 : "range out of bounds", return isl_bool_error);
2411 :
2412 0 : active = isl_local_space_get_active(aff->ls, aff->v->el + 2);
2413 0 : if (!active)
2414 0 : goto error;
2415 :
2416 0 : first += isl_local_space_offset(aff->ls, type) - 1;
2417 0 : for (i = 0; i < n; ++i)
2418 0 : if (active[first + i]) {
2419 0 : involves = isl_bool_true;
2420 0 : break;
2421 : }
2422 :
2423 0 : free(active);
2424 :
2425 0 : return involves;
2426 : error:
2427 0 : free(active);
2428 0 : return isl_bool_error;
2429 : }
2430 :
2431 0 : __isl_give isl_aff *isl_aff_drop_dims(__isl_take isl_aff *aff,
2432 : enum isl_dim_type type, unsigned first, unsigned n)
2433 : {
2434 : isl_ctx *ctx;
2435 :
2436 0 : if (!aff)
2437 0 : return NULL;
2438 0 : if (type == isl_dim_out)
2439 0 : isl_die(aff->v->ctx, isl_error_invalid,
2440 : "cannot drop output/set dimension",
2441 : return isl_aff_free(aff));
2442 0 : if (type == isl_dim_in)
2443 0 : type = isl_dim_set;
2444 0 : if (n == 0 && !isl_local_space_is_named_or_nested(aff->ls, type))
2445 0 : return aff;
2446 :
2447 0 : ctx = isl_aff_get_ctx(aff);
2448 0 : if (first + n > isl_local_space_dim(aff->ls, type))
2449 0 : isl_die(ctx, isl_error_invalid, "range out of bounds",
2450 : return isl_aff_free(aff));
2451 :
2452 0 : aff = isl_aff_cow(aff);
2453 0 : if (!aff)
2454 0 : return NULL;
2455 :
2456 0 : aff->ls = isl_local_space_drop_dims(aff->ls, type, first, n);
2457 0 : if (!aff->ls)
2458 0 : return isl_aff_free(aff);
2459 :
2460 0 : first += 1 + isl_local_space_offset(aff->ls, type);
2461 0 : aff->v = isl_vec_drop_els(aff->v, first, n);
2462 0 : if (!aff->v)
2463 0 : return isl_aff_free(aff);
2464 :
2465 0 : return aff;
2466 : }
2467 :
2468 : /* Drop the "n" domain dimensions starting at "first" from "aff",
2469 : * after checking that they do not appear in the affine expression.
2470 : */
2471 0 : static __isl_give isl_aff *drop_domain(__isl_take isl_aff *aff, unsigned first,
2472 : unsigned n)
2473 : {
2474 : isl_bool involves;
2475 :
2476 0 : involves = isl_aff_involves_dims(aff, isl_dim_in, first, n);
2477 0 : if (involves < 0)
2478 0 : return isl_aff_free(aff);
2479 0 : if (involves)
2480 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
2481 : "affine expression involves some of the domain dimensions",
2482 : return isl_aff_free(aff));
2483 0 : return isl_aff_drop_dims(aff, isl_dim_in, first, n);
2484 : }
2485 :
2486 : /* Project the domain of the affine expression onto its parameter space.
2487 : * The affine expression may not involve any of the domain dimensions.
2488 : */
2489 0 : __isl_give isl_aff *isl_aff_project_domain_on_params(__isl_take isl_aff *aff)
2490 : {
2491 : isl_space *space;
2492 : unsigned n;
2493 :
2494 0 : n = isl_aff_dim(aff, isl_dim_in);
2495 0 : aff = drop_domain(aff, 0, n);
2496 0 : space = isl_aff_get_domain_space(aff);
2497 0 : space = isl_space_params(space);
2498 0 : aff = isl_aff_reset_domain_space(aff, space);
2499 0 : return aff;
2500 : }
2501 :
2502 : /* Check that the domain of "aff" is a product.
2503 : */
2504 0 : static isl_stat check_domain_product(__isl_keep isl_aff *aff)
2505 : {
2506 : isl_bool is_product;
2507 :
2508 0 : is_product = isl_space_is_product(isl_aff_peek_domain_space(aff));
2509 0 : if (is_product < 0)
2510 0 : return isl_stat_error;
2511 0 : if (!is_product)
2512 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
2513 : "domain is not a product", return isl_stat_error);
2514 0 : return isl_stat_ok;
2515 : }
2516 :
2517 : /* Given an affine function with a domain of the form [A -> B] that
2518 : * does not depend on B, return the same function on domain A.
2519 : */
2520 0 : __isl_give isl_aff *isl_aff_domain_factor_domain(__isl_take isl_aff *aff)
2521 : {
2522 : isl_space *space;
2523 : int n, n_in;
2524 :
2525 0 : if (check_domain_product(aff) < 0)
2526 0 : return isl_aff_free(aff);
2527 0 : space = isl_aff_get_domain_space(aff);
2528 0 : n = isl_space_dim(space, isl_dim_set);
2529 0 : space = isl_space_factor_domain(space);
2530 0 : n_in = isl_space_dim(space, isl_dim_set);
2531 0 : aff = drop_domain(aff, n_in, n - n_in);
2532 0 : aff = isl_aff_reset_domain_space(aff, space);
2533 0 : return aff;
2534 : }
2535 :
2536 : /* Convert an affine expression defined over a parameter domain
2537 : * into one that is defined over a zero-dimensional set.
2538 : */
2539 0 : __isl_give isl_aff *isl_aff_from_range(__isl_take isl_aff *aff)
2540 : {
2541 : isl_local_space *ls;
2542 :
2543 0 : ls = isl_aff_take_domain_local_space(aff);
2544 0 : ls = isl_local_space_set_from_params(ls);
2545 0 : aff = isl_aff_restore_domain_local_space(aff, ls);
2546 :
2547 0 : return aff;
2548 : }
2549 :
2550 0 : __isl_give isl_aff *isl_aff_insert_dims(__isl_take isl_aff *aff,
2551 : enum isl_dim_type type, unsigned first, unsigned n)
2552 : {
2553 : isl_ctx *ctx;
2554 :
2555 0 : if (!aff)
2556 0 : return NULL;
2557 0 : if (type == isl_dim_out)
2558 0 : isl_die(aff->v->ctx, isl_error_invalid,
2559 : "cannot insert output/set dimensions",
2560 : return isl_aff_free(aff));
2561 0 : if (type == isl_dim_in)
2562 0 : type = isl_dim_set;
2563 0 : if (n == 0 && !isl_local_space_is_named_or_nested(aff->ls, type))
2564 0 : return aff;
2565 :
2566 0 : ctx = isl_aff_get_ctx(aff);
2567 0 : if (first > isl_local_space_dim(aff->ls, type))
2568 0 : isl_die(ctx, isl_error_invalid, "position out of bounds",
2569 : return isl_aff_free(aff));
2570 :
2571 0 : aff = isl_aff_cow(aff);
2572 0 : if (!aff)
2573 0 : return NULL;
2574 :
2575 0 : aff->ls = isl_local_space_insert_dims(aff->ls, type, first, n);
2576 0 : if (!aff->ls)
2577 0 : return isl_aff_free(aff);
2578 :
2579 0 : first += 1 + isl_local_space_offset(aff->ls, type);
2580 0 : aff->v = isl_vec_insert_zero_els(aff->v, first, n);
2581 0 : if (!aff->v)
2582 0 : return isl_aff_free(aff);
2583 :
2584 0 : return aff;
2585 : }
2586 :
2587 0 : __isl_give isl_aff *isl_aff_add_dims(__isl_take isl_aff *aff,
2588 : enum isl_dim_type type, unsigned n)
2589 : {
2590 : unsigned pos;
2591 :
2592 0 : pos = isl_aff_dim(aff, type);
2593 :
2594 0 : return isl_aff_insert_dims(aff, type, pos, n);
2595 : }
2596 :
2597 0 : __isl_give isl_pw_aff *isl_pw_aff_add_dims(__isl_take isl_pw_aff *pwaff,
2598 : enum isl_dim_type type, unsigned n)
2599 : {
2600 : unsigned pos;
2601 :
2602 0 : pos = isl_pw_aff_dim(pwaff, type);
2603 :
2604 0 : return isl_pw_aff_insert_dims(pwaff, type, pos, n);
2605 : }
2606 :
2607 : /* Move the "n" dimensions of "src_type" starting at "src_pos" of "aff"
2608 : * to dimensions of "dst_type" at "dst_pos".
2609 : *
2610 : * We only support moving input dimensions to parameters and vice versa.
2611 : */
2612 0 : __isl_give isl_aff *isl_aff_move_dims(__isl_take isl_aff *aff,
2613 : enum isl_dim_type dst_type, unsigned dst_pos,
2614 : enum isl_dim_type src_type, unsigned src_pos, unsigned n)
2615 : {
2616 : unsigned g_dst_pos;
2617 : unsigned g_src_pos;
2618 :
2619 0 : if (!aff)
2620 0 : return NULL;
2621 0 : if (n == 0 &&
2622 0 : !isl_local_space_is_named_or_nested(aff->ls, src_type) &&
2623 0 : !isl_local_space_is_named_or_nested(aff->ls, dst_type))
2624 0 : return aff;
2625 :
2626 0 : if (dst_type == isl_dim_out || src_type == isl_dim_out)
2627 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
2628 : "cannot move output/set dimension",
2629 : return isl_aff_free(aff));
2630 0 : if (dst_type == isl_dim_div || src_type == isl_dim_div)
2631 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
2632 : "cannot move divs", return isl_aff_free(aff));
2633 0 : if (dst_type == isl_dim_in)
2634 0 : dst_type = isl_dim_set;
2635 0 : if (src_type == isl_dim_in)
2636 0 : src_type = isl_dim_set;
2637 :
2638 0 : if (src_pos + n > isl_local_space_dim(aff->ls, src_type))
2639 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
2640 : "range out of bounds", return isl_aff_free(aff));
2641 0 : if (dst_type == src_type)
2642 0 : isl_die(isl_aff_get_ctx(aff), isl_error_unsupported,
2643 : "moving dims within the same type not supported",
2644 : return isl_aff_free(aff));
2645 :
2646 0 : aff = isl_aff_cow(aff);
2647 0 : if (!aff)
2648 0 : return NULL;
2649 :
2650 0 : g_src_pos = 1 + isl_local_space_offset(aff->ls, src_type) + src_pos;
2651 0 : g_dst_pos = 1 + isl_local_space_offset(aff->ls, dst_type) + dst_pos;
2652 0 : if (dst_type > src_type)
2653 0 : g_dst_pos -= n;
2654 :
2655 0 : aff->v = isl_vec_move_els(aff->v, g_dst_pos, g_src_pos, n);
2656 0 : aff->ls = isl_local_space_move_dims(aff->ls, dst_type, dst_pos,
2657 : src_type, src_pos, n);
2658 0 : if (!aff->v || !aff->ls)
2659 0 : return isl_aff_free(aff);
2660 :
2661 0 : aff = sort_divs(aff);
2662 :
2663 0 : return aff;
2664 : }
2665 :
2666 0 : __isl_give isl_pw_aff *isl_pw_aff_from_aff(__isl_take isl_aff *aff)
2667 : {
2668 0 : isl_set *dom = isl_set_universe(isl_aff_get_domain_space(aff));
2669 0 : return isl_pw_aff_alloc(dom, aff);
2670 : }
2671 :
2672 : #define isl_aff_involves_nan isl_aff_is_nan
2673 :
2674 : #undef PW
2675 : #define PW isl_pw_aff
2676 : #undef EL
2677 : #define EL isl_aff
2678 : #undef EL_IS_ZERO
2679 : #define EL_IS_ZERO is_empty
2680 : #undef ZERO
2681 : #define ZERO empty
2682 : #undef IS_ZERO
2683 : #define IS_ZERO is_empty
2684 : #undef FIELD
2685 : #define FIELD aff
2686 : #undef DEFAULT_IS_ZERO
2687 : #define DEFAULT_IS_ZERO 0
2688 :
2689 : #define NO_OPT
2690 : #define NO_LIFT
2691 : #define NO_MORPH
2692 :
2693 : #include <isl_pw_templ.c>
2694 : #include <isl_pw_eval.c>
2695 : #include <isl_pw_hash.c>
2696 : #include <isl_pw_union_opt.c>
2697 :
2698 : #undef BASE
2699 : #define BASE pw_aff
2700 :
2701 : #include <isl_union_single.c>
2702 : #include <isl_union_neg.c>
2703 :
2704 0 : static __isl_give isl_set *align_params_pw_pw_set_and(
2705 : __isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2,
2706 : __isl_give isl_set *(*fn)(__isl_take isl_pw_aff *pwaff1,
2707 : __isl_take isl_pw_aff *pwaff2))
2708 : {
2709 : isl_bool equal_params;
2710 :
2711 0 : if (!pwaff1 || !pwaff2)
2712 : goto error;
2713 0 : equal_params = isl_space_has_equal_params(pwaff1->dim, pwaff2->dim);
2714 0 : if (equal_params < 0)
2715 0 : goto error;
2716 0 : if (equal_params)
2717 0 : return fn(pwaff1, pwaff2);
2718 0 : if (isl_pw_aff_check_named_params(pwaff1) < 0 ||
2719 0 : isl_pw_aff_check_named_params(pwaff2) < 0)
2720 : goto error;
2721 0 : pwaff1 = isl_pw_aff_align_params(pwaff1, isl_pw_aff_get_space(pwaff2));
2722 0 : pwaff2 = isl_pw_aff_align_params(pwaff2, isl_pw_aff_get_space(pwaff1));
2723 0 : return fn(pwaff1, pwaff2);
2724 : error:
2725 0 : isl_pw_aff_free(pwaff1);
2726 0 : isl_pw_aff_free(pwaff2);
2727 0 : return NULL;
2728 : }
2729 :
2730 : /* Align the parameters of the to isl_pw_aff arguments and
2731 : * then apply a function "fn" on them that returns an isl_map.
2732 : */
2733 0 : static __isl_give isl_map *align_params_pw_pw_map_and(
2734 : __isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2,
2735 : __isl_give isl_map *(*fn)(__isl_take isl_pw_aff *pa1,
2736 : __isl_take isl_pw_aff *pa2))
2737 : {
2738 : isl_bool equal_params;
2739 :
2740 0 : if (!pa1 || !pa2)
2741 : goto error;
2742 0 : equal_params = isl_space_has_equal_params(pa1->dim, pa2->dim);
2743 0 : if (equal_params < 0)
2744 0 : goto error;
2745 0 : if (equal_params)
2746 0 : return fn(pa1, pa2);
2747 0 : if (isl_pw_aff_check_named_params(pa1) < 0 ||
2748 0 : isl_pw_aff_check_named_params(pa2) < 0)
2749 : goto error;
2750 0 : pa1 = isl_pw_aff_align_params(pa1, isl_pw_aff_get_space(pa2));
2751 0 : pa2 = isl_pw_aff_align_params(pa2, isl_pw_aff_get_space(pa1));
2752 0 : return fn(pa1, pa2);
2753 : error:
2754 0 : isl_pw_aff_free(pa1);
2755 0 : isl_pw_aff_free(pa2);
2756 0 : return NULL;
2757 : }
2758 :
2759 : /* Compute a piecewise quasi-affine expression with a domain that
2760 : * is the union of those of pwaff1 and pwaff2 and such that on each
2761 : * cell, the quasi-affine expression is the maximum of those of pwaff1
2762 : * and pwaff2. If only one of pwaff1 or pwaff2 is defined on a given
2763 : * cell, then the associated expression is the defined one.
2764 : */
2765 0 : static __isl_give isl_pw_aff *pw_aff_union_max(__isl_take isl_pw_aff *pwaff1,
2766 : __isl_take isl_pw_aff *pwaff2)
2767 : {
2768 0 : return isl_pw_aff_union_opt_cmp(pwaff1, pwaff2, &isl_aff_ge_set);
2769 : }
2770 :
2771 0 : __isl_give isl_pw_aff *isl_pw_aff_union_max(__isl_take isl_pw_aff *pwaff1,
2772 : __isl_take isl_pw_aff *pwaff2)
2773 : {
2774 0 : return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2,
2775 : &pw_aff_union_max);
2776 : }
2777 :
2778 : /* Compute a piecewise quasi-affine expression with a domain that
2779 : * is the union of those of pwaff1 and pwaff2 and such that on each
2780 : * cell, the quasi-affine expression is the minimum of those of pwaff1
2781 : * and pwaff2. If only one of pwaff1 or pwaff2 is defined on a given
2782 : * cell, then the associated expression is the defined one.
2783 : */
2784 0 : static __isl_give isl_pw_aff *pw_aff_union_min(__isl_take isl_pw_aff *pwaff1,
2785 : __isl_take isl_pw_aff *pwaff2)
2786 : {
2787 0 : return isl_pw_aff_union_opt_cmp(pwaff1, pwaff2, &isl_aff_le_set);
2788 : }
2789 :
2790 0 : __isl_give isl_pw_aff *isl_pw_aff_union_min(__isl_take isl_pw_aff *pwaff1,
2791 : __isl_take isl_pw_aff *pwaff2)
2792 : {
2793 0 : return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2,
2794 : &pw_aff_union_min);
2795 : }
2796 :
2797 0 : __isl_give isl_pw_aff *isl_pw_aff_union_opt(__isl_take isl_pw_aff *pwaff1,
2798 : __isl_take isl_pw_aff *pwaff2, int max)
2799 : {
2800 0 : if (max)
2801 0 : return isl_pw_aff_union_max(pwaff1, pwaff2);
2802 : else
2803 0 : return isl_pw_aff_union_min(pwaff1, pwaff2);
2804 : }
2805 :
2806 : /* Return a set containing those elements in the domain
2807 : * of "pwaff" where it satisfies "fn" (if complement is 0) or
2808 : * does not satisfy "fn" (if complement is 1).
2809 : *
2810 : * The pieces with a NaN never belong to the result since
2811 : * NaN does not satisfy any property.
2812 : */
2813 0 : static __isl_give isl_set *pw_aff_locus(__isl_take isl_pw_aff *pwaff,
2814 : __isl_give isl_basic_set *(*fn)(__isl_take isl_aff *aff, int rational),
2815 : int complement)
2816 : {
2817 : int i;
2818 : isl_set *set;
2819 :
2820 0 : if (!pwaff)
2821 0 : return NULL;
2822 :
2823 0 : set = isl_set_empty(isl_pw_aff_get_domain_space(pwaff));
2824 :
2825 0 : for (i = 0; i < pwaff->n; ++i) {
2826 : isl_basic_set *bset;
2827 : isl_set *set_i, *locus;
2828 : isl_bool rational;
2829 :
2830 0 : if (isl_aff_is_nan(pwaff->p[i].aff))
2831 0 : continue;
2832 :
2833 0 : rational = isl_set_has_rational(pwaff->p[i].set);
2834 0 : bset = fn(isl_aff_copy(pwaff->p[i].aff), rational);
2835 0 : locus = isl_set_from_basic_set(bset);
2836 0 : set_i = isl_set_copy(pwaff->p[i].set);
2837 0 : if (complement)
2838 0 : set_i = isl_set_subtract(set_i, locus);
2839 : else
2840 0 : set_i = isl_set_intersect(set_i, locus);
2841 0 : set = isl_set_union_disjoint(set, set_i);
2842 : }
2843 :
2844 0 : isl_pw_aff_free(pwaff);
2845 :
2846 0 : return set;
2847 : }
2848 :
2849 : /* Return a set containing those elements in the domain
2850 : * of "pa" where it is positive.
2851 : */
2852 0 : __isl_give isl_set *isl_pw_aff_pos_set(__isl_take isl_pw_aff *pa)
2853 : {
2854 0 : return pw_aff_locus(pa, &aff_pos_basic_set, 0);
2855 : }
2856 :
2857 : /* Return a set containing those elements in the domain
2858 : * of pwaff where it is non-negative.
2859 : */
2860 0 : __isl_give isl_set *isl_pw_aff_nonneg_set(__isl_take isl_pw_aff *pwaff)
2861 : {
2862 0 : return pw_aff_locus(pwaff, &aff_nonneg_basic_set, 0);
2863 : }
2864 :
2865 : /* Return a set containing those elements in the domain
2866 : * of pwaff where it is zero.
2867 : */
2868 0 : __isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff)
2869 : {
2870 0 : return pw_aff_locus(pwaff, &aff_zero_basic_set, 0);
2871 : }
2872 :
2873 : /* Return a set containing those elements in the domain
2874 : * of pwaff where it is not zero.
2875 : */
2876 0 : __isl_give isl_set *isl_pw_aff_non_zero_set(__isl_take isl_pw_aff *pwaff)
2877 : {
2878 0 : return pw_aff_locus(pwaff, &aff_zero_basic_set, 1);
2879 : }
2880 :
2881 : /* Return a set containing those elements in the shared domain
2882 : * of pwaff1 and pwaff2 where pwaff1 is greater than (or equal) to pwaff2.
2883 : *
2884 : * We compute the difference on the shared domain and then construct
2885 : * the set of values where this difference is non-negative.
2886 : * If strict is set, we first subtract 1 from the difference.
2887 : * If equal is set, we only return the elements where pwaff1 and pwaff2
2888 : * are equal.
2889 : */
2890 0 : static __isl_give isl_set *pw_aff_gte_set(__isl_take isl_pw_aff *pwaff1,
2891 : __isl_take isl_pw_aff *pwaff2, int strict, int equal)
2892 : {
2893 : isl_set *set1, *set2;
2894 :
2895 0 : set1 = isl_pw_aff_domain(isl_pw_aff_copy(pwaff1));
2896 0 : set2 = isl_pw_aff_domain(isl_pw_aff_copy(pwaff2));
2897 0 : set1 = isl_set_intersect(set1, set2);
2898 0 : pwaff1 = isl_pw_aff_intersect_domain(pwaff1, isl_set_copy(set1));
2899 0 : pwaff2 = isl_pw_aff_intersect_domain(pwaff2, isl_set_copy(set1));
2900 0 : pwaff1 = isl_pw_aff_add(pwaff1, isl_pw_aff_neg(pwaff2));
2901 :
2902 0 : if (strict) {
2903 0 : isl_space *dim = isl_set_get_space(set1);
2904 : isl_aff *aff;
2905 0 : aff = isl_aff_zero_on_domain(isl_local_space_from_space(dim));
2906 0 : aff = isl_aff_add_constant_si(aff, -1);
2907 0 : pwaff1 = isl_pw_aff_add(pwaff1, isl_pw_aff_alloc(set1, aff));
2908 : } else
2909 0 : isl_set_free(set1);
2910 :
2911 0 : if (equal)
2912 0 : return isl_pw_aff_zero_set(pwaff1);
2913 0 : return isl_pw_aff_nonneg_set(pwaff1);
2914 : }
2915 :
2916 : /* Return a set containing those elements in the shared domain
2917 : * of pwaff1 and pwaff2 where pwaff1 is equal to pwaff2.
2918 : */
2919 0 : static __isl_give isl_set *pw_aff_eq_set(__isl_take isl_pw_aff *pwaff1,
2920 : __isl_take isl_pw_aff *pwaff2)
2921 : {
2922 0 : return pw_aff_gte_set(pwaff1, pwaff2, 0, 1);
2923 : }
2924 :
2925 0 : __isl_give isl_set *isl_pw_aff_eq_set(__isl_take isl_pw_aff *pwaff1,
2926 : __isl_take isl_pw_aff *pwaff2)
2927 : {
2928 0 : return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_eq_set);
2929 : }
2930 :
2931 : /* Return a set containing those elements in the shared domain
2932 : * of pwaff1 and pwaff2 where pwaff1 is greater than or equal to pwaff2.
2933 : */
2934 0 : static __isl_give isl_set *pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1,
2935 : __isl_take isl_pw_aff *pwaff2)
2936 : {
2937 0 : return pw_aff_gte_set(pwaff1, pwaff2, 0, 0);
2938 : }
2939 :
2940 0 : __isl_give isl_set *isl_pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1,
2941 : __isl_take isl_pw_aff *pwaff2)
2942 : {
2943 0 : return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_ge_set);
2944 : }
2945 :
2946 : /* Return a set containing those elements in the shared domain
2947 : * of pwaff1 and pwaff2 where pwaff1 is strictly greater than pwaff2.
2948 : */
2949 0 : static __isl_give isl_set *pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1,
2950 : __isl_take isl_pw_aff *pwaff2)
2951 : {
2952 0 : return pw_aff_gte_set(pwaff1, pwaff2, 1, 0);
2953 : }
2954 :
2955 0 : __isl_give isl_set *isl_pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1,
2956 : __isl_take isl_pw_aff *pwaff2)
2957 : {
2958 0 : return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_gt_set);
2959 : }
2960 :
2961 0 : __isl_give isl_set *isl_pw_aff_le_set(__isl_take isl_pw_aff *pwaff1,
2962 : __isl_take isl_pw_aff *pwaff2)
2963 : {
2964 0 : return isl_pw_aff_ge_set(pwaff2, pwaff1);
2965 : }
2966 :
2967 0 : __isl_give isl_set *isl_pw_aff_lt_set(__isl_take isl_pw_aff *pwaff1,
2968 : __isl_take isl_pw_aff *pwaff2)
2969 : {
2970 0 : return isl_pw_aff_gt_set(pwaff2, pwaff1);
2971 : }
2972 :
2973 : /* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
2974 : * where the function values are ordered in the same way as "order",
2975 : * which returns a set in the shared domain of its two arguments.
2976 : * The parameters of "pa1" and "pa2" are assumed to have been aligned.
2977 : *
2978 : * Let "pa1" and "pa2" be defined on domains A and B respectively.
2979 : * We first pull back the two functions such that they are defined on
2980 : * the domain [A -> B]. Then we apply "order", resulting in a set
2981 : * in the space [A -> B]. Finally, we unwrap this set to obtain
2982 : * a map in the space A -> B.
2983 : */
2984 0 : static __isl_give isl_map *isl_pw_aff_order_map_aligned(
2985 : __isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2,
2986 : __isl_give isl_set *(*order)(__isl_take isl_pw_aff *pa1,
2987 : __isl_take isl_pw_aff *pa2))
2988 : {
2989 : isl_space *space1, *space2;
2990 : isl_multi_aff *ma;
2991 : isl_set *set;
2992 :
2993 0 : space1 = isl_space_domain(isl_pw_aff_get_space(pa1));
2994 0 : space2 = isl_space_domain(isl_pw_aff_get_space(pa2));
2995 0 : space1 = isl_space_map_from_domain_and_range(space1, space2);
2996 0 : ma = isl_multi_aff_domain_map(isl_space_copy(space1));
2997 0 : pa1 = isl_pw_aff_pullback_multi_aff(pa1, ma);
2998 0 : ma = isl_multi_aff_range_map(space1);
2999 0 : pa2 = isl_pw_aff_pullback_multi_aff(pa2, ma);
3000 0 : set = order(pa1, pa2);
3001 :
3002 0 : return isl_set_unwrap(set);
3003 : }
3004 :
3005 : /* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
3006 : * where the function values are equal.
3007 : * The parameters of "pa1" and "pa2" are assumed to have been aligned.
3008 : */
3009 0 : static __isl_give isl_map *isl_pw_aff_eq_map_aligned(__isl_take isl_pw_aff *pa1,
3010 : __isl_take isl_pw_aff *pa2)
3011 : {
3012 0 : return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_eq_set);
3013 : }
3014 :
3015 : /* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
3016 : * where the function values are equal.
3017 : */
3018 0 : __isl_give isl_map *isl_pw_aff_eq_map(__isl_take isl_pw_aff *pa1,
3019 : __isl_take isl_pw_aff *pa2)
3020 : {
3021 0 : return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_eq_map_aligned);
3022 : }
3023 :
3024 : /* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
3025 : * where the function value of "pa1" is less than the function value of "pa2".
3026 : * The parameters of "pa1" and "pa2" are assumed to have been aligned.
3027 : */
3028 0 : static __isl_give isl_map *isl_pw_aff_lt_map_aligned(__isl_take isl_pw_aff *pa1,
3029 : __isl_take isl_pw_aff *pa2)
3030 : {
3031 0 : return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_lt_set);
3032 : }
3033 :
3034 : /* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
3035 : * where the function value of "pa1" is less than the function value of "pa2".
3036 : */
3037 0 : __isl_give isl_map *isl_pw_aff_lt_map(__isl_take isl_pw_aff *pa1,
3038 : __isl_take isl_pw_aff *pa2)
3039 : {
3040 0 : return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_lt_map_aligned);
3041 : }
3042 :
3043 : /* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
3044 : * where the function value of "pa1" is greater than the function value
3045 : * of "pa2".
3046 : * The parameters of "pa1" and "pa2" are assumed to have been aligned.
3047 : */
3048 0 : static __isl_give isl_map *isl_pw_aff_gt_map_aligned(__isl_take isl_pw_aff *pa1,
3049 : __isl_take isl_pw_aff *pa2)
3050 : {
3051 0 : return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_gt_set);
3052 : }
3053 :
3054 : /* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
3055 : * where the function value of "pa1" is greater than the function value
3056 : * of "pa2".
3057 : */
3058 0 : __isl_give isl_map *isl_pw_aff_gt_map(__isl_take isl_pw_aff *pa1,
3059 : __isl_take isl_pw_aff *pa2)
3060 : {
3061 0 : return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_gt_map_aligned);
3062 : }
3063 :
3064 : /* Return a set containing those elements in the shared domain
3065 : * of the elements of list1 and list2 where each element in list1
3066 : * has the relation specified by "fn" with each element in list2.
3067 : */
3068 0 : static __isl_give isl_set *pw_aff_list_set(__isl_take isl_pw_aff_list *list1,
3069 : __isl_take isl_pw_aff_list *list2,
3070 : __isl_give isl_set *(*fn)(__isl_take isl_pw_aff *pwaff1,
3071 : __isl_take isl_pw_aff *pwaff2))
3072 : {
3073 : int i, j;
3074 : isl_ctx *ctx;
3075 : isl_set *set;
3076 :
3077 0 : if (!list1 || !list2)
3078 : goto error;
3079 :
3080 0 : ctx = isl_pw_aff_list_get_ctx(list1);
3081 0 : if (list1->n < 1 || list2->n < 1)
3082 0 : isl_die(ctx, isl_error_invalid,
3083 : "list should contain at least one element", goto error);
3084 :
3085 0 : set = isl_set_universe(isl_pw_aff_get_domain_space(list1->p[0]));
3086 0 : for (i = 0; i < list1->n; ++i)
3087 0 : for (j = 0; j < list2->n; ++j) {
3088 : isl_set *set_ij;
3089 :
3090 0 : set_ij = fn(isl_pw_aff_copy(list1->p[i]),
3091 0 : isl_pw_aff_copy(list2->p[j]));
3092 0 : set = isl_set_intersect(set, set_ij);
3093 : }
3094 :
3095 0 : isl_pw_aff_list_free(list1);
3096 0 : isl_pw_aff_list_free(list2);
3097 0 : return set;
3098 : error:
3099 0 : isl_pw_aff_list_free(list1);
3100 0 : isl_pw_aff_list_free(list2);
3101 0 : return NULL;
3102 : }
3103 :
3104 : /* Return a set containing those elements in the shared domain
3105 : * of the elements of list1 and list2 where each element in list1
3106 : * is equal to each element in list2.
3107 : */
3108 0 : __isl_give isl_set *isl_pw_aff_list_eq_set(__isl_take isl_pw_aff_list *list1,
3109 : __isl_take isl_pw_aff_list *list2)
3110 : {
3111 0 : return pw_aff_list_set(list1, list2, &isl_pw_aff_eq_set);
3112 : }
3113 :
3114 0 : __isl_give isl_set *isl_pw_aff_list_ne_set(__isl_take isl_pw_aff_list *list1,
3115 : __isl_take isl_pw_aff_list *list2)
3116 : {
3117 0 : return pw_aff_list_set(list1, list2, &isl_pw_aff_ne_set);
3118 : }
3119 :
3120 : /* Return a set containing those elements in the shared domain
3121 : * of the elements of list1 and list2 where each element in list1
3122 : * is less than or equal to each element in list2.
3123 : */
3124 0 : __isl_give isl_set *isl_pw_aff_list_le_set(__isl_take isl_pw_aff_list *list1,
3125 : __isl_take isl_pw_aff_list *list2)
3126 : {
3127 0 : return pw_aff_list_set(list1, list2, &isl_pw_aff_le_set);
3128 : }
3129 :
3130 0 : __isl_give isl_set *isl_pw_aff_list_lt_set(__isl_take isl_pw_aff_list *list1,
3131 : __isl_take isl_pw_aff_list *list2)
3132 : {
3133 0 : return pw_aff_list_set(list1, list2, &isl_pw_aff_lt_set);
3134 : }
3135 :
3136 0 : __isl_give isl_set *isl_pw_aff_list_ge_set(__isl_take isl_pw_aff_list *list1,
3137 : __isl_take isl_pw_aff_list *list2)
3138 : {
3139 0 : return pw_aff_list_set(list1, list2, &isl_pw_aff_ge_set);
3140 : }
3141 :
3142 0 : __isl_give isl_set *isl_pw_aff_list_gt_set(__isl_take isl_pw_aff_list *list1,
3143 : __isl_take isl_pw_aff_list *list2)
3144 : {
3145 0 : return pw_aff_list_set(list1, list2, &isl_pw_aff_gt_set);
3146 : }
3147 :
3148 :
3149 : /* Return a set containing those elements in the shared domain
3150 : * of pwaff1 and pwaff2 where pwaff1 is not equal to pwaff2.
3151 : */
3152 0 : static __isl_give isl_set *pw_aff_ne_set(__isl_take isl_pw_aff *pwaff1,
3153 : __isl_take isl_pw_aff *pwaff2)
3154 : {
3155 : isl_set *set_lt, *set_gt;
3156 :
3157 0 : set_lt = isl_pw_aff_lt_set(isl_pw_aff_copy(pwaff1),
3158 : isl_pw_aff_copy(pwaff2));
3159 0 : set_gt = isl_pw_aff_gt_set(pwaff1, pwaff2);
3160 0 : return isl_set_union_disjoint(set_lt, set_gt);
3161 : }
3162 :
3163 0 : __isl_give isl_set *isl_pw_aff_ne_set(__isl_take isl_pw_aff *pwaff1,
3164 : __isl_take isl_pw_aff *pwaff2)
3165 : {
3166 0 : return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_ne_set);
3167 : }
3168 :
3169 0 : __isl_give isl_pw_aff *isl_pw_aff_scale_down(__isl_take isl_pw_aff *pwaff,
3170 : isl_int v)
3171 : {
3172 : int i;
3173 :
3174 0 : if (isl_int_is_one(v))
3175 0 : return pwaff;
3176 0 : if (!isl_int_is_pos(v))
3177 0 : isl_die(isl_pw_aff_get_ctx(pwaff), isl_error_invalid,
3178 : "factor needs to be positive",
3179 : return isl_pw_aff_free(pwaff));
3180 0 : pwaff = isl_pw_aff_cow(pwaff);
3181 0 : if (!pwaff)
3182 0 : return NULL;
3183 0 : if (pwaff->n == 0)
3184 0 : return pwaff;
3185 :
3186 0 : for (i = 0; i < pwaff->n; ++i) {
3187 0 : pwaff->p[i].aff = isl_aff_scale_down(pwaff->p[i].aff, v);
3188 0 : if (!pwaff->p[i].aff)
3189 0 : return isl_pw_aff_free(pwaff);
3190 : }
3191 :
3192 0 : return pwaff;
3193 : }
3194 :
3195 0 : __isl_give isl_pw_aff *isl_pw_aff_floor(__isl_take isl_pw_aff *pwaff)
3196 : {
3197 : int i;
3198 :
3199 0 : pwaff = isl_pw_aff_cow(pwaff);
3200 0 : if (!pwaff)
3201 0 : return NULL;
3202 0 : if (pwaff->n == 0)
3203 0 : return pwaff;
3204 :
3205 0 : for (i = 0; i < pwaff->n; ++i) {
3206 0 : pwaff->p[i].aff = isl_aff_floor(pwaff->p[i].aff);
3207 0 : if (!pwaff->p[i].aff)
3208 0 : return isl_pw_aff_free(pwaff);
3209 : }
3210 :
3211 0 : return pwaff;
3212 : }
3213 :
3214 0 : __isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff)
3215 : {
3216 : int i;
3217 :
3218 0 : pwaff = isl_pw_aff_cow(pwaff);
3219 0 : if (!pwaff)
3220 0 : return NULL;
3221 0 : if (pwaff->n == 0)
3222 0 : return pwaff;
3223 :
3224 0 : for (i = 0; i < pwaff->n; ++i) {
3225 0 : pwaff->p[i].aff = isl_aff_ceil(pwaff->p[i].aff);
3226 0 : if (!pwaff->p[i].aff)
3227 0 : return isl_pw_aff_free(pwaff);
3228 : }
3229 :
3230 0 : return pwaff;
3231 : }
3232 :
3233 : /* Assuming that "cond1" and "cond2" are disjoint,
3234 : * return an affine expression that is equal to pwaff1 on cond1
3235 : * and to pwaff2 on cond2.
3236 : */
3237 0 : static __isl_give isl_pw_aff *isl_pw_aff_select(
3238 : __isl_take isl_set *cond1, __isl_take isl_pw_aff *pwaff1,
3239 : __isl_take isl_set *cond2, __isl_take isl_pw_aff *pwaff2)
3240 : {
3241 0 : pwaff1 = isl_pw_aff_intersect_domain(pwaff1, cond1);
3242 0 : pwaff2 = isl_pw_aff_intersect_domain(pwaff2, cond2);
3243 :
3244 0 : return isl_pw_aff_add_disjoint(pwaff1, pwaff2);
3245 : }
3246 :
3247 : /* Return an affine expression that is equal to pwaff_true for elements
3248 : * where "cond" is non-zero and to pwaff_false for elements where "cond"
3249 : * is zero.
3250 : * That is, return cond ? pwaff_true : pwaff_false;
3251 : *
3252 : * If "cond" involves and NaN, then we conservatively return a NaN
3253 : * on its entire domain. In principle, we could consider the pieces
3254 : * where it is NaN separately from those where it is not.
3255 : *
3256 : * If "pwaff_true" and "pwaff_false" are obviously equal to each other,
3257 : * then only use the domain of "cond" to restrict the domain.
3258 : */
3259 0 : __isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_pw_aff *cond,
3260 : __isl_take isl_pw_aff *pwaff_true, __isl_take isl_pw_aff *pwaff_false)
3261 : {
3262 : isl_set *cond_true, *cond_false;
3263 : isl_bool equal;
3264 :
3265 0 : if (!cond)
3266 0 : goto error;
3267 0 : if (isl_pw_aff_involves_nan(cond)) {
3268 0 : isl_space *space = isl_pw_aff_get_domain_space(cond);
3269 0 : isl_local_space *ls = isl_local_space_from_space(space);
3270 0 : isl_pw_aff_free(cond);
3271 0 : isl_pw_aff_free(pwaff_true);
3272 0 : isl_pw_aff_free(pwaff_false);
3273 0 : return isl_pw_aff_nan_on_domain(ls);
3274 : }
3275 :
3276 0 : pwaff_true = isl_pw_aff_align_params(pwaff_true,
3277 : isl_pw_aff_get_space(pwaff_false));
3278 0 : pwaff_false = isl_pw_aff_align_params(pwaff_false,
3279 : isl_pw_aff_get_space(pwaff_true));
3280 0 : equal = isl_pw_aff_plain_is_equal(pwaff_true, pwaff_false);
3281 0 : if (equal < 0)
3282 0 : goto error;
3283 0 : if (equal) {
3284 : isl_set *dom;
3285 :
3286 0 : dom = isl_set_coalesce(isl_pw_aff_domain(cond));
3287 0 : isl_pw_aff_free(pwaff_false);
3288 0 : return isl_pw_aff_intersect_domain(pwaff_true, dom);
3289 : }
3290 :
3291 0 : cond_true = isl_pw_aff_non_zero_set(isl_pw_aff_copy(cond));
3292 0 : cond_false = isl_pw_aff_zero_set(cond);
3293 0 : return isl_pw_aff_select(cond_true, pwaff_true,
3294 : cond_false, pwaff_false);
3295 : error:
3296 0 : isl_pw_aff_free(cond);
3297 0 : isl_pw_aff_free(pwaff_true);
3298 0 : isl_pw_aff_free(pwaff_false);
3299 0 : return NULL;
3300 : }
3301 :
3302 0 : isl_bool isl_aff_is_cst(__isl_keep isl_aff *aff)
3303 : {
3304 0 : if (!aff)
3305 0 : return isl_bool_error;
3306 :
3307 0 : return isl_seq_first_non_zero(aff->v->el + 2, aff->v->size - 2) == -1;
3308 : }
3309 :
3310 : /* Check whether pwaff is a piecewise constant.
3311 : */
3312 0 : isl_bool isl_pw_aff_is_cst(__isl_keep isl_pw_aff *pwaff)
3313 : {
3314 : int i;
3315 :
3316 0 : if (!pwaff)
3317 0 : return isl_bool_error;
3318 :
3319 0 : for (i = 0; i < pwaff->n; ++i) {
3320 0 : isl_bool is_cst = isl_aff_is_cst(pwaff->p[i].aff);
3321 0 : if (is_cst < 0 || !is_cst)
3322 0 : return is_cst;
3323 : }
3324 :
3325 0 : return isl_bool_true;
3326 : }
3327 :
3328 : /* Are all elements of "mpa" piecewise constants?
3329 : */
3330 0 : isl_bool isl_multi_pw_aff_is_cst(__isl_keep isl_multi_pw_aff *mpa)
3331 : {
3332 : int i;
3333 :
3334 0 : if (!mpa)
3335 0 : return isl_bool_error;
3336 :
3337 0 : for (i = 0; i < mpa->n; ++i) {
3338 0 : isl_bool is_cst = isl_pw_aff_is_cst(mpa->u.p[i]);
3339 0 : if (is_cst < 0 || !is_cst)
3340 0 : return is_cst;
3341 : }
3342 :
3343 0 : return isl_bool_true;
3344 : }
3345 :
3346 : /* Return the product of "aff1" and "aff2".
3347 : *
3348 : * If either of the two is NaN, then the result is NaN.
3349 : *
3350 : * Otherwise, at least one of "aff1" or "aff2" needs to be a constant.
3351 : */
3352 0 : __isl_give isl_aff *isl_aff_mul(__isl_take isl_aff *aff1,
3353 : __isl_take isl_aff *aff2)
3354 : {
3355 0 : if (!aff1 || !aff2)
3356 : goto error;
3357 :
3358 0 : if (isl_aff_is_nan(aff1)) {
3359 0 : isl_aff_free(aff2);
3360 0 : return aff1;
3361 : }
3362 0 : if (isl_aff_is_nan(aff2)) {
3363 0 : isl_aff_free(aff1);
3364 0 : return aff2;
3365 : }
3366 :
3367 0 : if (!isl_aff_is_cst(aff2) && isl_aff_is_cst(aff1))
3368 0 : return isl_aff_mul(aff2, aff1);
3369 :
3370 0 : if (!isl_aff_is_cst(aff2))
3371 0 : isl_die(isl_aff_get_ctx(aff1), isl_error_invalid,
3372 : "at least one affine expression should be constant",
3373 : goto error);
3374 :
3375 0 : aff1 = isl_aff_cow(aff1);
3376 0 : if (!aff1 || !aff2)
3377 : goto error;
3378 :
3379 0 : aff1 = isl_aff_scale(aff1, aff2->v->el[1]);
3380 0 : aff1 = isl_aff_scale_down(aff1, aff2->v->el[0]);
3381 :
3382 0 : isl_aff_free(aff2);
3383 0 : return aff1;
3384 : error:
3385 0 : isl_aff_free(aff1);
3386 0 : isl_aff_free(aff2);
3387 0 : return NULL;
3388 : }
3389 :
3390 : /* Divide "aff1" by "aff2", assuming "aff2" is a constant.
3391 : *
3392 : * If either of the two is NaN, then the result is NaN.
3393 : */
3394 0 : __isl_give isl_aff *isl_aff_div(__isl_take isl_aff *aff1,
3395 : __isl_take isl_aff *aff2)
3396 : {
3397 : int is_cst;
3398 : int neg;
3399 :
3400 0 : if (!aff1 || !aff2)
3401 : goto error;
3402 :
3403 0 : if (isl_aff_is_nan(aff1)) {
3404 0 : isl_aff_free(aff2);
3405 0 : return aff1;
3406 : }
3407 0 : if (isl_aff_is_nan(aff2)) {
3408 0 : isl_aff_free(aff1);
3409 0 : return aff2;
3410 : }
3411 :
3412 0 : is_cst = isl_aff_is_cst(aff2);
3413 0 : if (is_cst < 0)
3414 0 : goto error;
3415 0 : if (!is_cst)
3416 0 : isl_die(isl_aff_get_ctx(aff2), isl_error_invalid,
3417 : "second argument should be a constant", goto error);
3418 :
3419 0 : if (!aff2)
3420 0 : goto error;
3421 :
3422 0 : neg = isl_int_is_neg(aff2->v->el[1]);
3423 0 : if (neg) {
3424 0 : isl_int_neg(aff2->v->el[0], aff2->v->el[0]);
3425 0 : isl_int_neg(aff2->v->el[1], aff2->v->el[1]);
3426 : }
3427 :
3428 0 : aff1 = isl_aff_scale(aff1, aff2->v->el[0]);
3429 0 : aff1 = isl_aff_scale_down(aff1, aff2->v->el[1]);
3430 :
3431 0 : if (neg) {
3432 0 : isl_int_neg(aff2->v->el[0], aff2->v->el[0]);
3433 0 : isl_int_neg(aff2->v->el[1], aff2->v->el[1]);
3434 : }
3435 :
3436 0 : isl_aff_free(aff2);
3437 0 : return aff1;
3438 : error:
3439 0 : isl_aff_free(aff1);
3440 0 : isl_aff_free(aff2);
3441 0 : return NULL;
3442 : }
3443 :
3444 0 : static __isl_give isl_pw_aff *pw_aff_add(__isl_take isl_pw_aff *pwaff1,
3445 : __isl_take isl_pw_aff *pwaff2)
3446 : {
3447 0 : return isl_pw_aff_on_shared_domain(pwaff1, pwaff2, &isl_aff_add);
3448 : }
3449 :
3450 0 : __isl_give isl_pw_aff *isl_pw_aff_add(__isl_take isl_pw_aff *pwaff1,
3451 : __isl_take isl_pw_aff *pwaff2)
3452 : {
3453 0 : return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2, &pw_aff_add);
3454 : }
3455 :
3456 0 : __isl_give isl_pw_aff *isl_pw_aff_union_add(__isl_take isl_pw_aff *pwaff1,
3457 : __isl_take isl_pw_aff *pwaff2)
3458 : {
3459 0 : return isl_pw_aff_union_add_(pwaff1, pwaff2);
3460 : }
3461 :
3462 0 : static __isl_give isl_pw_aff *pw_aff_mul(__isl_take isl_pw_aff *pwaff1,
3463 : __isl_take isl_pw_aff *pwaff2)
3464 : {
3465 0 : return isl_pw_aff_on_shared_domain(pwaff1, pwaff2, &isl_aff_mul);
3466 : }
3467 :
3468 0 : __isl_give isl_pw_aff *isl_pw_aff_mul(__isl_take isl_pw_aff *pwaff1,
3469 : __isl_take isl_pw_aff *pwaff2)
3470 : {
3471 0 : return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2, &pw_aff_mul);
3472 : }
3473 :
3474 0 : static __isl_give isl_pw_aff *pw_aff_div(__isl_take isl_pw_aff *pa1,
3475 : __isl_take isl_pw_aff *pa2)
3476 : {
3477 0 : return isl_pw_aff_on_shared_domain(pa1, pa2, &isl_aff_div);
3478 : }
3479 :
3480 : /* Divide "pa1" by "pa2", assuming "pa2" is a piecewise constant.
3481 : */
3482 0 : __isl_give isl_pw_aff *isl_pw_aff_div(__isl_take isl_pw_aff *pa1,
3483 : __isl_take isl_pw_aff *pa2)
3484 : {
3485 : int is_cst;
3486 :
3487 0 : is_cst = isl_pw_aff_is_cst(pa2);
3488 0 : if (is_cst < 0)
3489 0 : goto error;
3490 0 : if (!is_cst)
3491 0 : isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid,
3492 : "second argument should be a piecewise constant",
3493 : goto error);
3494 0 : return isl_pw_aff_align_params_pw_pw_and(pa1, pa2, &pw_aff_div);
3495 : error:
3496 0 : isl_pw_aff_free(pa1);
3497 0 : isl_pw_aff_free(pa2);
3498 0 : return NULL;
3499 : }
3500 :
3501 : /* Compute the quotient of the integer division of "pa1" by "pa2"
3502 : * with rounding towards zero.
3503 : * "pa2" is assumed to be a piecewise constant.
3504 : *
3505 : * In particular, return
3506 : *
3507 : * pa1 >= 0 ? floor(pa1/pa2) : ceil(pa1/pa2)
3508 : *
3509 : */
3510 0 : __isl_give isl_pw_aff *isl_pw_aff_tdiv_q(__isl_take isl_pw_aff *pa1,
3511 : __isl_take isl_pw_aff *pa2)
3512 : {
3513 : int is_cst;
3514 : isl_set *cond;
3515 : isl_pw_aff *f, *c;
3516 :
3517 0 : is_cst = isl_pw_aff_is_cst(pa2);
3518 0 : if (is_cst < 0)
3519 0 : goto error;
3520 0 : if (!is_cst)
3521 0 : isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid,
3522 : "second argument should be a piecewise constant",
3523 : goto error);
3524 :
3525 0 : pa1 = isl_pw_aff_div(pa1, pa2);
3526 :
3527 0 : cond = isl_pw_aff_nonneg_set(isl_pw_aff_copy(pa1));
3528 0 : f = isl_pw_aff_floor(isl_pw_aff_copy(pa1));
3529 0 : c = isl_pw_aff_ceil(pa1);
3530 0 : return isl_pw_aff_cond(isl_set_indicator_function(cond), f, c);
3531 : error:
3532 0 : isl_pw_aff_free(pa1);
3533 0 : isl_pw_aff_free(pa2);
3534 0 : return NULL;
3535 : }
3536 :
3537 : /* Compute the remainder of the integer division of "pa1" by "pa2"
3538 : * with rounding towards zero.
3539 : * "pa2" is assumed to be a piecewise constant.
3540 : *
3541 : * In particular, return
3542 : *
3543 : * pa1 - pa2 * (pa1 >= 0 ? floor(pa1/pa2) : ceil(pa1/pa2))
3544 : *
3545 : */
3546 0 : __isl_give isl_pw_aff *isl_pw_aff_tdiv_r(__isl_take isl_pw_aff *pa1,
3547 : __isl_take isl_pw_aff *pa2)
3548 : {
3549 : int is_cst;
3550 : isl_pw_aff *res;
3551 :
3552 0 : is_cst = isl_pw_aff_is_cst(pa2);
3553 0 : if (is_cst < 0)
3554 0 : goto error;
3555 0 : if (!is_cst)
3556 0 : isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid,
3557 : "second argument should be a piecewise constant",
3558 : goto error);
3559 0 : res = isl_pw_aff_tdiv_q(isl_pw_aff_copy(pa1), isl_pw_aff_copy(pa2));
3560 0 : res = isl_pw_aff_mul(pa2, res);
3561 0 : res = isl_pw_aff_sub(pa1, res);
3562 0 : return res;
3563 : error:
3564 0 : isl_pw_aff_free(pa1);
3565 0 : isl_pw_aff_free(pa2);
3566 0 : return NULL;
3567 : }
3568 :
3569 : /* Does either of "pa1" or "pa2" involve any NaN2?
3570 : */
3571 0 : static isl_bool either_involves_nan(__isl_keep isl_pw_aff *pa1,
3572 : __isl_keep isl_pw_aff *pa2)
3573 : {
3574 : isl_bool has_nan;
3575 :
3576 0 : has_nan = isl_pw_aff_involves_nan(pa1);
3577 0 : if (has_nan < 0 || has_nan)
3578 0 : return has_nan;
3579 0 : return isl_pw_aff_involves_nan(pa2);
3580 : }
3581 :
3582 : /* Replace "pa1" and "pa2" (at least one of which involves a NaN)
3583 : * by a NaN on their shared domain.
3584 : *
3585 : * In principle, the result could be refined to only being NaN
3586 : * on the parts of this domain where at least one of "pa1" or "pa2" is NaN.
3587 : */
3588 0 : static __isl_give isl_pw_aff *replace_by_nan(__isl_take isl_pw_aff *pa1,
3589 : __isl_take isl_pw_aff *pa2)
3590 : {
3591 : isl_local_space *ls;
3592 : isl_set *dom;
3593 : isl_pw_aff *pa;
3594 :
3595 0 : dom = isl_set_intersect(isl_pw_aff_domain(pa1), isl_pw_aff_domain(pa2));
3596 0 : ls = isl_local_space_from_space(isl_set_get_space(dom));
3597 0 : pa = isl_pw_aff_nan_on_domain(ls);
3598 0 : pa = isl_pw_aff_intersect_domain(pa, dom);
3599 :
3600 0 : return pa;
3601 : }
3602 :
3603 0 : static __isl_give isl_pw_aff *pw_aff_min(__isl_take isl_pw_aff *pwaff1,
3604 : __isl_take isl_pw_aff *pwaff2)
3605 : {
3606 : isl_set *le;
3607 : isl_set *dom;
3608 :
3609 0 : dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)),
3610 : isl_pw_aff_domain(isl_pw_aff_copy(pwaff2)));
3611 0 : le = isl_pw_aff_le_set(isl_pw_aff_copy(pwaff1),
3612 : isl_pw_aff_copy(pwaff2));
3613 0 : dom = isl_set_subtract(dom, isl_set_copy(le));
3614 0 : return isl_pw_aff_select(le, pwaff1, dom, pwaff2);
3615 : }
3616 :
3617 0 : static __isl_give isl_pw_aff *pw_aff_max(__isl_take isl_pw_aff *pwaff1,
3618 : __isl_take isl_pw_aff *pwaff2)
3619 : {
3620 : isl_set *ge;
3621 : isl_set *dom;
3622 :
3623 0 : dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)),
3624 : isl_pw_aff_domain(isl_pw_aff_copy(pwaff2)));
3625 0 : ge = isl_pw_aff_ge_set(isl_pw_aff_copy(pwaff1),
3626 : isl_pw_aff_copy(pwaff2));
3627 0 : dom = isl_set_subtract(dom, isl_set_copy(ge));
3628 0 : return isl_pw_aff_select(ge, pwaff1, dom, pwaff2);
3629 : }
3630 :
3631 : /* Return an expression for the minimum (if "max" is not set) or
3632 : * the maximum (if "max" is set) of "pa1" and "pa2".
3633 : * If either expression involves any NaN, then return a NaN
3634 : * on the shared domain as result.
3635 : */
3636 0 : static __isl_give isl_pw_aff *pw_aff_min_max(__isl_take isl_pw_aff *pa1,
3637 : __isl_take isl_pw_aff *pa2, int max)
3638 : {
3639 : isl_bool has_nan;
3640 :
3641 0 : has_nan = either_involves_nan(pa1, pa2);
3642 0 : if (has_nan < 0)
3643 0 : pa1 = isl_pw_aff_free(pa1);
3644 0 : else if (has_nan)
3645 0 : return replace_by_nan(pa1, pa2);
3646 :
3647 0 : if (max)
3648 0 : return isl_pw_aff_align_params_pw_pw_and(pa1, pa2, &pw_aff_max);
3649 : else
3650 0 : return isl_pw_aff_align_params_pw_pw_and(pa1, pa2, &pw_aff_min);
3651 : }
3652 :
3653 : /* Return an expression for the minimum of "pwaff1" and "pwaff2".
3654 : */
3655 0 : __isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1,
3656 : __isl_take isl_pw_aff *pwaff2)
3657 : {
3658 0 : return pw_aff_min_max(pwaff1, pwaff2, 0);
3659 : }
3660 :
3661 : /* Return an expression for the maximum of "pwaff1" and "pwaff2".
3662 : */
3663 0 : __isl_give isl_pw_aff *isl_pw_aff_max(__isl_take isl_pw_aff *pwaff1,
3664 : __isl_take isl_pw_aff *pwaff2)
3665 : {
3666 0 : return pw_aff_min_max(pwaff1, pwaff2, 1);
3667 : }
3668 :
3669 0 : static __isl_give isl_pw_aff *pw_aff_list_reduce(
3670 : __isl_take isl_pw_aff_list *list,
3671 : __isl_give isl_pw_aff *(*fn)(__isl_take isl_pw_aff *pwaff1,
3672 : __isl_take isl_pw_aff *pwaff2))
3673 : {
3674 : int i;
3675 : isl_ctx *ctx;
3676 : isl_pw_aff *res;
3677 :
3678 0 : if (!list)
3679 0 : return NULL;
3680 :
3681 0 : ctx = isl_pw_aff_list_get_ctx(list);
3682 0 : if (list->n < 1)
3683 0 : isl_die(ctx, isl_error_invalid,
3684 : "list should contain at least one element", goto error);
3685 :
3686 0 : res = isl_pw_aff_copy(list->p[0]);
3687 0 : for (i = 1; i < list->n; ++i)
3688 0 : res = fn(res, isl_pw_aff_copy(list->p[i]));
3689 :
3690 0 : isl_pw_aff_list_free(list);
3691 0 : return res;
3692 : error:
3693 0 : isl_pw_aff_list_free(list);
3694 0 : return NULL;
3695 : }
3696 :
3697 : /* Return an isl_pw_aff that maps each element in the intersection of the
3698 : * domains of the elements of list to the minimal corresponding affine
3699 : * expression.
3700 : */
3701 0 : __isl_give isl_pw_aff *isl_pw_aff_list_min(__isl_take isl_pw_aff_list *list)
3702 : {
3703 0 : return pw_aff_list_reduce(list, &isl_pw_aff_min);
3704 : }
3705 :
3706 : /* Return an isl_pw_aff that maps each element in the intersection of the
3707 : * domains of the elements of list to the maximal corresponding affine
3708 : * expression.
3709 : */
3710 0 : __isl_give isl_pw_aff *isl_pw_aff_list_max(__isl_take isl_pw_aff_list *list)
3711 : {
3712 0 : return pw_aff_list_reduce(list, &isl_pw_aff_max);
3713 : }
3714 :
3715 : /* Mark the domains of "pwaff" as rational.
3716 : */
3717 0 : __isl_give isl_pw_aff *isl_pw_aff_set_rational(__isl_take isl_pw_aff *pwaff)
3718 : {
3719 : int i;
3720 :
3721 0 : pwaff = isl_pw_aff_cow(pwaff);
3722 0 : if (!pwaff)
3723 0 : return NULL;
3724 0 : if (pwaff->n == 0)
3725 0 : return pwaff;
3726 :
3727 0 : for (i = 0; i < pwaff->n; ++i) {
3728 0 : pwaff->p[i].set = isl_set_set_rational(pwaff->p[i].set);
3729 0 : if (!pwaff->p[i].set)
3730 0 : return isl_pw_aff_free(pwaff);
3731 : }
3732 :
3733 0 : return pwaff;
3734 : }
3735 :
3736 : /* Mark the domains of the elements of "list" as rational.
3737 : */
3738 0 : __isl_give isl_pw_aff_list *isl_pw_aff_list_set_rational(
3739 : __isl_take isl_pw_aff_list *list)
3740 : {
3741 : int i, n;
3742 :
3743 0 : if (!list)
3744 0 : return NULL;
3745 0 : if (list->n == 0)
3746 0 : return list;
3747 :
3748 0 : n = list->n;
3749 0 : for (i = 0; i < n; ++i) {
3750 : isl_pw_aff *pa;
3751 :
3752 0 : pa = isl_pw_aff_list_get_pw_aff(list, i);
3753 0 : pa = isl_pw_aff_set_rational(pa);
3754 0 : list = isl_pw_aff_list_set_pw_aff(list, i, pa);
3755 : }
3756 :
3757 0 : return list;
3758 : }
3759 :
3760 : /* Do the parameters of "aff" match those of "space"?
3761 : */
3762 0 : isl_bool isl_aff_matching_params(__isl_keep isl_aff *aff,
3763 : __isl_keep isl_space *space)
3764 : {
3765 : isl_space *aff_space;
3766 : isl_bool match;
3767 :
3768 0 : if (!aff || !space)
3769 0 : return isl_bool_error;
3770 :
3771 0 : aff_space = isl_aff_get_domain_space(aff);
3772 :
3773 0 : match = isl_space_has_equal_params(space, aff_space);
3774 :
3775 0 : isl_space_free(aff_space);
3776 0 : return match;
3777 : }
3778 :
3779 : /* Check that the domain space of "aff" matches "space".
3780 : */
3781 0 : isl_stat isl_aff_check_match_domain_space(__isl_keep isl_aff *aff,
3782 : __isl_keep isl_space *space)
3783 : {
3784 : isl_space *aff_space;
3785 : isl_bool match;
3786 :
3787 0 : if (!aff || !space)
3788 0 : return isl_stat_error;
3789 :
3790 0 : aff_space = isl_aff_get_domain_space(aff);
3791 :
3792 0 : match = isl_space_has_equal_params(space, aff_space);
3793 0 : if (match < 0)
3794 0 : goto error;
3795 0 : if (!match)
3796 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
3797 : "parameters don't match", goto error);
3798 0 : match = isl_space_tuple_is_equal(space, isl_dim_in,
3799 : aff_space, isl_dim_set);
3800 0 : if (match < 0)
3801 0 : goto error;
3802 0 : if (!match)
3803 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
3804 : "domains don't match", goto error);
3805 0 : isl_space_free(aff_space);
3806 0 : return isl_stat_ok;
3807 : error:
3808 0 : isl_space_free(aff_space);
3809 0 : return isl_stat_error;
3810 : }
3811 :
3812 : #undef BASE
3813 : #define BASE aff
3814 : #undef DOMBASE
3815 : #define DOMBASE set
3816 : #define NO_DOMAIN
3817 :
3818 : #include <isl_multi_no_explicit_domain.c>
3819 : #include <isl_multi_templ.c>
3820 : #include <isl_multi_apply_set.c>
3821 : #include <isl_multi_cmp.c>
3822 : #include <isl_multi_dims.c>
3823 : #include <isl_multi_floor.c>
3824 : #include <isl_multi_gist.c>
3825 :
3826 : #undef NO_DOMAIN
3827 :
3828 : /* Construct an isl_multi_aff living in "space" that corresponds
3829 : * to the affine transformation matrix "mat".
3830 : */
3831 0 : __isl_give isl_multi_aff *isl_multi_aff_from_aff_mat(
3832 : __isl_take isl_space *space, __isl_take isl_mat *mat)
3833 : {
3834 : isl_ctx *ctx;
3835 0 : isl_local_space *ls = NULL;
3836 0 : isl_multi_aff *ma = NULL;
3837 : int n_row, n_col, n_out, total;
3838 : int i;
3839 :
3840 0 : if (!space || !mat)
3841 : goto error;
3842 :
3843 0 : ctx = isl_mat_get_ctx(mat);
3844 :
3845 0 : n_row = isl_mat_rows(mat);
3846 0 : n_col = isl_mat_cols(mat);
3847 0 : if (n_row < 1)
3848 0 : isl_die(ctx, isl_error_invalid,
3849 : "insufficient number of rows", goto error);
3850 0 : if (n_col < 1)
3851 0 : isl_die(ctx, isl_error_invalid,
3852 : "insufficient number of columns", goto error);
3853 0 : n_out = isl_space_dim(space, isl_dim_out);
3854 0 : total = isl_space_dim(space, isl_dim_all);
3855 0 : if (1 + n_out != n_row || 2 + total != n_row + n_col)
3856 0 : isl_die(ctx, isl_error_invalid,
3857 : "dimension mismatch", goto error);
3858 :
3859 0 : ma = isl_multi_aff_zero(isl_space_copy(space));
3860 0 : ls = isl_local_space_from_space(isl_space_domain(space));
3861 :
3862 0 : for (i = 0; i < n_row - 1; ++i) {
3863 : isl_vec *v;
3864 : isl_aff *aff;
3865 :
3866 0 : v = isl_vec_alloc(ctx, 1 + n_col);
3867 0 : if (!v)
3868 0 : goto error;
3869 0 : isl_int_set(v->el[0], mat->row[0][0]);
3870 0 : isl_seq_cpy(v->el + 1, mat->row[1 + i], n_col);
3871 0 : v = isl_vec_normalize(v);
3872 0 : aff = isl_aff_alloc_vec(isl_local_space_copy(ls), v);
3873 0 : ma = isl_multi_aff_set_aff(ma, i, aff);
3874 : }
3875 :
3876 0 : isl_local_space_free(ls);
3877 0 : isl_mat_free(mat);
3878 0 : return ma;
3879 : error:
3880 0 : isl_local_space_free(ls);
3881 0 : isl_mat_free(mat);
3882 0 : isl_multi_aff_free(ma);
3883 0 : return NULL;
3884 : }
3885 :
3886 : /* Remove any internal structure of the domain of "ma".
3887 : * If there is any such internal structure in the input,
3888 : * then the name of the corresponding space is also removed.
3889 : */
3890 0 : __isl_give isl_multi_aff *isl_multi_aff_flatten_domain(
3891 : __isl_take isl_multi_aff *ma)
3892 : {
3893 : isl_space *space;
3894 :
3895 0 : if (!ma)
3896 0 : return NULL;
3897 :
3898 0 : if (!ma->space->nested[0])
3899 0 : return ma;
3900 :
3901 0 : space = isl_multi_aff_get_space(ma);
3902 0 : space = isl_space_flatten_domain(space);
3903 0 : ma = isl_multi_aff_reset_space(ma, space);
3904 :
3905 0 : return ma;
3906 : }
3907 :
3908 : /* Given a map space, return an isl_multi_aff that maps a wrapped copy
3909 : * of the space to its domain.
3910 : */
3911 0 : __isl_give isl_multi_aff *isl_multi_aff_domain_map(__isl_take isl_space *space)
3912 : {
3913 : int i, n_in;
3914 : isl_local_space *ls;
3915 : isl_multi_aff *ma;
3916 :
3917 0 : if (!space)
3918 0 : return NULL;
3919 0 : if (!isl_space_is_map(space))
3920 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
3921 : "not a map space", goto error);
3922 :
3923 0 : n_in = isl_space_dim(space, isl_dim_in);
3924 0 : space = isl_space_domain_map(space);
3925 :
3926 0 : ma = isl_multi_aff_alloc(isl_space_copy(space));
3927 0 : if (n_in == 0) {
3928 0 : isl_space_free(space);
3929 0 : return ma;
3930 : }
3931 :
3932 0 : space = isl_space_domain(space);
3933 0 : ls = isl_local_space_from_space(space);
3934 0 : for (i = 0; i < n_in; ++i) {
3935 : isl_aff *aff;
3936 :
3937 0 : aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
3938 : isl_dim_set, i);
3939 0 : ma = isl_multi_aff_set_aff(ma, i, aff);
3940 : }
3941 0 : isl_local_space_free(ls);
3942 0 : return ma;
3943 : error:
3944 0 : isl_space_free(space);
3945 0 : return NULL;
3946 : }
3947 :
3948 : /* Given a map space, return an isl_multi_aff that maps a wrapped copy
3949 : * of the space to its range.
3950 : */
3951 0 : __isl_give isl_multi_aff *isl_multi_aff_range_map(__isl_take isl_space *space)
3952 : {
3953 : int i, n_in, n_out;
3954 : isl_local_space *ls;
3955 : isl_multi_aff *ma;
3956 :
3957 0 : if (!space)
3958 0 : return NULL;
3959 0 : if (!isl_space_is_map(space))
3960 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
3961 : "not a map space", goto error);
3962 :
3963 0 : n_in = isl_space_dim(space, isl_dim_in);
3964 0 : n_out = isl_space_dim(space, isl_dim_out);
3965 0 : space = isl_space_range_map(space);
3966 :
3967 0 : ma = isl_multi_aff_alloc(isl_space_copy(space));
3968 0 : if (n_out == 0) {
3969 0 : isl_space_free(space);
3970 0 : return ma;
3971 : }
3972 :
3973 0 : space = isl_space_domain(space);
3974 0 : ls = isl_local_space_from_space(space);
3975 0 : for (i = 0; i < n_out; ++i) {
3976 : isl_aff *aff;
3977 :
3978 0 : aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
3979 0 : isl_dim_set, n_in + i);
3980 0 : ma = isl_multi_aff_set_aff(ma, i, aff);
3981 : }
3982 0 : isl_local_space_free(ls);
3983 0 : return ma;
3984 : error:
3985 0 : isl_space_free(space);
3986 0 : return NULL;
3987 : }
3988 :
3989 : /* Given a map space, return an isl_pw_multi_aff that maps a wrapped copy
3990 : * of the space to its range.
3991 : */
3992 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_map(
3993 : __isl_take isl_space *space)
3994 : {
3995 0 : return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_range_map(space));
3996 : }
3997 :
3998 : /* Given the space of a set and a range of set dimensions,
3999 : * construct an isl_multi_aff that projects out those dimensions.
4000 : */
4001 0 : __isl_give isl_multi_aff *isl_multi_aff_project_out_map(
4002 : __isl_take isl_space *space, enum isl_dim_type type,
4003 : unsigned first, unsigned n)
4004 : {
4005 : int i, dim;
4006 : isl_local_space *ls;
4007 : isl_multi_aff *ma;
4008 :
4009 0 : if (!space)
4010 0 : return NULL;
4011 0 : if (!isl_space_is_set(space))
4012 0 : isl_die(isl_space_get_ctx(space), isl_error_unsupported,
4013 : "expecting set space", goto error);
4014 0 : if (type != isl_dim_set)
4015 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
4016 : "only set dimensions can be projected out", goto error);
4017 :
4018 0 : dim = isl_space_dim(space, isl_dim_set);
4019 0 : if (first + n > dim)
4020 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
4021 : "range out of bounds", goto error);
4022 :
4023 0 : space = isl_space_from_domain(space);
4024 0 : space = isl_space_add_dims(space, isl_dim_out, dim - n);
4025 :
4026 0 : if (dim == n)
4027 0 : return isl_multi_aff_alloc(space);
4028 :
4029 0 : ma = isl_multi_aff_alloc(isl_space_copy(space));
4030 0 : space = isl_space_domain(space);
4031 0 : ls = isl_local_space_from_space(space);
4032 :
4033 0 : for (i = 0; i < first; ++i) {
4034 : isl_aff *aff;
4035 :
4036 0 : aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
4037 : isl_dim_set, i);
4038 0 : ma = isl_multi_aff_set_aff(ma, i, aff);
4039 : }
4040 :
4041 0 : for (i = 0; i < dim - (first + n); ++i) {
4042 : isl_aff *aff;
4043 :
4044 0 : aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
4045 0 : isl_dim_set, first + n + i);
4046 0 : ma = isl_multi_aff_set_aff(ma, first + i, aff);
4047 : }
4048 :
4049 0 : isl_local_space_free(ls);
4050 0 : return ma;
4051 : error:
4052 0 : isl_space_free(space);
4053 0 : return NULL;
4054 : }
4055 :
4056 : /* Given the space of a set and a range of set dimensions,
4057 : * construct an isl_pw_multi_aff that projects out those dimensions.
4058 : */
4059 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_out_map(
4060 : __isl_take isl_space *space, enum isl_dim_type type,
4061 : unsigned first, unsigned n)
4062 : {
4063 : isl_multi_aff *ma;
4064 :
4065 0 : ma = isl_multi_aff_project_out_map(space, type, first, n);
4066 0 : return isl_pw_multi_aff_from_multi_aff(ma);
4067 : }
4068 :
4069 : /* Create an isl_pw_multi_aff with the given isl_multi_aff on a universe
4070 : * domain.
4071 : */
4072 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_aff(
4073 : __isl_take isl_multi_aff *ma)
4074 : {
4075 0 : isl_set *dom = isl_set_universe(isl_multi_aff_get_domain_space(ma));
4076 0 : return isl_pw_multi_aff_alloc(dom, ma);
4077 : }
4078 :
4079 : /* Create a piecewise multi-affine expression in the given space that maps each
4080 : * input dimension to the corresponding output dimension.
4081 : */
4082 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity(
4083 : __isl_take isl_space *space)
4084 : {
4085 0 : return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_identity(space));
4086 : }
4087 :
4088 : /* Exploit the equalities in "eq" to simplify the affine expressions.
4089 : */
4090 0 : static __isl_give isl_multi_aff *isl_multi_aff_substitute_equalities(
4091 : __isl_take isl_multi_aff *maff, __isl_take isl_basic_set *eq)
4092 : {
4093 : int i;
4094 :
4095 0 : maff = isl_multi_aff_cow(maff);
4096 0 : if (!maff || !eq)
4097 : goto error;
4098 :
4099 0 : for (i = 0; i < maff->n; ++i) {
4100 0 : maff->u.p[i] = isl_aff_substitute_equalities(maff->u.p[i],
4101 : isl_basic_set_copy(eq));
4102 0 : if (!maff->u.p[i])
4103 0 : goto error;
4104 : }
4105 :
4106 0 : isl_basic_set_free(eq);
4107 0 : return maff;
4108 : error:
4109 0 : isl_basic_set_free(eq);
4110 0 : isl_multi_aff_free(maff);
4111 0 : return NULL;
4112 : }
4113 :
4114 0 : __isl_give isl_multi_aff *isl_multi_aff_scale(__isl_take isl_multi_aff *maff,
4115 : isl_int f)
4116 : {
4117 : int i;
4118 :
4119 0 : maff = isl_multi_aff_cow(maff);
4120 0 : if (!maff)
4121 0 : return NULL;
4122 :
4123 0 : for (i = 0; i < maff->n; ++i) {
4124 0 : maff->u.p[i] = isl_aff_scale(maff->u.p[i], f);
4125 0 : if (!maff->u.p[i])
4126 0 : return isl_multi_aff_free(maff);
4127 : }
4128 :
4129 0 : return maff;
4130 : }
4131 :
4132 0 : __isl_give isl_multi_aff *isl_multi_aff_add_on_domain(__isl_keep isl_set *dom,
4133 : __isl_take isl_multi_aff *maff1, __isl_take isl_multi_aff *maff2)
4134 : {
4135 0 : maff1 = isl_multi_aff_add(maff1, maff2);
4136 0 : maff1 = isl_multi_aff_gist(maff1, isl_set_copy(dom));
4137 0 : return maff1;
4138 : }
4139 :
4140 0 : int isl_multi_aff_is_empty(__isl_keep isl_multi_aff *maff)
4141 : {
4142 0 : if (!maff)
4143 0 : return -1;
4144 :
4145 0 : return 0;
4146 : }
4147 :
4148 : /* Return the set of domain elements where "ma1" is lexicographically
4149 : * smaller than or equal to "ma2".
4150 : */
4151 0 : __isl_give isl_set *isl_multi_aff_lex_le_set(__isl_take isl_multi_aff *ma1,
4152 : __isl_take isl_multi_aff *ma2)
4153 : {
4154 0 : return isl_multi_aff_lex_ge_set(ma2, ma1);
4155 : }
4156 :
4157 : /* Return the set of domain elements where "ma1" is lexicographically
4158 : * smaller than "ma2".
4159 : */
4160 0 : __isl_give isl_set *isl_multi_aff_lex_lt_set(__isl_take isl_multi_aff *ma1,
4161 : __isl_take isl_multi_aff *ma2)
4162 : {
4163 0 : return isl_multi_aff_lex_gt_set(ma2, ma1);
4164 : }
4165 :
4166 : /* Return the set of domain elements where "ma1" and "ma2"
4167 : * satisfy "order".
4168 : */
4169 0 : static __isl_give isl_set *isl_multi_aff_order_set(
4170 : __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2,
4171 : __isl_give isl_map *order(__isl_take isl_space *set_space))
4172 : {
4173 : isl_space *space;
4174 : isl_map *map1, *map2;
4175 : isl_map *map, *ge;
4176 :
4177 0 : map1 = isl_map_from_multi_aff_internal(ma1);
4178 0 : map2 = isl_map_from_multi_aff_internal(ma2);
4179 0 : map = isl_map_range_product(map1, map2);
4180 0 : space = isl_space_range(isl_map_get_space(map));
4181 0 : space = isl_space_domain(isl_space_unwrap(space));
4182 0 : ge = order(space);
4183 0 : map = isl_map_intersect_range(map, isl_map_wrap(ge));
4184 :
4185 0 : return isl_map_domain(map);
4186 : }
4187 :
4188 : /* Return the set of domain elements where "ma1" is lexicographically
4189 : * greater than or equal to "ma2".
4190 : */
4191 0 : __isl_give isl_set *isl_multi_aff_lex_ge_set(__isl_take isl_multi_aff *ma1,
4192 : __isl_take isl_multi_aff *ma2)
4193 : {
4194 0 : return isl_multi_aff_order_set(ma1, ma2, &isl_map_lex_ge);
4195 : }
4196 :
4197 : /* Return the set of domain elements where "ma1" is lexicographically
4198 : * greater than "ma2".
4199 : */
4200 0 : __isl_give isl_set *isl_multi_aff_lex_gt_set(__isl_take isl_multi_aff *ma1,
4201 : __isl_take isl_multi_aff *ma2)
4202 : {
4203 0 : return isl_multi_aff_order_set(ma1, ma2, &isl_map_lex_gt);
4204 : }
4205 :
4206 : #undef PW
4207 : #define PW isl_pw_multi_aff
4208 : #undef EL
4209 : #define EL isl_multi_aff
4210 : #undef EL_IS_ZERO
4211 : #define EL_IS_ZERO is_empty
4212 : #undef ZERO
4213 : #define ZERO empty
4214 : #undef IS_ZERO
4215 : #define IS_ZERO is_empty
4216 : #undef FIELD
4217 : #define FIELD maff
4218 : #undef DEFAULT_IS_ZERO
4219 : #define DEFAULT_IS_ZERO 0
4220 :
4221 : #define NO_SUB
4222 : #define NO_OPT
4223 : #define NO_INSERT_DIMS
4224 : #define NO_LIFT
4225 : #define NO_MORPH
4226 :
4227 : #include <isl_pw_templ.c>
4228 : #include <isl_pw_union_opt.c>
4229 :
4230 : #undef NO_SUB
4231 :
4232 : #undef BASE
4233 : #define BASE pw_multi_aff
4234 :
4235 : #include <isl_union_multi.c>
4236 : #include <isl_union_neg.c>
4237 :
4238 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_union_lexmax(
4239 : __isl_take isl_pw_multi_aff *pma1,
4240 : __isl_take isl_pw_multi_aff *pma2)
4241 : {
4242 0 : return isl_pw_multi_aff_union_opt_cmp(pma1, pma2,
4243 : &isl_multi_aff_lex_ge_set);
4244 : }
4245 :
4246 : /* Given two piecewise multi affine expressions, return a piecewise
4247 : * multi-affine expression defined on the union of the definition domains
4248 : * of the inputs that is equal to the lexicographic maximum of the two
4249 : * inputs on each cell. If only one of the two inputs is defined on
4250 : * a given cell, then it is considered to be the maximum.
4251 : */
4252 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmax(
4253 : __isl_take isl_pw_multi_aff *pma1,
4254 : __isl_take isl_pw_multi_aff *pma2)
4255 : {
4256 0 : return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
4257 : &pw_multi_aff_union_lexmax);
4258 : }
4259 :
4260 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_union_lexmin(
4261 : __isl_take isl_pw_multi_aff *pma1,
4262 : __isl_take isl_pw_multi_aff *pma2)
4263 : {
4264 0 : return isl_pw_multi_aff_union_opt_cmp(pma1, pma2,
4265 : &isl_multi_aff_lex_le_set);
4266 : }
4267 :
4268 : /* Given two piecewise multi affine expressions, return a piecewise
4269 : * multi-affine expression defined on the union of the definition domains
4270 : * of the inputs that is equal to the lexicographic minimum of the two
4271 : * inputs on each cell. If only one of the two inputs is defined on
4272 : * a given cell, then it is considered to be the minimum.
4273 : */
4274 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin(
4275 : __isl_take isl_pw_multi_aff *pma1,
4276 : __isl_take isl_pw_multi_aff *pma2)
4277 : {
4278 0 : return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
4279 : &pw_multi_aff_union_lexmin);
4280 : }
4281 :
4282 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_add(
4283 : __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
4284 : {
4285 0 : return isl_pw_multi_aff_on_shared_domain(pma1, pma2,
4286 : &isl_multi_aff_add);
4287 : }
4288 :
4289 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_add(
4290 : __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
4291 : {
4292 0 : return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
4293 : &pw_multi_aff_add);
4294 : }
4295 :
4296 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_sub(
4297 : __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
4298 : {
4299 0 : return isl_pw_multi_aff_on_shared_domain(pma1, pma2,
4300 : &isl_multi_aff_sub);
4301 : }
4302 :
4303 : /* Subtract "pma2" from "pma1" and return the result.
4304 : */
4305 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub(
4306 : __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
4307 : {
4308 0 : return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
4309 : &pw_multi_aff_sub);
4310 : }
4311 :
4312 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add(
4313 : __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
4314 : {
4315 0 : return isl_pw_multi_aff_union_add_(pma1, pma2);
4316 : }
4317 :
4318 : /* Compute the sum of "upa1" and "upa2" on the union of their domains,
4319 : * with the actual sum on the shared domain and
4320 : * the defined expression on the symmetric difference of the domains.
4321 : */
4322 0 : __isl_give isl_union_pw_aff *isl_union_pw_aff_union_add(
4323 : __isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2)
4324 : {
4325 0 : return isl_union_pw_aff_union_add_(upa1, upa2);
4326 : }
4327 :
4328 : /* Compute the sum of "upma1" and "upma2" on the union of their domains,
4329 : * with the actual sum on the shared domain and
4330 : * the defined expression on the symmetric difference of the domains.
4331 : */
4332 0 : __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_union_add(
4333 : __isl_take isl_union_pw_multi_aff *upma1,
4334 : __isl_take isl_union_pw_multi_aff *upma2)
4335 : {
4336 0 : return isl_union_pw_multi_aff_union_add_(upma1, upma2);
4337 : }
4338 :
4339 : /* Given two piecewise multi-affine expressions A -> B and C -> D,
4340 : * construct a piecewise multi-affine expression [A -> C] -> [B -> D].
4341 : */
4342 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_product(
4343 : __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
4344 : {
4345 : int i, j, n;
4346 : isl_space *space;
4347 : isl_pw_multi_aff *res;
4348 :
4349 0 : if (!pma1 || !pma2)
4350 : goto error;
4351 :
4352 0 : n = pma1->n * pma2->n;
4353 0 : space = isl_space_product(isl_space_copy(pma1->dim),
4354 : isl_space_copy(pma2->dim));
4355 0 : res = isl_pw_multi_aff_alloc_size(space, n);
4356 :
4357 0 : for (i = 0; i < pma1->n; ++i) {
4358 0 : for (j = 0; j < pma2->n; ++j) {
4359 : isl_set *domain;
4360 : isl_multi_aff *ma;
4361 :
4362 0 : domain = isl_set_product(isl_set_copy(pma1->p[i].set),
4363 : isl_set_copy(pma2->p[j].set));
4364 0 : ma = isl_multi_aff_product(
4365 : isl_multi_aff_copy(pma1->p[i].maff),
4366 : isl_multi_aff_copy(pma2->p[j].maff));
4367 0 : res = isl_pw_multi_aff_add_piece(res, domain, ma);
4368 : }
4369 : }
4370 :
4371 0 : isl_pw_multi_aff_free(pma1);
4372 0 : isl_pw_multi_aff_free(pma2);
4373 0 : return res;
4374 : error:
4375 0 : isl_pw_multi_aff_free(pma1);
4376 0 : isl_pw_multi_aff_free(pma2);
4377 0 : return NULL;
4378 : }
4379 :
4380 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_product(
4381 : __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
4382 : {
4383 0 : return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
4384 : &pw_multi_aff_product);
4385 : }
4386 :
4387 : /* Subtract the initial "n" elements in "ma" with coefficients in "c" and
4388 : * denominator "denom".
4389 : * "denom" is allowed to be negative, in which case the actual denominator
4390 : * is -denom and the expressions are added instead.
4391 : */
4392 0 : static __isl_give isl_aff *subtract_initial(__isl_take isl_aff *aff,
4393 : __isl_keep isl_multi_aff *ma, int n, isl_int *c, isl_int denom)
4394 : {
4395 : int i, first;
4396 : int sign;
4397 : isl_int d;
4398 :
4399 0 : first = isl_seq_first_non_zero(c, n);
4400 0 : if (first == -1)
4401 0 : return aff;
4402 :
4403 0 : sign = isl_int_sgn(denom);
4404 0 : isl_int_init(d);
4405 0 : isl_int_abs(d, denom);
4406 0 : for (i = first; i < n; ++i) {
4407 : isl_aff *aff_i;
4408 :
4409 0 : if (isl_int_is_zero(c[i]))
4410 0 : continue;
4411 0 : aff_i = isl_multi_aff_get_aff(ma, i);
4412 0 : aff_i = isl_aff_scale(aff_i, c[i]);
4413 0 : aff_i = isl_aff_scale_down(aff_i, d);
4414 0 : if (sign >= 0)
4415 0 : aff = isl_aff_sub(aff, aff_i);
4416 : else
4417 0 : aff = isl_aff_add(aff, aff_i);
4418 : }
4419 0 : isl_int_clear(d);
4420 :
4421 0 : return aff;
4422 : }
4423 :
4424 : /* Extract an affine expression that expresses the output dimension "pos"
4425 : * of "bmap" in terms of the parameters and input dimensions from
4426 : * equality "eq".
4427 : * Note that this expression may involve integer divisions defined
4428 : * in terms of parameters and input dimensions.
4429 : * The equality may also involve references to earlier (but not later)
4430 : * output dimensions. These are replaced by the corresponding elements
4431 : * in "ma".
4432 : *
4433 : * If the equality is of the form
4434 : *
4435 : * f(i) + h(j) + a x + g(i) = 0,
4436 : *
4437 : * with f(i) a linear combinations of the parameters and input dimensions,
4438 : * g(i) a linear combination of integer divisions defined in terms of the same
4439 : * and h(j) a linear combinations of earlier output dimensions,
4440 : * then the affine expression is
4441 : *
4442 : * (-f(i) - g(i))/a - h(j)/a
4443 : *
4444 : * If the equality is of the form
4445 : *
4446 : * f(i) + h(j) - a x + g(i) = 0,
4447 : *
4448 : * then the affine expression is
4449 : *
4450 : * (f(i) + g(i))/a - h(j)/(-a)
4451 : *
4452 : *
4453 : * If "div" refers to an integer division (i.e., it is smaller than
4454 : * the number of integer divisions), then the equality constraint
4455 : * does involve an integer division (the one at position "div") that
4456 : * is defined in terms of output dimensions. However, this integer
4457 : * division can be eliminated by exploiting a pair of constraints
4458 : * x >= l and x <= l + n, with n smaller than the coefficient of "div"
4459 : * in the equality constraint. "ineq" refers to inequality x >= l, i.e.,
4460 : * -l + x >= 0.
4461 : * In particular, let
4462 : *
4463 : * x = e(i) + m floor(...)
4464 : *
4465 : * with e(i) the expression derived above and floor(...) the integer
4466 : * division involving output dimensions.
4467 : * From
4468 : *
4469 : * l <= x <= l + n,
4470 : *
4471 : * we have
4472 : *
4473 : * 0 <= x - l <= n
4474 : *
4475 : * This means
4476 : *
4477 : * e(i) + m floor(...) - l = (e(i) + m floor(...) - l) mod m
4478 : * = (e(i) - l) mod m
4479 : *
4480 : * Therefore,
4481 : *
4482 : * x - l = (e(i) - l) mod m
4483 : *
4484 : * or
4485 : *
4486 : * x = ((e(i) - l) mod m) + l
4487 : *
4488 : * The variable "shift" below contains the expression -l, which may
4489 : * also involve a linear combination of earlier output dimensions.
4490 : */
4491 0 : static __isl_give isl_aff *extract_aff_from_equality(
4492 : __isl_keep isl_basic_map *bmap, int pos, int eq, int div, int ineq,
4493 : __isl_keep isl_multi_aff *ma)
4494 : {
4495 : unsigned o_out;
4496 : unsigned n_div, n_out;
4497 : isl_ctx *ctx;
4498 : isl_local_space *ls;
4499 : isl_aff *aff, *shift;
4500 : isl_val *mod;
4501 :
4502 0 : ctx = isl_basic_map_get_ctx(bmap);
4503 0 : ls = isl_basic_map_get_local_space(bmap);
4504 0 : ls = isl_local_space_domain(ls);
4505 0 : aff = isl_aff_alloc(isl_local_space_copy(ls));
4506 0 : if (!aff)
4507 0 : goto error;
4508 0 : o_out = isl_basic_map_offset(bmap, isl_dim_out);
4509 0 : n_out = isl_basic_map_dim(bmap, isl_dim_out);
4510 0 : n_div = isl_basic_map_dim(bmap, isl_dim_div);
4511 0 : if (isl_int_is_neg(bmap->eq[eq][o_out + pos])) {
4512 0 : isl_seq_cpy(aff->v->el + 1, bmap->eq[eq], o_out);
4513 0 : isl_seq_cpy(aff->v->el + 1 + o_out,
4514 0 : bmap->eq[eq] + o_out + n_out, n_div);
4515 : } else {
4516 0 : isl_seq_neg(aff->v->el + 1, bmap->eq[eq], o_out);
4517 0 : isl_seq_neg(aff->v->el + 1 + o_out,
4518 0 : bmap->eq[eq] + o_out + n_out, n_div);
4519 : }
4520 0 : if (div < n_div)
4521 0 : isl_int_set_si(aff->v->el[1 + o_out + div], 0);
4522 0 : isl_int_abs(aff->v->el[0], bmap->eq[eq][o_out + pos]);
4523 0 : aff = subtract_initial(aff, ma, pos, bmap->eq[eq] + o_out,
4524 0 : bmap->eq[eq][o_out + pos]);
4525 0 : if (div < n_div) {
4526 0 : shift = isl_aff_alloc(isl_local_space_copy(ls));
4527 0 : if (!shift)
4528 0 : goto error;
4529 0 : isl_seq_cpy(shift->v->el + 1, bmap->ineq[ineq], o_out);
4530 0 : isl_seq_cpy(shift->v->el + 1 + o_out,
4531 0 : bmap->ineq[ineq] + o_out + n_out, n_div);
4532 0 : isl_int_set_si(shift->v->el[0], 1);
4533 0 : shift = subtract_initial(shift, ma, pos,
4534 0 : bmap->ineq[ineq] + o_out, ctx->negone);
4535 0 : aff = isl_aff_add(aff, isl_aff_copy(shift));
4536 0 : mod = isl_val_int_from_isl_int(ctx,
4537 0 : bmap->eq[eq][o_out + n_out + div]);
4538 0 : mod = isl_val_abs(mod);
4539 0 : aff = isl_aff_mod_val(aff, mod);
4540 0 : aff = isl_aff_sub(aff, shift);
4541 : }
4542 :
4543 0 : isl_local_space_free(ls);
4544 0 : return aff;
4545 : error:
4546 0 : isl_local_space_free(ls);
4547 0 : isl_aff_free(aff);
4548 0 : return NULL;
4549 : }
4550 :
4551 : /* Given a basic map with output dimensions defined
4552 : * in terms of the parameters input dimensions and earlier
4553 : * output dimensions using an equality (and possibly a pair on inequalities),
4554 : * extract an isl_aff that expresses output dimension "pos" in terms
4555 : * of the parameters and input dimensions.
4556 : * Note that this expression may involve integer divisions defined
4557 : * in terms of parameters and input dimensions.
4558 : * "ma" contains the expressions corresponding to earlier output dimensions.
4559 : *
4560 : * This function shares some similarities with
4561 : * isl_basic_map_has_defining_equality and isl_constraint_get_bound.
4562 : */
4563 0 : static __isl_give isl_aff *extract_isl_aff_from_basic_map(
4564 : __isl_keep isl_basic_map *bmap, int pos, __isl_keep isl_multi_aff *ma)
4565 : {
4566 : int eq, div, ineq;
4567 : isl_aff *aff;
4568 :
4569 0 : if (!bmap)
4570 0 : return NULL;
4571 0 : eq = isl_basic_map_output_defining_equality(bmap, pos, &div, &ineq);
4572 0 : if (eq >= bmap->n_eq)
4573 0 : isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
4574 : "unable to find suitable equality", return NULL);
4575 0 : aff = extract_aff_from_equality(bmap, pos, eq, div, ineq, ma);
4576 :
4577 0 : aff = isl_aff_remove_unused_divs(aff);
4578 0 : return aff;
4579 : }
4580 :
4581 : /* Given a basic map where each output dimension is defined
4582 : * in terms of the parameters and input dimensions using an equality,
4583 : * extract an isl_multi_aff that expresses the output dimensions in terms
4584 : * of the parameters and input dimensions.
4585 : */
4586 0 : static __isl_give isl_multi_aff *extract_isl_multi_aff_from_basic_map(
4587 : __isl_take isl_basic_map *bmap)
4588 : {
4589 : int i;
4590 : unsigned n_out;
4591 : isl_multi_aff *ma;
4592 :
4593 0 : if (!bmap)
4594 0 : return NULL;
4595 :
4596 0 : ma = isl_multi_aff_alloc(isl_basic_map_get_space(bmap));
4597 0 : n_out = isl_basic_map_dim(bmap, isl_dim_out);
4598 :
4599 0 : for (i = 0; i < n_out; ++i) {
4600 : isl_aff *aff;
4601 :
4602 0 : aff = extract_isl_aff_from_basic_map(bmap, i, ma);
4603 0 : ma = isl_multi_aff_set_aff(ma, i, aff);
4604 : }
4605 :
4606 0 : isl_basic_map_free(bmap);
4607 :
4608 0 : return ma;
4609 : }
4610 :
4611 : /* Given a basic set where each set dimension is defined
4612 : * in terms of the parameters using an equality,
4613 : * extract an isl_multi_aff that expresses the set dimensions in terms
4614 : * of the parameters.
4615 : */
4616 0 : __isl_give isl_multi_aff *isl_multi_aff_from_basic_set_equalities(
4617 : __isl_take isl_basic_set *bset)
4618 : {
4619 0 : return extract_isl_multi_aff_from_basic_map(bset);
4620 : }
4621 :
4622 : /* Create an isl_pw_multi_aff that is equivalent to
4623 : * isl_map_intersect_domain(isl_map_from_basic_map(bmap), domain).
4624 : * The given basic map is such that each output dimension is defined
4625 : * in terms of the parameters and input dimensions using an equality.
4626 : *
4627 : * Since some applications expect the result of isl_pw_multi_aff_from_map
4628 : * to only contain integer affine expressions, we compute the floor
4629 : * of the expression before returning.
4630 : *
4631 : * Remove all constraints involving local variables without
4632 : * an explicit representation (resulting in the removal of those
4633 : * local variables) prior to the actual extraction to ensure
4634 : * that the local spaces in which the resulting affine expressions
4635 : * are created do not contain any unknown local variables.
4636 : * Removing such constraints is safe because constraints involving
4637 : * unknown local variables are not used to determine whether
4638 : * a basic map is obviously single-valued.
4639 : */
4640 0 : static __isl_give isl_pw_multi_aff *plain_pw_multi_aff_from_map(
4641 : __isl_take isl_set *domain, __isl_take isl_basic_map *bmap)
4642 : {
4643 : isl_multi_aff *ma;
4644 :
4645 0 : bmap = isl_basic_map_drop_constraint_involving_unknown_divs(bmap);
4646 0 : ma = extract_isl_multi_aff_from_basic_map(bmap);
4647 0 : ma = isl_multi_aff_floor(ma);
4648 0 : return isl_pw_multi_aff_alloc(domain, ma);
4649 : }
4650 :
4651 : /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map.
4652 : * This obviously only works if the input "map" is single-valued.
4653 : * If so, we compute the lexicographic minimum of the image in the form
4654 : * of an isl_pw_multi_aff. Since the image is unique, it is equal
4655 : * to its lexicographic minimum.
4656 : * If the input is not single-valued, we produce an error.
4657 : */
4658 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_base(
4659 : __isl_take isl_map *map)
4660 : {
4661 : int i;
4662 : int sv;
4663 : isl_pw_multi_aff *pma;
4664 :
4665 0 : sv = isl_map_is_single_valued(map);
4666 0 : if (sv < 0)
4667 0 : goto error;
4668 0 : if (!sv)
4669 0 : isl_die(isl_map_get_ctx(map), isl_error_invalid,
4670 : "map is not single-valued", goto error);
4671 0 : map = isl_map_make_disjoint(map);
4672 0 : if (!map)
4673 0 : return NULL;
4674 :
4675 0 : pma = isl_pw_multi_aff_empty(isl_map_get_space(map));
4676 :
4677 0 : for (i = 0; i < map->n; ++i) {
4678 : isl_pw_multi_aff *pma_i;
4679 : isl_basic_map *bmap;
4680 0 : bmap = isl_basic_map_copy(map->p[i]);
4681 0 : pma_i = isl_basic_map_lexmin_pw_multi_aff(bmap);
4682 0 : pma = isl_pw_multi_aff_add_disjoint(pma, pma_i);
4683 : }
4684 :
4685 0 : isl_map_free(map);
4686 0 : return pma;
4687 : error:
4688 0 : isl_map_free(map);
4689 0 : return NULL;
4690 : }
4691 :
4692 : /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map,
4693 : * taking into account that the output dimension at position "d"
4694 : * can be represented as
4695 : *
4696 : * x = floor((e(...) + c1) / m)
4697 : *
4698 : * given that constraint "i" is of the form
4699 : *
4700 : * e(...) + c1 - m x >= 0
4701 : *
4702 : *
4703 : * Let "map" be of the form
4704 : *
4705 : * A -> B
4706 : *
4707 : * We construct a mapping
4708 : *
4709 : * A -> [A -> x = floor(...)]
4710 : *
4711 : * apply that to the map, obtaining
4712 : *
4713 : * [A -> x = floor(...)] -> B
4714 : *
4715 : * and equate dimension "d" to x.
4716 : * We then compute a isl_pw_multi_aff representation of the resulting map
4717 : * and plug in the mapping above.
4718 : */
4719 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_div(
4720 : __isl_take isl_map *map, __isl_take isl_basic_map *hull, int d, int i)
4721 : {
4722 : isl_ctx *ctx;
4723 : isl_space *space;
4724 : isl_local_space *ls;
4725 : isl_multi_aff *ma;
4726 : isl_aff *aff;
4727 : isl_vec *v;
4728 : isl_map *insert;
4729 : int offset;
4730 : int n;
4731 : int n_in;
4732 : isl_pw_multi_aff *pma;
4733 : isl_bool is_set;
4734 :
4735 0 : is_set = isl_map_is_set(map);
4736 0 : if (is_set < 0)
4737 0 : goto error;
4738 :
4739 0 : offset = isl_basic_map_offset(hull, isl_dim_out);
4740 0 : ctx = isl_map_get_ctx(map);
4741 0 : space = isl_space_domain(isl_map_get_space(map));
4742 0 : n_in = isl_space_dim(space, isl_dim_set);
4743 0 : n = isl_space_dim(space, isl_dim_all);
4744 :
4745 0 : v = isl_vec_alloc(ctx, 1 + 1 + n);
4746 0 : if (v) {
4747 0 : isl_int_neg(v->el[0], hull->ineq[i][offset + d]);
4748 0 : isl_seq_cpy(v->el + 1, hull->ineq[i], 1 + n);
4749 : }
4750 0 : isl_basic_map_free(hull);
4751 :
4752 0 : ls = isl_local_space_from_space(isl_space_copy(space));
4753 0 : aff = isl_aff_alloc_vec(ls, v);
4754 0 : aff = isl_aff_floor(aff);
4755 0 : if (is_set) {
4756 0 : isl_space_free(space);
4757 0 : ma = isl_multi_aff_from_aff(aff);
4758 : } else {
4759 0 : ma = isl_multi_aff_identity(isl_space_map_from_set(space));
4760 0 : ma = isl_multi_aff_range_product(ma,
4761 : isl_multi_aff_from_aff(aff));
4762 : }
4763 :
4764 0 : insert = isl_map_from_multi_aff_internal(isl_multi_aff_copy(ma));
4765 0 : map = isl_map_apply_domain(map, insert);
4766 0 : map = isl_map_equate(map, isl_dim_in, n_in, isl_dim_out, d);
4767 0 : pma = isl_pw_multi_aff_from_map(map);
4768 0 : pma = isl_pw_multi_aff_pullback_multi_aff(pma, ma);
4769 :
4770 0 : return pma;
4771 : error:
4772 0 : isl_map_free(map);
4773 0 : isl_basic_map_free(hull);
4774 0 : return NULL;
4775 : }
4776 :
4777 : /* Is constraint "c" of the form
4778 : *
4779 : * e(...) + c1 - m x >= 0
4780 : *
4781 : * or
4782 : *
4783 : * -e(...) + c2 + m x >= 0
4784 : *
4785 : * where m > 1 and e only depends on parameters and input dimemnsions?
4786 : *
4787 : * "offset" is the offset of the output dimensions
4788 : * "pos" is the position of output dimension x.
4789 : */
4790 0 : static int is_potential_div_constraint(isl_int *c, int offset, int d, int total)
4791 : {
4792 0 : if (isl_int_is_zero(c[offset + d]))
4793 0 : return 0;
4794 0 : if (isl_int_is_one(c[offset + d]))
4795 0 : return 0;
4796 0 : if (isl_int_is_negone(c[offset + d]))
4797 0 : return 0;
4798 0 : if (isl_seq_first_non_zero(c + offset, d) != -1)
4799 0 : return 0;
4800 0 : if (isl_seq_first_non_zero(c + offset + d + 1,
4801 0 : total - (offset + d + 1)) != -1)
4802 0 : return 0;
4803 0 : return 1;
4804 : }
4805 :
4806 : /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map.
4807 : *
4808 : * As a special case, we first check if there is any pair of constraints,
4809 : * shared by all the basic maps in "map" that force a given dimension
4810 : * to be equal to the floor of some affine combination of the input dimensions.
4811 : *
4812 : * In particular, if we can find two constraints
4813 : *
4814 : * e(...) + c1 - m x >= 0 i.e., m x <= e(...) + c1
4815 : *
4816 : * and
4817 : *
4818 : * -e(...) + c2 + m x >= 0 i.e., m x >= e(...) - c2
4819 : *
4820 : * where m > 1 and e only depends on parameters and input dimemnsions,
4821 : * and such that
4822 : *
4823 : * c1 + c2 < m i.e., -c2 >= c1 - (m - 1)
4824 : *
4825 : * then we know that we can take
4826 : *
4827 : * x = floor((e(...) + c1) / m)
4828 : *
4829 : * without having to perform any computation.
4830 : *
4831 : * Note that we know that
4832 : *
4833 : * c1 + c2 >= 1
4834 : *
4835 : * If c1 + c2 were 0, then we would have detected an equality during
4836 : * simplification. If c1 + c2 were negative, then we would have detected
4837 : * a contradiction.
4838 : */
4839 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_check_div(
4840 : __isl_take isl_map *map)
4841 : {
4842 : int d, dim;
4843 : int i, j, n;
4844 : int offset, total;
4845 : isl_int sum;
4846 : isl_basic_map *hull;
4847 :
4848 0 : hull = isl_map_unshifted_simple_hull(isl_map_copy(map));
4849 0 : if (!hull)
4850 0 : goto error;
4851 :
4852 0 : isl_int_init(sum);
4853 0 : dim = isl_map_dim(map, isl_dim_out);
4854 0 : offset = isl_basic_map_offset(hull, isl_dim_out);
4855 0 : total = 1 + isl_basic_map_total_dim(hull);
4856 0 : n = hull->n_ineq;
4857 0 : for (d = 0; d < dim; ++d) {
4858 0 : for (i = 0; i < n; ++i) {
4859 0 : if (!is_potential_div_constraint(hull->ineq[i],
4860 : offset, d, total))
4861 0 : continue;
4862 0 : for (j = i + 1; j < n; ++j) {
4863 0 : if (!isl_seq_is_neg(hull->ineq[i] + 1,
4864 0 : hull->ineq[j] + 1, total - 1))
4865 0 : continue;
4866 0 : isl_int_add(sum, hull->ineq[i][0],
4867 : hull->ineq[j][0]);
4868 0 : if (isl_int_abs_lt(sum,
4869 : hull->ineq[i][offset + d]))
4870 0 : break;
4871 :
4872 : }
4873 0 : if (j >= n)
4874 0 : continue;
4875 0 : isl_int_clear(sum);
4876 0 : if (isl_int_is_pos(hull->ineq[j][offset + d]))
4877 0 : j = i;
4878 0 : return pw_multi_aff_from_map_div(map, hull, d, j);
4879 : }
4880 : }
4881 0 : isl_int_clear(sum);
4882 0 : isl_basic_map_free(hull);
4883 0 : return pw_multi_aff_from_map_base(map);
4884 : error:
4885 0 : isl_map_free(map);
4886 0 : isl_basic_map_free(hull);
4887 0 : return NULL;
4888 : }
4889 :
4890 : /* Given an affine expression
4891 : *
4892 : * [A -> B] -> f(A,B)
4893 : *
4894 : * construct an isl_multi_aff
4895 : *
4896 : * [A -> B] -> B'
4897 : *
4898 : * such that dimension "d" in B' is set to "aff" and the remaining
4899 : * dimensions are set equal to the corresponding dimensions in B.
4900 : * "n_in" is the dimension of the space A.
4901 : * "n_out" is the dimension of the space B.
4902 : *
4903 : * If "is_set" is set, then the affine expression is of the form
4904 : *
4905 : * [B] -> f(B)
4906 : *
4907 : * and we construct an isl_multi_aff
4908 : *
4909 : * B -> B'
4910 : */
4911 0 : static __isl_give isl_multi_aff *range_map(__isl_take isl_aff *aff, int d,
4912 : unsigned n_in, unsigned n_out, int is_set)
4913 : {
4914 : int i;
4915 : isl_multi_aff *ma;
4916 : isl_space *space, *space2;
4917 : isl_local_space *ls;
4918 :
4919 0 : space = isl_aff_get_domain_space(aff);
4920 0 : ls = isl_local_space_from_space(isl_space_copy(space));
4921 0 : space2 = isl_space_copy(space);
4922 0 : if (!is_set)
4923 0 : space2 = isl_space_range(isl_space_unwrap(space2));
4924 0 : space = isl_space_map_from_domain_and_range(space, space2);
4925 0 : ma = isl_multi_aff_alloc(space);
4926 0 : ma = isl_multi_aff_set_aff(ma, d, aff);
4927 :
4928 0 : for (i = 0; i < n_out; ++i) {
4929 0 : if (i == d)
4930 0 : continue;
4931 0 : aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
4932 : isl_dim_set, n_in + i);
4933 0 : ma = isl_multi_aff_set_aff(ma, i, aff);
4934 : }
4935 :
4936 0 : isl_local_space_free(ls);
4937 :
4938 0 : return ma;
4939 : }
4940 :
4941 : /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map,
4942 : * taking into account that the dimension at position "d" can be written as
4943 : *
4944 : * x = m a + f(..) (1)
4945 : *
4946 : * where m is equal to "gcd".
4947 : * "i" is the index of the equality in "hull" that defines f(..).
4948 : * In particular, the equality is of the form
4949 : *
4950 : * f(..) - x + m g(existentials) = 0
4951 : *
4952 : * or
4953 : *
4954 : * -f(..) + x + m g(existentials) = 0
4955 : *
4956 : * We basically plug (1) into "map", resulting in a map with "a"
4957 : * in the range instead of "x". The corresponding isl_pw_multi_aff
4958 : * defining "a" is then plugged back into (1) to obtain a definition for "x".
4959 : *
4960 : * Specifically, given the input map
4961 : *
4962 : * A -> B
4963 : *
4964 : * We first wrap it into a set
4965 : *
4966 : * [A -> B]
4967 : *
4968 : * and define (1) on top of the corresponding space, resulting in "aff".
4969 : * We use this to create an isl_multi_aff that maps the output position "d"
4970 : * from "a" to "x", leaving all other (intput and output) dimensions unchanged.
4971 : * We plug this into the wrapped map, unwrap the result and compute the
4972 : * corresponding isl_pw_multi_aff.
4973 : * The result is an expression
4974 : *
4975 : * A -> T(A)
4976 : *
4977 : * We adjust that to
4978 : *
4979 : * A -> [A -> T(A)]
4980 : *
4981 : * so that we can plug that into "aff", after extending the latter to
4982 : * a mapping
4983 : *
4984 : * [A -> B] -> B'
4985 : *
4986 : *
4987 : * If "map" is actually a set, then there is no "A" space, meaning
4988 : * that we do not need to perform any wrapping, and that the result
4989 : * of the recursive call is of the form
4990 : *
4991 : * [T]
4992 : *
4993 : * which is plugged into a mapping of the form
4994 : *
4995 : * B -> B'
4996 : */
4997 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_stride(
4998 : __isl_take isl_map *map, __isl_take isl_basic_map *hull, int d, int i,
4999 : isl_int gcd)
5000 : {
5001 : isl_set *set;
5002 : isl_space *space;
5003 : isl_local_space *ls;
5004 : isl_aff *aff;
5005 : isl_multi_aff *ma;
5006 : isl_pw_multi_aff *pma, *id;
5007 : unsigned n_in;
5008 : unsigned o_out;
5009 : unsigned n_out;
5010 : isl_bool is_set;
5011 :
5012 0 : is_set = isl_map_is_set(map);
5013 0 : if (is_set < 0)
5014 0 : goto error;
5015 :
5016 0 : n_in = isl_basic_map_dim(hull, isl_dim_in);
5017 0 : n_out = isl_basic_map_dim(hull, isl_dim_out);
5018 0 : o_out = isl_basic_map_offset(hull, isl_dim_out);
5019 :
5020 0 : if (is_set)
5021 0 : set = map;
5022 : else
5023 0 : set = isl_map_wrap(map);
5024 0 : space = isl_space_map_from_set(isl_set_get_space(set));
5025 0 : ma = isl_multi_aff_identity(space);
5026 0 : ls = isl_local_space_from_space(isl_set_get_space(set));
5027 0 : aff = isl_aff_alloc(ls);
5028 0 : if (aff) {
5029 0 : isl_int_set_si(aff->v->el[0], 1);
5030 0 : if (isl_int_is_one(hull->eq[i][o_out + d]))
5031 0 : isl_seq_neg(aff->v->el + 1, hull->eq[i],
5032 0 : aff->v->size - 1);
5033 : else
5034 0 : isl_seq_cpy(aff->v->el + 1, hull->eq[i],
5035 0 : aff->v->size - 1);
5036 0 : isl_int_set(aff->v->el[1 + o_out + d], gcd);
5037 : }
5038 0 : ma = isl_multi_aff_set_aff(ma, n_in + d, isl_aff_copy(aff));
5039 0 : set = isl_set_preimage_multi_aff(set, ma);
5040 :
5041 0 : ma = range_map(aff, d, n_in, n_out, is_set);
5042 :
5043 0 : if (is_set)
5044 0 : map = set;
5045 : else
5046 0 : map = isl_set_unwrap(set);
5047 0 : pma = isl_pw_multi_aff_from_map(map);
5048 :
5049 0 : if (!is_set) {
5050 0 : space = isl_pw_multi_aff_get_domain_space(pma);
5051 0 : space = isl_space_map_from_set(space);
5052 0 : id = isl_pw_multi_aff_identity(space);
5053 0 : pma = isl_pw_multi_aff_range_product(id, pma);
5054 : }
5055 0 : id = isl_pw_multi_aff_from_multi_aff(ma);
5056 0 : pma = isl_pw_multi_aff_pullback_pw_multi_aff(id, pma);
5057 :
5058 0 : isl_basic_map_free(hull);
5059 0 : return pma;
5060 : error:
5061 0 : isl_map_free(map);
5062 0 : isl_basic_map_free(hull);
5063 0 : return NULL;
5064 : }
5065 :
5066 : /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map.
5067 : * "hull" contains the equalities valid for "map".
5068 : *
5069 : * Check if any of the output dimensions is "strided".
5070 : * That is, we check if it can be written as
5071 : *
5072 : * x = m a + f(..)
5073 : *
5074 : * with m greater than 1, a some combination of existentially quantified
5075 : * variables and f an expression in the parameters and input dimensions.
5076 : * If so, we remove the stride in pw_multi_aff_from_map_stride.
5077 : *
5078 : * Otherwise, we continue with pw_multi_aff_from_map_check_div for a further
5079 : * special case.
5080 : */
5081 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_check_strides(
5082 : __isl_take isl_map *map, __isl_take isl_basic_map *hull)
5083 : {
5084 : int i, j;
5085 : unsigned n_out;
5086 : unsigned o_out;
5087 : unsigned n_div;
5088 : unsigned o_div;
5089 : isl_int gcd;
5090 :
5091 0 : n_div = isl_basic_map_dim(hull, isl_dim_div);
5092 0 : o_div = isl_basic_map_offset(hull, isl_dim_div);
5093 :
5094 0 : if (n_div == 0) {
5095 0 : isl_basic_map_free(hull);
5096 0 : return pw_multi_aff_from_map_check_div(map);
5097 : }
5098 :
5099 0 : isl_int_init(gcd);
5100 :
5101 0 : n_out = isl_basic_map_dim(hull, isl_dim_out);
5102 0 : o_out = isl_basic_map_offset(hull, isl_dim_out);
5103 :
5104 0 : for (i = 0; i < n_out; ++i) {
5105 0 : for (j = 0; j < hull->n_eq; ++j) {
5106 0 : isl_int *eq = hull->eq[j];
5107 : isl_pw_multi_aff *res;
5108 :
5109 0 : if (!isl_int_is_one(eq[o_out + i]) &&
5110 0 : !isl_int_is_negone(eq[o_out + i]))
5111 0 : continue;
5112 0 : if (isl_seq_first_non_zero(eq + o_out, i) != -1)
5113 0 : continue;
5114 0 : if (isl_seq_first_non_zero(eq + o_out + i + 1,
5115 0 : n_out - (i + 1)) != -1)
5116 0 : continue;
5117 0 : isl_seq_gcd(eq + o_div, n_div, &gcd);
5118 0 : if (isl_int_is_zero(gcd))
5119 0 : continue;
5120 0 : if (isl_int_is_one(gcd))
5121 0 : continue;
5122 :
5123 0 : res = pw_multi_aff_from_map_stride(map, hull,
5124 : i, j, gcd);
5125 0 : isl_int_clear(gcd);
5126 0 : return res;
5127 : }
5128 : }
5129 :
5130 0 : isl_int_clear(gcd);
5131 0 : isl_basic_map_free(hull);
5132 0 : return pw_multi_aff_from_map_check_div(map);
5133 : }
5134 :
5135 : /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map.
5136 : *
5137 : * As a special case, we first check if all output dimensions are uniquely
5138 : * defined in terms of the parameters and input dimensions over the entire
5139 : * domain. If so, we extract the desired isl_pw_multi_aff directly
5140 : * from the affine hull of "map" and its domain.
5141 : *
5142 : * Otherwise, continue with pw_multi_aff_from_map_check_strides for more
5143 : * special cases.
5144 : */
5145 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map(__isl_take isl_map *map)
5146 : {
5147 : isl_bool sv;
5148 : isl_basic_map *hull;
5149 :
5150 0 : if (!map)
5151 0 : return NULL;
5152 :
5153 0 : if (isl_map_n_basic_map(map) == 1) {
5154 0 : hull = isl_map_unshifted_simple_hull(isl_map_copy(map));
5155 0 : hull = isl_basic_map_plain_affine_hull(hull);
5156 0 : sv = isl_basic_map_plain_is_single_valued(hull);
5157 0 : if (sv >= 0 && sv)
5158 0 : return plain_pw_multi_aff_from_map(isl_map_domain(map),
5159 : hull);
5160 0 : isl_basic_map_free(hull);
5161 : }
5162 0 : map = isl_map_detect_equalities(map);
5163 0 : hull = isl_map_unshifted_simple_hull(isl_map_copy(map));
5164 0 : sv = isl_basic_map_plain_is_single_valued(hull);
5165 0 : if (sv >= 0 && sv)
5166 0 : return plain_pw_multi_aff_from_map(isl_map_domain(map), hull);
5167 0 : if (sv >= 0)
5168 0 : return pw_multi_aff_from_map_check_strides(map, hull);
5169 0 : isl_basic_map_free(hull);
5170 0 : isl_map_free(map);
5171 0 : return NULL;
5172 : }
5173 :
5174 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(__isl_take isl_set *set)
5175 : {
5176 0 : return isl_pw_multi_aff_from_map(set);
5177 : }
5178 :
5179 : /* Convert "map" into an isl_pw_multi_aff (if possible) and
5180 : * add it to *user.
5181 : */
5182 0 : static isl_stat pw_multi_aff_from_map(__isl_take isl_map *map, void *user)
5183 : {
5184 0 : isl_union_pw_multi_aff **upma = user;
5185 : isl_pw_multi_aff *pma;
5186 :
5187 0 : pma = isl_pw_multi_aff_from_map(map);
5188 0 : *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma);
5189 :
5190 0 : return *upma ? isl_stat_ok : isl_stat_error;
5191 : }
5192 :
5193 : /* Create an isl_union_pw_multi_aff with the given isl_aff on a universe
5194 : * domain.
5195 : */
5196 0 : __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_aff(
5197 : __isl_take isl_aff *aff)
5198 : {
5199 : isl_multi_aff *ma;
5200 : isl_pw_multi_aff *pma;
5201 :
5202 0 : ma = isl_multi_aff_from_aff(aff);
5203 0 : pma = isl_pw_multi_aff_from_multi_aff(ma);
5204 0 : return isl_union_pw_multi_aff_from_pw_multi_aff(pma);
5205 : }
5206 :
5207 : /* Try and create an isl_union_pw_multi_aff that is equivalent
5208 : * to the given isl_union_map.
5209 : * The isl_union_map is required to be single-valued in each space.
5210 : * Otherwise, an error is produced.
5211 : */
5212 0 : __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_map(
5213 : __isl_take isl_union_map *umap)
5214 : {
5215 : isl_space *space;
5216 : isl_union_pw_multi_aff *upma;
5217 :
5218 0 : space = isl_union_map_get_space(umap);
5219 0 : upma = isl_union_pw_multi_aff_empty(space);
5220 0 : if (isl_union_map_foreach_map(umap, &pw_multi_aff_from_map, &upma) < 0)
5221 0 : upma = isl_union_pw_multi_aff_free(upma);
5222 0 : isl_union_map_free(umap);
5223 :
5224 0 : return upma;
5225 : }
5226 :
5227 : /* Try and create an isl_union_pw_multi_aff that is equivalent
5228 : * to the given isl_union_set.
5229 : * The isl_union_set is required to be a singleton in each space.
5230 : * Otherwise, an error is produced.
5231 : */
5232 0 : __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_set(
5233 : __isl_take isl_union_set *uset)
5234 : {
5235 0 : return isl_union_pw_multi_aff_from_union_map(uset);
5236 : }
5237 :
5238 : /* Return the piecewise affine expression "set ? 1 : 0".
5239 : */
5240 0 : __isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set)
5241 : {
5242 : isl_pw_aff *pa;
5243 0 : isl_space *space = isl_set_get_space(set);
5244 0 : isl_local_space *ls = isl_local_space_from_space(space);
5245 0 : isl_aff *zero = isl_aff_zero_on_domain(isl_local_space_copy(ls));
5246 0 : isl_aff *one = isl_aff_zero_on_domain(ls);
5247 :
5248 0 : one = isl_aff_add_constant_si(one, 1);
5249 0 : pa = isl_pw_aff_alloc(isl_set_copy(set), one);
5250 0 : set = isl_set_complement(set);
5251 0 : pa = isl_pw_aff_add_disjoint(pa, isl_pw_aff_alloc(set, zero));
5252 :
5253 0 : return pa;
5254 : }
5255 :
5256 : /* Plug in "subs" for dimension "type", "pos" of "aff".
5257 : *
5258 : * Let i be the dimension to replace and let "subs" be of the form
5259 : *
5260 : * f/d
5261 : *
5262 : * and "aff" of the form
5263 : *
5264 : * (a i + g)/m
5265 : *
5266 : * The result is
5267 : *
5268 : * (a f + d g')/(m d)
5269 : *
5270 : * where g' is the result of plugging in "subs" in each of the integer
5271 : * divisions in g.
5272 : */
5273 0 : __isl_give isl_aff *isl_aff_substitute(__isl_take isl_aff *aff,
5274 : enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
5275 : {
5276 : isl_ctx *ctx;
5277 : isl_int v;
5278 :
5279 0 : aff = isl_aff_cow(aff);
5280 0 : if (!aff || !subs)
5281 0 : return isl_aff_free(aff);
5282 :
5283 0 : ctx = isl_aff_get_ctx(aff);
5284 0 : if (!isl_space_is_equal(aff->ls->dim, subs->ls->dim))
5285 0 : isl_die(ctx, isl_error_invalid,
5286 : "spaces don't match", return isl_aff_free(aff));
5287 0 : if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
5288 0 : isl_die(ctx, isl_error_unsupported,
5289 : "cannot handle divs yet", return isl_aff_free(aff));
5290 :
5291 0 : aff->ls = isl_local_space_substitute(aff->ls, type, pos, subs);
5292 0 : if (!aff->ls)
5293 0 : return isl_aff_free(aff);
5294 :
5295 0 : aff->v = isl_vec_cow(aff->v);
5296 0 : if (!aff->v)
5297 0 : return isl_aff_free(aff);
5298 :
5299 0 : pos += isl_local_space_offset(aff->ls, type);
5300 :
5301 0 : isl_int_init(v);
5302 0 : isl_seq_substitute(aff->v->el, pos, subs->v->el,
5303 0 : aff->v->size, subs->v->size, v);
5304 0 : isl_int_clear(v);
5305 :
5306 0 : return aff;
5307 : }
5308 :
5309 : /* Plug in "subs" for dimension "type", "pos" in each of the affine
5310 : * expressions in "maff".
5311 : */
5312 0 : __isl_give isl_multi_aff *isl_multi_aff_substitute(
5313 : __isl_take isl_multi_aff *maff, enum isl_dim_type type, unsigned pos,
5314 : __isl_keep isl_aff *subs)
5315 : {
5316 : int i;
5317 :
5318 0 : maff = isl_multi_aff_cow(maff);
5319 0 : if (!maff || !subs)
5320 0 : return isl_multi_aff_free(maff);
5321 :
5322 0 : if (type == isl_dim_in)
5323 0 : type = isl_dim_set;
5324 :
5325 0 : for (i = 0; i < maff->n; ++i) {
5326 0 : maff->u.p[i] = isl_aff_substitute(maff->u.p[i],
5327 : type, pos, subs);
5328 0 : if (!maff->u.p[i])
5329 0 : return isl_multi_aff_free(maff);
5330 : }
5331 :
5332 0 : return maff;
5333 : }
5334 :
5335 : /* Plug in "subs" for dimension "type", "pos" of "pma".
5336 : *
5337 : * pma is of the form
5338 : *
5339 : * A_i(v) -> M_i(v)
5340 : *
5341 : * while subs is of the form
5342 : *
5343 : * v' = B_j(v) -> S_j
5344 : *
5345 : * Each pair i,j such that C_ij = A_i \cap B_i is non-empty
5346 : * has a contribution in the result, in particular
5347 : *
5348 : * C_ij(S_j) -> M_i(S_j)
5349 : *
5350 : * Note that plugging in S_j in C_ij may also result in an empty set
5351 : * and this contribution should simply be discarded.
5352 : */
5353 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_substitute(
5354 : __isl_take isl_pw_multi_aff *pma, enum isl_dim_type type, unsigned pos,
5355 : __isl_keep isl_pw_aff *subs)
5356 : {
5357 : int i, j, n;
5358 : isl_pw_multi_aff *res;
5359 :
5360 0 : if (!pma || !subs)
5361 0 : return isl_pw_multi_aff_free(pma);
5362 :
5363 0 : n = pma->n * subs->n;
5364 0 : res = isl_pw_multi_aff_alloc_size(isl_space_copy(pma->dim), n);
5365 :
5366 0 : for (i = 0; i < pma->n; ++i) {
5367 0 : for (j = 0; j < subs->n; ++j) {
5368 : isl_set *common;
5369 : isl_multi_aff *res_ij;
5370 : int empty;
5371 :
5372 0 : common = isl_set_intersect(
5373 : isl_set_copy(pma->p[i].set),
5374 0 : isl_set_copy(subs->p[j].set));
5375 0 : common = isl_set_substitute(common,
5376 0 : type, pos, subs->p[j].aff);
5377 0 : empty = isl_set_plain_is_empty(common);
5378 0 : if (empty < 0 || empty) {
5379 0 : isl_set_free(common);
5380 0 : if (empty < 0)
5381 0 : goto error;
5382 0 : continue;
5383 : }
5384 :
5385 0 : res_ij = isl_multi_aff_substitute(
5386 : isl_multi_aff_copy(pma->p[i].maff),
5387 0 : type, pos, subs->p[j].aff);
5388 :
5389 0 : res = isl_pw_multi_aff_add_piece(res, common, res_ij);
5390 : }
5391 : }
5392 :
5393 0 : isl_pw_multi_aff_free(pma);
5394 0 : return res;
5395 : error:
5396 0 : isl_pw_multi_aff_free(pma);
5397 0 : isl_pw_multi_aff_free(res);
5398 0 : return NULL;
5399 : }
5400 :
5401 : /* Compute the preimage of a range of dimensions in the affine expression "src"
5402 : * under "ma" and put the result in "dst". The number of dimensions in "src"
5403 : * that precede the range is given by "n_before". The number of dimensions
5404 : * in the range is given by the number of output dimensions of "ma".
5405 : * The number of dimensions that follow the range is given by "n_after".
5406 : * If "has_denom" is set (to one),
5407 : * then "src" and "dst" have an extra initial denominator.
5408 : * "n_div_ma" is the number of existentials in "ma"
5409 : * "n_div_bset" is the number of existentials in "src"
5410 : * The resulting "dst" (which is assumed to have been allocated by
5411 : * the caller) contains coefficients for both sets of existentials,
5412 : * first those in "ma" and then those in "src".
5413 : * f, c1, c2 and g are temporary objects that have been initialized
5414 : * by the caller.
5415 : *
5416 : * Let src represent the expression
5417 : *
5418 : * (a(p) + f_u u + b v + f_w w + c(divs))/d
5419 : *
5420 : * and let ma represent the expressions
5421 : *
5422 : * v_i = (r_i(p) + s_i(y) + t_i(divs'))/m_i
5423 : *
5424 : * We start out with the following expression for dst:
5425 : *
5426 : * (a(p) + f_u u + 0 y + f_w w + 0 divs' + c(divs) + f \sum_i b_i v_i)/d
5427 : *
5428 : * with the multiplication factor f initially equal to 1
5429 : * and f \sum_i b_i v_i kept separately.
5430 : * For each x_i that we substitute, we multiply the numerator
5431 : * (and denominator) of dst by c_1 = m_i and add the numerator
5432 : * of the x_i expression multiplied by c_2 = f b_i,
5433 : * after removing the common factors of c_1 and c_2.
5434 : * The multiplication factor f also needs to be multiplied by c_1
5435 : * for the next x_j, j > i.
5436 : */
5437 0 : void isl_seq_preimage(isl_int *dst, isl_int *src,
5438 : __isl_keep isl_multi_aff *ma, int n_before, int n_after,
5439 : int n_div_ma, int n_div_bmap,
5440 : isl_int f, isl_int c1, isl_int c2, isl_int g, int has_denom)
5441 : {
5442 : int i;
5443 : int n_param, n_in, n_out;
5444 : int o_dst, o_src;
5445 :
5446 0 : n_param = isl_multi_aff_dim(ma, isl_dim_param);
5447 0 : n_in = isl_multi_aff_dim(ma, isl_dim_in);
5448 0 : n_out = isl_multi_aff_dim(ma, isl_dim_out);
5449 :
5450 0 : isl_seq_cpy(dst, src, has_denom + 1 + n_param + n_before);
5451 0 : o_dst = o_src = has_denom + 1 + n_param + n_before;
5452 0 : isl_seq_clr(dst + o_dst, n_in);
5453 0 : o_dst += n_in;
5454 0 : o_src += n_out;
5455 0 : isl_seq_cpy(dst + o_dst, src + o_src, n_after);
5456 0 : o_dst += n_after;
5457 0 : o_src += n_after;
5458 0 : isl_seq_clr(dst + o_dst, n_div_ma);
5459 0 : o_dst += n_div_ma;
5460 0 : isl_seq_cpy(dst + o_dst, src + o_src, n_div_bmap);
5461 :
5462 0 : isl_int_set_si(f, 1);
5463 :
5464 0 : for (i = 0; i < n_out; ++i) {
5465 0 : int offset = has_denom + 1 + n_param + n_before + i;
5466 :
5467 0 : if (isl_int_is_zero(src[offset]))
5468 0 : continue;
5469 0 : isl_int_set(c1, ma->u.p[i]->v->el[0]);
5470 0 : isl_int_mul(c2, f, src[offset]);
5471 0 : isl_int_gcd(g, c1, c2);
5472 0 : isl_int_divexact(c1, c1, g);
5473 0 : isl_int_divexact(c2, c2, g);
5474 :
5475 0 : isl_int_mul(f, f, c1);
5476 0 : o_dst = has_denom;
5477 0 : o_src = 1;
5478 0 : isl_seq_combine(dst + o_dst, c1, dst + o_dst,
5479 0 : c2, ma->u.p[i]->v->el + o_src, 1 + n_param);
5480 0 : o_dst += 1 + n_param;
5481 0 : o_src += 1 + n_param;
5482 0 : isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_before);
5483 0 : o_dst += n_before;
5484 0 : isl_seq_combine(dst + o_dst, c1, dst + o_dst,
5485 0 : c2, ma->u.p[i]->v->el + o_src, n_in);
5486 0 : o_dst += n_in;
5487 0 : o_src += n_in;
5488 0 : isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_after);
5489 0 : o_dst += n_after;
5490 0 : isl_seq_combine(dst + o_dst, c1, dst + o_dst,
5491 0 : c2, ma->u.p[i]->v->el + o_src, n_div_ma);
5492 0 : o_dst += n_div_ma;
5493 0 : o_src += n_div_ma;
5494 0 : isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_div_bmap);
5495 0 : if (has_denom)
5496 0 : isl_int_mul(dst[0], dst[0], c1);
5497 : }
5498 0 : }
5499 :
5500 : /* Compute the pullback of "aff" by the function represented by "ma".
5501 : * In other words, plug in "ma" in "aff". The result is an affine expression
5502 : * defined over the domain space of "ma".
5503 : *
5504 : * If "aff" is represented by
5505 : *
5506 : * (a(p) + b x + c(divs))/d
5507 : *
5508 : * and ma is represented by
5509 : *
5510 : * x = D(p) + F(y) + G(divs')
5511 : *
5512 : * then the result is
5513 : *
5514 : * (a(p) + b D(p) + b F(y) + b G(divs') + c(divs))/d
5515 : *
5516 : * The divs in the local space of the input are similarly adjusted
5517 : * through a call to isl_local_space_preimage_multi_aff.
5518 : */
5519 0 : __isl_give isl_aff *isl_aff_pullback_multi_aff(__isl_take isl_aff *aff,
5520 : __isl_take isl_multi_aff *ma)
5521 : {
5522 0 : isl_aff *res = NULL;
5523 : isl_local_space *ls;
5524 : int n_div_aff, n_div_ma;
5525 : isl_int f, c1, c2, g;
5526 :
5527 0 : ma = isl_multi_aff_align_divs(ma);
5528 0 : if (!aff || !ma)
5529 : goto error;
5530 :
5531 0 : n_div_aff = isl_aff_dim(aff, isl_dim_div);
5532 0 : n_div_ma = ma->n ? isl_aff_dim(ma->u.p[0], isl_dim_div) : 0;
5533 :
5534 0 : ls = isl_aff_get_domain_local_space(aff);
5535 0 : ls = isl_local_space_preimage_multi_aff(ls, isl_multi_aff_copy(ma));
5536 0 : res = isl_aff_alloc(ls);
5537 0 : if (!res)
5538 0 : goto error;
5539 :
5540 0 : isl_int_init(f);
5541 0 : isl_int_init(c1);
5542 0 : isl_int_init(c2);
5543 0 : isl_int_init(g);
5544 :
5545 0 : isl_seq_preimage(res->v->el, aff->v->el, ma, 0, 0, n_div_ma, n_div_aff,
5546 : f, c1, c2, g, 1);
5547 :
5548 0 : isl_int_clear(f);
5549 0 : isl_int_clear(c1);
5550 0 : isl_int_clear(c2);
5551 0 : isl_int_clear(g);
5552 :
5553 0 : isl_aff_free(aff);
5554 0 : isl_multi_aff_free(ma);
5555 0 : res = isl_aff_normalize(res);
5556 0 : return res;
5557 : error:
5558 0 : isl_aff_free(aff);
5559 0 : isl_multi_aff_free(ma);
5560 0 : isl_aff_free(res);
5561 0 : return NULL;
5562 : }
5563 :
5564 : /* Compute the pullback of "aff1" by the function represented by "aff2".
5565 : * In other words, plug in "aff2" in "aff1". The result is an affine expression
5566 : * defined over the domain space of "aff1".
5567 : *
5568 : * The domain of "aff1" should match the range of "aff2", which means
5569 : * that it should be single-dimensional.
5570 : */
5571 0 : __isl_give isl_aff *isl_aff_pullback_aff(__isl_take isl_aff *aff1,
5572 : __isl_take isl_aff *aff2)
5573 : {
5574 : isl_multi_aff *ma;
5575 :
5576 0 : ma = isl_multi_aff_from_aff(aff2);
5577 0 : return isl_aff_pullback_multi_aff(aff1, ma);
5578 : }
5579 :
5580 : /* Compute the pullback of "ma1" by the function represented by "ma2".
5581 : * In other words, plug in "ma2" in "ma1".
5582 : *
5583 : * The parameters of "ma1" and "ma2" are assumed to have been aligned.
5584 : */
5585 0 : static __isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff_aligned(
5586 : __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2)
5587 : {
5588 : int i;
5589 0 : isl_space *space = NULL;
5590 :
5591 0 : ma2 = isl_multi_aff_align_divs(ma2);
5592 0 : ma1 = isl_multi_aff_cow(ma1);
5593 0 : if (!ma1 || !ma2)
5594 : goto error;
5595 :
5596 0 : space = isl_space_join(isl_multi_aff_get_space(ma2),
5597 : isl_multi_aff_get_space(ma1));
5598 :
5599 0 : for (i = 0; i < ma1->n; ++i) {
5600 0 : ma1->u.p[i] = isl_aff_pullback_multi_aff(ma1->u.p[i],
5601 : isl_multi_aff_copy(ma2));
5602 0 : if (!ma1->u.p[i])
5603 0 : goto error;
5604 : }
5605 :
5606 0 : ma1 = isl_multi_aff_reset_space(ma1, space);
5607 0 : isl_multi_aff_free(ma2);
5608 0 : return ma1;
5609 : error:
5610 0 : isl_space_free(space);
5611 0 : isl_multi_aff_free(ma2);
5612 0 : isl_multi_aff_free(ma1);
5613 0 : return NULL;
5614 : }
5615 :
5616 : /* Compute the pullback of "ma1" by the function represented by "ma2".
5617 : * In other words, plug in "ma2" in "ma1".
5618 : */
5619 0 : __isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff(
5620 : __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2)
5621 : {
5622 0 : return isl_multi_aff_align_params_multi_multi_and(ma1, ma2,
5623 : &isl_multi_aff_pullback_multi_aff_aligned);
5624 : }
5625 :
5626 : /* Extend the local space of "dst" to include the divs
5627 : * in the local space of "src".
5628 : *
5629 : * If "src" does not have any divs or if the local spaces of "dst" and
5630 : * "src" are the same, then no extension is required.
5631 : */
5632 0 : __isl_give isl_aff *isl_aff_align_divs(__isl_take isl_aff *dst,
5633 : __isl_keep isl_aff *src)
5634 : {
5635 : isl_ctx *ctx;
5636 : int src_n_div, dst_n_div;
5637 0 : int *exp1 = NULL;
5638 0 : int *exp2 = NULL;
5639 : isl_bool equal;
5640 : isl_mat *div;
5641 :
5642 0 : if (!src || !dst)
5643 0 : return isl_aff_free(dst);
5644 :
5645 0 : ctx = isl_aff_get_ctx(src);
5646 0 : equal = isl_local_space_has_equal_space(src->ls, dst->ls);
5647 0 : if (equal < 0)
5648 0 : return isl_aff_free(dst);
5649 0 : if (!equal)
5650 0 : isl_die(ctx, isl_error_invalid,
5651 : "spaces don't match", goto error);
5652 :
5653 0 : src_n_div = isl_local_space_dim(src->ls, isl_dim_div);
5654 0 : if (src_n_div == 0)
5655 0 : return dst;
5656 0 : equal = isl_local_space_is_equal(src->ls, dst->ls);
5657 0 : if (equal < 0)
5658 0 : return isl_aff_free(dst);
5659 0 : if (equal)
5660 0 : return dst;
5661 :
5662 0 : dst_n_div = isl_local_space_dim(dst->ls, isl_dim_div);
5663 0 : exp1 = isl_alloc_array(ctx, int, src_n_div);
5664 0 : exp2 = isl_alloc_array(ctx, int, dst_n_div);
5665 0 : if (!exp1 || (dst_n_div && !exp2))
5666 : goto error;
5667 :
5668 0 : div = isl_merge_divs(src->ls->div, dst->ls->div, exp1, exp2);
5669 0 : dst = isl_aff_expand_divs(dst, div, exp2);
5670 0 : free(exp1);
5671 0 : free(exp2);
5672 :
5673 0 : return dst;
5674 : error:
5675 0 : free(exp1);
5676 0 : free(exp2);
5677 0 : return isl_aff_free(dst);
5678 : }
5679 :
5680 : /* Adjust the local spaces of the affine expressions in "maff"
5681 : * such that they all have the save divs.
5682 : */
5683 0 : __isl_give isl_multi_aff *isl_multi_aff_align_divs(
5684 : __isl_take isl_multi_aff *maff)
5685 : {
5686 : int i;
5687 :
5688 0 : if (!maff)
5689 0 : return NULL;
5690 0 : if (maff->n == 0)
5691 0 : return maff;
5692 0 : maff = isl_multi_aff_cow(maff);
5693 0 : if (!maff)
5694 0 : return NULL;
5695 :
5696 0 : for (i = 1; i < maff->n; ++i)
5697 0 : maff->u.p[0] = isl_aff_align_divs(maff->u.p[0], maff->u.p[i]);
5698 0 : for (i = 1; i < maff->n; ++i) {
5699 0 : maff->u.p[i] = isl_aff_align_divs(maff->u.p[i], maff->u.p[0]);
5700 0 : if (!maff->u.p[i])
5701 0 : return isl_multi_aff_free(maff);
5702 : }
5703 :
5704 0 : return maff;
5705 : }
5706 :
5707 0 : __isl_give isl_aff *isl_aff_lift(__isl_take isl_aff *aff)
5708 : {
5709 0 : aff = isl_aff_cow(aff);
5710 0 : if (!aff)
5711 0 : return NULL;
5712 :
5713 0 : aff->ls = isl_local_space_lift(aff->ls);
5714 0 : if (!aff->ls)
5715 0 : return isl_aff_free(aff);
5716 :
5717 0 : return aff;
5718 : }
5719 :
5720 : /* Lift "maff" to a space with extra dimensions such that the result
5721 : * has no more existentially quantified variables.
5722 : * If "ls" is not NULL, then *ls is assigned the local space that lies
5723 : * at the basis of the lifting applied to "maff".
5724 : */
5725 0 : __isl_give isl_multi_aff *isl_multi_aff_lift(__isl_take isl_multi_aff *maff,
5726 : __isl_give isl_local_space **ls)
5727 : {
5728 : int i;
5729 : isl_space *space;
5730 : unsigned n_div;
5731 :
5732 0 : if (ls)
5733 0 : *ls = NULL;
5734 :
5735 0 : if (!maff)
5736 0 : return NULL;
5737 :
5738 0 : if (maff->n == 0) {
5739 0 : if (ls) {
5740 0 : isl_space *space = isl_multi_aff_get_domain_space(maff);
5741 0 : *ls = isl_local_space_from_space(space);
5742 0 : if (!*ls)
5743 0 : return isl_multi_aff_free(maff);
5744 : }
5745 0 : return maff;
5746 : }
5747 :
5748 0 : maff = isl_multi_aff_cow(maff);
5749 0 : maff = isl_multi_aff_align_divs(maff);
5750 0 : if (!maff)
5751 0 : return NULL;
5752 :
5753 0 : n_div = isl_aff_dim(maff->u.p[0], isl_dim_div);
5754 0 : space = isl_multi_aff_get_space(maff);
5755 0 : space = isl_space_lift(isl_space_domain(space), n_div);
5756 0 : space = isl_space_extend_domain_with_range(space,
5757 : isl_multi_aff_get_space(maff));
5758 0 : if (!space)
5759 0 : return isl_multi_aff_free(maff);
5760 0 : isl_space_free(maff->space);
5761 0 : maff->space = space;
5762 :
5763 0 : if (ls) {
5764 0 : *ls = isl_aff_get_domain_local_space(maff->u.p[0]);
5765 0 : if (!*ls)
5766 0 : return isl_multi_aff_free(maff);
5767 : }
5768 :
5769 0 : for (i = 0; i < maff->n; ++i) {
5770 0 : maff->u.p[i] = isl_aff_lift(maff->u.p[i]);
5771 0 : if (!maff->u.p[i])
5772 0 : goto error;
5773 : }
5774 :
5775 0 : return maff;
5776 : error:
5777 0 : if (ls)
5778 0 : isl_local_space_free(*ls);
5779 0 : return isl_multi_aff_free(maff);
5780 : }
5781 :
5782 :
5783 : /* Extract an isl_pw_aff corresponding to output dimension "pos" of "pma".
5784 : */
5785 0 : __isl_give isl_pw_aff *isl_pw_multi_aff_get_pw_aff(
5786 : __isl_keep isl_pw_multi_aff *pma, int pos)
5787 : {
5788 : int i;
5789 : int n_out;
5790 : isl_space *space;
5791 : isl_pw_aff *pa;
5792 :
5793 0 : if (!pma)
5794 0 : return NULL;
5795 :
5796 0 : n_out = isl_pw_multi_aff_dim(pma, isl_dim_out);
5797 0 : if (pos < 0 || pos >= n_out)
5798 0 : isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
5799 : "index out of bounds", return NULL);
5800 :
5801 0 : space = isl_pw_multi_aff_get_space(pma);
5802 0 : space = isl_space_drop_dims(space, isl_dim_out,
5803 0 : pos + 1, n_out - pos - 1);
5804 0 : space = isl_space_drop_dims(space, isl_dim_out, 0, pos);
5805 :
5806 0 : pa = isl_pw_aff_alloc_size(space, pma->n);
5807 0 : for (i = 0; i < pma->n; ++i) {
5808 : isl_aff *aff;
5809 0 : aff = isl_multi_aff_get_aff(pma->p[i].maff, pos);
5810 0 : pa = isl_pw_aff_add_piece(pa, isl_set_copy(pma->p[i].set), aff);
5811 : }
5812 :
5813 0 : return pa;
5814 : }
5815 :
5816 : /* Return an isl_pw_multi_aff with the given "set" as domain and
5817 : * an unnamed zero-dimensional range.
5818 : */
5819 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_domain(
5820 : __isl_take isl_set *set)
5821 : {
5822 : isl_multi_aff *ma;
5823 : isl_space *space;
5824 :
5825 0 : space = isl_set_get_space(set);
5826 0 : space = isl_space_from_domain(space);
5827 0 : ma = isl_multi_aff_zero(space);
5828 0 : return isl_pw_multi_aff_alloc(set, ma);
5829 : }
5830 :
5831 : /* Add an isl_pw_multi_aff with the given "set" as domain and
5832 : * an unnamed zero-dimensional range to *user.
5833 : */
5834 0 : static isl_stat add_pw_multi_aff_from_domain(__isl_take isl_set *set,
5835 : void *user)
5836 : {
5837 0 : isl_union_pw_multi_aff **upma = user;
5838 : isl_pw_multi_aff *pma;
5839 :
5840 0 : pma = isl_pw_multi_aff_from_domain(set);
5841 0 : *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma);
5842 :
5843 0 : return isl_stat_ok;
5844 : }
5845 :
5846 : /* Return an isl_union_pw_multi_aff with the given "uset" as domain and
5847 : * an unnamed zero-dimensional range.
5848 : */
5849 0 : __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_domain(
5850 : __isl_take isl_union_set *uset)
5851 : {
5852 : isl_space *space;
5853 : isl_union_pw_multi_aff *upma;
5854 :
5855 0 : if (!uset)
5856 0 : return NULL;
5857 :
5858 0 : space = isl_union_set_get_space(uset);
5859 0 : upma = isl_union_pw_multi_aff_empty(space);
5860 :
5861 0 : if (isl_union_set_foreach_set(uset,
5862 : &add_pw_multi_aff_from_domain, &upma) < 0)
5863 0 : goto error;
5864 :
5865 0 : isl_union_set_free(uset);
5866 0 : return upma;
5867 : error:
5868 0 : isl_union_set_free(uset);
5869 0 : isl_union_pw_multi_aff_free(upma);
5870 0 : return NULL;
5871 : }
5872 :
5873 : /* Local data for bin_entry and the callback "fn".
5874 : */
5875 : struct isl_union_pw_multi_aff_bin_data {
5876 : isl_union_pw_multi_aff *upma2;
5877 : isl_union_pw_multi_aff *res;
5878 : isl_pw_multi_aff *pma;
5879 : isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, void *user);
5880 : };
5881 :
5882 : /* Given an isl_pw_multi_aff from upma1, store it in data->pma
5883 : * and call data->fn for each isl_pw_multi_aff in data->upma2.
5884 : */
5885 0 : static isl_stat bin_entry(__isl_take isl_pw_multi_aff *pma, void *user)
5886 : {
5887 0 : struct isl_union_pw_multi_aff_bin_data *data = user;
5888 : isl_stat r;
5889 :
5890 0 : data->pma = pma;
5891 0 : r = isl_union_pw_multi_aff_foreach_pw_multi_aff(data->upma2,
5892 : data->fn, data);
5893 0 : isl_pw_multi_aff_free(pma);
5894 :
5895 0 : return r;
5896 : }
5897 :
5898 : /* Call "fn" on each pair of isl_pw_multi_affs in "upma1" and "upma2".
5899 : * The isl_pw_multi_aff from upma1 is stored in data->pma (where data is
5900 : * passed as user field) and the isl_pw_multi_aff from upma2 is available
5901 : * as *entry. The callback should adjust data->res if desired.
5902 : */
5903 0 : static __isl_give isl_union_pw_multi_aff *bin_op(
5904 : __isl_take isl_union_pw_multi_aff *upma1,
5905 : __isl_take isl_union_pw_multi_aff *upma2,
5906 : isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, void *user))
5907 : {
5908 : isl_space *space;
5909 0 : struct isl_union_pw_multi_aff_bin_data data = { NULL, NULL, NULL, fn };
5910 :
5911 0 : space = isl_union_pw_multi_aff_get_space(upma2);
5912 0 : upma1 = isl_union_pw_multi_aff_align_params(upma1, space);
5913 0 : space = isl_union_pw_multi_aff_get_space(upma1);
5914 0 : upma2 = isl_union_pw_multi_aff_align_params(upma2, space);
5915 :
5916 0 : if (!upma1 || !upma2)
5917 : goto error;
5918 :
5919 0 : data.upma2 = upma2;
5920 0 : data.res = isl_union_pw_multi_aff_alloc_same_size(upma1);
5921 0 : if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma1,
5922 : &bin_entry, &data) < 0)
5923 0 : goto error;
5924 :
5925 0 : isl_union_pw_multi_aff_free(upma1);
5926 0 : isl_union_pw_multi_aff_free(upma2);
5927 0 : return data.res;
5928 : error:
5929 0 : isl_union_pw_multi_aff_free(upma1);
5930 0 : isl_union_pw_multi_aff_free(upma2);
5931 0 : isl_union_pw_multi_aff_free(data.res);
5932 0 : return NULL;
5933 : }
5934 :
5935 : /* Given two aligned isl_pw_multi_affs A -> B and C -> D,
5936 : * construct an isl_pw_multi_aff (A * C) -> [B -> D].
5937 : */
5938 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_range_product(
5939 : __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
5940 : {
5941 : isl_space *space;
5942 :
5943 0 : space = isl_space_range_product(isl_pw_multi_aff_get_space(pma1),
5944 : isl_pw_multi_aff_get_space(pma2));
5945 0 : return isl_pw_multi_aff_on_shared_domain_in(pma1, pma2, space,
5946 : &isl_multi_aff_range_product);
5947 : }
5948 :
5949 : /* Given two isl_pw_multi_affs A -> B and C -> D,
5950 : * construct an isl_pw_multi_aff (A * C) -> [B -> D].
5951 : */
5952 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_product(
5953 : __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
5954 : {
5955 0 : return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
5956 : &pw_multi_aff_range_product);
5957 : }
5958 :
5959 : /* Given two aligned isl_pw_multi_affs A -> B and C -> D,
5960 : * construct an isl_pw_multi_aff (A * C) -> (B, D).
5961 : */
5962 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_flat_range_product(
5963 : __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
5964 : {
5965 : isl_space *space;
5966 :
5967 0 : space = isl_space_range_product(isl_pw_multi_aff_get_space(pma1),
5968 : isl_pw_multi_aff_get_space(pma2));
5969 0 : space = isl_space_flatten_range(space);
5970 0 : return isl_pw_multi_aff_on_shared_domain_in(pma1, pma2, space,
5971 : &isl_multi_aff_flat_range_product);
5972 : }
5973 :
5974 : /* Given two isl_pw_multi_affs A -> B and C -> D,
5975 : * construct an isl_pw_multi_aff (A * C) -> (B, D).
5976 : */
5977 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_flat_range_product(
5978 : __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
5979 : {
5980 0 : return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
5981 : &pw_multi_aff_flat_range_product);
5982 : }
5983 :
5984 : /* If data->pma and "pma2" have the same domain space, then compute
5985 : * their flat range product and the result to data->res.
5986 : */
5987 0 : static isl_stat flat_range_product_entry(__isl_take isl_pw_multi_aff *pma2,
5988 : void *user)
5989 : {
5990 0 : struct isl_union_pw_multi_aff_bin_data *data = user;
5991 :
5992 0 : if (!isl_space_tuple_is_equal(data->pma->dim, isl_dim_in,
5993 : pma2->dim, isl_dim_in)) {
5994 0 : isl_pw_multi_aff_free(pma2);
5995 0 : return isl_stat_ok;
5996 : }
5997 :
5998 0 : pma2 = isl_pw_multi_aff_flat_range_product(
5999 : isl_pw_multi_aff_copy(data->pma), pma2);
6000 :
6001 0 : data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma2);
6002 :
6003 0 : return isl_stat_ok;
6004 : }
6005 :
6006 : /* Given two isl_union_pw_multi_affs A -> B and C -> D,
6007 : * construct an isl_union_pw_multi_aff (A * C) -> (B, D).
6008 : */
6009 0 : __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_flat_range_product(
6010 : __isl_take isl_union_pw_multi_aff *upma1,
6011 : __isl_take isl_union_pw_multi_aff *upma2)
6012 : {
6013 0 : return bin_op(upma1, upma2, &flat_range_product_entry);
6014 : }
6015 :
6016 : /* Replace the affine expressions at position "pos" in "pma" by "pa".
6017 : * The parameters are assumed to have been aligned.
6018 : *
6019 : * The implementation essentially performs an isl_pw_*_on_shared_domain,
6020 : * except that it works on two different isl_pw_* types.
6021 : */
6022 0 : static __isl_give isl_pw_multi_aff *pw_multi_aff_set_pw_aff(
6023 : __isl_take isl_pw_multi_aff *pma, unsigned pos,
6024 : __isl_take isl_pw_aff *pa)
6025 : {
6026 : int i, j, n;
6027 0 : isl_pw_multi_aff *res = NULL;
6028 :
6029 0 : if (!pma || !pa)
6030 : goto error;
6031 :
6032 0 : if (!isl_space_tuple_is_equal(pma->dim, isl_dim_in,
6033 : pa->dim, isl_dim_in))
6034 0 : isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
6035 : "domains don't match", goto error);
6036 0 : if (pos >= isl_pw_multi_aff_dim(pma, isl_dim_out))
6037 0 : isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
6038 : "index out of bounds", goto error);
6039 :
6040 0 : n = pma->n * pa->n;
6041 0 : res = isl_pw_multi_aff_alloc_size(isl_pw_multi_aff_get_space(pma), n);
6042 :
6043 0 : for (i = 0; i < pma->n; ++i) {
6044 0 : for (j = 0; j < pa->n; ++j) {
6045 : isl_set *common;
6046 : isl_multi_aff *res_ij;
6047 : int empty;
6048 :
6049 0 : common = isl_set_intersect(isl_set_copy(pma->p[i].set),
6050 0 : isl_set_copy(pa->p[j].set));
6051 0 : empty = isl_set_plain_is_empty(common);
6052 0 : if (empty < 0 || empty) {
6053 0 : isl_set_free(common);
6054 0 : if (empty < 0)
6055 0 : goto error;
6056 0 : continue;
6057 : }
6058 :
6059 0 : res_ij = isl_multi_aff_set_aff(
6060 : isl_multi_aff_copy(pma->p[i].maff), pos,
6061 0 : isl_aff_copy(pa->p[j].aff));
6062 0 : res_ij = isl_multi_aff_gist(res_ij,
6063 : isl_set_copy(common));
6064 :
6065 0 : res = isl_pw_multi_aff_add_piece(res, common, res_ij);
6066 : }
6067 : }
6068 :
6069 0 : isl_pw_multi_aff_free(pma);
6070 0 : isl_pw_aff_free(pa);
6071 0 : return res;
6072 : error:
6073 0 : isl_pw_multi_aff_free(pma);
6074 0 : isl_pw_aff_free(pa);
6075 0 : return isl_pw_multi_aff_free(res);
6076 : }
6077 :
6078 : /* Replace the affine expressions at position "pos" in "pma" by "pa".
6079 : */
6080 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_pw_aff(
6081 : __isl_take isl_pw_multi_aff *pma, unsigned pos,
6082 : __isl_take isl_pw_aff *pa)
6083 : {
6084 : isl_bool equal_params;
6085 :
6086 0 : if (!pma || !pa)
6087 : goto error;
6088 0 : equal_params = isl_space_has_equal_params(pma->dim, pa->dim);
6089 0 : if (equal_params < 0)
6090 0 : goto error;
6091 0 : if (equal_params)
6092 0 : return pw_multi_aff_set_pw_aff(pma, pos, pa);
6093 0 : if (isl_pw_multi_aff_check_named_params(pma) < 0 ||
6094 0 : isl_pw_aff_check_named_params(pa) < 0)
6095 : goto error;
6096 0 : pma = isl_pw_multi_aff_align_params(pma, isl_pw_aff_get_space(pa));
6097 0 : pa = isl_pw_aff_align_params(pa, isl_pw_multi_aff_get_space(pma));
6098 0 : return pw_multi_aff_set_pw_aff(pma, pos, pa);
6099 : error:
6100 0 : isl_pw_multi_aff_free(pma);
6101 0 : isl_pw_aff_free(pa);
6102 0 : return NULL;
6103 : }
6104 :
6105 : /* Do the parameters of "pa" match those of "space"?
6106 : */
6107 0 : isl_bool isl_pw_aff_matching_params(__isl_keep isl_pw_aff *pa,
6108 : __isl_keep isl_space *space)
6109 : {
6110 : isl_space *pa_space;
6111 : isl_bool match;
6112 :
6113 0 : if (!pa || !space)
6114 0 : return isl_bool_error;
6115 :
6116 0 : pa_space = isl_pw_aff_get_space(pa);
6117 :
6118 0 : match = isl_space_has_equal_params(space, pa_space);
6119 :
6120 0 : isl_space_free(pa_space);
6121 0 : return match;
6122 : }
6123 :
6124 : /* Check that the domain space of "pa" matches "space".
6125 : */
6126 0 : isl_stat isl_pw_aff_check_match_domain_space(__isl_keep isl_pw_aff *pa,
6127 : __isl_keep isl_space *space)
6128 : {
6129 : isl_space *pa_space;
6130 : isl_bool match;
6131 :
6132 0 : if (!pa || !space)
6133 0 : return isl_stat_error;
6134 :
6135 0 : pa_space = isl_pw_aff_get_space(pa);
6136 :
6137 0 : match = isl_space_has_equal_params(space, pa_space);
6138 0 : if (match < 0)
6139 0 : goto error;
6140 0 : if (!match)
6141 0 : isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
6142 : "parameters don't match", goto error);
6143 0 : match = isl_space_tuple_is_equal(space, isl_dim_in,
6144 : pa_space, isl_dim_in);
6145 0 : if (match < 0)
6146 0 : goto error;
6147 0 : if (!match)
6148 0 : isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
6149 : "domains don't match", goto error);
6150 0 : isl_space_free(pa_space);
6151 0 : return isl_stat_ok;
6152 : error:
6153 0 : isl_space_free(pa_space);
6154 0 : return isl_stat_error;
6155 : }
6156 :
6157 : #undef BASE
6158 : #define BASE pw_aff
6159 : #undef DOMBASE
6160 : #define DOMBASE set
6161 :
6162 : #include <isl_multi_explicit_domain.c>
6163 : #include <isl_multi_pw_aff_explicit_domain.c>
6164 : #include <isl_multi_templ.c>
6165 : #include <isl_multi_apply_set.c>
6166 : #include <isl_multi_coalesce.c>
6167 : #include <isl_multi_dims.c>
6168 : #include <isl_multi_gist.c>
6169 : #include <isl_multi_hash.c>
6170 : #include <isl_multi_align_set.c>
6171 : #include <isl_multi_intersect.c>
6172 :
6173 : /* Does "mpa" have a non-trivial explicit domain?
6174 : *
6175 : * The explicit domain, if present, is trivial if it represents
6176 : * an (obviously) universe set.
6177 : */
6178 0 : isl_bool isl_multi_pw_aff_has_non_trivial_domain(
6179 : __isl_keep isl_multi_pw_aff *mpa)
6180 : {
6181 0 : if (!mpa)
6182 0 : return isl_bool_error;
6183 0 : if (!isl_multi_pw_aff_has_explicit_domain(mpa))
6184 0 : return isl_bool_false;
6185 0 : return isl_bool_not(isl_set_plain_is_universe(mpa->u.dom));
6186 : }
6187 :
6188 : /* Scale the elements of "pma" by the corresponding elements of "mv".
6189 : */
6190 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_multi_val(
6191 : __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv)
6192 : {
6193 : int i;
6194 : isl_bool equal_params;
6195 :
6196 0 : pma = isl_pw_multi_aff_cow(pma);
6197 0 : if (!pma || !mv)
6198 : goto error;
6199 0 : if (!isl_space_tuple_is_equal(pma->dim, isl_dim_out,
6200 : mv->space, isl_dim_set))
6201 0 : isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
6202 : "spaces don't match", goto error);
6203 0 : equal_params = isl_space_has_equal_params(pma->dim, mv->space);
6204 0 : if (equal_params < 0)
6205 0 : goto error;
6206 0 : if (!equal_params) {
6207 0 : pma = isl_pw_multi_aff_align_params(pma,
6208 : isl_multi_val_get_space(mv));
6209 0 : mv = isl_multi_val_align_params(mv,
6210 : isl_pw_multi_aff_get_space(pma));
6211 0 : if (!pma || !mv)
6212 : goto error;
6213 : }
6214 :
6215 0 : for (i = 0; i < pma->n; ++i) {
6216 0 : pma->p[i].maff = isl_multi_aff_scale_multi_val(pma->p[i].maff,
6217 : isl_multi_val_copy(mv));
6218 0 : if (!pma->p[i].maff)
6219 0 : goto error;
6220 : }
6221 :
6222 0 : isl_multi_val_free(mv);
6223 0 : return pma;
6224 : error:
6225 0 : isl_multi_val_free(mv);
6226 0 : isl_pw_multi_aff_free(pma);
6227 0 : return NULL;
6228 : }
6229 :
6230 : /* This function is called for each entry of an isl_union_pw_multi_aff.
6231 : * If the space of the entry matches that of data->mv,
6232 : * then apply isl_pw_multi_aff_scale_multi_val and return the result.
6233 : * Otherwise, return an empty isl_pw_multi_aff.
6234 : */
6235 0 : static __isl_give isl_pw_multi_aff *union_pw_multi_aff_scale_multi_val_entry(
6236 : __isl_take isl_pw_multi_aff *pma, void *user)
6237 : {
6238 0 : isl_multi_val *mv = user;
6239 :
6240 0 : if (!pma)
6241 0 : return NULL;
6242 0 : if (!isl_space_tuple_is_equal(pma->dim, isl_dim_out,
6243 : mv->space, isl_dim_set)) {
6244 0 : isl_space *space = isl_pw_multi_aff_get_space(pma);
6245 0 : isl_pw_multi_aff_free(pma);
6246 0 : return isl_pw_multi_aff_empty(space);
6247 : }
6248 :
6249 0 : return isl_pw_multi_aff_scale_multi_val(pma, isl_multi_val_copy(mv));
6250 : }
6251 :
6252 : /* Scale the elements of "upma" by the corresponding elements of "mv",
6253 : * for those entries that match the space of "mv".
6254 : */
6255 0 : __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_multi_val(
6256 : __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_multi_val *mv)
6257 : {
6258 0 : upma = isl_union_pw_multi_aff_align_params(upma,
6259 : isl_multi_val_get_space(mv));
6260 0 : mv = isl_multi_val_align_params(mv,
6261 : isl_union_pw_multi_aff_get_space(upma));
6262 0 : if (!upma || !mv)
6263 : goto error;
6264 :
6265 0 : return isl_union_pw_multi_aff_transform(upma,
6266 : &union_pw_multi_aff_scale_multi_val_entry, mv);
6267 :
6268 : isl_multi_val_free(mv);
6269 : return upma;
6270 : error:
6271 0 : isl_multi_val_free(mv);
6272 0 : isl_union_pw_multi_aff_free(upma);
6273 0 : return NULL;
6274 : }
6275 :
6276 : /* Construct and return a piecewise multi affine expression
6277 : * in the given space with value zero in each of the output dimensions and
6278 : * a universe domain.
6279 : */
6280 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_zero(__isl_take isl_space *space)
6281 : {
6282 0 : return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_zero(space));
6283 : }
6284 :
6285 : /* Construct and return a piecewise multi affine expression
6286 : * that is equal to the given piecewise affine expression.
6287 : */
6288 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_pw_aff(
6289 : __isl_take isl_pw_aff *pa)
6290 : {
6291 : int i;
6292 : isl_space *space;
6293 : isl_pw_multi_aff *pma;
6294 :
6295 0 : if (!pa)
6296 0 : return NULL;
6297 :
6298 0 : space = isl_pw_aff_get_space(pa);
6299 0 : pma = isl_pw_multi_aff_alloc_size(space, pa->n);
6300 :
6301 0 : for (i = 0; i < pa->n; ++i) {
6302 : isl_set *set;
6303 : isl_multi_aff *ma;
6304 :
6305 0 : set = isl_set_copy(pa->p[i].set);
6306 0 : ma = isl_multi_aff_from_aff(isl_aff_copy(pa->p[i].aff));
6307 0 : pma = isl_pw_multi_aff_add_piece(pma, set, ma);
6308 : }
6309 :
6310 0 : isl_pw_aff_free(pa);
6311 0 : return pma;
6312 : }
6313 :
6314 : /* Construct and return a piecewise multi affine expression
6315 : * that is equal to the given multi piecewise affine expression
6316 : * on the shared domain of the piecewise affine expressions,
6317 : * in the special case of a 0D multi piecewise affine expression.
6318 : *
6319 : * Create a piecewise multi affine expression with the explicit domain of
6320 : * the 0D multi piecewise affine expression as domain.
6321 : */
6322 0 : static __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_pw_aff_0D(
6323 : __isl_take isl_multi_pw_aff *mpa)
6324 : {
6325 : isl_space *space;
6326 : isl_set *dom;
6327 : isl_multi_aff *ma;
6328 :
6329 0 : space = isl_multi_pw_aff_get_space(mpa);
6330 0 : dom = isl_multi_pw_aff_get_explicit_domain(mpa);
6331 0 : isl_multi_pw_aff_free(mpa);
6332 :
6333 0 : ma = isl_multi_aff_zero(space);
6334 0 : return isl_pw_multi_aff_alloc(dom, ma);
6335 : }
6336 :
6337 : /* Construct and return a piecewise multi affine expression
6338 : * that is equal to the given multi piecewise affine expression
6339 : * on the shared domain of the piecewise affine expressions.
6340 : */
6341 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_pw_aff(
6342 : __isl_take isl_multi_pw_aff *mpa)
6343 : {
6344 : int i;
6345 : isl_space *space;
6346 : isl_pw_aff *pa;
6347 : isl_pw_multi_aff *pma;
6348 :
6349 0 : if (!mpa)
6350 0 : return NULL;
6351 :
6352 0 : if (mpa->n == 0)
6353 0 : return isl_pw_multi_aff_from_multi_pw_aff_0D(mpa);
6354 :
6355 0 : space = isl_multi_pw_aff_get_space(mpa);
6356 0 : pa = isl_multi_pw_aff_get_pw_aff(mpa, 0);
6357 0 : pma = isl_pw_multi_aff_from_pw_aff(pa);
6358 :
6359 0 : for (i = 1; i < mpa->n; ++i) {
6360 : isl_pw_multi_aff *pma_i;
6361 :
6362 0 : pa = isl_multi_pw_aff_get_pw_aff(mpa, i);
6363 0 : pma_i = isl_pw_multi_aff_from_pw_aff(pa);
6364 0 : pma = isl_pw_multi_aff_range_product(pma, pma_i);
6365 : }
6366 :
6367 0 : pma = isl_pw_multi_aff_reset_space(pma, space);
6368 :
6369 0 : isl_multi_pw_aff_free(mpa);
6370 0 : return pma;
6371 : }
6372 :
6373 : /* Construct and return a multi piecewise affine expression
6374 : * that is equal to the given multi affine expression.
6375 : */
6376 0 : __isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_multi_aff(
6377 : __isl_take isl_multi_aff *ma)
6378 : {
6379 : int i, n;
6380 : isl_multi_pw_aff *mpa;
6381 :
6382 0 : if (!ma)
6383 0 : return NULL;
6384 :
6385 0 : n = isl_multi_aff_dim(ma, isl_dim_out);
6386 0 : mpa = isl_multi_pw_aff_alloc(isl_multi_aff_get_space(ma));
6387 :
6388 0 : for (i = 0; i < n; ++i) {
6389 : isl_pw_aff *pa;
6390 :
6391 0 : pa = isl_pw_aff_from_aff(isl_multi_aff_get_aff(ma, i));
6392 0 : mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);
6393 : }
6394 :
6395 0 : isl_multi_aff_free(ma);
6396 0 : return mpa;
6397 : }
6398 :
6399 : /* Construct and return a multi piecewise affine expression
6400 : * that is equal to the given piecewise multi affine expression.
6401 : *
6402 : * If the resulting multi piecewise affine expression has
6403 : * an explicit domain, then assign it the domain of the input.
6404 : * In other cases, the domain is stored in the individual elements.
6405 : */
6406 0 : __isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_multi_aff(
6407 : __isl_take isl_pw_multi_aff *pma)
6408 : {
6409 : int i, n;
6410 : isl_space *space;
6411 : isl_multi_pw_aff *mpa;
6412 :
6413 0 : if (!pma)
6414 0 : return NULL;
6415 :
6416 0 : n = isl_pw_multi_aff_dim(pma, isl_dim_out);
6417 0 : space = isl_pw_multi_aff_get_space(pma);
6418 0 : mpa = isl_multi_pw_aff_alloc(space);
6419 :
6420 0 : for (i = 0; i < n; ++i) {
6421 : isl_pw_aff *pa;
6422 :
6423 0 : pa = isl_pw_multi_aff_get_pw_aff(pma, i);
6424 0 : mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);
6425 : }
6426 0 : if (isl_multi_pw_aff_has_explicit_domain(mpa)) {
6427 : isl_set *dom;
6428 :
6429 0 : dom = isl_pw_multi_aff_domain(isl_pw_multi_aff_copy(pma));
6430 0 : mpa = isl_multi_pw_aff_intersect_domain(mpa, dom);
6431 : }
6432 :
6433 0 : isl_pw_multi_aff_free(pma);
6434 0 : return mpa;
6435 : }
6436 :
6437 : /* Do "pa1" and "pa2" represent the same function?
6438 : *
6439 : * We first check if they are obviously equal.
6440 : * If not, we convert them to maps and check if those are equal.
6441 : *
6442 : * If "pa1" or "pa2" contain any NaNs, then they are considered
6443 : * not to be the same. A NaN is not equal to anything, not even
6444 : * to another NaN.
6445 : */
6446 0 : isl_bool isl_pw_aff_is_equal(__isl_keep isl_pw_aff *pa1,
6447 : __isl_keep isl_pw_aff *pa2)
6448 : {
6449 : isl_bool equal;
6450 : isl_bool has_nan;
6451 : isl_map *map1, *map2;
6452 :
6453 0 : if (!pa1 || !pa2)
6454 0 : return isl_bool_error;
6455 :
6456 0 : equal = isl_pw_aff_plain_is_equal(pa1, pa2);
6457 0 : if (equal < 0 || equal)
6458 0 : return equal;
6459 0 : has_nan = either_involves_nan(pa1, pa2);
6460 0 : if (has_nan < 0)
6461 0 : return isl_bool_error;
6462 0 : if (has_nan)
6463 0 : return isl_bool_false;
6464 :
6465 0 : map1 = isl_map_from_pw_aff_internal(isl_pw_aff_copy(pa1));
6466 0 : map2 = isl_map_from_pw_aff_internal(isl_pw_aff_copy(pa2));
6467 0 : equal = isl_map_is_equal(map1, map2);
6468 0 : isl_map_free(map1);
6469 0 : isl_map_free(map2);
6470 :
6471 0 : return equal;
6472 : }
6473 :
6474 : /* Do "mpa1" and "mpa2" represent the same function?
6475 : *
6476 : * Note that we cannot convert the entire isl_multi_pw_aff
6477 : * to a map because the domains of the piecewise affine expressions
6478 : * may not be the same.
6479 : */
6480 0 : isl_bool isl_multi_pw_aff_is_equal(__isl_keep isl_multi_pw_aff *mpa1,
6481 : __isl_keep isl_multi_pw_aff *mpa2)
6482 : {
6483 : int i;
6484 : isl_bool equal, equal_params;
6485 :
6486 0 : if (!mpa1 || !mpa2)
6487 0 : return isl_bool_error;
6488 :
6489 0 : equal_params = isl_space_has_equal_params(mpa1->space, mpa2->space);
6490 0 : if (equal_params < 0)
6491 0 : return isl_bool_error;
6492 0 : if (!equal_params) {
6493 0 : if (!isl_space_has_named_params(mpa1->space))
6494 0 : return isl_bool_false;
6495 0 : if (!isl_space_has_named_params(mpa2->space))
6496 0 : return isl_bool_false;
6497 0 : mpa1 = isl_multi_pw_aff_copy(mpa1);
6498 0 : mpa2 = isl_multi_pw_aff_copy(mpa2);
6499 0 : mpa1 = isl_multi_pw_aff_align_params(mpa1,
6500 : isl_multi_pw_aff_get_space(mpa2));
6501 0 : mpa2 = isl_multi_pw_aff_align_params(mpa2,
6502 : isl_multi_pw_aff_get_space(mpa1));
6503 0 : equal = isl_multi_pw_aff_is_equal(mpa1, mpa2);
6504 0 : isl_multi_pw_aff_free(mpa1);
6505 0 : isl_multi_pw_aff_free(mpa2);
6506 0 : return equal;
6507 : }
6508 :
6509 0 : equal = isl_space_is_equal(mpa1->space, mpa2->space);
6510 0 : if (equal < 0 || !equal)
6511 0 : return equal;
6512 :
6513 0 : for (i = 0; i < mpa1->n; ++i) {
6514 0 : equal = isl_pw_aff_is_equal(mpa1->u.p[i], mpa2->u.p[i]);
6515 0 : if (equal < 0 || !equal)
6516 0 : return equal;
6517 : }
6518 :
6519 0 : return isl_bool_true;
6520 : }
6521 :
6522 : /* Do "pma1" and "pma2" represent the same function?
6523 : *
6524 : * First check if they are obviously equal.
6525 : * If not, then convert them to maps and check if those are equal.
6526 : *
6527 : * If "pa1" or "pa2" contain any NaNs, then they are considered
6528 : * not to be the same. A NaN is not equal to anything, not even
6529 : * to another NaN.
6530 : */
6531 0 : isl_bool isl_pw_multi_aff_is_equal(__isl_keep isl_pw_multi_aff *pma1,
6532 : __isl_keep isl_pw_multi_aff *pma2)
6533 : {
6534 : isl_bool equal;
6535 : isl_bool has_nan;
6536 : isl_map *map1, *map2;
6537 :
6538 0 : if (!pma1 || !pma2)
6539 0 : return isl_bool_error;
6540 :
6541 0 : equal = isl_pw_multi_aff_plain_is_equal(pma1, pma2);
6542 0 : if (equal < 0 || equal)
6543 0 : return equal;
6544 0 : has_nan = isl_pw_multi_aff_involves_nan(pma1);
6545 0 : if (has_nan >= 0 && !has_nan)
6546 0 : has_nan = isl_pw_multi_aff_involves_nan(pma2);
6547 0 : if (has_nan < 0 || has_nan)
6548 0 : return isl_bool_not(has_nan);
6549 :
6550 0 : map1 = isl_map_from_pw_multi_aff(isl_pw_multi_aff_copy(pma1));
6551 0 : map2 = isl_map_from_pw_multi_aff(isl_pw_multi_aff_copy(pma2));
6552 0 : equal = isl_map_is_equal(map1, map2);
6553 0 : isl_map_free(map1);
6554 0 : isl_map_free(map2);
6555 :
6556 0 : return equal;
6557 : }
6558 :
6559 : /* Compute the pullback of "mpa" by the function represented by "ma".
6560 : * In other words, plug in "ma" in "mpa".
6561 : *
6562 : * The parameters of "mpa" and "ma" are assumed to have been aligned.
6563 : *
6564 : * If "mpa" has an explicit domain, then it is this domain
6565 : * that needs to undergo a pullback, i.e., a preimage.
6566 : */
6567 0 : static __isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_aff_aligned(
6568 : __isl_take isl_multi_pw_aff *mpa, __isl_take isl_multi_aff *ma)
6569 : {
6570 : int i;
6571 0 : isl_space *space = NULL;
6572 :
6573 0 : mpa = isl_multi_pw_aff_cow(mpa);
6574 0 : if (!mpa || !ma)
6575 : goto error;
6576 :
6577 0 : space = isl_space_join(isl_multi_aff_get_space(ma),
6578 : isl_multi_pw_aff_get_space(mpa));
6579 0 : if (!space)
6580 0 : goto error;
6581 :
6582 0 : for (i = 0; i < mpa->n; ++i) {
6583 0 : mpa->u.p[i] = isl_pw_aff_pullback_multi_aff(mpa->u.p[i],
6584 : isl_multi_aff_copy(ma));
6585 0 : if (!mpa->u.p[i])
6586 0 : goto error;
6587 : }
6588 0 : if (isl_multi_pw_aff_has_explicit_domain(mpa)) {
6589 0 : mpa->u.dom = isl_set_preimage_multi_aff(mpa->u.dom,
6590 : isl_multi_aff_copy(ma));
6591 0 : if (!mpa->u.dom)
6592 0 : goto error;
6593 : }
6594 :
6595 0 : isl_multi_aff_free(ma);
6596 0 : isl_space_free(mpa->space);
6597 0 : mpa->space = space;
6598 0 : return mpa;
6599 : error:
6600 0 : isl_space_free(space);
6601 0 : isl_multi_pw_aff_free(mpa);
6602 0 : isl_multi_aff_free(ma);
6603 0 : return NULL;
6604 : }
6605 :
6606 : /* Compute the pullback of "mpa" by the function represented by "ma".
6607 : * In other words, plug in "ma" in "mpa".
6608 : */
6609 0 : __isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_aff(
6610 : __isl_take isl_multi_pw_aff *mpa, __isl_take isl_multi_aff *ma)
6611 : {
6612 : isl_bool equal_params;
6613 :
6614 0 : if (!mpa || !ma)
6615 : goto error;
6616 0 : equal_params = isl_space_has_equal_params(mpa->space, ma->space);
6617 0 : if (equal_params < 0)
6618 0 : goto error;
6619 0 : if (equal_params)
6620 0 : return isl_multi_pw_aff_pullback_multi_aff_aligned(mpa, ma);
6621 0 : mpa = isl_multi_pw_aff_align_params(mpa, isl_multi_aff_get_space(ma));
6622 0 : ma = isl_multi_aff_align_params(ma, isl_multi_pw_aff_get_space(mpa));
6623 0 : return isl_multi_pw_aff_pullback_multi_aff_aligned(mpa, ma);
6624 : error:
6625 0 : isl_multi_pw_aff_free(mpa);
6626 0 : isl_multi_aff_free(ma);
6627 0 : return NULL;
6628 : }
6629 :
6630 : /* Compute the pullback of "mpa" by the function represented by "pma".
6631 : * In other words, plug in "pma" in "mpa".
6632 : *
6633 : * The parameters of "mpa" and "mpa" are assumed to have been aligned.
6634 : *
6635 : * If "mpa" has an explicit domain, then it is this domain
6636 : * that needs to undergo a pullback, i.e., a preimage.
6637 : */
6638 : static __isl_give isl_multi_pw_aff *
6639 0 : isl_multi_pw_aff_pullback_pw_multi_aff_aligned(
6640 : __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_multi_aff *pma)
6641 : {
6642 : int i;
6643 0 : isl_space *space = NULL;
6644 :
6645 0 : mpa = isl_multi_pw_aff_cow(mpa);
6646 0 : if (!mpa || !pma)
6647 : goto error;
6648 :
6649 0 : space = isl_space_join(isl_pw_multi_aff_get_space(pma),
6650 : isl_multi_pw_aff_get_space(mpa));
6651 :
6652 0 : for (i = 0; i < mpa->n; ++i) {
6653 0 : mpa->u.p[i] = isl_pw_aff_pullback_pw_multi_aff_aligned(
6654 : mpa->u.p[i], isl_pw_multi_aff_copy(pma));
6655 0 : if (!mpa->u.p[i])
6656 0 : goto error;
6657 : }
6658 0 : if (isl_multi_pw_aff_has_explicit_domain(mpa)) {
6659 0 : mpa->u.dom = isl_set_preimage_pw_multi_aff(mpa->u.dom,
6660 : isl_pw_multi_aff_copy(pma));
6661 0 : if (!mpa->u.dom)
6662 0 : goto error;
6663 : }
6664 :
6665 0 : isl_pw_multi_aff_free(pma);
6666 0 : isl_space_free(mpa->space);
6667 0 : mpa->space = space;
6668 0 : return mpa;
6669 : error:
6670 0 : isl_space_free(space);
6671 0 : isl_multi_pw_aff_free(mpa);
6672 0 : isl_pw_multi_aff_free(pma);
6673 0 : return NULL;
6674 : }
6675 :
6676 : /* Compute the pullback of "mpa" by the function represented by "pma".
6677 : * In other words, plug in "pma" in "mpa".
6678 : */
6679 0 : __isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_pw_multi_aff(
6680 : __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_multi_aff *pma)
6681 : {
6682 : isl_bool equal_params;
6683 :
6684 0 : if (!mpa || !pma)
6685 : goto error;
6686 0 : equal_params = isl_space_has_equal_params(mpa->space, pma->dim);
6687 0 : if (equal_params < 0)
6688 0 : goto error;
6689 0 : if (equal_params)
6690 0 : return isl_multi_pw_aff_pullback_pw_multi_aff_aligned(mpa, pma);
6691 0 : mpa = isl_multi_pw_aff_align_params(mpa,
6692 : isl_pw_multi_aff_get_space(pma));
6693 0 : pma = isl_pw_multi_aff_align_params(pma,
6694 : isl_multi_pw_aff_get_space(mpa));
6695 0 : return isl_multi_pw_aff_pullback_pw_multi_aff_aligned(mpa, pma);
6696 : error:
6697 0 : isl_multi_pw_aff_free(mpa);
6698 0 : isl_pw_multi_aff_free(pma);
6699 0 : return NULL;
6700 : }
6701 :
6702 : /* Apply "aff" to "mpa". The range of "mpa" needs to be compatible
6703 : * with the domain of "aff". The domain of the result is the same
6704 : * as that of "mpa".
6705 : * "mpa" and "aff" are assumed to have been aligned.
6706 : *
6707 : * We first extract the parametric constant from "aff", defined
6708 : * over the correct domain.
6709 : * Then we add the appropriate combinations of the members of "mpa".
6710 : * Finally, we add the integer divisions through recursive calls.
6711 : */
6712 0 : static __isl_give isl_pw_aff *isl_multi_pw_aff_apply_aff_aligned(
6713 : __isl_take isl_multi_pw_aff *mpa, __isl_take isl_aff *aff)
6714 : {
6715 : int i, n_in, n_div;
6716 : isl_space *space;
6717 : isl_val *v;
6718 : isl_pw_aff *pa;
6719 : isl_aff *tmp;
6720 :
6721 0 : n_in = isl_aff_dim(aff, isl_dim_in);
6722 0 : n_div = isl_aff_dim(aff, isl_dim_div);
6723 :
6724 0 : space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
6725 0 : tmp = isl_aff_copy(aff);
6726 0 : tmp = isl_aff_drop_dims(tmp, isl_dim_div, 0, n_div);
6727 0 : tmp = isl_aff_drop_dims(tmp, isl_dim_in, 0, n_in);
6728 0 : tmp = isl_aff_add_dims(tmp, isl_dim_in,
6729 : isl_space_dim(space, isl_dim_set));
6730 0 : tmp = isl_aff_reset_domain_space(tmp, space);
6731 0 : pa = isl_pw_aff_from_aff(tmp);
6732 :
6733 0 : for (i = 0; i < n_in; ++i) {
6734 : isl_pw_aff *pa_i;
6735 :
6736 0 : if (!isl_aff_involves_dims(aff, isl_dim_in, i, 1))
6737 0 : continue;
6738 0 : v = isl_aff_get_coefficient_val(aff, isl_dim_in, i);
6739 0 : pa_i = isl_multi_pw_aff_get_pw_aff(mpa, i);
6740 0 : pa_i = isl_pw_aff_scale_val(pa_i, v);
6741 0 : pa = isl_pw_aff_add(pa, pa_i);
6742 : }
6743 :
6744 0 : for (i = 0; i < n_div; ++i) {
6745 : isl_aff *div;
6746 : isl_pw_aff *pa_i;
6747 :
6748 0 : if (!isl_aff_involves_dims(aff, isl_dim_div, i, 1))
6749 0 : continue;
6750 0 : div = isl_aff_get_div(aff, i);
6751 0 : pa_i = isl_multi_pw_aff_apply_aff_aligned(
6752 : isl_multi_pw_aff_copy(mpa), div);
6753 0 : pa_i = isl_pw_aff_floor(pa_i);
6754 0 : v = isl_aff_get_coefficient_val(aff, isl_dim_div, i);
6755 0 : pa_i = isl_pw_aff_scale_val(pa_i, v);
6756 0 : pa = isl_pw_aff_add(pa, pa_i);
6757 : }
6758 :
6759 0 : isl_multi_pw_aff_free(mpa);
6760 0 : isl_aff_free(aff);
6761 :
6762 0 : return pa;
6763 : }
6764 :
6765 : /* Apply "aff" to "mpa". The range of "mpa" needs to be compatible
6766 : * with the domain of "aff". The domain of the result is the same
6767 : * as that of "mpa".
6768 : */
6769 0 : __isl_give isl_pw_aff *isl_multi_pw_aff_apply_aff(
6770 : __isl_take isl_multi_pw_aff *mpa, __isl_take isl_aff *aff)
6771 : {
6772 : isl_bool equal_params;
6773 :
6774 0 : if (!aff || !mpa)
6775 : goto error;
6776 0 : equal_params = isl_space_has_equal_params(aff->ls->dim, mpa->space);
6777 0 : if (equal_params < 0)
6778 0 : goto error;
6779 0 : if (equal_params)
6780 0 : return isl_multi_pw_aff_apply_aff_aligned(mpa, aff);
6781 :
6782 0 : aff = isl_aff_align_params(aff, isl_multi_pw_aff_get_space(mpa));
6783 0 : mpa = isl_multi_pw_aff_align_params(mpa, isl_aff_get_space(aff));
6784 :
6785 0 : return isl_multi_pw_aff_apply_aff_aligned(mpa, aff);
6786 : error:
6787 0 : isl_aff_free(aff);
6788 0 : isl_multi_pw_aff_free(mpa);
6789 0 : return NULL;
6790 : }
6791 :
6792 : /* Apply "pa" to "mpa". The range of "mpa" needs to be compatible
6793 : * with the domain of "pa". The domain of the result is the same
6794 : * as that of "mpa".
6795 : * "mpa" and "pa" are assumed to have been aligned.
6796 : *
6797 : * We consider each piece in turn. Note that the domains of the
6798 : * pieces are assumed to be disjoint and they remain disjoint
6799 : * after taking the preimage (over the same function).
6800 : */
6801 0 : static __isl_give isl_pw_aff *isl_multi_pw_aff_apply_pw_aff_aligned(
6802 : __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_aff *pa)
6803 : {
6804 : isl_space *space;
6805 : isl_pw_aff *res;
6806 : int i;
6807 :
6808 0 : if (!mpa || !pa)
6809 : goto error;
6810 :
6811 0 : space = isl_space_join(isl_multi_pw_aff_get_space(mpa),
6812 : isl_pw_aff_get_space(pa));
6813 0 : res = isl_pw_aff_empty(space);
6814 :
6815 0 : for (i = 0; i < pa->n; ++i) {
6816 : isl_pw_aff *pa_i;
6817 : isl_set *domain;
6818 :
6819 0 : pa_i = isl_multi_pw_aff_apply_aff_aligned(
6820 : isl_multi_pw_aff_copy(mpa),
6821 0 : isl_aff_copy(pa->p[i].aff));
6822 0 : domain = isl_set_copy(pa->p[i].set);
6823 0 : domain = isl_set_preimage_multi_pw_aff(domain,
6824 : isl_multi_pw_aff_copy(mpa));
6825 0 : pa_i = isl_pw_aff_intersect_domain(pa_i, domain);
6826 0 : res = isl_pw_aff_add_disjoint(res, pa_i);
6827 : }
6828 :
6829 0 : isl_pw_aff_free(pa);
6830 0 : isl_multi_pw_aff_free(mpa);
6831 0 : return res;
6832 : error:
6833 0 : isl_pw_aff_free(pa);
6834 0 : isl_multi_pw_aff_free(mpa);
6835 0 : return NULL;
6836 : }
6837 :
6838 : /* Apply "pa" to "mpa". The range of "mpa" needs to be compatible
6839 : * with the domain of "pa". The domain of the result is the same
6840 : * as that of "mpa".
6841 : */
6842 0 : __isl_give isl_pw_aff *isl_multi_pw_aff_apply_pw_aff(
6843 : __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_aff *pa)
6844 : {
6845 : isl_bool equal_params;
6846 :
6847 0 : if (!pa || !mpa)
6848 : goto error;
6849 0 : equal_params = isl_space_has_equal_params(pa->dim, mpa->space);
6850 0 : if (equal_params < 0)
6851 0 : goto error;
6852 0 : if (equal_params)
6853 0 : return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa);
6854 :
6855 0 : pa = isl_pw_aff_align_params(pa, isl_multi_pw_aff_get_space(mpa));
6856 0 : mpa = isl_multi_pw_aff_align_params(mpa, isl_pw_aff_get_space(pa));
6857 :
6858 0 : return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa);
6859 : error:
6860 0 : isl_pw_aff_free(pa);
6861 0 : isl_multi_pw_aff_free(mpa);
6862 0 : return NULL;
6863 : }
6864 :
6865 : /* Compute the pullback of "pa" by the function represented by "mpa".
6866 : * In other words, plug in "mpa" in "pa".
6867 : * "pa" and "mpa" are assumed to have been aligned.
6868 : *
6869 : * The pullback is computed by applying "pa" to "mpa".
6870 : */
6871 0 : static __isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff_aligned(
6872 : __isl_take isl_pw_aff *pa, __isl_take isl_multi_pw_aff *mpa)
6873 : {
6874 0 : return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa);
6875 : }
6876 :
6877 : /* Compute the pullback of "pa" by the function represented by "mpa".
6878 : * In other words, plug in "mpa" in "pa".
6879 : *
6880 : * The pullback is computed by applying "pa" to "mpa".
6881 : */
6882 0 : __isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff(
6883 : __isl_take isl_pw_aff *pa, __isl_take isl_multi_pw_aff *mpa)
6884 : {
6885 0 : return isl_multi_pw_aff_apply_pw_aff(mpa, pa);
6886 : }
6887 :
6888 : /* Compute the pullback of "mpa1" by the function represented by "mpa2".
6889 : * In other words, plug in "mpa2" in "mpa1".
6890 : *
6891 : * The parameters of "mpa1" and "mpa2" are assumed to have been aligned.
6892 : *
6893 : * We pullback each member of "mpa1" in turn.
6894 : *
6895 : * If "mpa1" has an explicit domain, then it is this domain
6896 : * that needs to undergo a pullback instead, i.e., a preimage.
6897 : */
6898 : static __isl_give isl_multi_pw_aff *
6899 0 : isl_multi_pw_aff_pullback_multi_pw_aff_aligned(
6900 : __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2)
6901 : {
6902 : int i;
6903 0 : isl_space *space = NULL;
6904 :
6905 0 : mpa1 = isl_multi_pw_aff_cow(mpa1);
6906 0 : if (!mpa1 || !mpa2)
6907 : goto error;
6908 :
6909 0 : space = isl_space_join(isl_multi_pw_aff_get_space(mpa2),
6910 : isl_multi_pw_aff_get_space(mpa1));
6911 :
6912 0 : for (i = 0; i < mpa1->n; ++i) {
6913 0 : mpa1->u.p[i] = isl_pw_aff_pullback_multi_pw_aff_aligned(
6914 : mpa1->u.p[i], isl_multi_pw_aff_copy(mpa2));
6915 0 : if (!mpa1->u.p[i])
6916 0 : goto error;
6917 : }
6918 :
6919 0 : if (isl_multi_pw_aff_has_explicit_domain(mpa1)) {
6920 0 : mpa1->u.dom = isl_set_preimage_multi_pw_aff(mpa1->u.dom,
6921 : isl_multi_pw_aff_copy(mpa2));
6922 0 : if (!mpa1->u.dom)
6923 0 : goto error;
6924 : }
6925 0 : mpa1 = isl_multi_pw_aff_reset_space(mpa1, space);
6926 :
6927 0 : isl_multi_pw_aff_free(mpa2);
6928 0 : return mpa1;
6929 : error:
6930 0 : isl_space_free(space);
6931 0 : isl_multi_pw_aff_free(mpa1);
6932 0 : isl_multi_pw_aff_free(mpa2);
6933 0 : return NULL;
6934 : }
6935 :
6936 : /* Compute the pullback of "mpa1" by the function represented by "mpa2".
6937 : * In other words, plug in "mpa2" in "mpa1".
6938 : */
6939 0 : __isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_pw_aff(
6940 : __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2)
6941 : {
6942 0 : return isl_multi_pw_aff_align_params_multi_multi_and(mpa1, mpa2,
6943 : &isl_multi_pw_aff_pullback_multi_pw_aff_aligned);
6944 : }
6945 :
6946 : /* Align the parameters of "mpa1" and "mpa2", check that the ranges
6947 : * of "mpa1" and "mpa2" live in the same space, construct map space
6948 : * between the domain spaces of "mpa1" and "mpa2" and call "order"
6949 : * with this map space as extract argument.
6950 : */
6951 0 : static __isl_give isl_map *isl_multi_pw_aff_order_map(
6952 : __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2,
6953 : __isl_give isl_map *(*order)(__isl_keep isl_multi_pw_aff *mpa1,
6954 : __isl_keep isl_multi_pw_aff *mpa2, __isl_take isl_space *space))
6955 : {
6956 : int match;
6957 : isl_space *space1, *space2;
6958 : isl_map *res;
6959 :
6960 0 : mpa1 = isl_multi_pw_aff_align_params(mpa1,
6961 : isl_multi_pw_aff_get_space(mpa2));
6962 0 : mpa2 = isl_multi_pw_aff_align_params(mpa2,
6963 : isl_multi_pw_aff_get_space(mpa1));
6964 0 : if (!mpa1 || !mpa2)
6965 : goto error;
6966 0 : match = isl_space_tuple_is_equal(mpa1->space, isl_dim_out,
6967 : mpa2->space, isl_dim_out);
6968 0 : if (match < 0)
6969 0 : goto error;
6970 0 : if (!match)
6971 0 : isl_die(isl_multi_pw_aff_get_ctx(mpa1), isl_error_invalid,
6972 : "range spaces don't match", goto error);
6973 0 : space1 = isl_space_domain(isl_multi_pw_aff_get_space(mpa1));
6974 0 : space2 = isl_space_domain(isl_multi_pw_aff_get_space(mpa2));
6975 0 : space1 = isl_space_map_from_domain_and_range(space1, space2);
6976 :
6977 0 : res = order(mpa1, mpa2, space1);
6978 0 : isl_multi_pw_aff_free(mpa1);
6979 0 : isl_multi_pw_aff_free(mpa2);
6980 0 : return res;
6981 : error:
6982 0 : isl_multi_pw_aff_free(mpa1);
6983 0 : isl_multi_pw_aff_free(mpa2);
6984 0 : return NULL;
6985 : }
6986 :
6987 : /* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
6988 : * where the function values are equal. "space" is the space of the result.
6989 : * The parameters of "mpa1" and "mpa2" are assumed to have been aligned.
6990 : *
6991 : * "mpa1" and "mpa2" are equal when each of the pairs of elements
6992 : * in the sequences are equal.
6993 : */
6994 0 : static __isl_give isl_map *isl_multi_pw_aff_eq_map_on_space(
6995 : __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2,
6996 : __isl_take isl_space *space)
6997 : {
6998 : int i, n;
6999 : isl_map *res;
7000 :
7001 0 : res = isl_map_universe(space);
7002 :
7003 0 : n = isl_multi_pw_aff_dim(mpa1, isl_dim_out);
7004 0 : for (i = 0; i < n; ++i) {
7005 : isl_pw_aff *pa1, *pa2;
7006 : isl_map *map;
7007 :
7008 0 : pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i);
7009 0 : pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i);
7010 0 : map = isl_pw_aff_eq_map(pa1, pa2);
7011 0 : res = isl_map_intersect(res, map);
7012 : }
7013 :
7014 0 : return res;
7015 : }
7016 :
7017 : /* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
7018 : * where the function values are equal.
7019 : */
7020 0 : __isl_give isl_map *isl_multi_pw_aff_eq_map(__isl_take isl_multi_pw_aff *mpa1,
7021 : __isl_take isl_multi_pw_aff *mpa2)
7022 : {
7023 0 : return isl_multi_pw_aff_order_map(mpa1, mpa2,
7024 : &isl_multi_pw_aff_eq_map_on_space);
7025 : }
7026 :
7027 : /* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
7028 : * where the function values of "mpa1" is lexicographically satisfies "base"
7029 : * compared to that of "mpa2". "space" is the space of the result.
7030 : * The parameters of "mpa1" and "mpa2" are assumed to have been aligned.
7031 : *
7032 : * "mpa1" lexicographically satisfies "base" compared to "mpa2"
7033 : * if its i-th element satisfies "base" when compared to
7034 : * the i-th element of "mpa2" while all previous elements are
7035 : * pairwise equal.
7036 : */
7037 0 : static __isl_give isl_map *isl_multi_pw_aff_lex_map_on_space(
7038 : __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2,
7039 : __isl_give isl_map *(*base)(__isl_take isl_pw_aff *pa1,
7040 : __isl_take isl_pw_aff *pa2),
7041 : __isl_take isl_space *space)
7042 : {
7043 : int i, n;
7044 : isl_map *res, *rest;
7045 :
7046 0 : res = isl_map_empty(isl_space_copy(space));
7047 0 : rest = isl_map_universe(space);
7048 :
7049 0 : n = isl_multi_pw_aff_dim(mpa1, isl_dim_out);
7050 0 : for (i = 0; i < n; ++i) {
7051 : isl_pw_aff *pa1, *pa2;
7052 : isl_map *map;
7053 :
7054 0 : pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i);
7055 0 : pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i);
7056 0 : map = base(pa1, pa2);
7057 0 : map = isl_map_intersect(map, isl_map_copy(rest));
7058 0 : res = isl_map_union(res, map);
7059 :
7060 0 : if (i == n - 1)
7061 0 : continue;
7062 :
7063 0 : pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i);
7064 0 : pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i);
7065 0 : map = isl_pw_aff_eq_map(pa1, pa2);
7066 0 : rest = isl_map_intersect(rest, map);
7067 : }
7068 :
7069 0 : isl_map_free(rest);
7070 0 : return res;
7071 : }
7072 :
7073 : /* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
7074 : * where the function value of "mpa1" is lexicographically less than that
7075 : * of "mpa2". "space" is the space of the result.
7076 : * The parameters of "mpa1" and "mpa2" are assumed to have been aligned.
7077 : *
7078 : * "mpa1" is less than "mpa2" if its i-th element is smaller
7079 : * than the i-th element of "mpa2" while all previous elements are
7080 : * pairwise equal.
7081 : */
7082 0 : __isl_give isl_map *isl_multi_pw_aff_lex_lt_map_on_space(
7083 : __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2,
7084 : __isl_take isl_space *space)
7085 : {
7086 0 : return isl_multi_pw_aff_lex_map_on_space(mpa1, mpa2,
7087 : &isl_pw_aff_lt_map, space);
7088 : }
7089 :
7090 : /* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
7091 : * where the function value of "mpa1" is lexicographically less than that
7092 : * of "mpa2".
7093 : */
7094 0 : __isl_give isl_map *isl_multi_pw_aff_lex_lt_map(
7095 : __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2)
7096 : {
7097 0 : return isl_multi_pw_aff_order_map(mpa1, mpa2,
7098 : &isl_multi_pw_aff_lex_lt_map_on_space);
7099 : }
7100 :
7101 : /* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
7102 : * where the function value of "mpa1" is lexicographically greater than that
7103 : * of "mpa2". "space" is the space of the result.
7104 : * The parameters of "mpa1" and "mpa2" are assumed to have been aligned.
7105 : *
7106 : * "mpa1" is greater than "mpa2" if its i-th element is greater
7107 : * than the i-th element of "mpa2" while all previous elements are
7108 : * pairwise equal.
7109 : */
7110 0 : __isl_give isl_map *isl_multi_pw_aff_lex_gt_map_on_space(
7111 : __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2,
7112 : __isl_take isl_space *space)
7113 : {
7114 0 : return isl_multi_pw_aff_lex_map_on_space(mpa1, mpa2,
7115 : &isl_pw_aff_gt_map, space);
7116 : }
7117 :
7118 : /* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
7119 : * where the function value of "mpa1" is lexicographically greater than that
7120 : * of "mpa2".
7121 : */
7122 0 : __isl_give isl_map *isl_multi_pw_aff_lex_gt_map(
7123 : __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2)
7124 : {
7125 0 : return isl_multi_pw_aff_order_map(mpa1, mpa2,
7126 : &isl_multi_pw_aff_lex_gt_map_on_space);
7127 : }
7128 :
7129 : /* Compare two isl_affs.
7130 : *
7131 : * Return -1 if "aff1" is "smaller" than "aff2", 1 if "aff1" is "greater"
7132 : * than "aff2" and 0 if they are equal.
7133 : *
7134 : * The order is fairly arbitrary. We do consider expressions that only involve
7135 : * earlier dimensions as "smaller".
7136 : */
7137 0 : int isl_aff_plain_cmp(__isl_keep isl_aff *aff1, __isl_keep isl_aff *aff2)
7138 : {
7139 : int cmp;
7140 : int last1, last2;
7141 :
7142 0 : if (aff1 == aff2)
7143 0 : return 0;
7144 :
7145 0 : if (!aff1)
7146 0 : return -1;
7147 0 : if (!aff2)
7148 0 : return 1;
7149 :
7150 0 : cmp = isl_local_space_cmp(aff1->ls, aff2->ls);
7151 0 : if (cmp != 0)
7152 0 : return cmp;
7153 :
7154 0 : last1 = isl_seq_last_non_zero(aff1->v->el + 1, aff1->v->size - 1);
7155 0 : last2 = isl_seq_last_non_zero(aff2->v->el + 1, aff1->v->size - 1);
7156 0 : if (last1 != last2)
7157 0 : return last1 - last2;
7158 :
7159 0 : return isl_seq_cmp(aff1->v->el, aff2->v->el, aff1->v->size);
7160 : }
7161 :
7162 : /* Compare two isl_pw_affs.
7163 : *
7164 : * Return -1 if "pa1" is "smaller" than "pa2", 1 if "pa1" is "greater"
7165 : * than "pa2" and 0 if they are equal.
7166 : *
7167 : * The order is fairly arbitrary. We do consider expressions that only involve
7168 : * earlier dimensions as "smaller".
7169 : */
7170 0 : int isl_pw_aff_plain_cmp(__isl_keep isl_pw_aff *pa1,
7171 : __isl_keep isl_pw_aff *pa2)
7172 : {
7173 : int i;
7174 : int cmp;
7175 :
7176 0 : if (pa1 == pa2)
7177 0 : return 0;
7178 :
7179 0 : if (!pa1)
7180 0 : return -1;
7181 0 : if (!pa2)
7182 0 : return 1;
7183 :
7184 0 : cmp = isl_space_cmp(pa1->dim, pa2->dim);
7185 0 : if (cmp != 0)
7186 0 : return cmp;
7187 :
7188 0 : if (pa1->n != pa2->n)
7189 0 : return pa1->n - pa2->n;
7190 :
7191 0 : for (i = 0; i < pa1->n; ++i) {
7192 0 : cmp = isl_set_plain_cmp(pa1->p[i].set, pa2->p[i].set);
7193 0 : if (cmp != 0)
7194 0 : return cmp;
7195 0 : cmp = isl_aff_plain_cmp(pa1->p[i].aff, pa2->p[i].aff);
7196 0 : if (cmp != 0)
7197 0 : return cmp;
7198 : }
7199 :
7200 0 : return 0;
7201 : }
7202 :
7203 : /* Return a piecewise affine expression that is equal to "v" on "domain".
7204 : */
7205 0 : __isl_give isl_pw_aff *isl_pw_aff_val_on_domain(__isl_take isl_set *domain,
7206 : __isl_take isl_val *v)
7207 : {
7208 : isl_space *space;
7209 : isl_local_space *ls;
7210 : isl_aff *aff;
7211 :
7212 0 : space = isl_set_get_space(domain);
7213 0 : ls = isl_local_space_from_space(space);
7214 0 : aff = isl_aff_val_on_domain(ls, v);
7215 :
7216 0 : return isl_pw_aff_alloc(domain, aff);
7217 : }
7218 :
7219 : /* Return a multi affine expression that is equal to "mv" on domain
7220 : * space "space".
7221 : */
7222 0 : __isl_give isl_multi_aff *isl_multi_aff_multi_val_on_space(
7223 : __isl_take isl_space *space, __isl_take isl_multi_val *mv)
7224 : {
7225 : int i, n;
7226 : isl_space *space2;
7227 : isl_local_space *ls;
7228 : isl_multi_aff *ma;
7229 :
7230 0 : if (!space || !mv)
7231 : goto error;
7232 :
7233 0 : n = isl_multi_val_dim(mv, isl_dim_set);
7234 0 : space2 = isl_multi_val_get_space(mv);
7235 0 : space2 = isl_space_align_params(space2, isl_space_copy(space));
7236 0 : space = isl_space_align_params(space, isl_space_copy(space2));
7237 0 : space = isl_space_map_from_domain_and_range(space, space2);
7238 0 : ma = isl_multi_aff_alloc(isl_space_copy(space));
7239 0 : ls = isl_local_space_from_space(isl_space_domain(space));
7240 0 : for (i = 0; i < n; ++i) {
7241 : isl_val *v;
7242 : isl_aff *aff;
7243 :
7244 0 : v = isl_multi_val_get_val(mv, i);
7245 0 : aff = isl_aff_val_on_domain(isl_local_space_copy(ls), v);
7246 0 : ma = isl_multi_aff_set_aff(ma, i, aff);
7247 : }
7248 0 : isl_local_space_free(ls);
7249 :
7250 0 : isl_multi_val_free(mv);
7251 0 : return ma;
7252 : error:
7253 0 : isl_space_free(space);
7254 0 : isl_multi_val_free(mv);
7255 0 : return NULL;
7256 : }
7257 :
7258 : /* Return a piecewise multi-affine expression
7259 : * that is equal to "mv" on "domain".
7260 : */
7261 0 : __isl_give isl_pw_multi_aff *isl_pw_multi_aff_multi_val_on_domain(
7262 : __isl_take isl_set *domain, __isl_take isl_multi_val *mv)
7263 : {
7264 : isl_space *space;
7265 : isl_multi_aff *ma;
7266 :
7267 0 : space = isl_set_get_space(domain);
7268 0 : ma = isl_multi_aff_multi_val_on_space(space, mv);
7269 :
7270 0 : return isl_pw_multi_aff_alloc(domain, ma);
7271 : }
7272 :
7273 : /* Internal data structure for isl_union_pw_multi_aff_multi_val_on_domain.
7274 : * mv is the value that should be attained on each domain set
7275 : * res collects the results
7276 : */
7277 : struct isl_union_pw_multi_aff_multi_val_on_domain_data {
7278 : isl_multi_val *mv;
7279 : isl_union_pw_multi_aff *res;
7280 : };
7281 :
7282 : /* Create an isl_pw_multi_aff equal to data->mv on "domain"
7283 : * and add it to data->res.
7284 : */
7285 0 : static isl_stat pw_multi_aff_multi_val_on_domain(__isl_take isl_set *domain,
7286 : void *user)
7287 : {
7288 0 : struct isl_union_pw_multi_aff_multi_val_on_domain_data *data = user;
7289 : isl_pw_multi_aff *pma;
7290 : isl_multi_val *mv;
7291 :
7292 0 : mv = isl_multi_val_copy(data->mv);
7293 0 : pma = isl_pw_multi_aff_multi_val_on_domain(domain, mv);
7294 0 : data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma);
7295 :
7296 0 : return data->res ? isl_stat_ok : isl_stat_error;
7297 : }
7298 :
7299 : /* Return a union piecewise multi-affine expression
7300 : * that is equal to "mv" on "domain".
7301 : */
7302 0 : __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_multi_val_on_domain(
7303 : __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv)
7304 : {
7305 : struct isl_union_pw_multi_aff_multi_val_on_domain_data data;
7306 : isl_space *space;
7307 :
7308 0 : space = isl_union_set_get_space(domain);
7309 0 : data.res = isl_union_pw_multi_aff_empty(space);
7310 0 : data.mv = mv;
7311 0 : if (isl_union_set_foreach_set(domain,
7312 : &pw_multi_aff_multi_val_on_domain, &data) < 0)
7313 0 : data.res = isl_union_pw_multi_aff_free(data.res);
7314 0 : isl_union_set_free(domain);
7315 0 : isl_multi_val_free(mv);
7316 0 : return data.res;
7317 : }
7318 :
7319 : /* Compute the pullback of data->pma by the function represented by "pma2",
7320 : * provided the spaces match, and add the results to data->res.
7321 : */
7322 0 : static isl_stat pullback_entry(__isl_take isl_pw_multi_aff *pma2, void *user)
7323 : {
7324 0 : struct isl_union_pw_multi_aff_bin_data *data = user;
7325 :
7326 0 : if (!isl_space_tuple_is_equal(data->pma->dim, isl_dim_in,
7327 : pma2->dim, isl_dim_out)) {
7328 0 : isl_pw_multi_aff_free(pma2);
7329 0 : return isl_stat_ok;
7330 : }
7331 :
7332 0 : pma2 = isl_pw_multi_aff_pullback_pw_multi_aff(
7333 : isl_pw_multi_aff_copy(data->pma), pma2);
7334 :
7335 0 : data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma2);
7336 0 : if (!data->res)
7337 0 : return isl_stat_error;
7338 :
7339 0 : return isl_stat_ok;
7340 : }
7341 :
7342 : /* Compute the pullback of "upma1" by the function represented by "upma2".
7343 : */
7344 : __isl_give isl_union_pw_multi_aff *
7345 0 : isl_union_pw_multi_aff_pullback_union_pw_multi_aff(
7346 : __isl_take isl_union_pw_multi_aff *upma1,
7347 : __isl_take isl_union_pw_multi_aff *upma2)
7348 : {
7349 0 : return bin_op(upma1, upma2, &pullback_entry);
7350 : }
7351 :
7352 : /* Check that the domain space of "upa" matches "space".
7353 : *
7354 : * This function is called from isl_multi_union_pw_aff_set_union_pw_aff and
7355 : * can in principle never fail since the space "space" is that
7356 : * of the isl_multi_union_pw_aff and is a set space such that
7357 : * there is no domain space to match.
7358 : *
7359 : * We check the parameters and double-check that "space" is
7360 : * indeed that of a set.
7361 : */
7362 0 : static isl_stat isl_union_pw_aff_check_match_domain_space(
7363 : __isl_keep isl_union_pw_aff *upa, __isl_keep isl_space *space)
7364 : {
7365 : isl_space *upa_space;
7366 : isl_bool match;
7367 :
7368 0 : if (!upa || !space)
7369 0 : return isl_stat_error;
7370 :
7371 0 : match = isl_space_is_set(space);
7372 0 : if (match < 0)
7373 0 : return isl_stat_error;
7374 0 : if (!match)
7375 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
7376 : "expecting set space", return isl_stat_error);
7377 :
7378 0 : upa_space = isl_union_pw_aff_get_space(upa);
7379 0 : match = isl_space_has_equal_params(space, upa_space);
7380 0 : if (match < 0)
7381 0 : goto error;
7382 0 : if (!match)
7383 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
7384 : "parameters don't match", goto error);
7385 :
7386 0 : isl_space_free(upa_space);
7387 0 : return isl_stat_ok;
7388 : error:
7389 0 : isl_space_free(upa_space);
7390 0 : return isl_stat_error;
7391 : }
7392 :
7393 : /* Do the parameters of "upa" match those of "space"?
7394 : */
7395 0 : static isl_bool isl_union_pw_aff_matching_params(
7396 : __isl_keep isl_union_pw_aff *upa, __isl_keep isl_space *space)
7397 : {
7398 : isl_space *upa_space;
7399 : isl_bool match;
7400 :
7401 0 : if (!upa || !space)
7402 0 : return isl_bool_error;
7403 :
7404 0 : upa_space = isl_union_pw_aff_get_space(upa);
7405 :
7406 0 : match = isl_space_has_equal_params(space, upa_space);
7407 :
7408 0 : isl_space_free(upa_space);
7409 0 : return match;
7410 : }
7411 :
7412 : /* Internal data structure for isl_union_pw_aff_reset_domain_space.
7413 : * space represents the new parameters.
7414 : * res collects the results.
7415 : */
7416 : struct isl_union_pw_aff_reset_params_data {
7417 : isl_space *space;
7418 : isl_union_pw_aff *res;
7419 : };
7420 :
7421 : /* Replace the parameters of "pa" by data->space and
7422 : * add the result to data->res.
7423 : */
7424 0 : static isl_stat reset_params(__isl_take isl_pw_aff *pa, void *user)
7425 : {
7426 0 : struct isl_union_pw_aff_reset_params_data *data = user;
7427 : isl_space *space;
7428 :
7429 0 : space = isl_pw_aff_get_space(pa);
7430 0 : space = isl_space_replace_params(space, data->space);
7431 0 : pa = isl_pw_aff_reset_space(pa, space);
7432 0 : data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);
7433 :
7434 0 : return data->res ? isl_stat_ok : isl_stat_error;
7435 : }
7436 :
7437 : /* Replace the domain space of "upa" by "space".
7438 : * Since a union expression does not have a (single) domain space,
7439 : * "space" is necessarily a parameter space.
7440 : *
7441 : * Since the order and the names of the parameters determine
7442 : * the hash value, we need to create a new hash table.
7443 : */
7444 0 : static __isl_give isl_union_pw_aff *isl_union_pw_aff_reset_domain_space(
7445 : __isl_take isl_union_pw_aff *upa, __isl_take isl_space *space)
7446 : {
7447 0 : struct isl_union_pw_aff_reset_params_data data = { space };
7448 : isl_bool match;
7449 :
7450 0 : match = isl_union_pw_aff_matching_params(upa, space);
7451 0 : if (match < 0)
7452 0 : upa = isl_union_pw_aff_free(upa);
7453 0 : else if (match) {
7454 0 : isl_space_free(space);
7455 0 : return upa;
7456 : }
7457 :
7458 0 : data.res = isl_union_pw_aff_empty(isl_space_copy(space));
7459 0 : if (isl_union_pw_aff_foreach_pw_aff(upa, &reset_params, &data) < 0)
7460 0 : data.res = isl_union_pw_aff_free(data.res);
7461 :
7462 0 : isl_union_pw_aff_free(upa);
7463 0 : isl_space_free(space);
7464 0 : return data.res;
7465 : }
7466 :
7467 : /* Return the floor of "pa".
7468 : */
7469 0 : static __isl_give isl_pw_aff *floor_entry(__isl_take isl_pw_aff *pa, void *user)
7470 : {
7471 0 : return isl_pw_aff_floor(pa);
7472 : }
7473 :
7474 : /* Given f, return floor(f).
7475 : */
7476 0 : __isl_give isl_union_pw_aff *isl_union_pw_aff_floor(
7477 : __isl_take isl_union_pw_aff *upa)
7478 : {
7479 0 : return isl_union_pw_aff_transform_inplace(upa, &floor_entry, NULL);
7480 : }
7481 :
7482 : /* Compute
7483 : *
7484 : * upa mod m = upa - m * floor(upa/m)
7485 : *
7486 : * with m an integer value.
7487 : */
7488 0 : __isl_give isl_union_pw_aff *isl_union_pw_aff_mod_val(
7489 : __isl_take isl_union_pw_aff *upa, __isl_take isl_val *m)
7490 : {
7491 : isl_union_pw_aff *res;
7492 :
7493 0 : if (!upa || !m)
7494 : goto error;
7495 :
7496 0 : if (!isl_val_is_int(m))
7497 0 : isl_die(isl_val_get_ctx(m), isl_error_invalid,
7498 : "expecting integer modulo", goto error);
7499 0 : if (!isl_val_is_pos(m))
7500 0 : isl_die(isl_val_get_ctx(m), isl_error_invalid,
7501 : "expecting positive modulo", goto error);
7502 :
7503 0 : res = isl_union_pw_aff_copy(upa);
7504 0 : upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(m));
7505 0 : upa = isl_union_pw_aff_floor(upa);
7506 0 : upa = isl_union_pw_aff_scale_val(upa, m);
7507 0 : res = isl_union_pw_aff_sub(res, upa);
7508 :
7509 0 : return res;
7510 : error:
7511 0 : isl_val_free(m);
7512 0 : isl_union_pw_aff_free(upa);
7513 0 : return NULL;
7514 : }
7515 :
7516 : /* Internal data structure for isl_union_pw_multi_aff_get_union_pw_aff.
7517 : * pos is the output position that needs to be extracted.
7518 : * res collects the results.
7519 : */
7520 : struct isl_union_pw_multi_aff_get_union_pw_aff_data {
7521 : int pos;
7522 : isl_union_pw_aff *res;
7523 : };
7524 :
7525 : /* Extract an isl_pw_aff corresponding to output dimension "pos" of "pma"
7526 : * (assuming it has such a dimension) and add it to data->res.
7527 : */
7528 0 : static isl_stat get_union_pw_aff(__isl_take isl_pw_multi_aff *pma, void *user)
7529 : {
7530 0 : struct isl_union_pw_multi_aff_get_union_pw_aff_data *data = user;
7531 : int n_out;
7532 : isl_pw_aff *pa;
7533 :
7534 0 : if (!pma)
7535 0 : return isl_stat_error;
7536 :
7537 0 : n_out = isl_pw_multi_aff_dim(pma, isl_dim_out);
7538 0 : if (data->pos >= n_out) {
7539 0 : isl_pw_multi_aff_free(pma);
7540 0 : return isl_stat_ok;
7541 : }
7542 :
7543 0 : pa = isl_pw_multi_aff_get_pw_aff(pma, data->pos);
7544 0 : isl_pw_multi_aff_free(pma);
7545 :
7546 0 : data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);
7547 :
7548 0 : return data->res ? isl_stat_ok : isl_stat_error;
7549 : }
7550 :
7551 : /* Extract an isl_union_pw_aff corresponding to
7552 : * output dimension "pos" of "upma".
7553 : */
7554 0 : __isl_give isl_union_pw_aff *isl_union_pw_multi_aff_get_union_pw_aff(
7555 : __isl_keep isl_union_pw_multi_aff *upma, int pos)
7556 : {
7557 : struct isl_union_pw_multi_aff_get_union_pw_aff_data data;
7558 : isl_space *space;
7559 :
7560 0 : if (!upma)
7561 0 : return NULL;
7562 :
7563 0 : if (pos < 0)
7564 0 : isl_die(isl_union_pw_multi_aff_get_ctx(upma), isl_error_invalid,
7565 : "cannot extract at negative position", return NULL);
7566 :
7567 0 : space = isl_union_pw_multi_aff_get_space(upma);
7568 0 : data.res = isl_union_pw_aff_empty(space);
7569 0 : data.pos = pos;
7570 0 : if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
7571 : &get_union_pw_aff, &data) < 0)
7572 0 : data.res = isl_union_pw_aff_free(data.res);
7573 :
7574 0 : return data.res;
7575 : }
7576 :
7577 : /* Return a union piecewise affine expression
7578 : * that is equal to "aff" on "domain".
7579 : */
7580 0 : __isl_give isl_union_pw_aff *isl_union_pw_aff_aff_on_domain(
7581 : __isl_take isl_union_set *domain, __isl_take isl_aff *aff)
7582 : {
7583 : isl_pw_aff *pa;
7584 :
7585 0 : pa = isl_pw_aff_from_aff(aff);
7586 0 : return isl_union_pw_aff_pw_aff_on_domain(domain, pa);
7587 : }
7588 :
7589 : /* Return a union piecewise affine expression
7590 : * that is equal to the parameter identified by "id" on "domain".
7591 : *
7592 : * Make sure the parameter appears in the space passed to
7593 : * isl_aff_param_on_domain_space_id.
7594 : */
7595 0 : __isl_give isl_union_pw_aff *isl_union_pw_aff_param_on_domain_id(
7596 : __isl_take isl_union_set *domain, __isl_take isl_id *id)
7597 : {
7598 : isl_space *space;
7599 : isl_aff *aff;
7600 :
7601 0 : space = isl_union_set_get_space(domain);
7602 0 : space = isl_space_add_param_id(space, isl_id_copy(id));
7603 0 : aff = isl_aff_param_on_domain_space_id(space, id);
7604 0 : return isl_union_pw_aff_aff_on_domain(domain, aff);
7605 : }
7606 :
7607 : /* Internal data structure for isl_union_pw_aff_pw_aff_on_domain.
7608 : * "pa" is the piecewise symbolic value that the resulting isl_union_pw_aff
7609 : * needs to attain.
7610 : * "res" collects the results.
7611 : */
7612 : struct isl_union_pw_aff_pw_aff_on_domain_data {
7613 : isl_pw_aff *pa;
7614 : isl_union_pw_aff *res;
7615 : };
7616 :
7617 : /* Construct a piecewise affine expression that is equal to data->pa
7618 : * on "domain" and add the result to data->res.
7619 : */
7620 0 : static isl_stat pw_aff_on_domain(__isl_take isl_set *domain, void *user)
7621 : {
7622 0 : struct isl_union_pw_aff_pw_aff_on_domain_data *data = user;
7623 : isl_pw_aff *pa;
7624 : int dim;
7625 :
7626 0 : pa = isl_pw_aff_copy(data->pa);
7627 0 : dim = isl_set_dim(domain, isl_dim_set);
7628 0 : pa = isl_pw_aff_from_range(pa);
7629 0 : pa = isl_pw_aff_add_dims(pa, isl_dim_in, dim);
7630 0 : pa = isl_pw_aff_reset_domain_space(pa, isl_set_get_space(domain));
7631 0 : pa = isl_pw_aff_intersect_domain(pa, domain);
7632 0 : data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);
7633 :
7634 0 : return data->res ? isl_stat_ok : isl_stat_error;
7635 : }
7636 :
7637 : /* Return a union piecewise affine expression
7638 : * that is equal to "pa" on "domain", assuming "domain" and "pa"
7639 : * have been aligned.
7640 : *
7641 : * Construct an isl_pw_aff on each of the sets in "domain" and
7642 : * collect the results.
7643 : */
7644 0 : static __isl_give isl_union_pw_aff *isl_union_pw_aff_pw_aff_on_domain_aligned(
7645 : __isl_take isl_union_set *domain, __isl_take isl_pw_aff *pa)
7646 : {
7647 : struct isl_union_pw_aff_pw_aff_on_domain_data data;
7648 : isl_space *space;
7649 :
7650 0 : space = isl_union_set_get_space(domain);
7651 0 : data.res = isl_union_pw_aff_empty(space);
7652 0 : data.pa = pa;
7653 0 : if (isl_union_set_foreach_set(domain, &pw_aff_on_domain, &data) < 0)
7654 0 : data.res = isl_union_pw_aff_free(data.res);
7655 0 : isl_union_set_free(domain);
7656 0 : isl_pw_aff_free(pa);
7657 0 : return data.res;
7658 : }
7659 :
7660 : /* Return a union piecewise affine expression
7661 : * that is equal to "pa" on "domain".
7662 : *
7663 : * Check that "pa" is a parametric expression,
7664 : * align the parameters if needed and call
7665 : * isl_union_pw_aff_pw_aff_on_domain_aligned.
7666 : */
7667 0 : __isl_give isl_union_pw_aff *isl_union_pw_aff_pw_aff_on_domain(
7668 : __isl_take isl_union_set *domain, __isl_take isl_pw_aff *pa)
7669 : {
7670 : isl_bool is_set;
7671 : isl_bool equal_params;
7672 : isl_space *domain_space, *pa_space;
7673 :
7674 0 : pa_space = isl_pw_aff_peek_space(pa);
7675 0 : is_set = isl_space_is_set(pa_space);
7676 0 : if (is_set < 0)
7677 0 : goto error;
7678 0 : if (!is_set)
7679 0 : isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
7680 : "expecting parametric expression", goto error);
7681 :
7682 0 : domain_space = isl_union_set_get_space(domain);
7683 0 : pa_space = isl_pw_aff_get_space(pa);
7684 0 : equal_params = isl_space_has_equal_params(domain_space, pa_space);
7685 0 : if (equal_params >= 0 && !equal_params) {
7686 : isl_space *space;
7687 :
7688 0 : space = isl_space_align_params(domain_space, pa_space);
7689 0 : pa = isl_pw_aff_align_params(pa, isl_space_copy(space));
7690 0 : domain = isl_union_set_align_params(domain, space);
7691 : } else {
7692 0 : isl_space_free(domain_space);
7693 0 : isl_space_free(pa_space);
7694 : }
7695 :
7696 0 : if (equal_params < 0)
7697 0 : goto error;
7698 0 : return isl_union_pw_aff_pw_aff_on_domain_aligned(domain, pa);
7699 : error:
7700 0 : isl_union_set_free(domain);
7701 0 : isl_pw_aff_free(pa);
7702 0 : return NULL;
7703 : }
7704 :
7705 : /* Internal data structure for isl_union_pw_aff_val_on_domain.
7706 : * "v" is the value that the resulting isl_union_pw_aff needs to attain.
7707 : * "res" collects the results.
7708 : */
7709 : struct isl_union_pw_aff_val_on_domain_data {
7710 : isl_val *v;
7711 : isl_union_pw_aff *res;
7712 : };
7713 :
7714 : /* Construct a piecewise affine expression that is equal to data->v
7715 : * on "domain" and add the result to data->res.
7716 : */
7717 0 : static isl_stat pw_aff_val_on_domain(__isl_take isl_set *domain, void *user)
7718 : {
7719 0 : struct isl_union_pw_aff_val_on_domain_data *data = user;
7720 : isl_pw_aff *pa;
7721 : isl_val *v;
7722 :
7723 0 : v = isl_val_copy(data->v);
7724 0 : pa = isl_pw_aff_val_on_domain(domain, v);
7725 0 : data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);
7726 :
7727 0 : return data->res ? isl_stat_ok : isl_stat_error;
7728 : }
7729 :
7730 : /* Return a union piecewise affine expression
7731 : * that is equal to "v" on "domain".
7732 : *
7733 : * Construct an isl_pw_aff on each of the sets in "domain" and
7734 : * collect the results.
7735 : */
7736 0 : __isl_give isl_union_pw_aff *isl_union_pw_aff_val_on_domain(
7737 : __isl_take isl_union_set *domain, __isl_take isl_val *v)
7738 : {
7739 : struct isl_union_pw_aff_val_on_domain_data data;
7740 : isl_space *space;
7741 :
7742 0 : space = isl_union_set_get_space(domain);
7743 0 : data.res = isl_union_pw_aff_empty(space);
7744 0 : data.v = v;
7745 0 : if (isl_union_set_foreach_set(domain, &pw_aff_val_on_domain, &data) < 0)
7746 0 : data.res = isl_union_pw_aff_free(data.res);
7747 0 : isl_union_set_free(domain);
7748 0 : isl_val_free(v);
7749 0 : return data.res;
7750 : }
7751 :
7752 : /* Construct a piecewise multi affine expression
7753 : * that is equal to "pa" and add it to upma.
7754 : */
7755 0 : static isl_stat pw_multi_aff_from_pw_aff_entry(__isl_take isl_pw_aff *pa,
7756 : void *user)
7757 : {
7758 0 : isl_union_pw_multi_aff **upma = user;
7759 : isl_pw_multi_aff *pma;
7760 :
7761 0 : pma = isl_pw_multi_aff_from_pw_aff(pa);
7762 0 : *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma);
7763 :
7764 0 : return *upma ? isl_stat_ok : isl_stat_error;
7765 : }
7766 :
7767 : /* Construct and return a union piecewise multi affine expression
7768 : * that is equal to the given union piecewise affine expression.
7769 : */
7770 0 : __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_pw_aff(
7771 : __isl_take isl_union_pw_aff *upa)
7772 : {
7773 : isl_space *space;
7774 : isl_union_pw_multi_aff *upma;
7775 :
7776 0 : if (!upa)
7777 0 : return NULL;
7778 :
7779 0 : space = isl_union_pw_aff_get_space(upa);
7780 0 : upma = isl_union_pw_multi_aff_empty(space);
7781 :
7782 0 : if (isl_union_pw_aff_foreach_pw_aff(upa,
7783 : &pw_multi_aff_from_pw_aff_entry, &upma) < 0)
7784 0 : upma = isl_union_pw_multi_aff_free(upma);
7785 :
7786 0 : isl_union_pw_aff_free(upa);
7787 0 : return upma;
7788 : }
7789 :
7790 : /* Compute the set of elements in the domain of "pa" where it is zero and
7791 : * add this set to "uset".
7792 : */
7793 0 : static isl_stat zero_union_set(__isl_take isl_pw_aff *pa, void *user)
7794 : {
7795 0 : isl_union_set **uset = (isl_union_set **)user;
7796 :
7797 0 : *uset = isl_union_set_add_set(*uset, isl_pw_aff_zero_set(pa));
7798 :
7799 0 : return *uset ? isl_stat_ok : isl_stat_error;
7800 : }
7801 :
7802 : /* Return a union set containing those elements in the domain
7803 : * of "upa" where it is zero.
7804 : */
7805 0 : __isl_give isl_union_set *isl_union_pw_aff_zero_union_set(
7806 : __isl_take isl_union_pw_aff *upa)
7807 : {
7808 : isl_union_set *zero;
7809 :
7810 0 : zero = isl_union_set_empty(isl_union_pw_aff_get_space(upa));
7811 0 : if (isl_union_pw_aff_foreach_pw_aff(upa, &zero_union_set, &zero) < 0)
7812 0 : zero = isl_union_set_free(zero);
7813 :
7814 0 : isl_union_pw_aff_free(upa);
7815 0 : return zero;
7816 : }
7817 :
7818 : /* Internal data structure for isl_union_pw_aff_pullback_union_pw_multi_aff.
7819 : * upma is the function that is plugged in.
7820 : * pa is the current part of the function in which upma is plugged in.
7821 : * res collects the results.
7822 : */
7823 : struct isl_union_pw_aff_pullback_upma_data {
7824 : isl_union_pw_multi_aff *upma;
7825 : isl_pw_aff *pa;
7826 : isl_union_pw_aff *res;
7827 : };
7828 :
7829 : /* Check if "pma" can be plugged into data->pa.
7830 : * If so, perform the pullback and add the result to data->res.
7831 : */
7832 0 : static isl_stat pa_pb_pma(__isl_take isl_pw_multi_aff *pma, void *user)
7833 : {
7834 0 : struct isl_union_pw_aff_pullback_upma_data *data = user;
7835 : isl_pw_aff *pa;
7836 :
7837 0 : if (!isl_space_tuple_is_equal(data->pa->dim, isl_dim_in,
7838 : pma->dim, isl_dim_out)) {
7839 0 : isl_pw_multi_aff_free(pma);
7840 0 : return isl_stat_ok;
7841 : }
7842 :
7843 0 : pa = isl_pw_aff_copy(data->pa);
7844 0 : pa = isl_pw_aff_pullback_pw_multi_aff(pa, pma);
7845 :
7846 0 : data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);
7847 :
7848 0 : return data->res ? isl_stat_ok : isl_stat_error;
7849 : }
7850 :
7851 : /* Check if any of the elements of data->upma can be plugged into pa,
7852 : * add if so add the result to data->res.
7853 : */
7854 0 : static isl_stat upa_pb_upma(__isl_take isl_pw_aff *pa, void *user)
7855 : {
7856 0 : struct isl_union_pw_aff_pullback_upma_data *data = user;
7857 : isl_stat r;
7858 :
7859 0 : data->pa = pa;
7860 0 : r = isl_union_pw_multi_aff_foreach_pw_multi_aff(data->upma,
7861 : &pa_pb_pma, data);
7862 0 : isl_pw_aff_free(pa);
7863 :
7864 0 : return r;
7865 : }
7866 :
7867 : /* Compute the pullback of "upa" by the function represented by "upma".
7868 : * In other words, plug in "upma" in "upa". The result contains
7869 : * expressions defined over the domain space of "upma".
7870 : *
7871 : * Run over all pairs of elements in "upa" and "upma", perform
7872 : * the pullback when appropriate and collect the results.
7873 : * If the hash value were based on the domain space rather than
7874 : * the function space, then we could run through all elements
7875 : * of "upma" and directly pick out the corresponding element of "upa".
7876 : */
7877 0 : __isl_give isl_union_pw_aff *isl_union_pw_aff_pullback_union_pw_multi_aff(
7878 : __isl_take isl_union_pw_aff *upa,
7879 : __isl_take isl_union_pw_multi_aff *upma)
7880 : {
7881 0 : struct isl_union_pw_aff_pullback_upma_data data = { NULL, NULL };
7882 : isl_space *space;
7883 :
7884 0 : space = isl_union_pw_multi_aff_get_space(upma);
7885 0 : upa = isl_union_pw_aff_align_params(upa, space);
7886 0 : space = isl_union_pw_aff_get_space(upa);
7887 0 : upma = isl_union_pw_multi_aff_align_params(upma, space);
7888 :
7889 0 : if (!upa || !upma)
7890 : goto error;
7891 :
7892 0 : data.upma = upma;
7893 0 : data.res = isl_union_pw_aff_alloc_same_size(upa);
7894 0 : if (isl_union_pw_aff_foreach_pw_aff(upa, &upa_pb_upma, &data) < 0)
7895 0 : data.res = isl_union_pw_aff_free(data.res);
7896 :
7897 0 : isl_union_pw_aff_free(upa);
7898 0 : isl_union_pw_multi_aff_free(upma);
7899 0 : return data.res;
7900 : error:
7901 0 : isl_union_pw_aff_free(upa);
7902 0 : isl_union_pw_multi_aff_free(upma);
7903 0 : return NULL;
7904 : }
7905 :
7906 : #undef BASE
7907 : #define BASE union_pw_aff
7908 : #undef DOMBASE
7909 : #define DOMBASE union_set
7910 :
7911 : #define NO_MOVE_DIMS
7912 : #define NO_DOMAIN
7913 : #define NO_PRODUCT
7914 : #define NO_SPLICE
7915 : #define NO_ZERO
7916 : #define NO_IDENTITY
7917 :
7918 : #include <isl_multi_explicit_domain.c>
7919 : #include <isl_multi_union_pw_aff_explicit_domain.c>
7920 : #include <isl_multi_templ.c>
7921 : #include <isl_multi_apply_set.c>
7922 : #include <isl_multi_apply_union_set.c>
7923 : #include <isl_multi_coalesce.c>
7924 : #include <isl_multi_floor.c>
7925 : #include <isl_multi_gist.c>
7926 : #include <isl_multi_align_set.c>
7927 : #include <isl_multi_align_union_set.c>
7928 : #include <isl_multi_intersect.c>
7929 :
7930 : /* Does "mupa" have a non-trivial explicit domain?
7931 : *
7932 : * The explicit domain, if present, is trivial if it represents
7933 : * an (obviously) universe parameter set.
7934 : */
7935 0 : isl_bool isl_multi_union_pw_aff_has_non_trivial_domain(
7936 : __isl_keep isl_multi_union_pw_aff *mupa)
7937 : {
7938 : isl_bool is_params, trivial;
7939 : isl_set *set;
7940 :
7941 0 : if (!mupa)
7942 0 : return isl_bool_error;
7943 0 : if (!isl_multi_union_pw_aff_has_explicit_domain(mupa))
7944 0 : return isl_bool_false;
7945 0 : is_params = isl_union_set_is_params(mupa->u.dom);
7946 0 : if (is_params < 0 || !is_params)
7947 0 : return isl_bool_not(is_params);
7948 0 : set = isl_set_from_union_set(isl_union_set_copy(mupa->u.dom));
7949 0 : trivial = isl_set_plain_is_universe(set);
7950 0 : isl_set_free(set);
7951 0 : return isl_bool_not(trivial);
7952 : }
7953 :
7954 : /* Construct a multiple union piecewise affine expression
7955 : * in the given space with value zero in each of the output dimensions.
7956 : *
7957 : * Since there is no canonical zero value for
7958 : * a union piecewise affine expression, we can only construct
7959 : * a zero-dimensional "zero" value.
7960 : */
7961 0 : __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_zero(
7962 : __isl_take isl_space *space)
7963 : {
7964 : isl_bool params;
7965 :
7966 0 : if (!space)
7967 0 : return NULL;
7968 :
7969 0 : params = isl_space_is_params(space);
7970 0 : if (params < 0)
7971 0 : goto error;
7972 0 : if (params)
7973 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
7974 : "expecting proper set space", goto error);
7975 0 : if (!isl_space_is_set(space))
7976 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
7977 : "expecting set space", goto error);
7978 0 : if (isl_space_dim(space , isl_dim_out) != 0)
7979 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
7980 : "expecting 0D space", goto error);
7981 :
7982 0 : return isl_multi_union_pw_aff_alloc(space);
7983 : error:
7984 0 : isl_space_free(space);
7985 0 : return NULL;
7986 : }
7987 :
7988 : /* Compute the sum of "mupa1" and "mupa2" on the union of their domains,
7989 : * with the actual sum on the shared domain and
7990 : * the defined expression on the symmetric difference of the domains.
7991 : *
7992 : * We simply iterate over the elements in both arguments and
7993 : * call isl_union_pw_aff_union_add on each of them, if there is
7994 : * at least one element.
7995 : *
7996 : * Otherwise, the two expressions have an explicit domain and
7997 : * the union of these explicit domains is computed.
7998 : * This assumes that the explicit domains are either both in terms
7999 : * of specific domains elements or both in terms of parameters.
8000 : * However, if one of the expressions does not have any constraints
8001 : * on its explicit domain, then this is allowed as well and the result
8002 : * is the expression with no constraints on its explicit domain.
8003 : */
8004 : static __isl_give isl_multi_union_pw_aff *
8005 0 : isl_multi_union_pw_aff_union_add_aligned(
8006 : __isl_take isl_multi_union_pw_aff *mupa1,
8007 : __isl_take isl_multi_union_pw_aff *mupa2)
8008 : {
8009 : isl_bool has_domain, is_params1, is_params2;
8010 :
8011 0 : if (isl_multi_union_pw_aff_check_equal_space(mupa1, mupa2) < 0)
8012 0 : goto error;
8013 0 : if (mupa1->n > 0)
8014 0 : return isl_multi_union_pw_aff_bin_op(mupa1, mupa2,
8015 : &isl_union_pw_aff_union_add);
8016 0 : if (isl_multi_union_pw_aff_check_has_explicit_domain(mupa1) < 0 ||
8017 0 : isl_multi_union_pw_aff_check_has_explicit_domain(mupa2) < 0)
8018 : goto error;
8019 :
8020 0 : has_domain = isl_multi_union_pw_aff_has_non_trivial_domain(mupa1);
8021 0 : if (has_domain < 0)
8022 0 : goto error;
8023 0 : if (!has_domain) {
8024 0 : isl_multi_union_pw_aff_free(mupa2);
8025 0 : return mupa1;
8026 : }
8027 0 : has_domain = isl_multi_union_pw_aff_has_non_trivial_domain(mupa2);
8028 0 : if (has_domain < 0)
8029 0 : goto error;
8030 0 : if (!has_domain) {
8031 0 : isl_multi_union_pw_aff_free(mupa1);
8032 0 : return mupa2;
8033 : }
8034 :
8035 0 : is_params1 = isl_union_set_is_params(mupa1->u.dom);
8036 0 : is_params2 = isl_union_set_is_params(mupa2->u.dom);
8037 0 : if (is_params1 < 0 || is_params2 < 0)
8038 : goto error;
8039 0 : if (is_params1 != is_params2)
8040 0 : isl_die(isl_multi_union_pw_aff_get_ctx(mupa1),
8041 : isl_error_invalid,
8042 : "cannot compute union of concrete domain and "
8043 : "parameter constraints", goto error);
8044 0 : mupa1 = isl_multi_union_pw_aff_cow(mupa1);
8045 0 : if (!mupa1)
8046 0 : goto error;
8047 0 : mupa1->u.dom = isl_union_set_union(mupa1->u.dom,
8048 : isl_union_set_copy(mupa2->u.dom));
8049 0 : if (!mupa1->u.dom)
8050 0 : goto error;
8051 0 : isl_multi_union_pw_aff_free(mupa2);
8052 0 : return mupa1;
8053 : error:
8054 0 : isl_multi_union_pw_aff_free(mupa1);
8055 0 : isl_multi_union_pw_aff_free(mupa2);
8056 0 : return NULL;
8057 : }
8058 :
8059 : /* Compute the sum of "mupa1" and "mupa2" on the union of their domains,
8060 : * with the actual sum on the shared domain and
8061 : * the defined expression on the symmetric difference of the domains.
8062 : */
8063 0 : __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_union_add(
8064 : __isl_take isl_multi_union_pw_aff *mupa1,
8065 : __isl_take isl_multi_union_pw_aff *mupa2)
8066 : {
8067 0 : return isl_multi_union_pw_aff_align_params_multi_multi_and(mupa1, mupa2,
8068 : &isl_multi_union_pw_aff_union_add_aligned);
8069 : }
8070 :
8071 : /* Construct and return a multi union piecewise affine expression
8072 : * that is equal to the given multi affine expression.
8073 : */
8074 0 : __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_aff(
8075 : __isl_take isl_multi_aff *ma)
8076 : {
8077 : isl_multi_pw_aff *mpa;
8078 :
8079 0 : mpa = isl_multi_pw_aff_from_multi_aff(ma);
8080 0 : return isl_multi_union_pw_aff_from_multi_pw_aff(mpa);
8081 : }
8082 :
8083 : /* Construct and return a multi union piecewise affine expression
8084 : * that is equal to the given multi piecewise affine expression.
8085 : */
8086 0 : __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_pw_aff(
8087 : __isl_take isl_multi_pw_aff *mpa)
8088 : {
8089 : int i, n;
8090 : isl_space *space;
8091 : isl_multi_union_pw_aff *mupa;
8092 :
8093 0 : if (!mpa)
8094 0 : return NULL;
8095 :
8096 0 : space = isl_multi_pw_aff_get_space(mpa);
8097 0 : space = isl_space_range(space);
8098 0 : mupa = isl_multi_union_pw_aff_alloc(space);
8099 :
8100 0 : n = isl_multi_pw_aff_dim(mpa, isl_dim_out);
8101 0 : for (i = 0; i < n; ++i) {
8102 : isl_pw_aff *pa;
8103 : isl_union_pw_aff *upa;
8104 :
8105 0 : pa = isl_multi_pw_aff_get_pw_aff(mpa, i);
8106 0 : upa = isl_union_pw_aff_from_pw_aff(pa);
8107 0 : mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);
8108 : }
8109 :
8110 0 : isl_multi_pw_aff_free(mpa);
8111 :
8112 0 : return mupa;
8113 : }
8114 :
8115 : /* Extract the range space of "pma" and assign it to *space.
8116 : * If *space has already been set (through a previous call to this function),
8117 : * then check that the range space is the same.
8118 : */
8119 0 : static isl_stat extract_space(__isl_take isl_pw_multi_aff *pma, void *user)
8120 : {
8121 0 : isl_space **space = user;
8122 : isl_space *pma_space;
8123 : isl_bool equal;
8124 :
8125 0 : pma_space = isl_space_range(isl_pw_multi_aff_get_space(pma));
8126 0 : isl_pw_multi_aff_free(pma);
8127 :
8128 0 : if (!pma_space)
8129 0 : return isl_stat_error;
8130 0 : if (!*space) {
8131 0 : *space = pma_space;
8132 0 : return isl_stat_ok;
8133 : }
8134 :
8135 0 : equal = isl_space_is_equal(pma_space, *space);
8136 0 : isl_space_free(pma_space);
8137 :
8138 0 : if (equal < 0)
8139 0 : return isl_stat_error;
8140 0 : if (!equal)
8141 0 : isl_die(isl_space_get_ctx(*space), isl_error_invalid,
8142 : "range spaces not the same", return isl_stat_error);
8143 0 : return isl_stat_ok;
8144 : }
8145 :
8146 : /* Construct and return a multi union piecewise affine expression
8147 : * that is equal to the given union piecewise multi affine expression.
8148 : *
8149 : * In order to be able to perform the conversion, the input
8150 : * needs to be non-empty and may only involve a single range space.
8151 : *
8152 : * If the resulting multi union piecewise affine expression has
8153 : * an explicit domain, then assign it the domain of the input.
8154 : * In other cases, the domain is stored in the individual elements.
8155 : */
8156 : __isl_give isl_multi_union_pw_aff *
8157 0 : isl_multi_union_pw_aff_from_union_pw_multi_aff(
8158 : __isl_take isl_union_pw_multi_aff *upma)
8159 : {
8160 0 : isl_space *space = NULL;
8161 : isl_multi_union_pw_aff *mupa;
8162 : int i, n;
8163 :
8164 0 : if (!upma)
8165 0 : return NULL;
8166 0 : if (isl_union_pw_multi_aff_n_pw_multi_aff(upma) == 0)
8167 0 : isl_die(isl_union_pw_multi_aff_get_ctx(upma), isl_error_invalid,
8168 : "cannot extract range space from empty input",
8169 : goto error);
8170 0 : if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, &extract_space,
8171 : &space) < 0)
8172 0 : goto error;
8173 :
8174 0 : if (!space)
8175 0 : goto error;
8176 :
8177 0 : n = isl_space_dim(space, isl_dim_set);
8178 0 : mupa = isl_multi_union_pw_aff_alloc(space);
8179 :
8180 0 : for (i = 0; i < n; ++i) {
8181 : isl_union_pw_aff *upa;
8182 :
8183 0 : upa = isl_union_pw_multi_aff_get_union_pw_aff(upma, i);
8184 0 : mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);
8185 : }
8186 0 : if (isl_multi_union_pw_aff_has_explicit_domain(mupa)) {
8187 : isl_union_set *dom;
8188 : isl_union_pw_multi_aff *copy;
8189 :
8190 0 : copy = isl_union_pw_multi_aff_copy(upma);
8191 0 : dom = isl_union_pw_multi_aff_domain(copy);
8192 0 : mupa = isl_multi_union_pw_aff_intersect_domain(mupa, dom);
8193 : }
8194 :
8195 0 : isl_union_pw_multi_aff_free(upma);
8196 0 : return mupa;
8197 : error:
8198 0 : isl_space_free(space);
8199 0 : isl_union_pw_multi_aff_free(upma);
8200 0 : return NULL;
8201 : }
8202 :
8203 : /* Try and create an isl_multi_union_pw_aff that is equivalent
8204 : * to the given isl_union_map.
8205 : * The isl_union_map is required to be single-valued in each space.
8206 : * Moreover, it cannot be empty and all range spaces need to be the same.
8207 : * Otherwise, an error is produced.
8208 : */
8209 0 : __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_map(
8210 : __isl_take isl_union_map *umap)
8211 : {
8212 : isl_union_pw_multi_aff *upma;
8213 :
8214 0 : upma = isl_union_pw_multi_aff_from_union_map(umap);
8215 0 : return isl_multi_union_pw_aff_from_union_pw_multi_aff(upma);
8216 : }
8217 :
8218 : /* Return a multiple union piecewise affine expression
8219 : * that is equal to "mv" on "domain", assuming "domain" and "mv"
8220 : * have been aligned.
8221 : *
8222 : * If the resulting multi union piecewise affine expression has
8223 : * an explicit domain, then assign it the input domain.
8224 : * In other cases, the domain is stored in the individual elements.
8225 : */
8226 : static __isl_give isl_multi_union_pw_aff *
8227 0 : isl_multi_union_pw_aff_multi_val_on_domain_aligned(
8228 : __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv)
8229 : {
8230 : int i, n;
8231 : isl_space *space;
8232 : isl_multi_union_pw_aff *mupa;
8233 :
8234 0 : if (!domain || !mv)
8235 : goto error;
8236 :
8237 0 : n = isl_multi_val_dim(mv, isl_dim_set);
8238 0 : space = isl_multi_val_get_space(mv);
8239 0 : mupa = isl_multi_union_pw_aff_alloc(space);
8240 0 : for (i = 0; i < n; ++i) {
8241 : isl_val *v;
8242 : isl_union_pw_aff *upa;
8243 :
8244 0 : v = isl_multi_val_get_val(mv, i);
8245 0 : upa = isl_union_pw_aff_val_on_domain(isl_union_set_copy(domain),
8246 : v);
8247 0 : mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);
8248 : }
8249 0 : if (isl_multi_union_pw_aff_has_explicit_domain(mupa))
8250 0 : mupa = isl_multi_union_pw_aff_intersect_domain(mupa,
8251 : isl_union_set_copy(domain));
8252 :
8253 0 : isl_union_set_free(domain);
8254 0 : isl_multi_val_free(mv);
8255 0 : return mupa;
8256 : error:
8257 0 : isl_union_set_free(domain);
8258 0 : isl_multi_val_free(mv);
8259 0 : return NULL;
8260 : }
8261 :
8262 : /* Return a multiple union piecewise affine expression
8263 : * that is equal to "mv" on "domain".
8264 : */
8265 0 : __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_val_on_domain(
8266 : __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv)
8267 : {
8268 : isl_bool equal_params;
8269 :
8270 0 : if (!domain || !mv)
8271 : goto error;
8272 0 : equal_params = isl_space_has_equal_params(domain->dim, mv->space);
8273 0 : if (equal_params < 0)
8274 0 : goto error;
8275 0 : if (equal_params)
8276 0 : return isl_multi_union_pw_aff_multi_val_on_domain_aligned(
8277 : domain, mv);
8278 0 : domain = isl_union_set_align_params(domain,
8279 : isl_multi_val_get_space(mv));
8280 0 : mv = isl_multi_val_align_params(mv, isl_union_set_get_space(domain));
8281 0 : return isl_multi_union_pw_aff_multi_val_on_domain_aligned(domain, mv);
8282 : error:
8283 0 : isl_union_set_free(domain);
8284 0 : isl_multi_val_free(mv);
8285 0 : return NULL;
8286 : }
8287 :
8288 : /* Return a multiple union piecewise affine expression
8289 : * that is equal to "ma" on "domain".
8290 : */
8291 0 : __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_aff_on_domain(
8292 : __isl_take isl_union_set *domain, __isl_take isl_multi_aff *ma)
8293 : {
8294 : isl_pw_multi_aff *pma;
8295 :
8296 0 : pma = isl_pw_multi_aff_from_multi_aff(ma);
8297 0 : return isl_multi_union_pw_aff_pw_multi_aff_on_domain(domain, pma);
8298 : }
8299 :
8300 : /* Return a multiple union piecewise affine expression
8301 : * that is equal to "pma" on "domain", assuming "domain" and "pma"
8302 : * have been aligned.
8303 : *
8304 : * If the resulting multi union piecewise affine expression has
8305 : * an explicit domain, then assign it the input domain.
8306 : * In other cases, the domain is stored in the individual elements.
8307 : */
8308 : static __isl_give isl_multi_union_pw_aff *
8309 0 : isl_multi_union_pw_aff_pw_multi_aff_on_domain_aligned(
8310 : __isl_take isl_union_set *domain, __isl_take isl_pw_multi_aff *pma)
8311 : {
8312 : int i, n;
8313 : isl_space *space;
8314 : isl_multi_union_pw_aff *mupa;
8315 :
8316 0 : if (!domain || !pma)
8317 : goto error;
8318 :
8319 0 : n = isl_pw_multi_aff_dim(pma, isl_dim_set);
8320 0 : space = isl_pw_multi_aff_get_space(pma);
8321 0 : mupa = isl_multi_union_pw_aff_alloc(space);
8322 0 : for (i = 0; i < n; ++i) {
8323 : isl_pw_aff *pa;
8324 : isl_union_pw_aff *upa;
8325 :
8326 0 : pa = isl_pw_multi_aff_get_pw_aff(pma, i);
8327 0 : upa = isl_union_pw_aff_pw_aff_on_domain(
8328 : isl_union_set_copy(domain), pa);
8329 0 : mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);
8330 : }
8331 0 : if (isl_multi_union_pw_aff_has_explicit_domain(mupa))
8332 0 : mupa = isl_multi_union_pw_aff_intersect_domain(mupa,
8333 : isl_union_set_copy(domain));
8334 :
8335 0 : isl_union_set_free(domain);
8336 0 : isl_pw_multi_aff_free(pma);
8337 0 : return mupa;
8338 : error:
8339 0 : isl_union_set_free(domain);
8340 0 : isl_pw_multi_aff_free(pma);
8341 0 : return NULL;
8342 : }
8343 :
8344 : /* Return a multiple union piecewise affine expression
8345 : * that is equal to "pma" on "domain".
8346 : */
8347 : __isl_give isl_multi_union_pw_aff *
8348 0 : isl_multi_union_pw_aff_pw_multi_aff_on_domain(__isl_take isl_union_set *domain,
8349 : __isl_take isl_pw_multi_aff *pma)
8350 : {
8351 : isl_bool equal_params;
8352 : isl_space *space;
8353 :
8354 0 : space = isl_pw_multi_aff_peek_space(pma);
8355 0 : equal_params = isl_union_set_space_has_equal_params(domain, space);
8356 0 : if (equal_params < 0)
8357 0 : goto error;
8358 0 : if (equal_params)
8359 0 : return isl_multi_union_pw_aff_pw_multi_aff_on_domain_aligned(
8360 : domain, pma);
8361 0 : domain = isl_union_set_align_params(domain,
8362 : isl_pw_multi_aff_get_space(pma));
8363 0 : pma = isl_pw_multi_aff_align_params(pma,
8364 : isl_union_set_get_space(domain));
8365 0 : return isl_multi_union_pw_aff_pw_multi_aff_on_domain_aligned(domain,
8366 : pma);
8367 : error:
8368 0 : isl_union_set_free(domain);
8369 0 : isl_pw_multi_aff_free(pma);
8370 0 : return NULL;
8371 : }
8372 :
8373 : /* Return a union set containing those elements in the domains
8374 : * of the elements of "mupa" where they are all zero.
8375 : *
8376 : * If there are no elements, then simply return the entire domain.
8377 : */
8378 0 : __isl_give isl_union_set *isl_multi_union_pw_aff_zero_union_set(
8379 : __isl_take isl_multi_union_pw_aff *mupa)
8380 : {
8381 : int i, n;
8382 : isl_union_pw_aff *upa;
8383 : isl_union_set *zero;
8384 :
8385 0 : if (!mupa)
8386 0 : return NULL;
8387 :
8388 0 : n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
8389 0 : if (n == 0)
8390 0 : return isl_multi_union_pw_aff_domain(mupa);
8391 :
8392 0 : upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0);
8393 0 : zero = isl_union_pw_aff_zero_union_set(upa);
8394 :
8395 0 : for (i = 1; i < n; ++i) {
8396 : isl_union_set *zero_i;
8397 :
8398 0 : upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
8399 0 : zero_i = isl_union_pw_aff_zero_union_set(upa);
8400 :
8401 0 : zero = isl_union_set_intersect(zero, zero_i);
8402 : }
8403 :
8404 0 : isl_multi_union_pw_aff_free(mupa);
8405 0 : return zero;
8406 : }
8407 :
8408 : /* Construct a union map mapping the shared domain
8409 : * of the union piecewise affine expressions to the range of "mupa"
8410 : * in the special case of a 0D multi union piecewise affine expression.
8411 : *
8412 : * Construct a map between the explicit domain of "mupa" and
8413 : * the range space.
8414 : * Note that this assumes that the domain consists of explicit elements.
8415 : */
8416 0 : static __isl_give isl_union_map *isl_union_map_from_multi_union_pw_aff_0D(
8417 : __isl_take isl_multi_union_pw_aff *mupa)
8418 : {
8419 : isl_bool is_params;
8420 : isl_space *space;
8421 : isl_union_set *dom, *ran;
8422 :
8423 0 : space = isl_multi_union_pw_aff_get_space(mupa);
8424 0 : dom = isl_multi_union_pw_aff_domain(mupa);
8425 0 : ran = isl_union_set_from_set(isl_set_universe(space));
8426 :
8427 0 : is_params = isl_union_set_is_params(dom);
8428 0 : if (is_params < 0)
8429 0 : dom = isl_union_set_free(dom);
8430 0 : else if (is_params)
8431 0 : isl_die(isl_union_set_get_ctx(dom), isl_error_invalid,
8432 : "cannot create union map from expression without "
8433 : "explicit domain elements",
8434 : dom = isl_union_set_free(dom));
8435 :
8436 0 : return isl_union_map_from_domain_and_range(dom, ran);
8437 : }
8438 :
8439 : /* Construct a union map mapping the shared domain
8440 : * of the union piecewise affine expressions to the range of "mupa"
8441 : * with each dimension in the range equated to the
8442 : * corresponding union piecewise affine expression.
8443 : *
8444 : * If the input is zero-dimensional, then construct a mapping
8445 : * from its explicit domain.
8446 : */
8447 0 : __isl_give isl_union_map *isl_union_map_from_multi_union_pw_aff(
8448 : __isl_take isl_multi_union_pw_aff *mupa)
8449 : {
8450 : int i, n;
8451 : isl_space *space;
8452 : isl_union_map *umap;
8453 : isl_union_pw_aff *upa;
8454 :
8455 0 : if (!mupa)
8456 0 : return NULL;
8457 :
8458 0 : n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
8459 0 : if (n == 0)
8460 0 : return isl_union_map_from_multi_union_pw_aff_0D(mupa);
8461 :
8462 0 : upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0);
8463 0 : umap = isl_union_map_from_union_pw_aff(upa);
8464 :
8465 0 : for (i = 1; i < n; ++i) {
8466 : isl_union_map *umap_i;
8467 :
8468 0 : upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
8469 0 : umap_i = isl_union_map_from_union_pw_aff(upa);
8470 0 : umap = isl_union_map_flat_range_product(umap, umap_i);
8471 : }
8472 :
8473 0 : space = isl_multi_union_pw_aff_get_space(mupa);
8474 0 : umap = isl_union_map_reset_range_space(umap, space);
8475 :
8476 0 : isl_multi_union_pw_aff_free(mupa);
8477 0 : return umap;
8478 : }
8479 :
8480 : /* Internal data structure for isl_union_pw_multi_aff_reset_range_space.
8481 : * "range" is the space from which to set the range space.
8482 : * "res" collects the results.
8483 : */
8484 : struct isl_union_pw_multi_aff_reset_range_space_data {
8485 : isl_space *range;
8486 : isl_union_pw_multi_aff *res;
8487 : };
8488 :
8489 : /* Replace the range space of "pma" by the range space of data->range and
8490 : * add the result to data->res.
8491 : */
8492 0 : static isl_stat reset_range_space(__isl_take isl_pw_multi_aff *pma, void *user)
8493 : {
8494 0 : struct isl_union_pw_multi_aff_reset_range_space_data *data = user;
8495 : isl_space *space;
8496 :
8497 0 : space = isl_pw_multi_aff_get_space(pma);
8498 0 : space = isl_space_domain(space);
8499 0 : space = isl_space_extend_domain_with_range(space,
8500 : isl_space_copy(data->range));
8501 0 : pma = isl_pw_multi_aff_reset_space(pma, space);
8502 0 : data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma);
8503 :
8504 0 : return data->res ? isl_stat_ok : isl_stat_error;
8505 : }
8506 :
8507 : /* Replace the range space of all the piecewise affine expressions in "upma" by
8508 : * the range space of "space".
8509 : *
8510 : * This assumes that all these expressions have the same output dimension.
8511 : *
8512 : * Since the spaces of the expressions change, so do their hash values.
8513 : * We therefore need to create a new isl_union_pw_multi_aff.
8514 : * Note that the hash value is currently computed based on the entire
8515 : * space even though there can only be a single expression with a given
8516 : * domain space.
8517 : */
8518 : static __isl_give isl_union_pw_multi_aff *
8519 0 : isl_union_pw_multi_aff_reset_range_space(
8520 : __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_space *space)
8521 : {
8522 0 : struct isl_union_pw_multi_aff_reset_range_space_data data = { space };
8523 : isl_space *space_upma;
8524 :
8525 0 : space_upma = isl_union_pw_multi_aff_get_space(upma);
8526 0 : data.res = isl_union_pw_multi_aff_empty(space_upma);
8527 0 : if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
8528 : &reset_range_space, &data) < 0)
8529 0 : data.res = isl_union_pw_multi_aff_free(data.res);
8530 :
8531 0 : isl_space_free(space);
8532 0 : isl_union_pw_multi_aff_free(upma);
8533 0 : return data.res;
8534 : }
8535 :
8536 : /* Construct and return a union piecewise multi affine expression
8537 : * that is equal to the given multi union piecewise affine expression,
8538 : * in the special case of a 0D multi union piecewise affine expression.
8539 : *
8540 : * Construct a union piecewise multi affine expression
8541 : * on top of the explicit domain of the input.
8542 : */
8543 : __isl_give isl_union_pw_multi_aff *
8544 0 : isl_union_pw_multi_aff_from_multi_union_pw_aff_0D(
8545 : __isl_take isl_multi_union_pw_aff *mupa)
8546 : {
8547 : isl_space *space;
8548 : isl_multi_val *mv;
8549 : isl_union_set *domain;
8550 :
8551 0 : space = isl_multi_union_pw_aff_get_space(mupa);
8552 0 : mv = isl_multi_val_zero(space);
8553 0 : domain = isl_multi_union_pw_aff_domain(mupa);
8554 0 : return isl_union_pw_multi_aff_multi_val_on_domain(domain, mv);
8555 : }
8556 :
8557 : /* Construct and return a union piecewise multi affine expression
8558 : * that is equal to the given multi union piecewise affine expression.
8559 : *
8560 : * If the input is zero-dimensional, then
8561 : * construct a union piecewise multi affine expression
8562 : * on top of the explicit domain of the input.
8563 : */
8564 : __isl_give isl_union_pw_multi_aff *
8565 0 : isl_union_pw_multi_aff_from_multi_union_pw_aff(
8566 : __isl_take isl_multi_union_pw_aff *mupa)
8567 : {
8568 : int i, n;
8569 : isl_space *space;
8570 : isl_union_pw_multi_aff *upma;
8571 : isl_union_pw_aff *upa;
8572 :
8573 0 : if (!mupa)
8574 0 : return NULL;
8575 :
8576 0 : n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
8577 0 : if (n == 0)
8578 0 : return isl_union_pw_multi_aff_from_multi_union_pw_aff_0D(mupa);
8579 :
8580 0 : space = isl_multi_union_pw_aff_get_space(mupa);
8581 0 : upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0);
8582 0 : upma = isl_union_pw_multi_aff_from_union_pw_aff(upa);
8583 :
8584 0 : for (i = 1; i < n; ++i) {
8585 : isl_union_pw_multi_aff *upma_i;
8586 :
8587 0 : upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
8588 0 : upma_i = isl_union_pw_multi_aff_from_union_pw_aff(upa);
8589 0 : upma = isl_union_pw_multi_aff_flat_range_product(upma, upma_i);
8590 : }
8591 :
8592 0 : upma = isl_union_pw_multi_aff_reset_range_space(upma, space);
8593 :
8594 0 : isl_multi_union_pw_aff_free(mupa);
8595 0 : return upma;
8596 : }
8597 :
8598 : /* Intersect the range of "mupa" with "range",
8599 : * in the special case where "mupa" is 0D.
8600 : *
8601 : * Intersect the domain of "mupa" with the constraints on the parameters
8602 : * of "range".
8603 : */
8604 0 : static __isl_give isl_multi_union_pw_aff *mupa_intersect_range_0D(
8605 : __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *range)
8606 : {
8607 0 : range = isl_set_params(range);
8608 0 : mupa = isl_multi_union_pw_aff_intersect_params(mupa, range);
8609 0 : return mupa;
8610 : }
8611 :
8612 : /* Intersect the range of "mupa" with "range".
8613 : * That is, keep only those domain elements that have a function value
8614 : * in "range".
8615 : */
8616 0 : __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_range(
8617 : __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *range)
8618 : {
8619 : isl_union_pw_multi_aff *upma;
8620 : isl_union_set *domain;
8621 : isl_space *space;
8622 : int n;
8623 : int match;
8624 :
8625 0 : if (!mupa || !range)
8626 : goto error;
8627 :
8628 0 : space = isl_set_get_space(range);
8629 0 : match = isl_space_tuple_is_equal(mupa->space, isl_dim_set,
8630 : space, isl_dim_set);
8631 0 : isl_space_free(space);
8632 0 : if (match < 0)
8633 0 : goto error;
8634 0 : if (!match)
8635 0 : isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid,
8636 : "space don't match", goto error);
8637 0 : n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
8638 0 : if (n == 0)
8639 0 : return mupa_intersect_range_0D(mupa, range);
8640 :
8641 0 : upma = isl_union_pw_multi_aff_from_multi_union_pw_aff(
8642 : isl_multi_union_pw_aff_copy(mupa));
8643 0 : domain = isl_union_set_from_set(range);
8644 0 : domain = isl_union_set_preimage_union_pw_multi_aff(domain, upma);
8645 0 : mupa = isl_multi_union_pw_aff_intersect_domain(mupa, domain);
8646 :
8647 0 : return mupa;
8648 : error:
8649 0 : isl_multi_union_pw_aff_free(mupa);
8650 0 : isl_set_free(range);
8651 0 : return NULL;
8652 : }
8653 :
8654 : /* Return the shared domain of the elements of "mupa",
8655 : * in the special case where "mupa" is zero-dimensional.
8656 : *
8657 : * Return the explicit domain of "mupa".
8658 : * Note that this domain may be a parameter set, either
8659 : * because "mupa" is meant to live in a set space or
8660 : * because no explicit domain has been set.
8661 : */
8662 0 : __isl_give isl_union_set *isl_multi_union_pw_aff_domain_0D(
8663 : __isl_take isl_multi_union_pw_aff *mupa)
8664 : {
8665 : isl_union_set *dom;
8666 :
8667 0 : dom = isl_multi_union_pw_aff_get_explicit_domain(mupa);
8668 0 : isl_multi_union_pw_aff_free(mupa);
8669 :
8670 0 : return dom;
8671 : }
8672 :
8673 : /* Return the shared domain of the elements of "mupa".
8674 : *
8675 : * If "mupa" is zero-dimensional, then return its explicit domain.
8676 : */
8677 0 : __isl_give isl_union_set *isl_multi_union_pw_aff_domain(
8678 : __isl_take isl_multi_union_pw_aff *mupa)
8679 : {
8680 : int i, n;
8681 : isl_union_pw_aff *upa;
8682 : isl_union_set *dom;
8683 :
8684 0 : if (!mupa)
8685 0 : return NULL;
8686 :
8687 0 : n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
8688 0 : if (n == 0)
8689 0 : return isl_multi_union_pw_aff_domain_0D(mupa);
8690 :
8691 0 : upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0);
8692 0 : dom = isl_union_pw_aff_domain(upa);
8693 0 : for (i = 1; i < n; ++i) {
8694 : isl_union_set *dom_i;
8695 :
8696 0 : upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
8697 0 : dom_i = isl_union_pw_aff_domain(upa);
8698 0 : dom = isl_union_set_intersect(dom, dom_i);
8699 : }
8700 :
8701 0 : isl_multi_union_pw_aff_free(mupa);
8702 0 : return dom;
8703 : }
8704 :
8705 : /* Apply "aff" to "mupa". The space of "mupa" is equal to the domain of "aff".
8706 : * In particular, the spaces have been aligned.
8707 : * The result is defined over the shared domain of the elements of "mupa"
8708 : *
8709 : * We first extract the parametric constant part of "aff" and
8710 : * define that over the shared domain.
8711 : * Then we iterate over all input dimensions of "aff" and add the corresponding
8712 : * multiples of the elements of "mupa".
8713 : * Finally, we consider the integer divisions, calling the function
8714 : * recursively to obtain an isl_union_pw_aff corresponding to the
8715 : * integer division argument.
8716 : */
8717 0 : static __isl_give isl_union_pw_aff *multi_union_pw_aff_apply_aff(
8718 : __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff)
8719 : {
8720 : int i, n_in, n_div;
8721 : isl_union_pw_aff *upa;
8722 : isl_union_set *uset;
8723 : isl_val *v;
8724 : isl_aff *cst;
8725 :
8726 0 : n_in = isl_aff_dim(aff, isl_dim_in);
8727 0 : n_div = isl_aff_dim(aff, isl_dim_div);
8728 :
8729 0 : uset = isl_multi_union_pw_aff_domain(isl_multi_union_pw_aff_copy(mupa));
8730 0 : cst = isl_aff_copy(aff);
8731 0 : cst = isl_aff_drop_dims(cst, isl_dim_div, 0, n_div);
8732 0 : cst = isl_aff_drop_dims(cst, isl_dim_in, 0, n_in);
8733 0 : cst = isl_aff_project_domain_on_params(cst);
8734 0 : upa = isl_union_pw_aff_aff_on_domain(uset, cst);
8735 :
8736 0 : for (i = 0; i < n_in; ++i) {
8737 : isl_union_pw_aff *upa_i;
8738 :
8739 0 : if (!isl_aff_involves_dims(aff, isl_dim_in, i, 1))
8740 0 : continue;
8741 0 : v = isl_aff_get_coefficient_val(aff, isl_dim_in, i);
8742 0 : upa_i = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
8743 0 : upa_i = isl_union_pw_aff_scale_val(upa_i, v);
8744 0 : upa = isl_union_pw_aff_add(upa, upa_i);
8745 : }
8746 :
8747 0 : for (i = 0; i < n_div; ++i) {
8748 : isl_aff *div;
8749 : isl_union_pw_aff *upa_i;
8750 :
8751 0 : if (!isl_aff_involves_dims(aff, isl_dim_div, i, 1))
8752 0 : continue;
8753 0 : div = isl_aff_get_div(aff, i);
8754 0 : upa_i = multi_union_pw_aff_apply_aff(
8755 : isl_multi_union_pw_aff_copy(mupa), div);
8756 0 : upa_i = isl_union_pw_aff_floor(upa_i);
8757 0 : v = isl_aff_get_coefficient_val(aff, isl_dim_div, i);
8758 0 : upa_i = isl_union_pw_aff_scale_val(upa_i, v);
8759 0 : upa = isl_union_pw_aff_add(upa, upa_i);
8760 : }
8761 :
8762 0 : isl_multi_union_pw_aff_free(mupa);
8763 0 : isl_aff_free(aff);
8764 :
8765 0 : return upa;
8766 : }
8767 :
8768 : /* Apply "aff" to "mupa". The space of "mupa" needs to be compatible
8769 : * with the domain of "aff".
8770 : * Furthermore, the dimension of this space needs to be greater than zero.
8771 : * The result is defined over the shared domain of the elements of "mupa"
8772 : *
8773 : * We perform these checks and then hand over control to
8774 : * multi_union_pw_aff_apply_aff.
8775 : */
8776 0 : __isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_aff(
8777 : __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff)
8778 : {
8779 : isl_space *space1, *space2;
8780 : int equal;
8781 :
8782 0 : mupa = isl_multi_union_pw_aff_align_params(mupa,
8783 : isl_aff_get_space(aff));
8784 0 : aff = isl_aff_align_params(aff, isl_multi_union_pw_aff_get_space(mupa));
8785 0 : if (!mupa || !aff)
8786 : goto error;
8787 :
8788 0 : space1 = isl_multi_union_pw_aff_get_space(mupa);
8789 0 : space2 = isl_aff_get_domain_space(aff);
8790 0 : equal = isl_space_is_equal(space1, space2);
8791 0 : isl_space_free(space1);
8792 0 : isl_space_free(space2);
8793 0 : if (equal < 0)
8794 0 : goto error;
8795 0 : if (!equal)
8796 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
8797 : "spaces don't match", goto error);
8798 0 : if (isl_aff_dim(aff, isl_dim_in) == 0)
8799 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
8800 : "cannot determine domains", goto error);
8801 :
8802 0 : return multi_union_pw_aff_apply_aff(mupa, aff);
8803 : error:
8804 0 : isl_multi_union_pw_aff_free(mupa);
8805 0 : isl_aff_free(aff);
8806 0 : return NULL;
8807 : }
8808 :
8809 : /* Apply "ma" to "mupa", in the special case where "mupa" is 0D.
8810 : * The space of "mupa" is known to be compatible with the domain of "ma".
8811 : *
8812 : * Construct an isl_multi_union_pw_aff that is equal to "ma"
8813 : * on the domain of "mupa".
8814 : */
8815 0 : static __isl_give isl_multi_union_pw_aff *mupa_apply_multi_aff_0D(
8816 : __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma)
8817 : {
8818 : isl_union_set *dom;
8819 :
8820 0 : dom = isl_multi_union_pw_aff_domain(mupa);
8821 0 : ma = isl_multi_aff_project_domain_on_params(ma);
8822 :
8823 0 : return isl_multi_union_pw_aff_multi_aff_on_domain(dom, ma);
8824 : }
8825 :
8826 : /* Apply "ma" to "mupa". The space of "mupa" needs to be compatible
8827 : * with the domain of "ma".
8828 : * The result is defined over the shared domain of the elements of "mupa"
8829 : */
8830 0 : __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_multi_aff(
8831 : __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma)
8832 : {
8833 : isl_space *space1, *space2;
8834 : isl_multi_union_pw_aff *res;
8835 : int equal;
8836 : int i, n_out;
8837 :
8838 0 : mupa = isl_multi_union_pw_aff_align_params(mupa,
8839 : isl_multi_aff_get_space(ma));
8840 0 : ma = isl_multi_aff_align_params(ma,
8841 : isl_multi_union_pw_aff_get_space(mupa));
8842 0 : if (!mupa || !ma)
8843 : goto error;
8844 :
8845 0 : space1 = isl_multi_union_pw_aff_get_space(mupa);
8846 0 : space2 = isl_multi_aff_get_domain_space(ma);
8847 0 : equal = isl_space_is_equal(space1, space2);
8848 0 : isl_space_free(space1);
8849 0 : isl_space_free(space2);
8850 0 : if (equal < 0)
8851 0 : goto error;
8852 0 : if (!equal)
8853 0 : isl_die(isl_multi_aff_get_ctx(ma), isl_error_invalid,
8854 : "spaces don't match", goto error);
8855 0 : n_out = isl_multi_aff_dim(ma, isl_dim_out);
8856 0 : if (isl_multi_aff_dim(ma, isl_dim_in) == 0)
8857 0 : return mupa_apply_multi_aff_0D(mupa, ma);
8858 :
8859 0 : space1 = isl_space_range(isl_multi_aff_get_space(ma));
8860 0 : res = isl_multi_union_pw_aff_alloc(space1);
8861 :
8862 0 : for (i = 0; i < n_out; ++i) {
8863 : isl_aff *aff;
8864 : isl_union_pw_aff *upa;
8865 :
8866 0 : aff = isl_multi_aff_get_aff(ma, i);
8867 0 : upa = multi_union_pw_aff_apply_aff(
8868 : isl_multi_union_pw_aff_copy(mupa), aff);
8869 0 : res = isl_multi_union_pw_aff_set_union_pw_aff(res, i, upa);
8870 : }
8871 :
8872 0 : isl_multi_aff_free(ma);
8873 0 : isl_multi_union_pw_aff_free(mupa);
8874 0 : return res;
8875 : error:
8876 0 : isl_multi_union_pw_aff_free(mupa);
8877 0 : isl_multi_aff_free(ma);
8878 0 : return NULL;
8879 : }
8880 :
8881 : /* Apply "pa" to "mupa", in the special case where "mupa" is 0D.
8882 : * The space of "mupa" is known to be compatible with the domain of "pa".
8883 : *
8884 : * Construct an isl_multi_union_pw_aff that is equal to "pa"
8885 : * on the domain of "mupa".
8886 : */
8887 0 : static __isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_pw_aff_0D(
8888 : __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_pw_aff *pa)
8889 : {
8890 : isl_union_set *dom;
8891 :
8892 0 : dom = isl_multi_union_pw_aff_domain(mupa);
8893 0 : pa = isl_pw_aff_project_domain_on_params(pa);
8894 :
8895 0 : return isl_union_pw_aff_pw_aff_on_domain(dom, pa);
8896 : }
8897 :
8898 : /* Apply "pa" to "mupa". The space of "mupa" needs to be compatible
8899 : * with the domain of "pa".
8900 : * Furthermore, the dimension of this space needs to be greater than zero.
8901 : * The result is defined over the shared domain of the elements of "mupa"
8902 : */
8903 0 : __isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_pw_aff(
8904 : __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_pw_aff *pa)
8905 : {
8906 : int i;
8907 : int equal;
8908 : isl_space *space, *space2;
8909 : isl_union_pw_aff *upa;
8910 :
8911 0 : mupa = isl_multi_union_pw_aff_align_params(mupa,
8912 : isl_pw_aff_get_space(pa));
8913 0 : pa = isl_pw_aff_align_params(pa,
8914 : isl_multi_union_pw_aff_get_space(mupa));
8915 0 : if (!mupa || !pa)
8916 : goto error;
8917 :
8918 0 : space = isl_multi_union_pw_aff_get_space(mupa);
8919 0 : space2 = isl_pw_aff_get_domain_space(pa);
8920 0 : equal = isl_space_is_equal(space, space2);
8921 0 : isl_space_free(space);
8922 0 : isl_space_free(space2);
8923 0 : if (equal < 0)
8924 0 : goto error;
8925 0 : if (!equal)
8926 0 : isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
8927 : "spaces don't match", goto error);
8928 0 : if (isl_pw_aff_dim(pa, isl_dim_in) == 0)
8929 0 : return isl_multi_union_pw_aff_apply_pw_aff_0D(mupa, pa);
8930 :
8931 0 : space = isl_space_params(isl_multi_union_pw_aff_get_space(mupa));
8932 0 : upa = isl_union_pw_aff_empty(space);
8933 :
8934 0 : for (i = 0; i < pa->n; ++i) {
8935 : isl_aff *aff;
8936 : isl_set *domain;
8937 : isl_multi_union_pw_aff *mupa_i;
8938 : isl_union_pw_aff *upa_i;
8939 :
8940 0 : mupa_i = isl_multi_union_pw_aff_copy(mupa);
8941 0 : domain = isl_set_copy(pa->p[i].set);
8942 0 : mupa_i = isl_multi_union_pw_aff_intersect_range(mupa_i, domain);
8943 0 : aff = isl_aff_copy(pa->p[i].aff);
8944 0 : upa_i = multi_union_pw_aff_apply_aff(mupa_i, aff);
8945 0 : upa = isl_union_pw_aff_union_add(upa, upa_i);
8946 : }
8947 :
8948 0 : isl_multi_union_pw_aff_free(mupa);
8949 0 : isl_pw_aff_free(pa);
8950 0 : return upa;
8951 : error:
8952 0 : isl_multi_union_pw_aff_free(mupa);
8953 0 : isl_pw_aff_free(pa);
8954 0 : return NULL;
8955 : }
8956 :
8957 : /* Apply "pma" to "mupa", in the special case where "mupa" is 0D.
8958 : * The space of "mupa" is known to be compatible with the domain of "pma".
8959 : *
8960 : * Construct an isl_multi_union_pw_aff that is equal to "pma"
8961 : * on the domain of "mupa".
8962 : */
8963 0 : static __isl_give isl_multi_union_pw_aff *mupa_apply_pw_multi_aff_0D(
8964 : __isl_take isl_multi_union_pw_aff *mupa,
8965 : __isl_take isl_pw_multi_aff *pma)
8966 : {
8967 : isl_union_set *dom;
8968 :
8969 0 : dom = isl_multi_union_pw_aff_domain(mupa);
8970 0 : pma = isl_pw_multi_aff_project_domain_on_params(pma);
8971 :
8972 0 : return isl_multi_union_pw_aff_pw_multi_aff_on_domain(dom, pma);
8973 : }
8974 :
8975 : /* Apply "pma" to "mupa". The space of "mupa" needs to be compatible
8976 : * with the domain of "pma".
8977 : * The result is defined over the shared domain of the elements of "mupa"
8978 : */
8979 0 : __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_pw_multi_aff(
8980 : __isl_take isl_multi_union_pw_aff *mupa,
8981 : __isl_take isl_pw_multi_aff *pma)
8982 : {
8983 : isl_space *space1, *space2;
8984 : isl_multi_union_pw_aff *res;
8985 : int equal;
8986 : int i, n_out;
8987 :
8988 0 : mupa = isl_multi_union_pw_aff_align_params(mupa,
8989 : isl_pw_multi_aff_get_space(pma));
8990 0 : pma = isl_pw_multi_aff_align_params(pma,
8991 : isl_multi_union_pw_aff_get_space(mupa));
8992 0 : if (!mupa || !pma)
8993 : goto error;
8994 :
8995 0 : space1 = isl_multi_union_pw_aff_get_space(mupa);
8996 0 : space2 = isl_pw_multi_aff_get_domain_space(pma);
8997 0 : equal = isl_space_is_equal(space1, space2);
8998 0 : isl_space_free(space1);
8999 0 : isl_space_free(space2);
9000 0 : if (equal < 0)
9001 0 : goto error;
9002 0 : if (!equal)
9003 0 : isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
9004 : "spaces don't match", goto error);
9005 0 : n_out = isl_pw_multi_aff_dim(pma, isl_dim_out);
9006 0 : if (isl_pw_multi_aff_dim(pma, isl_dim_in) == 0)
9007 0 : return mupa_apply_pw_multi_aff_0D(mupa, pma);
9008 :
9009 0 : space1 = isl_space_range(isl_pw_multi_aff_get_space(pma));
9010 0 : res = isl_multi_union_pw_aff_alloc(space1);
9011 :
9012 0 : for (i = 0; i < n_out; ++i) {
9013 : isl_pw_aff *pa;
9014 : isl_union_pw_aff *upa;
9015 :
9016 0 : pa = isl_pw_multi_aff_get_pw_aff(pma, i);
9017 0 : upa = isl_multi_union_pw_aff_apply_pw_aff(
9018 : isl_multi_union_pw_aff_copy(mupa), pa);
9019 0 : res = isl_multi_union_pw_aff_set_union_pw_aff(res, i, upa);
9020 : }
9021 :
9022 0 : isl_pw_multi_aff_free(pma);
9023 0 : isl_multi_union_pw_aff_free(mupa);
9024 0 : return res;
9025 : error:
9026 0 : isl_multi_union_pw_aff_free(mupa);
9027 0 : isl_pw_multi_aff_free(pma);
9028 0 : return NULL;
9029 : }
9030 :
9031 : /* Replace the explicit domain of "mupa" by its preimage under "upma".
9032 : * If the explicit domain only keeps track of constraints on the parameters,
9033 : * then only update those constraints.
9034 : */
9035 0 : static __isl_give isl_multi_union_pw_aff *preimage_explicit_domain(
9036 : __isl_take isl_multi_union_pw_aff *mupa,
9037 : __isl_keep isl_union_pw_multi_aff *upma)
9038 : {
9039 : isl_bool is_params;
9040 :
9041 0 : if (isl_multi_union_pw_aff_check_has_explicit_domain(mupa) < 0)
9042 0 : return isl_multi_union_pw_aff_free(mupa);
9043 :
9044 0 : mupa = isl_multi_union_pw_aff_cow(mupa);
9045 0 : if (!mupa)
9046 0 : return NULL;
9047 :
9048 0 : is_params = isl_union_set_is_params(mupa->u.dom);
9049 0 : if (is_params < 0)
9050 0 : return isl_multi_union_pw_aff_free(mupa);
9051 :
9052 0 : upma = isl_union_pw_multi_aff_copy(upma);
9053 0 : if (is_params)
9054 0 : mupa->u.dom = isl_union_set_intersect_params(mupa->u.dom,
9055 : isl_union_set_params(isl_union_pw_multi_aff_domain(upma)));
9056 : else
9057 0 : mupa->u.dom = isl_union_set_preimage_union_pw_multi_aff(
9058 : mupa->u.dom, upma);
9059 0 : if (!mupa->u.dom)
9060 0 : return isl_multi_union_pw_aff_free(mupa);
9061 0 : return mupa;
9062 : }
9063 :
9064 : /* Compute the pullback of "mupa" by the function represented by "upma".
9065 : * In other words, plug in "upma" in "mupa". The result contains
9066 : * expressions defined over the domain space of "upma".
9067 : *
9068 : * Run over all elements of "mupa" and plug in "upma" in each of them.
9069 : *
9070 : * If "mupa" has an explicit domain, then it is this domain
9071 : * that needs to undergo a pullback instead, i.e., a preimage.
9072 : */
9073 : __isl_give isl_multi_union_pw_aff *
9074 0 : isl_multi_union_pw_aff_pullback_union_pw_multi_aff(
9075 : __isl_take isl_multi_union_pw_aff *mupa,
9076 : __isl_take isl_union_pw_multi_aff *upma)
9077 : {
9078 : int i, n;
9079 :
9080 0 : mupa = isl_multi_union_pw_aff_align_params(mupa,
9081 : isl_union_pw_multi_aff_get_space(upma));
9082 0 : upma = isl_union_pw_multi_aff_align_params(upma,
9083 : isl_multi_union_pw_aff_get_space(mupa));
9084 0 : mupa = isl_multi_union_pw_aff_cow(mupa);
9085 0 : if (!mupa || !upma)
9086 : goto error;
9087 :
9088 0 : n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
9089 0 : for (i = 0; i < n; ++i) {
9090 : isl_union_pw_aff *upa;
9091 :
9092 0 : upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
9093 0 : upa = isl_union_pw_aff_pullback_union_pw_multi_aff(upa,
9094 : isl_union_pw_multi_aff_copy(upma));
9095 0 : mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);
9096 : }
9097 :
9098 0 : if (isl_multi_union_pw_aff_has_explicit_domain(mupa))
9099 0 : mupa = preimage_explicit_domain(mupa, upma);
9100 :
9101 0 : isl_union_pw_multi_aff_free(upma);
9102 0 : return mupa;
9103 : error:
9104 0 : isl_multi_union_pw_aff_free(mupa);
9105 0 : isl_union_pw_multi_aff_free(upma);
9106 0 : return NULL;
9107 : }
9108 :
9109 : /* Extract the sequence of elements in "mupa" with domain space "space"
9110 : * (ignoring parameters).
9111 : *
9112 : * For the elements of "mupa" that are not defined on the specified space,
9113 : * the corresponding element in the result is empty.
9114 : */
9115 0 : __isl_give isl_multi_pw_aff *isl_multi_union_pw_aff_extract_multi_pw_aff(
9116 : __isl_keep isl_multi_union_pw_aff *mupa, __isl_take isl_space *space)
9117 : {
9118 : int i, n;
9119 : isl_space *space_mpa;
9120 : isl_multi_pw_aff *mpa;
9121 :
9122 0 : if (!mupa || !space)
9123 : goto error;
9124 :
9125 0 : space_mpa = isl_multi_union_pw_aff_get_space(mupa);
9126 0 : space = isl_space_replace_params(space, space_mpa);
9127 0 : space_mpa = isl_space_map_from_domain_and_range(isl_space_copy(space),
9128 : space_mpa);
9129 0 : mpa = isl_multi_pw_aff_alloc(space_mpa);
9130 :
9131 0 : space = isl_space_from_domain(space);
9132 0 : space = isl_space_add_dims(space, isl_dim_out, 1);
9133 0 : n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
9134 0 : for (i = 0; i < n; ++i) {
9135 : isl_union_pw_aff *upa;
9136 : isl_pw_aff *pa;
9137 :
9138 0 : upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
9139 0 : pa = isl_union_pw_aff_extract_pw_aff(upa,
9140 : isl_space_copy(space));
9141 0 : mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);
9142 0 : isl_union_pw_aff_free(upa);
9143 : }
9144 :
9145 0 : isl_space_free(space);
9146 0 : return mpa;
9147 : error:
9148 0 : isl_space_free(space);
9149 0 : return NULL;
9150 : }
9151 :
9152 : /* Evaluate the affine function "aff" in the void point "pnt".
9153 : * In particular, return the value NaN.
9154 : */
9155 0 : static __isl_give isl_val *eval_void(__isl_take isl_aff *aff,
9156 : __isl_take isl_point *pnt)
9157 : {
9158 : isl_ctx *ctx;
9159 :
9160 0 : ctx = isl_point_get_ctx(pnt);
9161 0 : isl_aff_free(aff);
9162 0 : isl_point_free(pnt);
9163 0 : return isl_val_nan(ctx);
9164 : }
9165 :
9166 : /* Evaluate the affine expression "aff"
9167 : * in the coordinates (with denominator) "pnt".
9168 : */
9169 0 : static __isl_give isl_val *eval(__isl_keep isl_vec *aff,
9170 : __isl_keep isl_vec *pnt)
9171 : {
9172 : isl_int n, d;
9173 : isl_ctx *ctx;
9174 : isl_val *v;
9175 :
9176 0 : if (!aff || !pnt)
9177 0 : return NULL;
9178 :
9179 0 : ctx = isl_vec_get_ctx(aff);
9180 0 : isl_int_init(n);
9181 0 : isl_int_init(d);
9182 0 : isl_seq_inner_product(aff->el + 1, pnt->el, pnt->size, &n);
9183 0 : isl_int_mul(d, aff->el[0], pnt->el[0]);
9184 0 : v = isl_val_rat_from_isl_int(ctx, n, d);
9185 0 : v = isl_val_normalize(v);
9186 0 : isl_int_clear(n);
9187 0 : isl_int_clear(d);
9188 :
9189 0 : return v;
9190 : }
9191 :
9192 : /* Check that the domain space of "aff" is equal to "space".
9193 : */
9194 0 : static isl_stat isl_aff_check_has_domain_space(__isl_keep isl_aff *aff,
9195 : __isl_keep isl_space *space)
9196 : {
9197 : isl_bool ok;
9198 :
9199 0 : ok = isl_space_is_equal(isl_aff_peek_domain_space(aff), space);
9200 0 : if (ok < 0)
9201 0 : return isl_stat_error;
9202 0 : if (!ok)
9203 0 : isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
9204 : "incompatible spaces", return isl_stat_error);
9205 0 : return isl_stat_ok;
9206 : }
9207 :
9208 : /* Evaluate the affine function "aff" in "pnt".
9209 : */
9210 0 : __isl_give isl_val *isl_aff_eval(__isl_take isl_aff *aff,
9211 : __isl_take isl_point *pnt)
9212 : {
9213 : isl_bool is_void;
9214 : isl_val *v;
9215 : isl_local_space *ls;
9216 :
9217 0 : if (isl_aff_check_has_domain_space(aff, isl_point_peek_space(pnt)) < 0)
9218 0 : goto error;
9219 0 : is_void = isl_point_is_void(pnt);
9220 0 : if (is_void < 0)
9221 0 : goto error;
9222 0 : if (is_void)
9223 0 : return eval_void(aff, pnt);
9224 :
9225 0 : ls = isl_aff_get_domain_local_space(aff);
9226 0 : pnt = isl_local_space_lift_point(ls, pnt);
9227 :
9228 0 : v = eval(aff->v, isl_point_peek_vec(pnt));
9229 :
9230 0 : isl_aff_free(aff);
9231 0 : isl_point_free(pnt);
9232 :
9233 0 : return v;
9234 : error:
9235 0 : isl_aff_free(aff);
9236 0 : isl_point_free(pnt);
9237 0 : return NULL;
9238 : }
|