-#include "isl_mat.h"
-#include "isl_seq.h"
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010 INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ */
+
+#include <isl_mat_private.h>
+#include <isl/seq.h>
#include "isl_map_private.h"
#include "isl_equalities.h"
+#include <isl_val_private.h>
/* Given a set of modulo constraints
*
M = isl_mat_left_hermite(M, 0, &U, NULL);
if (!M || !U)
goto error;
- H = isl_mat_sub_alloc(B->ctx, M->row, 0, B->n_row, 0, B->n_row);
+ H = isl_mat_sub_alloc(M, 0, B->n_row, 0, B->n_row);
H = isl_mat_lin_to_aff(H);
C = isl_mat_inverse_product(H, C);
if (!C)
if (i < B->n_row)
cst = isl_mat_alloc(B->ctx, B->n_row, 0);
else
- cst = isl_mat_sub_alloc(C->ctx, C->row, 1, B->n_row, 0, 1);
- T = isl_mat_sub_alloc(U->ctx, U->row, B->n_row, B->n_col - 1, 0, B->n_row);
+ cst = isl_mat_sub_alloc(C, 1, B->n_row, 0, 1);
+ T = isl_mat_sub_alloc(U, B->n_row, B->n_col - 1, 0, B->n_row);
cst = isl_mat_product(T, cst);
isl_mat_free(M);
isl_mat_free(C);
isl_mat_col_mul(U, 0, d->block.data[0], 0);
U = isl_mat_lin_to_aff(U);
return U;
-error:
- isl_mat_free(U);
- return NULL;
}
/* Compute a common lattice of solutions to the linear modulo
struct isl_mat *B, struct isl_vec *d)
{
int i, j, k;
- int ok;
isl_int D;
struct isl_mat *A = NULL, *U = NULL;
struct isl_mat *T;
D, U->row[j][k]);
}
A = isl_mat_left_hermite(A, 0, NULL, NULL);
- T = isl_mat_sub_alloc(A->ctx, A->row, 0, A->n_row, 0, A->n_row);
+ T = isl_mat_sub_alloc(A, 0, A->n_row, 0, A->n_row);
T = isl_mat_lin_to_aff(T);
+ if (!T)
+ goto error;
isl_int_set(T->row[0][0], D);
T = isl_mat_right_inverse(T);
+ if (!T)
+ goto error;
isl_assert(T->ctx, isl_int_is_one(T->row[0][0]), goto error);
T = isl_mat_transpose(T);
isl_mat_free(A);
* then we divide this row of A by the common factor, unless gcd(A_i) = 0.
* In the later case, we simply drop the row (in both A and d).
*
- * If there are no rows left in A, the G is the identity matrix. Otherwise,
+ * If there are no rows left in A, then G is the identity matrix. Otherwise,
* for each row i, we now determine the lattice of integer vectors
* that satisfies this row. Let U_i be the unimodular extension of the
* row A_i. This unimodular extension exists because gcd(A_i) = 1.
/* Given a set of equalities
*
+ * B(y) + A x = 0 (*)
+ *
+ * compute and return an affine transformation T,
+ *
+ * y = T y'
+ *
+ * that bijectively maps the integer vectors y' to integer
+ * vectors y that satisfy the modulo constraints for some value of x.
+ *
+ * Let [H 0] be the Hermite Normal Form of A, i.e.,
+ *
+ * A = [H 0] Q
+ *
+ * Then y is a solution of (*) iff
+ *
+ * H^-1 B(y) (= - [I 0] Q x)
+ *
+ * is an integer vector. Let d be the common denominator of H^-1.
+ * We impose
+ *
+ * d H^-1 B(y) = 0 mod d
+ *
+ * and compute the solution using isl_mat_parameter_compression.
+ */
+__isl_give isl_mat *isl_mat_parameter_compression_ext(__isl_take isl_mat *B,
+ __isl_take isl_mat *A)
+{
+ isl_ctx *ctx;
+ isl_vec *d;
+ int n_row, n_col;
+
+ if (!A)
+ return isl_mat_free(B);
+
+ ctx = isl_mat_get_ctx(A);
+ n_row = A->n_row;
+ n_col = A->n_col;
+ A = isl_mat_left_hermite(A, 0, NULL, NULL);
+ A = isl_mat_drop_cols(A, n_row, n_col - n_row);
+ A = isl_mat_lin_to_aff(A);
+ A = isl_mat_right_inverse(A);
+ d = isl_vec_alloc(ctx, n_row);
+ if (A)
+ d = isl_vec_set(d, A->row[0][0]);
+ A = isl_mat_drop_rows(A, 0, 1);
+ A = isl_mat_drop_cols(A, 0, 1);
+ B = isl_mat_product(A, B);
+
+ return isl_mat_parameter_compression(B, d);
+}
+
+/* Given a set of equalities
+ *
* M x - c = 0
*
- * this function computes unimodular transformation from a lower-dimensional
+ * this function computes a unimodular transformation from a lower-dimensional
* space to the original space that bijectively maps the integer points x'
* in the lower-dimensional space to the integer points x in the original
* space that satisfy the equalities.
*
- * The input is given as a matrix B = [ -c M ] and the out is a
+ * The input is given as a matrix B = [ -c M ] and the output is a
* matrix that maps [1 x'] to [1 x].
* If T2 is not NULL, then *T2 is set to a matrix mapping [1 x] to [1 x'].
*
*
* If any of the c' is non-integer, then the original set has no
* integer solutions (since the x' are a unimodular transformation
- * of the x).
+ * of the x) and a zero-column matrix is returned.
* Otherwise, the transformation is given by
*
* x = U1 H1^{-1} c + U2 x2'
*
* x2' = Q2 x
*/
-struct isl_mat *isl_mat_variable_compression(struct isl_mat *B,
- struct isl_mat **T2)
+__isl_give isl_mat *isl_mat_variable_compression(__isl_take isl_mat *B,
+ __isl_give isl_mat **T2)
{
int i;
struct isl_mat *H = NULL, *C = NULL, *H1, *U = NULL, *U1, *U2, *TC;
goto error;
dim = B->n_col - 1;
- H = isl_mat_sub_alloc(B->ctx, B->row, 0, B->n_row, 1, dim);
+ H = isl_mat_sub_alloc(B, 0, B->n_row, 1, dim);
H = isl_mat_left_hermite(H, 0, &U, T2);
if (!H || !U || (T2 && !*T2))
goto error;
goto error;
isl_int_set_si(C->row[0][0], 1);
isl_mat_sub_neg(C->ctx, C->row+1, B->row, B->n_row, 0, 0, 1);
- H1 = isl_mat_sub_alloc(H->ctx, H->row, 0, H->n_row, 0, H->n_row);
+ H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
H1 = isl_mat_lin_to_aff(H1);
TC = isl_mat_inverse_product(H1, C);
if (!TC)
}
isl_int_set_si(TC->row[0][0], 1);
}
- U1 = isl_mat_sub_alloc(U->ctx, U->row, 0, U->n_row, 0, B->n_row);
+ U1 = isl_mat_sub_alloc(U, 0, U->n_row, 0, B->n_row);
U1 = isl_mat_lin_to_aff(U1);
- U2 = isl_mat_sub_alloc(U->ctx, U->row, 0, U->n_row,
- B->n_row, U->n_row - B->n_row);
+ U2 = isl_mat_sub_alloc(U, 0, U->n_row, B->n_row, U->n_row - B->n_row);
U2 = isl_mat_lin_to_aff(U2);
isl_mat_free(U);
TC = isl_mat_product(U1, TC);
if (bset->n_eq == 0)
return bset;
- B = isl_mat_sub_alloc(bset->ctx, bset->eq, 0, bset->n_eq, 0, 1 + dim);
+ B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq, 0, 1 + dim);
TC = isl_mat_variable_compression(B, T2);
if (!TC)
goto error;
if (!bset || !modulo || !residue)
return -1;
- if (isl_basic_set_fast_dim_is_fixed(bset, pos, residue)) {
+ if (isl_basic_set_plain_dim_is_fixed(bset, pos, residue)) {
isl_int_set_si(*modulo, 0);
return 0;
}
ctx = bset->ctx;
total = isl_basic_set_total_dim(bset);
nparam = isl_basic_set_n_param(bset);
- H = isl_mat_sub_alloc(bset->ctx, bset->eq, 0, bset->n_eq, 1, total);
+ H = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq, 1, total);
H = isl_mat_left_hermite(H, 0, &U, NULL);
if (!H)
return -1;
goto error;
isl_int_set_si(C->row[0][0], 1);
isl_mat_sub_neg(C->ctx, C->row+1, bset->eq, bset->n_eq, 0, 0, 1);
- H1 = isl_mat_sub_alloc(H->ctx, H->row, 0, H->n_row, 0, H->n_row);
+ H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
H1 = isl_mat_lin_to_aff(H1);
C = isl_mat_inverse_product(H1, C);
isl_mat_free(H);
- U1 = isl_mat_sub_alloc(U->ctx, U->row, nparam+pos, 1, 0, bset->n_eq);
+ U1 = isl_mat_sub_alloc(U, nparam+pos, 1, 0, bset->n_eq);
U1 = isl_mat_lin_to_aff(U1);
isl_mat_free(U);
C = isl_mat_product(U1, C);
isl_mat_free(U);
return -1;
}
+
+/* Check if dimension dim belongs to a residue class
+ * i_dim \equiv r mod m
+ * with m != 1 and if so return m in *modulo and r in *residue.
+ * As a special case, when i_dim has a fixed value v, then
+ * *modulo is set to 0 and *residue to v.
+ *
+ * If i_dim does not belong to such a residue class, then *modulo
+ * is set to 1 and *residue is set to 0.
+ */
+int isl_set_dim_residue_class(struct isl_set *set,
+ int pos, isl_int *modulo, isl_int *residue)
+{
+ isl_int m;
+ isl_int r;
+ int i;
+
+ if (!set || !modulo || !residue)
+ return -1;
+
+ if (set->n == 0) {
+ isl_int_set_si(*modulo, 0);
+ isl_int_set_si(*residue, 0);
+ return 0;
+ }
+
+ if (isl_basic_set_dim_residue_class(set->p[0], pos, modulo, residue)<0)
+ return -1;
+
+ if (set->n == 1)
+ return 0;
+
+ if (isl_int_is_one(*modulo))
+ return 0;
+
+ isl_int_init(m);
+ isl_int_init(r);
+
+ for (i = 1; i < set->n; ++i) {
+ if (isl_basic_set_dim_residue_class(set->p[i], pos, &m, &r) < 0)
+ goto error;
+ isl_int_gcd(*modulo, *modulo, m);
+ isl_int_sub(m, *residue, r);
+ isl_int_gcd(*modulo, *modulo, m);
+ if (!isl_int_is_zero(*modulo))
+ isl_int_fdiv_r(*residue, *residue, *modulo);
+ if (isl_int_is_one(*modulo))
+ break;
+ }
+
+ isl_int_clear(m);
+ isl_int_clear(r);
+
+ return 0;
+error:
+ isl_int_clear(m);
+ isl_int_clear(r);
+ return -1;
+}
+
+/* Check if dimension "dim" belongs to a residue class
+ * i_dim \equiv r mod m
+ * with m != 1 and if so return m in *modulo and r in *residue.
+ * As a special case, when i_dim has a fixed value v, then
+ * *modulo is set to 0 and *residue to v.
+ *
+ * If i_dim does not belong to such a residue class, then *modulo
+ * is set to 1 and *residue is set to 0.
+ */
+int isl_set_dim_residue_class_val(__isl_keep isl_set *set,
+ int pos, __isl_give isl_val **modulo, __isl_give isl_val **residue)
+{
+ *modulo = NULL;
+ *residue = NULL;
+ if (!set)
+ return -1;
+ *modulo = isl_val_alloc(isl_set_get_ctx(set));
+ *residue = isl_val_alloc(isl_set_get_ctx(set));
+ if (!*modulo || !*residue)
+ goto error;
+ if (isl_set_dim_residue_class(set, pos,
+ &(*modulo)->n, &(*residue)->n) < 0)
+ goto error;
+ isl_int_set_si((*modulo)->d, 1);
+ isl_int_set_si((*residue)->d, 1);
+ return 0;
+error:
+ isl_val_free(*modulo);
+ isl_val_free(*residue);
+ return -1;
+}