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 24693139509 : isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat)
26 : {
27 24693139509 : 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 42325072457 : 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 42325072457 : mat = isl_alloc_type(ctx, struct isl_mat);
60 42325072457 : if (!mat)
61 0 : return NULL;
62 :
63 42325072457 : mat->row = NULL;
64 42325072457 : mat->block = isl_blk_alloc(ctx, n_row * n_col);
65 42325072457 : if (isl_blk_is_error(mat->block))
66 0 : goto error;
67 42325072457 : mat->row = isl_alloc_array(ctx, isl_int *, n_row);
68 42325072457 : if (n_row && !mat->row)
69 0 : goto error;
70 :
71 >12763*10^7 : for (i = 0; i < n_row; ++i)
72 85310298267 : mat->row[i] = mat->block.data + i * n_col;
73 :
74 42325072457 : mat->ctx = ctx;
75 42325072457 : isl_ctx_ref(ctx);
76 42325072457 : mat->ref = 1;
77 42325072457 : mat->n_row = n_row;
78 42325072457 : mat->n_col = n_col;
79 42325072457 : mat->max_col = n_col;
80 42325072457 : mat->flags = 0;
81 :
82 42325072457 : return mat;
83 : error:
84 0 : isl_blk_free(ctx, mat->block);
85 0 : free(mat);
86 0 : return NULL;
87 : }
88 :
89 49214192 : 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 49214192 : if (!mat)
97 0 : return NULL;
98 :
99 49214192 : 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 49214192 : 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 49214192 : mat = isl_mat_cow(mat);
120 49214192 : if (!mat)
121 0 : goto error;
122 :
123 49214192 : old = mat->block.data;
124 49214192 : mat->block = isl_blk_extend(mat->ctx, mat->block, n_row * mat->max_col);
125 49214192 : if (isl_blk_is_error(mat->block))
126 0 : goto error;
127 49214192 : row = isl_realloc_array(mat->ctx, mat->row, isl_int *, n_row);
128 49214192 : if (n_row && !row)
129 0 : goto error;
130 49214192 : mat->row = row;
131 :
132 1100292106 : for (i = 0; i < mat->n_row; ++i)
133 1051077914 : mat->row[i] = mat->block.data + (mat->row[i] - old);
134 181252134 : for (i = mat->n_row; i < n_row; ++i)
135 132037942 : mat->row[i] = mat->block.data + i * mat->max_col;
136 49214192 : mat->n_row = n_row;
137 49214192 : if (mat->n_col < n_col)
138 0 : mat->n_col = n_col;
139 :
140 49214192 : return mat;
141 : error:
142 0 : isl_mat_free(mat);
143 0 : return NULL;
144 : }
145 :
146 28227183329 : __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 28227183329 : mat = isl_alloc_type(ctx, struct isl_mat);
153 28227183329 : if (!mat)
154 0 : return NULL;
155 28227183329 : mat->row = isl_alloc_array(ctx, isl_int *, n_row);
156 28227183329 : if (n_row && !mat->row)
157 0 : goto error;
158 52953304760 : for (i = 0; i < n_row; ++i)
159 24726121431 : mat->row[i] = row[first_row+i] + first_col;
160 28227183329 : mat->ctx = ctx;
161 28227183329 : isl_ctx_ref(ctx);
162 28227183329 : mat->ref = 1;
163 28227183329 : mat->n_row = n_row;
164 28227183329 : mat->n_col = n_col;
165 28227183329 : mat->block = isl_blk_empty();
166 28227183329 : mat->flags = ISL_MAT_BORROWED;
167 28227183329 : return mat;
168 : error:
169 0 : free(mat);
170 0 : return NULL;
171 : }
172 :
173 90722724 : __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 90722724 : if (!mat)
177 0 : return NULL;
178 90722724 : return isl_mat_sub_alloc6(mat->ctx, mat->row, first_row, n_row,
179 : first_col, n_col);
180 : }
181 :
182 87912686 : 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 730978568 : for (i = 0; i < n_row; ++i)
188 643065882 : isl_seq_cpy(dst[i]+dst_col, src[i]+src_col, n_col);
189 87912686 : }
190 :
191 22692851 : 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 63687855 : for (i = 0; i < n_row; ++i)
197 40995004 : isl_seq_neg(dst[i]+dst_col, src[i]+src_col, n_col);
198 22692851 : }
199 :
200 28133499647 : __isl_give isl_mat *isl_mat_copy(__isl_keep isl_mat *mat)
201 : {
202 28133499647 : if (!mat)
203 0 : return NULL;
204 :
205 28133499647 : mat->ref++;
206 28133499647 : return mat;
207 : }
208 :
209 1257069377 : __isl_give isl_mat *isl_mat_dup(__isl_keep isl_mat *mat)
210 : {
211 : int i;
212 : struct isl_mat *mat2;
213 :
214 1257069377 : if (!mat)
215 0 : return NULL;
216 1257069377 : mat2 = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col);
217 1257069377 : if (!mat2)
218 0 : return NULL;
219 5442499061 : for (i = 0; i < mat->n_row; ++i)
220 4185429684 : isl_seq_cpy(mat2->row[i], mat->row[i], mat->n_col);
221 1257069377 : return mat2;
222 : }
223 :
224 26469882340 : __isl_give isl_mat *isl_mat_cow(__isl_take isl_mat *mat)
225 : {
226 : struct isl_mat *mat2;
227 26469882340 : if (!mat)
228 0 : return NULL;
229 :
230 26469882340 : if (mat->ref == 1 && !ISL_F_ISSET(mat, ISL_MAT_BORROWED))
231 25212812963 : return mat;
232 :
233 1257069377 : mat2 = isl_mat_dup(mat);
234 1257069377 : isl_mat_free(mat);
235 1257069377 : return mat2;
236 : }
237 :
238 >10956*10^7 : __isl_null isl_mat *isl_mat_free(__isl_take isl_mat *mat)
239 : {
240 >10956*10^7 : if (!mat)
241 10879780139 : return NULL;
242 :
243 98685755433 : if (--mat->ref > 0)
244 28133499647 : return NULL;
245 :
246 70552255786 : if (!ISL_F_ISSET(mat, ISL_MAT_BORROWED))
247 42325072457 : isl_blk_free(mat->ctx, mat->block);
248 70552255786 : isl_ctx_deref(mat->ctx);
249 70552255786 : free(mat->row);
250 70552255786 : free(mat);
251 :
252 70552255786 : return NULL;
253 : }
254 :
255 22096141 : int isl_mat_rows(__isl_keep isl_mat *mat)
256 : {
257 22096141 : 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 19245068726 : static isl_stat check_col_range(__isl_keep isl_mat *mat, unsigned first,
292 : unsigned n)
293 : {
294 19245068726 : if (!mat)
295 0 : return isl_stat_error;
296 19245068726 : 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 19245068726 : return isl_stat_ok;
301 : }
302 :
303 : /* Check that there are "n" rows starting at position "first" in "mat".
304 : */
305 16638906685 : static isl_stat check_row_range(__isl_keep isl_mat *mat, unsigned first,
306 : unsigned n)
307 : {
308 16638906685 : if (!mat)
309 0 : return isl_stat_error;
310 16638906685 : 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 16638906685 : 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 3752847843 : __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 3752847843 : mat = isl_mat_alloc(ctx, n_row, n_row);
390 3752847843 : if (!mat)
391 0 : return NULL;
392 16845384770 : for (i = 0; i < n_row; ++i) {
393 13092536927 : isl_seq_clr(mat->row[i], i);
394 13092536927 : isl_int_set(mat->row[i][i], d);
395 13092536927 : isl_seq_clr(mat->row[i]+i+1, n_row-(i+1));
396 : }
397 :
398 3752847843 : 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 3752847843 : __isl_give isl_mat *isl_mat_identity(isl_ctx *ctx, unsigned n_row)
418 : {
419 3752847843 : if (!ctx)
420 0 : return NULL;
421 3752847843 : 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 26401132 : __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 26401132 : if (!mat || !vec)
455 : goto error;
456 :
457 26401132 : isl_assert(mat->ctx, mat->n_col == vec->size, goto error);
458 :
459 26401132 : prod = isl_vec_alloc(mat->ctx, mat->n_row);
460 26401132 : if (!prod)
461 0 : goto error;
462 :
463 206752426 : for (i = 0; i < prod->size; ++i)
464 360702588 : isl_seq_inner_product(mat->row[i], vec->el, vec->size,
465 360702588 : &prod->block.data[i]);
466 26401132 : isl_mat_free(mat);
467 26401132 : isl_vec_free(vec);
468 26401132 : 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 363347 : __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 363347 : if (!mat || !vec)
511 : goto error;
512 :
513 363347 : isl_assert(mat->ctx, mat->n_row == vec->size, goto error);
514 :
515 363347 : prod = isl_vec_alloc(mat->ctx, mat->n_col);
516 363347 : if (!prod)
517 0 : goto error;
518 :
519 2804218 : for (i = 0; i < prod->size; ++i) {
520 2440871 : isl_int_set_si(prod->el[i], 0);
521 20347375 : for (j = 0; j < vec->size; ++j)
522 17906504 : isl_int_addmul(prod->el[i], vec->el[j], mat->row[j][i]);
523 : }
524 363347 : isl_mat_free(mat);
525 363347 : isl_vec_free(vec);
526 363347 : return prod;
527 : error:
528 0 : isl_mat_free(mat);
529 0 : isl_vec_free(vec);
530 0 : return NULL;
531 : }
532 :
533 22668511 : __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 22668511 : if (!left || !right)
540 : goto error;
541 :
542 22668511 : isl_assert(left->ctx, left->n_row == right->n_row, goto error);
543 22668511 : isl_assert(left->ctx, left->n_row >= 1, goto error);
544 22668511 : isl_assert(left->ctx, left->n_col >= 1, goto error);
545 22668511 : isl_assert(left->ctx, right->n_col >= 1, goto error);
546 22668511 : isl_assert(left->ctx,
547 : isl_seq_first_non_zero(left->row[0]+1, left->n_col-1) == -1,
548 : goto error);
549 22668511 : isl_assert(left->ctx,
550 : isl_seq_first_non_zero(right->row[0]+1, right->n_col-1) == -1,
551 : goto error);
552 :
553 22668511 : sum = isl_mat_alloc(left->ctx, left->n_row, left->n_col + right->n_col - 1);
554 22668511 : if (!sum)
555 0 : goto error;
556 22668511 : isl_int_lcm(sum->row[0][0], left->row[0][0], right->row[0][0]);
557 22668511 : isl_int_divexact(left->row[0][0], sum->row[0][0], left->row[0][0]);
558 22668511 : isl_int_divexact(right->row[0][0], sum->row[0][0], right->row[0][0]);
559 :
560 22668511 : isl_seq_clr(sum->row[0]+1, sum->n_col-1);
561 168665521 : for (i = 1; i < sum->n_row; ++i) {
562 145997010 : isl_int_mul(sum->row[i][0], left->row[0][0], left->row[i][0]);
563 145997010 : isl_int_addmul(sum->row[i][0],
564 : right->row[0][0], right->row[i][0]);
565 145997010 : isl_seq_scale(sum->row[i]+1, left->row[i]+1, left->row[0][0],
566 145997010 : left->n_col-1);
567 437991030 : isl_seq_scale(sum->row[i]+left->n_col,
568 291994020 : right->row[i]+1, right->row[0][0],
569 145997010 : right->n_col-1);
570 : }
571 :
572 22668511 : isl_int_divexact(left->row[0][0], sum->row[0][0], left->row[0][0]);
573 22668511 : isl_int_divexact(right->row[0][0], sum->row[0][0], right->row[0][0]);
574 22668511 : isl_mat_free(left);
575 22668511 : isl_mat_free(right);
576 22668511 : return sum;
577 : error:
578 0 : isl_mat_free(left);
579 0 : isl_mat_free(right);
580 0 : return NULL;
581 : }
582 :
583 4784966641 : 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 16921476136 : for (r = row; r < M->n_row; ++r)
588 12136509495 : isl_int_swap(M->row[r][i], M->row[r][j]);
589 4784966641 : if (U) {
590 23433587976 : for (r = 0; r < (*U)->n_row; ++r)
591 18649971511 : isl_int_swap((*U)->row[r][i], (*U)->row[r][j]);
592 : }
593 4784966641 : if (Q)
594 237460409 : isl_mat_swap_rows(*Q, i, j);
595 4784966641 : }
596 :
597 5695858343 : 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 21944028011 : for (r = row; r < M->n_row; ++r)
602 16248169668 : isl_int_submul(M->row[r][j], m, M->row[r][i]);
603 5695858343 : if (U) {
604 28428401536 : for (r = 0; r < (*U)->n_row; ++r)
605 22733791870 : isl_int_submul((*U)->row[r][j], m, (*U)->row[r][i]);
606 : }
607 5695858343 : if (Q) {
608 2791384903 : for (r = 0; r < (*Q)->n_col; ++r)
609 2319782885 : isl_int_addmul((*Q)->row[i][r], m, (*Q)->row[j][r]);
610 : }
611 5695858343 : }
612 :
613 1962497460 : 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 5736755881 : for (r = row; r < M->n_row; ++r)
618 3774258421 : isl_int_neg(M->row[r][col], M->row[r][col]);
619 1962497460 : if (U) {
620 8865363187 : for (r = 0; r < (*U)->n_row; ++r)
621 6903680617 : isl_int_neg((*U)->row[r][col], (*U)->row[r][col]);
622 : }
623 1962497460 : if (Q)
624 92429549 : isl_seq_neg((*Q)->row[col], (*Q)->row[col], (*Q)->n_col);
625 1962497460 : }
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 83816633 : __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 83816633 : if (U)
646 82693012 : *U = NULL;
647 83816633 : if (Q)
648 45318016 : *Q = NULL;
649 83816633 : if (!M)
650 0 : goto error;
651 83816633 : M = isl_mat_cow(M);
652 83816633 : if (!M)
653 0 : goto error;
654 83816633 : if (U) {
655 82693012 : *U = isl_mat_identity(M->ctx, M->n_col);
656 82693012 : if (!*U)
657 0 : goto error;
658 : }
659 83816633 : if (Q) {
660 45318016 : *Q = isl_mat_identity(M->ctx, M->n_col);
661 45318016 : if (!*Q)
662 0 : goto error;
663 : }
664 :
665 83816633 : col = 0;
666 83816633 : isl_int_init(c);
667 786252622 : for (row = 0; row < M->n_row; ++row) {
668 : int first, i, off;
669 702435989 : first = isl_seq_abs_min_non_zero(M->row[row]+col, M->n_col-col);
670 702435989 : if (first == -1)
671 446932295 : continue;
672 255503694 : first += col;
673 255503694 : if (first != col)
674 122159630 : exchange(M, U, Q, row, first, col);
675 255503694 : if (isl_int_is_neg(M->row[row][col]))
676 94355156 : oppose(M, U, Q, row, col);
677 255503694 : first = col+1;
678 787255916 : while ((off = isl_seq_first_non_zero(M->row[row]+first,
679 531752222 : M->n_col-first)) != -1) {
680 276248528 : first += off;
681 276248528 : isl_int_fdiv_q(c, M->row[row][first], M->row[row][col]);
682 276248528 : subtract(M, U, Q, row, col, first, c);
683 276248528 : if (!isl_int_is_zero(M->row[row][first]))
684 170999084 : exchange(M, U, Q, row, first, col);
685 : else
686 105249444 : ++first;
687 : }
688 672226353 : for (i = 0; i < col; ++i) {
689 416722659 : if (isl_int_is_zero(M->row[row][i]))
690 157461436 : continue;
691 259261223 : if (neg)
692 0 : isl_int_cdiv_q(c, M->row[row][i], M->row[row][col]);
693 : else
694 259261223 : isl_int_fdiv_q(c, M->row[row][i], M->row[row][col]);
695 259261223 : if (isl_int_is_zero(c))
696 38826418 : continue;
697 220434805 : subtract(M, U, Q, row, col, i, c);
698 : }
699 255503694 : ++col;
700 : }
701 83816633 : isl_int_clear(c);
702 :
703 83816633 : 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 85225909 : __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 85225909 : if (!mat)
892 0 : return NULL;
893 85225909 : mat2 = isl_mat_alloc(mat->ctx, 1+mat->n_row, 1+mat->n_col);
894 85225909 : if (!mat2)
895 0 : goto error;
896 85225909 : isl_int_set_si(mat2->row[0][0], 1);
897 85225909 : isl_seq_clr(mat2->row[0]+1, mat->n_col);
898 504350633 : for (i = 0; i < mat->n_row; ++i) {
899 419124724 : isl_int_set_si(mat2->row[1+i][0], 0);
900 419124724 : isl_seq_cpy(mat2->row[1+i]+1, mat->row[i], mat->n_col);
901 : }
902 85225909 : isl_mat_free(mat);
903 85225909 : 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 467667 : __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 467667 : if (!mat1 || !mat2)
921 : goto error;
922 :
923 467667 : mat = isl_mat_alloc(mat1->ctx, mat1->n_row + mat2->n_row,
924 467667 : mat1->n_col + mat2->n_col);
925 467667 : if (!mat)
926 0 : goto error;
927 935334 : for (i = 0; i < mat1->n_row; ++i) {
928 467667 : isl_seq_cpy(mat->row[i], mat1->row[i], mat1->n_col);
929 467667 : isl_seq_clr(mat->row[i] + mat1->n_col, mat2->n_col);
930 : }
931 2213804 : for (i = 0; i < mat2->n_row; ++i) {
932 1746137 : isl_seq_clr(mat->row[mat1->n_row + i], mat1->n_col);
933 3492274 : isl_seq_cpy(mat->row[mat1->n_row + i] + mat1->n_col,
934 1746137 : mat2->row[i], mat2->n_col);
935 : }
936 467667 : isl_mat_free(mat1);
937 467667 : isl_mat_free(mat2);
938 467667 : return mat;
939 : error:
940 0 : isl_mat_free(mat1);
941 0 : isl_mat_free(mat2);
942 0 : return NULL;
943 : }
944 :
945 128409937 : static int row_first_non_zero(isl_int **row, unsigned n_row, unsigned col)
946 : {
947 : int i;
948 :
949 199198021 : for (i = 0; i < n_row; ++i)
950 135510166 : if (!isl_int_is_zero(row[i][col]))
951 64722082 : return i;
952 63687855 : return -1;
953 : }
954 :
955 63687855 : static int row_abs_min_non_zero(isl_int **row, unsigned n_row, unsigned col)
956 : {
957 63687855 : int i, min = row_first_non_zero(row, n_row, col);
958 63687855 : if (min < 0)
959 0 : return -1;
960 135468394 : for (i = min + 1; i < n_row; ++i) {
961 71780539 : if (isl_int_is_zero(row[i][col]))
962 70788084 : continue;
963 992455 : if (isl_int_abs_lt(row[i][col], row[min][col]))
964 30372 : min = i;
965 : }
966 63687855 : return min;
967 : }
968 :
969 71513 : static isl_stat inv_exchange(__isl_keep isl_mat **left,
970 : __isl_keep isl_mat **right, unsigned i, unsigned j)
971 : {
972 71513 : *left = isl_mat_swap_rows(*left, i, j);
973 71513 : *right = isl_mat_swap_rows(*right, i, j);
974 :
975 71513 : if (!*left || !*right)
976 0 : return isl_stat_error;
977 71513 : return isl_stat_ok;
978 : }
979 :
980 28657 : static void inv_oppose(
981 : struct isl_mat *left, struct isl_mat *right, unsigned row)
982 : {
983 28657 : isl_seq_neg(left->row[row]+row, left->row[row]+row, left->n_col-row);
984 28657 : isl_seq_neg(right->row[row], right->row[row], right->n_col);
985 28657 : }
986 :
987 1034227 : static void inv_subtract(struct isl_mat *left, struct isl_mat *right,
988 : unsigned row, unsigned i, isl_int m)
989 : {
990 1034227 : isl_int_neg(m, m);
991 6205362 : isl_seq_combine(left->row[i]+row,
992 3102681 : left->ctx->one, left->row[i]+row,
993 2068454 : m, left->row[row]+row,
994 1034227 : left->n_col-row);
995 2068454 : isl_seq_combine(right->row[i], right->ctx->one, right->row[i],
996 1034227 : m, right->row[row], right->n_col);
997 1034227 : }
998 :
999 : /* Compute inv(left)*right
1000 : */
1001 22692851 : __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 22692851 : if (!left || !right)
1008 : goto error;
1009 :
1010 22692851 : isl_assert(left->ctx, left->n_row == left->n_col, goto error);
1011 22692851 : isl_assert(left->ctx, left->n_row == right->n_row, goto error);
1012 :
1013 22692851 : if (left->n_row == 0) {
1014 0 : isl_mat_free(left);
1015 0 : return right;
1016 : }
1017 :
1018 22692851 : left = isl_mat_cow(left);
1019 22692851 : right = isl_mat_cow(right);
1020 22692851 : if (!left || !right)
1021 : goto error;
1022 :
1023 22692851 : isl_int_init(a);
1024 22692851 : isl_int_init(b);
1025 86380706 : for (row = 0; row < left->n_row; ++row) {
1026 : int pivot, first, i, off;
1027 63687855 : pivot = row_abs_min_non_zero(left->row+row, left->n_row-row, row);
1028 63687855 : 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 63687855 : pivot += row;
1034 63687855 : if (pivot != row)
1035 29741 : if (inv_exchange(&left, &right, pivot, row) < 0)
1036 0 : goto error;
1037 63687855 : if (isl_int_is_neg(left->row[row][row]))
1038 28657 : inv_oppose(left, right, row);
1039 63687855 : first = row+1;
1040 193132019 : while ((off = row_first_non_zero(left->row+first,
1041 64722082 : left->n_row-first, row)) != -1) {
1042 1034227 : first += off;
1043 1034227 : isl_int_fdiv_q(a, left->row[first][row],
1044 : left->row[row][row]);
1045 1034227 : inv_subtract(left, right, row, first, a);
1046 1034227 : if (!isl_int_is_zero(left->row[first][row])) {
1047 83544 : if (inv_exchange(&left, &right, row, first) < 0)
1048 0 : goto error;
1049 : } else {
1050 992455 : ++first;
1051 : }
1052 : }
1053 135468394 : for (i = 0; i < row; ++i) {
1054 71780539 : if (isl_int_is_zero(left->row[i][row]))
1055 71730116 : continue;
1056 50423 : isl_int_gcd(a, left->row[row][row], left->row[i][row]);
1057 50423 : isl_int_divexact(b, left->row[i][row], a);
1058 50423 : isl_int_divexact(a, left->row[row][row], a);
1059 50423 : isl_int_neg(b, b);
1060 252115 : isl_seq_combine(left->row[i] + i,
1061 100846 : a, left->row[i] + i,
1062 100846 : b, left->row[row] + i,
1063 50423 : left->n_col - i);
1064 100846 : isl_seq_combine(right->row[i], a, right->row[i],
1065 100846 : b, right->row[row], right->n_col);
1066 : }
1067 : }
1068 22692851 : isl_int_clear(b);
1069 :
1070 22692851 : isl_int_set(a, left->row[0][0]);
1071 63687855 : for (row = 1; row < left->n_row; ++row)
1072 40995004 : isl_int_lcm(a, a, left->row[row][row]);
1073 22692851 : if (isl_int_is_zero(a)){
1074 0 : isl_int_clear(a);
1075 0 : isl_assert(left->ctx, 0, goto error);
1076 : }
1077 86380706 : for (row = 0; row < left->n_row; ++row) {
1078 63687855 : isl_int_divexact(left->row[row][row], a, left->row[row][row]);
1079 63687855 : if (isl_int_is_one(left->row[row][row]))
1080 61521831 : continue;
1081 6498072 : isl_seq_scale(right->row[row], right->row[row],
1082 6498072 : left->row[row][row], right->n_col);
1083 : }
1084 22692851 : isl_int_clear(a);
1085 :
1086 22692851 : isl_mat_free(left);
1087 22692851 : return right;
1088 : error:
1089 0 : isl_mat_free(left);
1090 0 : isl_mat_free(right);
1091 0 : return NULL;
1092 : }
1093 :
1094 3131400315 : void isl_mat_col_scale(struct isl_mat *mat, unsigned col, isl_int m)
1095 : {
1096 : int i;
1097 :
1098 13903160750 : for (i = 0; i < mat->n_row; ++i)
1099 10771760435 : isl_int_mul(mat->row[i][col], mat->row[i][col], m);
1100 3131400315 : }
1101 :
1102 10273099964 : 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 10273099964 : isl_int_init(tmp);
1109 43298272567 : for (i = 0; i < mat->n_row; ++i) {
1110 33025172603 : isl_int_mul(tmp, m1, mat->row[i][src1]);
1111 33025172603 : isl_int_addmul(tmp, m2, mat->row[i][src2]);
1112 33025172603 : isl_int_set(mat->row[i][dst], tmp);
1113 : }
1114 10273099964 : isl_int_clear(tmp);
1115 10273099964 : }
1116 :
1117 3565212061 : __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 3565212061 : mat = isl_mat_cow(mat);
1124 3565212061 : if (!mat)
1125 0 : return NULL;
1126 :
1127 3565212061 : inv = isl_mat_identity(mat->ctx, mat->n_col);
1128 3565212061 : inv = isl_mat_cow(inv);
1129 3565212061 : if (!inv)
1130 0 : goto error;
1131 :
1132 3565212061 : isl_int_init(a);
1133 3565212061 : isl_int_init(b);
1134 13515400721 : for (row = 0; row < mat->n_row; ++row) {
1135 : int pivot, first, i, off;
1136 9950188660 : pivot = isl_seq_abs_min_non_zero(mat->row[row]+row, mat->n_col-row);
1137 9950188660 : 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 9950188660 : pivot += row;
1143 9950188660 : if (pivot != row)
1144 1938648261 : exchange(mat, &inv, NULL, row, pivot, row);
1145 9950188660 : if (isl_int_is_neg(mat->row[row][row]))
1146 1868142304 : oppose(mat, &inv, NULL, row, row);
1147 9950188660 : first = row+1;
1148 25099552330 : while ((off = isl_seq_first_non_zero(mat->row[row]+first,
1149 15149363670 : mat->n_col-first)) != -1) {
1150 5199175010 : first += off;
1151 5199175010 : isl_int_fdiv_q(a, mat->row[row][first],
1152 : mat->row[row][row]);
1153 5199175010 : subtract(mat, &inv, NULL, row, row, first, a);
1154 5199175010 : if (!isl_int_is_zero(mat->row[row][first]))
1155 2553159666 : exchange(mat, &inv, NULL, row, row, first);
1156 : else
1157 2646015344 : ++first;
1158 : }
1159 19752430675 : for (i = 0; i < row; ++i) {
1160 9802242015 : if (isl_int_is_zero(mat->row[row][i]))
1161 4665692033 : continue;
1162 5136549982 : isl_int_gcd(a, mat->row[row][row], mat->row[row][i]);
1163 5136549982 : isl_int_divexact(b, mat->row[row][i], a);
1164 5136549982 : isl_int_divexact(a, mat->row[row][row], a);
1165 5136549982 : isl_int_neg(a, a);
1166 5136549982 : isl_mat_col_combine(mat, i, a, i, b, row);
1167 5136549982 : isl_mat_col_combine(inv, i, a, i, b, row);
1168 : }
1169 : }
1170 3565212061 : isl_int_clear(b);
1171 :
1172 3565212061 : isl_int_set(a, mat->row[0][0]);
1173 9950188660 : for (row = 1; row < mat->n_row; ++row)
1174 6384976599 : isl_int_lcm(a, a, mat->row[row][row]);
1175 3565212061 : if (isl_int_is_zero(a)){
1176 0 : isl_int_clear(a);
1177 0 : goto error;
1178 : }
1179 13515400721 : for (row = 0; row < mat->n_row; ++row) {
1180 9950188660 : isl_int_divexact(mat->row[row][row], a, mat->row[row][row]);
1181 9950188660 : if (isl_int_is_one(mat->row[row][row]))
1182 6818788345 : continue;
1183 3131400315 : isl_mat_col_scale(inv, row, mat->row[row][row]);
1184 : }
1185 3565212061 : isl_int_clear(a);
1186 :
1187 3565212061 : isl_mat_free(mat);
1188 :
1189 3565212061 : 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 9013384923 : __isl_give isl_mat *isl_mat_swap_cols(__isl_take isl_mat *mat,
1227 : unsigned i, unsigned j)
1228 : {
1229 : int r;
1230 :
1231 9013384923 : mat = isl_mat_cow(mat);
1232 18026769846 : if (check_col_range(mat, i, 1) < 0 ||
1233 9013384923 : check_col_range(mat, j, 1) < 0)
1234 0 : return isl_mat_free(mat);
1235 :
1236 >21354*10^7 : for (r = 0; r < mat->n_row; ++r)
1237 >20453*10^7 : isl_int_swap(mat->row[r][i], mat->row[r][j]);
1238 9013384923 : return mat;
1239 : }
1240 :
1241 7710199175 : __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 7710199175 : if (!mat)
1247 0 : return NULL;
1248 7710199175 : mat = isl_mat_cow(mat);
1249 15420398350 : if (check_row_range(mat, i, 1) < 0 ||
1250 7710199175 : check_row_range(mat, j, 1) < 0)
1251 0 : return isl_mat_free(mat);
1252 :
1253 7710199175 : t = mat->row[i];
1254 7710199175 : mat->row[i] = mat->row[j];
1255 7710199175 : mat->row[j] = t;
1256 7710199175 : 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 28119639799 : __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 28119639799 : if (!left || !right)
1271 : goto error;
1272 28119639799 : isl_assert(left->ctx, left->n_col == right->n_row, goto error);
1273 28119639799 : prod = isl_mat_alloc(left->ctx, left->n_row, right->n_col);
1274 28119639799 : if (!prod)
1275 0 : goto error;
1276 28119639799 : 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 52581956425 : for (i = 0; i < prod->n_row; ++i) {
1284 >10698*10^7 : for (j = 0; j < prod->n_col; ++j)
1285 82527443406 : isl_int_mul(prod->row[i][j],
1286 : left->row[i][0], right->row[0][j]);
1287 91129506795 : for (k = 1; k < left->n_col; ++k) {
1288 66667190169 : if (isl_int_is_zero(left->row[i][k]))
1289 40449057242 : continue;
1290 >11848*10^7 : for (j = 0; j < prod->n_col; ++j)
1291 92263143657 : isl_int_addmul(prod->row[i][j],
1292 : left->row[i][k], right->row[k][j]);
1293 : }
1294 : }
1295 28119639799 : isl_mat_free(left);
1296 28119639799 : isl_mat_free(right);
1297 28119639799 : 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 28096583970 : 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 28096583970 : if (mat->n_col >= mat->n_row)
1323 15518765043 : e = 0;
1324 : else
1325 12577818927 : e = mat->n_row - mat->n_col;
1326 28096583970 : if (has_div)
1327 9365527990 : for (i = 0; i < n; ++i)
1328 0 : isl_int_mul(q[i][0], q[i][0], mat->row[0][0]);
1329 28096583970 : t = isl_mat_sub_alloc6(mat->ctx, q, 0, n, has_div, mat->n_row);
1330 28096583970 : t = isl_mat_product(t, mat);
1331 28096583970 : if (!t)
1332 0 : return -1;
1333 52389466597 : for (i = 0; i < n; ++i) {
1334 24292882627 : isl_seq_swp_or_cpy(q[i] + has_div, t->row[i], t->n_col);
1335 24292882627 : isl_seq_cpy(q[i] + has_div + t->n_col,
1336 24292882627 : q[i] + has_div + t->n_col + e, n_div);
1337 24292882627 : isl_seq_clr(q[i] + has_div + t->n_col + n_div, e);
1338 : }
1339 28096583970 : isl_mat_free(t);
1340 28096583970 : 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 9365527990 : __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 9365527990 : if (!bset || !mat)
1359 : goto error;
1360 :
1361 9365527990 : ctx = bset->ctx;
1362 9365527990 : bset = isl_basic_set_cow(bset);
1363 9365527990 : if (!bset)
1364 0 : goto error;
1365 :
1366 9365527990 : isl_assert(ctx, bset->dim->nparam == 0, goto error);
1367 9365527990 : isl_assert(ctx, 1+bset->dim->n_out == mat->n_row, goto error);
1368 9365527990 : isl_assert(ctx, mat->n_col > 0, goto error);
1369 :
1370 9365527990 : if (mat->n_col > mat->n_row) {
1371 1218488623 : bset = isl_basic_set_extend(bset, 0, mat->n_col-1, 0, 0, 0);
1372 1218488623 : if (!bset)
1373 0 : goto error;
1374 8147039367 : } else if (mat->n_col < mat->n_row) {
1375 4192606309 : bset->dim = isl_space_cow(bset->dim);
1376 4192606309 : if (!bset->dim)
1377 0 : goto error;
1378 4192606309 : bset->dim->n_out -= mat->n_row - mat->n_col;
1379 : }
1380 :
1381 9365527990 : if (preimage(ctx, bset->eq, bset->n_eq, bset->n_div, 0,
1382 9365527990 : isl_mat_copy(mat)) < 0)
1383 0 : goto error;
1384 :
1385 9365527990 : if (preimage(ctx, bset->ineq, bset->n_ineq, bset->n_div, 0,
1386 9365527990 : isl_mat_copy(mat)) < 0)
1387 0 : goto error;
1388 :
1389 9365527990 : if (preimage(ctx, bset->div, bset->n_div, bset->n_div, 1, mat) < 0)
1390 0 : goto error2;
1391 :
1392 9365527990 : ISL_F_CLR(bset, ISL_BASIC_SET_NO_IMPLICIT);
1393 9365527990 : ISL_F_CLR(bset, ISL_BASIC_SET_NO_REDUNDANT);
1394 9365527990 : ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED);
1395 9365527990 : ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED_DIVS);
1396 9365527990 : ISL_F_CLR(bset, ISL_BASIC_SET_ALL_EQUALITIES);
1397 :
1398 9365527990 : bset = isl_basic_set_simplify(bset);
1399 9365527990 : bset = isl_basic_set_finalize(bset);
1400 :
1401 9365527990 : 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 2347012851 : __isl_give isl_set *isl_set_preimage(
1410 : __isl_take isl_set *set, __isl_take isl_mat *mat)
1411 : {
1412 : int i;
1413 :
1414 2347012851 : set = isl_set_cow(set);
1415 2347012851 : if (!set)
1416 0 : goto error;
1417 :
1418 10433578285 : for (i = 0; i < set->n; ++i) {
1419 8086565434 : set->p[i] = isl_basic_set_preimage(set->p[i],
1420 : isl_mat_copy(mat));
1421 8086565434 : if (!set->p[i])
1422 0 : goto error;
1423 : }
1424 2347012851 : if (mat->n_col != mat->n_row) {
1425 1218341356 : set->dim = isl_space_cow(set->dim);
1426 1218341356 : if (!set->dim)
1427 0 : goto error;
1428 1218341356 : set->dim->n_out += mat->n_col;
1429 1218341356 : set->dim->n_out -= mat->n_row;
1430 : }
1431 2347012851 : isl_mat_free(mat);
1432 2347012851 : ISL_F_CLR(set, ISL_SET_NORMALIZED);
1433 2347012851 : 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 1218298880 : __isl_give isl_mat *isl_mat_drop_cols(__isl_take isl_mat *mat,
1499 : unsigned col, unsigned n)
1500 : {
1501 : int r;
1502 :
1503 1218298880 : if (n == 0)
1504 0 : return mat;
1505 :
1506 1218298880 : mat = isl_mat_cow(mat);
1507 1218298880 : if (check_col_range(mat, col, n) < 0)
1508 0 : return isl_mat_free(mat);
1509 :
1510 1218298880 : if (col != mat->n_col-n) {
1511 5345903892 : for (r = 0; r < mat->n_row; ++r)
1512 4127633609 : isl_seq_cpy(mat->row[r]+col, mat->row[r]+col+n,
1513 4127633609 : mat->n_col - col - n);
1514 : }
1515 1218298880 : mat->n_col -= n;
1516 1218298880 : return mat;
1517 : }
1518 :
1519 1218508335 : __isl_give isl_mat *isl_mat_drop_rows(__isl_take isl_mat *mat,
1520 : unsigned row, unsigned n)
1521 : {
1522 : int r;
1523 :
1524 1218508335 : mat = isl_mat_cow(mat);
1525 1218508335 : if (check_row_range(mat, row, n) < 0)
1526 0 : return isl_mat_free(mat);
1527 :
1528 2910526947 : for (r = row; r+n < mat->n_row; ++r)
1529 1692018612 : mat->row[r] = mat->row[r+n];
1530 :
1531 1218508335 : mat->n_row -= n;
1532 1218508335 : 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 586908 : void isl_mat_gcd(__isl_keep isl_mat *mat, isl_int *gcd)
1913 : {
1914 : int i;
1915 : isl_int g;
1916 :
1917 586908 : isl_int_set_si(*gcd, 0);
1918 586908 : if (!mat)
1919 0 : return;
1920 :
1921 586908 : isl_int_init(g);
1922 3266647 : for (i = 0; i < mat->n_row; ++i) {
1923 2679739 : isl_seq_gcd(mat->row[i], mat->n_col, &g);
1924 2679739 : isl_int_gcd(*gcd, *gcd, g);
1925 : }
1926 586908 : 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 586908 : __isl_give isl_mat *isl_mat_scale_down(__isl_take isl_mat *mat, isl_int m)
1949 : {
1950 : int i;
1951 :
1952 586908 : if (isl_int_is_one(m))
1953 0 : return mat;
1954 :
1955 586908 : mat = isl_mat_cow(mat);
1956 586908 : if (!mat)
1957 0 : return NULL;
1958 :
1959 3266647 : for (i = 0; i < mat->n_row; ++i)
1960 2679739 : isl_seq_scale_down(mat->row[i], mat->row[i], m, mat->n_col);
1961 :
1962 586908 : 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 586908 : __isl_give isl_mat *isl_mat_normalize(__isl_take isl_mat *mat)
1981 : {
1982 : isl_int gcd;
1983 :
1984 586908 : if (!mat)
1985 0 : return NULL;
1986 :
1987 586908 : isl_int_init(gcd);
1988 586908 : isl_mat_gcd(mat, &gcd);
1989 586908 : mat = isl_mat_scale_down(mat, gcd);
1990 586908 : isl_int_clear(gcd);
1991 :
1992 586908 : 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 : }
|