/* Make first row entries in column col of bset1 identical to * those of bset2, using the fact that entry bset1->eq[row][col]=a * is non-zero. Initially, these elements of bset1 are all zero. * For each row i < row, we set * A[i] = a * A[i] + B[i][col] * A[row] * B[i] = a * B[i] * so that * A[i][col] = B[i][col] = a * old(B[i][col]) */ static void construct_column( struct isl_basic_set *bset1, struct isl_basic_set *bset2, unsigned row, unsigned col) { int r; isl_int a; isl_int b; unsigned total; isl_int_init(a); isl_int_init(b); total = 1 + isl_basic_set_n_dim(bset1); for (r = 0; r < row; ++r) { if (isl_int_is_zero(bset2->eq[r][col])) continue; isl_int_gcd(b, bset2->eq[r][col], bset1->eq[row][col]); isl_int_divexact(a, bset1->eq[row][col], b); isl_int_divexact(b, bset2->eq[r][col], b); isl_seq_combine(bset1->eq[r], a, bset1->eq[r], b, bset1->eq[row], total); isl_seq_scale(bset2->eq[r], bset2->eq[r], a, total); } isl_int_clear(a); isl_int_clear(b); delete_row(bset1, row); }
/* Find an integer point in the set represented by "tab" * that lies outside of the equality "eq" e(x) = 0. * If "up" is true, look for a point satisfying e(x) - 1 >= 0. * Otherwise, look for a point satisfying -e(x) - 1 >= 0 (i.e., e(x) <= -1). * The point, if found, is returned. * If no point can be found, a zero-length vector is returned. * * Before solving an ILP problem, we first check if simply * adding the normal of the constraint to one of the known * integer points in the basic set represented by "tab" * yields another point inside the basic set. * * The caller of this function ensures that the tableau is bounded or * that tab->basis and tab->n_unbounded have been set appropriately. */ static struct isl_vec *outside_point(struct isl_tab *tab, isl_int *eq, int up) { struct isl_ctx *ctx; struct isl_vec *sample = NULL; struct isl_tab_undo *snap; unsigned dim; if (!tab) return NULL; ctx = tab->mat->ctx; dim = tab->n_var; sample = isl_vec_alloc(ctx, 1 + dim); if (!sample) return NULL; isl_int_set_si(sample->el[0], 1); isl_seq_combine(sample->el + 1, ctx->one, tab->bmap->sample->el + 1, up ? ctx->one : ctx->negone, eq + 1, dim); if (isl_basic_map_contains(tab->bmap, sample)) return sample; isl_vec_free(sample); sample = NULL; snap = isl_tab_snap(tab); if (!up) isl_seq_neg(eq, eq, 1 + dim); isl_int_sub_ui(eq[0], eq[0], 1); if (isl_tab_extend_cons(tab, 1) < 0) goto error; if (isl_tab_add_ineq(tab, eq) < 0) goto error; sample = isl_tab_sample(tab); isl_int_add_ui(eq[0], eq[0], 1); if (!up) isl_seq_neg(eq, eq, 1 + dim); if (sample && isl_tab_rollback(tab, snap) < 0) goto error; return sample; error: isl_vec_free(sample); return NULL; }
/* Make first row entries in column col of bset1 identical to * those of bset2, using only these entries of the two matrices. * Let t be the last row with different entries. * For each row i < t, we set * A[i] = (A[t][col]-B[t][col]) * A[i] + (B[i][col]-A[i][col) * A[t] * B[i] = (A[t][col]-B[t][col]) * B[i] + (B[i][col]-A[i][col) * B[t] * so that * A[i][col] = B[i][col] = old(A[t][col]*B[i][col]-A[i][col]*B[t][col]) */ static int transform_column( struct isl_basic_set *bset1, struct isl_basic_set *bset2, unsigned row, unsigned col) { int i, t; isl_int a, b, g; unsigned total; for (t = row-1; t >= 0; --t) if (isl_int_ne(bset1->eq[t][col], bset2->eq[t][col])) break; if (t < 0) return 0; total = 1 + isl_basic_set_n_dim(bset1); isl_int_init(a); isl_int_init(b); isl_int_init(g); isl_int_sub(b, bset1->eq[t][col], bset2->eq[t][col]); for (i = 0; i < t; ++i) { isl_int_sub(a, bset2->eq[i][col], bset1->eq[i][col]); isl_int_gcd(g, a, b); isl_int_divexact(a, a, g); isl_int_divexact(g, b, g); isl_seq_combine(bset1->eq[i], g, bset1->eq[i], a, bset1->eq[t], total); isl_seq_combine(bset2->eq[i], g, bset2->eq[i], a, bset2->eq[t], total); } isl_int_clear(a); isl_int_clear(b); isl_int_clear(g); delete_row(bset1, t); delete_row(bset2, t); return 1; }
/* Compute a reduced basis for the set represented by the tableau "tab". * tab->basis, which must be initialized by the calling function to an affine * unimodular basis, is updated to reflect the reduced basis. * The first tab->n_zero rows of the basis (ignoring the constant row) * are assumed to correspond to equalities and are left untouched. * tab->n_zero is updated to reflect any additional equalities that * have been detected in the first rows of the new basis. * The final tab->n_unbounded rows of the basis are assumed to correspond * to unbounded directions and are also left untouched. * In particular this means that the remaining rows are assumed to * correspond to bounded directions. * * This function implements the algorithm described in * "An Implementation of the Generalized Basis Reduction Algorithm * for Integer Programming" of Cook el al. to compute a reduced basis. * We use \epsilon = 1/4. * * If ctx->opt->gbr_only_first is set, the user is only interested * in the first direction. In this case we stop the basis reduction when * the width in the first direction becomes smaller than 2. */ struct isl_tab *isl_tab_compute_reduced_basis(struct isl_tab *tab) { unsigned dim; struct isl_ctx *ctx; struct isl_mat *B; int unbounded; int i; GBR_LP *lp = NULL; GBR_type F_old, alpha, F_new; int row; isl_int tmp; struct isl_vec *b_tmp; GBR_type *F = NULL; GBR_type *alpha_buffer[2] = { NULL, NULL }; GBR_type *alpha_saved; GBR_type F_saved; int use_saved = 0; isl_int mu[2]; GBR_type mu_F[2]; GBR_type two; GBR_type one; int empty = 0; int fixed = 0; int fixed_saved = 0; int mu_fixed[2]; int n_bounded; int gbr_only_first; if (!tab) return NULL; if (tab->empty) return tab; ctx = tab->mat->ctx; gbr_only_first = ctx->opt->gbr_only_first; dim = tab->n_var; B = tab->basis; if (!B) return tab; n_bounded = dim - tab->n_unbounded; if (n_bounded <= tab->n_zero + 1) return tab; isl_int_init(tmp); isl_int_init(mu[0]); isl_int_init(mu[1]); GBR_init(alpha); GBR_init(F_old); GBR_init(F_new); GBR_init(F_saved); GBR_init(mu_F[0]); GBR_init(mu_F[1]); GBR_init(two); GBR_init(one); b_tmp = isl_vec_alloc(ctx, dim); if (!b_tmp) goto error; F = isl_alloc_array(ctx, GBR_type, n_bounded); alpha_buffer[0] = isl_alloc_array(ctx, GBR_type, n_bounded); alpha_buffer[1] = isl_alloc_array(ctx, GBR_type, n_bounded); alpha_saved = alpha_buffer[0]; if (!F || !alpha_buffer[0] || !alpha_buffer[1]) goto error; for (i = 0; i < n_bounded; ++i) { GBR_init(F[i]); GBR_init(alpha_buffer[0][i]); GBR_init(alpha_buffer[1][i]); } GBR_set_ui(two, 2); GBR_set_ui(one, 1); lp = GBR_lp_init(tab); if (!lp) goto error; i = tab->n_zero; GBR_lp_set_obj(lp, B->row[1+i]+1, dim); ctx->stats->gbr_solved_lps++; unbounded = GBR_lp_solve(lp); isl_assert(ctx, !unbounded, goto error); GBR_lp_get_obj_val(lp, &F[i]); if (GBR_lt(F[i], one)) { if (!GBR_is_zero(F[i])) { empty = GBR_lp_cut(lp, B->row[1+i]+1); if (empty) goto done; GBR_set_ui(F[i], 0); } tab->n_zero++; } do { if (i+1 == tab->n_zero) { GBR_lp_set_obj(lp, B->row[1+i+1]+1, dim); ctx->stats->gbr_solved_lps++; unbounded = GBR_lp_solve(lp); isl_assert(ctx, !unbounded, goto error); GBR_lp_get_obj_val(lp, &F_new); fixed = GBR_lp_is_fixed(lp); GBR_set_ui(alpha, 0); } else if (use_saved) { row = GBR_lp_next_row(lp); GBR_set(F_new, F_saved); fixed = fixed_saved; GBR_set(alpha, alpha_saved[i]); } else { row = GBR_lp_add_row(lp, B->row[1+i]+1, dim); GBR_lp_set_obj(lp, B->row[1+i+1]+1, dim); ctx->stats->gbr_solved_lps++; unbounded = GBR_lp_solve(lp); isl_assert(ctx, !unbounded, goto error); GBR_lp_get_obj_val(lp, &F_new); fixed = GBR_lp_is_fixed(lp); GBR_lp_get_alpha(lp, row, &alpha); if (i > 0) save_alpha(lp, row-i, i, alpha_saved); if (GBR_lp_del_row(lp) < 0) goto error; } GBR_set(F[i+1], F_new); GBR_floor(mu[0], alpha); GBR_ceil(mu[1], alpha); if (isl_int_eq(mu[0], mu[1])) isl_int_set(tmp, mu[0]); else { int j; for (j = 0; j <= 1; ++j) { isl_int_set(tmp, mu[j]); isl_seq_combine(b_tmp->el, ctx->one, B->row[1+i+1]+1, tmp, B->row[1+i]+1, dim); GBR_lp_set_obj(lp, b_tmp->el, dim); ctx->stats->gbr_solved_lps++; unbounded = GBR_lp_solve(lp); isl_assert(ctx, !unbounded, goto error); GBR_lp_get_obj_val(lp, &mu_F[j]); mu_fixed[j] = GBR_lp_is_fixed(lp); if (i > 0) save_alpha(lp, row-i, i, alpha_buffer[j]); } if (GBR_lt(mu_F[0], mu_F[1])) j = 0; else j = 1; isl_int_set(tmp, mu[j]); GBR_set(F_new, mu_F[j]); fixed = mu_fixed[j]; alpha_saved = alpha_buffer[j]; } isl_seq_combine(B->row[1+i+1]+1, ctx->one, B->row[1+i+1]+1, tmp, B->row[1+i]+1, dim); if (i+1 == tab->n_zero && fixed) { if (!GBR_is_zero(F[i+1])) { empty = GBR_lp_cut(lp, B->row[1+i+1]+1); if (empty) goto done; GBR_set_ui(F[i+1], 0); } tab->n_zero++; } GBR_set(F_old, F[i]); use_saved = 0; /* mu_F[0] = 4 * F_new; mu_F[1] = 3 * F_old */ GBR_set_ui(mu_F[0], 4); GBR_mul(mu_F[0], mu_F[0], F_new); GBR_set_ui(mu_F[1], 3); GBR_mul(mu_F[1], mu_F[1], F_old); if (GBR_lt(mu_F[0], mu_F[1])) { B = isl_mat_swap_rows(B, 1 + i, 1 + i + 1); if (i > tab->n_zero) { use_saved = 1; GBR_set(F_saved, F_new); fixed_saved = fixed; if (GBR_lp_del_row(lp) < 0) goto error; --i; } else { GBR_set(F[tab->n_zero], F_new); if (gbr_only_first && GBR_lt(F[tab->n_zero], two)) break; if (fixed) { if (!GBR_is_zero(F[tab->n_zero])) { empty = GBR_lp_cut(lp, B->row[1+tab->n_zero]+1); if (empty) goto done; GBR_set_ui(F[tab->n_zero], 0); } tab->n_zero++; } } } else { GBR_lp_add_row(lp, B->row[1+i]+1, dim); ++i; } } while (i < n_bounded - 1);