Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright 2010-2011 INRIA Saclay
      3  * Copyright 2014      Ecole Normale Superieure
      4  *
      5  * Use of this software is governed by the MIT license
      6  *
      7  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
      8  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
      9  * 91893 Orsay, France
     10  * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
     11  */
     12 
     13 #include <isl_map_private.h>
     14 #include <isl_aff_private.h>
     15 #include <isl_morph.h>
     16 #include <isl_seq.h>
     17 #include <isl_mat_private.h>
     18 #include <isl_space_private.h>
     19 #include <isl_equalities.h>
     20 #include <isl_id_private.h>
     21 #include <isl_aff_private.h>
     22 #include <isl_vec_private.h>
     23 
     24 isl_ctx *isl_morph_get_ctx(__isl_keep isl_morph *morph)
     25 {
     26 	if (!morph)
     27 		return NULL;
     28 	return isl_basic_set_get_ctx(morph->dom);
     29 }
     30 
     31 __isl_give isl_morph *isl_morph_alloc(
     32 	__isl_take isl_basic_set *dom, __isl_take isl_basic_set *ran,
     33 	__isl_take isl_mat *map, __isl_take isl_mat *inv)
     34 {
     35 	isl_morph *morph;
     36 
     37 	if (!dom || !ran || !map || !inv)
     38 		goto error;
     39 
     40 	morph = isl_alloc_type(dom->ctx, struct isl_morph);
     41 	if (!morph)
     42 		goto error;
     43 
     44 	morph->ref = 1;
     45 	morph->dom = dom;
     46 	morph->ran = ran;
     47 	morph->map = map;
     48 	morph->inv = inv;
     49 
     50 	return morph;
     51 error:
     52 	isl_basic_set_free(dom);
     53 	isl_basic_set_free(ran);
     54 	isl_mat_free(map);
     55 	isl_mat_free(inv);
     56 	return NULL;
     57 }
     58 
     59 __isl_give isl_morph *isl_morph_copy(__isl_keep isl_morph *morph)
     60 {
     61 	if (!morph)
     62 		return NULL;
     63 
     64 	morph->ref++;
     65 	return morph;
     66 }
     67 
     68 __isl_give isl_morph *isl_morph_dup(__isl_keep isl_morph *morph)
     69 {
     70 	if (!morph)
     71 		return NULL;
     72 
     73 	return isl_morph_alloc(isl_basic_set_copy(morph->dom),
     74 		isl_basic_set_copy(morph->ran),
     75 		isl_mat_copy(morph->map), isl_mat_copy(morph->inv));
     76 }
     77 
     78 __isl_give isl_morph *isl_morph_cow(__isl_take isl_morph *morph)
     79 {
     80 	if (!morph)
     81 		return NULL;
     82 
     83 	if (morph->ref == 1)
     84 		return morph;
     85 	morph->ref--;
     86 	return isl_morph_dup(morph);
     87 }
     88 
     89 __isl_null isl_morph *isl_morph_free(__isl_take isl_morph *morph)
     90 {
     91 	if (!morph)
     92 		return NULL;
     93 
     94 	if (--morph->ref > 0)
     95 		return NULL;
     96 
     97 	isl_basic_set_free(morph->dom);
     98 	isl_basic_set_free(morph->ran);
     99 	isl_mat_free(morph->map);
    100 	isl_mat_free(morph->inv);
    101 	free(morph);
    102 
    103 	return NULL;
    104 }
    105 
    106 /* Is "morph" an identity on the parameters?
    107  */
    108 static isl_bool identity_on_parameters(__isl_keep isl_morph *morph)
    109 {
    110 	isl_bool is_identity;
    111 	isl_size nparam, nparam_ran;
    112 	isl_mat *sub;
    113 
    114 	nparam = isl_morph_dom_dim(morph, isl_dim_param);
    115 	nparam_ran = isl_morph_ran_dim(morph, isl_dim_param);
    116 	if (nparam < 0 || nparam_ran < 0)
    117 		return isl_bool_error;
    118 	if (nparam != nparam_ran)
    119 		return isl_bool_false;
    120 	if (nparam == 0)
    121 		return isl_bool_true;
    122 	sub = isl_mat_sub_alloc(morph->map, 0, 1 + nparam, 0, 1 + nparam);
    123 	is_identity = isl_mat_is_scaled_identity(sub);
    124 	isl_mat_free(sub);
    125 
    126 	return is_identity;
    127 }
    128 
    129 /* Return an affine expression of the variables of the range of "morph"
    130  * in terms of the parameters and the variables of the domain on "morph".
    131  *
    132  * In order for the space manipulations to make sense, we require
    133  * that the parameters are not modified by "morph".
    134  */
    135 __isl_give isl_multi_aff *isl_morph_get_var_multi_aff(
    136 	__isl_keep isl_morph *morph)
    137 {
    138 	isl_space *dom, *ran, *space;
    139 	isl_local_space *ls;
    140 	isl_multi_aff *ma;
    141 	isl_size nparam, nvar;
    142 	int i;
    143 	isl_bool is_identity;
    144 
    145 	if (!morph)
    146 		return NULL;
    147 
    148 	is_identity = identity_on_parameters(morph);
    149 	if (is_identity < 0)
    150 		return NULL;
    151 	if (!is_identity)
    152 		isl_die(isl_morph_get_ctx(morph), isl_error_invalid,
    153 			"cannot handle parameter compression", return NULL);
    154 
    155 	dom = isl_morph_get_dom_space(morph);
    156 	ls = isl_local_space_from_space(isl_space_copy(dom));
    157 	ran = isl_morph_get_ran_space(morph);
    158 	space = isl_space_map_from_domain_and_range(dom, ran);
    159 	ma = isl_multi_aff_zero(space);
    160 
    161 	nparam = isl_multi_aff_dim(ma, isl_dim_param);
    162 	nvar = isl_multi_aff_dim(ma, isl_dim_out);
    163 	if (nparam < 0 || nvar < 0)
    164 		ma = isl_multi_aff_free(ma);
    165 	for (i = 0; i < nvar; ++i) {
    166 		isl_val *val;
    167 		isl_vec *v;
    168 		isl_aff *aff;
    169 
    170 		v = isl_mat_get_row(morph->map, 1 + nparam + i);
    171 		v = isl_vec_insert_els(v, 0, 1);
    172 		val = isl_mat_get_element_val(morph->map, 0, 0);
    173 		v = isl_vec_set_element_val(v, 0, val);
    174 		aff = isl_aff_alloc_vec(isl_local_space_copy(ls), v);
    175 		ma = isl_multi_aff_set_aff(ma, i, aff);
    176 	}
    177 
    178 	isl_local_space_free(ls);
    179 	return ma;
    180 }
    181 
    182 /* Return the domain space of "morph".
    183  */
    184 static __isl_keep isl_space *isl_morph_peek_dom_space(
    185 	__isl_keep isl_morph *morph)
    186 {
    187 	if (!morph)
    188 		return NULL;
    189 
    190 	return isl_basic_set_peek_space(morph->dom);
    191 }
    192 
    193 /* Return a copy of the domain space of "morph".
    194  */
    195 __isl_give isl_space *isl_morph_get_dom_space(__isl_keep isl_morph *morph)
    196 {
    197 	return isl_space_copy(isl_morph_peek_dom_space(morph));
    198 }
    199 
    200 /* Check that the match against "space" with result "match" was successful.
    201  */
    202 static isl_stat check_space_match(__isl_keep isl_space *space, isl_bool match)
    203 {
    204 	if (match < 0)
    205 		return isl_stat_error;
    206 	if (!match)
    207 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
    208 			"spaces don't match", return isl_stat_error);
    209 
    210 	return isl_stat_ok;
    211 }
    212 
    213 /* Check that "morph" can be applied to the "space".
    214  */
    215 isl_stat isl_morph_check_applies(__isl_keep isl_morph *morph,
    216 	__isl_keep isl_space *space)
    217 {
    218 	isl_space *dom_space;
    219 	isl_bool applies;
    220 
    221 	dom_space = isl_morph_peek_dom_space(morph);
    222 	applies = isl_space_is_equal(dom_space, space);
    223 	return check_space_match(space, applies);
    224 }
    225 
    226 __isl_give isl_space *isl_morph_get_ran_space(__isl_keep isl_morph *morph)
    227 {
    228 	if (!morph)
    229 		return NULL;
    230 
    231 	return isl_space_copy(morph->ran->dim);
    232 }
    233 
    234 isl_size isl_morph_dom_dim(__isl_keep isl_morph *morph, enum isl_dim_type type)
    235 {
    236 	if (!morph)
    237 		return isl_size_error;
    238 
    239 	return isl_basic_set_dim(morph->dom, type);
    240 }
    241 
    242 isl_size isl_morph_ran_dim(__isl_keep isl_morph *morph, enum isl_dim_type type)
    243 {
    244 	if (!morph)
    245 		return isl_size_error;
    246 
    247 	return isl_basic_set_dim(morph->ran, type);
    248 }
    249 
    250 __isl_give isl_morph *isl_morph_remove_dom_dims(__isl_take isl_morph *morph,
    251 	enum isl_dim_type type, unsigned first, unsigned n)
    252 {
    253 	isl_size dom_offset;
    254 
    255 	if (n == 0)
    256 		return morph;
    257 
    258 	morph = isl_morph_cow(morph);
    259 	if (!morph)
    260 		return NULL;
    261 
    262 	dom_offset = isl_space_offset(morph->dom->dim, type);
    263 	if (dom_offset < 0)
    264 		return isl_morph_free(morph);
    265 
    266 	morph->dom = isl_basic_set_remove_dims(morph->dom, type, first, n);
    267 
    268 	morph->map = isl_mat_drop_cols(morph->map, 1 + dom_offset + first, n);
    269 
    270 	morph->inv = isl_mat_drop_rows(morph->inv, 1 + dom_offset + first, n);
    271 
    272 	if (morph->dom && morph->ran && morph->map && morph->inv)
    273 		return morph;
    274 
    275 	isl_morph_free(morph);
    276 	return NULL;
    277 }
    278 
    279 __isl_give isl_morph *isl_morph_remove_ran_dims(__isl_take isl_morph *morph,
    280 	enum isl_dim_type type, unsigned first, unsigned n)
    281 {
    282 	isl_size ran_offset;
    283 
    284 	if (n == 0)
    285 		return morph;
    286 
    287 	morph = isl_morph_cow(morph);
    288 	if (!morph)
    289 		return NULL;
    290 
    291 	ran_offset = isl_space_offset(morph->ran->dim, type);
    292 	if (ran_offset < 0)
    293 		return isl_morph_free(morph);
    294 
    295 	morph->ran = isl_basic_set_remove_dims(morph->ran, type, first, n);
    296 
    297 	morph->map = isl_mat_drop_rows(morph->map, 1 + ran_offset + first, n);
    298 
    299 	morph->inv = isl_mat_drop_cols(morph->inv, 1 + ran_offset + first, n);
    300 
    301 	if (morph->dom && morph->ran && morph->map && morph->inv)
    302 		return morph;
    303 
    304 	isl_morph_free(morph);
    305 	return NULL;
    306 }
    307 
    308 /* Project domain of morph onto its parameter domain.
    309  */
    310 __isl_give isl_morph *isl_morph_dom_params(__isl_take isl_morph *morph)
    311 {
    312 	isl_size n;
    313 
    314 	morph = isl_morph_cow(morph);
    315 	if (!morph)
    316 		return NULL;
    317 	n = isl_basic_set_dim(morph->dom, isl_dim_set);
    318 	if (n < 0)
    319 		return isl_morph_free(morph);
    320 	morph = isl_morph_remove_dom_dims(morph, isl_dim_set, 0, n);
    321 	if (!morph)
    322 		return NULL;
    323 	morph->dom = isl_basic_set_params(morph->dom);
    324 	if (morph->dom)
    325 		return morph;
    326 
    327 	isl_morph_free(morph);
    328 	return NULL;
    329 }
    330 
    331 /* Project range of morph onto its parameter domain.
    332  */
    333 __isl_give isl_morph *isl_morph_ran_params(__isl_take isl_morph *morph)
    334 {
    335 	isl_size n;
    336 
    337 	morph = isl_morph_cow(morph);
    338 	if (!morph)
    339 		return NULL;
    340 	n = isl_basic_set_dim(morph->ran, isl_dim_set);
    341 	if (n < 0)
    342 		return isl_morph_free(morph);
    343 	morph = isl_morph_remove_ran_dims(morph, isl_dim_set, 0, n);
    344 	if (!morph)
    345 		return NULL;
    346 	morph->ran = isl_basic_set_params(morph->ran);
    347 	if (morph->ran)
    348 		return morph;
    349 
    350 	isl_morph_free(morph);
    351 	return NULL;
    352 }
    353 
    354 /* Replace the identifier of the tuple of the range of the morph by "id".
    355  */
    356 static __isl_give isl_morph *isl_morph_set_ran_tuple_id(
    357 	__isl_take isl_morph *morph, __isl_keep isl_id *id)
    358 {
    359 	morph = isl_morph_cow(morph);
    360 	if (!morph)
    361 		return NULL;
    362 	morph->ran = isl_basic_set_set_tuple_id(morph->ran, isl_id_copy(id));
    363 	if (!morph->ran)
    364 		return isl_morph_free(morph);
    365 	return morph;
    366 }
    367 
    368 void isl_morph_print_internal(__isl_take isl_morph *morph, FILE *out)
    369 {
    370 	if (!morph)
    371 		return;
    372 
    373 	isl_basic_set_dump(morph->dom);
    374 	isl_basic_set_dump(morph->ran);
    375 	isl_mat_print_internal(morph->map, out, 4);
    376 	isl_mat_print_internal(morph->inv, out, 4);
    377 }
    378 
    379 void isl_morph_dump(__isl_take isl_morph *morph)
    380 {
    381 	isl_morph_print_internal(morph, stderr);
    382 }
    383 
    384 __isl_give isl_morph *isl_morph_identity(__isl_keep isl_basic_set *bset)
    385 {
    386 	isl_mat *id;
    387 	isl_basic_set *universe;
    388 	isl_size total;
    389 
    390 	total = isl_basic_set_dim(bset, isl_dim_all);
    391 	if (total < 0)
    392 		return NULL;
    393 
    394 	id = isl_mat_identity(bset->ctx, 1 + total);
    395 	universe = isl_basic_set_universe(isl_space_copy(bset->dim));
    396 
    397 	return isl_morph_alloc(universe, isl_basic_set_copy(universe),
    398 		id, isl_mat_copy(id));
    399 }
    400 
    401 /* Create a(n identity) morphism between empty sets of the same dimension
    402  * a "bset".
    403  */
    404 __isl_give isl_morph *isl_morph_empty(__isl_keep isl_basic_set *bset)
    405 {
    406 	isl_mat *id;
    407 	isl_basic_set *empty;
    408 	isl_size total;
    409 
    410 	total = isl_basic_set_dim(bset, isl_dim_all);
    411 	if (total < 0)
    412 		return NULL;
    413 
    414 	id = isl_mat_identity(bset->ctx, 1 + total);
    415 	empty = isl_basic_set_empty(isl_space_copy(bset->dim));
    416 
    417 	return isl_morph_alloc(empty, isl_basic_set_copy(empty),
    418 		id, isl_mat_copy(id));
    419 }
    420 
    421 /* Construct a basic set described by the "n" equalities of "bset" starting
    422  * at "first".
    423  */
    424 static __isl_give isl_basic_set *copy_equalities(__isl_keep isl_basic_set *bset,
    425 	unsigned first, unsigned n)
    426 {
    427 	int i, k;
    428 	isl_basic_set *eq;
    429 	isl_size total;
    430 
    431 	total = isl_basic_set_dim(bset, isl_dim_all);
    432 	if (total < 0 || isl_basic_set_check_no_locals(bset) < 0)
    433 		return NULL;
    434 
    435 	eq = isl_basic_set_alloc_space(isl_basic_set_get_space(bset), 0, n, 0);
    436 	if (!eq)
    437 		return NULL;
    438 	for (i = 0; i < n; ++i) {
    439 		k = isl_basic_set_alloc_equality(eq);
    440 		if (k < 0)
    441 			goto error;
    442 		isl_seq_cpy(eq->eq[k], bset->eq[first + i], 1 + total);
    443 	}
    444 
    445 	return eq;
    446 error:
    447 	isl_basic_set_free(eq);
    448 	return NULL;
    449 }
    450 
    451 /* Given a basic set, exploit the equalities in the basic set to construct
    452  * a morphism that maps the basic set to a lower-dimensional space.
    453  * Specifically, the morphism reduces the number of dimensions of type "type".
    454  *
    455  * We first select the equalities of interest, that is those that involve
    456  * variables of type "type" and no later variables.
    457  * Denote those equalities as
    458  *
    459  *		-C(p) + M x = 0
    460  *
    461  * where C(p) depends on the parameters if type == isl_dim_set and
    462  * is a constant if type == isl_dim_param.
    463  *
    464  * Use isl_mat_final_variable_compression to construct a compression
    465  *
    466  *	x = T x'
    467  *
    468  *	x' = Q x
    469  *
    470  * If T is a zero-column matrix, then the set of equality constraints
    471  * do not admit a solution.  In this case, an empty morphism is returned.
    472  *
    473  * Both matrices are extended to map the full original space to the full
    474  * compressed space.
    475  */
    476 __isl_give isl_morph *isl_basic_set_variable_compression(
    477 	__isl_keep isl_basic_set *bset, enum isl_dim_type type)
    478 {
    479 	unsigned otype;
    480 	isl_size ntype;
    481 	unsigned orest;
    482 	unsigned nrest;
    483 	isl_size total;
    484 	int f_eq, n_eq;
    485 	isl_space *space;
    486 	isl_mat *E, *Q, *C;
    487 	isl_basic_set *dom, *ran;
    488 
    489 	if (!bset)
    490 		return NULL;
    491 
    492 	if (isl_basic_set_plain_is_empty(bset))
    493 		return isl_morph_empty(bset);
    494 
    495 	if (isl_basic_set_check_no_locals(bset) < 0)
    496 		return NULL;
    497 
    498 	ntype = isl_basic_set_dim(bset, type);
    499 	total = isl_basic_set_dim(bset, isl_dim_all);
    500 	if (ntype < 0 || total < 0)
    501 		return NULL;
    502 	otype = isl_basic_set_offset(bset, type);
    503 	orest = otype + ntype;
    504 	nrest = total - (orest - 1);
    505 
    506 	for (f_eq = 0; f_eq < bset->n_eq; ++f_eq)
    507 		if (isl_seq_first_non_zero(bset->eq[f_eq] + orest, nrest) == -1)
    508 			break;
    509 	for (n_eq = 0; f_eq + n_eq < bset->n_eq; ++n_eq)
    510 		if (isl_seq_first_non_zero(bset->eq[f_eq + n_eq] + otype, ntype) == -1)
    511 			break;
    512 	if (n_eq == 0)
    513 		return isl_morph_identity(bset);
    514 
    515 	E = isl_mat_sub_alloc6(bset->ctx, bset->eq, f_eq, n_eq, 0, orest);
    516 	C = isl_mat_final_variable_compression(E, otype - 1, &Q);
    517 	if (!Q)
    518 		C = isl_mat_free(C);
    519 	if (C && C->n_col == 0) {
    520 		isl_mat_free(C);
    521 		isl_mat_free(Q);
    522 		return isl_morph_empty(bset);
    523 	}
    524 
    525 	Q = isl_mat_diagonal(Q, isl_mat_identity(bset->ctx, nrest));
    526 	C = isl_mat_diagonal(C, isl_mat_identity(bset->ctx, nrest));
    527 
    528 	space = isl_space_copy(bset->dim);
    529 	space = isl_space_drop_dims(space, type, 0, ntype);
    530 	space = isl_space_add_dims(space, type, ntype - n_eq);
    531 	ran = isl_basic_set_universe(space);
    532 	dom = copy_equalities(bset, f_eq, n_eq);
    533 
    534 	return isl_morph_alloc(dom, ran, Q, C);
    535 }
    536 
    537 /* Given a basic set, exploit the equalities in the basic set to construct
    538  * a morphism that maps the basic set to a lower-dimensional space
    539  * with identifier "id".
    540  * Specifically, the morphism reduces the number of set dimensions.
    541  */
    542 __isl_give isl_morph *isl_basic_set_variable_compression_with_id(
    543 	__isl_keep isl_basic_set *bset, __isl_keep isl_id *id)
    544 {
    545 	isl_morph *morph;
    546 
    547 	morph = isl_basic_set_variable_compression(bset, isl_dim_set);
    548 	morph = isl_morph_set_ran_tuple_id(morph, id);
    549 	return morph;
    550 }
    551 
    552 /* Construct a parameter compression for "bset".
    553  * We basically just call isl_mat_parameter_compression with the right input
    554  * and then extend the resulting matrix to include the variables.
    555  *
    556  * The implementation assumes that "bset" does not have any equalities
    557  * that only involve the parameters and that isl_basic_set_gauss has
    558  * been applied to "bset".
    559  *
    560  * Let the equalities be given as
    561  *
    562  *	B(p) + A x = 0.
    563  *
    564  * We use isl_mat_parameter_compression_ext to compute the compression
    565  *
    566  *	p = T p'.
    567  */
    568 __isl_give isl_morph *isl_basic_set_parameter_compression(
    569 	__isl_keep isl_basic_set *bset)
    570 {
    571 	isl_size nparam;
    572 	isl_size nvar;
    573 	isl_size n_div;
    574 	int n_eq;
    575 	isl_mat *H, *B;
    576 	isl_mat *map, *inv;
    577 	isl_basic_set *dom, *ran;
    578 
    579 	if (!bset)
    580 		return NULL;
    581 
    582 	if (isl_basic_set_plain_is_empty(bset))
    583 		return isl_morph_empty(bset);
    584 	if (bset->n_eq == 0)
    585 		return isl_morph_identity(bset);
    586 
    587 	n_eq = bset->n_eq;
    588 	nparam = isl_basic_set_dim(bset, isl_dim_param);
    589 	nvar = isl_basic_set_dim(bset, isl_dim_set);
    590 	n_div = isl_basic_set_dim(bset, isl_dim_div);
    591 	if (nparam < 0 || nvar < 0 || n_div < 0)
    592 		return NULL;
    593 
    594 	if (isl_seq_first_non_zero(bset->eq[bset->n_eq - 1] + 1 + nparam,
    595 				    nvar + n_div) == -1)
    596 		isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid,
    597 			"input not allowed to have parameter equalities",
    598 			return NULL);
    599 	if (n_eq > nvar + n_div)
    600 		isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid,
    601 			"input not gaussed", return NULL);
    602 
    603 	B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, n_eq, 0, 1 + nparam);
    604 	H = isl_mat_sub_alloc6(bset->ctx, bset->eq,
    605 				0, n_eq, 1 + nparam, nvar + n_div);
    606 	inv = isl_mat_parameter_compression_ext(B, H);
    607 	inv = isl_mat_diagonal(inv, isl_mat_identity(bset->ctx, nvar));
    608 	map = isl_mat_right_inverse(isl_mat_copy(inv));
    609 
    610 	dom = isl_basic_set_universe(isl_space_copy(bset->dim));
    611 	ran = isl_basic_set_universe(isl_space_copy(bset->dim));
    612 
    613 	return isl_morph_alloc(dom, ran, map, inv);
    614 }
    615 
    616 /* Construct an isl_multi_aff that corresponds
    617  * to the affine transformation matrix "mat" and
    618  * that lives in an anonymous space.
    619  */
    620 static __isl_give isl_multi_aff *isl_multi_aff_from_aff_mat_anonymous(
    621 	__isl_take isl_mat *mat)
    622 {
    623 	isl_size n_row, n_col;
    624 	isl_ctx *ctx;
    625 	isl_space *space;
    626 
    627 	ctx = isl_mat_get_ctx(mat);
    628 	n_row = isl_mat_rows(mat);
    629 	n_col = isl_mat_cols(mat);
    630 	if (n_row < 0 || n_col < 0)
    631 		space = NULL;
    632 	else
    633 		space = isl_space_alloc(ctx, 0, n_col - 1, n_row - 1);
    634 
    635 	return isl_multi_aff_from_aff_mat(space, mat);
    636 }
    637 
    638 /* Apply the morphism to the basic set.
    639  * In particular, compute the preimage of "bset" under the inverse mapping
    640  * in morph and intersect with the range of the morphism.
    641  * Note that the mapping in morph applies to both parameters and set dimensions,
    642  * so the parameters need to be treated as set dimensions during the call
    643  * to isl_basic_set_preimage_multi_aff.
    644  */
    645 __isl_give isl_basic_set *isl_morph_basic_set(__isl_take isl_morph *morph,
    646 	__isl_take isl_basic_set *bset)
    647 {
    648 	isl_size n_param;
    649 	isl_space *space;
    650 	isl_multi_aff *ma;
    651 
    652 	if (!morph || isl_basic_set_check_equal_space(bset, morph->dom) < 0)
    653 		goto error;
    654 	n_param = isl_basic_set_dim(morph->dom, isl_dim_param);
    655 	if (n_param < 0)
    656 		goto error;
    657 
    658 	ma = isl_multi_aff_from_aff_mat_anonymous(isl_mat_copy(morph->inv));
    659 
    660 	bset = isl_basic_set_move_dims(bset, isl_dim_set, 0,
    661 					isl_dim_param, 0, n_param);
    662 	bset = isl_basic_set_preimage_multi_aff(bset, ma);
    663 	space = isl_basic_set_get_space(morph->ran);
    664 	bset = isl_basic_set_reset_space(bset, space);
    665 	bset = isl_basic_set_intersect(bset, isl_basic_set_copy(morph->ran));
    666 
    667 	isl_morph_free(morph);
    668 	return bset;
    669 error:
    670 	isl_morph_free(morph);
    671 	isl_basic_set_free(bset);
    672 	return NULL;
    673 }
    674 
    675 /* Apply the morphism to the set.
    676  * In particular, compute the preimage of "set" under the inverse mapping
    677  * in morph and intersect with the range of the morphism.
    678  * Note that the mapping in morph applies to both parameters and set dimensions,
    679  * so the parameters need to be treated as set dimensions during the call
    680  * to isl_set_preimage_multi_aff.
    681  */
    682 __isl_give isl_set *isl_morph_set(__isl_take isl_morph *morph,
    683 	__isl_take isl_set *set)
    684 {
    685 	isl_size n_param;
    686 	isl_space *space;
    687 	isl_multi_aff *ma;
    688 	isl_basic_set *ran;
    689 
    690 	if (!morph || isl_set_basic_set_check_equal_space(set, morph->dom) < 0)
    691 		goto error;
    692 	n_param = isl_basic_set_dim(morph->dom, isl_dim_param);
    693 	if (n_param < 0)
    694 		goto error;
    695 
    696 	ma = isl_multi_aff_from_aff_mat_anonymous(isl_mat_copy(morph->inv));
    697 
    698 	set = isl_set_move_dims(set, isl_dim_set, 0, isl_dim_param, 0, n_param);
    699 	set = isl_set_preimage_multi_aff(set, ma);
    700 	space = isl_basic_set_get_space(morph->ran);
    701 	set = isl_set_reset_space(set, space);
    702 	ran = isl_basic_set_copy(morph->ran);
    703 	set = isl_set_intersect(set, isl_set_from_basic_set(ran));
    704 
    705 	isl_morph_free(morph);
    706 	return set;
    707 error:
    708 	isl_set_free(set);
    709 	isl_morph_free(morph);
    710 	return NULL;
    711 }
    712 
    713 /* Construct a morphism that first does morph2 and then morph1.
    714  */
    715 __isl_give isl_morph *isl_morph_compose(__isl_take isl_morph *morph1,
    716 	__isl_take isl_morph *morph2)
    717 {
    718 	isl_mat *map, *inv;
    719 	isl_basic_set *dom, *ran;
    720 
    721 	if (!morph1 || !morph2)
    722 		goto error;
    723 
    724 	map = isl_mat_product(isl_mat_copy(morph1->map), isl_mat_copy(morph2->map));
    725 	inv = isl_mat_product(isl_mat_copy(morph2->inv), isl_mat_copy(morph1->inv));
    726 	dom = isl_morph_basic_set(isl_morph_inverse(isl_morph_copy(morph2)),
    727 				  isl_basic_set_copy(morph1->dom));
    728 	dom = isl_basic_set_intersect(dom, isl_basic_set_copy(morph2->dom));
    729 	ran = isl_morph_basic_set(isl_morph_copy(morph1),
    730 				  isl_basic_set_copy(morph2->ran));
    731 	ran = isl_basic_set_intersect(ran, isl_basic_set_copy(morph1->ran));
    732 
    733 	isl_morph_free(morph1);
    734 	isl_morph_free(morph2);
    735 
    736 	return isl_morph_alloc(dom, ran, map, inv);
    737 error:
    738 	isl_morph_free(morph1);
    739 	isl_morph_free(morph2);
    740 	return NULL;
    741 }
    742 
    743 __isl_give isl_morph *isl_morph_inverse(__isl_take isl_morph *morph)
    744 {
    745 	isl_basic_set *bset;
    746 	isl_mat *mat;
    747 
    748 	morph = isl_morph_cow(morph);
    749 	if (!morph)
    750 		return NULL;
    751 
    752 	bset = morph->dom;
    753 	morph->dom = morph->ran;
    754 	morph->ran = bset;
    755 
    756 	mat = morph->map;
    757 	morph->map = morph->inv;
    758 	morph->inv = mat;
    759 
    760 	return morph;
    761 }
    762 
    763 /* We detect all the equalities first to avoid implicit equalities
    764  * being discovered during the computations.  In particular,
    765  * the compression on the variables could expose additional stride
    766  * constraints on the parameters.  This would result in existentially
    767  * quantified variables after applying the resulting morph, which
    768  * in turn could break invariants of the calling functions.
    769  */
    770 __isl_give isl_morph *isl_basic_set_full_compression(
    771 	__isl_keep isl_basic_set *bset)
    772 {
    773 	isl_morph *morph, *morph2;
    774 
    775 	bset = isl_basic_set_copy(bset);
    776 	bset = isl_basic_set_detect_equalities(bset);
    777 
    778 	morph = isl_basic_set_variable_compression(bset, isl_dim_param);
    779 	bset = isl_morph_basic_set(isl_morph_copy(morph), bset);
    780 
    781 	morph2 = isl_basic_set_parameter_compression(bset);
    782 	bset = isl_morph_basic_set(isl_morph_copy(morph2), bset);
    783 
    784 	morph = isl_morph_compose(morph2, morph);
    785 
    786 	morph2 = isl_basic_set_variable_compression(bset, isl_dim_set);
    787 	isl_basic_set_free(bset);
    788 
    789 	morph = isl_morph_compose(morph2, morph);
    790 
    791 	return morph;
    792 }
    793 
    794 __isl_give isl_vec *isl_morph_vec(__isl_take isl_morph *morph,
    795 	__isl_take isl_vec *vec)
    796 {
    797 	if (!morph)
    798 		goto error;
    799 
    800 	vec = isl_mat_vec_product(isl_mat_copy(morph->map), vec);
    801 
    802 	isl_morph_free(morph);
    803 	return vec;
    804 error:
    805 	isl_morph_free(morph);
    806 	isl_vec_free(vec);
    807 	return NULL;
    808 }
    809