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