Home | History | Annotate | Line # | Download | only in dist
      1  1.1  mrg /*
      2  1.1  mrg  * Copyright 2010      INRIA Saclay
      3  1.1  mrg  *
      4  1.1  mrg  * Use of this software is governed by the MIT license
      5  1.1  mrg  *
      6  1.1  mrg  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
      7  1.1  mrg  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
      8  1.1  mrg  * 91893 Orsay, France
      9  1.1  mrg  */
     10  1.1  mrg 
     11  1.1  mrg #include <isl_ctx_private.h>
     12  1.1  mrg #include <isl_map_private.h>
     13  1.1  mrg #include <isl_bound.h>
     14  1.1  mrg #include <isl_bernstein.h>
     15  1.1  mrg #include <isl_range.h>
     16  1.1  mrg #include <isl_polynomial_private.h>
     17  1.1  mrg #include <isl_options_private.h>
     18  1.1  mrg 
     19  1.1  mrg /* Given a polynomial "poly" that is constant in terms
     20  1.1  mrg  * of the domain variables, construct a polynomial reduction
     21  1.1  mrg  * of type "type" that is equal to "poly" on "bset",
     22  1.1  mrg  * with the domain projected onto the parameters.
     23  1.1  mrg  */
     24  1.1  mrg __isl_give isl_pw_qpolynomial_fold *isl_qpolynomial_cst_bound(
     25  1.1  mrg 	__isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *poly,
     26  1.1  mrg 	enum isl_fold type, isl_bool *tight)
     27  1.1  mrg {
     28  1.1  mrg 	isl_set *dom;
     29  1.1  mrg 	isl_qpolynomial_fold *fold;
     30  1.1  mrg 	isl_pw_qpolynomial_fold *pwf;
     31  1.1  mrg 
     32  1.1  mrg 	fold = isl_qpolynomial_fold_alloc(type, poly);
     33  1.1  mrg 	dom = isl_set_from_basic_set(bset);
     34  1.1  mrg 	if (tight)
     35  1.1  mrg 		*tight = isl_bool_true;
     36  1.1  mrg 	pwf = isl_pw_qpolynomial_fold_alloc(type, dom, fold);
     37  1.1  mrg 	return isl_pw_qpolynomial_fold_project_domain_on_params(pwf);
     38  1.1  mrg }
     39  1.1  mrg 
     40  1.1  mrg /* Add the bound "pwf", which is not known to be tight,
     41  1.1  mrg  * to the output of "bound".
     42  1.1  mrg  */
     43  1.1  mrg isl_stat isl_bound_add(struct isl_bound *bound,
     44  1.1  mrg 	__isl_take isl_pw_qpolynomial_fold *pwf)
     45  1.1  mrg {
     46  1.1  mrg 	bound->pwf = isl_pw_qpolynomial_fold_fold(bound->pwf, pwf);
     47  1.1  mrg 	return isl_stat_non_null(bound->pwf);
     48  1.1  mrg }
     49  1.1  mrg 
     50  1.1  mrg /* Add the bound "pwf", which is known to be tight,
     51  1.1  mrg  * to the output of "bound".
     52  1.1  mrg  */
     53  1.1  mrg isl_stat isl_bound_add_tight(struct isl_bound *bound,
     54  1.1  mrg 	__isl_take isl_pw_qpolynomial_fold *pwf)
     55  1.1  mrg {
     56  1.1  mrg 	bound->pwf_tight = isl_pw_qpolynomial_fold_fold(bound->pwf_tight, pwf);
     57  1.1  mrg 	return isl_stat_non_null(bound->pwf);
     58  1.1  mrg }
     59  1.1  mrg 
     60  1.1  mrg /* Given a polynomial "poly" that is constant in terms
     61  1.1  mrg  * of the domain variables and the domain "bset",
     62  1.1  mrg  * construct the corresponding polynomial reduction and
     63  1.1  mrg  * add it to the tight bounds of "bound".
     64  1.1  mrg  */
     65  1.1  mrg static isl_stat add_constant_poly(__isl_take isl_basic_set *bset,
     66  1.1  mrg 	__isl_take isl_qpolynomial *poly, struct isl_bound *bound)
     67  1.1  mrg {
     68  1.1  mrg 	isl_pw_qpolynomial_fold *pwf;
     69  1.1  mrg 
     70  1.1  mrg 	pwf = isl_qpolynomial_cst_bound(bset, poly, bound->type, NULL);
     71  1.1  mrg 	return isl_bound_add_tight(bound, pwf);
     72  1.1  mrg }
     73  1.1  mrg 
     74  1.1  mrg /* Compute a bound on the polynomial defined over the parametric polytope
     75  1.1  mrg  * using either range propagation or bernstein expansion and
     76  1.1  mrg  * store the result in bound->pwf and bound->pwf_tight.
     77  1.1  mrg  * Since bernstein expansion requires bounded domains, we apply
     78  1.1  mrg  * range propagation on unbounded domains.  Otherwise, we respect the choice
     79  1.1  mrg  * of the user.
     80  1.1  mrg  *
     81  1.1  mrg  * If the polynomial does not depend on the set variables
     82  1.1  mrg  * then the bound is equal to the polynomial and
     83  1.1  mrg  * it can be added to "bound" directly.
     84  1.1  mrg  */
     85  1.1  mrg static isl_stat compressed_guarded_poly_bound(__isl_take isl_basic_set *bset,
     86  1.1  mrg 	__isl_take isl_qpolynomial *poly, void *user)
     87  1.1  mrg {
     88  1.1  mrg 	struct isl_bound *bound = (struct isl_bound *)user;
     89  1.1  mrg 	isl_ctx *ctx;
     90  1.1  mrg 	int bounded;
     91  1.1  mrg 	int degree;
     92  1.1  mrg 
     93  1.1  mrg 	if (!bset || !poly)
     94  1.1  mrg 		goto error;
     95  1.1  mrg 
     96  1.1  mrg 	degree = isl_qpolynomial_degree(poly);
     97  1.1  mrg 	if (degree < -1)
     98  1.1  mrg 		goto error;
     99  1.1  mrg 	if (degree <= 0)
    100  1.1  mrg 		return add_constant_poly(bset, poly, bound);
    101  1.1  mrg 
    102  1.1  mrg 	ctx = isl_basic_set_get_ctx(bset);
    103  1.1  mrg 	if (ctx->opt->bound == ISL_BOUND_RANGE)
    104  1.1  mrg 		return isl_qpolynomial_bound_on_domain_range(bset, poly, bound);
    105  1.1  mrg 
    106  1.1  mrg 	bounded = isl_basic_set_is_bounded(bset);
    107  1.1  mrg 	if (bounded < 0)
    108  1.1  mrg 		goto error;
    109  1.1  mrg 	if (bounded)
    110  1.1  mrg 		return isl_qpolynomial_bound_on_domain_bernstein(bset, poly, bound);
    111  1.1  mrg 	else
    112  1.1  mrg 		return isl_qpolynomial_bound_on_domain_range(bset, poly, bound);
    113  1.1  mrg error:
    114  1.1  mrg 	isl_basic_set_free(bset);
    115  1.1  mrg 	isl_qpolynomial_free(poly);
    116  1.1  mrg 	return isl_stat_error;
    117  1.1  mrg }
    118  1.1  mrg 
    119  1.1  mrg static isl_stat unwrapped_guarded_poly_bound(__isl_take isl_basic_set *bset,
    120  1.1  mrg 	__isl_take isl_qpolynomial *poly, void *user)
    121  1.1  mrg {
    122  1.1  mrg 	struct isl_bound *bound = (struct isl_bound *)user;
    123  1.1  mrg 	isl_pw_qpolynomial_fold *top_pwf;
    124  1.1  mrg 	isl_pw_qpolynomial_fold *top_pwf_tight;
    125  1.1  mrg 	isl_space *space;
    126  1.1  mrg 	isl_morph *morph;
    127  1.1  mrg 	isl_stat r;
    128  1.1  mrg 
    129  1.1  mrg 	bset = isl_basic_set_detect_equalities(bset);
    130  1.1  mrg 
    131  1.1  mrg 	if (!bset)
    132  1.1  mrg 		goto error;
    133  1.1  mrg 
    134  1.1  mrg 	if (bset->n_eq == 0)
    135  1.1  mrg 		return compressed_guarded_poly_bound(bset, poly, user);
    136  1.1  mrg 
    137  1.1  mrg 	morph = isl_basic_set_full_compression(bset);
    138  1.1  mrg 
    139  1.1  mrg 	bset = isl_morph_basic_set(isl_morph_copy(morph), bset);
    140  1.1  mrg 	poly = isl_qpolynomial_morph_domain(poly, isl_morph_copy(morph));
    141  1.1  mrg 
    142  1.1  mrg 	space = isl_morph_get_ran_space(morph);
    143  1.1  mrg 	space = isl_space_params(space);
    144  1.1  mrg 
    145  1.1  mrg 	top_pwf = bound->pwf;
    146  1.1  mrg 	top_pwf_tight = bound->pwf_tight;
    147  1.1  mrg 
    148  1.1  mrg 	space = isl_space_from_domain(space);
    149  1.1  mrg 	space = isl_space_add_dims(space, isl_dim_out, 1);
    150  1.1  mrg 	bound->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(space),
    151  1.1  mrg 						  bound->type);
    152  1.1  mrg 	bound->pwf_tight = isl_pw_qpolynomial_fold_zero(space, bound->type);
    153  1.1  mrg 
    154  1.1  mrg 	r = compressed_guarded_poly_bound(bset, poly, user);
    155  1.1  mrg 
    156  1.1  mrg 	morph = isl_morph_dom_params(morph);
    157  1.1  mrg 	morph = isl_morph_ran_params(morph);
    158  1.1  mrg 	morph = isl_morph_inverse(morph);
    159  1.1  mrg 
    160  1.1  mrg 	bound->pwf = isl_pw_qpolynomial_fold_morph_domain(bound->pwf,
    161  1.1  mrg 							isl_morph_copy(morph));
    162  1.1  mrg 	bound->pwf_tight = isl_pw_qpolynomial_fold_morph_domain(
    163  1.1  mrg 						bound->pwf_tight, morph);
    164  1.1  mrg 
    165  1.1  mrg 	isl_bound_add(bound, top_pwf);
    166  1.1  mrg 	isl_bound_add_tight(bound, top_pwf_tight);
    167  1.1  mrg 
    168  1.1  mrg 	return r;
    169  1.1  mrg error:
    170  1.1  mrg 	isl_basic_set_free(bset);
    171  1.1  mrg 	isl_qpolynomial_free(poly);
    172  1.1  mrg 	return isl_stat_error;
    173  1.1  mrg }
    174  1.1  mrg 
    175  1.1  mrg /* Update bound->pwf and bound->pwf_tight with a bound
    176  1.1  mrg  * of type bound->type on the polynomial "poly" over the domain "bset".
    177  1.1  mrg  *
    178  1.1  mrg  * If the original problem had a wrapped relation in the domain,
    179  1.1  mrg  * meaning that the bound should be computed over the range
    180  1.1  mrg  * of this relation, then temporarily treat the domain dimensions
    181  1.1  mrg  * of this wrapped relation as parameters, compute a bound
    182  1.1  mrg  * in terms of these and the original parameters,
    183  1.1  mrg  * turn the parameters back into set dimensions and
    184  1.1  mrg  * add the results to bound->pwf and bound->pwf_tight.
    185  1.1  mrg  *
    186  1.1  mrg  * Note that even though "bset" is known to live in the same space
    187  1.1  mrg  * as the domain of "poly", the names of the set dimensions
    188  1.1  mrg  * may be different (or missing).  Make sure the naming is exactly
    189  1.1  mrg  * the same before turning these dimensions into parameters
    190  1.1  mrg  * to ensure that the spaces are still the same after
    191  1.1  mrg  * this operation.
    192  1.1  mrg  */
    193  1.1  mrg static isl_stat guarded_poly_bound(__isl_take isl_basic_set *bset,
    194  1.1  mrg 	__isl_take isl_qpolynomial *poly, void *user)
    195  1.1  mrg {
    196  1.1  mrg 	struct isl_bound *bound = (struct isl_bound *)user;
    197  1.1  mrg 	isl_space *space;
    198  1.1  mrg 	isl_pw_qpolynomial_fold *top_pwf;
    199  1.1  mrg 	isl_pw_qpolynomial_fold *top_pwf_tight;
    200  1.1  mrg 	isl_size nparam;
    201  1.1  mrg 	isl_size n_in;
    202  1.1  mrg 	isl_stat r;
    203  1.1  mrg 
    204  1.1  mrg 	if (!bound->wrapping)
    205  1.1  mrg 		return unwrapped_guarded_poly_bound(bset, poly, user);
    206  1.1  mrg 
    207  1.1  mrg 	nparam = isl_space_dim(bound->dim, isl_dim_param);
    208  1.1  mrg 	n_in = isl_space_dim(bound->dim, isl_dim_in);
    209  1.1  mrg 	if (nparam < 0 || n_in < 0)
    210  1.1  mrg 		goto error;
    211  1.1  mrg 
    212  1.1  mrg 	space = isl_qpolynomial_get_domain_space(poly);
    213  1.1  mrg 	bset = isl_basic_set_reset_space(bset, space);
    214  1.1  mrg 
    215  1.1  mrg 	bset = isl_basic_set_move_dims(bset, isl_dim_param, nparam,
    216  1.1  mrg 					isl_dim_set, 0, n_in);
    217  1.1  mrg 	poly = isl_qpolynomial_move_dims(poly, isl_dim_param, nparam,
    218  1.1  mrg 					isl_dim_in, 0, n_in);
    219  1.1  mrg 
    220  1.1  mrg 	space = isl_basic_set_get_space(bset);
    221  1.1  mrg 	space = isl_space_params(space);
    222  1.1  mrg 
    223  1.1  mrg 	top_pwf = bound->pwf;
    224  1.1  mrg 	top_pwf_tight = bound->pwf_tight;
    225  1.1  mrg 
    226  1.1  mrg 	space = isl_space_from_domain(space);
    227  1.1  mrg 	space = isl_space_add_dims(space, isl_dim_out, 1);
    228  1.1  mrg 	bound->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(space),
    229  1.1  mrg 						  bound->type);
    230  1.1  mrg 	bound->pwf_tight = isl_pw_qpolynomial_fold_zero(space, bound->type);
    231  1.1  mrg 
    232  1.1  mrg 	r = unwrapped_guarded_poly_bound(bset, poly, user);
    233  1.1  mrg 
    234  1.1  mrg 	bound->pwf = isl_pw_qpolynomial_fold_reset_space(bound->pwf,
    235  1.1  mrg 						    isl_space_copy(bound->dim));
    236  1.1  mrg 	bound->pwf_tight = isl_pw_qpolynomial_fold_reset_space(bound->pwf_tight,
    237  1.1  mrg 						    isl_space_copy(bound->dim));
    238  1.1  mrg 
    239  1.1  mrg 	isl_bound_add(bound, top_pwf);
    240  1.1  mrg 	isl_bound_add_tight(bound, top_pwf_tight);
    241  1.1  mrg 
    242  1.1  mrg 	return r;
    243  1.1  mrg error:
    244  1.1  mrg 	isl_basic_set_free(bset);
    245  1.1  mrg 	isl_qpolynomial_free(poly);
    246  1.1  mrg 	return isl_stat_error;
    247  1.1  mrg }
    248  1.1  mrg 
    249  1.1  mrg static isl_stat guarded_qp(__isl_take isl_qpolynomial *qp, void *user)
    250  1.1  mrg {
    251  1.1  mrg 	struct isl_bound *bound = (struct isl_bound *)user;
    252  1.1  mrg 	isl_stat r;
    253  1.1  mrg 
    254  1.1  mrg 	r = isl_qpolynomial_as_polynomial_on_domain(qp, bound->bset,
    255  1.1  mrg 						    &guarded_poly_bound, user);
    256  1.1  mrg 	isl_qpolynomial_free(qp);
    257  1.1  mrg 	return r;
    258  1.1  mrg }
    259  1.1  mrg 
    260  1.1  mrg static isl_stat basic_guarded_fold(__isl_take isl_basic_set *bset, void *user)
    261  1.1  mrg {
    262  1.1  mrg 	struct isl_bound *bound = (struct isl_bound *)user;
    263  1.1  mrg 	isl_stat r;
    264  1.1  mrg 
    265  1.1  mrg 	bound->bset = bset;
    266  1.1  mrg 	r = isl_qpolynomial_fold_foreach_qpolynomial(bound->fold,
    267  1.1  mrg 							&guarded_qp, user);
    268  1.1  mrg 	isl_basic_set_free(bset);
    269  1.1  mrg 	return r;
    270  1.1  mrg }
    271  1.1  mrg 
    272  1.1  mrg static isl_stat guarded_fold(__isl_take isl_set *set,
    273  1.1  mrg 	__isl_take isl_qpolynomial_fold *fold, void *user)
    274  1.1  mrg {
    275  1.1  mrg 	struct isl_bound *bound = (struct isl_bound *)user;
    276  1.1  mrg 
    277  1.1  mrg 	if (!set || !fold)
    278  1.1  mrg 		goto error;
    279  1.1  mrg 
    280  1.1  mrg 	set = isl_set_make_disjoint(set);
    281  1.1  mrg 
    282  1.1  mrg 	bound->fold = fold;
    283  1.1  mrg 	bound->type = isl_qpolynomial_fold_get_type(fold);
    284  1.1  mrg 
    285  1.1  mrg 	if (isl_set_foreach_basic_set(set, &basic_guarded_fold, bound) < 0)
    286  1.1  mrg 		goto error;
    287  1.1  mrg 
    288  1.1  mrg 	isl_set_free(set);
    289  1.1  mrg 	isl_qpolynomial_fold_free(fold);
    290  1.1  mrg 
    291  1.1  mrg 	return isl_stat_ok;
    292  1.1  mrg error:
    293  1.1  mrg 	isl_set_free(set);
    294  1.1  mrg 	isl_qpolynomial_fold_free(fold);
    295  1.1  mrg 	return isl_stat_error;
    296  1.1  mrg }
    297  1.1  mrg 
    298  1.1  mrg __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_bound(
    299  1.1  mrg 	__isl_take isl_pw_qpolynomial_fold *pwf, isl_bool *tight)
    300  1.1  mrg {
    301  1.1  mrg 	isl_size nvar;
    302  1.1  mrg 	struct isl_bound bound;
    303  1.1  mrg 	isl_bool covers;
    304  1.1  mrg 
    305  1.1  mrg 	if (!pwf)
    306  1.1  mrg 		return NULL;
    307  1.1  mrg 
    308  1.1  mrg 	bound.dim = isl_pw_qpolynomial_fold_get_domain_space(pwf);
    309  1.1  mrg 
    310  1.1  mrg 	bound.wrapping = isl_space_is_wrapping(bound.dim);
    311  1.1  mrg 	if (bound.wrapping)
    312  1.1  mrg 		bound.dim = isl_space_unwrap(bound.dim);
    313  1.1  mrg 	nvar = isl_space_dim(bound.dim, isl_dim_out);
    314  1.1  mrg 	if (nvar < 0)
    315  1.1  mrg 		bound.dim = isl_space_free(bound.dim);
    316  1.1  mrg 	bound.dim = isl_space_domain(bound.dim);
    317  1.1  mrg 	bound.dim = isl_space_from_domain(bound.dim);
    318  1.1  mrg 	bound.dim = isl_space_add_dims(bound.dim, isl_dim_out, 1);
    319  1.1  mrg 
    320  1.1  mrg 	if (nvar == 0) {
    321  1.1  mrg 		if (tight)
    322  1.1  mrg 			*tight = isl_bool_true;
    323  1.1  mrg 		return isl_pw_qpolynomial_fold_reset_space(pwf, bound.dim);
    324  1.1  mrg 	}
    325  1.1  mrg 
    326  1.1  mrg 	if (isl_pw_qpolynomial_fold_is_zero(pwf)) {
    327  1.1  mrg 		enum isl_fold type = pwf->type;
    328  1.1  mrg 		isl_pw_qpolynomial_fold_free(pwf);
    329  1.1  mrg 		if (tight)
    330  1.1  mrg 			*tight = isl_bool_true;
    331  1.1  mrg 		return isl_pw_qpolynomial_fold_zero(bound.dim, type);
    332  1.1  mrg 	}
    333  1.1  mrg 
    334  1.1  mrg 	bound.pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(bound.dim),
    335  1.1  mrg 							pwf->type);
    336  1.1  mrg 	bound.pwf_tight = isl_pw_qpolynomial_fold_zero(isl_space_copy(bound.dim),
    337  1.1  mrg 							pwf->type);
    338  1.1  mrg 	bound.check_tight = !!tight;
    339  1.1  mrg 
    340  1.1  mrg 	if (isl_pw_qpolynomial_fold_foreach_lifted_piece(pwf,
    341  1.1  mrg 							guarded_fold, &bound) < 0)
    342  1.1  mrg 		goto error;
    343  1.1  mrg 
    344  1.1  mrg 	covers = isl_pw_qpolynomial_fold_covers(bound.pwf_tight, bound.pwf);
    345  1.1  mrg 	if (covers < 0)
    346  1.1  mrg 		goto error;
    347  1.1  mrg 
    348  1.1  mrg 	if (tight)
    349  1.1  mrg 		*tight = covers;
    350  1.1  mrg 
    351  1.1  mrg 	isl_space_free(bound.dim);
    352  1.1  mrg 	isl_pw_qpolynomial_fold_free(pwf);
    353  1.1  mrg 
    354  1.1  mrg 	if (covers) {
    355  1.1  mrg 		isl_pw_qpolynomial_fold_free(bound.pwf);
    356  1.1  mrg 		return bound.pwf_tight;
    357  1.1  mrg 	}
    358  1.1  mrg 
    359  1.1  mrg 	bound.pwf = isl_pw_qpolynomial_fold_fold(bound.pwf, bound.pwf_tight);
    360  1.1  mrg 
    361  1.1  mrg 	return bound.pwf;
    362  1.1  mrg error:
    363  1.1  mrg 	isl_pw_qpolynomial_fold_free(bound.pwf_tight);
    364  1.1  mrg 	isl_pw_qpolynomial_fold_free(bound.pwf);
    365  1.1  mrg 	isl_pw_qpolynomial_fold_free(pwf);
    366  1.1  mrg 	isl_space_free(bound.dim);
    367  1.1  mrg 	return NULL;
    368  1.1  mrg }
    369  1.1  mrg 
    370  1.1  mrg __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_bound(
    371  1.1  mrg 	__isl_take isl_pw_qpolynomial *pwqp, enum isl_fold type,
    372  1.1  mrg 	isl_bool *tight)
    373  1.1  mrg {
    374  1.1  mrg 	isl_pw_qpolynomial_fold *pwf;
    375  1.1  mrg 
    376  1.1  mrg 	pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(type, pwqp);
    377  1.1  mrg 	return isl_pw_qpolynomial_fold_bound(pwf, tight);
    378  1.1  mrg }
    379  1.1  mrg 
    380  1.1  mrg struct isl_union_bound_data {
    381  1.1  mrg 	enum isl_fold type;
    382  1.1  mrg 	isl_bool tight;
    383  1.1  mrg 	isl_union_pw_qpolynomial_fold *res;
    384  1.1  mrg };
    385  1.1  mrg 
    386  1.1  mrg static isl_stat bound_pw(__isl_take isl_pw_qpolynomial *pwqp, void *user)
    387  1.1  mrg {
    388  1.1  mrg 	struct isl_union_bound_data *data = user;
    389  1.1  mrg 	isl_pw_qpolynomial_fold *pwf;
    390  1.1  mrg 
    391  1.1  mrg 	pwf = isl_pw_qpolynomial_bound(pwqp, data->type,
    392  1.1  mrg 					data->tight ? &data->tight : NULL);
    393  1.1  mrg 	data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
    394  1.1  mrg 								data->res, pwf);
    395  1.1  mrg 
    396  1.1  mrg 	return isl_stat_ok;
    397  1.1  mrg }
    398  1.1  mrg 
    399  1.1  mrg __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_bound(
    400  1.1  mrg 	__isl_take isl_union_pw_qpolynomial *upwqp,
    401  1.1  mrg 	enum isl_fold type, isl_bool *tight)
    402  1.1  mrg {
    403  1.1  mrg 	isl_space *space;
    404  1.1  mrg 	struct isl_union_bound_data data = { type, 1, NULL };
    405  1.1  mrg 
    406  1.1  mrg 	if (!upwqp)
    407  1.1  mrg 		return NULL;
    408  1.1  mrg 
    409  1.1  mrg 	if (!tight)
    410  1.1  mrg 		data.tight = isl_bool_false;
    411  1.1  mrg 
    412  1.1  mrg 	space = isl_union_pw_qpolynomial_get_space(upwqp);
    413  1.1  mrg 	data.res = isl_union_pw_qpolynomial_fold_zero(space, type);
    414  1.1  mrg 	if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp,
    415  1.1  mrg 						    &bound_pw, &data) < 0)
    416  1.1  mrg 		goto error;
    417  1.1  mrg 
    418  1.1  mrg 	isl_union_pw_qpolynomial_free(upwqp);
    419  1.1  mrg 	if (tight)
    420  1.1  mrg 		*tight = data.tight;
    421  1.1  mrg 
    422  1.1  mrg 	return data.res;
    423  1.1  mrg error:
    424  1.1  mrg 	isl_union_pw_qpolynomial_free(upwqp);
    425  1.1  mrg 	isl_union_pw_qpolynomial_fold_free(data.res);
    426  1.1  mrg 	return NULL;
    427  1.1  mrg }
    428