/* * Copyright 2008-2009 Katholieke Universiteit Leuven * Copyright 2012-2013 Ecole Normale Superieure * Copyright 2014-2015 INRIA Rocquencourt * Copyright 2016 Sven Verdoolaege * * Use of this software is governed by the MIT license * * Written by Sven Verdoolaege, K.U.Leuven, Departement * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, * B.P. 105 - 78153 Le Chesnay, France */ #include <isl_ctx_private.h> #include <isl_map_private.h> #include "isl_equalities.h" #include <isl/map.h> #include <isl_seq.h> #include "isl_tab.h" #include <isl_space_private.h> #include <isl_mat_private.h> #include <isl_vec_private.h> #include <bset_to_bmap.c> #include <bset_from_bmap.c> #include <set_to_map.c> #include <set_from_map.c> static void swap_equality(__isl_keep isl_basic_map *bmap, int a, int b) { … } static void swap_inequality(__isl_keep isl_basic_map *bmap, int a, int b) { … } __isl_give isl_basic_map *isl_basic_map_normalize_constraints( __isl_take isl_basic_map *bmap) { … } __isl_give isl_basic_set *isl_basic_set_normalize_constraints( __isl_take isl_basic_set *bset) { … } /* Reduce the coefficient of the variable at position "pos" * in integer division "div", such that it lies in the half-open * interval (1/2,1/2], extracting any excess value from this integer division. * "pos" is as determined by isl_basic_map_offset, i.e., pos == 0 * corresponds to the constant term. * * That is, the integer division is of the form * * floor((... + (c * d + r) * x_pos + ...)/d) * * with -d < 2 * r <= d. * Replace it by * * floor((... + r * x_pos + ...)/d) + c * x_pos * * If 2 * ((c * d + r) % d) <= d, then c = floor((c * d + r)/d). * Otherwise, c = floor((c * d + r)/d) + 1. * * This is the same normalization that is performed by isl_aff_floor. */ static __isl_give isl_basic_map *reduce_coefficient_in_div( __isl_take isl_basic_map *bmap, int div, int pos) { … } /* Does the coefficient of the variable at position "pos" * in integer division "div" need to be reduced? * That is, does it lie outside the half-open interval (1/2,1/2]? * The coefficient c/d lies outside this interval if abs(2 * c) >= d and * 2 * c != d. */ static isl_bool needs_reduction(__isl_keep isl_basic_map *bmap, int div, int pos) { … } /* Reduce the coefficients (including the constant term) of * integer division "div", if needed. * In particular, make sure all coefficients lie in * the half-open interval (1/2,1/2]. */ static __isl_give isl_basic_map *reduce_div_coefficients_of_div( __isl_take isl_basic_map *bmap, int div) { … } /* Reduce the coefficients (including the constant term) of * the known integer divisions, if needed * In particular, make sure all coefficients lie in * the half-open interval (1/2,1/2]. */ static __isl_give isl_basic_map *reduce_div_coefficients( __isl_take isl_basic_map *bmap) { … } /* Remove any common factor in numerator and denominator of the div expression, * not taking into account the constant term. * That is, if the div is of the form * * floor((a + m f(x))/(m d)) * * then replace it by * * floor((floor(a/m) + f(x))/d) * * The difference {a/m}/d in the argument satisfies 0 <= {a/m}/d < 1/d * and can therefore not influence the result of the floor. */ static __isl_give isl_basic_map *normalize_div_expression( __isl_take isl_basic_map *bmap, int div) { … } /* Remove any common factor in numerator and denominator of a div expression, * not taking into account the constant term. * That is, look for any div of the form * * floor((a + m f(x))/(m d)) * * and replace it by * * floor((floor(a/m) + f(x))/d) * * The difference {a/m}/d in the argument satisfies 0 <= {a/m}/d < 1/d * and can therefore not influence the result of the floor. */ static __isl_give isl_basic_map *normalize_div_expressions( __isl_take isl_basic_map *bmap) { … } /* Assumes divs have been ordered if keep_divs is set. */ static __isl_give isl_basic_map *eliminate_var_using_equality( __isl_take isl_basic_map *bmap, unsigned pos, isl_int *eq, int keep_divs, int *progress) { … } /* Assumes divs have been ordered if keep_divs is set. */ static __isl_give isl_basic_map *eliminate_div(__isl_take isl_basic_map *bmap, isl_int *eq, unsigned div, int keep_divs) { … } /* Check if elimination of div "div" using equality "eq" would not * result in a div depending on a later div. */ static isl_bool ok_to_eliminate_div(__isl_keep isl_basic_map *bmap, isl_int *eq, unsigned div) { … } /* Eliminate divs based on equalities */ static __isl_give isl_basic_map *eliminate_divs_eq( __isl_take isl_basic_map *bmap, int *progress) { … } /* Eliminate divs based on inequalities */ static __isl_give isl_basic_map *eliminate_divs_ineq( __isl_take isl_basic_map *bmap, int *progress) { … } /* Does the equality constraint at position "eq" in "bmap" involve * any local variables in the range [first, first + n) * that are not marked as having an explicit representation? */ static isl_bool bmap_eq_involves_unknown_divs(__isl_keep isl_basic_map *bmap, int eq, unsigned first, unsigned n) { … } /* The last local variable involved in the equality constraint * at position "eq" in "bmap" is the local variable at position "div". * It can therefore be used to extract an explicit representation * for that variable. * Do so unless the local variable already has an explicit representation or * the explicit representation would involve any other local variables * that in turn do not have an explicit representation. * An equality constraint involving local variables without an explicit * representation can be used in isl_basic_map_drop_redundant_divs * to separate out an independent local variable. Introducing * an explicit representation here would block this transformation, * while the partial explicit representation in itself is not very useful. * Set *progress if anything is changed. * * The equality constraint is of the form * * f(x) + n e >= 0 * * with n a positive number. The explicit representation derived from * this constraint is * * floor((-f(x))/n) */ static __isl_give isl_basic_map *set_div_from_eq(__isl_take isl_basic_map *bmap, int div, int eq, int *progress) { … } /* Perform fangcheng (Gaussian elimination) on the equality * constraints of "bmap". * That is, put them into row-echelon form, starting from the last column * backward and use them to eliminate the corresponding coefficients * from all constraints. * * If "progress" is not NULL, then it gets set if the elimination * results in any changes. * The elimination process may result in some equality constraints * getting interchanged or removed. * If "swap" or "drop" are not NULL, then they get called when * two equality constraints get interchanged or * when a number of final equality constraints get removed. * As a special case, if the input turns out to be empty, * then drop gets called with the number of removed equality * constraints set to the total number of equality constraints. * If "swap" or "drop" are not NULL, then the local variables (if any) * are assumed to be in a valid order. */ __isl_give isl_basic_map *isl_basic_map_gauss5(__isl_take isl_basic_map *bmap, int *progress, isl_stat (*swap)(unsigned a, unsigned b, void *user), isl_stat (*drop)(unsigned n, void *user), void *user) { … } __isl_give isl_basic_map *isl_basic_map_gauss(__isl_take isl_basic_map *bmap, int *progress) { … } __isl_give isl_basic_set *isl_basic_set_gauss( __isl_take isl_basic_set *bset, int *progress) { … } static unsigned int round_up(unsigned int v) { … } /* Hash table of inequalities in a basic map. * "index" is an array of addresses of inequalities in the basic map, some * of which are NULL. The inequalities are hashed on the coefficients * except the constant term. * "size" is the number of elements in the array and is always a power of two * "bits" is the number of bits need to represent an index into the array. * "total" is the total dimension of the basic map. */ struct isl_constraint_index { … }; /* Fill in the "ci" data structure for holding the inequalities of "bmap". */ static isl_stat create_constraint_index(struct isl_constraint_index *ci, __isl_keep isl_basic_map *bmap) { … } /* Free the memory allocated by create_constraint_index. */ static void constraint_index_free(struct isl_constraint_index *ci) { … } /* Return the position in ci->index that contains the address of * an inequality that is equal to *ineq up to the constant term, * provided this address is not identical to "ineq". * If there is no such inequality, then return the position where * such an inequality should be inserted. */ static int hash_index_ineq(struct isl_constraint_index *ci, isl_int **ineq) { … } /* Return the position in ci->index that contains the address of * an inequality that is equal to the k'th inequality of "bmap" * up to the constant term, provided it does not point to the very * same inequality. * If there is no such inequality, then return the position where * such an inequality should be inserted. */ static int hash_index(struct isl_constraint_index *ci, __isl_keep isl_basic_map *bmap, int k) { … } static int set_hash_index(struct isl_constraint_index *ci, __isl_keep isl_basic_set *bset, int k) { … } /* Fill in the "ci" data structure with the inequalities of "bset". */ static isl_stat setup_constraint_index(struct isl_constraint_index *ci, __isl_keep isl_basic_set *bset) { … } /* Is the inequality ineq (obviously) redundant with respect * to the constraints in "ci"? * * Look for an inequality in "ci" with the same coefficients and then * check if the contant term of "ineq" is greater than or equal * to the constant term of that inequality. If so, "ineq" is clearly * redundant. * * Note that hash_index_ineq ignores a stored constraint if it has * the same address as the passed inequality. It is ok to pass * the address of a local variable here since it will never be * the same as the address of a constraint in "ci". */ static isl_bool constraint_index_is_redundant(struct isl_constraint_index *ci, isl_int *ineq) { … } /* If we can eliminate more than one div, then we need to make * sure we do it from last div to first div, in order not to * change the position of the other divs that still need to * be removed. */ static __isl_give isl_basic_map *remove_duplicate_divs( __isl_take isl_basic_map *bmap, int *progress) { … } static int n_pure_div_eq(__isl_keep isl_basic_map *bmap) { … } /* Normalize divs that appear in equalities. * * In particular, we assume that bmap contains some equalities * of the form * * a x = m * e_i * * and we want to replace the set of e_i by a minimal set and * such that the new e_i have a canonical representation in terms * of the vector x. * If any of the equalities involves more than one divs, then * we currently simply bail out. * * Let us first additionally assume that all equalities involve * a div. The equalities then express modulo constraints on the * remaining variables and we can use "parameter compression" * to find a minimal set of constraints. The result is a transformation * * x = T(x') = x_0 + G x' * * with G a lower-triangular matrix with all elements below the diagonal * non-negative and smaller than the diagonal element on the same row. * We first normalize x_0 by making the same property hold in the affine * T matrix. * The rows i of G with a 1 on the diagonal do not impose any modulo * constraint and simply express x_i = x'_i. * For each of the remaining rows i, we introduce a div and a corresponding * equality. In particular * * g_ii e_j = x_i - g_i(x') * * where each x'_k is replaced either by x_k (if g_kk = 1) or the * corresponding div (if g_kk != 1). * * If there are any equalities not involving any div, then we * first apply a variable compression on the variables x: * * x = C x'' x'' = C_2 x * * and perform the above parameter compression on A C instead of on A. * The resulting compression is then of the form * * x'' = T(x') = x_0 + G x' * * and in constructing the new divs and the corresponding equalities, * we have to replace each x'', i.e., the x'_k with (g_kk = 1), * by the corresponding row from C_2. */ static __isl_give isl_basic_map *normalize_divs(__isl_take isl_basic_map *bmap, int *progress) { … } static __isl_give isl_basic_map *set_div_from_lower_bound( __isl_take isl_basic_map *bmap, int div, int ineq) { … } /* 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 isl_bool ok_to_set_div_from_bound(__isl_keep isl_basic_map *bmap, int div, int ineq) { … } /* Would an expression for div "div" based on inequality "ineq" of "bmap" * be a better expression than the current one? * * If we do not have any expression yet, then any expression would be better. * Otherwise we check if the last variable involved in the inequality * (disregarding the div that it would define) is in an earlier position * than the last variable involved in the current div expression. */ static isl_bool better_div_constraint(__isl_keep isl_basic_map *bmap, int div, int ineq) { … } /* 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 or * a "better" expression for a div for which we already have an expression. * "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 to 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 __isl_give isl_basic_map *check_for_div_constraints( __isl_take isl_basic_map *bmap, int k, int l, isl_int sum, int *progress) { … } __isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints( __isl_take isl_basic_map *bmap, int *progress, int detect_divs) { … } /* Detect all pairs of inequalities that form an equality. * * isl_basic_map_remove_duplicate_constraints detects at most one such pair. * Call it repeatedly while it is making progress. */ __isl_give isl_basic_map *isl_basic_map_detect_inequality_pairs( __isl_take isl_basic_map *bmap, int *progress) { … } /* Given a known integer division "div" that is not integral * (with denominator 1), eliminate it from the constraints in "bmap" * where it appears with a (positive or negative) unit coefficient. * If "progress" is not NULL, then it gets set if the elimination * results in any changes. * * That is, replace * * floor(e/m) + f >= 0 * * by * * e + m f >= 0 * * and * * -floor(e/m) + f >= 0 * * by * * -e + m f + m - 1 >= 0 * * The first conversion is valid because floor(e/m) >= -f is equivalent * to e/m >= -f because -f is an integral expression. * The second conversion follows from the fact that * * -floor(e/m) = ceil(-e/m) = floor((-e + m - 1)/m) * * * Note that one of the div constraints may have been eliminated * due to being redundant with respect to the constraint that is * being modified by this function. The modified constraint may * no longer imply this div constraint, so we add it back to make * sure we do not lose any information. */ static __isl_give isl_basic_map *eliminate_unit_div( __isl_take isl_basic_map *bmap, int div, int *progress) { … } /* Eliminate selected known divs from constraints where they appear with * a (positive or negative) unit coefficient. * In particular, only handle those for which "select" returns isl_bool_true. * If "progress" is not NULL, then it gets set if the elimination * results in any changes. * * We skip integral divs, i.e., those with denominator 1, as we would * risk eliminating the div from the div constraints. We do not need * to handle those divs here anyway since the div constraints will turn * out to form an equality and this equality can then be used to eliminate * the div from all constraints. */ static __isl_give isl_basic_map *eliminate_selected_unit_divs( __isl_take isl_basic_map *bmap, isl_bool (*select)(__isl_keep isl_basic_map *bmap, int div), int *progress) { … } /* eliminate_selected_unit_divs callback that selects every * integer division. */ static isl_bool is_any_div(__isl_keep isl_basic_map *bmap, int div) { … } /* Eliminate known divs from constraints where they appear with * a (positive or negative) unit coefficient. * If "progress" is not NULL, then it gets set if the elimination * results in any changes. */ static __isl_give isl_basic_map *eliminate_unit_divs( __isl_take isl_basic_map *bmap, int *progress) { … } /* eliminate_selected_unit_divs callback that selects * integer divisions that only appear with * a (positive or negative) unit coefficient * (outside their div constraints). */ static isl_bool is_pure_unit_div(__isl_keep isl_basic_map *bmap, int div) { … } /* Eliminate known divs from constraints where they appear with * a (positive or negative) unit coefficient, * but only if they do not appear in any other constraints * (other than the div constraints). */ __isl_give isl_basic_map *isl_basic_map_eliminate_pure_unit_divs( __isl_take isl_basic_map *bmap) { … } __isl_give isl_basic_map *isl_basic_map_simplify(__isl_take isl_basic_map *bmap) { … } __isl_give isl_basic_set *isl_basic_set_simplify( __isl_take isl_basic_set *bset) { … } isl_bool isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap, isl_int *constraint, unsigned div) { … } /* If the only constraints a div d=floor(f/m) * appears in are its two defining constraints * * f - m d >=0 * -(f - (m - 1)) + m d >= 0 * * then it can safely be removed. */ static isl_bool div_is_redundant(__isl_keep isl_basic_map *bmap, int div) { … } /* * Remove divs that don't occur in any of the constraints or other divs. * These can arise when dropping constraints from a basic map or * when the divs of a basic map have been temporarily aligned * with the divs of another basic map. */ static __isl_give isl_basic_map *remove_redundant_divs( __isl_take isl_basic_map *bmap) { … } /* Mark "bmap" as final, without checking for obviously redundant * integer divisions. This function should be used when "bmap" * is known not to involve any such integer divisions. */ __isl_give isl_basic_map *isl_basic_map_mark_final( __isl_take isl_basic_map *bmap) { … } /* Mark "bmap" as final, after removing obviously redundant integer divisions. */ __isl_give isl_basic_map *isl_basic_map_finalize(__isl_take isl_basic_map *bmap) { … } __isl_give isl_basic_set *isl_basic_set_finalize( __isl_take isl_basic_set *bset) { … } /* 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 __isl_give isl_basic_map *remove_dependent_vars( __isl_take isl_basic_map *bmap, int pos) { … } /* Eliminate the specified variables from the constraints using * Fourier-Motzkin. The variables themselves are not removed. */ __isl_give isl_basic_map *isl_basic_map_eliminate_vars( __isl_take isl_basic_map *bmap, unsigned pos, unsigned n) { … } __isl_give isl_basic_set *isl_basic_set_eliminate_vars( __isl_take isl_basic_set *bset, unsigned pos, unsigned n) { … } /* Eliminate the specified n dimensions starting at first from the * constraints, without removing the dimensions from the space. * If the set is rational, the dimensions are eliminated using Fourier-Motzkin. * Otherwise, they are projected out and the original space is restored. */ __isl_give isl_basic_map *isl_basic_map_eliminate( __isl_take isl_basic_map *bmap, enum isl_dim_type type, unsigned first, unsigned n) { … } __isl_give isl_basic_set *isl_basic_set_eliminate( __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned first, unsigned n) { … } /* Remove all constraints from "bmap" that reference any unknown local * variables (directly or indirectly). * * Dropping all constraints on a local variable will make it redundant, * so it will get removed implicitly by * isl_basic_map_drop_constraints_involving_dims. Some other local * variables may also end up becoming redundant if they only appear * in constraints together with the unknown local variable. * Therefore, start over after calling * isl_basic_map_drop_constraints_involving_dims. */ __isl_give isl_basic_map *isl_basic_map_drop_constraints_involving_unknown_divs( __isl_take isl_basic_map *bmap) { … } /* Remove all constraints from "bset" that reference any unknown local * variables (directly or indirectly). */ __isl_give isl_basic_set *isl_basic_set_drop_constraints_involving_unknown_divs( __isl_take isl_basic_set *bset) { … } /* Remove all constraints from "map" that reference any unknown local * variables (directly or indirectly). * * Since constraints may get dropped from the basic maps, * they may no longer be disjoint from each other. */ __isl_give isl_map *isl_map_drop_constraints_involving_unknown_divs( __isl_take isl_map *map) { … } /* Don't assume equalities are in order, because align_divs * may have changed the order of the divs. */ static void compute_elimination_index(__isl_keep isl_basic_map *bmap, int *elim, unsigned len) { … } static void set_compute_elimination_index(__isl_keep isl_basic_set *bset, int *elim, unsigned len) { … } static int reduced_using_equalities(isl_int *dst, isl_int *src, __isl_keep isl_basic_map *bmap, int *elim, unsigned total) { … } static int set_reduced_using_equalities(isl_int *dst, isl_int *src, __isl_keep isl_basic_set *bset, int *elim, unsigned total) { … } static __isl_give isl_basic_set *isl_basic_set_reduce_using_equalities( __isl_take isl_basic_set *bset, __isl_take isl_basic_set *context) { … } /* For each inequality in "ineq" that is a shifted (more relaxed) * copy of an inequality in "context", mark the corresponding entry * in "row" with -1. * If an inequality only has a non-negative constant term, then * mark it as well. */ static isl_stat mark_shifted_constraints(__isl_keep isl_mat *ineq, __isl_keep isl_basic_set *context, int *row) { … } static __isl_give isl_basic_set *remove_shifted_constraints( __isl_take isl_basic_set *bset, __isl_keep isl_basic_set *context) { … } /* Remove constraints from "bmap" that are identical to constraints * in "context" or that are more relaxed (greater constant term). * * We perform the test for shifted copies on the pure constraints * in remove_shifted_constraints. */ static __isl_give isl_basic_map *isl_basic_map_remove_shifted_constraints( __isl_take isl_basic_map *bmap, __isl_take isl_basic_map *context) { … } /* Does the (linear part of a) constraint "c" involve any of the "len" * "relevant" dimensions? */ static int is_related(isl_int *c, int len, int *relevant) { … } /* Drop constraints from "bmap" that do not involve any of * the dimensions marked "relevant". */ static __isl_give isl_basic_map *drop_unrelated_constraints( __isl_take isl_basic_map *bmap, int *relevant) { … } /* Update the groups in "group" based on the (linear part of a) constraint "c". * * In particular, for any variable involved in the constraint, * find the actual group id from before and replace the group * of the corresponding variable by the minimal group of all * the variables involved in the constraint considered so far * (if this minimum is smaller) or replace the minimum by this group * (if the minimum is larger). * * At the end, all the variables in "c" will (indirectly) point * to the minimal of the groups that they referred to originally. */ static void update_groups(int dim, int *group, isl_int *c) { … } /* Allocate an array of groups of variables, one for each variable * in "context", initialized to zero. */ static int *alloc_groups(__isl_keep isl_basic_set *context) { … } /* Drop constraints from "bmap" that only involve variables that are * not related to any of the variables marked with a "-1" in "group". * * We construct groups of variables that collect variables that * (indirectly) appear in some common constraint of "bmap". * Each group is identified by the first variable in the group, * except for the special group of variables that was already identified * in the input as -1 (or are related to those variables). * If group[i] is equal to i (or -1), then the group of i is i (or -1), * otherwise the group of i is the group of group[i]. * * We first initialize groups for the remaining variables. * Then we iterate over the constraints of "bmap" and update the * group of the variables in the constraint by the smallest group. * Finally, we resolve indirect references to groups by running over * the variables. * * After computing the groups, we drop constraints that do not involve * any variables in the -1 group. */ __isl_give isl_basic_map *isl_basic_map_drop_unrelated_constraints( __isl_take isl_basic_map *bmap, __isl_take int *group) { … } /* Drop constraints from "context" that are irrelevant for computing * the gist of "bset". * * In particular, drop constraints in variables that are not related * to any of the variables involved in the constraints of "bset" * in the sense that there is no sequence of constraints that connects them. * * We first mark all variables that appear in "bset" as belonging * to a "-1" group and then continue with group_and_drop_irrelevant_constraints. */ static __isl_give isl_basic_set *drop_irrelevant_constraints( __isl_take isl_basic_set *context, __isl_keep isl_basic_set *bset) { … } /* Drop constraints from "context" that are irrelevant for computing * the gist of the inequalities "ineq". * Inequalities in "ineq" for which the corresponding element of row * is set to -1 have already been marked for removal and should be ignored. * * In particular, drop constraints in variables that are not related * to any of the variables involved in "ineq" * in the sense that there is no sequence of constraints that connects them. * * We first mark all variables that appear in "bset" as belonging * to a "-1" group and then continue with group_and_drop_irrelevant_constraints. */ static __isl_give isl_basic_set *drop_irrelevant_constraints_marked( __isl_take isl_basic_set *context, __isl_keep isl_mat *ineq, int *row) { … } /* Do all "n" entries of "row" contain a negative value? */ static int all_neg(int *row, int n) { … } /* Update the inequalities in "bset" based on the information in "row" * and "tab". * * In particular, the array "row" contains either -1, meaning that * the corresponding inequality of "bset" is redundant, or the index * of an inequality in "tab". * * If the row entry is -1, then drop the inequality. * Otherwise, if the constraint is marked redundant in the tableau, * then drop the inequality. Similarly, if it is marked as an equality * in the tableau, then turn the inequality into an equality and * perform Gaussian elimination. */ static __isl_give isl_basic_set *update_ineq(__isl_take isl_basic_set *bset, __isl_keep int *row, struct isl_tab *tab) { … } /* Update the inequalities in "bset" based on the information in "row" * and "tab" and free all arguments (other than "bset"). */ static __isl_give isl_basic_set *update_ineq_free( __isl_take isl_basic_set *bset, __isl_take isl_mat *ineq, __isl_take isl_basic_set *context, __isl_take int *row, struct isl_tab *tab) { … } /* Remove all information from bset that is redundant in the context * of context. * "ineq" contains the (possibly transformed) inequalities of "bset", * in the same order. * The (explicit) equalities of "bset" are assumed to have been taken * into account by the transformation such that only the inequalities * are relevant. * "context" is assumed not to be empty. * * "row" keeps track of the constraint index of a "bset" inequality in "tab". * A value of -1 means that the inequality is obviously redundant and may * not even appear in "tab". * * We first mark the inequalities of "bset" * that are obviously redundant with respect to some inequality in "context". * Then we remove those constraints from "context" that have become * irrelevant for computing the gist of "bset". * Note that this removal of constraints cannot be replaced by * a factorization because factors in "bset" may still be connected * to each other through constraints 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 inequalities, we freeze all constraints such that * they won't be considered redundant in terms of the constraints of "bset". * 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 __isl_give isl_basic_set *uset_gist_full(__isl_take isl_basic_set *bset, __isl_take isl_mat *ineq, __isl_take isl_basic_set *context) { … } /* Extract the inequalities of "bset" as an isl_mat. */ static __isl_give isl_mat *extract_ineq(__isl_keep isl_basic_set *bset) { … } /* Remove all information from "bset" that is redundant in the context * of "context", for the case where both "bset" and "context" are * full-dimensional. */ static __isl_give isl_basic_set *uset_gist_uncompressed( __isl_take isl_basic_set *bset, __isl_take isl_basic_set *context) { … } /* Replace "bset" by an empty basic set in the same space. */ static __isl_give isl_basic_set *replace_by_empty( __isl_take isl_basic_set *bset) { … } /* Remove all information from "bset" that is redundant in the context * of "context", for the case where the combined equalities of * "bset" and "context" allow for a compression that can be obtained * by preapplication of "T". * If the compression of "context" is empty, meaning that "bset" and * "context" do not intersect, then return the empty set. * * "bset" itself is not transformed by "T". Instead, the inequalities * are extracted from "bset" and those are transformed by "T". * uset_gist_full then determines which of the transformed inequalities * are redundant with respect to the transformed "context" and removes * the corresponding inequalities from "bset". * * After preapplying "T" to the inequalities, any common factor is * removed from the coefficients. If this results in a tightening * of the constant term, then the same tightening is applied to * the corresponding untransformed inequality in "bset". * That is, if after plugging in T, a constraint f(x) >= 0 is of the form * * g f'(x) + r >= 0 * * with 0 <= r < g, then it is equivalent to * * f'(x) >= 0 * * This means that f(x) >= 0 is equivalent to f(x) - r >= 0 in the affine * subspace compressed by T since the latter would be transformed to * * g f'(x) >= 0 */ static __isl_give isl_basic_set *uset_gist_compressed( __isl_take isl_basic_set *bset, __isl_take isl_basic_set *context, __isl_take isl_mat *T) { … } /* Project "bset" onto the variables that are involved in "template". */ static __isl_give isl_basic_set *project_onto_involved( __isl_take isl_basic_set *bset, __isl_keep isl_basic_set *template) { … } /* 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. * * First of all, we drop those constraints from "context" * that are irrelevant for computing the gist of "bset". * Alternatively, we could factorize the intersection of "context" and "bset". * * We first compute the intersection of the integer affine hulls * of "bset" and "context", * compute the gist inside this intersection and then reduce * the constraints with respect to the equalities of the context * that only involve variables already involved in the input. * If the intersection of the affine hulls turns out to be empty, * then return the empty set. * * If two constraints are mutually redundant, then uset_gist_full * will remove the second of those constraints. We therefore first * sort the constraints so that constraints not involving existentially * quantified variables are given precedence over those that do. * We have to perform this sorting before the variable compression, * because that may effect the order of the variables. */ static __isl_give isl_basic_set *uset_gist(__isl_take isl_basic_set *bset, __isl_take isl_basic_set *context) { … } /* Return the number of equality constraints in "bmap" that involve * local variables. This function assumes that Gaussian elimination * has been applied to the equality constraints. */ static int n_div_eq(__isl_keep isl_basic_map *bmap) { … } /* Construct a basic map in "space" defined by the equality constraints in "eq". * The constraints are assumed not to involve any local variables. */ static __isl_give isl_basic_map *basic_map_from_equalities( __isl_take isl_space *space, __isl_take isl_mat *eq) { … } /* Construct and return a variable compression based on the equality * constraints in "bmap1" and "bmap2" that do not involve the local variables. * "n1" is the number of (initial) equality constraints in "bmap1" * that do involve local variables. * "n2" is the number of (initial) equality constraints in "bmap2" * that do involve local variables. * "total" is the total number of other variables. * This function assumes that Gaussian elimination * has been applied to the equality constraints in both "bmap1" and "bmap2" * such that the equality constraints not involving local variables * are those that start at "n1" or "n2". * * If either of "bmap1" and "bmap2" does not have such equality constraints, * then simply compute the compression based on the equality constraints * in the other basic map. * Otherwise, combine the equality constraints from both into a new * basic map such that Gaussian elimination can be applied to this combination * and then construct a variable compression from the resulting * equality constraints. */ static __isl_give isl_mat *combined_variable_compression( __isl_keep isl_basic_map *bmap1, int n1, __isl_keep isl_basic_map *bmap2, int n2, int total) { … } /* Extract the stride constraints from "bmap", compressed * with respect to both the stride constraints in "context" and * the remaining equality constraints in both "bmap" and "context". * "bmap_n_eq" is the number of (initial) stride constraints in "bmap". * "context_n_eq" is the number of (initial) stride constraints in "context". * * Let x be all variables in "bmap" (and "context") other than the local * variables. First compute a variable compression * * x = V x' * * based on the non-stride equality constraints in "bmap" and "context". * Consider the stride constraints of "context", * * A(x) + B(y) = 0 * * with y the local variables and plug in the variable compression, * resulting in * * A(V x') + B(y) = 0 * * Use these constraints to compute a parameter compression on x' * * x' = T x'' * * Now consider the stride constraints of "bmap" * * C(x) + D(y) = 0 * * and plug in x = V*T x''. * That is, return A = [C*V*T D]. */ static __isl_give isl_mat *extract_compressed_stride_constraints( __isl_keep isl_basic_map *bmap, int bmap_n_eq, __isl_keep isl_basic_map *context, int context_n_eq) { … } /* Remove the prime factors from *g that have an exponent that * is strictly smaller than the exponent in "c". * All exponents in *g are known to be smaller than or equal * to those in "c". * * That is, if *g is equal to * * p_1^{e_1} p_2^{e_2} ... p_n^{e_n} * * and "c" is equal to * * p_1^{f_1} p_2^{f_2} ... p_n^{f_n} * * then update *g to * * p_1^{e_1 * (e_1 = f_1)} p_2^{e_2 * (e_2 = f_2)} ... * p_n^{e_n * (e_n = f_n)} * * If e_i = f_i, then c / *g does not have any p_i factors and therefore * neither does the gcd of *g and c / *g. * If e_i < f_i, then the gcd of *g and c / *g has a positive * power min(e_i, s_i) of p_i with s_i = f_i - e_i among its factors. * Dividing *g by this gcd therefore strictly reduces the exponent * of the prime factors that need to be removed, while leaving the * other prime factors untouched. * Repeating this process until gcd(*g, c / *g) = 1 therefore * removes all undesired factors, without removing any others. */ static void remove_incomplete_powers(isl_int *g, isl_int c) { … } /* Reduce the "n" stride constraints in "bmap" based on a copy "A" * of the same stride constraints in a compressed space that exploits * all equalities in the context and the other equalities in "bmap". * * If the stride constraints of "bmap" are of the form * * C(x) + D(y) = 0 * * then A is of the form * * B(x') + D(y) = 0 * * If any of these constraints involves only a single local variable y, * then the constraint appears as * * f(x) + m y_i = 0 * * in "bmap" and as * * h(x') + m y_i = 0 * * in "A". * * Let g be the gcd of m and the coefficients of h. * Then, in particular, g is a divisor of the coefficients of h and * * f(x) = h(x') * * is known to be a multiple of g. * If some prime factor in m appears with the same exponent in g, * then it can be removed from m because f(x) is already known * to be a multiple of g and therefore in particular of this power * of the prime factors. * Prime factors that appear with a smaller exponent in g cannot * be removed from m. * Let g' be the divisor of g containing all prime factors that * appear with the same exponent in m and g, then * * f(x) + m y_i = 0 * * can be replaced by * * f(x) + m/g' y_i' = 0 * * Note that (if g' != 1) this changes the explicit representation * of y_i to that of y_i', so the integer division at position i * is marked unknown and later recomputed by a call to * isl_basic_map_gauss. */ static __isl_give isl_basic_map *reduce_stride_constraints( __isl_take isl_basic_map *bmap, int n, __isl_keep isl_mat *A) { … } /* Simplify the stride constraints in "bmap" based on * the remaining equality constraints in "bmap" and all equality * constraints in "context". * Only do this if both "bmap" and "context" have stride constraints. * * First extract a copy of the stride constraints in "bmap" in a compressed * space exploiting all the other equality constraints and then * use this compressed copy to simplify the original stride constraints. */ static __isl_give isl_basic_map *gist_strides(__isl_take isl_basic_map *bmap, __isl_keep isl_basic_map *context) { … } /* Return a basic map that has the same intersection with "context" as "bmap" * and that is as "simple" as possible. * * The core computation is performed on the pure constraints. * When we add back the meaning of the integer divisions, we need * to (re)introduce the div constraints. If we happen to have * discovered that some of these integer divisions are equal to * some affine combination of other variables, then these div * constraints may end up getting simplified in terms of the equalities, * resulting in extra inequalities on the other variables that * may have been removed already or that may not even have been * part of the input. We try and remove those constraints of * this form that are most obviously redundant with respect to * the context. We also remove those div constraints that are * redundant with respect to the other constraints in the result. * * The stride constraints among the equality constraints in "bmap" are * also simplified with respecting to the other equality constraints * in "bmap" and with respect to all equality constraints in "context". */ __isl_give isl_basic_map *isl_basic_map_gist(__isl_take isl_basic_map *bmap, __isl_take isl_basic_map *context) { … } /* * Assumes context has no implicit divs. */ __isl_give isl_map *isl_map_gist_basic_map(__isl_take isl_map *map, __isl_take isl_basic_map *context) { … } /* Drop all inequalities from "bmap" that also appear in "context". * "context" is assumed to have only known local variables and * the initial local variables of "bmap" are assumed to be the same * as those of "context". * The constraints of both "bmap" and "context" are assumed * to have been sorted using isl_basic_map_sort_constraints. * * Run through the inequality constraints of "bmap" and "context" * in sorted order. * If a constraint of "bmap" involves variables not in "context", * then it cannot appear in "context". * If a matching constraint is found, it is removed from "bmap". */ static __isl_give isl_basic_map *drop_inequalities( __isl_take isl_basic_map *bmap, __isl_keep isl_basic_map *context) { … } /* Drop all equalities from "bmap" that also appear in "context". * "context" is assumed to have only known local variables and * the initial local variables of "bmap" are assumed to be the same * as those of "context". * * Run through the equality constraints of "bmap" and "context" * in sorted order. * If a constraint of "bmap" involves variables not in "context", * then it cannot appear in "context". * If a matching constraint is found, it is removed from "bmap". */ static __isl_give isl_basic_map *drop_equalities( __isl_take isl_basic_map *bmap, __isl_keep isl_basic_map *context) { … } /* Remove the constraints in "context" from "bmap". * "context" is assumed to have explicit representations * for all local variables. * * First align the divs of "bmap" to those of "context" and * sort the constraints. Then drop all constraints from "bmap" * that appear in "context". */ __isl_give isl_basic_map *isl_basic_map_plain_gist( __isl_take isl_basic_map *bmap, __isl_take isl_basic_map *context) { … } /* Replace "map" by the disjunct at position "pos" and free "context". */ static __isl_give isl_map *replace_by_disjunct(__isl_take isl_map *map, int pos, __isl_take isl_basic_map *context) { … } /* Remove the constraints in "context" from "map". * If any of the disjuncts in the result turns out to be the universe, * then return this universe. * "context" is assumed to have explicit representations * for all local variables. */ __isl_give isl_map *isl_map_plain_gist_basic_map(__isl_take isl_map *map, __isl_take isl_basic_map *context) { … } /* Remove the constraints in "context" from "set". * If any of the disjuncts in the result turns out to be the universe, * then return this universe. * "context" is assumed to have explicit representations * for all local variables. */ __isl_give isl_set *isl_set_plain_gist_basic_set(__isl_take isl_set *set, __isl_take isl_basic_set *context) { … } /* Remove the constraints in "context" from "map". * If any of the disjuncts in the result turns out to be the universe, * then return this universe. * "context" is assumed to consist of a single disjunct and * to have explicit representations for all local variables. */ __isl_give isl_map *isl_map_plain_gist(__isl_take isl_map *map, __isl_take isl_map *context) { … } /* Replace "map" by a universe map in the same space and free "drop". */ static __isl_give isl_map *replace_by_universe(__isl_take isl_map *map, __isl_take isl_map *drop) { … } /* Return a map that has the same intersection with "context" as "map" * and that is as "simple" as possible. * * If "map" is already the universe, then we cannot make it any simpler. * Similarly, if "context" is the universe, then we cannot exploit it * to simplify "map" * If "map" and "context" are identical to each other, then we can * return the corresponding universe. * * If either "map" or "context" consists of multiple disjuncts, * then check if "context" happens to be a subset of "map", * in which case all constraints can be removed. * In case of multiple disjuncts, the standard procedure * may not be able to detect that all constraints can be removed. * * If none of these cases apply, we have to work a bit harder. * During this computation, we make use of a single disjunct context, * so if the original context consists of more than one disjunct * then we need to approximate the context by a single disjunct set. * Simply taking the simple hull may drop constraints that are * only implicitly available in each disjunct. We therefore also * look for constraints among those defining "map" that are valid * for the context. These can then be used to simplify away * the corresponding constraints in "map". */ __isl_give isl_map *isl_map_gist(__isl_take isl_map *map, __isl_take isl_map *context) { … } __isl_give isl_basic_set *isl_basic_set_gist(__isl_take isl_basic_set *bset, __isl_take isl_basic_set *context) { … } __isl_give isl_set *isl_set_gist_basic_set(__isl_take isl_set *set, __isl_take isl_basic_set *context) { … } __isl_give isl_set *isl_set_gist_params_basic_set(__isl_take isl_set *set, __isl_take isl_basic_set *context) { … } __isl_give isl_set *isl_set_gist(__isl_take isl_set *set, __isl_take isl_set *context) { … } /* Compute the gist of "bmap" with respect to the constraints "context" * on the domain. */ __isl_give isl_basic_map *isl_basic_map_gist_domain( __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *context) { … } __isl_give isl_map *isl_map_gist_domain(__isl_take isl_map *map, __isl_take isl_set *context) { … } __isl_give isl_map *isl_map_gist_range(__isl_take isl_map *map, __isl_take isl_set *context) { … } __isl_give isl_map *isl_map_gist_params(__isl_take isl_map *map, __isl_take isl_set *context) { … } __isl_give isl_set *isl_set_gist_params(__isl_take isl_set *set, __isl_take isl_set *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 * basic map and check if we get a contradiction. */ isl_bool isl_basic_map_plain_is_disjoint(__isl_keep isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2) { … } int isl_basic_set_plain_is_disjoint(__isl_keep isl_basic_set *bset1, __isl_keep isl_basic_set *bset2) { … } /* Does "test" hold for all pairs of basic maps in "map1" and "map2"? */ static isl_bool all_pairs(__isl_keep isl_map *map1, __isl_keep isl_map *map2, isl_bool (*test)(__isl_keep isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2)) { … } /* Are "map1" and "map2" obviously disjoint, based on information * that can be derived without looking at the individual basic maps? * * In particular, if one of them is empty or if they live in different spaces * (ignoring parameters), then they are clearly disjoint. */ static isl_bool isl_map_plain_is_disjoint_global(__isl_keep isl_map *map1, __isl_keep isl_map *map2) { … } /* Are "map1" and "map2" obviously disjoint? * * If one of them is empty or if they live in different spaces (ignoring * parameters), then they are clearly disjoint. * This is checked by isl_map_plain_is_disjoint_global. * * If they have different parameters, then we skip any further tests. * * If they are obviously equal, but not obviously empty, then we will * not be able to detect if they are disjoint. * * Otherwise we check if each basic map in "map1" is obviously disjoint * from each basic map in "map2". */ isl_bool isl_map_plain_is_disjoint(__isl_keep isl_map *map1, __isl_keep isl_map *map2) { … } /* Are "map1" and "map2" disjoint? * The parameters are assumed to have been aligned. * * In particular, check whether all pairs of basic maps are disjoint. */ static isl_bool isl_map_is_disjoint_aligned(__isl_keep isl_map *map1, __isl_keep isl_map *map2) { … } /* Are "map1" and "map2" disjoint? * * They are disjoint if they are "obviously disjoint" or if one of them * is empty. Otherwise, they are not disjoint if one of them is universal. * If the two inputs are (obviously) equal and not empty, then they are * not disjoint. * If none of these cases apply, then check if all pairs of basic maps * are disjoint after aligning the parameters. */ isl_bool isl_map_is_disjoint(__isl_keep isl_map *map1, __isl_keep isl_map *map2) { … } /* Are "bmap1" and "bmap2" disjoint? * * They are disjoint if they are "obviously disjoint" or if one of them * is empty. Otherwise, they are not disjoint if one of them is universal. * If none of these cases apply, we compute the intersection and see if * the result is empty. */ isl_bool isl_basic_map_is_disjoint(__isl_keep isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2) { … } /* Are "bset1" and "bset2" disjoint? */ isl_bool isl_basic_set_is_disjoint(__isl_keep isl_basic_set *bset1, __isl_keep isl_basic_set *bset2) { … } isl_bool isl_set_plain_is_disjoint(__isl_keep isl_set *set1, __isl_keep isl_set *set2) { … } /* Are "set1" and "set2" disjoint? */ isl_bool isl_set_is_disjoint(__isl_keep isl_set *set1, __isl_keep isl_set *set2) { … } /* Is "v" equal to 0, 1 or -1? */ static int is_zero_or_one(isl_int v) { … } /* Are the "n" coefficients starting at "first" of inequality constraints * "i" and "j" of "bmap" opposite to each other? */ static int is_opposite_part(__isl_keep isl_basic_map *bmap, int i, int j, int first, int n) { … } /* Are inequality constraints "i" and "j" of "bmap" opposite to each other, * apart from the constant term? */ static isl_bool is_opposite(__isl_keep isl_basic_map *bmap, int i, int j) { … } /* 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 a position beyond the integer divisions. * Return -1 on error. * * 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 (except for the lower and upper bound) * are of the form * * e + f (a + m b) >= 0 * * Furthermore, in the constraints that only contain b, the coefficient * of b should be equal to 1 or -1. * 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(__isl_keep isl_basic_map *bmap, int *pairs, unsigned div, unsigned l, unsigned u) { … } /* Internal data structure used during the construction and/or evaluation of * an inequality that ensures that a pair of bounds always allows * for an integer value. * * "tab" is the tableau in which the inequality is evaluated. It may * be NULL until it is actually needed. * "v" contains the inequality coefficients. * "g", "fl" and "fu" are temporary scalars used during the construction and * evaluation. */ struct test_ineq_data { … }; /* Free all the memory allocated by the fields of "data". */ static void test_ineq_data_clear(struct test_ineq_data *data) { … } /* Is the inequality stored in data->v satisfied by "bmap"? * That is, does it only attain non-negative values? * data->tab is a tableau corresponding to "bmap". */ static isl_bool test_ineq_is_satisfied(__isl_keep isl_basic_map *bmap, struct test_ineq_data *data) { … } /* Given a lower and an upper bound on div i, do they always allow * for an integer value of the given div? * Determine this property by constructing an inequality * such that the property is guaranteed when the inequality is nonnegative. * The lower bound is inequality l, while the upper bound is inequality u. * The constructed inequality is stored in data->v. * * 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 * * or * * f_l e_u + f_u e_l + f_l - 1 + f_u - 1 + 1 - f_u f_l g >= 0 * * If the coefficients of f_l e_u + f_u e_l have a common divisor g', * then the constraint can be scaled down by a factor g', * with the constant term replaced by * floor((f_l e_{u,0} + f_u e_{l,0} + f_l - 1 + f_u - 1 + 1 - f_u f_l g)/g'). * Note that the result of applying Fourier-Motzkin to this pair * of constraints is * * f_l e_u + f_u e_l >= 0 * * If the constant term of the scaled down version of this constraint, * i.e., floor((f_l e_{u,0} + f_u e_{l,0})/g') is equal to the constant * term of the scaled down test constraint, then the test constraint * is known to hold and no explicit evaluation is required. * This is essentially the Omega test. * * If the test constraint consists of only a constant term, then * it is sufficient to look at the sign of this constant term. */ static isl_bool int_between_bounds(__isl_keep isl_basic_map *bmap, int i, int l, int u, struct test_ineq_data *data) { … } /* 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, * then we can eliminate the div using Fourier-Motzkin without * introducing any spurious solutions. * * If at least one of the two constraints has a unit coefficient for the div, * then the presence of such a value is guaranteed so there is no need to check. * In particular, the value attained by the bound with unit coefficient * can serve as this intermediate value. */ static __isl_give isl_basic_map *drop_more_redundant_divs( __isl_take isl_basic_map *bmap, __isl_take int *pairs, int n) { … } /* Given a pair of divs div1 and div2 such that, except 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 * The coefficient of div2 is known to be equal to 1 or -1. * (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 l be * * div1 + f >=0 * * and u * * -div1 + f' >= 0 * * A lower bound on div2 * * div2 + t >= 0 * * can be replaced by * * m div2 + div1 + m t + f >= 0 * * An upper bound * * -div2 + t >= 0 * * can be replaced by * * -(m div2 + div1) + m t + f' >= 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. * Since the new div is only placed in the same location that used * to store div2, but otherwise has a different meaning, any possible * explicit representation of the original div2 is removed. */ static __isl_give isl_basic_map *coalesce_divs(__isl_take isl_basic_map *bmap, unsigned div1, unsigned div2, unsigned l, unsigned u) { … } /* 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 __isl_give isl_basic_map *coalesce_or_drop_more_redundant_divs( __isl_take isl_basic_map *bmap, int *pairs, int n) { … } /* Are the "n" coefficients starting at "first" of inequality constraints * "i" and "j" of "bmap" equal to each other? */ static int is_parallel_part(__isl_keep isl_basic_map *bmap, int i, int j, int first, int n) { … } /* Are inequality constraints "i" and "j" of "bmap" equal to each other, * apart from the constant term and the coefficient at position "pos"? */ static isl_bool is_parallel_except(__isl_keep isl_basic_map *bmap, int i, int j, int pos) { … } /* Are inequality constraints "i" and "j" of "bmap" opposite to each other, * apart from the constant term and the coefficient at position "pos"? */ static isl_bool is_opposite_except(__isl_keep isl_basic_map *bmap, int i, int j, int pos) { … } /* Restart isl_basic_map_drop_redundant_divs after "bmap" has * been modified, simplying it if "simplify" is set. * Free the temporary data structure "pairs" that was associated * to the old version of "bmap". */ static __isl_give isl_basic_map *drop_redundant_divs_again( __isl_take isl_basic_map *bmap, __isl_take int *pairs, int simplify) { … } /* Is "div" the single unknown existentially quantified variable * in inequality constraint "ineq" of "bmap"? * "div" is known to have a non-zero coefficient in "ineq". */ static isl_bool single_unknown(__isl_keep isl_basic_map *bmap, int ineq, int div) { … } /* Does integer division "div" have coefficient 1 in inequality constraint * "ineq" of "map"? */ static isl_bool has_coef_one(__isl_keep isl_basic_map *bmap, int div, int ineq) { … } /* Turn inequality constraint "ineq" of "bmap" into an equality and * then try and drop redundant divs again, * freeing the temporary data structure "pairs" that was associated * to the old version of "bmap". */ static __isl_give isl_basic_map *set_eq_and_try_again( __isl_take isl_basic_map *bmap, int ineq, __isl_take int *pairs) { … } /* Drop the integer division at position "div", along with the two * inequality constraints "ineq1" and "ineq2" in which it appears * from "bmap" and then try and drop redundant divs again, * freeing the temporary data structure "pairs" that was associated * to the old version of "bmap". */ static __isl_give isl_basic_map *drop_div_and_try_again( __isl_take isl_basic_map *bmap, int div, int ineq1, int ineq2, __isl_take int *pairs) { … } /* Given two inequality constraints * * f(x) + n d + c >= 0, (ineq) * * with d the variable at position "pos", and * * f(x) + c0 >= 0, (lower) * * compute the maximal value of the lower bound ceil((-f(x) - c)/n) * determined by the first constraint. * That is, store * * ceil((c0 - c)/n) * * in *l. */ static void lower_bound_from_parallel(__isl_keep isl_basic_map *bmap, int ineq, int lower, int pos, isl_int *l) { … } /* Given two inequality constraints * * f(x) + n d + c >= 0, (ineq) * * with d the variable at position "pos", and * * -f(x) - c0 >= 0, (upper) * * compute the minimal value of the lower bound ceil((-f(x) - c)/n) * determined by the first constraint. * That is, store * * ceil((-c1 - c)/n) * * in *u. */ static void lower_bound_from_opposite(__isl_keep isl_basic_map *bmap, int ineq, int upper, int pos, isl_int *u) { … } /* Given a lower bound constraint "ineq" on "div" in "bmap", * does the corresponding lower bound have a fixed value in "bmap"? * * In particular, "ineq" is of the form * * f(x) + n d + c >= 0 * * with n > 0, c the constant term and * d the existentially quantified variable "div". * That is, the lower bound is * * ceil((-f(x) - c)/n) * * Look for a pair of constraints * * f(x) + c0 >= 0 * -f(x) + c1 >= 0 * * i.e., -c1 <= -f(x) <= c0, that fix ceil((-f(x) - c)/n) to a constant value. * That is, check that * * ceil((-c1 - c)/n) = ceil((c0 - c)/n) * * If so, return the index of inequality f(x) + c0 >= 0. * Otherwise, return bmap->n_ineq. * Return -1 on error. */ static int lower_bound_is_cst(__isl_keep isl_basic_map *bmap, int div, int ineq) { … } /* Given a lower bound constraint "ineq" on the existentially quantified * variable "div", such that the corresponding lower bound has * a fixed value in "bmap", assign this fixed value to the variable and * then try and drop redundant divs again, * freeing the temporary data structure "pairs" that was associated * to the old version of "bmap". * "lower" determines the constant value for the lower bound. * * In particular, "ineq" is of the form * * f(x) + n d + c >= 0, * * while "lower" is of the form * * f(x) + c0 >= 0 * * The lower bound is ceil((-f(x) - c)/n) and its constant value * is ceil((c0 - c)/n). */ static __isl_give isl_basic_map *fix_cst_lower(__isl_take isl_basic_map *bmap, int div, int ineq, int lower, int *pairs) { … } /* Do any of the integer divisions of "bmap" involve integer division "div"? * * The integer division "div" could only ever appear in any later * integer division (with an explicit representation). */ static isl_bool any_div_involves_div(__isl_keep isl_basic_map *bmap, int div) { … } /* Remove divs that are not strictly needed based on the inequality * constraints. * In particular, if a div only occurs positively (or negatively) * in constraints, then it can simply be dropped. * Also, if a div occurs in only 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 coefficient of the div in the constraints, * then we can also simply drop the div. * * If an existentially quantified variable does not have an explicit * representation, appears in only a single lower bound that does not * involve any other such existentially quantified variables and appears * in this lower bound with coefficient 1, * then fix the variable to the value of the lower bound. That is, * turn the inequality into an equality. * If for any value of the other variables, there is any value * for the existentially quantified variable satisfying the constraints, * then this lower bound also satisfies the constraints. * It is therefore safe to pick this lower bound. * * The same reasoning holds even if the coefficient is not one. * However, fixing the variable to the value of the lower bound may * in general introduce an extra integer division, in which case * it may be better to pick another value. * If this integer division has a known constant value, then plugging * in this constant value removes the existentially quantified variable * completely. In particular, if the lower bound is of the form * ceil((-f(x) - c)/n) and there are two constraints, f(x) + c0 >= 0 and * -f(x) + c1 >= 0 such that ceil((-c1 - c)/n) = ceil((c0 - c)/n), * then the existentially quantified variable can be assigned this * shared value. * * We skip divs that appear in equalities or in the definition of other divs. * Divs that appear in the definition of other divs usually occur in at least * 4 constraints, but the constraints may have been simplified. * * If any divs are left after these simple checks then we move on * to more complicated cases in drop_more_redundant_divs. */ static __isl_give isl_basic_map *isl_basic_map_drop_redundant_divs_ineq( __isl_take isl_basic_map *bmap) { … } /* Consider the coefficients at "c" as a row vector and replace * them with their product with "T". "T" is assumed to be a square matrix. */ static isl_stat preimage(isl_int *c, __isl_keep isl_mat *T) { … } /* Plug in T for the variables in "bmap" starting at "pos". * T is a linear unimodular matrix, i.e., without constant term. */ static __isl_give isl_basic_map *isl_basic_map_preimage_vars( __isl_take isl_basic_map *bmap, unsigned pos, __isl_take isl_mat *T) { … } /* Remove divs that are not strictly needed. * * First look for an equality constraint involving two or more * existentially quantified variables without an explicit * representation. Replace the combination that appears * in the equality constraint by a single existentially quantified * variable such that the equality can be used to derive * an explicit representation for the variable. * If there are no more such equality constraints, then continue * with isl_basic_map_drop_redundant_divs_ineq. * * In particular, if the equality constraint is of the form * * f(x) + \sum_i c_i a_i = 0 * * with a_i existentially quantified variable without explicit * representation, then apply a transformation on the existentially * quantified variables to turn the constraint into * * f(x) + g a_1' = 0 * * with g the gcd of the c_i. * In order to easily identify which existentially quantified variables * have a complete explicit representation, i.e., without being defined * in terms of other existentially quantified variables without * an explicit representation, the existentially quantified variables * are first sorted. * * The variable transformation is computed by extending the row * [c_1/g ... c_n/g] to a unimodular matrix, obtaining the transformation * * [a_1'] [c_1/g ... c_n/g] [ a_1 ] * [a_2'] [ a_2 ] * ... = U .... * [a_n'] [ a_n ] * * with [c_1/g ... c_n/g] representing the first row of U. * The inverse of U is then plugged into the original constraints. * The call to isl_basic_map_simplify makes sure the explicit * representation for a_1' is extracted from the equality constraint. */ __isl_give isl_basic_map *isl_basic_map_drop_redundant_divs( __isl_take isl_basic_map *bmap) { … } /* Does "bmap" satisfy any equality that involves more than 2 variables * and/or has coefficients different from -1 and 1? */ static isl_bool has_multiple_var_equality(__isl_keep isl_basic_map *bmap) { … } /* Remove any common factor g from the constraint coefficients in "v". * The constant term is stored in the first position and is replaced * by floor(c/g). If any common factor is removed and if this results * in a tightening of the constraint, then set *tightened. */ static __isl_give isl_vec *normalize_constraint(__isl_take isl_vec *v, int *tightened) { … } /* If "bmap" is an integer set that satisfies any equality involving * more than 2 variables and/or has coefficients different from -1 and 1, * then use variable compression to reduce the coefficients by removing * any (hidden) common factor. * In particular, apply the variable compression to each constraint, * factor out any common factor in the non-constant coefficients and * then apply the inverse of the compression. * At the end, we mark the basic map as having reduced constants. * If this flag is still set on the next invocation of this function, * then we skip the computation. * * Removing a common factor may result in a tightening of some of * the constraints. If this happens, then we may end up with two * opposite inequalities that can be replaced by an equality. * We therefore call isl_basic_map_detect_inequality_pairs, * which checks for such pairs of inequalities as well as eliminate_divs_eq * and isl_basic_map_gauss if such a pair was found. * * Tightening may also result in some other constraints becoming * (rationally) redundant with respect to the tightened constraint * (in combination with other constraints). The basic map may * therefore no longer be assumed to have no redundant constraints. * * Note that this function may leave the result in an inconsistent state. * In particular, the constraints may not be gaussed. * Unfortunately, isl_map_coalesce actually depends on this inconsistent state * for some of the test cases to pass successfully. * Any potential modification of the representation is therefore only * performed on a single copy of the basic map. */ __isl_give isl_basic_map *isl_basic_map_reduce_coefficients( __isl_take isl_basic_map *bmap) { … } /* Shift the integer division at position "div" of "bmap" * by "shift" times the variable at position "pos". * "pos" is as determined by isl_basic_map_offset, i.e., pos == 0 * corresponds to the constant term. * * That is, if the integer division has the form * * floor(f(x)/d) * * then replace it by * * floor((f(x) + shift * d * x_pos)/d) - shift * x_pos */ __isl_give isl_basic_map *isl_basic_map_shift_div( __isl_take isl_basic_map *bmap, int div, int pos, isl_int shift) { … }