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 MIT 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 /* Return the isl_ctx to which "f" belongs.
23 isl_ctx
*isl_factorizer_get_ctx(__isl_keep isl_factorizer
*f
)
27 return isl_basic_set_get_ctx(f
->bset
);
30 static __isl_give isl_factorizer
*isl_factorizer_alloc(
31 __isl_keep isl_basic_set
*bset
, __isl_take isl_morph
*morph
,
34 isl_factorizer
*f
= NULL
;
41 len
= isl_alloc_array(morph
->dom
->ctx
, int, n_group
);
46 f
= isl_alloc_type(morph
->dom
->ctx
, struct isl_factorizer
);
50 f
->bset
= isl_basic_set_copy(bset
);
58 isl_morph_free(morph
);
62 __isl_null isl_factorizer
*isl_factorizer_free(__isl_take isl_factorizer
*f
)
67 isl_basic_set_free(f
->bset
);
68 isl_morph_free(f
->morph
);
74 void isl_factorizer_dump(__isl_take isl_factorizer
*f
)
81 isl_morph_print_internal(f
->morph
, stderr
);
83 for (i
= 0; i
< f
->n_group
; ++i
) {
85 fprintf(stderr
, ", ");
86 fprintf(stderr
, "%d", f
->len
[i
]);
88 fprintf(stderr
, "]\n");
91 __isl_give isl_factorizer
*isl_factorizer_identity(__isl_keep isl_basic_set
*bset
)
93 return isl_factorizer_alloc(bset
, isl_morph_identity(bset
), 0);
96 __isl_give isl_factorizer
*isl_factorizer_groups(__isl_keep isl_basic_set
*bset
,
97 __isl_take isl_mat
*Q
, __isl_take isl_mat
*U
, int n
, int *len
)
108 nvar
= isl_basic_set_dim(bset
, isl_dim_set
);
109 off
= isl_basic_set_var_offset(bset
, isl_dim_set
);
110 if (nvar
< 0 || off
< 0 || !Q
|| !U
)
113 id
= isl_mat_identity(bset
->ctx
, 1 + off
);
114 Q
= isl_mat_diagonal(isl_mat_copy(id
), Q
);
115 U
= isl_mat_diagonal(id
, U
);
117 space
= isl_basic_set_get_space(bset
);
118 dom
= isl_basic_set_universe(isl_space_copy(space
));
119 space
= isl_space_drop_dims(space
, isl_dim_set
, 0, nvar
);
120 space
= isl_space_add_dims(space
, isl_dim_set
, nvar
);
121 ran
= isl_basic_set_universe(space
);
122 morph
= isl_morph_alloc(dom
, ran
, Q
, U
);
123 f
= isl_factorizer_alloc(bset
, morph
, n
);
126 for (i
= 0; i
< n
; ++i
)
135 struct isl_factor_groups
{
136 int *pos
; /* for each column: row position of pivot */
137 int *group
; /* group to which a column belongs */
138 int *cnt
; /* number of columns in the group */
139 int *rowgroup
; /* group to which a constraint belongs */
142 /* Initialize isl_factor_groups structure: find pivot row positions,
143 * each column initially belongs to its own group and the groups
144 * of the constraints are still unknown.
146 static int init_groups(struct isl_factor_groups
*g
, __isl_keep isl_mat
*H
)
153 g
->pos
= isl_alloc_array(H
->ctx
, int, H
->n_col
);
154 g
->group
= isl_alloc_array(H
->ctx
, int, H
->n_col
);
155 g
->cnt
= isl_alloc_array(H
->ctx
, int, H
->n_col
);
156 g
->rowgroup
= isl_alloc_array(H
->ctx
, int, H
->n_row
);
158 if (!g
->pos
|| !g
->group
|| !g
->cnt
|| !g
->rowgroup
)
161 for (i
= 0; i
< H
->n_row
; ++i
)
163 for (i
= 0, j
= 0; i
< H
->n_col
; ++i
) {
164 for ( ; j
< H
->n_row
; ++j
)
165 if (!isl_int_is_zero(H
->row
[j
][i
]))
169 for (i
= 0; i
< H
->n_col
; ++i
) {
177 /* Update group[k] to the group column k belongs to.
178 * When merging two groups, only the group of the current
179 * group leader is changed. Here we change the group of
180 * the other members to also point to the group that the
181 * old group leader now points to.
183 static void update_group(struct isl_factor_groups
*g
, int k
)
186 while (g
->cnt
[p
] == 0)
191 /* Merge group i with all groups of the subsequent columns
192 * with non-zero coefficients in row j of H.
193 * (The previous columns are all zero; otherwise we would have handled
196 static int update_group_i_with_row_j(struct isl_factor_groups
*g
, int i
, int j
,
197 __isl_keep isl_mat
*H
)
201 g
->rowgroup
[j
] = g
->group
[i
];
202 for (k
= i
+ 1; k
< H
->n_col
&& j
>= g
->pos
[k
]; ++k
) {
205 if (g
->group
[k
] != g
->group
[i
] &&
206 !isl_int_is_zero(H
->row
[j
][k
])) {
207 isl_assert(H
->ctx
, g
->cnt
[g
->group
[k
]] != 0, return -1);
208 isl_assert(H
->ctx
, g
->cnt
[g
->group
[i
]] != 0, return -1);
209 if (g
->group
[i
] < g
->group
[k
]) {
210 g
->cnt
[g
->group
[i
]] += g
->cnt
[g
->group
[k
]];
211 g
->cnt
[g
->group
[k
]] = 0;
212 g
->group
[g
->group
[k
]] = g
->group
[i
];
214 g
->cnt
[g
->group
[k
]] += g
->cnt
[g
->group
[i
]];
215 g
->cnt
[g
->group
[i
]] = 0;
216 g
->group
[g
->group
[i
]] = g
->group
[k
];
224 /* Update the group information based on the constraint matrix.
226 static int update_groups(struct isl_factor_groups
*g
, __isl_keep isl_mat
*H
)
230 for (i
= 0; i
< H
->n_col
&& g
->cnt
[0] < H
->n_col
; ++i
) {
231 if (g
->pos
[i
] == H
->n_row
)
232 continue; /* A line direction */
233 if (g
->rowgroup
[g
->pos
[i
]] == -1)
234 g
->rowgroup
[g
->pos
[i
]] = i
;
235 for (j
= g
->pos
[i
] + 1; j
< H
->n_row
; ++j
) {
236 if (isl_int_is_zero(H
->row
[j
][i
]))
238 if (g
->rowgroup
[j
] != -1)
240 if (update_group_i_with_row_j(g
, i
, j
, H
) < 0)
244 for (i
= 1; i
< H
->n_col
; ++i
)
250 static void clear_groups(struct isl_factor_groups
*g
)
260 /* Determine if the set variables of the basic set can be factorized and
261 * return the results in an isl_factorizer.
263 * The algorithm works by first computing the Hermite normal form
264 * and then grouping columns linked by one or more constraints together,
265 * where a constraints "links" two or more columns if the constraint
266 * has nonzero coefficients in the columns.
268 __isl_give isl_factorizer
*isl_basic_set_factorizer(
269 __isl_keep isl_basic_set
*bset
)
273 isl_size nvar
, first
;
274 struct isl_factor_groups g
= { 0 };
277 nvar
= isl_basic_set_dim(bset
, isl_dim_set
);
278 first
= isl_basic_set_var_offset(bset
, isl_dim_set
);
279 if (nvar
< 0 || first
< 0 || isl_basic_set_check_no_locals(bset
) < 0)
283 return isl_factorizer_identity(bset
);
285 H
= isl_mat_alloc(bset
->ctx
, bset
->n_eq
+ bset
->n_ineq
, nvar
);
288 isl_mat_sub_copy(bset
->ctx
, H
->row
, bset
->eq
, bset
->n_eq
,
290 isl_mat_sub_copy(bset
->ctx
, H
->row
+ bset
->n_eq
, bset
->ineq
, bset
->n_ineq
,
292 H
= isl_mat_left_hermite(H
, 0, &U
, &Q
);
294 if (init_groups(&g
, H
) < 0)
296 if (update_groups(&g
, H
) < 0)
299 if (g
.cnt
[0] == nvar
) {
305 return isl_factorizer_identity(bset
);
310 while (done
!= nvar
) {
311 int group
= g
.group
[done
];
312 for (i
= 1; i
< g
.cnt
[group
]; ++i
) {
313 if (g
.group
[done
+ i
] == group
)
315 for (j
= done
+ g
.cnt
[group
]; j
< nvar
; ++j
)
316 if (g
.group
[j
] == group
)
319 isl_die(bset
->ctx
, isl_error_internal
,
320 "internal error", goto error
);
321 g
.group
[j
] = g
.group
[done
+ i
];
322 Q
= isl_mat_swap_rows(Q
, done
+ i
, j
);
323 U
= isl_mat_swap_cols(U
, done
+ i
, j
);
325 done
+= g
.cnt
[group
];
326 g
.pos
[n
++] = g
.cnt
[group
];
329 f
= isl_factorizer_groups(bset
, Q
, U
, n
, g
.pos
);
343 /* Given the factorizer "f" of a basic set,
344 * call "test" on each resulting factor as long as each call succeeds.
346 __isl_give isl_bool
isl_factorizer_every_factor_basic_set(
347 __isl_keep isl_factorizer
*f
,
348 isl_bool (*test
)(__isl_keep isl_basic_set
*bset
, void *user
),
352 isl_bool every
= isl_bool_true
;
353 isl_size nparam
, nvar
;
357 return isl_bool_error
;
358 nparam
= isl_basic_set_dim(f
->bset
, isl_dim_param
);
359 nvar
= isl_basic_set_dim(f
->bset
, isl_dim_set
);
360 if (nparam
< 0 || nvar
< 0)
361 return isl_bool_error
;
363 bset
= isl_basic_set_copy(f
->bset
);
364 bset
= isl_morph_basic_set(isl_morph_copy(f
->morph
), bset
);
366 for (i
= 0, n
= 0; i
< f
->n_group
; ++i
) {
367 isl_basic_set
*factor
;
369 factor
= isl_basic_set_copy(bset
);
370 factor
= isl_basic_set_drop_constraints_involving(factor
,
371 nparam
+ n
+ f
->len
[i
], nvar
- n
- f
->len
[i
]);
372 factor
= isl_basic_set_drop_constraints_involving(factor
,
374 factor
= isl_basic_set_drop(factor
, isl_dim_set
,
375 n
+ f
->len
[i
], nvar
- n
- f
->len
[i
]);
376 factor
= isl_basic_set_drop(factor
, isl_dim_set
, 0, n
);
377 every
= test(factor
, user
);
378 isl_basic_set_free(factor
);
380 if (every
< 0 || !every
)
386 isl_basic_set_free(bset
);