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
;
29 len
= isl_alloc_array(morph
->dom
->ctx
, int, n_group
);
34 f
= isl_alloc_type(morph
->dom
->ctx
, struct isl_factorizer
);
45 isl_morph_free(morph
);
49 void isl_factorizer_free(__isl_take isl_factorizer
*f
)
54 isl_morph_free(f
->morph
);
59 void isl_factorizer_dump(__isl_take isl_factorizer
*f
, FILE *out
)
66 isl_morph_dump(f
->morph
, out
);
68 for (i
= 0; i
< f
->n_group
; ++i
) {
71 fprintf(out
, "%d", f
->len
[i
]);
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
)
94 if (!bset
|| !Q
|| !U
)
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
);
112 for (i
= 0; i
< n
; ++i
)
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
)
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
)
147 for (i
= 0; i
< H
->n_row
; ++i
)
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
]))
155 for (i
= 0; i
< H
->n_col
; ++i
) {
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
)
172 while (g
->cnt
[p
] == 0)
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
182 static int update_group_i_with_row_j(struct isl_factor_groups
*g
, int i
, int j
,
183 __isl_keep isl_mat
*H
)
187 g
->rowgroup
[j
] = g
->group
[i
];
188 for (k
= i
+ 1; k
< H
->n_col
&& j
>= g
->pos
[k
]; ++k
) {
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
];
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
];
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
)
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
]))
224 if (g
->rowgroup
[j
] != -1)
226 if (update_group_i_with_row_j(g
, i
, j
, H
) < 0)
234 static void clear_groups(struct isl_factor_groups
*g
)
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
)
258 struct isl_factor_groups g
= { 0 };
264 isl_assert(bset
->ctx
, isl_basic_set_dim(bset
, isl_dim_div
) == 0,
267 nvar
= isl_basic_set_dim(bset
, isl_dim_set
);
269 return isl_factorizer_identity(bset
);
271 H
= isl_mat_alloc(bset
->ctx
, bset
->n_eq
+ bset
->n_ineq
, nvar
);
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)
282 if (update_groups(&g
, H
) < 0)
285 if (g
.cnt
[0] == nvar
) {
291 return isl_factorizer_identity(bset
);
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
)
301 for (j
= done
+ g
.cnt
[group
]; j
< nvar
; ++j
)
302 if (g
.group
[j
] == group
)
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
);