brintos

brintos / llvm-project-archived public Read only

0
0
Text · 33.6 KiB · 3862509 Raw
1253 lines · c
1/*2 * Copyright 2008-2009 Katholieke Universiteit Leuven3 * Copyright 2010      INRIA Saclay4 * Copyright 2012      Ecole Normale Superieure5 *6 * Use of this software is governed by the MIT license7 *8 * Written by Sven Verdoolaege, K.U.Leuven, Departement9 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium10 * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,11 * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France12 * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France13 */14 15#include <isl_ctx_private.h>16#include <isl_map_private.h>17#include <isl_seq.h>18#include <isl/set.h>19#include <isl/lp.h>20#include <isl/map.h>21#include "isl_equalities.h"22#include "isl_sample.h"23#include "isl_tab.h"24#include <isl_mat_private.h>25#include <isl_vec_private.h>26 27#include <bset_to_bmap.c>28#include <bset_from_bmap.c>29#include <set_to_map.c>30#include <set_from_map.c>31 32__isl_give isl_basic_map *isl_basic_map_implicit_equalities(33	__isl_take isl_basic_map *bmap)34{35	struct isl_tab *tab;36 37	if (!bmap)38		return bmap;39 40	bmap = isl_basic_map_gauss(bmap, NULL);41	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))42		return bmap;43	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NO_IMPLICIT))44		return bmap;45	if (bmap->n_ineq <= 1)46		return bmap;47 48	tab = isl_tab_from_basic_map(bmap, 0);49	if (isl_tab_detect_implicit_equalities(tab) < 0)50		goto error;51	bmap = isl_basic_map_update_from_tab(bmap, tab);52	isl_tab_free(tab);53	bmap = isl_basic_map_gauss(bmap, NULL);54	ISL_F_SET(bmap, ISL_BASIC_MAP_NO_IMPLICIT);55	return bmap;56error:57	isl_tab_free(tab);58	isl_basic_map_free(bmap);59	return NULL;60}61 62__isl_give isl_basic_set *isl_basic_set_implicit_equalities(63	__isl_take isl_basic_set *bset)64{65	return bset_from_bmap(66		isl_basic_map_implicit_equalities(bset_to_bmap(bset)));67}68 69/* Make eq[row][col] of both bmaps equal so we can add the row70 * add the column to the common matrix.71 * Note that because of the echelon form, the columns of row row72 * after column col are zero.73 */74static void set_common_multiple(75	struct isl_basic_set *bset1, struct isl_basic_set *bset2,76	unsigned row, unsigned col)77{78	isl_int m, c;79 80	if (isl_int_eq(bset1->eq[row][col], bset2->eq[row][col]))81		return;82 83	isl_int_init(c);84	isl_int_init(m);85	isl_int_lcm(m, bset1->eq[row][col], bset2->eq[row][col]);86	isl_int_divexact(c, m, bset1->eq[row][col]);87	isl_seq_scale(bset1->eq[row], bset1->eq[row], c, col+1);88	isl_int_divexact(c, m, bset2->eq[row][col]);89	isl_seq_scale(bset2->eq[row], bset2->eq[row], c, col+1);90	isl_int_clear(c);91	isl_int_clear(m);92}93 94/* Delete a given equality, moving all the following equalities one up.95 */96static void delete_row(__isl_keep isl_basic_set *bset, unsigned row)97{98	isl_int *t;99	int r;100 101	t = bset->eq[row];102	bset->n_eq--;103	for (r = row; r < bset->n_eq; ++r)104		bset->eq[r] = bset->eq[r+1];105	bset->eq[bset->n_eq] = t;106}107 108/* Make first row entries in column col of bset1 identical to109 * those of bset2, using the fact that entry bset1->eq[row][col]=a110 * is non-zero.  Initially, these elements of bset1 are all zero.111 * For each row i < row, we set112 *		A[i] = a * A[i] + B[i][col] * A[row]113 *		B[i] = a * B[i]114 * so that115 *		A[i][col] = B[i][col] = a * old(B[i][col])116 */117static isl_stat construct_column(118	__isl_keep isl_basic_set *bset1, __isl_keep isl_basic_set *bset2,119	unsigned row, unsigned col)120{121	int r;122	isl_int a;123	isl_int b;124	isl_size total;125 126	total = isl_basic_set_dim(bset1, isl_dim_set);127	if (total < 0)128		return isl_stat_error;129 130	isl_int_init(a);131	isl_int_init(b);132	for (r = 0; r < row; ++r) {133		if (isl_int_is_zero(bset2->eq[r][col]))134			continue;135		isl_int_gcd(b, bset2->eq[r][col], bset1->eq[row][col]);136		isl_int_divexact(a, bset1->eq[row][col], b);137		isl_int_divexact(b, bset2->eq[r][col], b);138		isl_seq_combine(bset1->eq[r], a, bset1->eq[r],139					      b, bset1->eq[row], 1 + total);140		isl_seq_scale(bset2->eq[r], bset2->eq[r], a, 1 + total);141	}142	isl_int_clear(a);143	isl_int_clear(b);144	delete_row(bset1, row);145 146	return isl_stat_ok;147}148 149/* Make first row entries in column col of bset1 identical to150 * those of bset2, using only these entries of the two matrices.151 * Let t be the last row with different entries.152 * For each row i < t, we set153 *	A[i] = (A[t][col]-B[t][col]) * A[i] + (B[i][col]-A[i][col) * A[t]154 *	B[i] = (A[t][col]-B[t][col]) * B[i] + (B[i][col]-A[i][col) * B[t]155 * so that156 *	A[i][col] = B[i][col] = old(A[t][col]*B[i][col]-A[i][col]*B[t][col])157 */158static isl_bool transform_column(159	__isl_keep isl_basic_set *bset1, __isl_keep isl_basic_set *bset2,160	unsigned row, unsigned col)161{162	int i, t;163	isl_int a, b, g;164	isl_size total;165 166	for (t = row-1; t >= 0; --t)167		if (isl_int_ne(bset1->eq[t][col], bset2->eq[t][col]))168			break;169	if (t < 0)170		return isl_bool_false;171 172	total = isl_basic_set_dim(bset1, isl_dim_set);173	if (total < 0)174		return isl_bool_error;175	isl_int_init(a);176	isl_int_init(b);177	isl_int_init(g);178	isl_int_sub(b, bset1->eq[t][col], bset2->eq[t][col]);179	for (i = 0; i < t; ++i) {180		isl_int_sub(a, bset2->eq[i][col], bset1->eq[i][col]);181		isl_int_gcd(g, a, b);182		isl_int_divexact(a, a, g);183		isl_int_divexact(g, b, g);184		isl_seq_combine(bset1->eq[i], g, bset1->eq[i], a, bset1->eq[t],185				1 + total);186		isl_seq_combine(bset2->eq[i], g, bset2->eq[i], a, bset2->eq[t],187				1 + total);188	}189	isl_int_clear(a);190	isl_int_clear(b);191	isl_int_clear(g);192	delete_row(bset1, t);193	delete_row(bset2, t);194	return isl_bool_true;195}196 197/* The implementation is based on Section 5.2 of Michael Karr,198 * "Affine Relationships Among Variables of a Program",199 * except that the echelon form we use starts from the last column200 * and that we are dealing with integer coefficients.201 */202static __isl_give isl_basic_set *affine_hull(203	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)204{205	isl_size dim;206	unsigned total;207	int col;208	int row;209 210	dim = isl_basic_set_dim(bset1, isl_dim_set);211	if (dim < 0 || !bset2)212		goto error;213 214	total = 1 + dim;215 216	row = 0;217	for (col = total-1; col >= 0; --col) {218		int is_zero1 = row >= bset1->n_eq ||219			isl_int_is_zero(bset1->eq[row][col]);220		int is_zero2 = row >= bset2->n_eq ||221			isl_int_is_zero(bset2->eq[row][col]);222		if (!is_zero1 && !is_zero2) {223			set_common_multiple(bset1, bset2, row, col);224			++row;225		} else if (!is_zero1 && is_zero2) {226			if (construct_column(bset1, bset2, row, col) < 0)227				goto error;228		} else if (is_zero1 && !is_zero2) {229			if (construct_column(bset2, bset1, row, col) < 0)230				goto error;231		} else {232			isl_bool transform;233 234			transform = transform_column(bset1, bset2, row, col);235			if (transform < 0)236				goto error;237			if (transform)238				--row;239		}240	}241	isl_assert(bset1->ctx, row == bset1->n_eq, goto error);242	isl_basic_set_free(bset2);243	bset1 = isl_basic_set_normalize_constraints(bset1);244	return bset1;245error:246	isl_basic_set_free(bset1);247	isl_basic_set_free(bset2);248	return NULL;249}250 251/* Find an integer point in the set represented by "tab"252 * that lies outside of the equality "eq" e(x) = 0.253 * If "up" is true, look for a point satisfying e(x) - 1 >= 0.254 * Otherwise, look for a point satisfying -e(x) - 1 >= 0 (i.e., e(x) <= -1).255 * The point, if found, is returned.256 * If no point can be found, a zero-length vector is returned.257 *258 * Before solving an ILP problem, we first check if simply259 * adding the normal of the constraint to one of the known260 * integer points in the basic set represented by "tab"261 * yields another point inside the basic set.262 *263 * The caller of this function ensures that the tableau is bounded or264 * that tab->basis and tab->n_unbounded have been set appropriately.265 */266static __isl_give isl_vec *outside_point(struct isl_tab *tab, isl_int *eq,267	int up)268{269	struct isl_ctx *ctx;270	struct isl_vec *sample = NULL;271	struct isl_tab_undo *snap;272	unsigned dim;273 274	if (!tab)275		return NULL;276	ctx = tab->mat->ctx;277 278	dim = tab->n_var;279	sample = isl_vec_alloc(ctx, 1 + dim);280	if (!sample)281		return NULL;282	isl_int_set_si(sample->el[0], 1);283	isl_seq_combine(sample->el + 1,284		ctx->one, tab->bmap->sample->el + 1,285		up ? ctx->one : ctx->negone, eq + 1, dim);286	if (isl_basic_map_contains(tab->bmap, sample))287		return sample;288	isl_vec_free(sample);289	sample = NULL;290 291	snap = isl_tab_snap(tab);292 293	if (!up)294		isl_seq_neg(eq, eq, 1 + dim);295	isl_int_sub_ui(eq[0], eq[0], 1);296 297	if (isl_tab_extend_cons(tab, 1) < 0)298		goto error;299	if (isl_tab_add_ineq(tab, eq) < 0)300		goto error;301 302	sample = isl_tab_sample(tab);303 304	isl_int_add_ui(eq[0], eq[0], 1);305	if (!up)306		isl_seq_neg(eq, eq, 1 + dim);307 308	if (sample && isl_tab_rollback(tab, snap) < 0)309		goto error;310 311	return sample;312error:313	isl_vec_free(sample);314	return NULL;315}316 317__isl_give isl_basic_set *isl_basic_set_recession_cone(318	__isl_take isl_basic_set *bset)319{320	int i;321	isl_bool empty;322 323	empty = isl_basic_set_plain_is_empty(bset);324	if (empty < 0)325		return isl_basic_set_free(bset);326	if (empty)327		return bset;328 329	bset = isl_basic_set_cow(bset);330	if (isl_basic_set_check_no_locals(bset) < 0)331		return isl_basic_set_free(bset);332 333	for (i = 0; i < bset->n_eq; ++i)334		isl_int_set_si(bset->eq[i][0], 0);335 336	for (i = 0; i < bset->n_ineq; ++i)337		isl_int_set_si(bset->ineq[i][0], 0);338 339	ISL_F_CLR(bset, ISL_BASIC_SET_NO_IMPLICIT);340	return isl_basic_set_implicit_equalities(bset);341}342 343/* Move "sample" to a point that is one up (or down) from the original344 * point in dimension "pos".345 */346static void adjacent_point(__isl_keep isl_vec *sample, int pos, int up)347{348	if (up)349		isl_int_add_ui(sample->el[1 + pos], sample->el[1 + pos], 1);350	else351		isl_int_sub_ui(sample->el[1 + pos], sample->el[1 + pos], 1);352}353 354/* Check if any points that are adjacent to "sample" also belong to "bset".355 * If so, add them to "hull" and return the updated hull.356 *357 * Before checking whether and adjacent point belongs to "bset", we first358 * check whether it already belongs to "hull" as this test is typically359 * much cheaper.360 */361static __isl_give isl_basic_set *add_adjacent_points(362	__isl_take isl_basic_set *hull, __isl_take isl_vec *sample,363	__isl_keep isl_basic_set *bset)364{365	int i, up;366	isl_size dim;367 368	dim = isl_basic_set_dim(hull, isl_dim_set);369	if (!sample || dim < 0)370		goto error;371 372	for (i = 0; i < dim; ++i) {373		for (up = 0; up <= 1; ++up) {374			int contains;375			isl_basic_set *point;376 377			adjacent_point(sample, i, up);378			contains = isl_basic_set_contains(hull, sample);379			if (contains < 0)380				goto error;381			if (contains) {382				adjacent_point(sample, i, !up);383				continue;384			}385			contains = isl_basic_set_contains(bset, sample);386			if (contains < 0)387				goto error;388			if (contains) {389				point = isl_basic_set_from_vec(390							isl_vec_copy(sample));391				hull = affine_hull(hull, point);392			}393			adjacent_point(sample, i, !up);394			if (contains)395				break;396		}397	}398 399	isl_vec_free(sample);400 401	return hull;402error:403	isl_vec_free(sample);404	isl_basic_set_free(hull);405	return NULL;406}407 408/* Extend an initial (under-)approximation of the affine hull of basic409 * set represented by the tableau "tab"410 * by looking for points that do not satisfy one of the equalities411 * in the current approximation and adding them to that approximation412 * until no such points can be found any more.413 *414 * The caller of this function ensures that "tab" is bounded or415 * that tab->basis and tab->n_unbounded have been set appropriately.416 *417 * "bset" may be either NULL or the basic set represented by "tab".418 * If "bset" is not NULL, we check for any point we find if any419 * of its adjacent points also belong to "bset".420 */421static __isl_give isl_basic_set *extend_affine_hull(struct isl_tab *tab,422	__isl_take isl_basic_set *hull, __isl_keep isl_basic_set *bset)423{424	int i, j;425	unsigned dim;426 427	if (!tab || !hull)428		goto error;429 430	dim = tab->n_var;431 432	if (isl_tab_extend_cons(tab, 2 * dim + 1) < 0)433		goto error;434 435	for (i = 0; i < dim; ++i) {436		struct isl_vec *sample;437		struct isl_basic_set *point;438		for (j = 0; j < hull->n_eq; ++j) {439			sample = outside_point(tab, hull->eq[j], 1);440			if (!sample)441				goto error;442			if (sample->size > 0)443				break;444			isl_vec_free(sample);445			sample = outside_point(tab, hull->eq[j], 0);446			if (!sample)447				goto error;448			if (sample->size > 0)449				break;450			isl_vec_free(sample);451 452			if (isl_tab_add_eq(tab, hull->eq[j]) < 0)453				goto error;454		}455		if (j == hull->n_eq)456			break;457		if (tab->samples &&458		    isl_tab_add_sample(tab, isl_vec_copy(sample)) < 0)459			hull = isl_basic_set_free(hull);460		if (bset)461			hull = add_adjacent_points(hull, isl_vec_copy(sample),462						    bset);463		point = isl_basic_set_from_vec(sample);464		hull = affine_hull(hull, point);465		if (!hull)466			return NULL;467	}468 469	return hull;470error:471	isl_basic_set_free(hull);472	return NULL;473}474 475/* Construct an initial underapproximation of the hull of "bset"476 * from "sample" and any of its adjacent points that also belong to "bset".477 */478static __isl_give isl_basic_set *initialize_hull(__isl_keep isl_basic_set *bset,479	__isl_take isl_vec *sample)480{481	isl_basic_set *hull;482 483	hull = isl_basic_set_from_vec(isl_vec_copy(sample));484	hull = add_adjacent_points(hull, sample, bset);485 486	return hull;487}488 489/* Look for all equalities satisfied by the integer points in bset,490 * which is assumed to be bounded.491 *492 * The equalities are obtained by successively looking for493 * a point that is affinely independent of the points found so far.494 * In particular, for each equality satisfied by the points so far,495 * we check if there is any point on a hyperplane parallel to the496 * corresponding hyperplane shifted by at least one (in either direction).497 */498static __isl_give isl_basic_set *uset_affine_hull_bounded(499	__isl_take isl_basic_set *bset)500{501	struct isl_vec *sample = NULL;502	struct isl_basic_set *hull;503	struct isl_tab *tab = NULL;504	isl_size dim;505 506	if (isl_basic_set_plain_is_empty(bset))507		return bset;508 509	dim = isl_basic_set_dim(bset, isl_dim_set);510	if (dim < 0)511		return isl_basic_set_free(bset);512 513	if (bset->sample && bset->sample->size == 1 + dim) {514		int contains = isl_basic_set_contains(bset, bset->sample);515		if (contains < 0)516			goto error;517		if (contains) {518			if (dim == 0)519				return bset;520			sample = isl_vec_copy(bset->sample);521		} else {522			isl_vec_free(bset->sample);523			bset->sample = NULL;524		}525	}526 527	tab = isl_tab_from_basic_set(bset, 1);528	if (!tab)529		goto error;530	if (tab->empty) {531		isl_tab_free(tab);532		isl_vec_free(sample);533		return isl_basic_set_set_to_empty(bset);534	}535 536	if (!sample) {537		struct isl_tab_undo *snap;538		snap = isl_tab_snap(tab);539		sample = isl_tab_sample(tab);540		if (isl_tab_rollback(tab, snap) < 0)541			goto error;542		isl_vec_free(tab->bmap->sample);543		tab->bmap->sample = isl_vec_copy(sample);544	}545 546	if (!sample)547		goto error;548	if (sample->size == 0) {549		isl_tab_free(tab);550		isl_vec_free(sample);551		return isl_basic_set_set_to_empty(bset);552	}553 554	hull = initialize_hull(bset, sample);555 556	hull = extend_affine_hull(tab, hull, bset);557	isl_basic_set_free(bset);558	isl_tab_free(tab);559 560	return hull;561error:562	isl_vec_free(sample);563	isl_tab_free(tab);564	isl_basic_set_free(bset);565	return NULL;566}567 568/* Given an unbounded tableau and an integer point satisfying the tableau,569 * construct an initial affine hull containing the recession cone570 * shifted to the given point.571 *572 * The unbounded directions are taken from the last rows of the basis,573 * which is assumed to have been initialized appropriately.574 */575static __isl_give isl_basic_set *initial_hull(struct isl_tab *tab,576	__isl_take isl_vec *vec)577{578	int i;579	int k;580	struct isl_basic_set *bset = NULL;581	struct isl_ctx *ctx;582	isl_size dim;583 584	if (!vec || !tab)585		return NULL;586	ctx = vec->ctx;587	isl_assert(ctx, vec->size != 0, goto error);588 589	bset = isl_basic_set_alloc(ctx, 0, vec->size - 1, 0, vec->size - 1, 0);590	dim = isl_basic_set_dim(bset, isl_dim_set);591	if (dim < 0)592		goto error;593	dim -= tab->n_unbounded;594	for (i = 0; i < dim; ++i) {595		k = isl_basic_set_alloc_equality(bset);596		if (k < 0)597			goto error;598		isl_seq_cpy(bset->eq[k] + 1, tab->basis->row[1 + i] + 1,599			    vec->size - 1);600		isl_seq_inner_product(bset->eq[k] + 1, vec->el +1,601				      vec->size - 1, &bset->eq[k][0]);602		isl_int_neg(bset->eq[k][0], bset->eq[k][0]);603	}604	bset->sample = vec;605	bset = isl_basic_set_gauss(bset, NULL);606 607	return bset;608error:609	isl_basic_set_free(bset);610	isl_vec_free(vec);611	return NULL;612}613 614/* Given a tableau of a set and a tableau of the corresponding615 * recession cone, detect and add all equalities to the tableau.616 * If the tableau is bounded, then we can simply keep the617 * tableau in its state after the return from extend_affine_hull.618 * However, if the tableau is unbounded, then619 * isl_tab_set_initial_basis_with_cone will add some additional620 * constraints to the tableau that have to be removed again.621 * In this case, we therefore rollback to the state before622 * any constraints were added and then add the equalities back in.623 */624struct isl_tab *isl_tab_detect_equalities(struct isl_tab *tab,625	struct isl_tab *tab_cone)626{627	int j;628	struct isl_vec *sample;629	struct isl_basic_set *hull = NULL;630	struct isl_tab_undo *snap;631 632	if (!tab || !tab_cone)633		goto error;634 635	snap = isl_tab_snap(tab);636 637	isl_mat_free(tab->basis);638	tab->basis = NULL;639 640	isl_assert(tab->mat->ctx, tab->bmap, goto error);641	isl_assert(tab->mat->ctx, tab->samples, goto error);642	isl_assert(tab->mat->ctx, tab->samples->n_col == 1 + tab->n_var, goto error);643	isl_assert(tab->mat->ctx, tab->n_sample > tab->n_outside, goto error);644 645	if (isl_tab_set_initial_basis_with_cone(tab, tab_cone) < 0)646		goto error;647 648	sample = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var);649	if (!sample)650		goto error;651 652	isl_seq_cpy(sample->el, tab->samples->row[tab->n_outside], sample->size);653 654	isl_vec_free(tab->bmap->sample);655	tab->bmap->sample = isl_vec_copy(sample);656 657	if (tab->n_unbounded == 0)658		hull = isl_basic_set_from_vec(isl_vec_copy(sample));659	else660		hull = initial_hull(tab, isl_vec_copy(sample));661 662	for (j = tab->n_outside + 1; j < tab->n_sample; ++j) {663		isl_seq_cpy(sample->el, tab->samples->row[j], sample->size);664		hull = affine_hull(hull,665				isl_basic_set_from_vec(isl_vec_copy(sample)));666	}667 668	isl_vec_free(sample);669 670	hull = extend_affine_hull(tab, hull, NULL);671	if (!hull)672		goto error;673 674	if (tab->n_unbounded == 0) {675		isl_basic_set_free(hull);676		return tab;677	}678 679	if (isl_tab_rollback(tab, snap) < 0)680		goto error;681 682	if (hull->n_eq > tab->n_zero) {683		for (j = 0; j < hull->n_eq; ++j) {684			isl_seq_normalize(tab->mat->ctx, hull->eq[j], 1 + tab->n_var);685			if (isl_tab_add_eq(tab, hull->eq[j]) < 0)686				goto error;687		}688	}689 690	isl_basic_set_free(hull);691 692	return tab;693error:694	isl_basic_set_free(hull);695	isl_tab_free(tab);696	return NULL;697}698 699/* Compute the affine hull of "bset", where "cone" is the recession cone700 * of "bset".701 *702 * We first compute a unimodular transformation that puts the unbounded703 * directions in the last dimensions.  In particular, we take a transformation704 * that maps all equalities to equalities (in HNF) on the first dimensions.705 * Let x be the original dimensions and y the transformed, with y_1 bounded706 * and y_2 unbounded.707 *708 *	       [ y_1 ]			[ y_1 ]   [ Q_1 ]709 *	x = U  [ y_2 ]			[ y_2 ] = [ Q_2 ] x710 *711 * Let's call the input basic set S.  We compute S' = preimage(S, U)712 * and drop the final dimensions including any constraints involving them.713 * This results in set S''.714 * Then we compute the affine hull A'' of S''.715 * Let F y_1 >= g be the constraint system of A''.  In the transformed716 * space the y_2 are unbounded, so we can add them back without any constraints,717 * resulting in718 *719 *		        [ y_1 ]720 *		[ F 0 ] [ y_2 ] >= g721 * or722 *		        [ Q_1 ]723 *		[ F 0 ] [ Q_2 ] x >= g724 * or725 *		F Q_1 x >= g726 *727 * The affine hull in the original space is then obtained as728 * A = preimage(A'', Q_1).729 */730static __isl_give isl_basic_set *affine_hull_with_cone(731	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *cone)732{733	isl_size total;734	unsigned cone_dim;735	struct isl_basic_set *hull;736	struct isl_mat *M, *U, *Q;737 738	total = isl_basic_set_dim(cone, isl_dim_all);739	if (!bset || total < 0)740		goto error;741 742	cone_dim = total - cone->n_eq;743 744	M = isl_mat_sub_alloc6(bset->ctx, cone->eq, 0, cone->n_eq, 1, total);745	M = isl_mat_left_hermite(M, 0, &U, &Q);746	if (!M)747		goto error;748	isl_mat_free(M);749 750	U = isl_mat_lin_to_aff(U);751	bset = isl_basic_set_preimage(bset, isl_mat_copy(U));752 753	bset = isl_basic_set_drop_constraints_involving(bset, total - cone_dim,754							cone_dim);755	bset = isl_basic_set_drop_dims(bset, total - cone_dim, cone_dim);756 757	Q = isl_mat_lin_to_aff(Q);758	Q = isl_mat_drop_rows(Q, 1 + total - cone_dim, cone_dim);759 760	if (bset && bset->sample && bset->sample->size == 1 + total)761		bset->sample = isl_mat_vec_product(isl_mat_copy(Q), bset->sample);762 763	hull = uset_affine_hull_bounded(bset);764 765	if (!hull) {766		isl_mat_free(Q);767		isl_mat_free(U);768	} else {769		struct isl_vec *sample = isl_vec_copy(hull->sample);770		U = isl_mat_drop_cols(U, 1 + total - cone_dim, cone_dim);771		if (sample && sample->size > 0)772			sample = isl_mat_vec_product(U, sample);773		else774			isl_mat_free(U);775		hull = isl_basic_set_preimage(hull, Q);776		if (hull) {777			isl_vec_free(hull->sample);778			hull->sample = sample;779		} else780			isl_vec_free(sample);781	}782 783	isl_basic_set_free(cone);784 785	return hull;786error:787	isl_basic_set_free(bset);788	isl_basic_set_free(cone);789	return NULL;790}791 792/* Look for all equalities satisfied by the integer points in bset,793 * which is assumed not to have any explicit equalities.794 *795 * The equalities are obtained by successively looking for796 * a point that is affinely independent of the points found so far.797 * In particular, for each equality satisfied by the points so far,798 * we check if there is any point on a hyperplane parallel to the799 * corresponding hyperplane shifted by at least one (in either direction).800 *801 * Before looking for any outside points, we first compute the recession802 * cone.  The directions of this recession cone will always be part803 * of the affine hull, so there is no need for looking for any points804 * in these directions.805 * In particular, if the recession cone is full-dimensional, then806 * the affine hull is simply the whole universe.807 */808static __isl_give isl_basic_set *uset_affine_hull(809	__isl_take isl_basic_set *bset)810{811	struct isl_basic_set *cone;812	isl_size total;813 814	if (isl_basic_set_plain_is_empty(bset))815		return bset;816 817	cone = isl_basic_set_recession_cone(isl_basic_set_copy(bset));818	if (!cone)819		goto error;820	if (cone->n_eq == 0) {821		isl_space *space;822		space = isl_basic_set_get_space(bset);823		isl_basic_set_free(cone);824		isl_basic_set_free(bset);825		return isl_basic_set_universe(space);826	}827 828	total = isl_basic_set_dim(cone, isl_dim_all);829	if (total < 0)830		bset = isl_basic_set_free(bset);831	if (cone->n_eq < total)832		return affine_hull_with_cone(bset, cone);833 834	isl_basic_set_free(cone);835	return uset_affine_hull_bounded(bset);836error:837	isl_basic_set_free(bset);838	return NULL;839}840 841/* Look for all equalities satisfied by the integer points in bmap842 * that are independent of the equalities already explicitly available843 * in bmap.844 *845 * We first remove all equalities already explicitly available,846 * then look for additional equalities in the reduced space847 * and then transform the result to the original space.848 * The original equalities are _not_ added to this set.  This is849 * the responsibility of the calling function.850 * The resulting basic set has all meaning about the dimensions removed.851 * In particular, dimensions that correspond to existential variables852 * in bmap and that are found to be fixed are not removed.853 */854static __isl_give isl_basic_set *equalities_in_underlying_set(855	__isl_take isl_basic_map *bmap)856{857	struct isl_mat *T1 = NULL;858	struct isl_mat *T2 = NULL;859	struct isl_basic_set *bset = NULL;860	struct isl_basic_set *hull = NULL;861 862	bset = isl_basic_map_underlying_set(bmap);863	if (!bset)864		return NULL;865	if (bset->n_eq)866		bset = isl_basic_set_remove_equalities(bset, &T1, &T2);867	if (!bset)868		goto error;869 870	hull = uset_affine_hull(bset);871	if (!T2)872		return hull;873 874	if (!hull) {875		isl_mat_free(T1);876		isl_mat_free(T2);877	} else {878		struct isl_vec *sample = isl_vec_copy(hull->sample);879		if (sample && sample->size > 0)880			sample = isl_mat_vec_product(T1, sample);881		else882			isl_mat_free(T1);883		hull = isl_basic_set_preimage(hull, T2);884		if (hull) {885			isl_vec_free(hull->sample);886			hull->sample = sample;887		} else888			isl_vec_free(sample);889	}890 891	return hull;892error:893	isl_mat_free(T1);894	isl_mat_free(T2);895	isl_basic_set_free(bset);896	isl_basic_set_free(hull);897	return NULL;898}899 900/* Detect and make explicit all equalities satisfied by the (integer)901 * points in bmap.902 */903__isl_give isl_basic_map *isl_basic_map_detect_equalities(904	__isl_take isl_basic_map *bmap)905{906	int i, j;907	isl_size total;908	struct isl_basic_set *hull = NULL;909 910	if (!bmap)911		return NULL;912	if (bmap->n_ineq == 0)913		return bmap;914	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))915		return bmap;916	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_ALL_EQUALITIES))917		return bmap;918	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))919		return isl_basic_map_implicit_equalities(bmap);920 921	hull = equalities_in_underlying_set(isl_basic_map_copy(bmap));922	if (!hull)923		goto error;924	if (ISL_F_ISSET(hull, ISL_BASIC_SET_EMPTY)) {925		isl_basic_set_free(hull);926		return isl_basic_map_set_to_empty(bmap);927	}928	bmap = isl_basic_map_extend(bmap, 0, hull->n_eq, 0);929	total = isl_basic_set_dim(hull, isl_dim_all);930	if (total < 0)931		goto error;932	for (i = 0; i < hull->n_eq; ++i) {933		j = isl_basic_map_alloc_equality(bmap);934		if (j < 0)935			goto error;936		isl_seq_cpy(bmap->eq[j], hull->eq[i], 1 + total);937	}938	isl_vec_free(bmap->sample);939	bmap->sample = isl_vec_copy(hull->sample);940	isl_basic_set_free(hull);941	ISL_F_SET(bmap, ISL_BASIC_MAP_NO_IMPLICIT | ISL_BASIC_MAP_ALL_EQUALITIES);942	bmap = isl_basic_map_simplify(bmap);943	return isl_basic_map_finalize(bmap);944error:945	isl_basic_set_free(hull);946	isl_basic_map_free(bmap);947	return NULL;948}949 950__isl_give isl_basic_set *isl_basic_set_detect_equalities(951						__isl_take isl_basic_set *bset)952{953	return bset_from_bmap(954		isl_basic_map_detect_equalities(bset_to_bmap(bset)));955}956 957__isl_give isl_map *isl_map_detect_equalities(__isl_take isl_map *map)958{959	return isl_map_inline_foreach_basic_map(map,960					    &isl_basic_map_detect_equalities);961}962 963__isl_give isl_set *isl_set_detect_equalities(__isl_take isl_set *set)964{965	return set_from_map(isl_map_detect_equalities(set_to_map(set)));966}967 968/* Return the superset of "bmap" described by the equalities969 * satisfied by "bmap" that are already known.970 */971__isl_give isl_basic_map *isl_basic_map_plain_affine_hull(972	__isl_take isl_basic_map *bmap)973{974	bmap = isl_basic_map_cow(bmap);975	if (bmap)976		isl_basic_map_free_inequality(bmap, bmap->n_ineq);977	bmap = isl_basic_map_finalize(bmap);978	return bmap;979}980 981/* Return the superset of "bset" described by the equalities982 * satisfied by "bset" that are already known.983 */984__isl_give isl_basic_set *isl_basic_set_plain_affine_hull(985	__isl_take isl_basic_set *bset)986{987	return isl_basic_map_plain_affine_hull(bset);988}989 990/* After computing the rational affine hull (by detecting the implicit991 * equalities), we compute the additional equalities satisfied by992 * the integer points (if any) and add the original equalities back in.993 */994__isl_give isl_basic_map *isl_basic_map_affine_hull(995	__isl_take isl_basic_map *bmap)996{997	bmap = isl_basic_map_detect_equalities(bmap);998	bmap = isl_basic_map_plain_affine_hull(bmap);999	return bmap;1000}1001 1002__isl_give isl_basic_set *isl_basic_set_affine_hull(1003	__isl_take isl_basic_set *bset)1004{1005	return bset_from_bmap(isl_basic_map_affine_hull(bset_to_bmap(bset)));1006}1007 1008/* Given a rational affine matrix "M", add stride constraints to "bmap"1009 * that ensure that1010 *1011 *		M(x)1012 *1013 * is an integer vector.  The variables x include all the variables1014 * of "bmap" except the unknown divs.1015 *1016 * If d is the common denominator of M, then we need to impose that1017 *1018 *		d M(x) = 0 	mod d1019 *1020 * or1021 *1022 *		exists alpha : d M(x) = d alpha1023 *1024 * This function is similar to add_strides in isl_morph.c1025 */1026static __isl_give isl_basic_map *add_strides(__isl_take isl_basic_map *bmap,1027	__isl_keep isl_mat *M, int n_known)1028{1029	int i, div, k;1030	isl_int gcd;1031 1032	if (isl_int_is_one(M->row[0][0]))1033		return bmap;1034 1035	bmap = isl_basic_map_extend(bmap, M->n_row - 1, M->n_row - 1, 0);1036 1037	isl_int_init(gcd);1038	for (i = 1; i < M->n_row; ++i) {1039		isl_seq_gcd(M->row[i], M->n_col, &gcd);1040		if (isl_int_is_divisible_by(gcd, M->row[0][0]))1041			continue;1042		div = isl_basic_map_alloc_div(bmap);1043		if (div < 0)1044			goto error;1045		isl_int_set_si(bmap->div[div][0], 0);1046		k = isl_basic_map_alloc_equality(bmap);1047		if (k < 0)1048			goto error;1049		isl_seq_cpy(bmap->eq[k], M->row[i], M->n_col);1050		isl_seq_clr(bmap->eq[k] + M->n_col, bmap->n_div - n_known);1051		isl_int_set(bmap->eq[k][M->n_col - n_known + div],1052			    M->row[0][0]);1053	}1054	isl_int_clear(gcd);1055 1056	return bmap;1057error:1058	isl_int_clear(gcd);1059	isl_basic_map_free(bmap);1060	return NULL;1061}1062 1063/* If there are any equalities that involve (multiple) unknown divs,1064 * then extract the stride information encoded by those equalities1065 * and make it explicitly available in "bmap".1066 *1067 * We first sort the divs so that the unknown divs appear last and1068 * then we count how many equalities involve these divs.1069 *1070 * Let these equalities be of the form1071 *1072 *		A(x) + B y = 01073 *1074 * where y represents the unknown divs and x the remaining variables.1075 * Let [H 0] be the Hermite Normal Form of B, i.e.,1076 *1077 *		B = [H 0] Q1078 *1079 * Then x is a solution of the equalities iff1080 *1081 *		H^-1 A(x) (= - [I 0] Q y)1082 *1083 * is an integer vector.  Let d be the common denominator of H^-1.1084 * We impose1085 *1086 *		d H^-1 A(x) = d alpha1087 *1088 * in add_strides, with alpha fresh existentially quantified variables.1089 */1090static __isl_give isl_basic_map *isl_basic_map_make_strides_explicit(1091	__isl_take isl_basic_map *bmap)1092{1093	isl_bool known;1094	int n_known;1095	int n, n_col;1096	isl_size v_div;1097	isl_ctx *ctx;1098	isl_mat *A, *B, *M;1099 1100	known = isl_basic_map_divs_known(bmap);1101	if (known < 0)1102		return isl_basic_map_free(bmap);1103	if (known)1104		return bmap;1105	bmap = isl_basic_map_sort_divs(bmap);1106	bmap = isl_basic_map_gauss(bmap, NULL);1107	if (!bmap)1108		return NULL;1109 1110	for (n_known = 0; n_known < bmap->n_div; ++n_known)1111		if (isl_int_is_zero(bmap->div[n_known][0]))1112			break;1113	v_div = isl_basic_map_var_offset(bmap, isl_dim_div);1114	if (v_div < 0)1115		return isl_basic_map_free(bmap);1116	for (n = 0; n < bmap->n_eq; ++n)1117		if (isl_seq_first_non_zero(bmap->eq[n] + 1 + v_div + n_known,1118					    bmap->n_div - n_known) == -1)1119			break;1120	if (n == 0)1121		return bmap;1122	ctx = isl_basic_map_get_ctx(bmap);1123	B = isl_mat_sub_alloc6(ctx, bmap->eq, 0, n, 0, 1 + v_div + n_known);1124	n_col = bmap->n_div - n_known;1125	A = isl_mat_sub_alloc6(ctx, bmap->eq, 0, n, 1 + v_div + n_known, n_col);1126	A = isl_mat_left_hermite(A, 0, NULL, NULL);1127	A = isl_mat_drop_cols(A, n, n_col - n);1128	A = isl_mat_lin_to_aff(A);1129	A = isl_mat_right_inverse(A);1130	B = isl_mat_insert_zero_rows(B, 0, 1);1131	B = isl_mat_set_element_si(B, 0, 0, 1);1132	M = isl_mat_product(A, B);1133	if (!M)1134		return isl_basic_map_free(bmap);1135	bmap = add_strides(bmap, M, n_known);1136	bmap = isl_basic_map_gauss(bmap, NULL);1137	isl_mat_free(M);1138 1139	return bmap;1140}1141 1142/* Compute the affine hull of each basic map in "map" separately1143 * and make all stride information explicit so that we can remove1144 * all unknown divs without losing this information.1145 * The result is also guaranteed to be gaussed.1146 *1147 * In simple cases where a div is determined by an equality,1148 * calling isl_basic_map_gauss is enough to make the stride information1149 * explicit, as it will derive an explicit representation for the div1150 * from the equality.  If, however, the stride information1151 * is encoded through multiple unknown divs then we need to make1152 * some extra effort in isl_basic_map_make_strides_explicit.1153 */1154static __isl_give isl_map *isl_map_local_affine_hull(__isl_take isl_map *map)1155{1156	int i;1157 1158	map = isl_map_cow(map);1159	if (!map)1160		return NULL;1161 1162	for (i = 0; i < map->n; ++i) {1163		map->p[i] = isl_basic_map_affine_hull(map->p[i]);1164		map->p[i] = isl_basic_map_gauss(map->p[i], NULL);1165		map->p[i] = isl_basic_map_make_strides_explicit(map->p[i]);1166		if (!map->p[i])1167			return isl_map_free(map);1168	}1169 1170	return map;1171}1172 1173static __isl_give isl_set *isl_set_local_affine_hull(__isl_take isl_set *set)1174{1175	return isl_map_local_affine_hull(set);1176}1177 1178/* Return an empty basic map living in the same space as "map".1179 */1180static __isl_give isl_basic_map *replace_map_by_empty_basic_map(1181	__isl_take isl_map *map)1182{1183	isl_space *space;1184 1185	space = isl_map_get_space(map);1186	isl_map_free(map);1187	return isl_basic_map_empty(space);1188}1189 1190/* Compute the affine hull of "map".1191 *1192 * We first compute the affine hull of each basic map separately.1193 * Then we align the divs and recompute the affine hulls of the basic1194 * maps since some of them may now have extra divs.1195 * In order to avoid performing parametric integer programming to1196 * compute explicit expressions for the divs, possible leading to1197 * an explosion in the number of basic maps, we first drop all unknown1198 * divs before aligning the divs.  Note that isl_map_local_affine_hull tries1199 * to make sure that all stride information is explicitly available1200 * in terms of known divs.  This involves calling isl_basic_set_gauss,1201 * which is also needed because affine_hull assumes its input has been gaussed,1202 * while isl_map_affine_hull may be called on input that has not been gaussed,1203 * in particular from initial_facet_constraint.1204 * Similarly, align_divs may reorder some divs so that we need to1205 * gauss the result again.1206 * Finally, we combine the individual affine hulls into a single1207 * affine hull.1208 */1209__isl_give isl_basic_map *isl_map_affine_hull(__isl_take isl_map *map)1210{1211	struct isl_basic_map *model = NULL;1212	struct isl_basic_map *hull = NULL;1213	struct isl_set *set;1214	isl_basic_set *bset;1215 1216	map = isl_map_detect_equalities(map);1217	map = isl_map_local_affine_hull(map);1218	map = isl_map_remove_empty_parts(map);1219	map = isl_map_remove_unknown_divs(map);1220	map = isl_map_align_divs_internal(map);1221 1222	if (!map)1223		return NULL;1224 1225	if (map->n == 0)1226		return replace_map_by_empty_basic_map(map);1227 1228	model = isl_basic_map_copy(map->p[0]);1229	set = isl_map_underlying_set(map);1230	set = isl_set_cow(set);1231	set = isl_set_local_affine_hull(set);1232	if (!set)1233		goto error;1234 1235	while (set->n > 1)1236		set->p[0] = affine_hull(set->p[0], set->p[--set->n]);1237 1238	bset = isl_basic_set_copy(set->p[0]);1239	hull = isl_basic_map_overlying_set(bset, model);1240	isl_set_free(set);1241	hull = isl_basic_map_simplify(hull);1242	return isl_basic_map_finalize(hull);1243error:1244	isl_basic_map_free(model);1245	isl_set_free(set);1246	return NULL;1247}1248 1249__isl_give isl_basic_set *isl_set_affine_hull(__isl_take isl_set *set)1250{1251	return bset_from_bmap(isl_map_affine_hull(set_to_map(set)));1252}1253