isl_fold.c 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183
  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_map_private.h>
  11. #include <isl_union_map_private.h>
  12. #include <isl_polynomial_private.h>
  13. #include <isl_point_private.h>
  14. #include <isl_space_private.h>
  15. #include <isl_lp_private.h>
  16. #include <isl_seq.h>
  17. #include <isl_mat_private.h>
  18. #include <isl_val_private.h>
  19. #include <isl_vec_private.h>
  20. #include <isl_config.h>
  21. #undef EL_BASE
  22. #define EL_BASE pw_qpolynomial_fold
  23. #include <isl_list_templ.c>
  24. enum isl_fold isl_fold_type_negate(enum isl_fold type)
  25. {
  26. switch (type) {
  27. case isl_fold_error:
  28. return isl_fold_error;
  29. case isl_fold_min:
  30. return isl_fold_max;
  31. case isl_fold_max:
  32. return isl_fold_min;
  33. case isl_fold_list:
  34. return isl_fold_list;
  35. }
  36. isl_die(NULL, isl_error_internal, "unhandled isl_fold type", abort());
  37. }
  38. /* Construct a new reduction with the given type, domain space and
  39. * list of polynomials.
  40. */
  41. static __isl_give isl_qpolynomial_fold *qpolynomial_fold_alloc(
  42. enum isl_fold type, __isl_take isl_space *space,
  43. __isl_take isl_qpolynomial_list *list)
  44. {
  45. isl_ctx *ctx;
  46. isl_qpolynomial_fold *fold;
  47. if (type < 0 || !space || !list)
  48. goto error;
  49. ctx = isl_space_get_ctx(space);
  50. fold = isl_calloc_type(ctx, struct isl_qpolynomial_fold);
  51. if (!fold)
  52. goto error;
  53. fold->ref = 1;
  54. fold->type = type;
  55. fold->dim = space;
  56. fold->list = list;
  57. return fold;
  58. error:
  59. isl_space_free(space);
  60. isl_qpolynomial_list_free(list);
  61. return NULL;
  62. }
  63. isl_ctx *isl_qpolynomial_fold_get_ctx(__isl_keep isl_qpolynomial_fold *fold)
  64. {
  65. return fold ? fold->dim->ctx : NULL;
  66. }
  67. /* Return the domain space of "fold".
  68. */
  69. static __isl_keep isl_space *isl_qpolynomial_fold_peek_domain_space(
  70. __isl_keep isl_qpolynomial_fold *fold)
  71. {
  72. return fold ? fold->dim : NULL;
  73. }
  74. __isl_give isl_space *isl_qpolynomial_fold_get_domain_space(
  75. __isl_keep isl_qpolynomial_fold *fold)
  76. {
  77. return isl_space_copy(isl_qpolynomial_fold_peek_domain_space(fold));
  78. }
  79. /* Return the space of the domain of "fold".
  80. * This may be either a copy or the space itself
  81. * if there is only one reference to "fold".
  82. * This allows the space to be modified inplace
  83. * if both the expression and its space have only a single reference.
  84. * The caller is not allowed to modify "fold" between this call and
  85. * a subsequent call to isl_qpolynomial_fold_restore_domain_space.
  86. * The only exception is that isl_qpolynomial_fold_free can be called instead.
  87. */
  88. static __isl_give isl_space *isl_qpolynomial_fold_take_domain_space(
  89. __isl_keep isl_qpolynomial_fold *fold)
  90. {
  91. isl_space *space;
  92. if (!fold)
  93. return NULL;
  94. if (fold->ref != 1)
  95. return isl_qpolynomial_fold_get_domain_space(fold);
  96. space = fold->dim;
  97. fold->dim = NULL;
  98. return space;
  99. }
  100. /* Set the space of the domain of "fold" to "space",
  101. * where the space of "fold" may be missing
  102. * due to a preceding call to isl_qpolynomial_fold_take_domain_space.
  103. * However, in this case, "fold" only has a single reference and
  104. * then the call to isl_qpolynomial_fold_cow has no effect.
  105. */
  106. static
  107. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_restore_domain_space(
  108. __isl_keep isl_qpolynomial_fold *fold, __isl_take isl_space *space)
  109. {
  110. if (!fold || !space)
  111. goto error;
  112. if (fold->dim == space) {
  113. isl_space_free(space);
  114. return fold;
  115. }
  116. fold = isl_qpolynomial_fold_cow(fold);
  117. if (!fold)
  118. goto error;
  119. isl_space_free(fold->dim);
  120. fold->dim = space;
  121. return fold;
  122. error:
  123. isl_qpolynomial_fold_free(fold);
  124. isl_space_free(space);
  125. return NULL;
  126. }
  127. __isl_give isl_space *isl_qpolynomial_fold_get_space(
  128. __isl_keep isl_qpolynomial_fold *fold)
  129. {
  130. isl_space *space;
  131. if (!fold)
  132. return NULL;
  133. space = isl_space_copy(fold->dim);
  134. space = isl_space_from_domain(space);
  135. space = isl_space_add_dims(space, isl_dim_out, 1);
  136. return space;
  137. }
  138. /* Return the list of polynomials in the reduction "fold".
  139. */
  140. __isl_keep isl_qpolynomial_list *isl_qpolynomial_fold_peek_list(
  141. __isl_keep isl_qpolynomial_fold *fold)
  142. {
  143. return fold ? fold->list : NULL;
  144. }
  145. /* Return a copy of the list of polynomials in the reduction "fold".
  146. */
  147. static __isl_give isl_qpolynomial_list *isl_qpolynomial_fold_get_list(
  148. __isl_keep isl_qpolynomial_fold *fold)
  149. {
  150. return isl_qpolynomial_list_copy(isl_qpolynomial_fold_peek_list(fold));
  151. }
  152. /* Return the list of polynomials of "fold".
  153. * This may be either a copy or the list itself
  154. * if there is only one reference to "fold".
  155. * This allows the list to be modified inplace
  156. * if both the expression and its list have only a single reference.
  157. * The caller is not allowed to modify "fold" between this call and
  158. * a subsequent call to isl_qpolynomial_fold_restore_list.
  159. * The only exception is that isl_qpolynomial_fold_free can be called instead.
  160. */
  161. static __isl_give isl_qpolynomial_list *isl_qpolynomial_fold_take_list(
  162. __isl_keep isl_qpolynomial_fold *fold)
  163. {
  164. isl_qpolynomial_list *list;
  165. if (!fold)
  166. return NULL;
  167. if (fold->ref != 1)
  168. return isl_qpolynomial_fold_get_list(fold);
  169. list = fold->list;
  170. fold->list = NULL;
  171. return list;
  172. }
  173. /* Set the space of the list of polynomials of "fold" to "space",
  174. * where the list of polynomials of "fold" may be missing
  175. * due to a preceding call to isl_qpolynomial_fold_take_list.
  176. * However, in this case, "fold" only has a single reference and
  177. * then the call to isl_qpolynomial_fold_cow has no effect.
  178. */
  179. static __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_restore_list(
  180. __isl_keep isl_qpolynomial_fold *fold,
  181. __isl_take isl_qpolynomial_list *list)
  182. {
  183. if (!fold || !list)
  184. goto error;
  185. if (fold->list == list) {
  186. isl_qpolynomial_list_free(list);
  187. return fold;
  188. }
  189. fold = isl_qpolynomial_fold_cow(fold);
  190. if (!fold)
  191. goto error;
  192. isl_qpolynomial_list_free(fold->list);
  193. fold->list = list;
  194. return fold;
  195. error:
  196. isl_qpolynomial_fold_free(fold);
  197. isl_qpolynomial_list_free(list);
  198. return NULL;
  199. }
  200. /* isl_qpolynomial_list_map callback that calls
  201. * isl_qpolynomial_reset_domain_space on "qp".
  202. */
  203. static __isl_give isl_qpolynomial *reset_domain_space(
  204. __isl_take isl_qpolynomial *qp, void *user)
  205. {
  206. isl_space *space = user;
  207. return isl_qpolynomial_reset_domain_space(qp, isl_space_copy(space));
  208. }
  209. /* Replace the domain space of "fold" by "space".
  210. *
  211. * Replace the domain space itself and that of all polynomials
  212. * in the list.
  213. */
  214. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space(
  215. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space)
  216. {
  217. isl_qpolynomial_list *list;
  218. list = isl_qpolynomial_fold_take_list(fold);
  219. list = isl_qpolynomial_list_map(list, &reset_domain_space, space);
  220. fold = isl_qpolynomial_fold_restore_list(fold, list);
  221. isl_space_free(isl_qpolynomial_fold_take_domain_space(fold));
  222. fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
  223. return fold;
  224. }
  225. /* Reset the space of "fold". This function is called from isl_pw_templ.c
  226. * and doesn't know if the space of an element object is represented
  227. * directly or through its domain. It therefore passes along both.
  228. */
  229. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_space_and_domain(
  230. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space,
  231. __isl_take isl_space *domain)
  232. {
  233. isl_space_free(space);
  234. return isl_qpolynomial_fold_reset_domain_space(fold, domain);
  235. }
  236. /* Internal data structure for isl_qpolynomial_fold_*_dims
  237. * representing their arguments.
  238. */
  239. struct isl_fold_dims_data {
  240. enum isl_dim_type type;
  241. unsigned first;
  242. unsigned n;
  243. };
  244. /* isl_qpolynomial_list_every callback that checks whether "qp"
  245. * does not involve any dimensions in the given range.
  246. */
  247. static isl_bool not_involved(__isl_keep isl_qpolynomial *qp, void *user)
  248. {
  249. struct isl_fold_dims_data *data = user;
  250. isl_bool involves;
  251. involves = isl_qpolynomial_involves_dims(qp, data->type,
  252. data->first, data->n);
  253. return isl_bool_not(involves);
  254. }
  255. /* Does "fold" involve any dimensions in the given range.
  256. *
  257. * It involves any of those dimensions if it is not the case
  258. * that every polynomial in the reduction does not involve
  259. * any of the dimensions.
  260. */
  261. static isl_bool isl_qpolynomial_fold_involves_dims(
  262. __isl_keep isl_qpolynomial_fold *fold,
  263. enum isl_dim_type type, unsigned first, unsigned n)
  264. {
  265. struct isl_fold_dims_data data = { type, first, n };
  266. isl_qpolynomial_list *list;
  267. isl_bool not;
  268. if (!fold)
  269. return isl_bool_error;
  270. if (n == 0)
  271. return isl_bool_false;
  272. list = isl_qpolynomial_fold_peek_list(fold);
  273. not = isl_qpolynomial_list_every(list, &not_involved, &data);
  274. return isl_bool_not(not);
  275. }
  276. /* Internal data structure for isl_qpolynomial_fold_set_dim_name
  277. * representing its arguments.
  278. */
  279. struct isl_fold_set_dim_name_data {
  280. enum isl_dim_type type;
  281. unsigned pos;
  282. const char *s;
  283. };
  284. /* isl_qpolynomial_list_map callback for calling
  285. * isl_qpolynomial_set_dim_name on "qp".
  286. */
  287. static __isl_give isl_qpolynomial *set_dim_name(__isl_take isl_qpolynomial *qp,
  288. void *user)
  289. {
  290. struct isl_fold_set_dim_name_data *data = user;
  291. qp = isl_qpolynomial_set_dim_name(qp, data->type, data->pos, data->s);
  292. return qp;
  293. }
  294. /* Given a dimension type for an isl_qpolynomial_fold,
  295. * return the corresponding type for the domain.
  296. */
  297. static enum isl_dim_type domain_type(enum isl_dim_type type)
  298. {
  299. if (type == isl_dim_in)
  300. return isl_dim_set;
  301. return type;
  302. }
  303. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_set_dim_name(
  304. __isl_take isl_qpolynomial_fold *fold,
  305. enum isl_dim_type type, unsigned pos, const char *s)
  306. {
  307. struct isl_fold_set_dim_name_data data = { type, pos, s };
  308. enum isl_dim_type set_type;
  309. isl_space *space;
  310. isl_qpolynomial_list *list;
  311. list = isl_qpolynomial_fold_take_list(fold);
  312. list = isl_qpolynomial_list_map(list, &set_dim_name, &data);
  313. fold = isl_qpolynomial_fold_restore_list(fold, list);
  314. set_type = domain_type(type);
  315. space = isl_qpolynomial_fold_take_domain_space(fold);
  316. space = isl_space_set_dim_name(space, set_type, pos, s);
  317. fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
  318. return fold;
  319. }
  320. /* isl_qpolynomial_list_map callback for calling
  321. * isl_qpolynomial_drop_dims on "qp".
  322. */
  323. static __isl_give isl_qpolynomial *drop_dims(__isl_take isl_qpolynomial *qp,
  324. void *user)
  325. {
  326. struct isl_fold_dims_data *data = user;
  327. qp = isl_qpolynomial_drop_dims(qp, data->type, data->first, data->n);
  328. return qp;
  329. }
  330. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_drop_dims(
  331. __isl_take isl_qpolynomial_fold *fold,
  332. enum isl_dim_type type, unsigned first, unsigned n)
  333. {
  334. struct isl_fold_dims_data data = { type, first, n };
  335. enum isl_dim_type set_type;
  336. isl_space *space;
  337. isl_qpolynomial_list *list;
  338. if (!fold)
  339. return NULL;
  340. if (n == 0)
  341. return fold;
  342. set_type = domain_type(type);
  343. list = isl_qpolynomial_fold_take_list(fold);
  344. list = isl_qpolynomial_list_map(list, &drop_dims, &data);
  345. fold = isl_qpolynomial_fold_restore_list(fold, list);
  346. space = isl_qpolynomial_fold_take_domain_space(fold);
  347. space = isl_space_drop_dims(space, set_type, first, n);
  348. fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
  349. return fold;
  350. }
  351. /* isl_qpolynomial_list_map callback for calling
  352. * isl_qpolynomial_insert_dims on "qp".
  353. */
  354. static __isl_give isl_qpolynomial *insert_dims(__isl_take isl_qpolynomial *qp,
  355. void *user)
  356. {
  357. struct isl_fold_dims_data *data = user;
  358. qp = isl_qpolynomial_insert_dims(qp, data->type, data->first, data->n);
  359. return qp;
  360. }
  361. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_insert_dims(
  362. __isl_take isl_qpolynomial_fold *fold,
  363. enum isl_dim_type type, unsigned first, unsigned n)
  364. {
  365. struct isl_fold_dims_data data = { type, first, n };
  366. enum isl_dim_type set_type;
  367. isl_space *space;
  368. isl_qpolynomial_list *list;
  369. if (!fold)
  370. return NULL;
  371. if (n == 0 && !isl_space_is_named_or_nested(fold->dim, type))
  372. return fold;
  373. list = isl_qpolynomial_fold_take_list(fold);
  374. list = isl_qpolynomial_list_map(list, &insert_dims, &data);
  375. fold = isl_qpolynomial_fold_restore_list(fold, list);
  376. set_type = domain_type(type);
  377. space = isl_qpolynomial_fold_take_domain_space(fold);
  378. space = isl_space_insert_dims(space, set_type, first, n);
  379. fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
  380. return fold;
  381. }
  382. /* Determine the sign of the constant quasipolynomial "qp".
  383. *
  384. * Return
  385. * -1 if qp <= 0
  386. * 1 if qp >= 0
  387. * 0 if unknown
  388. *
  389. * For qp == 0, we can return either -1 or 1. In practice, we return 1.
  390. * For qp == NaN, the sign is undefined, so we return 0.
  391. */
  392. static int isl_qpolynomial_cst_sign(__isl_keep isl_qpolynomial *qp)
  393. {
  394. isl_poly_cst *cst;
  395. if (isl_qpolynomial_is_nan(qp))
  396. return 0;
  397. cst = isl_poly_as_cst(qp->poly);
  398. if (!cst)
  399. return 0;
  400. return isl_int_sgn(cst->n) < 0 ? -1 : 1;
  401. }
  402. static int isl_qpolynomial_aff_sign(__isl_keep isl_set *set,
  403. __isl_keep isl_qpolynomial *qp)
  404. {
  405. enum isl_lp_result res;
  406. isl_vec *aff;
  407. isl_int opt;
  408. int sgn = 0;
  409. aff = isl_qpolynomial_extract_affine(qp);
  410. if (!aff)
  411. return 0;
  412. isl_int_init(opt);
  413. res = isl_set_solve_lp(set, 0, aff->el + 1, aff->el[0],
  414. &opt, NULL, NULL);
  415. if (res == isl_lp_error)
  416. goto done;
  417. if (res == isl_lp_empty ||
  418. (res == isl_lp_ok && !isl_int_is_neg(opt))) {
  419. sgn = 1;
  420. goto done;
  421. }
  422. res = isl_set_solve_lp(set, 1, aff->el + 1, aff->el[0],
  423. &opt, NULL, NULL);
  424. if (res == isl_lp_ok && !isl_int_is_pos(opt))
  425. sgn = -1;
  426. done:
  427. isl_int_clear(opt);
  428. isl_vec_free(aff);
  429. return sgn;
  430. }
  431. /* Determine, if possible, the sign of the quasipolynomial "qp" on
  432. * the domain "set".
  433. *
  434. * If qp is a constant, then the problem is trivial.
  435. * If qp is linear, then we check if the minimum of the corresponding
  436. * affine constraint is non-negative or if the maximum is non-positive.
  437. *
  438. * Otherwise, we check if the outermost variable "v" has a lower bound "l"
  439. * in "set". If so, we write qp(v,v') as
  440. *
  441. * q(v,v') * (v - l) + r(v')
  442. *
  443. * if q(v,v') and r(v') have the same known sign, then the original
  444. * quasipolynomial has the same sign as well.
  445. *
  446. * Return
  447. * -1 if qp <= 0
  448. * 1 if qp >= 0
  449. * 0 if unknown
  450. */
  451. static int isl_qpolynomial_sign(__isl_keep isl_set *set,
  452. __isl_keep isl_qpolynomial *qp)
  453. {
  454. isl_size d;
  455. int i;
  456. isl_bool is;
  457. isl_poly_rec *rec;
  458. isl_vec *v;
  459. isl_int l;
  460. enum isl_lp_result res;
  461. int sgn = 0;
  462. is = isl_qpolynomial_is_cst(qp, NULL, NULL);
  463. if (is < 0)
  464. return 0;
  465. if (is)
  466. return isl_qpolynomial_cst_sign(qp);
  467. is = isl_qpolynomial_is_affine(qp);
  468. if (is < 0)
  469. return 0;
  470. if (is)
  471. return isl_qpolynomial_aff_sign(set, qp);
  472. if (qp->div->n_row > 0)
  473. return 0;
  474. rec = isl_poly_as_rec(qp->poly);
  475. if (!rec)
  476. return 0;
  477. d = isl_space_dim(qp->dim, isl_dim_all);
  478. if (d < 0)
  479. return 0;
  480. v = isl_vec_alloc(set->ctx, 2 + d);
  481. if (!v)
  482. return 0;
  483. isl_seq_clr(v->el + 1, 1 + d);
  484. isl_int_set_si(v->el[0], 1);
  485. isl_int_set_si(v->el[2 + qp->poly->var], 1);
  486. isl_int_init(l);
  487. res = isl_set_solve_lp(set, 0, v->el + 1, v->el[0], &l, NULL, NULL);
  488. if (res == isl_lp_ok) {
  489. isl_qpolynomial *min;
  490. isl_qpolynomial *base;
  491. isl_qpolynomial *r, *q;
  492. isl_qpolynomial *t;
  493. min = isl_qpolynomial_cst_on_domain(isl_space_copy(qp->dim), l);
  494. base = isl_qpolynomial_var_pow_on_domain(isl_space_copy(qp->dim),
  495. qp->poly->var, 1);
  496. r = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0,
  497. isl_poly_copy(rec->p[rec->n - 1]));
  498. q = isl_qpolynomial_copy(r);
  499. for (i = rec->n - 2; i >= 0; --i) {
  500. r = isl_qpolynomial_mul(r, isl_qpolynomial_copy(min));
  501. t = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0,
  502. isl_poly_copy(rec->p[i]));
  503. r = isl_qpolynomial_add(r, t);
  504. if (i == 0)
  505. break;
  506. q = isl_qpolynomial_mul(q, isl_qpolynomial_copy(base));
  507. q = isl_qpolynomial_add(q, isl_qpolynomial_copy(r));
  508. }
  509. if (isl_qpolynomial_is_zero(q))
  510. sgn = isl_qpolynomial_sign(set, r);
  511. else if (isl_qpolynomial_is_zero(r))
  512. sgn = isl_qpolynomial_sign(set, q);
  513. else {
  514. int sgn_q, sgn_r;
  515. sgn_r = isl_qpolynomial_sign(set, r);
  516. sgn_q = isl_qpolynomial_sign(set, q);
  517. if (sgn_r == sgn_q)
  518. sgn = sgn_r;
  519. }
  520. isl_qpolynomial_free(min);
  521. isl_qpolynomial_free(base);
  522. isl_qpolynomial_free(q);
  523. isl_qpolynomial_free(r);
  524. }
  525. isl_int_clear(l);
  526. isl_vec_free(v);
  527. return sgn;
  528. }
  529. /* Check that "fold1" and "fold2" have the same type.
  530. */
  531. static isl_stat isl_qpolynomial_fold_check_equal_type(
  532. __isl_keep isl_qpolynomial_fold *fold1,
  533. __isl_keep isl_qpolynomial_fold *fold2)
  534. {
  535. enum isl_fold type1, type2;
  536. type1 = isl_qpolynomial_fold_get_type(fold1);
  537. type2 = isl_qpolynomial_fold_get_type(fold2);
  538. if (type1 < 0 || type2 < 0)
  539. return isl_stat_error;
  540. if (type1 != type2)
  541. isl_die(isl_qpolynomial_fold_get_ctx(fold1), isl_error_invalid,
  542. "fold types don't match", return isl_stat_error);
  543. return isl_stat_ok;
  544. }
  545. /* Check that "fold1" and "fold2" have the same (domain) space.
  546. */
  547. static isl_stat isl_qpolynomial_fold_check_equal_space(
  548. __isl_keep isl_qpolynomial_fold *fold1,
  549. __isl_keep isl_qpolynomial_fold *fold2)
  550. {
  551. isl_bool equal;
  552. isl_space *space1, *space2;
  553. space1 = isl_qpolynomial_fold_peek_domain_space(fold1);
  554. space2 = isl_qpolynomial_fold_peek_domain_space(fold2);
  555. equal = isl_space_is_equal(space1, space2);
  556. if (equal < 0)
  557. return isl_stat_error;
  558. if (!equal)
  559. isl_die(isl_qpolynomial_fold_get_ctx(fold1), isl_error_invalid,
  560. "spaces don't match", return isl_stat_error);
  561. return isl_stat_ok;
  562. }
  563. /* Combine "list1" and "list2" into a single list, eliminating
  564. * those elements of one list that are already covered by the other
  565. * list on "set".
  566. *
  567. * "better" is the sign that the difference qp1 - qp2 needs to have for qp1
  568. * to be covered by qp2.
  569. */
  570. static __isl_give isl_qpolynomial_list *merge_lists(__isl_keep isl_set *set,
  571. __isl_take isl_qpolynomial_list *list1,
  572. __isl_take isl_qpolynomial_list *list2, int better)
  573. {
  574. int i, j;
  575. isl_size n1, n2;
  576. n1 = isl_qpolynomial_list_size(list1);
  577. n2 = isl_qpolynomial_list_size(list2);
  578. if (n1 < 0 || n2 < 0)
  579. goto error;
  580. for (i = n2 - 1; i >= 0; --i) {
  581. for (j = n1 - 1; j >= 0; --j) {
  582. isl_qpolynomial *qp1, *qp2, *d;
  583. int sgn;
  584. isl_bool equal;
  585. qp1 = isl_qpolynomial_list_peek(list1, j);
  586. qp2 = isl_qpolynomial_list_peek(list2, i);
  587. equal = isl_qpolynomial_plain_is_equal(qp1, qp2);
  588. if (equal < 0)
  589. goto error;
  590. if (equal)
  591. break;
  592. d = isl_qpolynomial_sub(
  593. isl_qpolynomial_copy(qp1),
  594. isl_qpolynomial_copy(qp2));
  595. sgn = isl_qpolynomial_sign(set, d);
  596. isl_qpolynomial_free(d);
  597. if (sgn == 0)
  598. continue;
  599. if (sgn != better)
  600. break;
  601. list1 = isl_qpolynomial_list_drop(list1, j, 1);
  602. n1--;
  603. }
  604. if (j < 0)
  605. continue;
  606. list2 = isl_qpolynomial_list_drop(list2, i, 1);
  607. n2--;
  608. }
  609. return isl_qpolynomial_list_concat(list1, list2);
  610. error:
  611. isl_qpolynomial_list_free(list1);
  612. isl_qpolynomial_list_free(list2);
  613. return NULL;
  614. }
  615. /* Combine "fold1" and "fold2" into a single reduction, eliminating
  616. * those elements of one reduction that are already covered by the other
  617. * reduction on "set".
  618. *
  619. * If "fold1" or "fold2" is an empty reduction, then return
  620. * the other reduction.
  621. * If "fold1" or "fold2" is a NaN, then return this NaN.
  622. */
  623. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain(
  624. __isl_keep isl_set *set,
  625. __isl_take isl_qpolynomial_fold *fold1,
  626. __isl_take isl_qpolynomial_fold *fold2)
  627. {
  628. isl_qpolynomial_list *list1;
  629. isl_qpolynomial_list *list2;
  630. int better;
  631. if (isl_qpolynomial_fold_check_equal_type(fold1, fold2) < 0)
  632. goto error;
  633. if (isl_qpolynomial_fold_check_equal_space(fold1, fold2) < 0)
  634. goto error;
  635. better = fold1->type == isl_fold_max ? -1 : 1;
  636. if (isl_qpolynomial_fold_is_empty(fold1) ||
  637. isl_qpolynomial_fold_is_nan(fold2)) {
  638. isl_qpolynomial_fold_free(fold1);
  639. return fold2;
  640. }
  641. if (isl_qpolynomial_fold_is_empty(fold2) ||
  642. isl_qpolynomial_fold_is_nan(fold1)) {
  643. isl_qpolynomial_fold_free(fold2);
  644. return fold1;
  645. }
  646. list1 = isl_qpolynomial_fold_take_list(fold1);
  647. list2 = isl_qpolynomial_fold_take_list(fold2);
  648. list1 = merge_lists(set, list1, list2, better);
  649. fold1 = isl_qpolynomial_fold_restore_list(fold1, list1);
  650. isl_qpolynomial_fold_free(fold2);
  651. return fold1;
  652. error:
  653. isl_qpolynomial_fold_free(fold1);
  654. isl_qpolynomial_fold_free(fold2);
  655. return NULL;
  656. }
  657. /* isl_qpolynomial_list_map callback for adding "qp2" to "qp".
  658. */
  659. static __isl_give isl_qpolynomial *add_qpolynomial(
  660. __isl_take isl_qpolynomial *qp, void *user)
  661. {
  662. isl_qpolynomial *qp2 = user;
  663. return isl_qpolynomial_add(qp, isl_qpolynomial_copy(qp2));
  664. }
  665. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_qpolynomial(
  666. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_qpolynomial *qp)
  667. {
  668. isl_qpolynomial_list *list;
  669. if (!fold || !qp)
  670. goto error;
  671. if (isl_qpolynomial_is_zero(qp)) {
  672. isl_qpolynomial_free(qp);
  673. return fold;
  674. }
  675. list = isl_qpolynomial_fold_take_list(fold);
  676. list = isl_qpolynomial_list_map(list, &add_qpolynomial, qp);
  677. fold = isl_qpolynomial_fold_restore_list(fold, list);
  678. isl_qpolynomial_free(qp);
  679. return fold;
  680. error:
  681. isl_qpolynomial_fold_free(fold);
  682. isl_qpolynomial_free(qp);
  683. return NULL;
  684. }
  685. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain(
  686. __isl_keep isl_set *dom,
  687. __isl_take isl_qpolynomial_fold *fold1,
  688. __isl_take isl_qpolynomial_fold *fold2)
  689. {
  690. int i;
  691. isl_size n1, n2;
  692. isl_qpolynomial_fold *res = NULL;
  693. isl_qpolynomial *qp;
  694. isl_qpolynomial_list *list1, *list2;
  695. if (!fold1 || !fold2)
  696. goto error;
  697. if (isl_qpolynomial_fold_is_empty(fold1)) {
  698. isl_qpolynomial_fold_free(fold1);
  699. return fold2;
  700. }
  701. if (isl_qpolynomial_fold_is_empty(fold2)) {
  702. isl_qpolynomial_fold_free(fold2);
  703. return fold1;
  704. }
  705. list1 = isl_qpolynomial_fold_peek_list(fold1);
  706. list2 = isl_qpolynomial_fold_peek_list(fold2);
  707. n1 = isl_qpolynomial_list_size(list1);
  708. n2 = isl_qpolynomial_list_size(list2);
  709. if (n1 < 0 || n2 < 0)
  710. goto error;
  711. if (n1 == 1 && n2 != 1)
  712. return isl_qpolynomial_fold_add_on_domain(dom, fold2, fold1);
  713. qp = isl_qpolynomial_list_get_at(list2, 0);
  714. if (n2 == 1) {
  715. res = isl_qpolynomial_fold_add_qpolynomial(fold1, qp);
  716. isl_qpolynomial_fold_free(fold2);
  717. return res;
  718. }
  719. res = isl_qpolynomial_fold_add_qpolynomial(
  720. isl_qpolynomial_fold_copy(fold1), qp);
  721. for (i = 1; i < n2; ++i) {
  722. isl_qpolynomial_fold *res_i;
  723. qp = isl_qpolynomial_list_get_at(list2, i);
  724. res_i = isl_qpolynomial_fold_add_qpolynomial(
  725. isl_qpolynomial_fold_copy(fold1), qp);
  726. res = isl_qpolynomial_fold_fold_on_domain(dom, res, res_i);
  727. }
  728. isl_qpolynomial_fold_free(fold1);
  729. isl_qpolynomial_fold_free(fold2);
  730. return res;
  731. error:
  732. isl_qpolynomial_fold_free(res);
  733. isl_qpolynomial_fold_free(fold1);
  734. isl_qpolynomial_fold_free(fold2);
  735. return NULL;
  736. }
  737. /* isl_qpolynomial_list_map callback for calling
  738. * isl_qpolynomial_substitute_equalities on "qp" and "eq".
  739. */
  740. static __isl_give isl_qpolynomial *substitute_equalities(
  741. __isl_take isl_qpolynomial *qp, void *user)
  742. {
  743. isl_basic_set *eq = user;
  744. eq = isl_basic_set_copy(eq);
  745. return isl_qpolynomial_substitute_equalities(qp, eq);
  746. }
  747. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities(
  748. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq)
  749. {
  750. isl_qpolynomial_list *list;
  751. list = isl_qpolynomial_fold_take_list(fold);
  752. list = isl_qpolynomial_list_map(list, &substitute_equalities, eq);
  753. fold = isl_qpolynomial_fold_restore_list(fold, list);
  754. isl_basic_set_free(eq);
  755. return fold;
  756. }
  757. /* isl_qpolynomial_list_map callback for calling
  758. * isl_qpolynomial_substitute_equalities on "qp" and "context".
  759. */
  760. static __isl_give isl_qpolynomial *gist(__isl_take isl_qpolynomial *qp,
  761. void *user)
  762. {
  763. isl_set *context = user;
  764. return isl_qpolynomial_gist(qp, isl_set_copy(context));
  765. }
  766. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
  767. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
  768. {
  769. isl_qpolynomial_list *list;
  770. list = isl_qpolynomial_fold_take_list(fold);
  771. list = isl_qpolynomial_list_map(list, &gist, context);
  772. fold = isl_qpolynomial_fold_restore_list(fold, list);
  773. isl_set_free(context);
  774. return fold;
  775. }
  776. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params(
  777. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
  778. {
  779. isl_space *space = isl_qpolynomial_fold_get_domain_space(fold);
  780. isl_set *dom_context = isl_set_universe(space);
  781. dom_context = isl_set_intersect_params(dom_context, context);
  782. return isl_qpolynomial_fold_gist(fold, dom_context);
  783. }
  784. /* Return a zero (i.e., empty) isl_qpolynomial_fold in the given space.
  785. *
  786. * This is a helper function for isl_pw_*_as_* that ensures a uniform
  787. * interface over all piecewise types.
  788. */
  789. static __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_zero_in_space(
  790. __isl_take isl_space *space, enum isl_fold type)
  791. {
  792. return isl_qpolynomial_fold_empty(type, isl_space_domain(space));
  793. }
  794. #define isl_qpolynomial_fold_involves_nan isl_qpolynomial_fold_is_nan
  795. #define HAS_TYPE
  796. #undef PW
  797. #define PW isl_pw_qpolynomial_fold
  798. #undef BASE
  799. #define BASE qpolynomial_fold
  800. #undef EL_IS_ZERO
  801. #define EL_IS_ZERO is_empty
  802. #undef ZERO
  803. #define ZERO zero
  804. #undef IS_ZERO
  805. #define IS_ZERO is_zero
  806. #undef FIELD
  807. #define FIELD fold
  808. #undef DEFAULT_IS_ZERO
  809. #define DEFAULT_IS_ZERO 1
  810. #include <isl_pw_templ.c>
  811. #include <isl_pw_eval.c>
  812. #include <isl_pw_insert_dims_templ.c>
  813. #include <isl_pw_lift_templ.c>
  814. #include <isl_pw_morph_templ.c>
  815. #include <isl_pw_move_dims_templ.c>
  816. #include <isl_pw_opt_templ.c>
  817. #undef BASE
  818. #define BASE pw_qpolynomial_fold
  819. #define NO_SUB
  820. #include <isl_union_single.c>
  821. #include <isl_union_eval.c>
  822. /* Construct a new reduction of the given type and space
  823. * with an empty list of polynomials.
  824. */
  825. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type,
  826. __isl_take isl_space *space)
  827. {
  828. isl_ctx *ctx;
  829. isl_qpolynomial_list *list;
  830. if (!space)
  831. return NULL;
  832. ctx = isl_space_get_ctx(space);
  833. list = isl_qpolynomial_list_alloc(ctx, 0);
  834. return qpolynomial_fold_alloc(type, space, list);
  835. }
  836. /* Construct a new reduction of the given type and
  837. * a single given polynomial.
  838. */
  839. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_alloc(
  840. enum isl_fold type, __isl_take isl_qpolynomial *qp)
  841. {
  842. isl_space *space;
  843. isl_qpolynomial_list *list;
  844. space = isl_qpolynomial_get_domain_space(qp);
  845. list = isl_qpolynomial_list_from_qpolynomial(qp);
  846. return qpolynomial_fold_alloc(type, space, list);
  847. }
  848. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_copy(
  849. __isl_keep isl_qpolynomial_fold *fold)
  850. {
  851. if (!fold)
  852. return NULL;
  853. fold->ref++;
  854. return fold;
  855. }
  856. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup(
  857. __isl_keep isl_qpolynomial_fold *fold)
  858. {
  859. enum isl_fold type;
  860. isl_space *space;
  861. isl_qpolynomial_list *list;
  862. type = isl_qpolynomial_fold_get_type(fold);
  863. space = isl_qpolynomial_fold_get_domain_space(fold);
  864. list = isl_qpolynomial_fold_get_list(fold);
  865. return qpolynomial_fold_alloc(type, space, list);
  866. }
  867. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow(
  868. __isl_take isl_qpolynomial_fold *fold)
  869. {
  870. if (!fold)
  871. return NULL;
  872. if (fold->ref == 1)
  873. return fold;
  874. fold->ref--;
  875. return isl_qpolynomial_fold_dup(fold);
  876. }
  877. __isl_null isl_qpolynomial_fold *isl_qpolynomial_fold_free(
  878. __isl_take isl_qpolynomial_fold *fold)
  879. {
  880. if (!fold)
  881. return NULL;
  882. if (--fold->ref > 0)
  883. return NULL;
  884. isl_qpolynomial_list_free(fold->list);
  885. isl_space_free(fold->dim);
  886. free(fold);
  887. return NULL;
  888. }
  889. isl_bool isl_qpolynomial_fold_is_empty(__isl_keep isl_qpolynomial_fold *fold)
  890. {
  891. isl_size n;
  892. isl_qpolynomial_list *list;
  893. list = isl_qpolynomial_fold_peek_list(fold);
  894. n = isl_qpolynomial_list_size(list);
  895. if (n < 0)
  896. return isl_bool_error;
  897. return isl_bool_ok(n == 0);
  898. }
  899. /* Does "fold" represent max(NaN) or min(NaN)?
  900. */
  901. isl_bool isl_qpolynomial_fold_is_nan(__isl_keep isl_qpolynomial_fold *fold)
  902. {
  903. isl_size n;
  904. isl_qpolynomial *qp;
  905. isl_qpolynomial_list *list;
  906. list = isl_qpolynomial_fold_peek_list(fold);
  907. n = isl_qpolynomial_list_size(list);
  908. if (n < 0)
  909. return isl_bool_error;
  910. if (n != 1)
  911. return isl_bool_false;
  912. qp = isl_qpolynomial_list_peek(list, 0);
  913. return isl_qpolynomial_is_nan(qp);
  914. }
  915. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold(
  916. __isl_take isl_qpolynomial_fold *fold1,
  917. __isl_take isl_qpolynomial_fold *fold2)
  918. {
  919. isl_qpolynomial_list *list1, *list2;
  920. if (isl_qpolynomial_fold_check_equal_type(fold1, fold2) < 0)
  921. goto error;
  922. if (isl_qpolynomial_fold_check_equal_space(fold1, fold2) < 0)
  923. goto error;
  924. if (isl_qpolynomial_fold_is_empty(fold1)) {
  925. isl_qpolynomial_fold_free(fold1);
  926. return fold2;
  927. }
  928. if (isl_qpolynomial_fold_is_empty(fold2)) {
  929. isl_qpolynomial_fold_free(fold2);
  930. return fold1;
  931. }
  932. list1 = isl_qpolynomial_fold_take_list(fold1);
  933. list2 = isl_qpolynomial_fold_take_list(fold2);
  934. list1 = isl_qpolynomial_list_concat(list1, list2);
  935. fold1 = isl_qpolynomial_fold_restore_list(fold1, list1);
  936. isl_qpolynomial_fold_free(fold2);
  937. return fold1;
  938. error:
  939. isl_qpolynomial_fold_free(fold1);
  940. isl_qpolynomial_fold_free(fold2);
  941. return NULL;
  942. }
  943. __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold(
  944. __isl_take isl_pw_qpolynomial_fold *pw1,
  945. __isl_take isl_pw_qpolynomial_fold *pw2)
  946. {
  947. int i, j, n;
  948. struct isl_pw_qpolynomial_fold *res;
  949. isl_set *set;
  950. if (!pw1 || !pw2)
  951. goto error;
  952. isl_assert(pw1->dim->ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
  953. if (isl_pw_qpolynomial_fold_is_zero(pw1)) {
  954. isl_pw_qpolynomial_fold_free(pw1);
  955. return pw2;
  956. }
  957. if (isl_pw_qpolynomial_fold_is_zero(pw2)) {
  958. isl_pw_qpolynomial_fold_free(pw2);
  959. return pw1;
  960. }
  961. if (pw1->type != pw2->type)
  962. isl_die(pw1->dim->ctx, isl_error_invalid,
  963. "fold types don't match", goto error);
  964. n = (pw1->n + 1) * (pw2->n + 1);
  965. res = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pw1->dim),
  966. pw1->type, n);
  967. for (i = 0; i < pw1->n; ++i) {
  968. set = isl_set_copy(pw1->p[i].set);
  969. for (j = 0; j < pw2->n; ++j) {
  970. struct isl_set *common;
  971. isl_qpolynomial_fold *sum;
  972. set = isl_set_subtract(set,
  973. isl_set_copy(pw2->p[j].set));
  974. common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
  975. isl_set_copy(pw2->p[j].set));
  976. if (isl_set_plain_is_empty(common)) {
  977. isl_set_free(common);
  978. continue;
  979. }
  980. sum = isl_qpolynomial_fold_fold_on_domain(common,
  981. isl_qpolynomial_fold_copy(pw1->p[i].fold),
  982. isl_qpolynomial_fold_copy(pw2->p[j].fold));
  983. res = isl_pw_qpolynomial_fold_add_piece(res, common, sum);
  984. }
  985. res = isl_pw_qpolynomial_fold_add_piece(res, set,
  986. isl_qpolynomial_fold_copy(pw1->p[i].fold));
  987. }
  988. for (j = 0; j < pw2->n; ++j) {
  989. set = isl_set_copy(pw2->p[j].set);
  990. for (i = 0; i < pw1->n; ++i)
  991. set = isl_set_subtract(set, isl_set_copy(pw1->p[i].set));
  992. res = isl_pw_qpolynomial_fold_add_piece(res, set,
  993. isl_qpolynomial_fold_copy(pw2->p[j].fold));
  994. }
  995. isl_pw_qpolynomial_fold_free(pw1);
  996. isl_pw_qpolynomial_fold_free(pw2);
  997. return res;
  998. error:
  999. isl_pw_qpolynomial_fold_free(pw1);
  1000. isl_pw_qpolynomial_fold_free(pw2);
  1001. return NULL;
  1002. }
  1003. __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
  1004. __isl_take isl_union_pw_qpolynomial_fold *u,
  1005. __isl_take isl_pw_qpolynomial_fold *part)
  1006. {
  1007. struct isl_hash_table_entry *entry;
  1008. u = isl_union_pw_qpolynomial_fold_cow(u);
  1009. if (!part || !u)
  1010. goto error;
  1011. if (isl_space_check_equal_params(part->dim, u->space) < 0)
  1012. goto error;
  1013. entry = isl_union_pw_qpolynomial_fold_find_part_entry(u, part->dim, 1);
  1014. if (!entry)
  1015. goto error;
  1016. if (!entry->data)
  1017. entry->data = part;
  1018. else {
  1019. entry->data = isl_pw_qpolynomial_fold_fold(entry->data,
  1020. isl_pw_qpolynomial_fold_copy(part));
  1021. if (!entry->data)
  1022. goto error;
  1023. isl_pw_qpolynomial_fold_free(part);
  1024. }
  1025. return u;
  1026. error:
  1027. isl_pw_qpolynomial_fold_free(part);
  1028. isl_union_pw_qpolynomial_fold_free(u);
  1029. return NULL;
  1030. }
  1031. static isl_stat fold_part(__isl_take isl_pw_qpolynomial_fold *part, void *user)
  1032. {
  1033. isl_union_pw_qpolynomial_fold **u;
  1034. u = (isl_union_pw_qpolynomial_fold **)user;
  1035. *u = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(*u, part);
  1036. return isl_stat_ok;
  1037. }
  1038. __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold(
  1039. __isl_take isl_union_pw_qpolynomial_fold *u1,
  1040. __isl_take isl_union_pw_qpolynomial_fold *u2)
  1041. {
  1042. u1 = isl_union_pw_qpolynomial_fold_cow(u1);
  1043. if (!u1 || !u2)
  1044. goto error;
  1045. if (isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(u2,
  1046. &fold_part, &u1) < 0)
  1047. goto error;
  1048. isl_union_pw_qpolynomial_fold_free(u2);
  1049. return u1;
  1050. error:
  1051. isl_union_pw_qpolynomial_fold_free(u1);
  1052. isl_union_pw_qpolynomial_fold_free(u2);
  1053. return NULL;
  1054. }
  1055. __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial(
  1056. enum isl_fold type, __isl_take isl_pw_qpolynomial *pwqp)
  1057. {
  1058. int i;
  1059. isl_pw_qpolynomial_fold *pwf;
  1060. if (!pwqp)
  1061. return NULL;
  1062. pwf = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pwqp->dim),
  1063. type, pwqp->n);
  1064. for (i = 0; i < pwqp->n; ++i)
  1065. pwf = isl_pw_qpolynomial_fold_add_piece(pwf,
  1066. isl_set_copy(pwqp->p[i].set),
  1067. isl_qpolynomial_fold_alloc(type,
  1068. isl_qpolynomial_copy(pwqp->p[i].qp)));
  1069. isl_pw_qpolynomial_free(pwqp);
  1070. return pwf;
  1071. }
  1072. __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add(
  1073. __isl_take isl_pw_qpolynomial_fold *pwf1,
  1074. __isl_take isl_pw_qpolynomial_fold *pwf2)
  1075. {
  1076. return isl_pw_qpolynomial_fold_union_add_(pwf1, pwf2);
  1077. }
  1078. /* Compare two quasi-polynomial reductions.
  1079. *
  1080. * Return -1 if "fold1" is "smaller" than "fold2", 1 if "fold1" is "greater"
  1081. * than "fold2" and 0 if they are equal.
  1082. */
  1083. int isl_qpolynomial_fold_plain_cmp(__isl_keep isl_qpolynomial_fold *fold1,
  1084. __isl_keep isl_qpolynomial_fold *fold2)
  1085. {
  1086. int i;
  1087. isl_size n1, n2;
  1088. isl_qpolynomial_list *list1, *list2;
  1089. if (fold1 == fold2)
  1090. return 0;
  1091. list1 = isl_qpolynomial_fold_peek_list(fold1);
  1092. list2 = isl_qpolynomial_fold_peek_list(fold2);
  1093. n1 = isl_qpolynomial_list_size(list1);
  1094. n2 = isl_qpolynomial_list_size(list2);
  1095. if (n1 < 0)
  1096. return -1;
  1097. if (n2 < 0)
  1098. return 1;
  1099. if (n1 != n2)
  1100. return n1 - n2;
  1101. for (i = 0; i < n1; ++i) {
  1102. int cmp;
  1103. isl_qpolynomial *qp1, *qp2;
  1104. qp1 = isl_qpolynomial_list_peek(list1, i);
  1105. qp2 = isl_qpolynomial_list_peek(list2, i);
  1106. cmp = isl_qpolynomial_plain_cmp(qp1, qp2);
  1107. if (cmp != 0)
  1108. return cmp;
  1109. }
  1110. return 0;
  1111. }
  1112. /* Are the lists "list1" and "list2", both consisting of "n" elements
  1113. * obviously equal to each other?
  1114. */
  1115. static isl_bool isl_qpolynomial_list_plain_is_equal(unsigned n,
  1116. isl_qpolynomial_list *list1, isl_qpolynomial_list *list2)
  1117. {
  1118. int i;
  1119. for (i = 0; i < n; ++i) {
  1120. isl_bool eq;
  1121. isl_qpolynomial *qp1, *qp2;
  1122. qp1 = isl_qpolynomial_list_peek(list1, i);
  1123. qp2 = isl_qpolynomial_list_peek(list2, i);
  1124. eq = isl_qpolynomial_plain_is_equal(qp1, qp2);
  1125. if (eq < 0 || !eq)
  1126. return eq;
  1127. }
  1128. return isl_bool_true;
  1129. }
  1130. /* Wrapper around isl_qpolynomial_plain_cmp for use
  1131. * as a isl_qpolynomial_list_sort callback.
  1132. */
  1133. static int qpolynomial_cmp(__isl_keep isl_qpolynomial *a,
  1134. __isl_keep isl_qpolynomial *b, void *user)
  1135. {
  1136. return isl_qpolynomial_plain_cmp(a, b);
  1137. }
  1138. isl_bool isl_qpolynomial_fold_plain_is_equal(
  1139. __isl_keep isl_qpolynomial_fold *fold1,
  1140. __isl_keep isl_qpolynomial_fold *fold2)
  1141. {
  1142. isl_bool equal;
  1143. isl_size n1, n2;
  1144. isl_qpolynomial_list *list1, *list2;
  1145. list1 = isl_qpolynomial_fold_peek_list(fold1);
  1146. list2 = isl_qpolynomial_fold_peek_list(fold2);
  1147. n1 = isl_qpolynomial_list_size(list1);
  1148. n2 = isl_qpolynomial_list_size(list2);
  1149. if (n1 < 0 || n2 < 0)
  1150. return isl_bool_error;
  1151. if (n1 != n2)
  1152. return isl_bool_false;
  1153. list1 = isl_qpolynomial_list_copy(list1);
  1154. list1 = isl_qpolynomial_list_sort(list1, &qpolynomial_cmp, NULL);
  1155. list2 = isl_qpolynomial_list_copy(list2);
  1156. list2 = isl_qpolynomial_list_sort(list2, &qpolynomial_cmp, NULL);
  1157. equal = isl_qpolynomial_list_plain_is_equal(n1, list1, list2);
  1158. isl_qpolynomial_list_free(list1);
  1159. isl_qpolynomial_list_free(list2);
  1160. return equal;
  1161. }
  1162. __isl_give isl_val *isl_qpolynomial_fold_eval(
  1163. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_point *pnt)
  1164. {
  1165. isl_size n;
  1166. isl_ctx *ctx;
  1167. isl_val *v;
  1168. isl_qpolynomial *qp;
  1169. isl_qpolynomial_list *list;
  1170. if (!fold || !pnt)
  1171. goto error;
  1172. ctx = isl_point_get_ctx(pnt);
  1173. isl_assert(pnt->dim->ctx, isl_space_is_equal(pnt->dim, fold->dim), goto error);
  1174. isl_assert(pnt->dim->ctx,
  1175. fold->type == isl_fold_max || fold->type == isl_fold_min,
  1176. goto error);
  1177. list = isl_qpolynomial_fold_peek_list(fold);
  1178. n = isl_qpolynomial_list_size(list);
  1179. if (n < 0)
  1180. goto error;
  1181. if (n == 0)
  1182. v = isl_val_zero(ctx);
  1183. else {
  1184. int i;
  1185. qp = isl_qpolynomial_list_get_at(list, 0);
  1186. v = isl_qpolynomial_eval(qp, isl_point_copy(pnt));
  1187. for (i = 1; i < n; ++i) {
  1188. isl_val *v_i;
  1189. qp = isl_qpolynomial_list_get_at(list, i);
  1190. v_i = isl_qpolynomial_eval(qp, isl_point_copy(pnt));
  1191. if (fold->type == isl_fold_max)
  1192. v = isl_val_max(v, v_i);
  1193. else
  1194. v = isl_val_min(v, v_i);
  1195. }
  1196. }
  1197. isl_qpolynomial_fold_free(fold);
  1198. isl_point_free(pnt);
  1199. return v;
  1200. error:
  1201. isl_qpolynomial_fold_free(fold);
  1202. isl_point_free(pnt);
  1203. return NULL;
  1204. }
  1205. size_t isl_pw_qpolynomial_fold_size(__isl_keep isl_pw_qpolynomial_fold *pwf)
  1206. {
  1207. int i;
  1208. size_t n = 0;
  1209. for (i = 0; i < pwf->n; ++i) {
  1210. isl_size n_i;
  1211. isl_qpolynomial_list *list;
  1212. list = isl_qpolynomial_fold_peek_list(pwf->p[i].fold);
  1213. n_i = isl_qpolynomial_list_size(list);
  1214. if (n_i < 0)
  1215. return isl_size_error;
  1216. n += n_i;
  1217. }
  1218. return n;
  1219. }
  1220. __isl_give isl_val *isl_qpolynomial_fold_opt_on_domain(
  1221. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *set, int max)
  1222. {
  1223. int i;
  1224. isl_size n;
  1225. isl_val *opt;
  1226. isl_qpolynomial *qp;
  1227. isl_qpolynomial_list *list;
  1228. list = isl_qpolynomial_fold_peek_list(fold);
  1229. n = isl_qpolynomial_list_size(list);
  1230. if (!set || n < 0)
  1231. goto error;
  1232. if (n == 0) {
  1233. opt = isl_val_zero(isl_set_get_ctx(set));
  1234. isl_set_free(set);
  1235. isl_qpolynomial_fold_free(fold);
  1236. return opt;
  1237. }
  1238. qp = isl_qpolynomial_list_get_at(list, 0);
  1239. opt = isl_qpolynomial_opt_on_domain(qp, isl_set_copy(set), max);
  1240. for (i = 1; i < n; ++i) {
  1241. isl_val *opt_i;
  1242. qp = isl_qpolynomial_list_get_at(list, i);
  1243. opt_i = isl_qpolynomial_opt_on_domain(qp,
  1244. isl_set_copy(set), max);
  1245. if (max)
  1246. opt = isl_val_max(opt, opt_i);
  1247. else
  1248. opt = isl_val_min(opt, opt_i);
  1249. }
  1250. isl_set_free(set);
  1251. isl_qpolynomial_fold_free(fold);
  1252. return opt;
  1253. error:
  1254. isl_set_free(set);
  1255. isl_qpolynomial_fold_free(fold);
  1256. return NULL;
  1257. }
  1258. /* Check whether for each quasi-polynomial in "fold2" there is
  1259. * a quasi-polynomial in "fold1" that dominates it on "set".
  1260. */
  1261. static isl_bool qpolynomial_fold_covers_on_domain(__isl_keep isl_set *set,
  1262. __isl_keep isl_qpolynomial_fold *fold1,
  1263. __isl_keep isl_qpolynomial_fold *fold2)
  1264. {
  1265. int i, j;
  1266. int covers;
  1267. isl_size n1, n2;
  1268. isl_qpolynomial_list *list1, *list2;
  1269. list1 = isl_qpolynomial_fold_peek_list(fold1);
  1270. list2 = isl_qpolynomial_fold_peek_list(fold2);
  1271. n1 = isl_qpolynomial_list_size(list1);
  1272. n2 = isl_qpolynomial_list_size(list2);
  1273. if (!set || n1 < 0 || n2 < 0)
  1274. return isl_bool_error;
  1275. covers = fold1->type == isl_fold_max ? 1 : -1;
  1276. for (i = 0; i < n2; ++i) {
  1277. for (j = 0; j < n1; ++j) {
  1278. isl_qpolynomial *qp1, *qp2, *d;
  1279. int sgn;
  1280. qp1 = isl_qpolynomial_list_get_at(list1, j);
  1281. qp2 = isl_qpolynomial_list_get_at(list2, i);
  1282. d = isl_qpolynomial_sub(qp1, qp2);
  1283. sgn = isl_qpolynomial_sign(set, d);
  1284. isl_qpolynomial_free(d);
  1285. if (sgn == covers)
  1286. break;
  1287. }
  1288. if (j >= n1)
  1289. return isl_bool_false;
  1290. }
  1291. return isl_bool_true;
  1292. }
  1293. /* Check whether "pwf1" dominated "pwf2", i.e., the domain of "pwf1" contains
  1294. * that of "pwf2" and on each cell, the corresponding fold from pwf1 dominates
  1295. * that of pwf2.
  1296. */
  1297. isl_bool isl_pw_qpolynomial_fold_covers(
  1298. __isl_keep isl_pw_qpolynomial_fold *pwf1,
  1299. __isl_keep isl_pw_qpolynomial_fold *pwf2)
  1300. {
  1301. int i, j;
  1302. isl_set *dom1, *dom2;
  1303. isl_bool is_subset;
  1304. if (!pwf1 || !pwf2)
  1305. return isl_bool_error;
  1306. if (pwf2->n == 0)
  1307. return isl_bool_true;
  1308. if (pwf1->n == 0)
  1309. return isl_bool_false;
  1310. dom1 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf1));
  1311. dom2 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf2));
  1312. is_subset = isl_set_is_subset(dom2, dom1);
  1313. isl_set_free(dom1);
  1314. isl_set_free(dom2);
  1315. if (is_subset < 0 || !is_subset)
  1316. return is_subset;
  1317. for (i = 0; i < pwf2->n; ++i) {
  1318. for (j = 0; j < pwf1->n; ++j) {
  1319. isl_bool is_empty;
  1320. isl_set *common;
  1321. isl_bool covers;
  1322. common = isl_set_intersect(isl_set_copy(pwf1->p[j].set),
  1323. isl_set_copy(pwf2->p[i].set));
  1324. is_empty = isl_set_is_empty(common);
  1325. if (is_empty < 0 || is_empty) {
  1326. isl_set_free(common);
  1327. if (is_empty < 0)
  1328. return isl_bool_error;
  1329. continue;
  1330. }
  1331. covers = qpolynomial_fold_covers_on_domain(common,
  1332. pwf1->p[j].fold, pwf2->p[i].fold);
  1333. isl_set_free(common);
  1334. if (covers < 0 || !covers)
  1335. return covers;
  1336. }
  1337. }
  1338. return isl_bool_true;
  1339. }
  1340. /* isl_qpolynomial_list_map callback that calls
  1341. * isl_qpolynomial_morph_domain on "qp".
  1342. */
  1343. static __isl_give isl_qpolynomial *morph_domain(
  1344. __isl_take isl_qpolynomial *qp, void *user)
  1345. {
  1346. isl_morph *morph = user;
  1347. return isl_qpolynomial_morph_domain(qp, isl_morph_copy(morph));
  1348. }
  1349. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain(
  1350. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph)
  1351. {
  1352. isl_space *space;
  1353. isl_qpolynomial_list *list;
  1354. space = isl_qpolynomial_fold_peek_domain_space(fold);
  1355. if (isl_morph_check_applies(morph, space) < 0)
  1356. goto error;
  1357. list = isl_qpolynomial_fold_take_list(fold);
  1358. list = isl_qpolynomial_list_map(list, &morph_domain, morph);
  1359. fold = isl_qpolynomial_fold_restore_list(fold, list);
  1360. space = isl_morph_get_ran_space(morph);
  1361. isl_space_free(isl_qpolynomial_fold_take_domain_space(fold));
  1362. fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
  1363. isl_morph_free(morph);
  1364. return fold;
  1365. error:
  1366. isl_qpolynomial_fold_free(fold);
  1367. isl_morph_free(morph);
  1368. return NULL;
  1369. }
  1370. enum isl_fold isl_qpolynomial_fold_get_type(__isl_keep isl_qpolynomial_fold *fold)
  1371. {
  1372. if (!fold)
  1373. return isl_fold_error;
  1374. return fold->type;
  1375. }
  1376. /* Return the type of this piecewise quasipolynomial reduction.
  1377. */
  1378. enum isl_fold isl_pw_qpolynomial_fold_get_type(
  1379. __isl_keep isl_pw_qpolynomial_fold *pwf)
  1380. {
  1381. if (!pwf)
  1382. return isl_fold_error;
  1383. return pwf->type;
  1384. }
  1385. enum isl_fold isl_union_pw_qpolynomial_fold_get_type(
  1386. __isl_keep isl_union_pw_qpolynomial_fold *upwf)
  1387. {
  1388. if (!upwf)
  1389. return isl_fold_error;
  1390. return upwf->type;
  1391. }
  1392. /* isl_qpolynomial_list_map callback that calls
  1393. * isl_qpolynomial_lift on "qp".
  1394. */
  1395. static __isl_give isl_qpolynomial *lift(__isl_take isl_qpolynomial *qp,
  1396. void *user)
  1397. {
  1398. isl_space *space = user;
  1399. return isl_qpolynomial_lift(qp, isl_space_copy(space));
  1400. }
  1401. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift(
  1402. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space)
  1403. {
  1404. isl_qpolynomial_list *list;
  1405. if (!fold || !space)
  1406. goto error;
  1407. if (isl_space_is_equal(fold->dim, space)) {
  1408. isl_space_free(space);
  1409. return fold;
  1410. }
  1411. list = isl_qpolynomial_fold_take_list(fold);
  1412. list = isl_qpolynomial_list_map(list, &lift, space);
  1413. fold = isl_qpolynomial_fold_restore_list(fold, list);
  1414. isl_space_free(isl_qpolynomial_fold_take_domain_space(fold));
  1415. fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
  1416. return fold;
  1417. error:
  1418. isl_qpolynomial_fold_free(fold);
  1419. isl_space_free(space);
  1420. return NULL;
  1421. }
  1422. isl_stat isl_qpolynomial_fold_foreach_qpolynomial(
  1423. __isl_keep isl_qpolynomial_fold *fold,
  1424. isl_stat (*fn)(__isl_take isl_qpolynomial *qp, void *user), void *user)
  1425. {
  1426. isl_qpolynomial_list *list;
  1427. list = isl_qpolynomial_fold_peek_list(fold);
  1428. return isl_qpolynomial_list_foreach(list, fn, user);
  1429. }
  1430. /* Internal data structure for isl_qpolynomial_fold_move_dims
  1431. * representing its arguments.
  1432. */
  1433. struct isl_fold_move_dims_data {
  1434. enum isl_dim_type dst_type;
  1435. unsigned dst_pos;
  1436. enum isl_dim_type src_type;
  1437. unsigned src_pos;
  1438. unsigned n;
  1439. };
  1440. /* isl_qpolynomial_list_map callback for calling
  1441. * isl_qpolynomial_move_dims on "qp".
  1442. */
  1443. static __isl_give isl_qpolynomial *move_dims(__isl_take isl_qpolynomial *qp,
  1444. void *user)
  1445. {
  1446. struct isl_fold_move_dims_data *data = user;
  1447. qp = isl_qpolynomial_move_dims(qp, data->dst_type, data->dst_pos,
  1448. data->src_type, data->src_pos, data->n);
  1449. return qp;
  1450. }
  1451. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims(
  1452. __isl_take isl_qpolynomial_fold *fold,
  1453. enum isl_dim_type dst_type, unsigned dst_pos,
  1454. enum isl_dim_type src_type, unsigned src_pos, unsigned n)
  1455. {
  1456. struct isl_fold_move_dims_data data =
  1457. { dst_type, dst_pos, src_type, src_pos, n };
  1458. enum isl_dim_type set_src_type, set_dst_type;
  1459. isl_space *space;
  1460. isl_qpolynomial_list *list;
  1461. if (n == 0)
  1462. return fold;
  1463. fold = isl_qpolynomial_fold_cow(fold);
  1464. if (!fold)
  1465. return NULL;
  1466. set_src_type = domain_type(src_type);
  1467. set_dst_type = domain_type(dst_type);
  1468. list = isl_qpolynomial_fold_take_list(fold);
  1469. list = isl_qpolynomial_list_map(list, &move_dims, &data);
  1470. fold = isl_qpolynomial_fold_restore_list(fold, list);
  1471. space = isl_qpolynomial_fold_take_domain_space(fold);
  1472. space = isl_space_move_dims(space, set_dst_type, dst_pos,
  1473. set_src_type, src_pos, n);
  1474. fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
  1475. return fold;
  1476. }
  1477. /* Internal data structure for isl_qpolynomial_fold_substitute
  1478. * representing its arguments.
  1479. */
  1480. struct isl_fold_substitute {
  1481. enum isl_dim_type type;
  1482. unsigned first;
  1483. unsigned n;
  1484. isl_qpolynomial **subs;
  1485. };
  1486. /* isl_qpolynomial_list_map callback for calling
  1487. * isl_qpolynomial_substitute on "qp".
  1488. */
  1489. static __isl_give isl_qpolynomial *substitute(__isl_take isl_qpolynomial *qp,
  1490. void *user)
  1491. {
  1492. struct isl_fold_substitute *data = user;
  1493. qp = isl_qpolynomial_substitute(qp,
  1494. data->type, data->first, data->n, data->subs);
  1495. return qp;
  1496. }
  1497. /* For each 0 <= i < "n", replace variable "first" + i of type "type"
  1498. * in fold->qp[k] by subs[i].
  1499. */
  1500. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute(
  1501. __isl_take isl_qpolynomial_fold *fold,
  1502. enum isl_dim_type type, unsigned first, unsigned n,
  1503. __isl_keep isl_qpolynomial **subs)
  1504. {
  1505. struct isl_fold_substitute data = { type, first, n, subs };
  1506. isl_qpolynomial_list *list;
  1507. if (n == 0)
  1508. return fold;
  1509. list = isl_qpolynomial_fold_take_list(fold);
  1510. list = isl_qpolynomial_list_map(list, &substitute, &data);
  1511. fold = isl_qpolynomial_fold_restore_list(fold, list);
  1512. return fold;
  1513. }
  1514. static isl_stat add_pwqp(__isl_take isl_pw_qpolynomial *pwqp, void *user)
  1515. {
  1516. isl_pw_qpolynomial_fold *pwf;
  1517. isl_union_pw_qpolynomial_fold **upwf;
  1518. struct isl_hash_table_entry *entry;
  1519. upwf = (isl_union_pw_qpolynomial_fold **)user;
  1520. entry = isl_union_pw_qpolynomial_fold_find_part_entry(*upwf,
  1521. pwqp->dim, 1);
  1522. if (!entry)
  1523. goto error;
  1524. pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial((*upwf)->type, pwqp);
  1525. if (!entry->data)
  1526. entry->data = pwf;
  1527. else {
  1528. entry->data = isl_pw_qpolynomial_fold_add(entry->data, pwf);
  1529. if (!entry->data)
  1530. return isl_stat_error;
  1531. if (isl_pw_qpolynomial_fold_is_zero(entry->data))
  1532. *upwf = isl_union_pw_qpolynomial_fold_remove_part_entry(
  1533. *upwf, entry);
  1534. }
  1535. return isl_stat_ok;
  1536. error:
  1537. isl_pw_qpolynomial_free(pwqp);
  1538. return isl_stat_error;
  1539. }
  1540. __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial(
  1541. __isl_take isl_union_pw_qpolynomial_fold *upwf,
  1542. __isl_take isl_union_pw_qpolynomial *upwqp)
  1543. {
  1544. upwf = isl_union_pw_qpolynomial_fold_align_params(upwf,
  1545. isl_union_pw_qpolynomial_get_space(upwqp));
  1546. upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
  1547. isl_union_pw_qpolynomial_fold_get_space(upwf));
  1548. upwf = isl_union_pw_qpolynomial_fold_cow(upwf);
  1549. if (!upwf || !upwqp)
  1550. goto error;
  1551. if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &add_pwqp,
  1552. &upwf) < 0)
  1553. goto error;
  1554. isl_union_pw_qpolynomial_free(upwqp);
  1555. return upwf;
  1556. error:
  1557. isl_union_pw_qpolynomial_fold_free(upwf);
  1558. isl_union_pw_qpolynomial_free(upwqp);
  1559. return NULL;
  1560. }
  1561. static isl_bool join_compatible(__isl_keep isl_space *space1,
  1562. __isl_keep isl_space *space2)
  1563. {
  1564. isl_bool m;
  1565. m = isl_space_has_equal_params(space1, space2);
  1566. if (m < 0 || !m)
  1567. return m;
  1568. return isl_space_tuple_is_equal(space1, isl_dim_out,
  1569. space2, isl_dim_in);
  1570. }
  1571. /* Compute the intersection of the range of the map and the domain
  1572. * of the piecewise quasipolynomial reduction and then compute a bound
  1573. * on the associated quasipolynomial reduction over all elements
  1574. * in this intersection.
  1575. *
  1576. * We first introduce some unconstrained dimensions in the
  1577. * piecewise quasipolynomial, intersect the resulting domain
  1578. * with the wrapped map and the compute the sum.
  1579. */
  1580. __isl_give isl_pw_qpolynomial_fold *isl_map_apply_pw_qpolynomial_fold(
  1581. __isl_take isl_map *map, __isl_take isl_pw_qpolynomial_fold *pwf,
  1582. isl_bool *tight)
  1583. {
  1584. isl_ctx *ctx;
  1585. isl_set *dom;
  1586. isl_space *map_space;
  1587. isl_space *pwf_space;
  1588. isl_size n_in;
  1589. isl_bool ok;
  1590. ctx = isl_map_get_ctx(map);
  1591. if (!ctx)
  1592. goto error;
  1593. map_space = isl_map_get_space(map);
  1594. pwf_space = isl_pw_qpolynomial_fold_get_space(pwf);
  1595. ok = join_compatible(map_space, pwf_space);
  1596. isl_space_free(map_space);
  1597. isl_space_free(pwf_space);
  1598. if (ok < 0)
  1599. goto error;
  1600. if (!ok)
  1601. isl_die(ctx, isl_error_invalid, "incompatible dimensions",
  1602. goto error);
  1603. n_in = isl_map_dim(map, isl_dim_in);
  1604. if (n_in < 0)
  1605. goto error;
  1606. pwf = isl_pw_qpolynomial_fold_insert_dims(pwf, isl_dim_in, 0, n_in);
  1607. dom = isl_map_wrap(map);
  1608. pwf = isl_pw_qpolynomial_fold_reset_domain_space(pwf,
  1609. isl_set_get_space(dom));
  1610. pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, dom);
  1611. pwf = isl_pw_qpolynomial_fold_bound(pwf, tight);
  1612. return pwf;
  1613. error:
  1614. isl_map_free(map);
  1615. isl_pw_qpolynomial_fold_free(pwf);
  1616. return NULL;
  1617. }
  1618. __isl_give isl_pw_qpolynomial_fold *isl_set_apply_pw_qpolynomial_fold(
  1619. __isl_take isl_set *set, __isl_take isl_pw_qpolynomial_fold *pwf,
  1620. isl_bool *tight)
  1621. {
  1622. return isl_map_apply_pw_qpolynomial_fold(set, pwf, tight);
  1623. }
  1624. struct isl_apply_fold_data {
  1625. isl_union_pw_qpolynomial_fold *upwf;
  1626. isl_union_pw_qpolynomial_fold *res;
  1627. isl_map *map;
  1628. isl_bool tight;
  1629. };
  1630. static isl_stat pw_qpolynomial_fold_apply(
  1631. __isl_take isl_pw_qpolynomial_fold *pwf, void *user)
  1632. {
  1633. isl_space *map_dim;
  1634. isl_space *pwf_dim;
  1635. struct isl_apply_fold_data *data = user;
  1636. isl_bool ok;
  1637. map_dim = isl_map_get_space(data->map);
  1638. pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf);
  1639. ok = join_compatible(map_dim, pwf_dim);
  1640. isl_space_free(map_dim);
  1641. isl_space_free(pwf_dim);
  1642. if (ok < 0)
  1643. return isl_stat_error;
  1644. if (ok) {
  1645. pwf = isl_map_apply_pw_qpolynomial_fold(isl_map_copy(data->map),
  1646. pwf, data->tight ? &data->tight : NULL);
  1647. data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
  1648. data->res, pwf);
  1649. } else
  1650. isl_pw_qpolynomial_fold_free(pwf);
  1651. return isl_stat_ok;
  1652. }
  1653. static isl_stat map_apply(__isl_take isl_map *map, void *user)
  1654. {
  1655. struct isl_apply_fold_data *data = user;
  1656. isl_stat r;
  1657. data->map = map;
  1658. r = isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(
  1659. data->upwf, &pw_qpolynomial_fold_apply, data);
  1660. isl_map_free(map);
  1661. return r;
  1662. }
  1663. __isl_give isl_union_pw_qpolynomial_fold *isl_union_map_apply_union_pw_qpolynomial_fold(
  1664. __isl_take isl_union_map *umap,
  1665. __isl_take isl_union_pw_qpolynomial_fold *upwf, isl_bool *tight)
  1666. {
  1667. isl_space *space;
  1668. enum isl_fold type;
  1669. struct isl_apply_fold_data data;
  1670. upwf = isl_union_pw_qpolynomial_fold_align_params(upwf,
  1671. isl_union_map_get_space(umap));
  1672. umap = isl_union_map_align_params(umap,
  1673. isl_union_pw_qpolynomial_fold_get_space(upwf));
  1674. data.upwf = upwf;
  1675. data.tight = tight ? isl_bool_true : isl_bool_false;
  1676. space = isl_union_pw_qpolynomial_fold_get_space(upwf);
  1677. type = isl_union_pw_qpolynomial_fold_get_type(upwf);
  1678. data.res = isl_union_pw_qpolynomial_fold_zero(space, type);
  1679. if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
  1680. goto error;
  1681. isl_union_map_free(umap);
  1682. isl_union_pw_qpolynomial_fold_free(upwf);
  1683. if (tight)
  1684. *tight = data.tight;
  1685. return data.res;
  1686. error:
  1687. isl_union_map_free(umap);
  1688. isl_union_pw_qpolynomial_fold_free(upwf);
  1689. isl_union_pw_qpolynomial_fold_free(data.res);
  1690. return NULL;
  1691. }
  1692. __isl_give isl_union_pw_qpolynomial_fold *isl_union_set_apply_union_pw_qpolynomial_fold(
  1693. __isl_take isl_union_set *uset,
  1694. __isl_take isl_union_pw_qpolynomial_fold *upwf, isl_bool *tight)
  1695. {
  1696. return isl_union_map_apply_union_pw_qpolynomial_fold(uset, upwf, tight);
  1697. }
  1698. /* isl_qpolynomial_list_map callback for calling
  1699. * isl_qpolynomial_realign_domain on "qp".
  1700. */
  1701. static __isl_give isl_qpolynomial *realign_domain(
  1702. __isl_take isl_qpolynomial *qp, void *user)
  1703. {
  1704. isl_reordering *r = user;
  1705. qp = isl_qpolynomial_realign_domain(qp, isl_reordering_copy(r));
  1706. return qp;
  1707. }
  1708. /* Reorder the dimension of "fold" according to the given reordering.
  1709. */
  1710. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain(
  1711. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r)
  1712. {
  1713. isl_space *space;
  1714. isl_qpolynomial_list *list;
  1715. list = isl_qpolynomial_fold_take_list(fold);
  1716. list = isl_qpolynomial_list_map(list, &realign_domain, r);
  1717. fold = isl_qpolynomial_fold_restore_list(fold, list);
  1718. space = isl_reordering_get_space(r);
  1719. fold = isl_qpolynomial_fold_reset_domain_space(fold, space);
  1720. isl_reordering_free(r);
  1721. return fold;
  1722. }
  1723. /* isl_qpolynomial_list_map callback for calling
  1724. * isl_qpolynomial_mul_isl_int on "qp".
  1725. */
  1726. static __isl_give isl_qpolynomial *mul_int(__isl_take isl_qpolynomial *qp,
  1727. void *user)
  1728. {
  1729. isl_int *v = user;
  1730. qp = isl_qpolynomial_mul_isl_int(qp, *v);
  1731. return qp;
  1732. }
  1733. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int(
  1734. __isl_take isl_qpolynomial_fold *fold, isl_int v)
  1735. {
  1736. isl_qpolynomial_list *list;
  1737. if (isl_int_is_one(v))
  1738. return fold;
  1739. if (fold && isl_int_is_zero(v)) {
  1740. isl_qpolynomial_fold *zero;
  1741. isl_space *space = isl_space_copy(fold->dim);
  1742. zero = isl_qpolynomial_fold_empty(fold->type, space);
  1743. isl_qpolynomial_fold_free(fold);
  1744. return zero;
  1745. }
  1746. fold = isl_qpolynomial_fold_cow(fold);
  1747. if (!fold)
  1748. return NULL;
  1749. if (isl_int_is_neg(v))
  1750. fold->type = isl_fold_type_negate(fold->type);
  1751. list = isl_qpolynomial_fold_take_list(fold);
  1752. list = isl_qpolynomial_list_map(list, &mul_int, &v);
  1753. fold = isl_qpolynomial_fold_restore_list(fold, list);
  1754. return fold;
  1755. }
  1756. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale(
  1757. __isl_take isl_qpolynomial_fold *fold, isl_int v)
  1758. {
  1759. return isl_qpolynomial_fold_mul_isl_int(fold, v);
  1760. }
  1761. /* isl_qpolynomial_list_map callback for calling
  1762. * isl_qpolynomial_scale_val on "qp".
  1763. */
  1764. static __isl_give isl_qpolynomial *scale_val(__isl_take isl_qpolynomial *qp,
  1765. void *user)
  1766. {
  1767. isl_val *v = user;
  1768. qp = isl_qpolynomial_scale_val(qp, isl_val_copy(v));
  1769. return qp;
  1770. }
  1771. /* Multiply "fold" by "v".
  1772. */
  1773. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_val(
  1774. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
  1775. {
  1776. isl_qpolynomial_list *list;
  1777. if (!fold || !v)
  1778. goto error;
  1779. if (isl_val_is_one(v)) {
  1780. isl_val_free(v);
  1781. return fold;
  1782. }
  1783. if (isl_val_is_zero(v)) {
  1784. isl_qpolynomial_fold *zero;
  1785. isl_space *space = isl_qpolynomial_fold_get_domain_space(fold);
  1786. zero = isl_qpolynomial_fold_empty(fold->type, space);
  1787. isl_qpolynomial_fold_free(fold);
  1788. isl_val_free(v);
  1789. return zero;
  1790. }
  1791. if (!isl_val_is_rat(v))
  1792. isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid,
  1793. "expecting rational factor", goto error);
  1794. fold = isl_qpolynomial_fold_cow(fold);
  1795. if (!fold)
  1796. goto error;
  1797. if (isl_val_is_neg(v))
  1798. fold->type = isl_fold_type_negate(fold->type);
  1799. list = isl_qpolynomial_fold_take_list(fold);
  1800. list = isl_qpolynomial_list_map(list, &scale_val, v);
  1801. fold = isl_qpolynomial_fold_restore_list(fold, list);
  1802. isl_val_free(v);
  1803. return fold;
  1804. error:
  1805. isl_val_free(v);
  1806. isl_qpolynomial_fold_free(fold);
  1807. return NULL;
  1808. }
  1809. /* Divide "fold" by "v".
  1810. */
  1811. __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_down_val(
  1812. __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
  1813. {
  1814. if (!fold || !v)
  1815. goto error;
  1816. if (isl_val_is_one(v)) {
  1817. isl_val_free(v);
  1818. return fold;
  1819. }
  1820. if (!isl_val_is_rat(v))
  1821. isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid,
  1822. "expecting rational factor", goto error);
  1823. if (isl_val_is_zero(v))
  1824. isl_die(isl_val_get_ctx(v), isl_error_invalid,
  1825. "cannot scale down by zero", goto error);
  1826. return isl_qpolynomial_fold_scale_val(fold, isl_val_inv(v));
  1827. error:
  1828. isl_val_free(v);
  1829. isl_qpolynomial_fold_free(fold);
  1830. return NULL;
  1831. }