isl_basic_set_sample: remove equalities first
authorSven Verdoolaege <skimo@kotnet.org>
Sun, 10 Aug 2008 21:13:10 +0000 (23:13 +0200)
committerSven Verdoolaege <skimo@kotnet.org>
Mon, 25 Aug 2008 08:11:28 +0000 (10:11 +0200)
13 files changed:
Makefile.am
include/isl_blk.h
include/isl_int.h
include/isl_seq.h
isl_blk.c
isl_equalities.c [new file with mode: 0644]
isl_equalities.h [new file with mode: 0644]
isl_map.c
isl_map_private.h
isl_mat.c [new file with mode: 0644]
isl_mat.h [new file with mode: 0644]
isl_sample.c
isl_seq.c

index 6d8dd3e..d074a3f 100644 (file)
@@ -35,6 +35,8 @@ libisl_la_SOURCES = \
        isl_blk.h \
        isl_ctx.c \
        isl_ctx.h \
+       isl_equalities.c \
+       isl_equalities.h \
        isl_gmp.c \
        isl_int.h \
        isl_lp.h \
@@ -43,6 +45,8 @@ libisl_la_SOURCES = \
        isl_map.h \
        isl_map_affine_hull.c \
        isl_map_private.h \
+       isl_mat.c \
+       isl_mat.h \
        isl_sample.h \
        isl_sample.c \
        isl_set.h \
index f46a0f1..dd9e2ca 100644 (file)
@@ -14,6 +14,7 @@ struct isl_blk {
 };
 
 struct isl_blk isl_blk_alloc(struct isl_ctx *ctx, size_t n);
+struct isl_blk isl_blk_empty();
 struct isl_blk isl_blk_extend(struct isl_ctx *ctx, struct isl_blk block,
                                size_t new_n);
 void isl_blk_free(struct isl_ctx *ctx, struct isl_blk block);
index 731e240..770e0d1 100644 (file)
@@ -31,6 +31,7 @@ typedef mpz_t isl_int;
 #define isl_int_sub(r,i,j)     mpz_sub(r,i,j)
 #define isl_int_mul(r,i,j)     mpz_mul(r,i,j)
 #define isl_int_addmul(r,i,j)  mpz_addmul(r,i,j)
+#define isl_int_submul(r,i,j)  mpz_submul(r,i,j)
 
 #define isl_int_gcd(r,i,j)     mpz_gcd(r,i,j)
 #define isl_int_lcm(r,i,j)     mpz_lcm(r,i,j)
index 120182b..e909d84 100644 (file)
@@ -9,11 +9,14 @@
 void isl_seq_clr(isl_int *p, unsigned len);
 void isl_seq_neg(isl_int *dat, isl_int *src, unsigned len);
 void isl_seq_cpy(isl_int *dst, isl_int *src, unsigned len);
+void isl_seq_swp_or_cpy(isl_int *dst, isl_int *src, unsigned len);
 void isl_seq_scale(isl_int *dst, isl_int *src, isl_int f, unsigned len);
 void isl_seq_scale_down(isl_int *dst, isl_int *src, isl_int f, unsigned len);
 void isl_seq_elim(isl_int *dst, isl_int *src, unsigned pos, unsigned len,
                  isl_int *m);
 void isl_seq_gcd(isl_int *p, unsigned len, isl_int *gcd);
+void isl_seq_inner_product(isl_int *p1, isl_int *p2, unsigned len,
+                          isl_int *prod);
 int isl_seq_first_non_zero(isl_int *p, unsigned len);
 int isl_seq_abs_min_non_zero(isl_int *p, unsigned len);
 int isl_seq_eq(isl_int *p1, isl_int *p2, unsigned len);
index a7a4496..0cb833c 100644 (file)
--- a/isl_blk.c
+++ b/isl_blk.c
@@ -1,5 +1,13 @@
 #include "isl_blk.h"
 
+struct isl_blk isl_blk_empty()
+{
+       struct isl_blk block;
+       block.size = -1;
+       block.data = NULL;
+       return block;
+}
+
 struct isl_blk isl_blk_alloc(struct isl_ctx *ctx, size_t n)
 {
        struct isl_blk block;
diff --git a/isl_equalities.c b/isl_equalities.c
new file mode 100644 (file)
index 0000000..408d2dd
--- /dev/null
@@ -0,0 +1,140 @@
+#include "isl_mat.h"
+#include "isl_map_private.h"
+#include "isl_equalities.h"
+
+/* Use the n equalities of bset to unimodularly transform the
+ * variables x such that n transformed variables x1' have a constant value
+ * and rewrite the constraints of bset in terms of the remaining
+ * transformed variables x2'.  The matrix pointed to by T maps
+ * the new variables x2' back to the original variables x, while T2
+ * maps the original variables to the new variables.
+ *
+ * Let the equalities of bset be
+ *
+ *             M x - c = 0
+ *
+ * Compute the (left) Hermite normal form of M,
+ *
+ *             M [U1 U2] = M U = H = [H1 0]
+ * or
+ *                           M = H Q = [H1 0] [Q1]
+ *                                             [Q2]
+ *
+ * with U, Q unimodular, Q = U^{-1} (and H lower triangular).
+ * Define the transformed variables as
+ *
+ *             x = [U1 U2] [ x1' ] = [U1 U2] [Q1] x
+ *                         [ x2' ]           [Q2]
+ *
+ * The equalities then become
+ *
+ *             H1 x1' - c = 0   or   x1' = H1^{-1} c = c'
+ *
+ * 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).
+ * Otherwise, the transformation is given by
+ *
+ *             x = U1 H1^{-1} c + U2 x2'
+ *
+ * The inverse transformation is simply
+ *
+ *             x2' = Q2 x
+ */
+static struct isl_basic_set *compress_variables(struct isl_ctx *ctx,
+       struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2)
+{
+       int i;
+       struct isl_mat *H = NULL, *C = NULL, *H1, *U = NULL, *U1, *U2, *TC;
+
+       if (T)
+               *T = NULL;
+       if (T2)
+               *T2 = NULL;
+       if (!bset)
+               goto error;
+       isl_assert(ctx, bset->nparam == 0, goto error);
+       isl_assert(ctx, bset->n_div == 0, goto error);
+       isl_assert(ctx, bset->n_eq <= bset->dim, goto error);
+       if (bset->n_eq == 0)
+               return bset;
+
+       H = isl_mat_sub_alloc(ctx, bset->eq, 0, bset->n_eq, 1, bset->dim);
+       H = isl_mat_left_hermite(ctx, H, &U, T2);
+       if (!H || !U || (T2 && !*T2))
+               goto error;
+       if (T2) {
+               *T2 = isl_mat_drop_rows(ctx, *T2, 0, bset->n_eq);
+               *T2 = isl_mat_lin_to_aff(ctx, *T2);
+               if (!*T2)
+                       goto error;
+       }
+       C = isl_mat_alloc(ctx, 1+bset->n_eq, 1);
+       if (!C)
+               goto error;
+       isl_int_set_si(C->row[0][0], 1);
+       isl_mat_sub_neg(ctx, C->row+1, bset->eq, bset->n_eq, 0, 0, 1);
+       H1 = isl_mat_sub_alloc(ctx, H->row, 0, H->n_row, 0, H->n_row);
+       H1 = isl_mat_lin_to_aff(ctx, H1);
+       TC = isl_mat_inverse_product(ctx, H1, C);
+       if (!TC)
+               goto error;
+       isl_mat_free(ctx, H);
+       if (!isl_int_is_one(TC->row[0][0])) {
+               for (i = 0; i < bset->n_eq; ++i) {
+                       if (!isl_int_is_divisible_by(TC->row[1+i][0], TC->row[0][0])) {
+                               isl_mat_free(ctx, TC);
+                               isl_mat_free(ctx, U);
+                               if (T2) {
+                                       isl_mat_free(ctx, *T2);
+                                       *T2 = NULL;
+                               }
+                               return isl_basic_set_set_to_empty(ctx, bset);
+                       }
+                       isl_seq_scale_down(TC->row[1+i], TC->row[1+i], TC->row[0][0], 1);
+               }
+               isl_int_set_si(TC->row[0][0], 1);
+       }
+       U1 = isl_mat_sub_alloc(ctx, U->row, 0, U->n_row, 0, bset->n_eq);
+       U1 = isl_mat_lin_to_aff(ctx, U1);
+       U2 = isl_mat_sub_alloc(ctx, U->row, 0, U->n_row,
+                               bset->n_eq, U->n_row - bset->n_eq);
+       U2 = isl_mat_lin_to_aff(ctx, U2);
+       isl_mat_free(ctx, U);
+       TC = isl_mat_product(ctx, U1, TC);
+       TC = isl_mat_aff_direct_sum(ctx, TC, U2);
+       bset = isl_basic_set_preimage(ctx, bset, T ? isl_mat_copy(ctx, TC) : TC);
+       if (T)
+               *T = TC;
+       return bset;
+error:
+       isl_mat_free(ctx, H);
+       isl_mat_free(ctx, U);
+       if (T2)
+               isl_mat_free(ctx, *T2);
+       isl_basic_set_free(ctx, bset);
+       if (T)
+               *T = NULL;
+       if (T2)
+               *T2 = NULL;
+       return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_remove_equalities(struct isl_ctx *ctx,
+       struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2)
+{
+       isl_assert(ctx, bset->nparam == 0, goto error);
+       if (T)
+               *T = NULL;
+       if (T2)
+               *T2 = NULL;
+       bset = isl_basic_set_gauss(ctx, bset, NULL);
+       if (F_ISSET(bset, ISL_BASIC_SET_EMPTY))
+               return bset;
+       bset = compress_variables(ctx, bset, T, T2);
+       return bset;
+error:
+       isl_basic_set_free(ctx, bset);
+       *T = NULL;
+       return NULL;
+}
diff --git a/isl_equalities.h b/isl_equalities.h
new file mode 100644 (file)
index 0000000..e579fbe
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef ISL_EQUALITIES_H
+#define ISL_EQUALITIES_H
+
+#include <isl_set.h>
+#include <isl_mat.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_basic_set *isl_basic_set_remove_equalities(struct isl_ctx *ctx,
+       struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
index 0a8e55d..f84169a 100644 (file)
--- a/isl_map.c
+++ b/isl_map.c
@@ -423,7 +423,7 @@ struct isl_basic_set *isl_basic_set_extend(struct isl_ctx *ctx,
                                        nparam, 0, dim, extra, n_eq, n_ineq);
 }
 
-static struct isl_basic_set *isl_basic_set_cow(struct isl_ctx *ctx,
+struct isl_basic_set *isl_basic_set_cow(struct isl_ctx *ctx,
                struct isl_basic_set *bset)
 {
        return (struct isl_basic_set *)
@@ -674,6 +674,13 @@ error:
        return NULL;
 }
 
+struct isl_basic_set *isl_basic_set_set_to_empty(
+               struct isl_ctx *ctx, struct isl_basic_set *bset)
+{
+       return (struct isl_basic_set *)
+               isl_basic_map_set_to_empty(ctx, (struct isl_basic_map *)bset);
+}
+
 static void swap_equality(struct isl_basic_map *bmap, int a, int b)
 {
        isl_int *t = bmap->eq[a];
@@ -788,6 +795,13 @@ struct isl_basic_map *isl_basic_map_gauss(struct isl_ctx *ctx,
        return bmap;
 }
 
+struct isl_basic_set *isl_basic_set_gauss(struct isl_ctx *ctx,
+       struct isl_basic_set *bset, int *progress)
+{
+       return (struct isl_basic_set*)isl_basic_map_gauss(ctx,
+                       (struct isl_basic_map *)bset, progress);
+}
+
 static unsigned int round_up(unsigned int v)
 {
        int old_v = v;
index 34c4471..d93e53a 100644 (file)
@@ -17,12 +17,16 @@ int isl_basic_map_free_div(struct isl_ctx *ctx,
 int isl_inequality_negate(struct isl_ctx *ctx,
                struct isl_basic_map *bmap, unsigned pos);
 
+struct isl_basic_set *isl_basic_set_cow(struct isl_ctx *ctx,
+               struct isl_basic_set *bset);
 struct isl_basic_map *isl_basic_map_cow(struct isl_ctx *ctx,
                struct isl_basic_map *bmap);
 struct isl_map *isl_map_cow(struct isl_ctx *ctx, struct isl_map *map);
 
 struct isl_basic_map *isl_basic_map_set_to_empty(
                struct isl_ctx *ctx, struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_set_set_to_empty(
+               struct isl_ctx *ctx, struct isl_basic_set *bset);
 struct isl_map *isl_basic_map_compute_divs(struct isl_ctx *ctx,
                struct isl_basic_map *bmap);
 struct isl_map *isl_map_compute_divs(struct isl_ctx *ctx, struct isl_map *map);
@@ -30,3 +34,5 @@ struct isl_basic_map *isl_basic_map_align_divs(struct isl_ctx *ctx,
                struct isl_basic_map *dst, struct isl_basic_map *src);
 struct isl_basic_map *isl_basic_map_gauss(struct isl_ctx *ctx,
        struct isl_basic_map *bmap, int *progress);
+struct isl_basic_set *isl_basic_set_gauss(struct isl_ctx *ctx,
+       struct isl_basic_set *bset, int *progress);
diff --git a/isl_mat.c b/isl_mat.c
new file mode 100644 (file)
index 0000000..15c6b49
--- /dev/null
+++ b/isl_mat.c
@@ -0,0 +1,671 @@
+#include "isl_seq.h"
+#include "isl_mat.h"
+#include "isl_map_private.h"
+
+struct isl_mat *isl_mat_alloc(struct isl_ctx *ctx,
+       unsigned n_row, unsigned n_col)
+{
+       int i;
+       struct isl_mat *mat;
+
+       mat = isl_alloc_type(ctx, struct isl_mat);
+       if (!mat)
+               return NULL;
+
+       mat->block.size = 0;
+       mat->row = NULL;
+       mat->block = isl_blk_alloc(ctx, n_row * n_col);
+       if (!mat->block.data)
+               goto error;
+       mat->row = isl_alloc_array(ctx, isl_int *, n_row);
+       if (!mat->row)
+               goto error;
+
+       for (i = 0; i < n_row; ++i)
+               mat->row[i] = mat->block.data + i * n_col;
+
+       mat->ref = 1;
+       mat->n_row = n_row;
+       mat->n_col = n_col;
+       mat->flags = 0;
+
+       return mat;
+error:
+       isl_blk_free(ctx, mat->block);
+       free(mat);
+       return NULL;
+}
+
+struct isl_mat *isl_mat_sub_alloc(struct isl_ctx *ctx, isl_int **row,
+       unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col)
+{
+       int i;
+       struct isl_mat *mat;
+
+       mat = isl_alloc_type(ctx, struct isl_mat);
+       if (!mat)
+               return NULL;
+       mat->row = isl_alloc_array(ctx, isl_int *, n_row);
+       if (!mat->row)
+               goto error;
+       for (i = 0; i < n_row; ++i)
+               mat->row[i] = row[first_row+i] + first_col;
+       mat->ref = 1;
+       mat->n_row = n_row;
+       mat->n_col = n_col;
+       mat->block = isl_blk_empty();
+       mat->flags = ISL_MAT_BORROWED;
+       return mat;
+error:
+       free(mat);
+       return NULL;
+}
+
+void isl_mat_sub_copy(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+       unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col)
+{
+       int i;
+
+       for (i = 0; i < n_row; ++i)
+               isl_seq_cpy(dst[i]+dst_col, src[i]+src_col, n_col);
+}
+
+void isl_mat_sub_neg(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+       unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col)
+{
+       int i;
+
+       for (i = 0; i < n_row; ++i)
+               isl_seq_neg(dst[i]+dst_col, src[i]+src_col, n_col);
+}
+
+struct isl_mat *isl_mat_copy(struct isl_ctx *ctx, struct isl_mat *mat)
+{
+       if (!mat)
+               return NULL;
+
+       mat->ref++;
+       return mat;
+}
+
+struct isl_mat *isl_mat_dup(struct isl_ctx *ctx, struct isl_mat *mat)
+{
+       int i;
+       struct isl_mat *mat2;
+
+       if (!mat)
+               return NULL;
+       mat2 = isl_mat_alloc(ctx, mat->n_row, mat->n_col);
+       if (!mat2)
+               return NULL;
+       for (i = 0; i < mat->n_row; ++i)
+               isl_seq_cpy(mat2->row[i], mat->row[i], mat->n_col);
+       return mat2;
+}
+
+struct isl_mat *isl_mat_cow(struct isl_ctx *ctx, struct isl_mat *mat)
+{
+       struct isl_mat *mat2;
+       if (!mat)
+               return NULL;
+
+       if (mat->ref == 1 && !F_ISSET(mat, ISL_MAT_BORROWED))
+               return mat;
+
+       mat2 = isl_mat_dup(ctx, mat);
+       isl_mat_free(ctx, mat);
+       return mat2;
+}
+
+void isl_mat_free(struct isl_ctx *ctx, struct isl_mat *mat)
+{
+       if (!mat)
+               return;
+
+       if (--mat->ref > 0)
+               return;
+
+       if (!F_ISSET(mat, ISL_MAT_BORROWED))
+               isl_blk_free(ctx, mat->block);
+       free(mat->row);
+       free(mat);
+}
+
+struct isl_mat *isl_mat_identity(struct isl_ctx *ctx, unsigned n_row)
+{
+       int i;
+       struct isl_mat *mat;
+
+       mat = isl_mat_alloc(ctx, n_row, n_row);
+       if (!mat)
+               return NULL;
+       for (i = 0; i < n_row; ++i) {
+               isl_seq_clr(mat->row[i], i);
+               isl_int_set_si(mat->row[i][i], 1);
+               isl_seq_clr(mat->row[i]+i+1, n_row-(i+1));
+       }
+
+       return mat;
+}
+
+struct isl_vec *isl_mat_vec_product(struct isl_ctx *ctx,
+       struct isl_mat *mat, struct isl_vec *vec)
+{
+       int i;
+       struct isl_vec *prod;
+
+       if (!mat || !vec)
+               goto error;
+
+       isl_assert(ctx, mat->n_col == vec->size, goto error);
+
+       prod = isl_vec_alloc(ctx, mat->n_row);
+       if (!prod)
+               goto error;
+
+       for (i = 0; i < prod->size; ++i)
+               isl_seq_inner_product(mat->row[i], vec->block.data, vec->size,
+                                       &prod->block.data[i]);
+       isl_mat_free(ctx, mat);
+       isl_vec_free(ctx, vec);
+       return prod;
+error:
+       isl_mat_free(ctx, mat);
+       isl_vec_free(ctx, vec);
+       return NULL;
+}
+
+struct isl_mat *isl_mat_aff_direct_sum(struct isl_ctx *ctx,
+       struct isl_mat *left, struct isl_mat *right)
+{
+       int i;
+       struct isl_mat *sum;
+
+       if (!left || !right)
+               goto error;
+
+       isl_assert(ctx, left->n_row == right->n_row, goto error);
+       isl_assert(ctx, left->n_row >= 1, goto error);
+       isl_assert(ctx, left->n_col >= 1, goto error);
+       isl_assert(ctx, right->n_col >= 1, goto error);
+       isl_assert(ctx,
+           isl_seq_first_non_zero(left->row[0]+1, left->n_col-1) == -1,
+           goto error);
+       isl_assert(ctx,
+           isl_seq_first_non_zero(right->row[0]+1, right->n_col-1) == -1,
+           goto error);
+
+       sum = isl_mat_alloc(ctx, left->n_row, left->n_col + right->n_col - 1);
+       if (!sum)
+               goto error;
+       isl_int_lcm(sum->row[0][0], left->row[0][0], right->row[0][0]);
+       isl_int_divexact(left->row[0][0], sum->row[0][0], left->row[0][0]);
+       isl_int_divexact(right->row[0][0], sum->row[0][0], right->row[0][0]);
+
+       isl_seq_clr(sum->row[0]+1, sum->n_col-1);
+       for (i = 1; i < sum->n_row; ++i) {
+               isl_int_mul(sum->row[i][0], left->row[0][0], left->row[i][0]);
+               isl_int_addmul(sum->row[i][0],
+                               right->row[0][0], right->row[i][0]);
+               isl_seq_scale(sum->row[i]+1, left->row[i]+1, left->row[0][0],
+                               left->n_col-1);
+               isl_seq_scale(sum->row[i]+left->n_col,
+                               right->row[i]+1, right->row[0][0],
+                               right->n_col-1);
+       }
+
+       isl_int_divexact(left->row[0][0], sum->row[0][0], left->row[0][0]);
+       isl_int_divexact(right->row[0][0], sum->row[0][0], right->row[0][0]);
+       isl_mat_free(ctx, left);
+       isl_mat_free(ctx, right);
+       return sum;
+error:
+       isl_mat_free(ctx, left);
+       isl_mat_free(ctx, right);
+       return NULL;
+}
+
+static void exchange(struct isl_ctx *ctx, struct isl_mat *M, struct isl_mat **U,
+       struct isl_mat **Q, unsigned row, unsigned i, unsigned j)
+{
+       int r;
+       for (r = row; r < M->n_row; ++r)
+               isl_int_swap(M->row[r][i], M->row[r][j]);
+       if (U) {
+               for (r = 0; r < (*U)->n_row; ++r)
+                       isl_int_swap((*U)->row[r][i], (*U)->row[r][j]);
+       }
+       if (Q)
+               isl_mat_swap_rows(ctx, *Q, i, j);
+}
+
+static void subtract(struct isl_ctx *ctx, struct isl_mat *M, struct isl_mat **U,
+       struct isl_mat **Q, unsigned row, unsigned i, unsigned j, isl_int m)
+{
+       int r, c;
+       for (r = row; r < M->n_row; ++r)
+               isl_int_submul(M->row[r][j], m, M->row[r][i]);
+       if (U) {
+               for (r = 0; r < (*U)->n_row; ++r)
+                       isl_int_submul((*U)->row[r][j], m, (*U)->row[r][i]);
+       }
+       if (Q) {
+               for (r = 0; r < (*Q)->n_col; ++r)
+                       isl_int_addmul((*Q)->row[i][r], m, (*Q)->row[j][r]);
+       }
+}
+
+static void oppose(struct isl_ctx *ctx, struct isl_mat *M, struct isl_mat **U,
+       struct isl_mat **Q, unsigned row, unsigned col)
+{
+       int r;
+       for (r = row; r < M->n_row; ++r)
+               isl_int_neg(M->row[r][col], M->row[r][col]);
+       if (U) {
+               for (r = 0; r < (*U)->n_row; ++r)
+                       isl_int_neg((*U)->row[r][col], (*U)->row[r][col]);
+       }
+       if (Q)
+               isl_seq_neg((*Q)->row[col], (*Q)->row[col], (*Q)->n_col);
+}
+
+/* Given matrix M, compute
+ *
+ *             M U = H
+ *             M   = H Q
+ *
+ * with U and Q unimodular matrices and H a matrix in column echelon form
+ * such that on each echelon row the entries in the non-echelon column
+ * are non-negative and stricly smaller than the entries in the echelon
+ * column.  If U or Q are NULL, then these matrices are not computed.
+ */
+struct isl_mat *isl_mat_left_hermite(struct isl_ctx *ctx,
+       struct isl_mat *M, struct isl_mat **U, struct isl_mat **Q)
+{
+       isl_int c;
+       int row, col;
+
+       if (U)
+               *U = NULL;
+       if (Q)
+               *Q = NULL;
+       if (!M)
+               goto error;
+       M = isl_mat_cow(ctx, M);
+       if (!M)
+               goto error;
+       if (U) {
+               *U = isl_mat_identity(ctx, M->n_col);
+               if (!*U)
+                       goto error;
+       }
+       if (Q) {
+               *Q = isl_mat_identity(ctx, M->n_col);
+               if (!*Q)
+                       goto error;
+       }
+
+       col = 0;
+       isl_int_init(c);
+       for (row = 0; row < M->n_row; ++row) {
+               int first, i, off;
+               first = isl_seq_abs_min_non_zero(M->row[row]+col, M->n_col-col);
+               if (first == -1)
+                       continue;
+               first += col;
+               if (first != col)
+                       exchange(ctx, M, U, Q, row, first, col);
+               if (isl_int_is_neg(M->row[row][col]))
+                       oppose(ctx, M, U, Q, row, col);
+               first = col+1;
+               while ((off = isl_seq_first_non_zero(M->row[row]+first,
+                                                      M->n_col-first)) != -1) {
+                       first += off;
+                       isl_int_fdiv_q(c, M->row[row][first], M->row[row][col]);
+                       subtract(ctx, M, U, Q, row, col, first, c);
+                       if (!isl_int_is_zero(M->row[row][first]))
+                               exchange(ctx, M, U, Q, row, first, col);
+                       else
+                               ++first;
+               }
+               for (i = 0; i < col; ++i) {
+                       if (isl_int_is_zero(M->row[row][i]))
+                               continue;
+                       isl_int_fdiv_q(c, M->row[row][i], M->row[row][col]);
+                       if (isl_int_is_zero(c))
+                               continue;
+                       subtract(ctx, M, U, Q, row, col, i, c);
+               }
+               ++col;
+       }
+       isl_int_clear(c);
+
+       return M;
+error:
+       if (Q) {
+               isl_mat_free(ctx, *Q);
+               *Q = NULL;
+       }
+       if (U) {
+               isl_mat_free(ctx, *U);
+               *U = NULL;
+       }
+       return NULL;
+}
+
+struct isl_mat *isl_mat_lin_to_aff(struct isl_ctx *ctx, struct isl_mat *mat)
+{
+       int i;
+       struct isl_mat *mat2;
+
+       if (!mat)
+               return NULL;
+       mat2 = isl_mat_alloc(ctx, 1+mat->n_row, 1+mat->n_col);
+       if (!mat2)
+               return NULL;
+       isl_int_set_si(mat2->row[0][0], 1);
+       isl_seq_clr(mat2->row[0]+1, mat->n_col);
+       for (i = 0; i < mat->n_row; ++i) {
+               isl_int_set_si(mat2->row[1+i][0], 0);
+               isl_seq_cpy(mat2->row[1+i]+1, mat->row[i], mat->n_col);
+       }
+       isl_mat_free(ctx, mat);
+       return mat2;
+}
+
+static int row_first_non_zero(isl_int **row, unsigned n_row, unsigned col)
+{
+       int i;
+
+       for (i = 0; i < n_row; ++i)
+               if (!isl_int_is_zero(row[i][col]))
+                       return i;
+       return -1;
+}
+
+static int row_abs_min_non_zero(isl_int **row, unsigned n_row, unsigned col)
+{
+       int i, min = row_first_non_zero(row, n_row, col);
+       if (min < 0)
+               return -1;
+       for (i = min + 1; i < n_row; ++i) {
+               if (isl_int_is_zero(row[i][col]))
+                       continue;
+               if (isl_int_abs_lt(row[i][col], row[min][col]))
+                       min = i;
+       }
+       return min;
+}
+
+static void inv_exchange(struct isl_ctx *ctx,
+       struct isl_mat *left, struct isl_mat *right,
+       unsigned i, unsigned j)
+{
+       left = isl_mat_swap_rows(ctx, left, i, j);
+       right = isl_mat_swap_rows(ctx, right, i, j);
+}
+
+static void inv_oppose(struct isl_ctx *ctx,
+       struct isl_mat *left, struct isl_mat *right, unsigned row)
+{
+       isl_seq_neg(left->row[row]+row, left->row[row]+row, left->n_col-row);
+       isl_seq_neg(right->row[row], right->row[row], right->n_col);
+}
+
+static void inv_subtract(struct isl_ctx *ctx,
+       struct isl_mat *left, struct isl_mat *right,
+       unsigned row, unsigned i, isl_int m)
+{
+       isl_int_neg(m, m);
+       isl_seq_combine(left->row[i]+row,
+                       ctx->one, left->row[i]+row,
+                       m, left->row[row]+row,
+                       left->n_col-row);
+       isl_seq_combine(right->row[i], ctx->one, right->row[i],
+                       m, right->row[row], right->n_col);
+}
+
+/* Compute inv(left)*right
+ */
+struct isl_mat *isl_mat_inverse_product(struct isl_ctx *ctx,
+       struct isl_mat *left, struct isl_mat *right)
+{
+       int row;
+       isl_int a, b;
+
+       if (!left || !right)
+               goto error;
+
+       isl_assert(ctx, left->n_row == left->n_col, goto error);
+       isl_assert(ctx, left->n_row == right->n_row, goto error);
+
+       if (left->n_row == 0) {
+               isl_mat_free(ctx, left);
+               return right;
+       }
+
+       left = isl_mat_cow(ctx, left);
+       right = isl_mat_cow(ctx, right);
+       if (!left || !right)
+               goto error;
+
+       isl_int_init(a);
+       isl_int_init(b);
+       for (row = 0; row < left->n_row; ++row) {
+               int pivot, first, i, off;
+               pivot = row_abs_min_non_zero(left->row+row, left->n_row-row, row);
+               if (pivot < 0) {
+                       isl_int_clear(a);
+                       isl_int_clear(b);
+                       isl_assert(ctx, pivot >= 0, goto error);
+               }
+               pivot += row;
+               if (pivot != row)
+                       inv_exchange(ctx, left, right, pivot, row);
+               if (isl_int_is_neg(left->row[row][row]))
+                       inv_oppose(ctx, left, right, row);
+               first = row+1;
+               while ((off = row_first_non_zero(left->row+first,
+                                       left->n_row-first, row)) != -1) {
+                       first += off;
+                       isl_int_fdiv_q(a, left->row[first][row],
+                                       left->row[row][row]);
+                       inv_subtract(ctx, left, right, row, first, a);
+                       if (!isl_int_is_zero(left->row[first][row]))
+                               inv_exchange(ctx, left, right, row, first);
+                       else
+                               ++first;
+               }
+               for (i = 0; i < row; ++i) {
+                       if (isl_int_is_zero(left->row[i][row]))
+                               continue;
+                       isl_int_gcd(a, left->row[row][row], left->row[i][row]);
+                       isl_int_divexact(b, left->row[i][row], a);
+                       isl_int_divexact(a, left->row[row][row], a);
+                       isl_int_neg(a, a);
+                       isl_seq_combine(left->row[i]+row,
+                                       a, left->row[i]+row,
+                                       b, left->row[row]+row,
+                                       left->n_col-row);
+                       isl_seq_combine(right->row[i], a, right->row[i],
+                                       b, right->row[row], right->n_col);
+               }
+       }
+       isl_int_clear(b);
+
+       isl_int_set(a, left->row[0][0]);
+       for (row = 1; row < left->n_row; ++row)
+               isl_int_lcm(a, a, left->row[row][row]);
+       if (isl_int_is_zero(a)){
+               isl_int_clear(a);
+               isl_assert(ctx, 0, goto error);
+       }
+       for (row = 0; row < left->n_row; ++row) {
+               isl_int_divexact(left->row[row][row], a, left->row[row][row]);
+               if (isl_int_is_one(left->row[row][row]))
+                       continue;
+               isl_seq_scale(right->row[row], right->row[row],
+                               left->row[row][row], right->n_col);
+       }
+       isl_int_clear(a);
+
+       isl_mat_free(ctx, left);
+       return right;
+error:
+       isl_mat_free(ctx, left);
+       isl_mat_free(ctx, right);
+       return NULL;
+}
+
+struct isl_mat *isl_mat_swap_rows(struct isl_ctx *ctx,
+       struct isl_mat *mat, unsigned i, unsigned j)
+{
+       isl_int *t;
+
+       if (!mat)
+               return NULL;
+       mat = isl_mat_cow(ctx, mat);
+       if (!mat)
+               return NULL;
+       t = mat->row[i];
+       mat->row[i] = mat->row[j];
+       mat->row[j] = t;
+       return mat;
+}
+
+struct isl_mat *isl_mat_product(struct isl_ctx *ctx,
+       struct isl_mat *left, struct isl_mat *right)
+{
+       int i, j, k;
+       struct isl_mat *prod;
+
+       if (!left || !right)
+               goto error;
+       isl_assert(ctx, left->n_col == right->n_row, goto error);
+       prod = isl_mat_alloc(ctx, left->n_row, right->n_col);
+       if (!prod)
+               goto error;
+       if (left->n_col == 0) {
+               for (i = 0; i < prod->n_row; ++i)
+                       isl_seq_clr(prod->row[i], prod->n_col);
+               return prod;
+       }
+       for (i = 0; i < prod->n_row; ++i) {
+               for (j = 0; j < prod->n_col; ++j) {
+                       isl_int_mul(prod->row[i][j],
+                                   left->row[i][0], right->row[0][j]);
+                       for (k = 1; k < left->n_col; ++k)
+                               isl_int_addmul(prod->row[i][j],
+                                           left->row[i][k], right->row[k][j]);
+               }
+       }
+       isl_mat_free(ctx, left);
+       isl_mat_free(ctx, right);
+       return prod;
+error:
+       isl_mat_free(ctx, left);
+       isl_mat_free(ctx, right);
+       return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_preimage(struct isl_ctx *ctx,
+       struct isl_basic_set *bset, struct isl_mat *mat)
+{
+       struct isl_mat *t;
+       int i;
+
+       if (!bset || !mat)
+               goto error;
+
+       bset = isl_basic_set_cow(ctx, bset);
+       if (!bset)
+               goto error;
+
+       isl_assert(ctx, bset->nparam == 0, goto error);
+       isl_assert(ctx, bset->n_div == 0, goto error);
+       isl_assert(ctx, 1+bset->dim == mat->n_row, goto error);
+
+       t = isl_mat_sub_alloc(ctx, bset->eq, 0, bset->n_eq, 0, mat->n_row);
+       t = isl_mat_product(ctx, t, isl_mat_copy(ctx, mat));
+       if (!t)
+               goto error;
+       for (i = 0; i < bset->n_eq; ++i)
+               isl_seq_swp_or_cpy(bset->eq[i], t->row[i], t->n_col);
+       isl_mat_free(ctx, t);
+
+       t = isl_mat_sub_alloc(ctx, bset->ineq, 0, bset->n_ineq, 0, mat->n_row);
+       t = isl_mat_product(ctx, t, isl_mat_copy(ctx, mat));
+       if (!t)
+               goto error;
+       for (i = 0; i < bset->n_ineq; ++i)
+               isl_seq_swp_or_cpy(bset->ineq[i], t->row[i], t->n_col);
+       isl_mat_free(ctx, t);
+
+       bset->dim -= mat->n_row - mat->n_col;
+       bset = isl_basic_set_simplify(ctx, bset);
+       bset = isl_basic_set_finalize(ctx, bset);
+
+       isl_mat_free(ctx, mat);
+       return bset;
+error:
+       isl_mat_free(ctx, mat);
+       isl_basic_set_free(ctx, bset);
+       return NULL;
+}
+
+void isl_mat_dump(struct isl_ctx *ctx, struct isl_mat *mat,
+                               FILE *out, int indent)
+{
+       int i, j;
+
+       if (mat->n_row == 0)
+               fprintf(out, "%*s[]\n", indent, "");
+
+       for (i = 0; i < mat->n_row; ++i) {
+               if (!i)
+                       fprintf(out, "%*s[[", indent, "");
+               else
+                       fprintf(out, "%*s[", indent+1, "");
+               for (j = 0; j < mat->n_col; ++j) {
+                       if (j)
+                           fprintf(out, ",");
+                       isl_int_print(out, mat->row[i][j]);
+               }
+               if (i == mat->n_row-1)
+                       fprintf(out, "]]\n");
+               else
+                       fprintf(out, "]\n");
+       }
+}
+
+struct isl_mat *isl_mat_drop_col(struct isl_ctx *ctx, struct isl_mat *mat,
+                               unsigned col)
+{
+       int r;
+
+       if (!mat)
+               return NULL;
+
+       if (col != mat->n_col-1) {
+               for (r = 0; r < mat->n_row; ++r)
+                       isl_seq_cpy(mat->row[r]+col, mat->row[r]+col+1,
+                                       mat->n_col - col - 1);
+       }
+       mat->n_col--;
+       return mat;
+}
+
+struct isl_mat *isl_mat_drop_rows(struct isl_ctx *ctx, struct isl_mat *mat,
+                               unsigned row, unsigned n)
+{
+       int r;
+
+       if (!mat)
+               return NULL;
+
+       for (r = row; r+n < mat->n_row; ++r)
+               mat->row[r] = mat->row[r+n];
+
+       mat->n_row -= n;
+       return mat;
+}
diff --git a/isl_mat.h b/isl_mat.h
new file mode 100644 (file)
index 0000000..12346fa
--- /dev/null
+++ b/isl_mat.h
@@ -0,0 +1,74 @@
+#ifndef ISL_MAT_H
+#define ISL_MAT_H
+
+#include <stdio.h>
+
+#include <isl_int.h>
+#include <isl_ctx.h>
+#include <isl_blk.h>
+#include <isl_set.h>
+#include "isl_vec.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_mat {
+       int ref;
+
+#define ISL_MAT_BORROWED               (1 << 0)
+       unsigned flags;
+
+       unsigned n_row;
+       unsigned n_col;
+
+       isl_int **row;
+
+       struct isl_blk block;
+};
+
+struct isl_mat *isl_mat_alloc(struct isl_ctx *ctx,
+       unsigned n_row, unsigned n_col);
+struct isl_mat *isl_mat_identity(struct isl_ctx *ctx, unsigned n_row);
+struct isl_mat *isl_mat_copy(struct isl_ctx *ctx, struct isl_mat *mat);
+struct isl_mat *isl_mat_cow(struct isl_ctx *ctx, struct isl_mat *mat);
+void isl_mat_free(struct isl_ctx *ctx, struct isl_mat *mat);
+
+struct isl_mat *isl_mat_sub_alloc(struct isl_ctx *ctx, isl_int **row,
+       unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col);
+void isl_mat_sub_copy(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+       unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col);
+void isl_mat_sub_neg(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+       unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col);
+
+struct isl_mat *isl_mat_swap_rows(struct isl_ctx *ctx,
+       struct isl_mat *mat, unsigned i, unsigned j);
+
+struct isl_vec *isl_mat_vec_product(struct isl_ctx *ctx,
+       struct isl_mat *mat, struct isl_vec *vec);
+struct isl_mat *isl_mat_aff_direct_sum(struct isl_ctx *ctx,
+       struct isl_mat *left, struct isl_mat *right);
+struct isl_mat *isl_mat_left_hermite(struct isl_ctx *ctx,
+       struct isl_mat *M, struct isl_mat **U, struct isl_mat **Q);
+struct isl_mat *isl_mat_lin_to_aff(struct isl_ctx *ctx, struct isl_mat *mat);
+struct isl_mat *isl_mat_inverse_product(struct isl_ctx *ctx,
+       struct isl_mat *left, struct isl_mat *right);
+struct isl_mat *isl_mat_product(struct isl_ctx *ctx,
+       struct isl_mat *left, struct isl_mat *right);
+
+struct isl_mat *isl_mat_drop_col(struct isl_ctx *ctx, struct isl_mat *mat,
+                               unsigned col);
+struct isl_mat *isl_mat_drop_rows(struct isl_ctx *ctx, struct isl_mat *mat,
+                               unsigned row, unsigned n);
+
+struct isl_basic_set *isl_basic_set_preimage(struct isl_ctx *ctx,
+       struct isl_basic_set *bset, struct isl_mat *mat);
+
+void isl_mat_dump(struct isl_ctx *ctx, struct isl_mat *mat,
+                               FILE *out, int indent);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
index c218593..2dfaa0a 100644 (file)
@@ -1,13 +1,38 @@
 #include "isl_sample.h"
 #include "isl_sample_piplib.h"
 #include "isl_vec.h"
+#include "isl_mat.h"
+#include "isl_map_private.h"
+#include "isl_equalities.h"
 
 struct isl_vec *isl_basic_set_sample(struct isl_ctx *ctx,
        struct isl_basic_set *bset)
 {
+       if (!bset)
+               return NULL;
+
        if (F_ISSET(bset, ISL_BASIC_SET_EMPTY)) {
                isl_basic_set_free(ctx, bset);
                return isl_vec_alloc(ctx, 0);
        }
+
+       isl_assert(ctx, bset->nparam == 0, goto error);
+       isl_assert(ctx, bset->n_div == 0, goto error);
+
+       if (bset->n_eq > 0) {
+               struct isl_mat *T;
+               struct isl_vec *sample;
+
+               bset = isl_basic_set_remove_equalities(ctx, bset, &T, NULL);
+               sample = isl_basic_set_sample(ctx, bset);
+               if (sample && sample->size != 0)
+                       sample = isl_mat_vec_product(ctx, T, sample);
+               else
+                       isl_mat_free(ctx, T);
+               return sample;
+       }
        return isl_pip_basic_set_sample(ctx, bset);
+error:
+       isl_basic_set_free(ctx, bset);
+       return NULL;
 }
index 5d02804..bbffae5 100644 (file)
--- a/isl_seq.c
+++ b/isl_seq.c
@@ -21,6 +21,13 @@ void isl_seq_cpy(isl_int *dst, isl_int *src, unsigned len)
                isl_int_set(dst[i], src[i]);
 }
 
+void isl_seq_swp_or_cpy(isl_int *dst, isl_int *src, unsigned len)
+{
+       int i;
+       for (i = 0; i < len; ++i)
+               isl_int_swap_or_set(dst[i], src[i]);
+}
+
 void isl_seq_scale(isl_int *dst, isl_int *src, isl_int m, unsigned len)
 {
        int i;
@@ -147,6 +154,19 @@ void isl_seq_gcd(isl_int *p, unsigned len, isl_int *gcd)
        }
 }
 
+void isl_seq_inner_product(isl_int *p1, isl_int *p2, unsigned len,
+                          isl_int *prod)
+{
+       int i;
+       if (len == 0) {
+               isl_int_set_si(*prod, 0);
+               return;
+       }
+       isl_int_mul(*prod, p1[0], p2[0]);
+       for (i = 1; i < len; ++i)
+               isl_int_addmul(*prod, p1[i], p2[i]);
+}
+
 u_int32_t isl_seq_hash(isl_int *p, unsigned len, unsigned bits)
 {
        int i;