buildtools/gcc/isl/isl_farkas.c
Adrien Destugues 680f0e1112 import ISL 0.24
2022-07-15 15:05:28 +02:00

967 lines
27 KiB
C

/*
* Copyright 2010 INRIA Saclay
*
* Use of this software is governed by the MIT license
*
* Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
* Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
* 91893 Orsay, France
*/
#include <isl_map_private.h>
#include <isl/set.h>
#include <isl_space_private.h>
#include <isl_seq.h>
#include <isl_aff_private.h>
#include <isl_mat_private.h>
#include <isl_factorization.h>
/*
* Let C be a cone and define
*
* C' := { y | forall x in C : y x >= 0 }
*
* C' contains the coefficients of all linear constraints
* that are valid for C.
* Furthermore, C'' = C.
*
* If C is defined as { x | A x >= 0 }
* then any element in C' must be a non-negative combination
* of the rows of A, i.e., y = t A with t >= 0. That is,
*
* C' = { y | exists t >= 0 : y = t A }
*
* If any of the rows in A actually represents an equality, then
* also negative combinations of this row are allowed and so the
* non-negativity constraint on the corresponding element of t
* can be dropped.
*
* A polyhedron P = { x | b + A x >= 0 } can be represented
* in homogeneous coordinates by the cone
* C = { [z,x] | b z + A x >= and z >= 0 }
* The valid linear constraints on C correspond to the valid affine
* constraints on P.
* This is essentially Farkas' lemma.
*
* Since
* [ 1 0 ]
* [ w y ] = [t_0 t] [ b A ]
*
* we have
*
* C' = { w, y | exists t_0, t >= 0 : y = t A and w = t_0 + t b }
* or
*
* C' = { w, y | exists t >= 0 : y = t A and w - t b >= 0 }
*
* In practice, we introduce an extra variable (w), shifting all
* other variables to the right, and an extra inequality
* (w - t b >= 0) corresponding to the positivity constraint on
* the homogeneous coordinate.
*
* When going back from coefficients to solutions, we immediately
* plug in 1 for z, which corresponds to shifting all variables
* to the left, with the leftmost ending up in the constant position.
*/
/* Add the given prefix to all named isl_dim_set dimensions in "space".
*/
static __isl_give isl_space *isl_space_prefix(__isl_take isl_space *space,
const char *prefix)
{
int i;
isl_ctx *ctx;
isl_size nvar;
size_t prefix_len = strlen(prefix);
if (!space)
return NULL;
ctx = isl_space_get_ctx(space);
nvar = isl_space_dim(space, isl_dim_set);
if (nvar < 0)
return isl_space_free(space);
for (i = 0; i < nvar; ++i) {
const char *name;
char *prefix_name;
name = isl_space_get_dim_name(space, isl_dim_set, i);
if (!name)
continue;
prefix_name = isl_alloc_array(ctx, char,
prefix_len + strlen(name) + 1);
if (!prefix_name)
goto error;
memcpy(prefix_name, prefix, prefix_len);
strcpy(prefix_name + prefix_len, name);
space = isl_space_set_dim_name(space,
isl_dim_set, i, prefix_name);
free(prefix_name);
}
return space;
error:
isl_space_free(space);
return NULL;
}
/* Given a dimension specification of the solutions space, construct
* a dimension specification for the space of coefficients.
*
* In particular transform
*
* [params] -> { S }
*
* to
*
* { coefficients[[cst, params] -> S] }
*
* and prefix each dimension name with "c_".
*/
static __isl_give isl_space *isl_space_coefficients(__isl_take isl_space *space)
{
isl_space *space_param;
isl_size nvar;
isl_size nparam;
nvar = isl_space_dim(space, isl_dim_set);
nparam = isl_space_dim(space, isl_dim_param);
if (nvar < 0 || nparam < 0)
return isl_space_free(space);
space_param = isl_space_copy(space);
space_param = isl_space_drop_dims(space_param, isl_dim_set, 0, nvar);
space_param = isl_space_move_dims(space_param, isl_dim_set, 0,
isl_dim_param, 0, nparam);
space_param = isl_space_prefix(space_param, "c_");
space_param = isl_space_insert_dims(space_param, isl_dim_set, 0, 1);
space_param = isl_space_set_dim_name(space_param,
isl_dim_set, 0, "c_cst");
space = isl_space_drop_dims(space, isl_dim_param, 0, nparam);
space = isl_space_prefix(space, "c_");
space = isl_space_join(isl_space_from_domain(space_param),
isl_space_from_range(space));
space = isl_space_wrap(space);
space = isl_space_set_tuple_name(space, isl_dim_set, "coefficients");
return space;
}
/* Drop the given prefix from all named dimensions of type "type" in "space".
*/
static __isl_give isl_space *isl_space_unprefix(__isl_take isl_space *space,
enum isl_dim_type type, const char *prefix)
{
int i;
isl_size n;
size_t prefix_len = strlen(prefix);
n = isl_space_dim(space, type);
if (n < 0)
return isl_space_free(space);
for (i = 0; i < n; ++i) {
const char *name;
name = isl_space_get_dim_name(space, type, i);
if (!name)
continue;
if (strncmp(name, prefix, prefix_len))
continue;
space = isl_space_set_dim_name(space,
type, i, name + prefix_len);
}
return space;
}
/* Given a dimension specification of the space of coefficients, construct
* a dimension specification for the space of solutions.
*
* In particular transform
*
* { coefficients[[cst, params] -> S] }
*
* to
*
* [params] -> { S }
*
* and drop the "c_" prefix from the dimension names.
*/
static __isl_give isl_space *isl_space_solutions(__isl_take isl_space *space)
{
isl_size nparam;
space = isl_space_unwrap(space);
space = isl_space_drop_dims(space, isl_dim_in, 0, 1);
space = isl_space_unprefix(space, isl_dim_in, "c_");
space = isl_space_unprefix(space, isl_dim_out, "c_");
nparam = isl_space_dim(space, isl_dim_in);
if (nparam < 0)
return isl_space_free(space);
space = isl_space_move_dims(space,
isl_dim_param, 0, isl_dim_in, 0, nparam);
space = isl_space_range(space);
return space;
}
/* Return the rational universe basic set in the given space.
*/
static __isl_give isl_basic_set *rational_universe(__isl_take isl_space *space)
{
isl_basic_set *bset;
bset = isl_basic_set_universe(space);
bset = isl_basic_set_set_rational(bset);
return bset;
}
/* Compute the dual of "bset" by applying Farkas' lemma.
* As explained above, we add an extra dimension to represent
* the coefficient of the constant term when going from solutions
* to coefficients (shift == 1) and we drop the extra dimension when going
* in the opposite direction (shift == -1).
* The dual can be created in an arbitrary space.
* The caller is responsible for putting the result in the appropriate space.
*
* If "bset" is (obviously) empty, then the way this emptiness
* is represented by the constraints does not allow for the application
* of the standard farkas algorithm. We therefore handle this case
* specifically and return the universe basic set.
*/
static __isl_give isl_basic_set *farkas(__isl_take isl_basic_set *bset,
int shift)
{
int i, j, k;
isl_ctx *ctx;
isl_space *space;
isl_basic_set *dual = NULL;
isl_size total;
total = isl_basic_set_dim(bset, isl_dim_all);
if (total < 0)
return isl_basic_set_free(bset);
ctx = isl_basic_set_get_ctx(bset);
space = isl_space_set_alloc(ctx, 0, total + shift);
if (isl_basic_set_plain_is_empty(bset)) {
isl_basic_set_free(bset);
return rational_universe(space);
}
dual = isl_basic_set_alloc_space(space, bset->n_eq + bset->n_ineq,
total, bset->n_ineq + (shift > 0));
dual = isl_basic_set_set_rational(dual);
for (i = 0; i < bset->n_eq + bset->n_ineq; ++i) {
k = isl_basic_set_alloc_div(dual);
if (k < 0)
goto error;
isl_int_set_si(dual->div[k][0], 0);
}
for (i = 0; i < total; ++i) {
k = isl_basic_set_alloc_equality(dual);
if (k < 0)
goto error;
isl_seq_clr(dual->eq[k], 1 + shift + total);
isl_int_set_si(dual->eq[k][1 + shift + i], -1);
for (j = 0; j < bset->n_eq; ++j)
isl_int_set(dual->eq[k][1 + shift + total + j],
bset->eq[j][1 + i]);
for (j = 0; j < bset->n_ineq; ++j)
isl_int_set(dual->eq[k][1 + shift + total + bset->n_eq + j],
bset->ineq[j][1 + i]);
}
for (i = 0; i < bset->n_ineq; ++i) {
k = isl_basic_set_alloc_inequality(dual);
if (k < 0)
goto error;
isl_seq_clr(dual->ineq[k],
1 + shift + total + bset->n_eq + bset->n_ineq);
isl_int_set_si(dual->ineq[k][1 + shift + total + bset->n_eq + i], 1);
}
if (shift > 0) {
k = isl_basic_set_alloc_inequality(dual);
if (k < 0)
goto error;
isl_seq_clr(dual->ineq[k], 2 + total);
isl_int_set_si(dual->ineq[k][1], 1);
for (j = 0; j < bset->n_eq; ++j)
isl_int_neg(dual->ineq[k][2 + total + j],
bset->eq[j][0]);
for (j = 0; j < bset->n_ineq; ++j)
isl_int_neg(dual->ineq[k][2 + total + bset->n_eq + j],
bset->ineq[j][0]);
}
dual = isl_basic_set_remove_divs(dual);
dual = isl_basic_set_simplify(dual);
dual = isl_basic_set_finalize(dual);
isl_basic_set_free(bset);
return dual;
error:
isl_basic_set_free(bset);
isl_basic_set_free(dual);
return NULL;
}
/* Construct a basic set containing the tuples of coefficients of all
* valid affine constraints on the given basic set, ignoring
* the space of input and output and without any further decomposition.
*/
static __isl_give isl_basic_set *isl_basic_set_coefficients_base(
__isl_take isl_basic_set *bset)
{
return farkas(bset, 1);
}
/* Return the inverse mapping of "morph".
*/
static __isl_give isl_mat *peek_inv(__isl_keep isl_morph *morph)
{
return morph ? morph->inv : NULL;
}
/* Return a copy of the inverse mapping of "morph".
*/
static __isl_give isl_mat *get_inv(__isl_keep isl_morph *morph)
{
return isl_mat_copy(peek_inv(morph));
}
/* Information about a single factor within isl_basic_set_coefficients_product.
*
* "start" is the position of the first coefficient (beyond
* the one corresponding to the constant term) in this factor.
* "dim" is the number of coefficients (other than
* the one corresponding to the constant term) in this factor.
* "n_line" is the number of lines in "coeff".
* "n_ray" is the number of rays (other than lines) in "coeff".
* "n_vertex" is the number of vertices in "coeff".
*
* While iterating over the vertices,
* "pos" represents the inequality constraint corresponding
* to the current vertex.
*/
struct isl_coefficients_factor_data {
isl_basic_set *coeff;
int start;
int dim;
int n_line;
int n_ray;
int n_vertex;
int pos;
};
/* Internal data structure for isl_basic_set_coefficients_product.
* "n" is the number of factors in the factorization.
* "pos" is the next factor that will be considered.
* "start_next" is the position of the first coefficient (beyond
* the one corresponding to the constant term) in the next factor.
* "factors" contains information about the individual "n" factors.
*/
struct isl_coefficients_product_data {
int n;
int pos;
int start_next;
struct isl_coefficients_factor_data *factors;
};
/* Initialize the internal data structure for
* isl_basic_set_coefficients_product.
*/
static isl_stat isl_coefficients_product_data_init(isl_ctx *ctx,
struct isl_coefficients_product_data *data, int n)
{
data->n = n;
data->pos = 0;
data->start_next = 0;
data->factors = isl_calloc_array(ctx,
struct isl_coefficients_factor_data, n);
if (!data->factors)
return isl_stat_error;
return isl_stat_ok;
}
/* Free all memory allocated in "data".
*/
static void isl_coefficients_product_data_clear(
struct isl_coefficients_product_data *data)
{
int i;
if (data->factors) {
for (i = 0; i < data->n; ++i) {
isl_basic_set_free(data->factors[i].coeff);
}
}
free(data->factors);
}
/* Does inequality "ineq" in the (dual) basic set "bset" represent a ray?
* In particular, does it have a zero denominator
* (i.e., a zero coefficient for the constant term)?
*/
static int is_ray(__isl_keep isl_basic_set *bset, int ineq)
{
return isl_int_is_zero(bset->ineq[ineq][1]);
}
/* isl_factorizer_every_factor_basic_set callback that
* constructs a basic set containing the tuples of coefficients of all
* valid affine constraints on the factor "bset" and
* extracts further information that will be used
* when combining the results over the different factors.
*/
static isl_bool isl_basic_set_coefficients_factor(
__isl_keep isl_basic_set *bset, void *user)
{
struct isl_coefficients_product_data *data = user;
isl_basic_set *coeff;
isl_size n_eq, n_ineq, dim;
int i, n_ray, n_vertex;
coeff = isl_basic_set_coefficients_base(isl_basic_set_copy(bset));
data->factors[data->pos].coeff = coeff;
if (!coeff)
return isl_bool_error;
dim = isl_basic_set_dim(bset, isl_dim_set);
n_eq = isl_basic_set_n_equality(coeff);
n_ineq = isl_basic_set_n_inequality(coeff);
if (dim < 0 || n_eq < 0 || n_ineq < 0)
return isl_bool_error;
n_ray = n_vertex = 0;
for (i = 0; i < n_ineq; ++i) {
if (is_ray(coeff, i))
n_ray++;
else
n_vertex++;
}
data->factors[data->pos].start = data->start_next;
data->factors[data->pos].dim = dim;
data->factors[data->pos].n_line = n_eq;
data->factors[data->pos].n_ray = n_ray;
data->factors[data->pos].n_vertex = n_vertex;
data->pos++;
data->start_next += dim;
return isl_bool_true;
}
/* Clear an entry in the product, given that there is a "total" number
* of coefficients (other than that of the constant term).
*/
static void clear_entry(isl_int *entry, int total)
{
isl_seq_clr(entry, 1 + 1 + total);
}
/* Set the part of the entry corresponding to factor "data",
* from the factor coefficients in "src".
*/
static void set_factor(isl_int *entry, isl_int *src,
struct isl_coefficients_factor_data *data)
{
isl_seq_cpy(entry + 1 + 1 + data->start, src + 1 + 1, data->dim);
}
/* Set the part of the entry corresponding to factor "data",
* from the factor coefficients in "src" multiplied by "f".
*/
static void scale_factor(isl_int *entry, isl_int *src, isl_int f,
struct isl_coefficients_factor_data *data)
{
isl_seq_scale(entry + 1 + 1 + data->start, src + 1 + 1, f, data->dim);
}
/* Add all lines from the given factor to "bset",
* given that there is a "total" number of coefficients
* (other than that of the constant term).
*/
static __isl_give isl_basic_set *add_lines(__isl_take isl_basic_set *bset,
struct isl_coefficients_factor_data *factor, int total)
{
int i;
for (i = 0; i < factor->n_line; ++i) {
int k;
k = isl_basic_set_alloc_equality(bset);
if (k < 0)
return isl_basic_set_free(bset);
clear_entry(bset->eq[k], total);
set_factor(bset->eq[k], factor->coeff->eq[i], factor);
}
return bset;
}
/* Add all rays (other than lines) from the given factor to "bset",
* given that there is a "total" number of coefficients
* (other than that of the constant term).
*/
static __isl_give isl_basic_set *add_rays(__isl_take isl_basic_set *bset,
struct isl_coefficients_factor_data *data, int total)
{
int i;
int n_ineq = data->n_ray + data->n_vertex;
for (i = 0; i < n_ineq; ++i) {
int k;
if (!is_ray(data->coeff, i))
continue;
k = isl_basic_set_alloc_inequality(bset);
if (k < 0)
return isl_basic_set_free(bset);
clear_entry(bset->ineq[k], total);
set_factor(bset->ineq[k], data->coeff->ineq[i], data);
}
return bset;
}
/* Move to the first vertex of the given factor starting
* at inequality constraint "start", setting factor->pos and
* returning 1 if a vertex is found.
*/
static int factor_first_vertex(struct isl_coefficients_factor_data *factor,
int start)
{
int j;
int n = factor->n_ray + factor->n_vertex;
for (j = start; j < n; ++j) {
if (is_ray(factor->coeff, j))
continue;
factor->pos = j;
return 1;
}
return 0;
}
/* Move to the first constraint in each factor starting at "first"
* that represents a vertex.
* In particular, skip the initial constraints that correspond to rays.
*/
static void first_vertex(struct isl_coefficients_product_data *data, int first)
{
int i;
for (i = first; i < data->n; ++i)
factor_first_vertex(&data->factors[i], 0);
}
/* Move to the next vertex in the product.
* In particular, move to the next vertex of the last factor.
* If all vertices of this last factor have already been considered,
* then move to the next vertex of the previous factor(s)
* until a factor is found that still has a next vertex.
* Once such a next vertex has been found, the subsequent
* factors are reset to the first vertex.
* Return 1 if any next vertex was found.
*/
static int next_vertex(struct isl_coefficients_product_data *data)
{
int i;
for (i = data->n - 1; i >= 0; --i) {
struct isl_coefficients_factor_data *factor = &data->factors[i];
if (!factor_first_vertex(factor, factor->pos + 1))
continue;
first_vertex(data, i + 1);
return 1;
}
return 0;
}
/* Add a vertex to the product "bset" combining the currently selected
* vertices of the factors.
*
* In the dual representation, the constant term is always zero.
* The vertex itself is the sum of the contributions of the factors
* with a shared denominator in position 1.
*
* First compute the shared denominator (lcm) and
* then scale the numerators to this shared denominator.
*/
static __isl_give isl_basic_set *add_vertex(__isl_take isl_basic_set *bset,
struct isl_coefficients_product_data *data)
{
int i;
int k;
isl_int lcm, f;
k = isl_basic_set_alloc_inequality(bset);
if (k < 0)
return isl_basic_set_free(bset);
isl_int_init(lcm);
isl_int_init(f);
isl_int_set_si(lcm, 1);
for (i = 0; i < data->n; ++i) {
struct isl_coefficients_factor_data *factor = &data->factors[i];
isl_basic_set *coeff = factor->coeff;
int pos = factor->pos;
isl_int_lcm(lcm, lcm, coeff->ineq[pos][1]);
}
isl_int_set_si(bset->ineq[k][0], 0);
isl_int_set(bset->ineq[k][1], lcm);
for (i = 0; i < data->n; ++i) {
struct isl_coefficients_factor_data *factor = &data->factors[i];
isl_basic_set *coeff = factor->coeff;
int pos = factor->pos;
isl_int_divexact(f, lcm, coeff->ineq[pos][1]);
scale_factor(bset->ineq[k], coeff->ineq[pos], f, factor);
}
isl_int_clear(f);
isl_int_clear(lcm);
return bset;
}
/* Combine the duals of the factors in the factorization of a basic set
* to form the dual of the entire basic set.
* The dual share the coefficient of the constant term.
* All other coefficients are specific to a factor.
* Any constraint not involving the coefficient of the constant term
* can therefor simply be copied into the appropriate position.
* This includes all equality constraints since the coefficient
* of the constant term can always be increased and therefore
* never appears in an equality constraint.
* The inequality constraints involving the coefficient of
* the constant term need to be combined across factors.
* In particular, if this coefficient needs to be greater than or equal
* to some linear combination of the other coefficients in each factor,
* then it needs to be greater than or equal to the sum of
* these linear combinations across the factors.
*
* Alternatively, the constraints of the dual can be seen
* as the vertices, rays and lines of the original basic set.
* Clearly, rays and lines can simply be copied,
* while vertices needs to be combined across factors.
* This means that the number of rays and lines in the product
* is equal to the sum of the numbers in the factors,
* while the number of vertices is the product
* of the number of vertices in the factors. Note that each
* factor has at least one vertex.
* The only exception is when the factor is the dual of an obviously empty set,
* in which case a universe dual is created.
* In this case, return a universe dual for the product as well.
*
* While constructing the vertices, look for the first combination
* of inequality constraints that represent a vertex,
* construct the corresponding vertex and then move on
* to the next combination of inequality constraints until
* all combinations have been considered.
*/
static __isl_give isl_basic_set *construct_product(isl_ctx *ctx,
struct isl_coefficients_product_data *data)
{
int i;
int n_line, n_ray, n_vertex;
int total;
isl_space *space;
isl_basic_set *product;
if (!data->factors)
return NULL;
total = data->start_next;
n_line = 0;
n_ray = 0;
n_vertex = 1;
for (i = 0; i < data->n; ++i) {
n_line += data->factors[i].n_line;
n_ray += data->factors[i].n_ray;
n_vertex *= data->factors[i].n_vertex;
}
space = isl_space_set_alloc(ctx, 0, 1 + total);
if (n_vertex == 0)
return rational_universe(space);
product = isl_basic_set_alloc_space(space, 0, n_line, n_ray + n_vertex);
product = isl_basic_set_set_rational(product);
for (i = 0; i < data->n; ++i)
product = add_lines(product, &data->factors[i], total);
for (i = 0; i < data->n; ++i)
product = add_rays(product, &data->factors[i], total);
first_vertex(data, 0);
do {
product = add_vertex(product, data);
} while (next_vertex(data));
return product;
}
/* Given a factorization "f" of a basic set,
* construct a basic set containing the tuples of coefficients of all
* valid affine constraints on the product of the factors, ignoring
* the space of input and output.
* Note that this product may not be equal to the original basic set,
* if a non-trivial transformation is involved.
* This is handled by the caller.
*
* Compute the tuples of coefficients for each factor separately and
* then combine the results.
*/
static __isl_give isl_basic_set *isl_basic_set_coefficients_product(
__isl_take isl_factorizer *f)
{
struct isl_coefficients_product_data data;
isl_ctx *ctx;
isl_basic_set *coeff;
isl_bool every;
ctx = isl_factorizer_get_ctx(f);
if (isl_coefficients_product_data_init(ctx, &data, f->n_group) < 0)
f = isl_factorizer_free(f);
every = isl_factorizer_every_factor_basic_set(f,
&isl_basic_set_coefficients_factor, &data);
isl_factorizer_free(f);
if (every >= 0)
coeff = construct_product(ctx, &data);
else
coeff = NULL;
isl_coefficients_product_data_clear(&data);
return coeff;
}
/* Given a factorization "f" of a basic set,
* construct a basic set containing the tuples of coefficients of all
* valid affine constraints on the basic set, ignoring
* the space of input and output.
*
* The factorization may involve a linear transformation of the basic set.
* In particular, the transformed basic set is formulated
* in terms of x' = U x, i.e., x = V x', with V = U^{-1}.
* The dual is then computed in terms of y' with y'^t [z; x'] >= 0.
* Plugging in y' = [1 0; 0 V^t] y yields
* y^t [1 0; 0 V] [z; x'] >= 0, i.e., y^t [z; x] >= 0, which is
* the desired set of coefficients y.
* Note that this transformation to y' only needs to be applied
* if U is not the identity matrix.
*/
static __isl_give isl_basic_set *isl_basic_set_coefficients_morphed_product(
__isl_take isl_factorizer *f)
{
isl_bool is_identity;
isl_space *space;
isl_mat *inv;
isl_multi_aff *ma;
isl_basic_set *coeff;
if (!f)
goto error;
is_identity = isl_mat_is_scaled_identity(peek_inv(f->morph));
if (is_identity < 0)
goto error;
if (is_identity)
return isl_basic_set_coefficients_product(f);
inv = get_inv(f->morph);
inv = isl_mat_transpose(inv);
inv = isl_mat_lin_to_aff(inv);
coeff = isl_basic_set_coefficients_product(f);
space = isl_space_map_from_set(isl_basic_set_get_space(coeff));
ma = isl_multi_aff_from_aff_mat(space, inv);
coeff = isl_basic_set_preimage_multi_aff(coeff, ma);
return coeff;
error:
isl_factorizer_free(f);
return NULL;
}
/* Construct a basic set containing the tuples of coefficients of all
* valid affine constraints on the given basic set, ignoring
* the space of input and output.
*
* The caller has already checked that "bset" does not involve
* any local variables. It may have parameters, though.
* Treat them as regular variables internally.
* This is especially important for the factorization,
* since the (original) parameters should be taken into account
* explicitly in this factorization.
*
* Check if the basic set can be factorized.
* If so, compute constraints on the coefficients of the factors
* separately and combine the results.
* Otherwise, compute the results for the input basic set as a whole.
*/
static __isl_give isl_basic_set *basic_set_coefficients(
__isl_take isl_basic_set *bset)
{
isl_factorizer *f;
isl_size nparam;
nparam = isl_basic_set_dim(bset, isl_dim_param);
if (nparam < 0)
return isl_basic_set_free(bset);
bset = isl_basic_set_move_dims(bset, isl_dim_set, 0,
isl_dim_param, 0, nparam);
f = isl_basic_set_factorizer(bset);
if (!f)
return isl_basic_set_free(bset);
if (f->n_group > 0) {
isl_basic_set_free(bset);
return isl_basic_set_coefficients_morphed_product(f);
}
isl_factorizer_free(f);
return isl_basic_set_coefficients_base(bset);
}
/* Construct a basic set containing the tuples of coefficients of all
* valid affine constraints on the given basic set.
*/
__isl_give isl_basic_set *isl_basic_set_coefficients(
__isl_take isl_basic_set *bset)
{
isl_space *space;
if (!bset)
return NULL;
if (bset->n_div)
isl_die(bset->ctx, isl_error_invalid,
"input set not allowed to have local variables",
goto error);
space = isl_basic_set_get_space(bset);
space = isl_space_coefficients(space);
bset = basic_set_coefficients(bset);
bset = isl_basic_set_reset_space(bset, space);
return bset;
error:
isl_basic_set_free(bset);
return NULL;
}
/* Construct a basic set containing the elements that satisfy all
* affine constraints whose coefficient tuples are
* contained in the given basic set.
*/
__isl_give isl_basic_set *isl_basic_set_solutions(
__isl_take isl_basic_set *bset)
{
isl_space *space;
if (!bset)
return NULL;
if (bset->n_div)
isl_die(bset->ctx, isl_error_invalid,
"input set not allowed to have local variables",
goto error);
space = isl_basic_set_get_space(bset);
space = isl_space_solutions(space);
bset = farkas(bset, -1);
bset = isl_basic_set_reset_space(bset, space);
return bset;
error:
isl_basic_set_free(bset);
return NULL;
}
/* Construct a basic set containing the tuples of coefficients of all
* valid affine constraints on the given set.
*/
__isl_give isl_basic_set *isl_set_coefficients(__isl_take isl_set *set)
{
int i;
isl_basic_set *coeff;
if (!set)
return NULL;
if (set->n == 0) {
isl_space *space = isl_set_get_space(set);
space = isl_space_coefficients(space);
isl_set_free(set);
return rational_universe(space);
}
coeff = isl_basic_set_coefficients(isl_basic_set_copy(set->p[0]));
for (i = 1; i < set->n; ++i) {
isl_basic_set *bset, *coeff_i;
bset = isl_basic_set_copy(set->p[i]);
coeff_i = isl_basic_set_coefficients(bset);
coeff = isl_basic_set_intersect(coeff, coeff_i);
}
isl_set_free(set);
return coeff;
}
/* Wrapper around isl_basic_set_coefficients for use
* as a isl_basic_set_list_map callback.
*/
static __isl_give isl_basic_set *coefficients_wrap(
__isl_take isl_basic_set *bset, void *user)
{
return isl_basic_set_coefficients(bset);
}
/* Replace the elements of "list" by the result of applying
* isl_basic_set_coefficients to them.
*/
__isl_give isl_basic_set_list *isl_basic_set_list_coefficients(
__isl_take isl_basic_set_list *list)
{
return isl_basic_set_list_map(list, &coefficients_wrap, NULL);
}
/* Construct a basic set containing the elements that satisfy all
* affine constraints whose coefficient tuples are
* contained in the given set.
*/
__isl_give isl_basic_set *isl_set_solutions(__isl_take isl_set *set)
{
int i;
isl_basic_set *sol;
if (!set)
return NULL;
if (set->n == 0) {
isl_space *space = isl_set_get_space(set);
space = isl_space_solutions(space);
isl_set_free(set);
return rational_universe(space);
}
sol = isl_basic_set_solutions(isl_basic_set_copy(set->p[0]));
for (i = 1; i < set->n; ++i) {
isl_basic_set *bset, *sol_i;
bset = isl_basic_set_copy(set->p[i]);
sol_i = isl_basic_set_solutions(bset);
sol = isl_basic_set_intersect(sol, sol_i);
}
isl_set_free(set);
return sol;
}