isl_basic_map_from_constraint: only return copy of bmap on equality constraints
[isl.git] / isl_factorization.c
blob379222bc278c80c1f465046a7ed686631a23f459
1 /*
2 * Copyright 2005-2007 Universiteit Leiden
3 * Copyright 2008-2009 Katholieke Universiteit Leuven
4 * Copyright 2010 INRIA Saclay
6 * Use of this software is governed by the GNU LGPLv2.1 license
8 * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science,
9 * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands
10 * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A,
11 * B-3001 Leuven, Belgium
12 * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
13 * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
16 #include <isl_factorization.h>
17 #include <isl_dim_private.h>
19 static __isl_give isl_factorizer *isl_factorizer_alloc(
20 __isl_take isl_morph *morph, int n_group)
22 isl_factorizer *f = NULL;
23 int *len = NULL;
25 if (!morph)
26 return NULL;
28 if (n_group > 0) {
29 len = isl_alloc_array(morph->dom->ctx, int, n_group);
30 if (!len)
31 goto error;
34 f = isl_alloc_type(morph->dom->ctx, struct isl_factorizer);
35 if (!f)
36 goto error;
38 f->morph = morph;
39 f->n_group = n_group;
40 f->len = len;
42 return f;
43 error:
44 free(len);
45 isl_morph_free(morph);
46 return NULL;
49 void isl_factorizer_free(__isl_take isl_factorizer *f)
51 if (!f)
52 return;
54 isl_morph_free(f->morph);
55 free(f->len);
56 free(f);
59 void isl_factorizer_dump(__isl_take isl_factorizer *f, FILE *out)
61 int i;
63 if (!f)
64 return;
66 isl_morph_dump(f->morph, out);
67 fprintf(out, "[");
68 for (i = 0; i < f->n_group; ++i) {
69 if (i)
70 fprintf(out, ", ");
71 fprintf(out, "%d", f->len[i]);
73 fprintf(out, "]\n");
76 __isl_give isl_factorizer *isl_factorizer_identity(__isl_keep isl_basic_set *bset)
78 return isl_factorizer_alloc(isl_morph_identity(bset), 0);
81 __isl_give isl_factorizer *isl_factorizer_groups(__isl_keep isl_basic_set *bset,
82 __isl_take isl_mat *Q, __isl_take isl_mat *U, int n, int *len)
84 int i;
85 unsigned nvar;
86 unsigned ovar;
87 isl_dim *dim;
88 isl_basic_set *dom;
89 isl_basic_set *ran;
90 isl_morph *morph;
91 isl_factorizer *f;
92 isl_mat *id;
94 if (!bset || !Q || !U)
95 goto error;
97 ovar = 1 + isl_dim_offset(bset->dim, isl_dim_set);
98 id = isl_mat_identity(bset->ctx, ovar);
99 Q = isl_mat_diagonal(isl_mat_copy(id), Q);
100 U = isl_mat_diagonal(id, U);
102 nvar = isl_basic_set_dim(bset, isl_dim_set);
103 dim = isl_basic_set_get_dim(bset);
104 dom = isl_basic_set_universe(isl_dim_copy(dim));
105 dim = isl_dim_drop(dim, isl_dim_set, 0, nvar);
106 dim = isl_dim_add(dim, isl_dim_set, nvar);
107 ran = isl_basic_set_universe(dim);
108 morph = isl_morph_alloc(dom, ran, Q, U);
109 f = isl_factorizer_alloc(morph, n);
110 if (!f)
111 return NULL;
112 for (i = 0; i < n; ++i)
113 f->len[i] = len[i];
114 return f;
115 error:
116 isl_mat_free(Q);
117 isl_mat_free(U);
118 return NULL;
121 struct isl_factor_groups {
122 int *pos; /* for each column: row position of pivot */
123 int *group; /* group to which a column belongs */
124 int *cnt; /* number of columns in the group */
125 int *rowgroup; /* group to which a constraint belongs */
128 /* Initialize isl_factor_groups structure: find pivot row positions,
129 * each column initially belongs to its own group and the groups
130 * of the constraints are still unknown.
132 static int init_groups(struct isl_factor_groups *g, __isl_keep isl_mat *H)
134 int i, j;
136 if (!H)
137 return -1;
139 g->pos = isl_alloc_array(H->ctx, int, H->n_col);
140 g->group = isl_alloc_array(H->ctx, int, H->n_col);
141 g->cnt = isl_alloc_array(H->ctx, int, H->n_col);
142 g->rowgroup = isl_alloc_array(H->ctx, int, H->n_row);
144 if (!g->pos || !g->group || !g->cnt || !g->rowgroup)
145 return -1;
147 for (i = 0; i < H->n_row; ++i)
148 g->rowgroup[i] = -1;
149 for (i = 0, j = 0; i < H->n_col; ++i) {
150 for ( ; j < H->n_row; ++j)
151 if (!isl_int_is_zero(H->row[j][i]))
152 break;
153 g->pos[i] = j;
155 for (i = 0; i < H->n_col; ++i) {
156 g->group[i] = i;
157 g->cnt[i] = 1;
160 return 0;
163 /* Update group[k] to the group column k belongs to.
164 * When merging two groups, only the group of the current
165 * group leader is changed. Here we change the group of
166 * the other members to also point to the group that the
167 * old group leader now points to.
169 static void update_group(struct isl_factor_groups *g, int k)
171 int p = g->group[k];
172 while (g->cnt[p] == 0)
173 p = g->group[p];
174 g->group[k] = p;
177 /* Merge group i with all groups of the subsequent columns
178 * with non-zero coefficients in row j of H.
179 * (The previous columns are all zero; otherwise we would have handled
180 * the row before.)
182 static int update_group_i_with_row_j(struct isl_factor_groups *g, int i, int j,
183 __isl_keep isl_mat *H)
185 int k;
187 g->rowgroup[j] = g->group[i];
188 for (k = i + 1; k < H->n_col && j >= g->pos[k]; ++k) {
189 update_group(g, k);
190 update_group(g, i);
191 if (g->group[k] != g->group[i] &&
192 !isl_int_is_zero(H->row[j][k])) {
193 isl_assert(H->ctx, g->cnt[g->group[k]] != 0, return -1);
194 isl_assert(H->ctx, g->cnt[g->group[i]] != 0, return -1);
195 if (g->group[i] < g->group[k]) {
196 g->cnt[g->group[i]] += g->cnt[g->group[k]];
197 g->cnt[g->group[k]] = 0;
198 g->group[g->group[k]] = g->group[i];
199 } else {
200 g->cnt[g->group[k]] += g->cnt[g->group[i]];
201 g->cnt[g->group[i]] = 0;
202 g->group[g->group[i]] = g->group[k];
207 return 0;
210 /* Update the group information based on the constraint matrix.
212 static int update_groups(struct isl_factor_groups *g, __isl_keep isl_mat *H)
214 int i, j;
216 for (i = 0; i < H->n_col && g->cnt[0] < H->n_col; ++i) {
217 if (g->pos[i] == H->n_row)
218 continue; /* A line direction */
219 if (g->rowgroup[g->pos[i]] == -1)
220 g->rowgroup[g->pos[i]] = i;
221 for (j = g->pos[i] + 1; j < H->n_row; ++j) {
222 if (isl_int_is_zero(H->row[j][i]))
223 continue;
224 if (g->rowgroup[j] != -1)
225 continue;
226 if (update_group_i_with_row_j(g, i, j, H) < 0)
227 return -1;
231 return 0;
234 static void clear_groups(struct isl_factor_groups *g)
236 if (!g)
237 return;
238 free(g->pos);
239 free(g->group);
240 free(g->cnt);
241 free(g->rowgroup);
244 /* Determine if the set variables of the basic set can be factorized and
245 * return the results in an isl_factorizer.
247 * The algorithm works by first computing the Hermite normal form
248 * and then grouping columns linked by one or more constraints together,
249 * where a constraints "links" two or more columns if the constraint
250 * has nonzero coefficients in the columns.
252 __isl_give isl_factorizer *isl_basic_set_factorizer(
253 __isl_keep isl_basic_set *bset)
255 int i, j, n, done;
256 isl_mat *H, *U, *Q;
257 unsigned nvar;
258 struct isl_factor_groups g = { 0 };
259 isl_factorizer *f;
261 if (!bset)
262 return NULL;
264 isl_assert(bset->ctx, isl_basic_set_dim(bset, isl_dim_div) == 0,
265 return NULL);
267 nvar = isl_basic_set_dim(bset, isl_dim_set);
268 if (nvar <= 1)
269 return isl_factorizer_identity(bset);
271 H = isl_mat_alloc(bset->ctx, bset->n_eq + bset->n_ineq, nvar);
272 if (!H)
273 return NULL;
274 isl_mat_sub_copy(bset->ctx, H->row, bset->eq, bset->n_eq,
275 0, 1 + isl_dim_offset(bset->dim, isl_dim_set), nvar);
276 isl_mat_sub_copy(bset->ctx, H->row + bset->n_eq, bset->ineq, bset->n_ineq,
277 0, 1 + isl_dim_offset(bset->dim, isl_dim_set), nvar);
278 H = isl_mat_left_hermite(H, 0, &U, &Q);
280 if (init_groups(&g, H) < 0)
281 goto error;
282 if (update_groups(&g, H) < 0)
283 goto error;
285 if (g.cnt[0] == nvar) {
286 isl_mat_free(H);
287 isl_mat_free(U);
288 isl_mat_free(Q);
289 clear_groups(&g);
291 return isl_factorizer_identity(bset);
294 done = 0;
295 n = 0;
296 while (done != nvar) {
297 int group = g.group[done];
298 for (i = 1; i < g.cnt[group]; ++i) {
299 if (g.group[done + i] == group)
300 continue;
301 for (j = done + g.cnt[group]; j < nvar; ++j)
302 if (g.group[j] == group)
303 break;
304 g.group[j] = g.group[done + i];
305 Q = isl_mat_swap_rows(Q, done + i, j);
306 U = isl_mat_swap_cols(U, done + i, j);
308 done += g.cnt[group];
309 g.pos[n++] = g.cnt[group];
312 f = isl_factorizer_groups(bset, Q, U, n, g.pos);
314 isl_mat_free(H);
315 clear_groups(&g);
317 return f;
318 error:
319 isl_mat_free(H);
320 isl_mat_free(U);
321 isl_mat_free(Q);
322 clear_groups(&g);
323 return NULL;