Line data Source code
1 : /*
2 : * Copyright 2008-2009 Katholieke Universiteit Leuven
3 : * Copyright 2010 INRIA Saclay
4 : * Copyright 2014 Ecole Normale Superieure
5 : * Copyright 2017 Sven Verdoolaege
6 : *
7 : * Use of this software is governed by the MIT license
8 : *
9 : * Written by Sven Verdoolaege, K.U.Leuven, Departement
10 : * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
11 : * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
12 : * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
13 : * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
14 : */
15 :
16 : #include <isl_ctx_private.h>
17 : #include <isl_map_private.h>
18 : #include <isl/space.h>
19 : #include <isl_seq.h>
20 : #include <isl_mat_private.h>
21 : #include <isl_vec_private.h>
22 : #include <isl_space_private.h>
23 : #include <isl_val_private.h>
24 :
25 20486646636 : isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat)
26 : {
27 20486646636 : return mat ? mat->ctx : NULL;
28 : }
29 :
30 : /* Return a hash value that digests "mat".
31 : */
32 0 : uint32_t isl_mat_get_hash(__isl_keep isl_mat *mat)
33 : {
34 : int i;
35 : uint32_t hash;
36 :
37 0 : if (!mat)
38 0 : return 0;
39 :
40 0 : hash = isl_hash_init();
41 0 : isl_hash_byte(hash, mat->n_row & 0xFF);
42 0 : isl_hash_byte(hash, mat->n_col & 0xFF);
43 0 : for (i = 0; i < mat->n_row; ++i) {
44 : uint32_t row_hash;
45 :
46 0 : row_hash = isl_seq_get_hash(mat->row[i], mat->n_col);
47 0 : isl_hash_hash(hash, row_hash);
48 : }
49 :
50 0 : return hash;
51 : }
52 :
53 16487237484 : struct isl_mat *isl_mat_alloc(struct isl_ctx *ctx,
54 : unsigned n_row, unsigned n_col)
55 : {
56 : int i;
57 : struct isl_mat *mat;
58 :
59 16487237484 : mat = isl_alloc_type(ctx, struct isl_mat);
60 16487237484 : if (!mat)
61 0 : return NULL;
62 :
63 16487237484 : mat->row = NULL;
64 16487237484 : mat->block = isl_blk_alloc(ctx, n_row * n_col);
65 16487237484 : if (isl_blk_is_error(mat->block))
66 0 : goto error;
67 16487237484 : mat->row = isl_alloc_array(ctx, isl_int *, n_row);
68 16487237484 : if (n_row && !mat->row)
69 0 : goto error;
70 :
71 >11769*10^7 : for (i = 0; i < n_row; ++i)
72 >10120*10^7 : mat->row[i] = mat->block.data + i * n_col;
73 :
74 16487237484 : mat->ctx = ctx;
75 16487237484 : isl_ctx_ref(ctx);
76 16487237484 : mat->ref = 1;
77 16487237484 : mat->n_row = n_row;
78 16487237484 : mat->n_col = n_col;
79 16487237484 : mat->max_col = n_col;
80 16487237484 : mat->flags = 0;
81 :
82 16487237484 : return mat;
83 : error:
84 0 : isl_blk_free(ctx, mat->block);
85 0 : free(mat);
86 0 : return NULL;
87 : }
88 :
89 54005843 : struct isl_mat *isl_mat_extend(struct isl_mat *mat,
90 : unsigned n_row, unsigned n_col)
91 : {
92 : int i;
93 : isl_int *old;
94 : isl_int **row;
95 :
96 54005843 : if (!mat)
97 0 : return NULL;
98 :
99 54005843 : if (mat->max_col >= n_col && mat->n_row >= n_row) {
100 0 : if (mat->n_col < n_col)
101 0 : mat->n_col = n_col;
102 0 : return mat;
103 : }
104 :
105 54005843 : if (mat->max_col < n_col) {
106 : struct isl_mat *new_mat;
107 :
108 0 : if (n_row < mat->n_row)
109 0 : n_row = mat->n_row;
110 0 : new_mat = isl_mat_alloc(mat->ctx, n_row, n_col);
111 0 : if (!new_mat)
112 0 : goto error;
113 0 : for (i = 0; i < mat->n_row; ++i)
114 0 : isl_seq_cpy(new_mat->row[i], mat->row[i], mat->n_col);
115 0 : isl_mat_free(mat);
116 0 : return new_mat;
117 : }
118 :
119 54005843 : mat = isl_mat_cow(mat);
120 54005843 : if (!mat)
121 0 : goto error;
122 :
123 54005843 : old = mat->block.data;
124 54005843 : mat->block = isl_blk_extend(mat->ctx, mat->block, n_row * mat->max_col);
125 54005843 : if (isl_blk_is_error(mat->block))
126 0 : goto error;
127 54005843 : row = isl_realloc_array(mat->ctx, mat->row, isl_int *, n_row);
128 54005843 : if (n_row && !row)
129 0 : goto error;
130 54005843 : mat->row = row;
131 :
132 773312800 : for (i = 0; i < mat->n_row; ++i)
133 719306957 : mat->row[i] = mat->block.data + (mat->row[i] - old);
134 109862848 : for (i = mat->n_row; i < n_row; ++i)
135 55857005 : mat->row[i] = mat->block.data + i * mat->max_col;
136 54005843 : mat->n_row = n_row;
137 54005843 : if (mat->n_col < n_col)
138 0 : mat->n_col = n_col;
139 :
140 54005843 : return mat;
141 : error:
142 0 : isl_mat_free(mat);
143 0 : return NULL;
144 : }
145 :
146 5789384470 : __isl_give isl_mat *isl_mat_sub_alloc6(isl_ctx *ctx, isl_int **row,
147 : unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col)
148 : {
149 : int i;
150 : struct isl_mat *mat;
151 :
152 5789384470 : mat = isl_alloc_type(ctx, struct isl_mat);
153 5789384470 : if (!mat)
154 0 : return NULL;
155 5789384470 : mat->row = isl_alloc_array(ctx, isl_int *, n_row);
156 5789384470 : if (n_row && !mat->row)
157 0 : goto error;
158 23010131232 : for (i = 0; i < n_row; ++i)
159 17220746762 : mat->row[i] = row[first_row+i] + first_col;
160 5789384470 : mat->ctx = ctx;
161 5789384470 : isl_ctx_ref(ctx);
162 5789384470 : mat->ref = 1;
163 5789384470 : mat->n_row = n_row;
164 5789384470 : mat->n_col = n_col;
165 5789384470 : mat->block = isl_blk_empty();
166 5789384470 : mat->flags = ISL_MAT_BORROWED;
167 5789384470 : return mat;
168 : error:
169 0 : free(mat);
170 0 : return NULL;
171 : }
172 :
173 1241198492 : __isl_give isl_mat *isl_mat_sub_alloc(__isl_keep isl_mat *mat,
174 : unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col)
175 : {
176 1241198492 : if (!mat)
177 0 : return NULL;
178 1241198492 : return isl_mat_sub_alloc6(mat->ctx, mat->row, first_row, n_row,
179 : first_col, n_col);
180 : }
181 :
182 2590915686 : void isl_mat_sub_copy(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
183 : unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col)
184 : {
185 : int i;
186 :
187 13342131276 : for (i = 0; i < n_row; ++i)
188 10751215590 : isl_seq_cpy(dst[i]+dst_col, src[i]+src_col, n_col);
189 2590915686 : }
190 :
191 310371625 : void isl_mat_sub_neg(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
192 : unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col)
193 : {
194 : int i;
195 :
196 674179449 : for (i = 0; i < n_row; ++i)
197 363807824 : isl_seq_neg(dst[i]+dst_col, src[i]+src_col, n_col);
198 310371625 : }
199 :
200 4736527617 : __isl_give isl_mat *isl_mat_copy(__isl_keep isl_mat *mat)
201 : {
202 4736527617 : if (!mat)
203 0 : return NULL;
204 :
205 4736527617 : mat->ref++;
206 4736527617 : return mat;
207 : }
208 :
209 1081849961 : __isl_give isl_mat *isl_mat_dup(__isl_keep isl_mat *mat)
210 : {
211 : int i;
212 : struct isl_mat *mat2;
213 :
214 1081849961 : if (!mat)
215 0 : return NULL;
216 1081849961 : mat2 = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col);
217 1081849961 : if (!mat2)
218 0 : return NULL;
219 4079450370 : for (i = 0; i < mat->n_row; ++i)
220 2997600409 : isl_seq_cpy(mat2->row[i], mat->row[i], mat->n_col);
221 1081849961 : return mat2;
222 : }
223 :
224 31814961101 : __isl_give isl_mat *isl_mat_cow(__isl_take isl_mat *mat)
225 : {
226 : struct isl_mat *mat2;
227 31814961101 : if (!mat)
228 0 : return NULL;
229 :
230 31814961101 : if (mat->ref == 1 && !ISL_F_ISSET(mat, ISL_MAT_BORROWED))
231 30733111140 : return mat;
232 :
233 1081849961 : mat2 = isl_mat_dup(mat);
234 1081849961 : isl_mat_free(mat);
235 1081849961 : return mat2;
236 : }
237 :
238 32913857706 : __isl_null isl_mat *isl_mat_free(__isl_take isl_mat *mat)
239 : {
240 32913857706 : if (!mat)
241 5900708135 : return NULL;
242 :
243 27013149571 : if (--mat->ref > 0)
244 4736527617 : return NULL;
245 :
246 22276621954 : if (!ISL_F_ISSET(mat, ISL_MAT_BORROWED))
247 16487237484 : isl_blk_free(mat->ctx, mat->block);
248 22276621954 : isl_ctx_deref(mat->ctx);
249 22276621954 : free(mat->row);
250 22276621954 : free(mat);
251 :
252 22276621954 : return NULL;
253 : }
254 :
255 12388551 : int isl_mat_rows(__isl_keep isl_mat *mat)
256 : {
257 12388551 : return mat ? mat->n_row : -1;
258 : }
259 :
260 0 : int isl_mat_cols(__isl_keep isl_mat *mat)
261 : {
262 0 : return mat ? mat->n_col : -1;
263 : }
264 :
265 : /* Check that "col" is a valid column position for "mat".
266 : */
267 0 : static isl_stat check_col(__isl_keep isl_mat *mat, int col)
268 : {
269 0 : if (!mat)
270 0 : return isl_stat_error;
271 0 : if (col < 0 || col >= mat->n_col)
272 0 : isl_die(isl_mat_get_ctx(mat), isl_error_invalid,
273 : "column out of range", return isl_stat_error);
274 0 : return isl_stat_ok;
275 : }
276 :
277 : /* Check that "row" is a valid row position for "mat".
278 : */
279 0 : static isl_stat check_row(__isl_keep isl_mat *mat, int row)
280 : {
281 0 : if (!mat)
282 0 : return isl_stat_error;
283 0 : if (row < 0 || row >= mat->n_row)
284 0 : isl_die(isl_mat_get_ctx(mat), isl_error_invalid,
285 : "row out of range", return isl_stat_error);
286 0 : return isl_stat_ok;
287 : }
288 :
289 : /* Check that there are "n" columns starting at position "first" in "mat".
290 : */
291 7371238595 : static isl_stat check_col_range(__isl_keep isl_mat *mat, unsigned first,
292 : unsigned n)
293 : {
294 7371238595 : if (!mat)
295 0 : return isl_stat_error;
296 7371238595 : if (first + n > mat->n_col || first + n < first)
297 0 : isl_die(isl_mat_get_ctx(mat), isl_error_invalid,
298 : "column position or range out of bounds",
299 : return isl_stat_error);
300 7371238595 : return isl_stat_ok;
301 : }
302 :
303 : /* Check that there are "n" rows starting at position "first" in "mat".
304 : */
305 50133233635 : static isl_stat check_row_range(__isl_keep isl_mat *mat, unsigned first,
306 : unsigned n)
307 : {
308 50133233635 : if (!mat)
309 0 : return isl_stat_error;
310 50133233635 : if (first + n > mat->n_row || first + n < first)
311 0 : isl_die(isl_mat_get_ctx(mat), isl_error_invalid,
312 : "row position or range out of bounds",
313 : return isl_stat_error);
314 50133233635 : return isl_stat_ok;
315 : }
316 :
317 0 : int isl_mat_get_element(__isl_keep isl_mat *mat, int row, int col, isl_int *v)
318 : {
319 0 : if (check_row(mat, row) < 0)
320 0 : return -1;
321 0 : if (check_col(mat, col) < 0)
322 0 : return -1;
323 0 : isl_int_set(*v, mat->row[row][col]);
324 0 : return 0;
325 : }
326 :
327 : /* Extract the element at row "row", oolumn "col" of "mat".
328 : */
329 0 : __isl_give isl_val *isl_mat_get_element_val(__isl_keep isl_mat *mat,
330 : int row, int col)
331 : {
332 : isl_ctx *ctx;
333 :
334 0 : if (check_row(mat, row) < 0)
335 0 : return NULL;
336 0 : if (check_col(mat, col) < 0)
337 0 : return NULL;
338 0 : ctx = isl_mat_get_ctx(mat);
339 0 : return isl_val_int_from_isl_int(ctx, mat->row[row][col]);
340 : }
341 :
342 0 : __isl_give isl_mat *isl_mat_set_element(__isl_take isl_mat *mat,
343 : int row, int col, isl_int v)
344 : {
345 0 : mat = isl_mat_cow(mat);
346 0 : if (check_row(mat, row) < 0)
347 0 : return isl_mat_free(mat);
348 0 : if (check_col(mat, col) < 0)
349 0 : return isl_mat_free(mat);
350 0 : isl_int_set(mat->row[row][col], v);
351 0 : return mat;
352 : }
353 :
354 0 : __isl_give isl_mat *isl_mat_set_element_si(__isl_take isl_mat *mat,
355 : int row, int col, int v)
356 : {
357 0 : mat = isl_mat_cow(mat);
358 0 : if (check_row(mat, row) < 0)
359 0 : return isl_mat_free(mat);
360 0 : if (check_col(mat, col) < 0)
361 0 : return isl_mat_free(mat);
362 0 : isl_int_set_si(mat->row[row][col], v);
363 0 : return mat;
364 : }
365 :
366 : /* Replace the element at row "row", column "col" of "mat" by "v".
367 : */
368 0 : __isl_give isl_mat *isl_mat_set_element_val(__isl_take isl_mat *mat,
369 : int row, int col, __isl_take isl_val *v)
370 : {
371 0 : if (!v)
372 0 : return isl_mat_free(mat);
373 0 : if (!isl_val_is_int(v))
374 0 : isl_die(isl_val_get_ctx(v), isl_error_invalid,
375 : "expecting integer value", goto error);
376 0 : mat = isl_mat_set_element(mat, row, col, v->n);
377 0 : isl_val_free(v);
378 0 : return mat;
379 : error:
380 0 : isl_val_free(v);
381 0 : return isl_mat_free(mat);
382 : }
383 :
384 4996134829 : __isl_give isl_mat *isl_mat_diag(isl_ctx *ctx, unsigned n_row, isl_int d)
385 : {
386 : int i;
387 : struct isl_mat *mat;
388 :
389 4996134829 : mat = isl_mat_alloc(ctx, n_row, n_row);
390 4996134829 : if (!mat)
391 0 : return NULL;
392 27008072447 : for (i = 0; i < n_row; ++i) {
393 22011937618 : isl_seq_clr(mat->row[i], i);
394 22011937618 : isl_int_set(mat->row[i][i], d);
395 22011937618 : isl_seq_clr(mat->row[i]+i+1, n_row-(i+1));
396 : }
397 :
398 4996134829 : return mat;
399 : }
400 :
401 : /* Create an "n_row" by "n_col" matrix with zero elements.
402 : */
403 0 : __isl_give isl_mat *isl_mat_zero(isl_ctx *ctx, unsigned n_row, unsigned n_col)
404 : {
405 : int i;
406 : isl_mat *mat;
407 :
408 0 : mat = isl_mat_alloc(ctx, n_row, n_col);
409 0 : if (!mat)
410 0 : return NULL;
411 0 : for (i = 0; i < n_row; ++i)
412 0 : isl_seq_clr(mat->row[i], n_col);
413 :
414 0 : return mat;
415 : }
416 :
417 4996134829 : __isl_give isl_mat *isl_mat_identity(isl_ctx *ctx, unsigned n_row)
418 : {
419 4996134829 : if (!ctx)
420 0 : return NULL;
421 4996134829 : return isl_mat_diag(ctx, n_row, ctx->one);
422 : }
423 :
424 : /* Is "mat" a (possibly scaled) identity matrix?
425 : */
426 0 : int isl_mat_is_scaled_identity(__isl_keep isl_mat *mat)
427 : {
428 : int i;
429 :
430 0 : if (!mat)
431 0 : return -1;
432 0 : if (mat->n_row != mat->n_col)
433 0 : return 0;
434 :
435 0 : for (i = 0; i < mat->n_row; ++i) {
436 0 : if (isl_seq_first_non_zero(mat->row[i], i) != -1)
437 0 : return 0;
438 0 : if (isl_int_ne(mat->row[0][0], mat->row[i][i]))
439 0 : return 0;
440 0 : if (isl_seq_first_non_zero(mat->row[i] + i + 1,
441 0 : mat->n_col - (i + 1)) != -1)
442 0 : return 0;
443 : }
444 :
445 0 : return 1;
446 : }
447 :
448 58067732 : __isl_give isl_vec *isl_mat_vec_product(__isl_take isl_mat *mat,
449 : __isl_take isl_vec *vec)
450 : {
451 : int i;
452 : struct isl_vec *prod;
453 :
454 58067732 : if (!mat || !vec)
455 : goto error;
456 :
457 58067732 : isl_assert(mat->ctx, mat->n_col == vec->size, goto error);
458 :
459 58067732 : prod = isl_vec_alloc(mat->ctx, mat->n_row);
460 58067732 : if (!prod)
461 0 : goto error;
462 :
463 420053347 : for (i = 0; i < prod->size; ++i)
464 723971230 : isl_seq_inner_product(mat->row[i], vec->el, vec->size,
465 723971230 : &prod->block.data[i]);
466 58067732 : isl_mat_free(mat);
467 58067732 : isl_vec_free(vec);
468 58067732 : return prod;
469 : error:
470 0 : isl_mat_free(mat);
471 0 : isl_vec_free(vec);
472 0 : return NULL;
473 : }
474 :
475 0 : __isl_give isl_vec *isl_mat_vec_inverse_product(__isl_take isl_mat *mat,
476 : __isl_take isl_vec *vec)
477 : {
478 : struct isl_mat *vec_mat;
479 : int i;
480 :
481 0 : if (!mat || !vec)
482 : goto error;
483 0 : vec_mat = isl_mat_alloc(vec->ctx, vec->size, 1);
484 0 : if (!vec_mat)
485 0 : goto error;
486 0 : for (i = 0; i < vec->size; ++i)
487 0 : isl_int_set(vec_mat->row[i][0], vec->el[i]);
488 0 : vec_mat = isl_mat_inverse_product(mat, vec_mat);
489 0 : isl_vec_free(vec);
490 0 : if (!vec_mat)
491 0 : return NULL;
492 0 : vec = isl_vec_alloc(vec_mat->ctx, vec_mat->n_row);
493 0 : if (vec)
494 0 : for (i = 0; i < vec->size; ++i)
495 0 : isl_int_set(vec->el[i], vec_mat->row[i][0]);
496 0 : isl_mat_free(vec_mat);
497 0 : return vec;
498 : error:
499 0 : isl_mat_free(mat);
500 0 : isl_vec_free(vec);
501 0 : return NULL;
502 : }
503 :
504 1127923 : __isl_give isl_vec *isl_vec_mat_product(__isl_take isl_vec *vec,
505 : __isl_take isl_mat *mat)
506 : {
507 : int i, j;
508 : struct isl_vec *prod;
509 :
510 1127923 : if (!mat || !vec)
511 : goto error;
512 :
513 1127923 : isl_assert(mat->ctx, mat->n_row == vec->size, goto error);
514 :
515 1127923 : prod = isl_vec_alloc(mat->ctx, mat->n_col);
516 1127923 : if (!prod)
517 0 : goto error;
518 :
519 8002439 : for (i = 0; i < prod->size; ++i) {
520 6874516 : isl_int_set_si(prod->el[i], 0);
521 51871004 : for (j = 0; j < vec->size; ++j)
522 44996488 : isl_int_addmul(prod->el[i], vec->el[j], mat->row[j][i]);
523 : }
524 1127923 : isl_mat_free(mat);
525 1127923 : isl_vec_free(vec);
526 1127923 : return prod;
527 : error:
528 0 : isl_mat_free(mat);
529 0 : isl_vec_free(vec);
530 0 : return NULL;
531 : }
532 :
533 310227621 : __isl_give isl_mat *isl_mat_aff_direct_sum(__isl_take isl_mat *left,
534 : __isl_take isl_mat *right)
535 : {
536 : int i;
537 : struct isl_mat *sum;
538 :
539 310227621 : if (!left || !right)
540 : goto error;
541 :
542 310227621 : isl_assert(left->ctx, left->n_row == right->n_row, goto error);
543 310227621 : isl_assert(left->ctx, left->n_row >= 1, goto error);
544 310227621 : isl_assert(left->ctx, left->n_col >= 1, goto error);
545 310227621 : isl_assert(left->ctx, right->n_col >= 1, goto error);
546 310227621 : isl_assert(left->ctx,
547 : isl_seq_first_non_zero(left->row[0]+1, left->n_col-1) == -1,
548 : goto error);
549 310227621 : isl_assert(left->ctx,
550 : isl_seq_first_non_zero(right->row[0]+1, right->n_col-1) == -1,
551 : goto error);
552 :
553 310227621 : sum = isl_mat_alloc(left->ctx, left->n_row, left->n_col + right->n_col - 1);
554 310227621 : if (!sum)
555 0 : goto error;
556 310227621 : isl_int_lcm(sum->row[0][0], left->row[0][0], right->row[0][0]);
557 310227621 : isl_int_divexact(left->row[0][0], sum->row[0][0], left->row[0][0]);
558 310227621 : isl_int_divexact(right->row[0][0], sum->row[0][0], right->row[0][0]);
559 :
560 310227621 : isl_seq_clr(sum->row[0]+1, sum->n_col-1);
561 1906741770 : for (i = 1; i < sum->n_row; ++i) {
562 1596514149 : isl_int_mul(sum->row[i][0], left->row[0][0], left->row[i][0]);
563 1596514149 : isl_int_addmul(sum->row[i][0],
564 : right->row[0][0], right->row[i][0]);
565 1596514149 : isl_seq_scale(sum->row[i]+1, left->row[i]+1, left->row[0][0],
566 1596514149 : left->n_col-1);
567 4789542447 : isl_seq_scale(sum->row[i]+left->n_col,
568 3193028298 : right->row[i]+1, right->row[0][0],
569 1596514149 : right->n_col-1);
570 : }
571 :
572 310227621 : isl_int_divexact(left->row[0][0], sum->row[0][0], left->row[0][0]);
573 310227621 : isl_int_divexact(right->row[0][0], sum->row[0][0], right->row[0][0]);
574 310227621 : isl_mat_free(left);
575 310227621 : isl_mat_free(right);
576 310227621 : return sum;
577 : error:
578 0 : isl_mat_free(left);
579 0 : isl_mat_free(right);
580 0 : return NULL;
581 : }
582 :
583 4015045232 : static void exchange(struct isl_mat *M, struct isl_mat **U,
584 : struct isl_mat **Q, unsigned row, unsigned i, unsigned j)
585 : {
586 : int r;
587 25558939627 : for (r = row; r < M->n_row; ++r)
588 21543894395 : isl_int_swap(M->row[r][i], M->row[r][j]);
589 4015045232 : if (U) {
590 23870263096 : for (r = 0; r < (*U)->n_row; ++r)
591 19855223998 : isl_int_swap((*U)->row[r][i], (*U)->row[r][j]);
592 : }
593 4015045232 : if (Q)
594 1955733468 : isl_mat_swap_rows(*Q, i, j);
595 4015045232 : }
596 :
597 8239614665 : static void subtract(struct isl_mat *M, struct isl_mat **U,
598 : struct isl_mat **Q, unsigned row, unsigned i, unsigned j, isl_int m)
599 : {
600 : int r;
601 64713973563 : for (r = row; r < M->n_row; ++r)
602 56474358898 : isl_int_submul(M->row[r][j], m, M->row[r][i]);
603 8239614665 : if (U) {
604 45632873049 : for (r = 0; r < (*U)->n_row; ++r)
605 37393272929 : isl_int_submul((*U)->row[r][j], m, (*U)->row[r][i]);
606 : }
607 8239614665 : if (Q) {
608 39844706779 : for (r = 0; r < (*Q)->n_col; ++r)
609 32503344674 : isl_int_addmul((*Q)->row[i][r], m, (*Q)->row[j][r]);
610 : }
611 8239614665 : }
612 :
613 2492079391 : static void oppose(struct isl_mat *M, struct isl_mat **U,
614 : struct isl_mat **Q, unsigned row, unsigned col)
615 : {
616 : int r;
617 19351507373 : for (r = row; r < M->n_row; ++r)
618 16859427982 : isl_int_neg(M->row[r][col], M->row[r][col]);
619 2492079391 : if (U) {
620 13181416616 : for (r = 0; r < (*U)->n_row; ++r)
621 10689343183 : isl_int_neg((*U)->row[r][col], (*U)->row[r][col]);
622 : }
623 2492079391 : if (Q)
624 2216361939 : isl_seq_neg((*Q)->row[col], (*Q)->row[col], (*Q)->n_col);
625 2492079391 : }
626 :
627 : /* Given matrix M, compute
628 : *
629 : * M U = H
630 : * M = H Q
631 : *
632 : * with U and Q unimodular matrices and H a matrix in column echelon form
633 : * such that on each echelon row the entries in the non-echelon column
634 : * are non-negative (if neg == 0) or non-positive (if neg == 1)
635 : * and strictly smaller (in absolute value) than the entries in the echelon
636 : * column.
637 : * If U or Q are NULL, then these matrices are not computed.
638 : */
639 2377312759 : __isl_give isl_mat *isl_mat_left_hermite(__isl_take isl_mat *M, int neg,
640 : __isl_give isl_mat **U, __isl_give isl_mat **Q)
641 : {
642 : isl_int c;
643 : int row, col;
644 :
645 2377312759 : if (U)
646 2377307804 : *U = NULL;
647 2377312759 : if (Q)
648 1309021027 : *Q = NULL;
649 2377312759 : if (!M)
650 0 : goto error;
651 2377312759 : M = isl_mat_cow(M);
652 2377312759 : if (!M)
653 0 : goto error;
654 2377312759 : if (U) {
655 2377307804 : *U = isl_mat_identity(M->ctx, M->n_col);
656 2377307804 : if (!*U)
657 0 : goto error;
658 : }
659 2377312759 : if (Q) {
660 1309021027 : *Q = isl_mat_identity(M->ctx, M->n_col);
661 1309021027 : if (!*Q)
662 0 : goto error;
663 : }
664 :
665 2377312759 : col = 0;
666 2377312759 : isl_int_init(c);
667 16126139546 : for (row = 0; row < M->n_row; ++row) {
668 : int first, i, off;
669 13748826787 : first = isl_seq_abs_min_non_zero(M->row[row]+col, M->n_col-col);
670 13748826787 : if (first == -1)
671 5771904528 : continue;
672 7976922259 : first += col;
673 7976922259 : if (first != col)
674 3911358537 : exchange(M, U, Q, row, first, col);
675 7976922259 : if (isl_int_is_neg(M->row[row][col]))
676 2491804499 : oppose(M, U, Q, row, col);
677 7976922259 : first = col+1;
678 19267416191 : while ((off = isl_seq_first_non_zero(M->row[row]+first,
679 11290493932 : M->n_col-first)) != -1) {
680 3313571673 : first += off;
681 3313571673 : isl_int_fdiv_q(c, M->row[row][first], M->row[row][col]);
682 3313571673 : subtract(M, U, Q, row, col, first, c);
683 3313571673 : if (!isl_int_is_zero(M->row[row][first]))
684 103338938 : exchange(M, U, Q, row, first, col);
685 : else
686 3210232735 : ++first;
687 : }
688 19745513660 : for (i = 0; i < col; ++i) {
689 11768591401 : if (isl_int_is_zero(M->row[row][i]))
690 6556298158 : continue;
691 5212293243 : if (neg)
692 0 : isl_int_cdiv_q(c, M->row[row][i], M->row[row][col]);
693 : else
694 5212293243 : isl_int_fdiv_q(c, M->row[row][i], M->row[row][col]);
695 5212293243 : if (isl_int_is_zero(c))
696 286860293 : continue;
697 4925432950 : subtract(M, U, Q, row, col, i, c);
698 : }
699 7976922259 : ++col;
700 : }
701 2377312759 : isl_int_clear(c);
702 :
703 2377312759 : return M;
704 : error:
705 0 : if (Q) {
706 0 : isl_mat_free(*Q);
707 0 : *Q = NULL;
708 : }
709 0 : if (U) {
710 0 : isl_mat_free(*U);
711 0 : *U = NULL;
712 : }
713 0 : isl_mat_free(M);
714 0 : return NULL;
715 : }
716 :
717 : /* Use row "row" of "mat" to eliminate column "col" from all other rows.
718 : */
719 0 : static __isl_give isl_mat *eliminate(__isl_take isl_mat *mat, int row, int col)
720 : {
721 : int k, nr, nc;
722 : isl_ctx *ctx;
723 :
724 0 : if (!mat)
725 0 : return NULL;
726 :
727 0 : ctx = isl_mat_get_ctx(mat);
728 0 : nr = isl_mat_rows(mat);
729 0 : nc = isl_mat_cols(mat);
730 :
731 0 : for (k = 0; k < nr; ++k) {
732 0 : if (k == row)
733 0 : continue;
734 0 : if (isl_int_is_zero(mat->row[k][col]))
735 0 : continue;
736 0 : mat = isl_mat_cow(mat);
737 0 : if (!mat)
738 0 : return NULL;
739 0 : isl_seq_elim(mat->row[k], mat->row[row], col, nc, NULL);
740 0 : isl_seq_normalize(ctx, mat->row[k], nc);
741 : }
742 :
743 0 : return mat;
744 : }
745 :
746 : /* Perform Gaussian elimination on the rows of "mat", but start
747 : * from the final row and the final column.
748 : * Any zero rows that result from the elimination are removed.
749 : *
750 : * In particular, for each column from last to first,
751 : * look for the last row with a non-zero coefficient in that column,
752 : * move it last (but before other rows moved last in previous steps) and
753 : * use it to eliminate the column from the other rows.
754 : */
755 0 : __isl_give isl_mat *isl_mat_reverse_gauss(__isl_take isl_mat *mat)
756 : {
757 : int k, row, last, nr, nc;
758 :
759 0 : if (!mat)
760 0 : return NULL;
761 :
762 0 : nr = isl_mat_rows(mat);
763 0 : nc = isl_mat_cols(mat);
764 :
765 0 : last = nc - 1;
766 0 : for (row = nr - 1; row >= 0; --row) {
767 0 : for (; last >= 0; --last) {
768 0 : for (k = row; k >= 0; --k)
769 0 : if (!isl_int_is_zero(mat->row[k][last]))
770 : break;
771 0 : if (k >= 0)
772 0 : break;
773 : }
774 0 : if (last < 0)
775 0 : break;
776 0 : if (k != row)
777 0 : mat = isl_mat_swap_rows(mat, k, row);
778 0 : if (!mat)
779 0 : return NULL;
780 0 : if (isl_int_is_neg(mat->row[row][last]))
781 0 : mat = isl_mat_row_neg(mat, row);
782 0 : mat = eliminate(mat, row, last);
783 0 : if (!mat)
784 0 : return NULL;
785 : }
786 0 : mat = isl_mat_drop_rows(mat, 0, row + 1);
787 :
788 0 : return mat;
789 : }
790 :
791 : /* Negate the lexicographically negative rows of "mat" such that
792 : * all rows in the result are lexicographically non-negative.
793 : */
794 0 : __isl_give isl_mat *isl_mat_lexnonneg_rows(__isl_take isl_mat *mat)
795 : {
796 : int i, nr, nc;
797 :
798 0 : if (!mat)
799 0 : return NULL;
800 :
801 0 : nr = isl_mat_rows(mat);
802 0 : nc = isl_mat_cols(mat);
803 :
804 0 : for (i = 0; i < nr; ++i) {
805 : int pos;
806 :
807 0 : pos = isl_seq_first_non_zero(mat->row[i], nc);
808 0 : if (pos < 0)
809 0 : continue;
810 0 : if (isl_int_is_nonneg(mat->row[i][pos]))
811 0 : continue;
812 0 : mat = isl_mat_row_neg(mat, i);
813 0 : if (!mat)
814 0 : return NULL;
815 : }
816 :
817 0 : return mat;
818 : }
819 :
820 : /* Given a matrix "H" is column echelon form, what is the first
821 : * zero column? That is how many initial columns are non-zero?
822 : * Start looking at column "first_col" and only consider
823 : * the columns to be of size "n_row".
824 : * "H" is assumed to be non-NULL.
825 : *
826 : * Since "H" is in column echelon form, the first non-zero entry
827 : * in a column is always in a later position compared to the previous column.
828 : */
829 0 : static int hermite_first_zero_col(__isl_keep isl_mat *H, int first_col,
830 : int n_row)
831 : {
832 : int row, col;
833 :
834 0 : for (col = first_col, row = 0; col < H->n_col; ++col) {
835 0 : for (; row < n_row; ++row)
836 0 : if (!isl_int_is_zero(H->row[row][col]))
837 : break;
838 0 : if (row == n_row)
839 0 : return col;
840 : }
841 :
842 0 : return H->n_col;
843 : }
844 :
845 : /* Return the rank of "mat", or -1 in case of error.
846 : */
847 0 : int isl_mat_rank(__isl_keep isl_mat *mat)
848 : {
849 : int rank;
850 : isl_mat *H;
851 :
852 0 : H = isl_mat_left_hermite(isl_mat_copy(mat), 0, NULL, NULL);
853 0 : if (!H)
854 0 : return -1;
855 :
856 0 : rank = hermite_first_zero_col(H, 0, H->n_row);
857 0 : isl_mat_free(H);
858 :
859 0 : return rank;
860 : }
861 :
862 0 : __isl_give isl_mat *isl_mat_right_kernel(__isl_take isl_mat *mat)
863 : {
864 : int rank;
865 0 : struct isl_mat *U = NULL;
866 : struct isl_mat *K;
867 :
868 0 : mat = isl_mat_left_hermite(mat, 0, &U, NULL);
869 0 : if (!mat || !U)
870 : goto error;
871 :
872 0 : rank = hermite_first_zero_col(mat, 0, mat->n_row);
873 0 : K = isl_mat_alloc(U->ctx, U->n_row, U->n_col - rank);
874 0 : if (!K)
875 0 : goto error;
876 0 : isl_mat_sub_copy(K->ctx, K->row, U->row, U->n_row, 0, rank, U->n_col-rank);
877 0 : isl_mat_free(mat);
878 0 : isl_mat_free(U);
879 0 : return K;
880 : error:
881 0 : isl_mat_free(mat);
882 0 : isl_mat_free(U);
883 0 : return NULL;
884 : }
885 :
886 1702352921 : __isl_give isl_mat *isl_mat_lin_to_aff(__isl_take isl_mat *mat)
887 : {
888 : int i;
889 : struct isl_mat *mat2;
890 :
891 1702352921 : if (!mat)
892 0 : return NULL;
893 1702352921 : mat2 = isl_mat_alloc(mat->ctx, 1+mat->n_row, 1+mat->n_col);
894 1702352921 : if (!mat2)
895 0 : goto error;
896 1702352921 : isl_int_set_si(mat2->row[0][0], 1);
897 1702352921 : isl_seq_clr(mat2->row[0]+1, mat->n_col);
898 9364146546 : for (i = 0; i < mat->n_row; ++i) {
899 7661793625 : isl_int_set_si(mat2->row[1+i][0], 0);
900 7661793625 : isl_seq_cpy(mat2->row[1+i]+1, mat->row[i], mat->n_col);
901 : }
902 1702352921 : isl_mat_free(mat);
903 1702352921 : return mat2;
904 : error:
905 0 : isl_mat_free(mat);
906 0 : return NULL;
907 : }
908 :
909 : /* Given two matrices M1 and M2, return the block matrix
910 : *
911 : * [ M1 0 ]
912 : * [ 0 M2 ]
913 : */
914 15218552 : __isl_give isl_mat *isl_mat_diagonal(__isl_take isl_mat *mat1,
915 : __isl_take isl_mat *mat2)
916 : {
917 : int i;
918 : isl_mat *mat;
919 :
920 15218552 : if (!mat1 || !mat2)
921 : goto error;
922 :
923 15218552 : mat = isl_mat_alloc(mat1->ctx, mat1->n_row + mat2->n_row,
924 15218552 : mat1->n_col + mat2->n_col);
925 15218552 : if (!mat)
926 0 : goto error;
927 30437104 : for (i = 0; i < mat1->n_row; ++i) {
928 15218552 : isl_seq_cpy(mat->row[i], mat1->row[i], mat1->n_col);
929 15218552 : isl_seq_clr(mat->row[i] + mat1->n_col, mat2->n_col);
930 : }
931 67943141 : for (i = 0; i < mat2->n_row; ++i) {
932 52724589 : isl_seq_clr(mat->row[mat1->n_row + i], mat1->n_col);
933 105449178 : isl_seq_cpy(mat->row[mat1->n_row + i] + mat1->n_col,
934 52724589 : mat2->row[i], mat2->n_col);
935 : }
936 15218552 : isl_mat_free(mat1);
937 15218552 : isl_mat_free(mat2);
938 15218552 : return mat;
939 : error:
940 0 : isl_mat_free(mat1);
941 0 : isl_mat_free(mat2);
942 0 : return NULL;
943 : }
944 :
945 1352004129 : static int row_first_non_zero(isl_int **row, unsigned n_row, unsigned col)
946 : {
947 : int i;
948 :
949 1770924884 : for (i = 0; i < n_row; ++i)
950 1096745435 : if (!isl_int_is_zero(row[i][col]))
951 677824680 : return i;
952 674179449 : return -1;
953 : }
954 :
955 674179449 : static int row_abs_min_non_zero(isl_int **row, unsigned n_row, unsigned col)
956 : {
957 674179449 : int i, min = row_first_non_zero(row, n_row, col);
958 674179449 : if (min < 0)
959 0 : return -1;
960 1096745435 : for (i = min + 1; i < n_row; ++i) {
961 422565986 : if (isl_int_is_zero(row[i][col]))
962 418920755 : continue;
963 3645231 : if (isl_int_abs_lt(row[i][col], row[min][col]))
964 190 : min = i;
965 : }
966 674179449 : return min;
967 : }
968 :
969 190 : static isl_stat inv_exchange(__isl_keep isl_mat **left,
970 : __isl_keep isl_mat **right, unsigned i, unsigned j)
971 : {
972 190 : *left = isl_mat_swap_rows(*left, i, j);
973 190 : *right = isl_mat_swap_rows(*right, i, j);
974 :
975 190 : if (!*left || !*right)
976 0 : return isl_stat_error;
977 190 : return isl_stat_ok;
978 : }
979 :
980 190 : static void inv_oppose(
981 : struct isl_mat *left, struct isl_mat *right, unsigned row)
982 : {
983 190 : isl_seq_neg(left->row[row]+row, left->row[row]+row, left->n_col-row);
984 190 : isl_seq_neg(right->row[row], right->row[row], right->n_col);
985 190 : }
986 :
987 3645231 : static void inv_subtract(struct isl_mat *left, struct isl_mat *right,
988 : unsigned row, unsigned i, isl_int m)
989 : {
990 3645231 : isl_int_neg(m, m);
991 21871386 : isl_seq_combine(left->row[i]+row,
992 10935693 : left->ctx->one, left->row[i]+row,
993 7290462 : m, left->row[row]+row,
994 3645231 : left->n_col-row);
995 7290462 : isl_seq_combine(right->row[i], right->ctx->one, right->row[i],
996 3645231 : m, right->row[row], right->n_col);
997 3645231 : }
998 :
999 : /* Compute inv(left)*right
1000 : */
1001 310371625 : __isl_give isl_mat *isl_mat_inverse_product(__isl_take isl_mat *left,
1002 : __isl_take isl_mat *right)
1003 : {
1004 : int row;
1005 : isl_int a, b;
1006 :
1007 310371625 : if (!left || !right)
1008 : goto error;
1009 :
1010 310371625 : isl_assert(left->ctx, left->n_row == left->n_col, goto error);
1011 310371625 : isl_assert(left->ctx, left->n_row == right->n_row, goto error);
1012 :
1013 310371625 : if (left->n_row == 0) {
1014 0 : isl_mat_free(left);
1015 0 : return right;
1016 : }
1017 :
1018 310371625 : left = isl_mat_cow(left);
1019 310371625 : right = isl_mat_cow(right);
1020 310371625 : if (!left || !right)
1021 : goto error;
1022 :
1023 310371625 : isl_int_init(a);
1024 310371625 : isl_int_init(b);
1025 984551074 : for (row = 0; row < left->n_row; ++row) {
1026 : int pivot, first, i, off;
1027 674179449 : pivot = row_abs_min_non_zero(left->row+row, left->n_row-row, row);
1028 674179449 : if (pivot < 0) {
1029 0 : isl_int_clear(a);
1030 0 : isl_int_clear(b);
1031 0 : isl_assert(left->ctx, pivot >= 0, goto error);
1032 : }
1033 674179449 : pivot += row;
1034 674179449 : if (pivot != row)
1035 190 : if (inv_exchange(&left, &right, pivot, row) < 0)
1036 0 : goto error;
1037 674179449 : if (isl_int_is_neg(left->row[row][row]))
1038 190 : inv_oppose(left, right, row);
1039 674179449 : first = row+1;
1040 2029828809 : while ((off = row_first_non_zero(left->row+first,
1041 677824680 : left->n_row-first, row)) != -1) {
1042 3645231 : first += off;
1043 3645231 : isl_int_fdiv_q(a, left->row[first][row],
1044 : left->row[row][row]);
1045 3645231 : inv_subtract(left, right, row, first, a);
1046 3645231 : if (!isl_int_is_zero(left->row[first][row])) {
1047 0 : if (inv_exchange(&left, &right, row, first) < 0)
1048 0 : goto error;
1049 : } else {
1050 3645231 : ++first;
1051 : }
1052 : }
1053 1096745435 : for (i = 0; i < row; ++i) {
1054 422565986 : if (isl_int_is_zero(left->row[i][row]))
1055 422565796 : continue;
1056 190 : isl_int_gcd(a, left->row[row][row], left->row[i][row]);
1057 190 : isl_int_divexact(b, left->row[i][row], a);
1058 190 : isl_int_divexact(a, left->row[row][row], a);
1059 190 : isl_int_neg(b, b);
1060 950 : isl_seq_combine(left->row[i] + i,
1061 380 : a, left->row[i] + i,
1062 380 : b, left->row[row] + i,
1063 190 : left->n_col - i);
1064 380 : isl_seq_combine(right->row[i], a, right->row[i],
1065 380 : b, right->row[row], right->n_col);
1066 : }
1067 : }
1068 310371625 : isl_int_clear(b);
1069 :
1070 310371625 : isl_int_set(a, left->row[0][0]);
1071 674179449 : for (row = 1; row < left->n_row; ++row)
1072 363807824 : isl_int_lcm(a, a, left->row[row][row]);
1073 310371625 : if (isl_int_is_zero(a)){
1074 0 : isl_int_clear(a);
1075 0 : isl_assert(left->ctx, 0, goto error);
1076 : }
1077 984551074 : for (row = 0; row < left->n_row; ++row) {
1078 674179449 : isl_int_divexact(left->row[row][row], a, left->row[row][row]);
1079 674179449 : if (isl_int_is_one(left->row[row][row]))
1080 666928618 : continue;
1081 21752493 : isl_seq_scale(right->row[row], right->row[row],
1082 21752493 : left->row[row][row], right->n_col);
1083 : }
1084 310371625 : isl_int_clear(a);
1085 :
1086 310371625 : isl_mat_free(left);
1087 310371625 : return right;
1088 : error:
1089 0 : isl_mat_free(left);
1090 0 : isl_mat_free(right);
1091 0 : return NULL;
1092 : }
1093 :
1094 254431 : void isl_mat_col_scale(struct isl_mat *mat, unsigned col, isl_int m)
1095 : {
1096 : int i;
1097 :
1098 1988906 : for (i = 0; i < mat->n_row; ++i)
1099 1734475 : isl_int_mul(mat->row[i][col], mat->row[i][col], m);
1100 254431 : }
1101 :
1102 665330 : void isl_mat_col_combine(struct isl_mat *mat, unsigned dst,
1103 : isl_int m1, unsigned src1, isl_int m2, unsigned src2)
1104 : {
1105 : int i;
1106 : isl_int tmp;
1107 :
1108 665330 : isl_int_init(tmp);
1109 3927404 : for (i = 0; i < mat->n_row; ++i) {
1110 3262074 : isl_int_mul(tmp, m1, mat->row[i][src1]);
1111 3262074 : isl_int_addmul(tmp, m2, mat->row[i][src2]);
1112 3262074 : isl_int_set(mat->row[i][dst], tmp);
1113 : }
1114 665330 : isl_int_clear(tmp);
1115 665330 : }
1116 :
1117 272491 : __isl_give isl_mat *isl_mat_right_inverse(__isl_take isl_mat *mat)
1118 : {
1119 : struct isl_mat *inv;
1120 : int row;
1121 : isl_int a, b;
1122 :
1123 272491 : mat = isl_mat_cow(mat);
1124 272491 : if (!mat)
1125 0 : return NULL;
1126 :
1127 272491 : inv = isl_mat_identity(mat->ctx, mat->n_col);
1128 272491 : inv = isl_mat_cow(inv);
1129 272491 : if (!inv)
1130 0 : goto error;
1131 :
1132 272491 : isl_int_init(a);
1133 272491 : isl_int_init(b);
1134 1089964 : for (row = 0; row < mat->n_row; ++row) {
1135 : int pivot, first, i, off;
1136 817473 : pivot = isl_seq_abs_min_non_zero(mat->row[row]+row, mat->n_col-row);
1137 817473 : if (pivot < 0) {
1138 0 : isl_int_clear(a);
1139 0 : isl_int_clear(b);
1140 0 : isl_assert(mat->ctx, pivot >= 0, goto error);
1141 : }
1142 817473 : pivot += row;
1143 817473 : if (pivot != row)
1144 337151 : exchange(mat, &inv, NULL, row, pivot, row);
1145 817473 : if (isl_int_is_neg(mat->row[row][row]))
1146 274892 : oppose(mat, &inv, NULL, row, row);
1147 817473 : first = row+1;
1148 2244988 : while ((off = isl_seq_first_non_zero(mat->row[row]+first,
1149 1427515 : mat->n_col-first)) != -1) {
1150 610042 : first += off;
1151 610042 : isl_int_fdiv_q(a, mat->row[row][first],
1152 : mat->row[row][row]);
1153 610042 : subtract(mat, &inv, NULL, row, row, first, a);
1154 610042 : if (!isl_int_is_zero(mat->row[row][first]))
1155 10606 : exchange(mat, &inv, NULL, row, row, first);
1156 : else
1157 599436 : ++first;
1158 : }
1159 1634946 : for (i = 0; i < row; ++i) {
1160 817473 : if (isl_int_is_zero(mat->row[row][i]))
1161 484808 : continue;
1162 332665 : isl_int_gcd(a, mat->row[row][row], mat->row[row][i]);
1163 332665 : isl_int_divexact(b, mat->row[row][i], a);
1164 332665 : isl_int_divexact(a, mat->row[row][row], a);
1165 332665 : isl_int_neg(a, a);
1166 332665 : isl_mat_col_combine(mat, i, a, i, b, row);
1167 332665 : isl_mat_col_combine(inv, i, a, i, b, row);
1168 : }
1169 : }
1170 272491 : isl_int_clear(b);
1171 :
1172 272491 : isl_int_set(a, mat->row[0][0]);
1173 817473 : for (row = 1; row < mat->n_row; ++row)
1174 544982 : isl_int_lcm(a, a, mat->row[row][row]);
1175 272491 : if (isl_int_is_zero(a)){
1176 0 : isl_int_clear(a);
1177 0 : goto error;
1178 : }
1179 1089964 : for (row = 0; row < mat->n_row; ++row) {
1180 817473 : isl_int_divexact(mat->row[row][row], a, mat->row[row][row]);
1181 817473 : if (isl_int_is_one(mat->row[row][row]))
1182 563042 : continue;
1183 254431 : isl_mat_col_scale(inv, row, mat->row[row][row]);
1184 : }
1185 272491 : isl_int_clear(a);
1186 :
1187 272491 : isl_mat_free(mat);
1188 :
1189 272491 : return inv;
1190 : error:
1191 0 : isl_mat_free(mat);
1192 0 : isl_mat_free(inv);
1193 0 : return NULL;
1194 : }
1195 :
1196 0 : __isl_give isl_mat *isl_mat_transpose(__isl_take isl_mat *mat)
1197 : {
1198 0 : struct isl_mat *transpose = NULL;
1199 : int i, j;
1200 :
1201 0 : if (!mat)
1202 0 : return NULL;
1203 :
1204 0 : if (mat->n_col == mat->n_row) {
1205 0 : mat = isl_mat_cow(mat);
1206 0 : if (!mat)
1207 0 : return NULL;
1208 0 : for (i = 0; i < mat->n_row; ++i)
1209 0 : for (j = i + 1; j < mat->n_col; ++j)
1210 0 : isl_int_swap(mat->row[i][j], mat->row[j][i]);
1211 0 : return mat;
1212 : }
1213 0 : transpose = isl_mat_alloc(mat->ctx, mat->n_col, mat->n_row);
1214 0 : if (!transpose)
1215 0 : goto error;
1216 0 : for (i = 0; i < mat->n_row; ++i)
1217 0 : for (j = 0; j < mat->n_col; ++j)
1218 0 : isl_int_set(transpose->row[j][i], mat->row[i][j]);
1219 0 : isl_mat_free(mat);
1220 0 : return transpose;
1221 : error:
1222 0 : isl_mat_free(mat);
1223 0 : return NULL;
1224 : }
1225 :
1226 3685597916 : __isl_give isl_mat *isl_mat_swap_cols(__isl_take isl_mat *mat,
1227 : unsigned i, unsigned j)
1228 : {
1229 : int r;
1230 :
1231 3685597916 : mat = isl_mat_cow(mat);
1232 7371195832 : if (check_col_range(mat, i, 1) < 0 ||
1233 3685597916 : check_col_range(mat, j, 1) < 0)
1234 0 : return isl_mat_free(mat);
1235 :
1236 62910564237 : for (r = 0; r < mat->n_row; ++r)
1237 59224966321 : isl_int_swap(mat->row[r][i], mat->row[r][j]);
1238 3685597916 : return mat;
1239 : }
1240 :
1241 25059837703 : __isl_give isl_mat *isl_mat_swap_rows(__isl_take isl_mat *mat,
1242 : unsigned i, unsigned j)
1243 : {
1244 : isl_int *t;
1245 :
1246 25059837703 : if (!mat)
1247 0 : return NULL;
1248 25059837703 : mat = isl_mat_cow(mat);
1249 50119675406 : if (check_row_range(mat, i, 1) < 0 ||
1250 25059837703 : check_row_range(mat, j, 1) < 0)
1251 0 : return isl_mat_free(mat);
1252 :
1253 25059837703 : t = mat->row[i];
1254 25059837703 : mat->row[i] = mat->row[j];
1255 25059837703 : mat->row[j] = t;
1256 25059837703 : return mat;
1257 : }
1258 :
1259 : /* Calculate the product of two matrices.
1260 : *
1261 : * This function is optimized for operand matrices that contain many zeros and
1262 : * skips multiplications where we know one of the operands is zero.
1263 : */
1264 3776563638 : __isl_give isl_mat *isl_mat_product(__isl_take isl_mat *left,
1265 : __isl_take isl_mat *right)
1266 : {
1267 : int i, j, k;
1268 : struct isl_mat *prod;
1269 :
1270 3776563638 : if (!left || !right)
1271 : goto error;
1272 3776563638 : isl_assert(left->ctx, left->n_col == right->n_row, goto error);
1273 3776563638 : prod = isl_mat_alloc(left->ctx, left->n_row, right->n_col);
1274 3776563638 : if (!prod)
1275 0 : goto error;
1276 3776563638 : if (left->n_col == 0) {
1277 0 : for (i = 0; i < prod->n_row; ++i)
1278 0 : isl_seq_clr(prod->row[i], prod->n_col);
1279 0 : isl_mat_free(left);
1280 0 : isl_mat_free(right);
1281 0 : return prod;
1282 : }
1283 15985807815 : for (i = 0; i < prod->n_row; ++i) {
1284 77639616309 : for (j = 0; j < prod->n_col; ++j)
1285 65430372132 : isl_int_mul(prod->row[i][j],
1286 : left->row[i][0], right->row[0][j]);
1287 70924234429 : for (k = 1; k < left->n_col; ++k) {
1288 58714990252 : if (isl_int_is_zero(left->row[i][k]))
1289 33709419860 : continue;
1290 >17956*10^7 : for (j = 0; j < prod->n_col; ++j)
1291 >15456*10^7 : isl_int_addmul(prod->row[i][j],
1292 : left->row[i][k], right->row[k][j]);
1293 : }
1294 : }
1295 3776563638 : isl_mat_free(left);
1296 3776563638 : isl_mat_free(right);
1297 3776563638 : return prod;
1298 : error:
1299 0 : isl_mat_free(left);
1300 0 : isl_mat_free(right);
1301 0 : return NULL;
1302 : }
1303 :
1304 : /* Replace the variables x in the rows q by x' given by x = M x',
1305 : * with M the matrix mat.
1306 : *
1307 : * If the number of new variables is greater than the original
1308 : * number of variables, then the rows q have already been
1309 : * preextended. If the new number is smaller, then the coefficients
1310 : * of the divs, which are not changed, need to be shifted down.
1311 : * The row q may be the equalities, the inequalities or the
1312 : * div expressions. In the latter case, has_div is true and
1313 : * we need to take into account the extra denominator column.
1314 : */
1315 3463781388 : static int preimage(struct isl_ctx *ctx, isl_int **q, unsigned n,
1316 : unsigned n_div, int has_div, struct isl_mat *mat)
1317 : {
1318 : int i;
1319 : struct isl_mat *t;
1320 : int e;
1321 :
1322 3463781388 : if (mat->n_col >= mat->n_row)
1323 2532456780 : e = 0;
1324 : else
1325 931324608 : e = mat->n_row - mat->n_col;
1326 3463781388 : if (has_div)
1327 1154593796 : for (i = 0; i < n; ++i)
1328 0 : isl_int_mul(q[i][0], q[i][0], mat->row[0][0]);
1329 3463781388 : t = isl_mat_sub_alloc6(mat->ctx, q, 0, n, has_div, mat->n_row);
1330 3463781388 : t = isl_mat_product(t, mat);
1331 3463781388 : if (!t)
1332 0 : return -1;
1333 13760162951 : for (i = 0; i < n; ++i) {
1334 10296381563 : isl_seq_swp_or_cpy(q[i] + has_div, t->row[i], t->n_col);
1335 10296381563 : isl_seq_cpy(q[i] + has_div + t->n_col,
1336 10296381563 : q[i] + has_div + t->n_col + e, n_div);
1337 10296381563 : isl_seq_clr(q[i] + has_div + t->n_col + n_div, e);
1338 : }
1339 3463781388 : isl_mat_free(t);
1340 3463781388 : return 0;
1341 : }
1342 :
1343 : /* Replace the variables x in bset by x' given by x = M x', with
1344 : * M the matrix mat.
1345 : *
1346 : * If there are fewer variables x' then there are x, then we perform
1347 : * the transformation in place, which means that, in principle,
1348 : * this frees up some extra variables as the number
1349 : * of columns remains constant, but we would have to extend
1350 : * the div array too as the number of rows in this array is assumed
1351 : * to be equal to extra.
1352 : */
1353 1154593796 : __isl_give isl_basic_set *isl_basic_set_preimage(
1354 : __isl_take isl_basic_set *bset, __isl_take isl_mat *mat)
1355 : {
1356 : struct isl_ctx *ctx;
1357 :
1358 1154593796 : if (!bset || !mat)
1359 : goto error;
1360 :
1361 1154593796 : ctx = bset->ctx;
1362 1154593796 : bset = isl_basic_set_cow(bset);
1363 1154593796 : if (!bset)
1364 0 : goto error;
1365 :
1366 1154593796 : isl_assert(ctx, bset->dim->nparam == 0, goto error);
1367 1154593796 : isl_assert(ctx, 1+bset->dim->n_out == mat->n_row, goto error);
1368 1154593796 : isl_assert(ctx, mat->n_col > 0, goto error);
1369 :
1370 1154593796 : if (mat->n_col > mat->n_row) {
1371 13487183 : bset = isl_basic_set_extend(bset, 0, mat->n_col-1, 0, 0, 0);
1372 13487183 : if (!bset)
1373 0 : goto error;
1374 1141106613 : } else if (mat->n_col < mat->n_row) {
1375 310441536 : bset->dim = isl_space_cow(bset->dim);
1376 310441536 : if (!bset->dim)
1377 0 : goto error;
1378 310441536 : bset->dim->n_out -= mat->n_row - mat->n_col;
1379 : }
1380 :
1381 1154593796 : if (preimage(ctx, bset->eq, bset->n_eq, bset->n_div, 0,
1382 1154593796 : isl_mat_copy(mat)) < 0)
1383 0 : goto error;
1384 :
1385 1154593796 : if (preimage(ctx, bset->ineq, bset->n_ineq, bset->n_div, 0,
1386 1154593796 : isl_mat_copy(mat)) < 0)
1387 0 : goto error;
1388 :
1389 1154593796 : if (preimage(ctx, bset->div, bset->n_div, bset->n_div, 1, mat) < 0)
1390 0 : goto error2;
1391 :
1392 1154593796 : ISL_F_CLR(bset, ISL_BASIC_SET_NO_IMPLICIT);
1393 1154593796 : ISL_F_CLR(bset, ISL_BASIC_SET_NO_REDUNDANT);
1394 1154593796 : ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED);
1395 1154593796 : ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED_DIVS);
1396 1154593796 : ISL_F_CLR(bset, ISL_BASIC_SET_ALL_EQUALITIES);
1397 :
1398 1154593796 : bset = isl_basic_set_simplify(bset);
1399 1154593796 : bset = isl_basic_set_finalize(bset);
1400 :
1401 1154593796 : return bset;
1402 : error:
1403 0 : isl_mat_free(mat);
1404 : error2:
1405 0 : isl_basic_set_free(bset);
1406 0 : return NULL;
1407 : }
1408 :
1409 272491 : __isl_give isl_set *isl_set_preimage(
1410 : __isl_take isl_set *set, __isl_take isl_mat *mat)
1411 : {
1412 : int i;
1413 :
1414 272491 : set = isl_set_cow(set);
1415 272491 : if (!set)
1416 0 : goto error;
1417 :
1418 544982 : for (i = 0; i < set->n; ++i) {
1419 272491 : set->p[i] = isl_basic_set_preimage(set->p[i],
1420 : isl_mat_copy(mat));
1421 272491 : if (!set->p[i])
1422 0 : goto error;
1423 : }
1424 272491 : if (mat->n_col != mat->n_row) {
1425 0 : set->dim = isl_space_cow(set->dim);
1426 0 : if (!set->dim)
1427 0 : goto error;
1428 0 : set->dim->n_out += mat->n_col;
1429 0 : set->dim->n_out -= mat->n_row;
1430 : }
1431 272491 : isl_mat_free(mat);
1432 272491 : ISL_F_CLR(set, ISL_SET_NORMALIZED);
1433 272491 : return set;
1434 : error:
1435 0 : isl_set_free(set);
1436 0 : isl_mat_free(mat);
1437 0 : return NULL;
1438 : }
1439 :
1440 : /* Replace the variables x starting at "first_col" in the rows "rows"
1441 : * of some coefficient matrix by x' with x = M x' with M the matrix mat.
1442 : * That is, replace the corresponding coefficients c by c M.
1443 : */
1444 0 : isl_stat isl_mat_sub_transform(isl_int **row, unsigned n_row,
1445 : unsigned first_col, __isl_take isl_mat *mat)
1446 : {
1447 : int i;
1448 : isl_ctx *ctx;
1449 : isl_mat *t;
1450 :
1451 0 : if (!mat)
1452 0 : return isl_stat_error;
1453 0 : ctx = isl_mat_get_ctx(mat);
1454 0 : t = isl_mat_sub_alloc6(ctx, row, 0, n_row, first_col, mat->n_row);
1455 0 : t = isl_mat_product(t, mat);
1456 0 : if (!t)
1457 0 : return isl_stat_error;
1458 0 : for (i = 0; i < n_row; ++i)
1459 0 : isl_seq_swp_or_cpy(row[i] + first_col, t->row[i], t->n_col);
1460 0 : isl_mat_free(t);
1461 0 : return isl_stat_ok;
1462 : }
1463 :
1464 0 : void isl_mat_print_internal(__isl_keep isl_mat *mat, FILE *out, int indent)
1465 : {
1466 : int i, j;
1467 :
1468 0 : if (!mat) {
1469 0 : fprintf(out, "%*snull mat\n", indent, "");
1470 0 : return;
1471 : }
1472 :
1473 0 : if (mat->n_row == 0)
1474 0 : fprintf(out, "%*s[]\n", indent, "");
1475 :
1476 0 : for (i = 0; i < mat->n_row; ++i) {
1477 0 : if (!i)
1478 0 : fprintf(out, "%*s[[", indent, "");
1479 : else
1480 0 : fprintf(out, "%*s[", indent+1, "");
1481 0 : for (j = 0; j < mat->n_col; ++j) {
1482 0 : if (j)
1483 0 : fprintf(out, ",");
1484 0 : isl_int_print(out, mat->row[i][j], 0);
1485 : }
1486 0 : if (i == mat->n_row-1)
1487 0 : fprintf(out, "]]\n");
1488 : else
1489 0 : fprintf(out, "]\n");
1490 : }
1491 : }
1492 :
1493 0 : void isl_mat_dump(__isl_keep isl_mat *mat)
1494 : {
1495 0 : isl_mat_print_internal(mat, stderr, 0);
1496 0 : }
1497 :
1498 42763 : __isl_give isl_mat *isl_mat_drop_cols(__isl_take isl_mat *mat,
1499 : unsigned col, unsigned n)
1500 : {
1501 : int r;
1502 :
1503 42763 : if (n == 0)
1504 0 : return mat;
1505 :
1506 42763 : mat = isl_mat_cow(mat);
1507 42763 : if (check_col_range(mat, col, n) < 0)
1508 0 : return isl_mat_free(mat);
1509 :
1510 42763 : if (col != mat->n_col-n) {
1511 0 : for (r = 0; r < mat->n_row; ++r)
1512 0 : isl_seq_cpy(mat->row[r]+col, mat->row[r]+col+n,
1513 0 : mat->n_col - col - n);
1514 : }
1515 42763 : mat->n_col -= n;
1516 42763 : return mat;
1517 : }
1518 :
1519 13558229 : __isl_give isl_mat *isl_mat_drop_rows(__isl_take isl_mat *mat,
1520 : unsigned row, unsigned n)
1521 : {
1522 : int r;
1523 :
1524 13558229 : mat = isl_mat_cow(mat);
1525 13558229 : if (check_row_range(mat, row, n) < 0)
1526 0 : return isl_mat_free(mat);
1527 :
1528 58645722 : for (r = row; r+n < mat->n_row; ++r)
1529 45087493 : mat->row[r] = mat->row[r+n];
1530 :
1531 13558229 : mat->n_row -= n;
1532 13558229 : return mat;
1533 : }
1534 :
1535 0 : __isl_give isl_mat *isl_mat_insert_cols(__isl_take isl_mat *mat,
1536 : unsigned col, unsigned n)
1537 : {
1538 : isl_mat *ext;
1539 :
1540 0 : if (check_col_range(mat, col, 0) < 0)
1541 0 : return isl_mat_free(mat);
1542 0 : if (n == 0)
1543 0 : return mat;
1544 :
1545 0 : ext = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col + n);
1546 0 : if (!ext)
1547 0 : goto error;
1548 :
1549 0 : isl_mat_sub_copy(mat->ctx, ext->row, mat->row, mat->n_row, 0, 0, col);
1550 0 : isl_mat_sub_copy(mat->ctx, ext->row, mat->row, mat->n_row,
1551 0 : col + n, col, mat->n_col - col);
1552 :
1553 0 : isl_mat_free(mat);
1554 0 : return ext;
1555 : error:
1556 0 : isl_mat_free(mat);
1557 0 : return NULL;
1558 : }
1559 :
1560 0 : __isl_give isl_mat *isl_mat_insert_zero_cols(__isl_take isl_mat *mat,
1561 : unsigned first, unsigned n)
1562 : {
1563 : int i;
1564 :
1565 0 : if (!mat)
1566 0 : return NULL;
1567 0 : mat = isl_mat_insert_cols(mat, first, n);
1568 0 : if (!mat)
1569 0 : return NULL;
1570 :
1571 0 : for (i = 0; i < mat->n_row; ++i)
1572 0 : isl_seq_clr(mat->row[i] + first, n);
1573 :
1574 0 : return mat;
1575 : }
1576 :
1577 0 : __isl_give isl_mat *isl_mat_add_zero_cols(__isl_take isl_mat *mat, unsigned n)
1578 : {
1579 0 : if (!mat)
1580 0 : return NULL;
1581 :
1582 0 : return isl_mat_insert_zero_cols(mat, mat->n_col, n);
1583 : }
1584 :
1585 0 : __isl_give isl_mat *isl_mat_insert_rows(__isl_take isl_mat *mat,
1586 : unsigned row, unsigned n)
1587 : {
1588 : isl_mat *ext;
1589 :
1590 0 : if (check_row_range(mat, row, 0) < 0)
1591 0 : return isl_mat_free(mat);
1592 0 : if (n == 0)
1593 0 : return mat;
1594 :
1595 0 : ext = isl_mat_alloc(mat->ctx, mat->n_row + n, mat->n_col);
1596 0 : if (!ext)
1597 0 : goto error;
1598 :
1599 0 : isl_mat_sub_copy(mat->ctx, ext->row, mat->row, row, 0, 0, mat->n_col);
1600 0 : isl_mat_sub_copy(mat->ctx, ext->row + row + n, mat->row + row,
1601 0 : mat->n_row - row, 0, 0, mat->n_col);
1602 :
1603 0 : isl_mat_free(mat);
1604 0 : return ext;
1605 : error:
1606 0 : isl_mat_free(mat);
1607 0 : return NULL;
1608 : }
1609 :
1610 0 : __isl_give isl_mat *isl_mat_add_rows(__isl_take isl_mat *mat, unsigned n)
1611 : {
1612 0 : if (!mat)
1613 0 : return NULL;
1614 :
1615 0 : return isl_mat_insert_rows(mat, mat->n_row, n);
1616 : }
1617 :
1618 0 : __isl_give isl_mat *isl_mat_insert_zero_rows(__isl_take isl_mat *mat,
1619 : unsigned row, unsigned n)
1620 : {
1621 : int i;
1622 :
1623 0 : mat = isl_mat_insert_rows(mat, row, n);
1624 0 : if (!mat)
1625 0 : return NULL;
1626 :
1627 0 : for (i = 0; i < n; ++i)
1628 0 : isl_seq_clr(mat->row[row + i], mat->n_col);
1629 :
1630 0 : return mat;
1631 : }
1632 :
1633 0 : __isl_give isl_mat *isl_mat_add_zero_rows(__isl_take isl_mat *mat, unsigned n)
1634 : {
1635 0 : if (!mat)
1636 0 : return NULL;
1637 :
1638 0 : return isl_mat_insert_zero_rows(mat, mat->n_row, n);
1639 : }
1640 :
1641 0 : void isl_mat_col_submul(struct isl_mat *mat,
1642 : int dst_col, isl_int f, int src_col)
1643 : {
1644 : int i;
1645 :
1646 0 : for (i = 0; i < mat->n_row; ++i)
1647 0 : isl_int_submul(mat->row[i][dst_col], f, mat->row[i][src_col]);
1648 0 : }
1649 :
1650 0 : void isl_mat_col_add(__isl_keep isl_mat *mat, int dst_col, int src_col)
1651 : {
1652 : int i;
1653 :
1654 0 : if (!mat)
1655 0 : return;
1656 :
1657 0 : for (i = 0; i < mat->n_row; ++i)
1658 0 : isl_int_add(mat->row[i][dst_col],
1659 : mat->row[i][dst_col], mat->row[i][src_col]);
1660 : }
1661 :
1662 0 : void isl_mat_col_mul(struct isl_mat *mat, int dst_col, isl_int f, int src_col)
1663 : {
1664 : int i;
1665 :
1666 0 : for (i = 0; i < mat->n_row; ++i)
1667 0 : isl_int_mul(mat->row[i][dst_col], f, mat->row[i][src_col]);
1668 0 : }
1669 :
1670 : /* Add "f" times column "src_col" to column "dst_col" of "mat" and
1671 : * return the result.
1672 : */
1673 0 : __isl_give isl_mat *isl_mat_col_addmul(__isl_take isl_mat *mat, int dst_col,
1674 : isl_int f, int src_col)
1675 : {
1676 : int i;
1677 :
1678 0 : if (check_col(mat, dst_col) < 0 || check_col(mat, src_col) < 0)
1679 0 : return isl_mat_free(mat);
1680 :
1681 0 : for (i = 0; i < mat->n_row; ++i) {
1682 0 : if (isl_int_is_zero(mat->row[i][src_col]))
1683 0 : continue;
1684 0 : mat = isl_mat_cow(mat);
1685 0 : if (!mat)
1686 0 : return NULL;
1687 0 : isl_int_addmul(mat->row[i][dst_col], f, mat->row[i][src_col]);
1688 : }
1689 :
1690 0 : return mat;
1691 : }
1692 :
1693 : /* Negate column "col" of "mat" and return the result.
1694 : */
1695 0 : __isl_give isl_mat *isl_mat_col_neg(__isl_take isl_mat *mat, int col)
1696 : {
1697 : int i;
1698 :
1699 0 : if (check_col(mat, col) < 0)
1700 0 : return isl_mat_free(mat);
1701 :
1702 0 : for (i = 0; i < mat->n_row; ++i) {
1703 0 : if (isl_int_is_zero(mat->row[i][col]))
1704 0 : continue;
1705 0 : mat = isl_mat_cow(mat);
1706 0 : if (!mat)
1707 0 : return NULL;
1708 0 : isl_int_neg(mat->row[i][col], mat->row[i][col]);
1709 : }
1710 :
1711 0 : return mat;
1712 : }
1713 :
1714 : /* Negate row "row" of "mat" and return the result.
1715 : */
1716 0 : __isl_give isl_mat *isl_mat_row_neg(__isl_take isl_mat *mat, int row)
1717 : {
1718 0 : if (check_row(mat, row) < 0)
1719 0 : return isl_mat_free(mat);
1720 0 : if (isl_seq_first_non_zero(mat->row[row], mat->n_col) == -1)
1721 0 : return mat;
1722 0 : mat = isl_mat_cow(mat);
1723 0 : if (!mat)
1724 0 : return NULL;
1725 0 : isl_seq_neg(mat->row[row], mat->row[row], mat->n_col);
1726 0 : return mat;
1727 : }
1728 :
1729 0 : __isl_give isl_mat *isl_mat_unimodular_complete(__isl_take isl_mat *M, int row)
1730 : {
1731 : int r;
1732 0 : struct isl_mat *H = NULL, *Q = NULL;
1733 :
1734 0 : if (!M)
1735 0 : return NULL;
1736 :
1737 0 : isl_assert(M->ctx, M->n_row == M->n_col, goto error);
1738 0 : M->n_row = row;
1739 0 : H = isl_mat_left_hermite(isl_mat_copy(M), 0, NULL, &Q);
1740 0 : M->n_row = M->n_col;
1741 0 : if (!H)
1742 0 : goto error;
1743 0 : for (r = 0; r < row; ++r)
1744 0 : isl_assert(M->ctx, isl_int_is_one(H->row[r][r]), goto error);
1745 0 : for (r = row; r < M->n_row; ++r)
1746 0 : isl_seq_cpy(M->row[r], Q->row[r], M->n_col);
1747 0 : isl_mat_free(H);
1748 0 : isl_mat_free(Q);
1749 0 : return M;
1750 : error:
1751 0 : isl_mat_free(H);
1752 0 : isl_mat_free(Q);
1753 0 : isl_mat_free(M);
1754 0 : return NULL;
1755 : }
1756 :
1757 0 : __isl_give isl_mat *isl_mat_concat(__isl_take isl_mat *top,
1758 : __isl_take isl_mat *bot)
1759 : {
1760 : struct isl_mat *mat;
1761 :
1762 0 : if (!top || !bot)
1763 : goto error;
1764 :
1765 0 : isl_assert(top->ctx, top->n_col == bot->n_col, goto error);
1766 0 : if (top->n_row == 0) {
1767 0 : isl_mat_free(top);
1768 0 : return bot;
1769 : }
1770 0 : if (bot->n_row == 0) {
1771 0 : isl_mat_free(bot);
1772 0 : return top;
1773 : }
1774 :
1775 0 : mat = isl_mat_alloc(top->ctx, top->n_row + bot->n_row, top->n_col);
1776 0 : if (!mat)
1777 0 : goto error;
1778 0 : isl_mat_sub_copy(mat->ctx, mat->row, top->row, top->n_row,
1779 : 0, 0, mat->n_col);
1780 0 : isl_mat_sub_copy(mat->ctx, mat->row + top->n_row, bot->row, bot->n_row,
1781 : 0, 0, mat->n_col);
1782 0 : isl_mat_free(top);
1783 0 : isl_mat_free(bot);
1784 0 : return mat;
1785 : error:
1786 0 : isl_mat_free(top);
1787 0 : isl_mat_free(bot);
1788 0 : return NULL;
1789 : }
1790 :
1791 0 : isl_bool isl_mat_is_equal(__isl_keep isl_mat *mat1, __isl_keep isl_mat *mat2)
1792 : {
1793 : int i;
1794 :
1795 0 : if (!mat1 || !mat2)
1796 0 : return isl_bool_error;
1797 :
1798 0 : if (mat1->n_row != mat2->n_row)
1799 0 : return isl_bool_false;
1800 :
1801 0 : if (mat1->n_col != mat2->n_col)
1802 0 : return isl_bool_false;
1803 :
1804 0 : for (i = 0; i < mat1->n_row; ++i)
1805 0 : if (!isl_seq_eq(mat1->row[i], mat2->row[i], mat1->n_col))
1806 0 : return isl_bool_false;
1807 :
1808 0 : return isl_bool_true;
1809 : }
1810 :
1811 0 : __isl_give isl_mat *isl_mat_from_row_vec(__isl_take isl_vec *vec)
1812 : {
1813 : struct isl_mat *mat;
1814 :
1815 0 : if (!vec)
1816 0 : return NULL;
1817 0 : mat = isl_mat_alloc(vec->ctx, 1, vec->size);
1818 0 : if (!mat)
1819 0 : goto error;
1820 :
1821 0 : isl_seq_cpy(mat->row[0], vec->el, vec->size);
1822 :
1823 0 : isl_vec_free(vec);
1824 0 : return mat;
1825 : error:
1826 0 : isl_vec_free(vec);
1827 0 : return NULL;
1828 : }
1829 :
1830 : /* Return a copy of row "row" of "mat" as an isl_vec.
1831 : */
1832 0 : __isl_give isl_vec *isl_mat_get_row(__isl_keep isl_mat *mat, unsigned row)
1833 : {
1834 : isl_vec *v;
1835 :
1836 0 : if (!mat)
1837 0 : return NULL;
1838 0 : if (row >= mat->n_row)
1839 0 : isl_die(mat->ctx, isl_error_invalid, "row out of range",
1840 : return NULL);
1841 :
1842 0 : v = isl_vec_alloc(isl_mat_get_ctx(mat), mat->n_col);
1843 0 : if (!v)
1844 0 : return NULL;
1845 0 : isl_seq_cpy(v->el, mat->row[row], mat->n_col);
1846 :
1847 0 : return v;
1848 : }
1849 :
1850 0 : __isl_give isl_mat *isl_mat_vec_concat(__isl_take isl_mat *top,
1851 : __isl_take isl_vec *bot)
1852 : {
1853 0 : return isl_mat_concat(top, isl_mat_from_row_vec(bot));
1854 : }
1855 :
1856 0 : __isl_give isl_mat *isl_mat_move_cols(__isl_take isl_mat *mat,
1857 : unsigned dst_col, unsigned src_col, unsigned n)
1858 : {
1859 : isl_mat *res;
1860 :
1861 0 : if (!mat)
1862 0 : return NULL;
1863 0 : if (n == 0 || dst_col == src_col)
1864 0 : return mat;
1865 :
1866 0 : res = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col);
1867 0 : if (!res)
1868 0 : goto error;
1869 :
1870 0 : if (dst_col < src_col) {
1871 0 : isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
1872 : 0, 0, dst_col);
1873 0 : isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
1874 : dst_col, src_col, n);
1875 0 : isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
1876 : dst_col + n, dst_col, src_col - dst_col);
1877 0 : isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
1878 : src_col + n, src_col + n,
1879 0 : res->n_col - src_col - n);
1880 : } else {
1881 0 : isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
1882 : 0, 0, src_col);
1883 0 : isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
1884 : src_col, src_col + n, dst_col - src_col);
1885 0 : isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
1886 : dst_col, src_col, n);
1887 0 : isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
1888 : dst_col + n, dst_col + n,
1889 0 : res->n_col - dst_col - n);
1890 : }
1891 0 : isl_mat_free(mat);
1892 :
1893 0 : return res;
1894 : error:
1895 0 : isl_mat_free(mat);
1896 0 : return NULL;
1897 : }
1898 :
1899 : /* Return the gcd of the elements in row "row" of "mat" in *gcd.
1900 : * Return isl_stat_ok on success and isl_stat_error on failure.
1901 : */
1902 0 : isl_stat isl_mat_row_gcd(__isl_keep isl_mat *mat, int row, isl_int *gcd)
1903 : {
1904 0 : if (check_row(mat, row) < 0)
1905 0 : return isl_stat_error;
1906 :
1907 0 : isl_seq_gcd(mat->row[row], mat->n_col, gcd);
1908 :
1909 0 : return isl_stat_ok;
1910 : }
1911 :
1912 3317656 : void isl_mat_gcd(__isl_keep isl_mat *mat, isl_int *gcd)
1913 : {
1914 : int i;
1915 : isl_int g;
1916 :
1917 3317656 : isl_int_set_si(*gcd, 0);
1918 3317656 : if (!mat)
1919 0 : return;
1920 :
1921 3317656 : isl_int_init(g);
1922 13726722 : for (i = 0; i < mat->n_row; ++i) {
1923 10409066 : isl_seq_gcd(mat->row[i], mat->n_col, &g);
1924 10409066 : isl_int_gcd(*gcd, *gcd, g);
1925 : }
1926 3317656 : isl_int_clear(g);
1927 : }
1928 :
1929 : /* Return the result of scaling "mat" by a factor of "m".
1930 : */
1931 0 : __isl_give isl_mat *isl_mat_scale(__isl_take isl_mat *mat, isl_int m)
1932 : {
1933 : int i;
1934 :
1935 0 : if (isl_int_is_one(m))
1936 0 : return mat;
1937 :
1938 0 : mat = isl_mat_cow(mat);
1939 0 : if (!mat)
1940 0 : return NULL;
1941 :
1942 0 : for (i = 0; i < mat->n_row; ++i)
1943 0 : isl_seq_scale(mat->row[i], mat->row[i], m, mat->n_col);
1944 :
1945 0 : return mat;
1946 : }
1947 :
1948 3317656 : __isl_give isl_mat *isl_mat_scale_down(__isl_take isl_mat *mat, isl_int m)
1949 : {
1950 : int i;
1951 :
1952 3317656 : if (isl_int_is_one(m))
1953 0 : return mat;
1954 :
1955 3317656 : mat = isl_mat_cow(mat);
1956 3317656 : if (!mat)
1957 0 : return NULL;
1958 :
1959 13726722 : for (i = 0; i < mat->n_row; ++i)
1960 10409066 : isl_seq_scale_down(mat->row[i], mat->row[i], m, mat->n_col);
1961 :
1962 3317656 : return mat;
1963 : }
1964 :
1965 0 : __isl_give isl_mat *isl_mat_scale_down_row(__isl_take isl_mat *mat, int row,
1966 : isl_int m)
1967 : {
1968 0 : if (isl_int_is_one(m))
1969 0 : return mat;
1970 :
1971 0 : mat = isl_mat_cow(mat);
1972 0 : if (!mat)
1973 0 : return NULL;
1974 :
1975 0 : isl_seq_scale_down(mat->row[row], mat->row[row], m, mat->n_col);
1976 :
1977 0 : return mat;
1978 : }
1979 :
1980 3317656 : __isl_give isl_mat *isl_mat_normalize(__isl_take isl_mat *mat)
1981 : {
1982 : isl_int gcd;
1983 :
1984 3317656 : if (!mat)
1985 0 : return NULL;
1986 :
1987 3317656 : isl_int_init(gcd);
1988 3317656 : isl_mat_gcd(mat, &gcd);
1989 3317656 : mat = isl_mat_scale_down(mat, gcd);
1990 3317656 : isl_int_clear(gcd);
1991 :
1992 3317656 : return mat;
1993 : }
1994 :
1995 0 : __isl_give isl_mat *isl_mat_normalize_row(__isl_take isl_mat *mat, int row)
1996 : {
1997 0 : mat = isl_mat_cow(mat);
1998 0 : if (!mat)
1999 0 : return NULL;
2000 :
2001 0 : isl_seq_normalize(mat->ctx, mat->row[row], mat->n_col);
2002 :
2003 0 : return mat;
2004 : }
2005 :
2006 : /* Number of initial non-zero columns.
2007 : */
2008 0 : int isl_mat_initial_non_zero_cols(__isl_keep isl_mat *mat)
2009 : {
2010 : int i;
2011 :
2012 0 : if (!mat)
2013 0 : return -1;
2014 :
2015 0 : for (i = 0; i < mat->n_col; ++i)
2016 0 : if (row_first_non_zero(mat->row, mat->n_row, i) < 0)
2017 0 : break;
2018 :
2019 0 : return i;
2020 : }
2021 :
2022 : /* Return a basis for the space spanned by the rows of "mat".
2023 : * Any basis will do, so simply perform Gaussian elimination and
2024 : * remove the empty rows.
2025 : */
2026 0 : __isl_give isl_mat *isl_mat_row_basis(__isl_take isl_mat *mat)
2027 : {
2028 0 : return isl_mat_reverse_gauss(mat);
2029 : }
2030 :
2031 : /* Return rows that extend a basis of "mat1" to one
2032 : * that covers both "mat1" and "mat2".
2033 : * The Hermite normal form of the concatenation of the two matrices is
2034 : *
2035 : * [ Q1 ]
2036 : * [ M1 ] = [ H1 0 0 ] [ Q2 ]
2037 : * [ M2 ] = [ H2 H3 0 ] [ Q3 ]
2038 : *
2039 : * The number of columns in H1 and H3 determine the number of rows
2040 : * in Q1 and Q2. Q1 is a basis for M1, while Q2 extends this basis
2041 : * to also cover M2.
2042 : */
2043 0 : __isl_give isl_mat *isl_mat_row_basis_extension(
2044 : __isl_take isl_mat *mat1, __isl_take isl_mat *mat2)
2045 : {
2046 : int n_row;
2047 : int r1, r, n1;
2048 : isl_mat *H, *Q;
2049 :
2050 0 : n1 = isl_mat_rows(mat1);
2051 0 : H = isl_mat_concat(mat1, mat2);
2052 0 : H = isl_mat_left_hermite(H, 0, NULL, &Q);
2053 0 : if (!H || !Q)
2054 : goto error;
2055 :
2056 0 : r1 = hermite_first_zero_col(H, 0, n1);
2057 0 : r = hermite_first_zero_col(H, r1, H->n_row);
2058 0 : n_row = isl_mat_rows(Q);
2059 0 : Q = isl_mat_drop_rows(Q, r, n_row - r);
2060 0 : Q = isl_mat_drop_rows(Q, 0, r1);
2061 :
2062 0 : isl_mat_free(H);
2063 0 : return Q;
2064 : error:
2065 0 : isl_mat_free(H);
2066 0 : isl_mat_free(Q);
2067 0 : return NULL;
2068 : }
2069 :
2070 : /* Are the rows of "mat1" linearly independent of those of "mat2"?
2071 : * That is, is there no linear dependence among the combined rows
2072 : * that is not already present in either "mat1" or "mat2"?
2073 : * In other words, is the rank of "mat1" and "mat2" combined equal
2074 : * to the sum of the ranks of "mat1" and "mat2"?
2075 : */
2076 0 : isl_bool isl_mat_has_linearly_independent_rows(__isl_keep isl_mat *mat1,
2077 : __isl_keep isl_mat *mat2)
2078 : {
2079 : int r1, r2, r;
2080 : isl_mat *mat;
2081 :
2082 0 : r1 = isl_mat_rank(mat1);
2083 0 : if (r1 < 0)
2084 0 : return isl_bool_error;
2085 0 : if (r1 == 0)
2086 0 : return isl_bool_true;
2087 0 : r2 = isl_mat_rank(mat2);
2088 0 : if (r2 < 0)
2089 0 : return isl_bool_error;
2090 0 : if (r2 == 0)
2091 0 : return isl_bool_true;
2092 :
2093 0 : mat = isl_mat_concat(isl_mat_copy(mat1), isl_mat_copy(mat2));
2094 0 : r = isl_mat_rank(mat);
2095 0 : isl_mat_free(mat);
2096 0 : if (r < 0)
2097 0 : return isl_bool_error;
2098 0 : return r == r1 + r2;
2099 : }
|