X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=isl_map_simplify.c;h=4775efaa8b8501837bdb495903b12f3be5f27c79;hb=3769d58bc91ea9900b8c6aa0bf4d8b04596f7abf;hp=f37cb2ae29e2a28538f8519e6abea984deaa9ffb;hpb=11b961b0bcb5d791e5adc82a6ae8cec0fdf9077b;p=platform%2Fupstream%2Fisl.git diff --git a/isl_map_simplify.c b/isl_map_simplify.c index f37cb2a..4775efa 100644 --- a/isl_map_simplify.c +++ b/isl_map_simplify.c @@ -1,6 +1,16 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * + * Use of this software is governed by the GNU LGPLv2.1 license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + #include "isl_equalities.h" #include "isl_map.h" #include "isl_map_private.h" +#include "isl_seq.h" #include "isl_tab.h" static void swap_equality(struct isl_basic_map *bmap, int a, int b) @@ -110,7 +120,34 @@ error: return NULL; } -/* Drop n input dimensions starting at first. +/* Move "n" divs starting at "first" to the end of the list of divs. + */ +static struct isl_basic_map *move_divs_last(struct isl_basic_map *bmap, + unsigned first, unsigned n) +{ + isl_int **div; + int i; + + if (first + n == bmap->n_div) + return bmap; + + div = isl_alloc_array(bmap->ctx, isl_int *, n); + if (!div) + goto error; + for (i = 0; i < n; ++i) + div[i] = bmap->div[first + i]; + for (i = 0; i < bmap->n_div - first - n; ++i) + bmap->div[first + i] = bmap->div[first + n + i]; + for (i = 0; i < n; ++i) + bmap->div[bmap->n_div - n + i] = div[i]; + free(div); + return bmap; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Drop "n" dimensions of type "type" starting at "first". * * In principle, this frees up some extra variables as the number * of columns remains constant, but we would have to extend @@ -149,7 +186,13 @@ struct isl_basic_map *isl_basic_map_drop(struct isl_basic_map *bmap, for (i = 0; i < bmap->n_div; ++i) constraint_drop_vars(bmap->div[i]+1+offset, n, left); - bmap->dim = isl_dim_drop(bmap->dim, type, first, n); + if (type == isl_dim_div) { + bmap = move_divs_last(bmap, first, n); + if (!bmap) + goto error; + isl_basic_map_free_div(bmap, n); + } else + bmap->dim = isl_dim_drop(bmap->dim, type, first, n); if (!bmap->dim) goto error; @@ -161,6 +204,13 @@ error: return NULL; } +__isl_give isl_basic_set *isl_basic_set_drop(__isl_take isl_basic_set *bset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return (isl_basic_set *)isl_basic_map_drop((isl_basic_map *)bset, + type, first, n); +} + struct isl_basic_map *isl_basic_map_drop_inputs( struct isl_basic_map *bmap, unsigned first, unsigned n) { @@ -199,6 +249,12 @@ error: return NULL; } +struct isl_set *isl_set_drop(struct isl_set *set, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return (isl_set *)isl_map_drop((isl_map *)set, type, first, n); +} + struct isl_map *isl_map_drop_inputs( struct isl_map *map, unsigned first, unsigned n) { @@ -261,6 +317,9 @@ struct isl_basic_map *isl_basic_map_normalize_constraints( isl_int gcd; unsigned total = isl_basic_map_total_dim(bmap); + if (!bmap) + return NULL; + isl_int_init(gcd); for (i = bmap->n_eq - 1; i >= 0; --i) { isl_seq_gcd(bmap->eq[i]+1, total, &gcd); @@ -308,36 +367,101 @@ struct isl_basic_map *isl_basic_map_normalize_constraints( struct isl_basic_set *isl_basic_set_normalize_constraints( struct isl_basic_set *bset) { - (struct isl_basic_set *)isl_basic_map_normalize_constraints( + return (struct isl_basic_set *)isl_basic_map_normalize_constraints( (struct isl_basic_map *)bset); } -static void eliminate_div(struct isl_basic_map *bmap, isl_int *eq, unsigned div) +/* Assumes divs have been ordered if keep_divs is set. + */ +static void eliminate_var_using_equality(struct isl_basic_map *bmap, + unsigned pos, isl_int *eq, int keep_divs, int *progress) { - int i; - unsigned pos = 1 + isl_dim_total(bmap->dim) + div; - unsigned len; - len = 1 + isl_basic_map_total_dim(bmap); + unsigned total; + int k; + int last_div; - for (i = 0; i < bmap->n_eq; ++i) - if (bmap->eq[i] != eq) - isl_seq_elim(bmap->eq[i], eq, pos, len, NULL); + total = isl_basic_map_total_dim(bmap); + last_div = isl_seq_last_non_zero(eq + 1 + isl_dim_total(bmap->dim), + bmap->n_div); + for (k = 0; k < bmap->n_eq; ++k) { + if (bmap->eq[k] == eq) + continue; + if (isl_int_is_zero(bmap->eq[k][1+pos])) + continue; + if (progress) + *progress = 1; + isl_seq_elim(bmap->eq[k], eq, 1+pos, 1+total, NULL); + } - for (i = 0; i < bmap->n_ineq; ++i) - isl_seq_elim(bmap->ineq[i], eq, pos, len, NULL); + for (k = 0; k < bmap->n_ineq; ++k) { + if (isl_int_is_zero(bmap->ineq[k][1+pos])) + continue; + if (progress) + *progress = 1; + isl_seq_elim(bmap->ineq[k], eq, 1+pos, 1+total, NULL); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + } - /* We need to be careful about circular definitions, - * so for now we just remove the definitions of other divs that - * depend on this div and (possibly) recompute them later. - */ - for (i = 0; i < bmap->n_div; ++i) - if (!isl_int_is_zero(bmap->div[i][0]) && - !isl_int_is_zero(bmap->div[i][1 + pos])) - isl_seq_clr(bmap->div[i], 1 + len); + for (k = 0; k < bmap->n_div; ++k) { + if (isl_int_is_zero(bmap->div[k][0])) + continue; + if (isl_int_is_zero(bmap->div[k][1+1+pos])) + continue; + if (progress) + *progress = 1; + /* We need to be careful about circular definitions, + * so for now we just remove the definition of div k + * if the equality contains any divs. + * If keep_divs is set, then the divs have been ordered + * and we can keep the definition as long as the result + * is still ordered. + */ + if (last_div == -1 || (keep_divs && last_div < k)) + isl_seq_elim(bmap->div[k]+1, eq, + 1+pos, 1+total, &bmap->div[k][0]); + else + isl_seq_clr(bmap->div[k], 1 + total); + ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); + } +} + +/* Assumes divs have been ordered if keep_divs is set. + */ +static void eliminate_div(struct isl_basic_map *bmap, isl_int *eq, + unsigned div, int keep_divs) +{ + unsigned pos = isl_dim_total(bmap->dim) + div; + + eliminate_var_using_equality(bmap, pos, eq, keep_divs, NULL); isl_basic_map_drop_div(bmap, div); } +/* Check if elimination of div "div" using equality "eq" would not + * result in a div depending on a later div. + */ +static int ok_to_eliminate_div(struct isl_basic_map *bmap, isl_int *eq, + unsigned div) +{ + int k; + int last_div; + unsigned pos = isl_dim_total(bmap->dim) + div; + + last_div = isl_seq_last_non_zero(eq + 1 + isl_dim_total(bmap->dim), + bmap->n_div); + if (last_div < 0 || last_div <= div) + return 1; + + for (k = 0; k <= last_div; ++k) { + if (isl_int_is_zero(bmap->div[k][0])) + return 1; + if (!isl_int_is_zero(bmap->div[k][1 + 1 + pos])) + return 0; + } + + return 1; +} + /* Elimininate divs based on equalities */ static struct isl_basic_map *eliminate_divs_eq( @@ -348,6 +472,8 @@ static struct isl_basic_map *eliminate_divs_eq( int modified = 0; unsigned off; + bmap = isl_basic_map_order_divs(bmap); + if (!bmap) return NULL; @@ -358,9 +484,11 @@ static struct isl_basic_map *eliminate_divs_eq( if (!isl_int_is_one(bmap->eq[i][off + d]) && !isl_int_is_negone(bmap->eq[i][off + d])) continue; + if (!ok_to_eliminate_div(bmap, bmap->eq[i], d)) + continue; modified = 1; *progress = 1; - eliminate_div(bmap, bmap->eq[i], d); + eliminate_div(bmap, bmap->eq[i], d, 1); isl_basic_map_drop_equality(bmap, i); break; } @@ -399,7 +527,7 @@ static struct isl_basic_map *eliminate_divs_ineq( continue; *progress = 1; bmap = isl_basic_map_eliminate_vars(bmap, (off-1)+d, 1); - if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) + if (!bmap || ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) break; bmap = isl_basic_map_drop_div(bmap, d); if (!bmap) @@ -408,56 +536,6 @@ static struct isl_basic_map *eliminate_divs_ineq( return bmap; } -static void eliminate_var_using_equality(struct isl_basic_map *bmap, - unsigned pos, isl_int *eq, int *progress) -{ - unsigned total; - int k; - int contains_divs; - - total = isl_basic_map_total_dim(bmap); - contains_divs = - isl_seq_first_non_zero(eq + 1 + isl_dim_total(bmap->dim), - bmap->n_div) != -1; - for (k = 0; k < bmap->n_eq; ++k) { - if (bmap->eq[k] == eq) - continue; - if (isl_int_is_zero(bmap->eq[k][1+pos])) - continue; - if (progress) - *progress = 1; - isl_seq_elim(bmap->eq[k], eq, 1+pos, 1+total, NULL); - } - - for (k = 0; k < bmap->n_ineq; ++k) { - if (isl_int_is_zero(bmap->ineq[k][1+pos])) - continue; - if (progress) - *progress = 1; - isl_seq_elim(bmap->ineq[k], eq, 1+pos, 1+total, NULL); - ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); - } - - for (k = 0; k < bmap->n_div; ++k) { - if (isl_int_is_zero(bmap->div[k][0])) - continue; - if (isl_int_is_zero(bmap->div[k][1+1+pos])) - continue; - if (progress) - *progress = 1; - /* We need to be careful about circular definitions, - * so for now we just remove the definition of div k - * if the equality contains any divs. - */ - if (contains_divs) - isl_seq_clr(bmap->div[k], 1 + total); - else - isl_seq_elim(bmap->div[k]+1, eq, - 1+pos, 1+total, &bmap->div[k][0]); - ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED); - } -} - struct isl_basic_map *isl_basic_map_gauss( struct isl_basic_map *bmap, int *progress) { @@ -467,6 +545,8 @@ struct isl_basic_map *isl_basic_map_gauss( unsigned total_var; unsigned total; + bmap = isl_basic_map_order_divs(bmap); + if (!bmap) return NULL; @@ -489,7 +569,7 @@ struct isl_basic_map *isl_basic_map_gauss( if (isl_int_is_neg(bmap->eq[done][1+last_var])) isl_seq_neg(bmap->eq[done], bmap->eq[done], 1+total); - eliminate_var_using_equality(bmap, last_var, bmap->eq[done], + eliminate_var_using_equality(bmap, last_var, bmap->eq[done], 1, progress); if (last_var >= total_var && @@ -565,13 +645,16 @@ static struct isl_basic_map *remove_duplicate_divs( int k, l, h; int bits; struct isl_blk eq; - unsigned total_var = isl_dim_total(bmap->dim); - unsigned total = total_var + bmap->n_div; + unsigned total_var; + unsigned total; struct isl_ctx *ctx; - if (bmap->n_div <= 1) + if (!bmap || bmap->n_div <= 1) return bmap; + total_var = isl_dim_total(bmap->dim); + total = total_var + bmap->n_div; + ctx = bmap->ctx; for (k = bmap->n_div - 1; k >= 0; --k) if (!isl_int_is_zero(bmap->div[k][0])) @@ -615,7 +698,7 @@ static struct isl_basic_map *remove_duplicate_divs( k = elim_for[l] - 1; isl_int_set_si(eq.data[1+total_var+k], -1); isl_int_set_si(eq.data[1+total_var+l], 1); - eliminate_div(bmap, eq.data, l); + eliminate_div(bmap, eq.data, l, 0); isl_int_set_si(eq.data[1+total_var+k], 0); isl_int_set_si(eq.data[1+total_var+l], 0); } @@ -627,6 +710,23 @@ out: return bmap; } +static int n_pure_div_eq(struct isl_basic_map *bmap) +{ + int i, j; + unsigned total; + + total = isl_dim_total(bmap->dim); + for (i = 0, j = bmap->n_div-1; i < bmap->n_eq; ++i) { + while (j >= 0 && isl_int_is_zero(bmap->eq[i][1 + total + j])) + --j; + if (j < 0) + break; + if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total, j) != -1) + return 0; + } + return i; +} + /* Normalize divs that appear in equalities. * * In particular, we assume that bmap contains some equalities @@ -703,28 +803,20 @@ static struct isl_basic_map *normalize_divs( return bmap; total = isl_dim_total(bmap->dim); - for (i = 0, j = bmap->n_div-1; i < bmap->n_eq; ++i) { - while (j >= 0 && isl_int_is_zero(bmap->eq[i][1 + total + j])) - --j; - if (j < 0) - break; - if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total, j) != -1) - goto done; - } - div_eq = i; + div_eq = n_pure_div_eq(bmap); if (div_eq == 0) return bmap; if (div_eq < bmap->n_eq) { B = isl_mat_sub_alloc(bmap->ctx, bmap->eq, div_eq, bmap->n_eq - div_eq, 0, 1 + total); - C = isl_mat_variable_compression(bmap->ctx, B, &C2); + C = isl_mat_variable_compression(B, &C2); if (!C || !C2) goto error; if (C->n_col == 0) { bmap = isl_basic_map_set_to_empty(bmap); - isl_mat_free(bmap->ctx, C); - isl_mat_free(bmap->ctx, C2); + isl_mat_free(C); + isl_mat_free(C2); goto done; } } @@ -740,17 +832,17 @@ static struct isl_basic_map *normalize_divs( B = isl_mat_sub_alloc(bmap->ctx, bmap->eq, 0, div_eq, 0, 1 + total); if (C) { - B = isl_mat_product(bmap->ctx, B, C); + B = isl_mat_product(B, C); C = NULL; } - T = isl_mat_parameter_compression(bmap->ctx, B, d); + T = isl_mat_parameter_compression(B, d); if (!T) goto error; if (T->n_col == 0) { bmap = isl_basic_map_set_to_empty(bmap); - isl_mat_free(bmap->ctx, C2); - isl_mat_free(bmap->ctx, T); + isl_mat_free(C2); + isl_mat_free(T); goto done; } isl_int_init(v); @@ -762,6 +854,8 @@ static struct isl_basic_map *normalize_divs( } isl_int_clear(v); pos = isl_alloc_array(bmap->ctx, int, T->n_row); + if (!pos) + goto error; /* We have to be careful because dropping equalities may reorder them */ dropped = 0; for (j = bmap->n_div - 1; j >= 0; --j) { @@ -814,18 +908,105 @@ static struct isl_basic_map *normalize_divs( isl_int_set(bmap->eq[j][pos[i]], bmap->div[k][0]); } free(pos); - isl_mat_free(bmap->ctx, C2); - isl_mat_free(bmap->ctx, T); + isl_mat_free(C2); + isl_mat_free(T); - *progress = 1; + if (progress) + *progress = 1; done: ISL_F_SET(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS); return bmap; error: - isl_mat_free(bmap->ctx, C); - isl_mat_free(bmap->ctx, C2); - isl_mat_free(bmap->ctx, T); + isl_mat_free(C); + isl_mat_free(C2); + isl_mat_free(T); + return bmap; +} + +static struct isl_basic_map *set_div_from_lower_bound( + struct isl_basic_map *bmap, int div, int ineq) +{ + unsigned total = 1 + isl_dim_total(bmap->dim); + + isl_seq_neg(bmap->div[div] + 1, bmap->ineq[ineq], total + bmap->n_div); + isl_int_set(bmap->div[div][0], bmap->ineq[ineq][total + div]); + isl_int_add(bmap->div[div][1], bmap->div[div][1], bmap->div[div][0]); + isl_int_sub_ui(bmap->div[div][1], bmap->div[div][1], 1); + isl_int_set_si(bmap->div[div][1 + total + div], 0); + + return bmap; +} + +/* Check whether it is ok to define a div based on an inequality. + * To avoid the introduction of circular definitions of divs, we + * do not allow such a definition if the resulting expression would refer to + * any other undefined divs or if any known div is defined in + * terms of the unknown div. + */ +static int ok_to_set_div_from_bound(struct isl_basic_map *bmap, + int div, int ineq) +{ + int j; + unsigned total = 1 + isl_dim_total(bmap->dim); + + /* Not defined in terms of unknown divs */ + for (j = 0; j < bmap->n_div; ++j) { + if (div == j) + continue; + if (isl_int_is_zero(bmap->ineq[ineq][total + j])) + continue; + if (isl_int_is_zero(bmap->div[j][0])) + return 0; + } + + /* No other div defined in terms of this one => avoid loops */ + for (j = 0; j < bmap->n_div; ++j) { + if (div == j) + continue; + if (isl_int_is_zero(bmap->div[j][0])) + continue; + if (!isl_int_is_zero(bmap->div[j][1 + total + div])) + return 0; + } + + return 1; +} + +/* Given two constraints "k" and "l" that are opposite to each other, + * except for the constant term, check if we can use them + * to obtain an expression for one of the hitherto unknown divs. + * "sum" is the sum of the constant terms of the constraints. + * If this sum is strictly smaller than the coefficient of one + * of the divs, then this pair can be used define the div. + * To avoid the introduction of circular definitions of divs, we + * do not use the pair if the resulting expression would refer to + * any other undefined divs or if any known div is defined in + * terms of the unknown div. + */ +static struct isl_basic_map *check_for_div_constraints( + struct isl_basic_map *bmap, int k, int l, isl_int sum, int *progress) +{ + int i; + unsigned total = 1 + isl_dim_total(bmap->dim); + + for (i = 0; i < bmap->n_div; ++i) { + if (!isl_int_is_zero(bmap->div[i][0])) + continue; + if (isl_int_is_zero(bmap->ineq[k][total + i])) + continue; + if (isl_int_abs_ge(sum, bmap->ineq[k][total + i])) + continue; + if (!ok_to_set_div_from_bound(bmap, i, k)) + break; + if (isl_int_is_pos(bmap->ineq[k][total + i])) + bmap = set_div_from_lower_bound(bmap, i, k); + else + bmap = set_div_from_lower_bound(bmap, i, l); + if (progress) + *progress = 1; + break; + } return bmap; } @@ -839,7 +1020,7 @@ static struct isl_basic_map *remove_duplicate_constraints( unsigned total = isl_basic_map_total_dim(bmap); isl_int sum; - if (bmap->n_ineq <= 1) + if (!bmap || bmap->n_ineq <= 1) return bmap; size = round_up(4 * (bmap->n_ineq+1) / 3 - 1); @@ -872,14 +1053,19 @@ static struct isl_basic_map *remove_duplicate_constraints( continue; l = index[h] - &bmap->ineq[0]; isl_int_add(sum, bmap->ineq[k][0], bmap->ineq[l][0]); - if (isl_int_is_pos(sum)) + if (isl_int_is_pos(sum)) { + bmap = check_for_div_constraints(bmap, k, l, sum, + progress); continue; + } if (isl_int_is_zero(sum)) { /* We need to break out of the loop after these * changes since the contents of the hash * will no longer be valid. * Plus, we probably we want to regauss first. */ + if (progress) + *progress = 1; isl_basic_map_drop_inequality(bmap, l); isl_basic_map_inequality_to_equality(bmap, k); } else @@ -901,12 +1087,12 @@ struct isl_basic_map *isl_basic_map_simplify(struct isl_basic_map *bmap) while (progress) { progress = 0; bmap = isl_basic_map_normalize_constraints(bmap); + bmap = remove_duplicate_divs(bmap, &progress); bmap = eliminate_divs_eq(bmap, &progress); bmap = eliminate_divs_ineq(bmap, &progress); bmap = isl_basic_map_gauss(bmap, &progress); /* requires equalities in normal form */ bmap = normalize_divs(bmap, &progress); - bmap = remove_duplicate_divs(bmap, &progress); bmap = remove_duplicate_constraints(bmap, &progress); } return bmap; @@ -919,6 +1105,43 @@ struct isl_basic_set *isl_basic_set_simplify(struct isl_basic_set *bset) } +int isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap, + isl_int *constraint, unsigned div) +{ + unsigned pos; + + if (!bmap) + return -1; + + pos = 1 + isl_dim_total(bmap->dim) + div; + + if (isl_int_eq(constraint[pos], bmap->div[div][0])) { + int neg; + isl_int_sub(bmap->div[div][1], + bmap->div[div][1], bmap->div[div][0]); + isl_int_add_ui(bmap->div[div][1], bmap->div[div][1], 1); + neg = isl_seq_is_neg(constraint, bmap->div[div]+1, pos); + isl_int_sub_ui(bmap->div[div][1], bmap->div[div][1], 1); + isl_int_add(bmap->div[div][1], + bmap->div[div][1], bmap->div[div][0]); + if (!neg) + return 0; + if (isl_seq_first_non_zero(constraint+pos+1, + bmap->n_div-div-1) != -1) + return 0; + } else if (isl_int_abs_eq(constraint[pos], bmap->div[div][0])) { + if (!isl_seq_eq(constraint, bmap->div[div]+1, pos)) + return 0; + if (isl_seq_first_non_zero(constraint+pos+1, + bmap->n_div-div-1) != -1) + return 0; + } else + return 0; + + return 1; +} + + /* If the only constraints a div d=floor(f/m) * appears in are its two defining constraints * @@ -939,27 +1162,7 @@ static int div_is_redundant(struct isl_basic_map *bmap, int div) for (i = 0; i < bmap->n_ineq; ++i) { if (isl_int_is_zero(bmap->ineq[i][pos])) continue; - if (isl_int_eq(bmap->ineq[i][pos], bmap->div[div][0])) { - int neg; - isl_int_sub(bmap->div[div][1], - bmap->div[div][1], bmap->div[div][0]); - isl_int_add_ui(bmap->div[div][1], bmap->div[div][1], 1); - neg = isl_seq_is_neg(bmap->ineq[i], bmap->div[div]+1, pos); - isl_int_sub_ui(bmap->div[div][1], bmap->div[div][1], 1); - isl_int_add(bmap->div[div][1], - bmap->div[div][1], bmap->div[div][0]); - if (!neg) - return 0; - if (isl_seq_first_non_zero(bmap->ineq[i]+pos+1, - bmap->n_div-div-1) != -1) - return 0; - } else if (isl_int_abs_eq(bmap->ineq[i][pos], bmap->div[div][0])) { - if (!isl_seq_eq(bmap->ineq[i], bmap->div[div]+1, pos)) - return 0; - if (isl_seq_first_non_zero(bmap->ineq[i]+pos+1, - bmap->n_div-div-1) != -1) - return 0; - } else + if (!isl_basic_map_is_div_constraint(bmap, bmap->ineq[i], div)) return 0; } @@ -1041,22 +1244,21 @@ error: } -/* Remove any div that is defined in terms of the given variable. +/* Remove definition of any div that is defined in terms of the given variable. + * The div itself is not removed. Functions such as + * eliminate_divs_ineq depend on the other divs remaining in place. */ static struct isl_basic_map *remove_dependent_vars(struct isl_basic_map *bmap, int pos) { int i; - unsigned dim = isl_dim_total(bmap->dim); for (i = 0; i < bmap->n_div; ++i) { if (isl_int_is_zero(bmap->div[i][0])) continue; if (isl_int_is_zero(bmap->div[i][1+1+pos])) continue; - bmap = isl_basic_map_eliminate_vars(bmap, dim + i, 1); - if (!bmap) - return NULL; + isl_int_set_si(bmap->div[i][0], 0); } return bmap; } @@ -1091,7 +1293,7 @@ struct isl_basic_map *isl_basic_map_eliminate_vars( for (i = 0; i < bmap->n_eq; ++i) { if (isl_int_is_zero(bmap->eq[i][1+d])) continue; - eliminate_var_using_equality(bmap, d, bmap->eq[i], NULL); + eliminate_var_using_equality(bmap, d, bmap->eq[i], 0, NULL); isl_basic_map_drop_equality(bmap, i); break; } @@ -1107,6 +1309,8 @@ struct isl_basic_map *isl_basic_map_eliminate_vars( } bmap = isl_basic_map_extend_constraints(bmap, 0, n_lower * n_upper); + if (!bmap) + goto error; for (i = bmap->n_ineq - 1; i >= 0; --i) { int last; if (isl_int_is_zero(bmap->ineq[i][1+d])) @@ -1134,7 +1338,7 @@ struct isl_basic_map *isl_basic_map_eliminate_vars( bmap = isl_basic_map_normalize_constraints(bmap); bmap = remove_duplicate_constraints(bmap, NULL); bmap = isl_basic_map_gauss(bmap, NULL); - bmap = isl_basic_map_convex_hull(bmap); + bmap = isl_basic_map_remove_redundancies(bmap); if (!bmap) goto error; if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) @@ -1178,13 +1382,13 @@ static void compute_elimination_index(struct isl_basic_map *bmap, int *elim) static void set_compute_elimination_index(struct isl_basic_set *bset, int *elim) { - return compute_elimination_index((struct isl_basic_map *)bset, elim); + compute_elimination_index((struct isl_basic_map *)bset, elim); } static int reduced_using_equalities(isl_int *dst, isl_int *src, struct isl_basic_map *bmap, int *elim) { - int d, i; + int d; int copied = 0; unsigned total; @@ -1219,11 +1423,16 @@ static struct isl_basic_set *isl_basic_set_reduce_using_equalities( if (!bset || !context) goto error; + if (context->n_eq == 0) { + isl_basic_set_free(context); + return bset; + } + bset = isl_basic_set_cow(bset); if (!bset) goto error; - elim = isl_alloc_array(ctx, int, isl_basic_set_n_dim(bset)); + elim = isl_alloc_array(bset->ctx, int, isl_basic_set_n_dim(bset)); if (!elim) goto error; set_compute_elimination_index(context, elim); @@ -1336,22 +1545,25 @@ static struct isl_basic_set *normalize_constraints_in_compressed_space( if (ISL_F_ISSET(bset, ISL_BASIC_SET_RATIONAL)) return bset; + if (!bset->n_ineq) + return bset; + bset = isl_basic_set_cow(bset); if (!bset) return NULL; total = isl_basic_set_total_dim(bset); B = isl_mat_sub_alloc(bset->ctx, bset->eq, 0, bset->n_eq, 0, 1 + total); - C = isl_mat_variable_compression(bset->ctx, B, NULL); + C = isl_mat_variable_compression(B, NULL); if (!C) return bset; if (C->n_col == 0) { - isl_mat_free(bset->ctx, C); + isl_mat_free(C); return isl_basic_set_set_to_empty(bset); } B = isl_mat_sub_alloc(bset->ctx, bset->ineq, 0, bset->n_ineq, 0, 1 + total); - C = isl_mat_product(bset->ctx, B, C); + C = isl_mat_product(B, C); if (!C) return bset; @@ -1365,117 +1577,227 @@ static struct isl_basic_set *normalize_constraints_in_compressed_space( } isl_int_clear(gcd); - isl_mat_free(bset->ctx, C); + isl_mat_free(C); return bset; } /* Remove all information from bset that is redundant in the context - * of context. In particular, equalities that are linear combinations - * of those in context are removed. Then the inequalities that are - * redundant in the context of the equalities and inequalities of - * context are removed. + * of context. Both bset and context are assumed to be full-dimensional. * - * We first simplify the constraints of "bset" in the context of the - * equalities of "context". - * Then we simplify the inequalities of the context in the context - * of the equalities of bset and remove the inequalities from "bset" + * We first * remove the inequalities from "bset" * that are obviously redundant with respect to some inequality in "context". * * If there are any inequalities left, we construct a tableau for * the context and then add the inequalities of "bset". - * Before adding these equalities, we freeze all constraints such that + * Before adding these inequalities, we freeze all constraints such that * they won't be considered redundant in terms of the constraints of "bset". - * Then we detect all equalities and redundant constraints (among the - * constraints that weren't frozen) and update bset according to the results. - * We have to be careful here because we don't want any of the context - * constraints to remain and because we haven't added the equalities of "bset" - * to the tableau so we temporarily have to pretend that there were no - * equalities. + * Then we detect all redundant constraints (among the + * constraints that weren't frozen), first by checking for redundancy in the + * the tableau and then by checking if replacing a constraint by its negation + * would lead to an empty set. This last step is fairly expensive + * and could be optimized by more reuse of the tableau. + * Finally, we update bset according to the results. */ -static struct isl_basic_set *uset_gist(struct isl_basic_set *bset, - struct isl_basic_set *context) +static __isl_give isl_basic_set *uset_gist_full(__isl_take isl_basic_set *bset, + __isl_take isl_basic_set *context) { - int i; - struct isl_tab *tab; - unsigned context_ineq, bset_eq; - struct isl_basic_set *combined = NULL; + int i, k; + isl_basic_set *combined = NULL; + struct isl_tab *tab = NULL; + unsigned context_ineq; + unsigned total; - if (!context || !bset) + if (!bset || !context) goto error; - if (context->n_eq > 0) - bset = isl_basic_set_reduce_using_equalities(bset, - isl_basic_set_copy(context)); + if (isl_basic_set_is_universe(bset)) { + isl_basic_set_free(context); + return bset; + } + + if (isl_basic_set_is_universe(context)) { + isl_basic_set_free(context); + return bset; + } + + bset = remove_shifted_constraints(bset, context); if (!bset) goto error; + if (bset->n_ineq == 0) + goto done; - if (bset->n_eq > 0) { - struct isl_basic_set *affine_hull; - affine_hull = isl_basic_set_copy(bset); - affine_hull = isl_basic_set_cow(affine_hull); - if (!affine_hull) - goto error; - isl_basic_set_free_inequality(affine_hull, affine_hull->n_ineq); - context = isl_basic_set_intersect(context, affine_hull); - context = isl_basic_set_gauss(context, NULL); - context = normalize_constraints_in_compressed_space(context); - } - if (!context) - goto error; - if (ISL_F_ISSET(context, ISL_BASIC_SET_EMPTY)) { - isl_basic_set_free(bset); - return context; - } - if (!context->n_ineq) - goto done; - bset = remove_shifted_constraints(bset, context); - if (!bset->n_ineq) - goto done; - isl_basic_set_free_equality(context, context->n_eq); context_ineq = context->n_ineq; combined = isl_basic_set_cow(isl_basic_set_copy(context)); - combined = isl_basic_set_extend_constraints(combined, - bset->n_eq, bset->n_ineq); + combined = isl_basic_set_extend_constraints(combined, 0, bset->n_ineq); tab = isl_tab_from_basic_set(combined); - if (!tab) - goto error; for (i = 0; i < context_ineq; ++i) - tab->con[i].frozen = 1; - tab = isl_tab_extend(bset->ctx, tab, bset->n_ineq); - if (!tab) - goto error; + if (isl_tab_freeze_constraint(tab, i) < 0) + goto error; + tab = isl_tab_extend(tab, bset->n_ineq); for (i = 0; i < bset->n_ineq; ++i) - tab = isl_tab_add_ineq(bset->ctx, tab, bset->ineq[i]); + if (isl_tab_add_ineq(tab, bset->ineq[i]) < 0) + goto error; bset = isl_basic_set_add_constraints(combined, bset, 0); - tab = isl_tab_detect_equalities(bset->ctx, tab); - tab = isl_tab_detect_redundant(bset->ctx, tab); - if (!tab) - goto error2; - for (i = 0; i < context_ineq; ++i) { - tab->con[i].is_zero = 0; + combined = NULL; + if (!bset) + goto error; + if (isl_tab_detect_redundant(tab) < 0) + goto error; + total = isl_basic_set_total_dim(bset); + for (i = context_ineq; i < bset->n_ineq; ++i) { + int is_empty; + if (tab->con[i].is_redundant) + continue; tab->con[i].is_redundant = 1; + combined = isl_basic_set_dup(bset); + combined = isl_basic_set_update_from_tab(combined, tab); + combined = isl_basic_set_extend_constraints(combined, 0, 1); + k = isl_basic_set_alloc_inequality(combined); + if (k < 0) + goto error; + isl_seq_neg(combined->ineq[k], bset->ineq[i], 1 + total); + isl_int_sub_ui(combined->ineq[k][0], combined->ineq[k][0], 1); + is_empty = isl_basic_set_is_empty(combined); + if (is_empty < 0) + goto error; + isl_basic_set_free(combined); + combined = NULL; + if (!is_empty) + tab->con[i].is_redundant = 0; } - bset_eq = bset->n_eq; - bset->n_eq = 0; + for (i = 0; i < context_ineq; ++i) + tab->con[i].is_redundant = 1; bset = isl_basic_set_update_from_tab(bset, tab); - bset->n_eq = bset_eq; - isl_tab_free(bset->ctx, tab); - ISL_F_SET(bset, ISL_BASIC_SET_NO_IMPLICIT); - ISL_F_SET(bset, ISL_BASIC_SET_NO_REDUNDANT); + if (bset) { + ISL_F_SET(bset, ISL_BASIC_SET_NO_IMPLICIT); + ISL_F_SET(bset, ISL_BASIC_SET_NO_REDUNDANT); + } + + isl_tab_free(tab); done: bset = isl_basic_set_simplify(bset); bset = isl_basic_set_finalize(bset); isl_basic_set_free(context); return bset; error: + isl_tab_free(tab); isl_basic_set_free(combined); -error2: + isl_basic_set_free(context); + isl_basic_set_free(bset); + return NULL; +} + +/* Remove all information from bset that is redundant in the context + * of context. In particular, equalities that are linear combinations + * of those in context are removed. Then the inequalities that are + * redundant in the context of the equalities and inequalities of + * context are removed. + * + * We first compute the integer affine hull of the intersection, + * compute the gist inside this affine hull and then add back + * those equalities that are not implied by the context. + */ +static __isl_give isl_basic_set *uset_gist(__isl_take isl_basic_set *bset, + __isl_take isl_basic_set *context) +{ + isl_mat *eq; + isl_mat *T, *T2; + isl_basic_set *aff; + isl_basic_set *aff_context; + unsigned total; + + if (!bset || !context) + goto error; + + bset = isl_basic_set_intersect(bset, isl_basic_set_copy(context)); + if (isl_basic_set_fast_is_empty(bset)) { + isl_basic_set_free(context); + return bset; + } + aff = isl_basic_set_affine_hull(isl_basic_set_copy(bset)); + if (!aff) + goto error; + if (isl_basic_set_fast_is_empty(aff)) { + isl_basic_set_free(aff); + isl_basic_set_free(context); + return bset; + } + if (aff->n_eq == 0) { + isl_basic_set_free(aff); + return uset_gist_full(bset, context); + } + total = isl_basic_set_total_dim(bset); + eq = isl_mat_sub_alloc(bset->ctx, aff->eq, 0, aff->n_eq, 0, 1 + total); + eq = isl_mat_cow(eq); + T = isl_mat_variable_compression(eq, &T2); + if (T && T->n_col == 0) { + isl_mat_free(T); + isl_mat_free(T2); + isl_basic_set_free(context); + isl_basic_set_free(aff); + return isl_basic_set_set_to_empty(bset); + } + + aff_context = isl_basic_set_affine_hull(isl_basic_set_copy(context)); + + bset = isl_basic_set_preimage(bset, isl_mat_copy(T)); + context = isl_basic_set_preimage(context, T); + + bset = uset_gist_full(bset, context); + bset = isl_basic_set_preimage(bset, T2); + bset = isl_basic_set_intersect(bset, aff); + bset = isl_basic_set_reduce_using_equalities(bset, aff_context); + + if (bset) { + ISL_F_SET(bset, ISL_BASIC_SET_NO_IMPLICIT); + ISL_F_SET(bset, ISL_BASIC_SET_NO_REDUNDANT); + } + + return bset; +error: isl_basic_set_free(bset); isl_basic_set_free(context); return NULL; } +/* Normalize the divs in "bmap" in the context of the equalities in "context". + * We simply add the equalities in context to bmap and then do a regular + * div normalizations. Better results can be obtained by normalizing + * only the divs in bmap than do not also appear in context. + * We need to be careful to reduce the divs using the equalities + * so that later calls to isl_basic_map_overlying_set wouldn't introduce + * spurious constraints. + */ +static struct isl_basic_map *normalize_divs_in_context( + struct isl_basic_map *bmap, struct isl_basic_map *context) +{ + int i; + unsigned total_context; + int div_eq; + + div_eq = n_pure_div_eq(bmap); + if (div_eq == 0) + return bmap; + + if (context->n_div > 0) + bmap = isl_basic_map_align_divs(bmap, context); + + total_context = isl_basic_map_total_dim(context); + bmap = isl_basic_map_extend_constraints(bmap, context->n_eq, 0); + for (i = 0; i < context->n_eq; ++i) { + int k; + k = isl_basic_map_alloc_equality(bmap); + isl_seq_cpy(bmap->eq[k], context->eq[i], 1 + total_context); + isl_seq_clr(bmap->eq[k] + 1 + total_context, + isl_basic_map_total_dim(bmap) - total_context); + } + bmap = isl_basic_map_gauss(bmap, NULL); + bmap = normalize_divs(bmap, NULL); + bmap = isl_basic_map_gauss(bmap, NULL); + return bmap; +} + struct isl_basic_map *isl_basic_map_gist(struct isl_basic_map *bmap, struct isl_basic_map *context) { @@ -1503,8 +1825,11 @@ struct isl_basic_map *isl_basic_map_gist(struct isl_basic_map *bmap, return bmap; } - bmap = isl_basic_map_convex_hull(bmap); - context = isl_basic_map_convex_hull(context); + bmap = isl_basic_map_remove_redundancies(bmap); + context = isl_basic_map_remove_redundancies(context); + + if (context->n_eq) + bmap = normalize_divs_in_context(bmap, context); context = isl_basic_map_align_divs(context, bmap); bmap = isl_basic_map_align_divs(bmap, context); @@ -1522,7 +1847,8 @@ error: /* * Assumes context has no implicit divs. */ -struct isl_map *isl_map_gist(struct isl_map *map, struct isl_basic_map *context) +__isl_give isl_map *isl_map_gist_basic_map(__isl_take isl_map *map, + __isl_take isl_basic_map *context) { int i; @@ -1540,7 +1866,7 @@ struct isl_map *isl_map_gist(struct isl_map *map, struct isl_basic_map *context) return isl_map_universe(dim); } - context = isl_basic_map_convex_hull(context); + context = isl_basic_map_remove_redundancies(context); map = isl_map_cow(map); if (!map || !context) goto error;; @@ -1563,6 +1889,12 @@ error: return NULL; } +__isl_give isl_map *isl_map_gist(__isl_take isl_map *map, + __isl_take isl_map *context) +{ + return isl_map_gist_basic_map(map, isl_map_convex_hull(context)); +} + struct isl_basic_set *isl_basic_set_gist(struct isl_basic_set *bset, struct isl_basic_set *context) { @@ -1570,12 +1902,20 @@ struct isl_basic_set *isl_basic_set_gist(struct isl_basic_set *bset, (struct isl_basic_map *)bset, (struct isl_basic_map *)context); } -struct isl_set *isl_set_gist(struct isl_set *set, struct isl_basic_set *context) +__isl_give isl_set *isl_set_gist_basic_set(__isl_take isl_set *set, + __isl_take isl_basic_set *context) { - return (struct isl_set *)isl_map_gist((struct isl_map *)set, + return (struct isl_set *)isl_map_gist_basic_map((struct isl_map *)set, (struct isl_basic_map *)context); } +__isl_give isl_set *isl_set_gist(__isl_take isl_set *set, + __isl_take isl_set *context) +{ + return (struct isl_set *)isl_map_gist((struct isl_map *)set, + (struct isl_map *)context); +} + /* Quick check to see if two basic maps are disjoint. * In particular, we reduce the equalities and inequalities of * one basic map in the context of the equalities of the other @@ -1587,7 +1927,7 @@ int isl_basic_map_fast_is_disjoint(struct isl_basic_map *bmap1, struct isl_vec *v = NULL; int *elim = NULL; unsigned total; - int d, i; + int i; if (!bmap1 || !bmap2) return -1; @@ -1633,15 +1973,15 @@ int isl_basic_map_fast_is_disjoint(struct isl_basic_map *bmap1, isl_seq_first_non_zero(v->block.data + 1, total) == -1) goto disjoint; } - isl_vec_free(bmap1->ctx, v); + isl_vec_free(v); free(elim); return 0; disjoint: - isl_vec_free(bmap1->ctx, v); + isl_vec_free(v); free(elim); return 1; error: - isl_vec_free(bmap1->ctx, v); + isl_vec_free(v); free(elim); return -1; } @@ -1679,3 +2019,547 @@ int isl_set_fast_is_disjoint(struct isl_set *set1, struct isl_set *set2) return isl_map_fast_is_disjoint((struct isl_map *)set1, (struct isl_map *)set2); } + +/* Check if we can combine a given div with lower bound l and upper + * bound u with some other div and if so return that other div. + * Otherwise return -1. + * + * We first check that + * - the bounds are opposites of each other (except for the constant + * term) + * - the bounds do not reference any other div + * - no div is defined in terms of this div + * + * Let m be the size of the range allowed on the div by the bounds. + * That is, the bounds are of the form + * + * e <= a <= e + m - 1 + * + * with e some expression in the other variables. + * We look for another div b such that no third div is defined in terms + * of this second div b and such that in any constraint that contains + * a (except for the given lower and upper bound), also contains b + * with a coefficient that is m times that of b. + * That is, all constraints (execpt for the lower and upper bound) + * are of the form + * + * e + f (a + m b) >= 0 + * + * If so, we return b so that "a + m b" can be replaced by + * a single div "c = a + m b". + */ +static int div_find_coalesce(struct isl_basic_map *bmap, int *pairs, + unsigned div, unsigned l, unsigned u) +{ + int i, j; + unsigned dim; + int coalesce = -1; + + if (bmap->n_div <= 1) + return -1; + dim = isl_dim_total(bmap->dim); + if (isl_seq_first_non_zero(bmap->ineq[l] + 1 + dim, div) != -1) + return -1; + if (isl_seq_first_non_zero(bmap->ineq[l] + 1 + dim + div + 1, + bmap->n_div - div - 1) != -1) + return -1; + if (!isl_seq_is_neg(bmap->ineq[l] + 1, bmap->ineq[u] + 1, + dim + bmap->n_div)) + return -1; + + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + if (!isl_int_is_zero(bmap->div[i][1 + 1 + dim + div])) + return -1; + } + + isl_int_add(bmap->ineq[l][0], bmap->ineq[l][0], bmap->ineq[u][0]); + if (isl_int_is_neg(bmap->ineq[l][0])) { + isl_int_sub(bmap->ineq[l][0], + bmap->ineq[l][0], bmap->ineq[u][0]); + bmap = isl_basic_map_copy(bmap); + bmap = isl_basic_map_set_to_empty(bmap); + isl_basic_map_free(bmap); + return -1; + } + isl_int_add_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1); + for (i = 0; i < bmap->n_div; ++i) { + if (i == div) + continue; + if (!pairs[i]) + continue; + for (j = 0; j < bmap->n_div; ++j) { + if (isl_int_is_zero(bmap->div[j][0])) + continue; + if (!isl_int_is_zero(bmap->div[j][1 + 1 + dim + i])) + break; + } + if (j < bmap->n_div) + continue; + for (j = 0; j < bmap->n_ineq; ++j) { + int valid; + if (j == l || j == u) + continue; + if (isl_int_is_zero(bmap->ineq[j][1 + dim + div])) + continue; + if (isl_int_is_zero(bmap->ineq[j][1 + dim + i])) + break; + isl_int_mul(bmap->ineq[j][1 + dim + div], + bmap->ineq[j][1 + dim + div], + bmap->ineq[l][0]); + valid = isl_int_eq(bmap->ineq[j][1 + dim + div], + bmap->ineq[j][1 + dim + i]); + isl_int_divexact(bmap->ineq[j][1 + dim + div], + bmap->ineq[j][1 + dim + div], + bmap->ineq[l][0]); + if (!valid) + break; + } + if (j < bmap->n_ineq) + continue; + coalesce = i; + break; + } + isl_int_sub_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1); + isl_int_sub(bmap->ineq[l][0], bmap->ineq[l][0], bmap->ineq[u][0]); + return coalesce; +} + +/* Given a lower and an upper bound on div i, construct an inequality + * that when nonnegative ensures that this pair of bounds always allows + * for an integer value of the given div. + * The lower bound is inequality l, while the upper bound is inequality u. + * The constructed inequality is stored in ineq. + * g, fl, fu are temporary scalars. + * + * Let the upper bound be + * + * -n_u a + e_u >= 0 + * + * and the lower bound + * + * n_l a + e_l >= 0 + * + * Let n_u = f_u g and n_l = f_l g, with g = gcd(n_u, n_l). + * We have + * + * - f_u e_l <= f_u f_l g a <= f_l e_u + * + * Since all variables are integer valued, this is equivalent to + * + * - f_u e_l - (f_u - 1) <= f_u f_l g a <= f_l e_u + (f_l - 1) + * + * If this interval is at least f_u f_l g, then it contains at least + * one integer value for a. + * That is, the test constraint is + * + * f_l e_u + f_u e_l + f_l - 1 + f_u - 1 + 1 >= f_u f_l g + */ +static void construct_test_ineq(struct isl_basic_map *bmap, int i, + int l, int u, isl_int *ineq, isl_int g, isl_int fl, isl_int fu) +{ + unsigned dim; + dim = isl_dim_total(bmap->dim); + + isl_int_gcd(g, bmap->ineq[l][1 + dim + i], bmap->ineq[u][1 + dim + i]); + isl_int_divexact(fl, bmap->ineq[l][1 + dim + i], g); + isl_int_divexact(fu, bmap->ineq[u][1 + dim + i], g); + isl_int_neg(fu, fu); + isl_seq_combine(ineq, fl, bmap->ineq[u], fu, bmap->ineq[l], + 1 + dim + bmap->n_div); + isl_int_add(ineq[0], ineq[0], fl); + isl_int_add(ineq[0], ineq[0], fu); + isl_int_sub_ui(ineq[0], ineq[0], 1); + isl_int_mul(g, g, fl); + isl_int_mul(g, g, fu); + isl_int_sub(ineq[0], ineq[0], g); +} + +/* Remove more kinds of divs that are not strictly needed. + * In particular, if all pairs of lower and upper bounds on a div + * are such that they allow at least one integer value of the div, + * the we can eliminate the div using Fourier-Motzkin without + * introducing any spurious solutions. + */ +static struct isl_basic_map *drop_more_redundant_divs( + struct isl_basic_map *bmap, int *pairs, int n) +{ + struct isl_tab *tab = NULL; + struct isl_vec *vec = NULL; + unsigned dim; + int remove = -1; + isl_int g, fl, fu; + + isl_int_init(g); + isl_int_init(fl); + isl_int_init(fu); + + if (!bmap) + goto error; + + dim = isl_dim_total(bmap->dim); + vec = isl_vec_alloc(bmap->ctx, 1 + dim + bmap->n_div); + if (!vec) + goto error; + + tab = isl_tab_from_basic_map(bmap); + + while (n > 0) { + int i, l, u; + int best = -1; + enum isl_lp_result res; + + for (i = 0; i < bmap->n_div; ++i) { + if (!pairs[i]) + continue; + if (best >= 0 && pairs[best] <= pairs[i]) + continue; + best = i; + } + + i = best; + for (l = 0; l < bmap->n_ineq; ++l) { + if (!isl_int_is_pos(bmap->ineq[l][1 + dim + i])) + continue; + for (u = 0; u < bmap->n_ineq; ++u) { + if (!isl_int_is_neg(bmap->ineq[u][1 + dim + i])) + continue; + construct_test_ineq(bmap, i, l, u, + vec->el, g, fl, fu); + res = isl_tab_min(tab, vec->el, + bmap->ctx->one, &g, NULL, 0); + if (res == isl_lp_error) + goto error; + if (res == isl_lp_empty) { + bmap = isl_basic_map_set_to_empty(bmap); + break; + } + if (res != isl_lp_ok || isl_int_is_neg(g)) + break; + } + if (u < bmap->n_ineq) + break; + } + if (l == bmap->n_ineq) { + remove = i; + break; + } + pairs[i] = 0; + --n; + } + + isl_tab_free(tab); + isl_vec_free(vec); + + isl_int_clear(g); + isl_int_clear(fl); + isl_int_clear(fu); + + free(pairs); + + if (remove < 0) + return bmap; + + bmap = isl_basic_map_remove(bmap, isl_dim_div, remove, 1); + return isl_basic_map_drop_redundant_divs(bmap); +error: + free(pairs); + isl_basic_map_free(bmap); + isl_tab_free(tab); + isl_vec_free(vec); + isl_int_clear(g); + isl_int_clear(fl); + isl_int_clear(fu); + return NULL; +} + +/* Given a pair of divs div1 and div2 such that, expect for the lower bound l + * and the upper bound u, div1 always occurs together with div2 in the form + * (div1 + m div2), where m is the constant range on the variable div1 + * allowed by l and u, replace the pair div1 and div2 by a single + * div that is equal to div1 + m div2. + * + * The new div will appear in the location that contains div2. + * We need to modify all constraints that contain + * div2 = (div - div1) / m + * (If a constraint does not contain div2, it will also not contain div1.) + * If the constraint also contains div1, then we know they appear + * as f (div1 + m div2) and we can simply replace (div1 + m div2) by div, + * i.e., the coefficient of div is f. + * + * Otherwise, we first need to introduce div1 into the constraint. + * Let the l be + * + * div1 + f >=0 + * + * and u + * + * -div1 + f' >= 0 + * + * A lower bound on div2 + * + * n div2 + t >= 0 + * + * can be replaced by + * + * (n * (m div 2 + div1) + m t + n f)/g >= 0 + * + * with g = gcd(m,n). + * An upper bound + * + * -n div2 + t >= 0 + * + * can be replaced by + * + * (-n * (m div2 + div1) + m t + n f')/g >= 0 + * + * These constraint are those that we would obtain from eliminating + * div1 using Fourier-Motzkin. + * + * After all constraints have been modified, we drop the lower and upper + * bound and then drop div1. + */ +static struct isl_basic_map *coalesce_divs(struct isl_basic_map *bmap, + unsigned div1, unsigned div2, unsigned l, unsigned u) +{ + isl_int a; + isl_int b; + isl_int m; + unsigned dim, total; + int i; + + dim = isl_dim_total(bmap->dim); + total = 1 + dim + bmap->n_div; + + isl_int_init(a); + isl_int_init(b); + isl_int_init(m); + isl_int_add(m, bmap->ineq[l][0], bmap->ineq[u][0]); + isl_int_add_ui(m, m, 1); + + for (i = 0; i < bmap->n_ineq; ++i) { + if (i == l || i == u) + continue; + if (isl_int_is_zero(bmap->ineq[i][1 + dim + div2])) + continue; + if (isl_int_is_zero(bmap->ineq[i][1 + dim + div1])) { + isl_int_gcd(b, m, bmap->ineq[i][1 + dim + div2]); + isl_int_divexact(a, m, b); + isl_int_divexact(b, bmap->ineq[i][1 + dim + div2], b); + if (isl_int_is_pos(b)) { + isl_seq_combine(bmap->ineq[i], a, bmap->ineq[i], + b, bmap->ineq[l], total); + } else { + isl_int_neg(b, b); + isl_seq_combine(bmap->ineq[i], a, bmap->ineq[i], + b, bmap->ineq[u], total); + } + } + isl_int_set(bmap->ineq[i][1 + dim + div2], + bmap->ineq[i][1 + dim + div1]); + isl_int_set_si(bmap->ineq[i][1 + dim + div1], 0); + } + + isl_int_clear(a); + isl_int_clear(b); + isl_int_clear(m); + if (l > u) { + isl_basic_map_drop_inequality(bmap, l); + isl_basic_map_drop_inequality(bmap, u); + } else { + isl_basic_map_drop_inequality(bmap, u); + isl_basic_map_drop_inequality(bmap, l); + } + bmap = isl_basic_map_drop_div(bmap, div1); + return bmap; +} + +/* First check if we can coalesce any pair of divs and + * then continue with dropping more redundant divs. + * + * We loop over all pairs of lower and upper bounds on a div + * with coefficient 1 and -1, respectively, check if there + * is any other div "c" with which we can coalesce the div + * and if so, perform the coalescing. + */ +static struct isl_basic_map *coalesce_or_drop_more_redundant_divs( + struct isl_basic_map *bmap, int *pairs, int n) +{ + int i, l, u; + unsigned dim; + + dim = isl_dim_total(bmap->dim); + + for (i = 0; i < bmap->n_div; ++i) { + if (!pairs[i]) + continue; + for (l = 0; l < bmap->n_ineq; ++l) { + if (!isl_int_is_one(bmap->ineq[l][1 + dim + i])) + continue; + for (u = 0; u < bmap->n_ineq; ++u) { + int c; + + if (!isl_int_is_negone(bmap->ineq[u][1+dim+i])) + continue; + c = div_find_coalesce(bmap, pairs, i, l, u); + if (c < 0) + continue; + free(pairs); + bmap = coalesce_divs(bmap, i, c, l, u); + return isl_basic_map_drop_redundant_divs(bmap); + } + } + } + + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) + return bmap; + + return drop_more_redundant_divs(bmap, pairs, n); +} + +/* Remove divs that are not strictly needed. + * In particular, if a div only occurs positively (or negatively) + * in constraints, then it can simply be dropped. + * Also, if a div occurs only occurs in two constraints and if moreover + * those two constraints are opposite to each other, except for the constant + * term and if the sum of the constant terms is such that for any value + * of the other values, there is always at least one integer value of the + * div, i.e., if one plus this sum is greater than or equal to + * the (absolute value) of the coefficent of the div in the constraints, + * then we can also simply drop the div. + * + * If any divs are left after these simple checks then we move on + * to more complicated cases in drop_more_redundant_divs. + */ +struct isl_basic_map *isl_basic_map_drop_redundant_divs( + struct isl_basic_map *bmap) +{ + int i, j; + unsigned off; + int *pairs = NULL; + int n = 0; + + if (!bmap) + goto error; + + off = isl_dim_total(bmap->dim); + pairs = isl_calloc_array(bmap->ctx, int, bmap->n_div); + if (!pairs) + goto error; + + for (i = 0; i < bmap->n_div; ++i) { + int pos, neg; + int last_pos, last_neg; + int redundant; + int defined; + + defined = !isl_int_is_zero(bmap->div[i][0]); + for (j = 0; j < bmap->n_eq; ++j) + if (!isl_int_is_zero(bmap->eq[j][1 + off + i])) + break; + if (j < bmap->n_eq) + continue; + ++n; + pos = neg = 0; + for (j = 0; j < bmap->n_ineq; ++j) { + if (isl_int_is_pos(bmap->ineq[j][1 + off + i])) { + last_pos = j; + ++pos; + } + if (isl_int_is_neg(bmap->ineq[j][1 + off + i])) { + last_neg = j; + ++neg; + } + } + pairs[i] = pos * neg; + if (pairs[i] == 0) { + for (j = bmap->n_ineq - 1; j >= 0; --j) + if (!isl_int_is_zero(bmap->ineq[j][1+off+i])) + isl_basic_map_drop_inequality(bmap, j); + bmap = isl_basic_map_drop_div(bmap, i); + free(pairs); + return isl_basic_map_drop_redundant_divs(bmap); + } + if (pairs[i] != 1) + continue; + if (!isl_seq_is_neg(bmap->ineq[last_pos] + 1, + bmap->ineq[last_neg] + 1, + off + bmap->n_div)) + continue; + + isl_int_add(bmap->ineq[last_pos][0], + bmap->ineq[last_pos][0], bmap->ineq[last_neg][0]); + isl_int_add_ui(bmap->ineq[last_pos][0], + bmap->ineq[last_pos][0], 1); + redundant = isl_int_ge(bmap->ineq[last_pos][0], + bmap->ineq[last_pos][1+off+i]); + isl_int_sub_ui(bmap->ineq[last_pos][0], + bmap->ineq[last_pos][0], 1); + isl_int_sub(bmap->ineq[last_pos][0], + bmap->ineq[last_pos][0], bmap->ineq[last_neg][0]); + if (!redundant) { + if (defined || + !ok_to_set_div_from_bound(bmap, i, last_pos)) { + pairs[i] = 0; + --n; + continue; + } + bmap = set_div_from_lower_bound(bmap, i, last_pos); + bmap = isl_basic_map_simplify(bmap); + free(pairs); + return isl_basic_map_drop_redundant_divs(bmap); + } + if (last_pos > last_neg) { + isl_basic_map_drop_inequality(bmap, last_pos); + isl_basic_map_drop_inequality(bmap, last_neg); + } else { + isl_basic_map_drop_inequality(bmap, last_neg); + isl_basic_map_drop_inequality(bmap, last_pos); + } + bmap = isl_basic_map_drop_div(bmap, i); + free(pairs); + return isl_basic_map_drop_redundant_divs(bmap); + } + + if (n > 0) + return coalesce_or_drop_more_redundant_divs(bmap, pairs, n); + + free(pairs); + return bmap; +error: + free(pairs); + isl_basic_map_free(bmap); + return NULL; +} + +struct isl_basic_set *isl_basic_set_drop_redundant_divs( + struct isl_basic_set *bset) +{ + return (struct isl_basic_set *) + isl_basic_map_drop_redundant_divs((struct isl_basic_map *)bset); +} + +struct isl_map *isl_map_drop_redundant_divs(struct isl_map *map) +{ + int i; + + if (!map) + return NULL; + for (i = 0; i < map->n; ++i) { + map->p[i] = isl_basic_map_drop_redundant_divs(map->p[i]); + if (!map->p[i]) + goto error; + } + ISL_F_CLR(map, ISL_MAP_NORMALIZED); + return map; +error: + isl_map_free(map); + return NULL; +} + +struct isl_set *isl_set_drop_redundant_divs(struct isl_set *set) +{ + return (struct isl_set *) + isl_map_drop_redundant_divs((struct isl_map *)set); +}