add isl_morph_dump
[platform/upstream/isl.git] / isl_morph.c
1 /*
2  * Copyright 2010      INRIA Saclay
3  *
4  * Use of this software is governed by the GNU LGPLv2.1 license
5  *
6  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
7  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
8  * 91893 Orsay, France 
9  */
10
11 #include <isl_map_private.h>
12 #include <isl_morph.h>
13 #include <isl/seq.h>
14 #include <isl_mat_private.h>
15 #include <isl_space_private.h>
16 #include <isl_equalities.h>
17
18 __isl_give isl_morph *isl_morph_alloc(
19         __isl_take isl_basic_set *dom, __isl_take isl_basic_set *ran,
20         __isl_take isl_mat *map, __isl_take isl_mat *inv)
21 {
22         isl_morph *morph;
23
24         if (!dom || !ran || !map || !inv)
25                 goto error;
26
27         morph = isl_alloc_type(dom->ctx, struct isl_morph);
28         if (!morph)
29                 goto error;
30
31         morph->ref = 1;
32         morph->dom = dom;
33         morph->ran = ran;
34         morph->map = map;
35         morph->inv = inv;
36
37         return morph;
38 error:
39         isl_basic_set_free(dom);
40         isl_basic_set_free(ran);
41         isl_mat_free(map);
42         isl_mat_free(inv);
43         return NULL;
44 }
45
46 __isl_give isl_morph *isl_morph_copy(__isl_keep isl_morph *morph)
47 {
48         if (!morph)
49                 return NULL;
50
51         morph->ref++;
52         return morph;
53 }
54
55 __isl_give isl_morph *isl_morph_dup(__isl_keep isl_morph *morph)
56 {
57         if (!morph)
58                 return NULL;
59
60         return isl_morph_alloc(isl_basic_set_copy(morph->dom),
61                 isl_basic_set_copy(morph->ran),
62                 isl_mat_copy(morph->map), isl_mat_copy(morph->inv));
63 }
64
65 __isl_give isl_morph *isl_morph_cow(__isl_take isl_morph *morph)
66 {
67         if (!morph)
68                 return NULL;
69
70         if (morph->ref == 1)
71                 return morph;
72         morph->ref--;
73         return isl_morph_dup(morph);
74 }
75
76 void isl_morph_free(__isl_take isl_morph *morph)
77 {
78         if (!morph)
79                 return;
80
81         if (--morph->ref > 0)
82                 return;
83
84         isl_basic_set_free(morph->dom);
85         isl_basic_set_free(morph->ran);
86         isl_mat_free(morph->map);
87         isl_mat_free(morph->inv);
88         free(morph);
89 }
90
91 __isl_give isl_space *isl_morph_get_ran_space(__isl_keep isl_morph *morph)
92 {
93         if (!morph)
94                 return NULL;
95         
96         return isl_space_copy(morph->ran->dim);
97 }
98
99 unsigned isl_morph_dom_dim(__isl_keep isl_morph *morph, enum isl_dim_type type)
100 {
101         if (!morph)
102                 return 0;
103
104         return isl_basic_set_dim(morph->dom, type);
105 }
106
107 unsigned isl_morph_ran_dim(__isl_keep isl_morph *morph, enum isl_dim_type type)
108 {
109         if (!morph)
110                 return 0;
111
112         return isl_basic_set_dim(morph->ran, type);
113 }
114
115 __isl_give isl_morph *isl_morph_remove_dom_dims(__isl_take isl_morph *morph,
116         enum isl_dim_type type, unsigned first, unsigned n)
117 {
118         unsigned dom_offset;
119
120         if (n == 0)
121                 return morph;
122
123         morph = isl_morph_cow(morph);
124         if (!morph)
125                 return NULL;
126
127         dom_offset = 1 + isl_space_offset(morph->dom->dim, type);
128
129         morph->dom = isl_basic_set_remove_dims(morph->dom, type, first, n);
130
131         morph->map = isl_mat_drop_cols(morph->map, dom_offset + first, n);
132
133         morph->inv = isl_mat_drop_rows(morph->inv, dom_offset + first, n);
134
135         if (morph->dom && morph->ran && morph->map && morph->inv)
136                 return morph;
137
138         isl_morph_free(morph);
139         return NULL;
140 }
141
142 __isl_give isl_morph *isl_morph_remove_ran_dims(__isl_take isl_morph *morph,
143         enum isl_dim_type type, unsigned first, unsigned n)
144 {
145         unsigned ran_offset;
146
147         if (n == 0)
148                 return morph;
149
150         morph = isl_morph_cow(morph);
151         if (!morph)
152                 return NULL;
153
154         ran_offset = 1 + isl_space_offset(morph->ran->dim, type);
155
156         morph->ran = isl_basic_set_remove_dims(morph->ran, type, first, n);
157
158         morph->map = isl_mat_drop_rows(morph->map, ran_offset + first, n);
159
160         morph->inv = isl_mat_drop_cols(morph->inv, ran_offset + first, n);
161
162         if (morph->dom && morph->ran && morph->map && morph->inv)
163                 return morph;
164
165         isl_morph_free(morph);
166         return NULL;
167 }
168
169 /* Project domain of morph onto its parameter domain.
170  */
171 __isl_give isl_morph *isl_morph_dom_params(__isl_take isl_morph *morph)
172 {
173         unsigned n;
174
175         if (!morph)
176                 return NULL;
177         n = isl_basic_set_dim(morph->dom, isl_dim_set);
178         morph = isl_morph_remove_dom_dims(morph, isl_dim_set, 0, n);
179         if (!morph)
180                 return NULL;
181         morph->dom = isl_basic_set_params(morph->dom);
182         if (morph->dom)
183                 return morph;
184
185         isl_morph_free(morph);
186         return NULL;
187 }
188
189 /* Project range of morph onto its parameter domain.
190  */
191 __isl_give isl_morph *isl_morph_ran_params(__isl_take isl_morph *morph)
192 {
193         unsigned n;
194
195         if (!morph)
196                 return NULL;
197         n = isl_basic_set_dim(morph->ran, isl_dim_set);
198         morph = isl_morph_remove_ran_dims(morph, isl_dim_set, 0, n);
199         if (!morph)
200                 return NULL;
201         morph->ran = isl_basic_set_params(morph->ran);
202         if (morph->ran)
203                 return morph;
204
205         isl_morph_free(morph);
206         return NULL;
207 }
208
209 void isl_morph_print_internal(__isl_take isl_morph *morph, FILE *out)
210 {
211         if (!morph)
212                 return;
213
214         isl_basic_set_print(morph->dom, out, 0, "", "", ISL_FORMAT_ISL);
215         isl_basic_set_print(morph->ran, out, 0, "", "", ISL_FORMAT_ISL);
216         isl_mat_print_internal(morph->map, out, 4);
217         isl_mat_print_internal(morph->inv, out, 4);
218 }
219
220 void isl_morph_dump(__isl_take isl_morph *morph)
221 {
222         isl_morph_print_internal(morph, stderr);
223 }
224
225 __isl_give isl_morph *isl_morph_identity(__isl_keep isl_basic_set *bset)
226 {
227         isl_mat *id;
228         isl_basic_set *universe;
229         unsigned total;
230
231         if (!bset)
232                 return NULL;
233
234         total = isl_basic_set_total_dim(bset);
235         id = isl_mat_identity(bset->ctx, 1 + total);
236         universe = isl_basic_set_universe(isl_space_copy(bset->dim));
237
238         return isl_morph_alloc(universe, isl_basic_set_copy(universe),
239                 id, isl_mat_copy(id));
240 }
241
242 /* Create a(n identity) morphism between empty sets of the same dimension
243  * a "bset".
244  */
245 __isl_give isl_morph *isl_morph_empty(__isl_keep isl_basic_set *bset)
246 {
247         isl_mat *id;
248         isl_basic_set *empty;
249         unsigned total;
250
251         if (!bset)
252                 return NULL;
253
254         total = isl_basic_set_total_dim(bset);
255         id = isl_mat_identity(bset->ctx, 1 + total);
256         empty = isl_basic_set_empty(isl_space_copy(bset->dim));
257
258         return isl_morph_alloc(empty, isl_basic_set_copy(empty),
259                 id, isl_mat_copy(id));
260 }
261
262 /* Given a matrix that maps a (possibly) parametric domain to
263  * a parametric domain, add in rows that map the "nparam" parameters onto
264  * themselves.
265  */
266 static __isl_give isl_mat *insert_parameter_rows(__isl_take isl_mat *mat,
267         unsigned nparam)
268 {
269         int i;
270
271         if (nparam == 0)
272                 return mat;
273         if (!mat)
274                 return NULL;
275
276         mat = isl_mat_insert_rows(mat, 1, nparam);
277         if (!mat)
278                 return NULL;
279
280         for (i = 0; i < nparam; ++i) {
281                 isl_seq_clr(mat->row[1 + i], mat->n_col);
282                 isl_int_set(mat->row[1 + i][1 + i], mat->row[0][0]);
283         }
284
285         return mat;
286 }
287
288 /* Construct a basic set described by the "n" equalities of "bset" starting
289  * at "first".
290  */
291 static __isl_give isl_basic_set *copy_equalities(__isl_keep isl_basic_set *bset,
292         unsigned first, unsigned n)
293 {
294         int i, k;
295         isl_basic_set *eq;
296         unsigned total;
297
298         isl_assert(bset->ctx, bset->n_div == 0, return NULL);
299
300         total = isl_basic_set_total_dim(bset);
301         eq = isl_basic_set_alloc_space(isl_space_copy(bset->dim), 0, n, 0);
302         if (!eq)
303                 return NULL;
304         for (i = 0; i < n; ++i) {
305                 k = isl_basic_set_alloc_equality(eq);
306                 if (k < 0)
307                         goto error;
308                 isl_seq_cpy(eq->eq[k], bset->eq[first + k], 1 + total);
309         }
310
311         return eq;
312 error:
313         isl_basic_set_free(eq);
314         return NULL;
315 }
316
317 /* Given a basic set, exploit the equalties in the a basic set to construct
318  * a morphishm that maps the basic set to a lower-dimensional space.
319  * Specifically, the morphism reduces the number of dimensions of type "type".
320  *
321  * This function is a slight generalization of isl_mat_variable_compression
322  * in that it allows the input to be parametric and that it allows for the
323  * compression of either parameters or set variables.
324  *
325  * We first select the equalities of interest, that is those that involve
326  * variables of type "type" and no later variables.
327  * Denote those equalities as
328  *
329  *              -C(p) + M x = 0
330  *
331  * where C(p) depends on the parameters if type == isl_dim_set and
332  * is a constant if type == isl_dim_param.
333  *
334  * First compute the (left) Hermite normal form of M,
335  *
336  *              M [U1 U2] = M U = H = [H1 0]
337  * or
338  *                            M = H Q = [H1 0] [Q1]
339  *                                             [Q2]
340  *
341  * with U, Q unimodular, Q = U^{-1} (and H lower triangular).
342  * Define the transformed variables as
343  *
344  *              x = [U1 U2] [ x1' ] = [U1 U2] [Q1] x
345  *                          [ x2' ]           [Q2]
346  *
347  * The equalities then become
348  *
349  *              -C(p) + H1 x1' = 0   or   x1' = H1^{-1} C(p) = C'(p)
350  *
351  * If the denominator of the constant term does not divide the
352  * the common denominator of the parametric terms, then every
353  * integer point is mapped to a non-integer point and then the original set has no
354  * integer solutions (since the x' are a unimodular transformation
355  * of the x).  In this case, an empty morphism is returned.
356  * Otherwise, the transformation is given by
357  *
358  *              x = U1 H1^{-1} C(p) + U2 x2'
359  *
360  * The inverse transformation is simply
361  *
362  *              x2' = Q2 x
363  *
364  * Both matrices are extended to map the full original space to the full
365  * compressed space.
366  */
367 __isl_give isl_morph *isl_basic_set_variable_compression(
368         __isl_keep isl_basic_set *bset, enum isl_dim_type type)
369 {
370         unsigned otype;
371         unsigned ntype;
372         unsigned orest;
373         unsigned nrest;
374         int f_eq, n_eq;
375         isl_space *dim;
376         isl_mat *H, *U, *Q, *C = NULL, *H1, *U1, *U2;
377         isl_basic_set *dom, *ran;
378
379         if (!bset)
380                 return NULL;
381
382         if (isl_basic_set_plain_is_empty(bset))
383                 return isl_morph_empty(bset);
384
385         isl_assert(bset->ctx, bset->n_div == 0, return NULL);
386
387         otype = 1 + isl_space_offset(bset->dim, type);
388         ntype = isl_basic_set_dim(bset, type);
389         orest = otype + ntype;
390         nrest = isl_basic_set_total_dim(bset) - (orest - 1);
391
392         for (f_eq = 0; f_eq < bset->n_eq; ++f_eq)
393                 if (isl_seq_first_non_zero(bset->eq[f_eq] + orest, nrest) == -1)
394                         break;
395         for (n_eq = 0; f_eq + n_eq < bset->n_eq; ++n_eq)
396                 if (isl_seq_first_non_zero(bset->eq[f_eq + n_eq] + otype, ntype) == -1)
397                         break;
398         if (n_eq == 0)
399                 return isl_morph_identity(bset);
400
401         H = isl_mat_sub_alloc6(bset->ctx, bset->eq, f_eq, n_eq, otype, ntype);
402         H = isl_mat_left_hermite(H, 0, &U, &Q);
403         if (!H || !U || !Q)
404                 goto error;
405         Q = isl_mat_drop_rows(Q, 0, n_eq);
406         Q = isl_mat_diagonal(isl_mat_identity(bset->ctx, otype), Q);
407         Q = isl_mat_diagonal(Q, isl_mat_identity(bset->ctx, nrest));
408         C = isl_mat_alloc(bset->ctx, 1 + n_eq, otype);
409         if (!C)
410                 goto error;
411         isl_int_set_si(C->row[0][0], 1);
412         isl_seq_clr(C->row[0] + 1, otype - 1);
413         isl_mat_sub_neg(C->ctx, C->row + 1, bset->eq + f_eq, n_eq, 0, 0, otype);
414         H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
415         H1 = isl_mat_lin_to_aff(H1);
416         C = isl_mat_inverse_product(H1, C);
417         if (!C)
418                 goto error;
419         isl_mat_free(H);
420
421         if (!isl_int_is_one(C->row[0][0])) {
422                 int i;
423                 isl_int g;
424
425                 isl_int_init(g);
426                 for (i = 0; i < n_eq; ++i) {
427                         isl_seq_gcd(C->row[1 + i] + 1, otype - 1, &g);
428                         isl_int_gcd(g, g, C->row[0][0]);
429                         if (!isl_int_is_divisible_by(C->row[1 + i][0], g))
430                                 break;
431                 }
432                 isl_int_clear(g);
433
434                 if (i < n_eq) {
435                         isl_mat_free(C);
436                         isl_mat_free(U);
437                         isl_mat_free(Q);
438                         return isl_morph_empty(bset);
439                 }
440
441                 C = isl_mat_normalize(C);
442         }
443
444         U1 = isl_mat_sub_alloc(U, 0, U->n_row, 0, n_eq);
445         U1 = isl_mat_lin_to_aff(U1);
446         U2 = isl_mat_sub_alloc(U, 0, U->n_row, n_eq, U->n_row - n_eq);
447         U2 = isl_mat_lin_to_aff(U2);
448         isl_mat_free(U);
449
450         C = isl_mat_product(U1, C);
451         C = isl_mat_aff_direct_sum(C, U2);
452         C = insert_parameter_rows(C, otype - 1);
453         C = isl_mat_diagonal(C, isl_mat_identity(bset->ctx, nrest));
454
455         dim = isl_space_copy(bset->dim);
456         dim = isl_space_drop_dims(dim, type, 0, ntype);
457         dim = isl_space_add_dims(dim, type, ntype - n_eq);
458         ran = isl_basic_set_universe(dim);
459         dom = copy_equalities(bset, f_eq, n_eq);
460
461         return isl_morph_alloc(dom, ran, Q, C);
462 error:
463         isl_mat_free(C);
464         isl_mat_free(H);
465         isl_mat_free(U);
466         isl_mat_free(Q);
467         return NULL;
468 }
469
470 /* Construct a parameter compression for "bset".
471  * We basically just call isl_mat_parameter_compression with the right input
472  * and then extend the resulting matrix to include the variables.
473  *
474  * Let the equalities be given as
475  *
476  *      B(p) + A x = 0
477  *
478  * and let [H 0] be the Hermite Normal Form of A, then
479  *
480  *      H^-1 B(p)
481  *
482  * needs to be integer, so we impose that each row is divisible by
483  * the denominator.
484  */
485 __isl_give isl_morph *isl_basic_set_parameter_compression(
486         __isl_keep isl_basic_set *bset)
487 {
488         unsigned nparam;
489         unsigned nvar;
490         int n_eq;
491         isl_mat *H, *B;
492         isl_vec *d;
493         isl_mat *map, *inv;
494         isl_basic_set *dom, *ran;
495
496         if (!bset)
497                 return NULL;
498
499         if (isl_basic_set_plain_is_empty(bset))
500                 return isl_morph_empty(bset);
501         if (bset->n_eq == 0)
502                 return isl_morph_identity(bset);
503
504         isl_assert(bset->ctx, bset->n_div == 0, return NULL);
505
506         n_eq = bset->n_eq;
507         nparam = isl_basic_set_dim(bset, isl_dim_param);
508         nvar = isl_basic_set_dim(bset, isl_dim_set);
509
510         isl_assert(bset->ctx, n_eq <= nvar, return NULL);
511
512         d = isl_vec_alloc(bset->ctx, n_eq);
513         B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, n_eq, 0, 1 + nparam);
514         H = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, n_eq, 1 + nparam, nvar);
515         H = isl_mat_left_hermite(H, 0, NULL, NULL);
516         H = isl_mat_drop_cols(H, n_eq, nvar - n_eq);
517         H = isl_mat_lin_to_aff(H);
518         H = isl_mat_right_inverse(H);
519         if (!H || !d)
520                 goto error;
521         isl_seq_set(d->el, H->row[0][0], d->size);
522         H = isl_mat_drop_rows(H, 0, 1);
523         H = isl_mat_drop_cols(H, 0, 1);
524         B = isl_mat_product(H, B);
525         inv = isl_mat_parameter_compression(B, d);
526         inv = isl_mat_diagonal(inv, isl_mat_identity(bset->ctx, nvar));
527         map = isl_mat_right_inverse(isl_mat_copy(inv));
528
529         dom = isl_basic_set_universe(isl_space_copy(bset->dim));
530         ran = isl_basic_set_universe(isl_space_copy(bset->dim));
531
532         return isl_morph_alloc(dom, ran, map, inv);
533 error:
534         isl_mat_free(H);
535         isl_mat_free(B);
536         isl_vec_free(d);
537         return NULL;
538 }
539
540 /* Add stride constraints to "bset" based on the inverse mapping
541  * that was plugged in.  In particular, if morph maps x' to x,
542  * the the constraints of the original input
543  *
544  *      A x' + b >= 0
545  *
546  * have been rewritten to
547  *
548  *      A inv x + b >= 0
549  *
550  * However, this substitution may loose information on the integrality of x',
551  * so we need to impose that
552  *
553  *      inv x
554  *
555  * is integral.  If inv = B/d, this means that we need to impose that
556  *
557  *      B x = 0         mod d
558  *
559  * or
560  *
561  *      exists alpha in Z^m: B x = d alpha
562  *
563  */
564 static __isl_give isl_basic_set *add_strides(__isl_take isl_basic_set *bset,
565         __isl_keep isl_morph *morph)
566 {
567         int i, div, k;
568         isl_int gcd;
569
570         if (isl_int_is_one(morph->inv->row[0][0]))
571                 return bset;
572
573         isl_int_init(gcd);
574
575         for (i = 0; 1 + i < morph->inv->n_row; ++i) {
576                 isl_seq_gcd(morph->inv->row[1 + i], morph->inv->n_col, &gcd);
577                 if (isl_int_is_divisible_by(gcd, morph->inv->row[0][0]))
578                         continue;
579                 div = isl_basic_set_alloc_div(bset);
580                 if (div < 0)
581                         goto error;
582                 k = isl_basic_set_alloc_equality(bset);
583                 if (k < 0)
584                         goto error;
585                 isl_seq_cpy(bset->eq[k], morph->inv->row[1 + i],
586                             morph->inv->n_col);
587                 isl_seq_clr(bset->eq[k] + morph->inv->n_col, bset->n_div);
588                 isl_int_set(bset->eq[k][morph->inv->n_col + div],
589                             morph->inv->row[0][0]);
590         }
591
592         isl_int_clear(gcd);
593
594         return bset;
595 error:
596         isl_int_clear(gcd);
597         isl_basic_set_free(bset);
598         return NULL;
599 }
600
601 /* Apply the morphism to the basic set.
602  * We basically just compute the preimage of "bset" under the inverse mapping
603  * in morph, add in stride constraints and intersect with the range
604  * of the morphism.
605  */
606 __isl_give isl_basic_set *isl_morph_basic_set(__isl_take isl_morph *morph,
607         __isl_take isl_basic_set *bset)
608 {
609         isl_basic_set *res = NULL;
610         isl_mat *mat = NULL;
611         int i, k;
612         int max_stride;
613
614         if (!morph || !bset)
615                 goto error;
616
617         isl_assert(bset->ctx, isl_space_is_equal(bset->dim, morph->dom->dim),
618                     goto error);
619
620         max_stride = morph->inv->n_row - 1;
621         if (isl_int_is_one(morph->inv->row[0][0]))
622                 max_stride = 0;
623         res = isl_basic_set_alloc_space(isl_space_copy(morph->ran->dim),
624                 bset->n_div + max_stride, bset->n_eq + max_stride, bset->n_ineq);
625
626         for (i = 0; i < bset->n_div; ++i)
627                 if (isl_basic_set_alloc_div(res) < 0)
628                         goto error;
629
630         mat = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq,
631                                         0, morph->inv->n_row);
632         mat = isl_mat_product(mat, isl_mat_copy(morph->inv));
633         if (!mat)
634                 goto error;
635         for (i = 0; i < bset->n_eq; ++i) {
636                 k = isl_basic_set_alloc_equality(res);
637                 if (k < 0)
638                         goto error;
639                 isl_seq_cpy(res->eq[k], mat->row[i], mat->n_col);
640                 isl_seq_scale(res->eq[k] + mat->n_col, bset->eq[i] + mat->n_col,
641                                 morph->inv->row[0][0], bset->n_div);
642         }
643         isl_mat_free(mat);
644
645         mat = isl_mat_sub_alloc6(bset->ctx, bset->ineq, 0, bset->n_ineq,
646                                         0, morph->inv->n_row);
647         mat = isl_mat_product(mat, isl_mat_copy(morph->inv));
648         if (!mat)
649                 goto error;
650         for (i = 0; i < bset->n_ineq; ++i) {
651                 k = isl_basic_set_alloc_inequality(res);
652                 if (k < 0)
653                         goto error;
654                 isl_seq_cpy(res->ineq[k], mat->row[i], mat->n_col);
655                 isl_seq_scale(res->ineq[k] + mat->n_col,
656                                 bset->ineq[i] + mat->n_col,
657                                 morph->inv->row[0][0], bset->n_div);
658         }
659         isl_mat_free(mat);
660
661         mat = isl_mat_sub_alloc6(bset->ctx, bset->div, 0, bset->n_div,
662                                         1, morph->inv->n_row);
663         mat = isl_mat_product(mat, isl_mat_copy(morph->inv));
664         if (!mat)
665                 goto error;
666         for (i = 0; i < bset->n_div; ++i) {
667                 isl_int_mul(res->div[i][0],
668                                 morph->inv->row[0][0], bset->div[i][0]);
669                 isl_seq_cpy(res->div[i] + 1, mat->row[i], mat->n_col);
670                 isl_seq_scale(res->div[i] + 1 + mat->n_col,
671                                 bset->div[i] + 1 + mat->n_col,
672                                 morph->inv->row[0][0], bset->n_div);
673         }
674         isl_mat_free(mat);
675
676         res = add_strides(res, morph);
677
678         if (isl_basic_set_is_rational(bset))
679                 res = isl_basic_set_set_rational(res);
680
681         res = isl_basic_set_simplify(res);
682         res = isl_basic_set_finalize(res);
683
684         res = isl_basic_set_intersect(res, isl_basic_set_copy(morph->ran));
685
686         isl_morph_free(morph);
687         isl_basic_set_free(bset);
688         return res;
689 error:
690         isl_mat_free(mat);
691         isl_morph_free(morph);
692         isl_basic_set_free(bset);
693         isl_basic_set_free(res);
694         return NULL;
695 }
696
697 /* Apply the morphism to the set.
698  */
699 __isl_give isl_set *isl_morph_set(__isl_take isl_morph *morph,
700         __isl_take isl_set *set)
701 {
702         int i;
703
704         if (!morph || !set)
705                 goto error;
706
707         isl_assert(set->ctx, isl_space_is_equal(set->dim, morph->dom->dim), goto error);
708
709         set = isl_set_cow(set);
710         if (!set)
711                 goto error;
712
713         isl_space_free(set->dim);
714         set->dim = isl_space_copy(morph->ran->dim);
715         if (!set->dim)
716                 goto error;
717
718         for (i = 0; i < set->n; ++i) {
719                 set->p[i] = isl_morph_basic_set(isl_morph_copy(morph), set->p[i]);
720                 if (!set->p[i])
721                         goto error;
722         }
723
724         isl_morph_free(morph);
725
726         ISL_F_CLR(set, ISL_SET_NORMALIZED);
727
728         return set;
729 error:
730         isl_set_free(set);
731         isl_morph_free(morph);
732         return NULL;
733 }
734
735 /* Construct a morphism that first does morph2 and then morph1.
736  */
737 __isl_give isl_morph *isl_morph_compose(__isl_take isl_morph *morph1,
738         __isl_take isl_morph *morph2)
739 {
740         isl_mat *map, *inv;
741         isl_basic_set *dom, *ran;
742
743         if (!morph1 || !morph2)
744                 goto error;
745
746         map = isl_mat_product(isl_mat_copy(morph1->map), isl_mat_copy(morph2->map));
747         inv = isl_mat_product(isl_mat_copy(morph2->inv), isl_mat_copy(morph1->inv));
748         dom = isl_morph_basic_set(isl_morph_inverse(isl_morph_copy(morph2)),
749                                   isl_basic_set_copy(morph1->dom));
750         dom = isl_basic_set_intersect(dom, isl_basic_set_copy(morph2->dom));
751         ran = isl_morph_basic_set(isl_morph_copy(morph1),
752                                   isl_basic_set_copy(morph2->ran));
753         ran = isl_basic_set_intersect(ran, isl_basic_set_copy(morph1->ran));
754
755         isl_morph_free(morph1);
756         isl_morph_free(morph2);
757
758         return isl_morph_alloc(dom, ran, map, inv);
759 error:
760         isl_morph_free(morph1);
761         isl_morph_free(morph2);
762         return NULL;
763 }
764
765 __isl_give isl_morph *isl_morph_inverse(__isl_take isl_morph *morph)
766 {
767         isl_basic_set *bset;
768         isl_mat *mat;
769
770         morph = isl_morph_cow(morph);
771         if (!morph)
772                 return NULL;
773
774         bset = morph->dom;
775         morph->dom = morph->ran;
776         morph->ran = bset;
777
778         mat = morph->map;
779         morph->map = morph->inv;
780         morph->inv = mat;
781
782         return morph;
783 }
784
785 __isl_give isl_morph *isl_basic_set_full_compression(
786         __isl_keep isl_basic_set *bset)
787 {
788         isl_morph *morph, *morph2;
789
790         bset = isl_basic_set_copy(bset);
791
792         morph = isl_basic_set_variable_compression(bset, isl_dim_param);
793         bset = isl_morph_basic_set(isl_morph_copy(morph), bset);
794
795         morph2 = isl_basic_set_parameter_compression(bset);
796         bset = isl_morph_basic_set(isl_morph_copy(morph2), bset);
797
798         morph = isl_morph_compose(morph2, morph);
799
800         morph2 = isl_basic_set_variable_compression(bset, isl_dim_set);
801         isl_basic_set_free(bset);
802
803         morph = isl_morph_compose(morph2, morph);
804
805         return morph;
806 }
807
808 __isl_give isl_vec *isl_morph_vec(__isl_take isl_morph *morph,
809         __isl_take isl_vec *vec)
810 {
811         if (!morph)
812                 goto error;
813
814         vec = isl_mat_vec_product(isl_mat_copy(morph->map), vec);
815
816         isl_morph_free(morph);
817         return vec;
818 error:
819         isl_morph_free(morph);
820         isl_vec_free(vec);
821         return NULL;
822 }