mirror of
https://review.haiku-os.org/buildtools
synced 2024-11-23 07:18:49 +01:00
967 lines
27 KiB
C
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;
|
|
}
|