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

          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             : }

Generated by: LCOV version 1.12