Skip to content

Commit

Permalink
isl_pw_qpolynomial_bound: special case affine polynomials
Browse files Browse the repository at this point in the history
If one or more of the quasi-polynomials is actually a quasi-affine
expression, then the bound on the corresponding domain
can always be computed exactly.
Do this instead of using the generic bound computation.

Signed-off-by: Sven Verdoolaege <[email protected]>
  • Loading branch information
Sven Verdoolaege committed Apr 23, 2023
1 parent 4344c51 commit a365af4
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 0 deletions.
99 changes: 99 additions & 0 deletions isl_bound.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
* 91893 Orsay, France
*/

#include <isl/aff.h>
#include <isl/val.h>
#include <isl_ctx_private.h>
#include <isl_map_private.h>
#include <isl_bound.h>
Expand Down Expand Up @@ -263,10 +265,107 @@ static isl_stat guarded_poly_bound(__isl_take isl_basic_set *bset,
return unwrap(bset, poly, &unwrapped_guarded_poly_bound, bound);
}

/* Is "bset" bounded and is "qp" a quasi-affine expression?
*/
static isl_bool is_bounded_affine(__isl_keep isl_basic_set *bset,
__isl_keep isl_qpolynomial *qp)
{
isl_bool affine;

affine = isl_qpolynomial_isa_aff(qp);
if (affine < 0 || !affine)
return affine;
return isl_basic_set_is_bounded(bset);
}

/* Update bound->pwf and bound->pwf_tight with a bound
* of type bound->type on the quasi-polynomial "qp" over the domain "bset",
* for the case where "bset" is bounded and
* "qp" is a quasi-affine expression and
* they have both been unwrapped already if needed.
*
* Consider the set of possible function values of "qp" over "bset" and
* take the minimum or maximum value in this set, depending
* on whether a lower or an upper bound is being computed.
* Do this by calling isl_set_lexmin_pw_multi_aff or
* isl_set_lexmax_pw_multi_aff, which compute a regular minimum or maximum
* since the set is one-dimensional.
* Since this computation is exact, the bound is always tight.
*
* Note that the minimum or maximum integer value is being computed,
* so if "qp" has some non-trivial denominator, then it needs
* to be multiplied out first and then taken into account again
* after computing the minimum or maximum.
*/
static isl_stat unwrapped_affine_qp(__isl_take isl_basic_set *bset,
__isl_take isl_qpolynomial *qp, struct isl_bound *bound)
{
isl_val *d;
isl_aff *aff;
isl_basic_map *bmap;
isl_set *range;
isl_pw_multi_aff *opt;
isl_pw_aff *pa;
isl_pw_qpolynomial *pwqp;
isl_pw_qpolynomial_fold *pwf;

aff = isl_qpolynomial_as_aff(qp);
d = isl_aff_get_denominator_val(aff);
aff = isl_aff_scale_val(aff, isl_val_copy(d));
bmap = isl_basic_map_from_aff(aff);
bmap = isl_basic_map_intersect_domain(bmap, bset);
range = isl_set_from_basic_set(isl_basic_map_range(bmap));
if (bound->type == isl_fold_min)
opt = isl_set_lexmin_pw_multi_aff(range);
else
opt = isl_set_lexmax_pw_multi_aff(range);
pa = isl_pw_multi_aff_get_at(opt, 0);
isl_pw_multi_aff_free(opt);
pa = isl_pw_aff_scale_down_val(pa, d);
pwqp = isl_pw_qpolynomial_from_pw_aff(pa);
pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(bound->type, pwqp);

bound->pwf_tight = isl_pw_qpolynomial_fold_fold(bound->pwf_tight, pwf);

return isl_stat_non_null(bound->pwf_tight);
}

/* Update bound->pwf and bound->pwf_tight with a bound
* of type bound->type on the quasi-polynomial "qp" over the domain bound->bset,
* for the case where bound->bset is bounded and
* "qp" is a quasi-affine expression,
* handling any wrapping in the domain.
*/
static isl_stat affine_qp(__isl_take isl_qpolynomial *qp,
struct isl_bound *bound)
{
isl_basic_set *bset;

bset = isl_basic_set_copy(bound->bset);
return unwrap(bset, qp, &unwrapped_affine_qp, bound);
}

/* Update bound->pwf and bound->pwf_tight with a bound
* of type bound->type on the quasi-polynomial "qp" over the domain bound->bset.
*
* If bound->bset is bounded and if "qp" is a quasi-affine expression,
* then use a specialized version.
*
* Otherwise, treat the integer divisions as extra variables and
* compute a bound over the polynomial in terms of the original and
* the extra variables.
*/
static isl_stat guarded_qp(__isl_take isl_qpolynomial *qp, void *user)
{
struct isl_bound *bound = (struct isl_bound *)user;
isl_stat r;
isl_bool bounded_affine;

bounded_affine = is_bounded_affine(bound->bset, qp);
if (bounded_affine < 0)
qp = isl_qpolynomial_free(qp);
else if (bounded_affine)
return affine_qp(qp, bound);

r = isl_qpolynomial_as_polynomial_on_domain(qp, bound->bset,
&guarded_poly_bound, user);
Expand Down
2 changes: 2 additions & 0 deletions isl_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -4036,6 +4036,8 @@ static struct {
{ 1, isl_fold_max, "{ [0:10] -> 1 }", "{ max(1) }" },
{ 1, isl_fold_max, "{ [[m] -> [0:m]] -> m^2 }",
"{ [m] -> max(m^2) : m >= 0 }" },
{ 1, isl_fold_max, "{ [[a=0:1] -> [b=0:1]] -> (floor((a + b)/2)) }",
"{ [a=0:1] -> max(a) }" },
};

/* Check that the bound computation can handle differences
Expand Down

0 comments on commit a365af4

Please sign in to comment.