isl_bound.c 12 KB

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