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_map_private.h>
17 #include <isl_factorization.h>
18 #include <isl_space_private.h>
19 #include <isl_mat_private.h>
21 static __isl_give isl_factorizer
*isl_factorizer_alloc(
22 __isl_take isl_morph
*morph
, int n_group
)
24 isl_factorizer
*f
= NULL
;
31 len
= isl_alloc_array(morph
->dom
->ctx
, int, n_group
);
36 f
= isl_alloc_type(morph
->dom
->ctx
, struct isl_factorizer
);
47 isl_morph_free(morph
);
51 void isl_factorizer_free(__isl_take isl_factorizer
*f
)
56 isl_morph_free(f
->morph
);
61 void isl_factorizer_dump(__isl_take isl_factorizer
*f
, FILE *out
)
68 isl_morph_dump(f
->morph
, out
);
70 for (i
= 0; i
< f
->n_group
; ++i
) {
73 fprintf(out
, "%d", f
->len
[i
]);
78 __isl_give isl_factorizer
*isl_factorizer_identity(__isl_keep isl_basic_set
*bset
)
80 return isl_factorizer_alloc(isl_morph_identity(bset
), 0);
83 __isl_give isl_factorizer
*isl_factorizer_groups(__isl_keep isl_basic_set
*bset
,
84 __isl_take isl_mat
*Q
, __isl_take isl_mat
*U
, int n
, int *len
)
96 if (!bset
|| !Q
|| !U
)
99 ovar
= 1 + isl_space_offset(bset
->dim
, isl_dim_set
);
100 id
= isl_mat_identity(bset
->ctx
, ovar
);
101 Q
= isl_mat_diagonal(isl_mat_copy(id
), Q
);
102 U
= isl_mat_diagonal(id
, U
);
104 nvar
= isl_basic_set_dim(bset
, isl_dim_set
);
105 dim
= isl_basic_set_get_space(bset
);
106 dom
= isl_basic_set_universe(isl_space_copy(dim
));
107 dim
= isl_space_drop_dims(dim
, isl_dim_set
, 0, nvar
);
108 dim
= isl_space_add_dims(dim
, isl_dim_set
, nvar
);
109 ran
= isl_basic_set_universe(dim
);
110 morph
= isl_morph_alloc(dom
, ran
, Q
, U
);
111 f
= isl_factorizer_alloc(morph
, n
);
114 for (i
= 0; i
< n
; ++i
)
123 struct isl_factor_groups
{
124 int *pos
; /* for each column: row position of pivot */
125 int *group
; /* group to which a column belongs */
126 int *cnt
; /* number of columns in the group */
127 int *rowgroup
; /* group to which a constraint belongs */
130 /* Initialize isl_factor_groups structure: find pivot row positions,
131 * each column initially belongs to its own group and the groups
132 * of the constraints are still unknown.
134 static int init_groups(struct isl_factor_groups
*g
, __isl_keep isl_mat
*H
)
141 g
->pos
= isl_alloc_array(H
->ctx
, int, H
->n_col
);
142 g
->group
= isl_alloc_array(H
->ctx
, int, H
->n_col
);
143 g
->cnt
= isl_alloc_array(H
->ctx
, int, H
->n_col
);
144 g
->rowgroup
= isl_alloc_array(H
->ctx
, int, H
->n_row
);
146 if (!g
->pos
|| !g
->group
|| !g
->cnt
|| !g
->rowgroup
)
149 for (i
= 0; i
< H
->n_row
; ++i
)
151 for (i
= 0, j
= 0; i
< H
->n_col
; ++i
) {
152 for ( ; j
< H
->n_row
; ++j
)
153 if (!isl_int_is_zero(H
->row
[j
][i
]))
157 for (i
= 0; i
< H
->n_col
; ++i
) {
165 /* Update group[k] to the group column k belongs to.
166 * When merging two groups, only the group of the current
167 * group leader is changed. Here we change the group of
168 * the other members to also point to the group that the
169 * old group leader now points to.
171 static void update_group(struct isl_factor_groups
*g
, int k
)
174 while (g
->cnt
[p
] == 0)
179 /* Merge group i with all groups of the subsequent columns
180 * with non-zero coefficients in row j of H.
181 * (The previous columns are all zero; otherwise we would have handled
184 static int update_group_i_with_row_j(struct isl_factor_groups
*g
, int i
, int j
,
185 __isl_keep isl_mat
*H
)
189 g
->rowgroup
[j
] = g
->group
[i
];
190 for (k
= i
+ 1; k
< H
->n_col
&& j
>= g
->pos
[k
]; ++k
) {
193 if (g
->group
[k
] != g
->group
[i
] &&
194 !isl_int_is_zero(H
->row
[j
][k
])) {
195 isl_assert(H
->ctx
, g
->cnt
[g
->group
[k
]] != 0, return -1);
196 isl_assert(H
->ctx
, g
->cnt
[g
->group
[i
]] != 0, return -1);
197 if (g
->group
[i
] < g
->group
[k
]) {
198 g
->cnt
[g
->group
[i
]] += g
->cnt
[g
->group
[k
]];
199 g
->cnt
[g
->group
[k
]] = 0;
200 g
->group
[g
->group
[k
]] = g
->group
[i
];
202 g
->cnt
[g
->group
[k
]] += g
->cnt
[g
->group
[i
]];
203 g
->cnt
[g
->group
[i
]] = 0;
204 g
->group
[g
->group
[i
]] = g
->group
[k
];
212 /* Update the group information based on the constraint matrix.
214 static int update_groups(struct isl_factor_groups
*g
, __isl_keep isl_mat
*H
)
218 for (i
= 0; i
< H
->n_col
&& g
->cnt
[0] < H
->n_col
; ++i
) {
219 if (g
->pos
[i
] == H
->n_row
)
220 continue; /* A line direction */
221 if (g
->rowgroup
[g
->pos
[i
]] == -1)
222 g
->rowgroup
[g
->pos
[i
]] = i
;
223 for (j
= g
->pos
[i
] + 1; j
< H
->n_row
; ++j
) {
224 if (isl_int_is_zero(H
->row
[j
][i
]))
226 if (g
->rowgroup
[j
] != -1)
228 if (update_group_i_with_row_j(g
, i
, j
, H
) < 0)
232 for (i
= 1; i
< H
->n_col
; ++i
)
238 static void clear_groups(struct isl_factor_groups
*g
)
248 /* Determine if the set variables of the basic set can be factorized and
249 * return the results in an isl_factorizer.
251 * The algorithm works by first computing the Hermite normal form
252 * and then grouping columns linked by one or more constraints together,
253 * where a constraints "links" two or more columns if the constraint
254 * has nonzero coefficients in the columns.
256 __isl_give isl_factorizer
*isl_basic_set_factorizer(
257 __isl_keep isl_basic_set
*bset
)
262 struct isl_factor_groups g
= { 0 };
268 isl_assert(bset
->ctx
, isl_basic_set_dim(bset
, isl_dim_div
) == 0,
271 nvar
= isl_basic_set_dim(bset
, isl_dim_set
);
273 return isl_factorizer_identity(bset
);
275 H
= isl_mat_alloc(bset
->ctx
, bset
->n_eq
+ bset
->n_ineq
, nvar
);
278 isl_mat_sub_copy(bset
->ctx
, H
->row
, bset
->eq
, bset
->n_eq
,
279 0, 1 + isl_space_offset(bset
->dim
, isl_dim_set
), nvar
);
280 isl_mat_sub_copy(bset
->ctx
, H
->row
+ bset
->n_eq
, bset
->ineq
, bset
->n_ineq
,
281 0, 1 + isl_space_offset(bset
->dim
, isl_dim_set
), nvar
);
282 H
= isl_mat_left_hermite(H
, 0, &U
, &Q
);
284 if (init_groups(&g
, H
) < 0)
286 if (update_groups(&g
, H
) < 0)
289 if (g
.cnt
[0] == nvar
) {
295 return isl_factorizer_identity(bset
);
300 while (done
!= nvar
) {
301 int group
= g
.group
[done
];
302 for (i
= 1; i
< g
.cnt
[group
]; ++i
) {
303 if (g
.group
[done
+ i
] == group
)
305 for (j
= done
+ g
.cnt
[group
]; j
< nvar
; ++j
)
306 if (g
.group
[j
] == group
)
309 isl_die(bset
->ctx
, isl_error_internal
,
310 "internal error", goto error
);
311 g
.group
[j
] = g
.group
[done
+ i
];
312 Q
= isl_mat_swap_rows(Q
, done
+ i
, j
);
313 U
= isl_mat_swap_cols(U
, done
+ i
, j
);
315 done
+= g
.cnt
[group
];
316 g
.pos
[n
++] = g
.cnt
[group
];
319 f
= isl_factorizer_groups(bset
, Q
, U
, n
, g
.pos
);