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