6012 lines · c
1/*2 * Copyright 2008-2009 Katholieke Universiteit Leuven3 * Copyright 2010 INRIA Saclay4 * Copyright 2016-2017 Sven Verdoolaege5 *6 * Use of this software is governed by the MIT license7 *8 * Written by Sven Verdoolaege, K.U.Leuven, Departement9 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium10 * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,11 * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 12 */13 14#include <isl_ctx_private.h>15#include "isl_map_private.h"16#include <isl_seq.h>17#include "isl_tab.h"18#include "isl_sample.h"19#include <isl_mat_private.h>20#include <isl_vec_private.h>21#include <isl_aff_private.h>22#include <isl_constraint_private.h>23#include <isl_options_private.h>24#include <isl_config.h>25 26#include <bset_to_bmap.c>27 28/*29 * The implementation of parametric integer linear programming in this file30 * was inspired by the paper "Parametric Integer Programming" and the31 * report "Solving systems of affine (in)equalities" by Paul Feautrier32 * (and others).33 *34 * The strategy used for obtaining a feasible solution is different35 * from the one used in isl_tab.c. In particular, in isl_tab.c,36 * upon finding a constraint that is not yet satisfied, we pivot37 * in a row that increases the constant term of the row holding the38 * constraint, making sure the sample solution remains feasible39 * for all the constraints it already satisfied.40 * Here, we always pivot in the row holding the constraint,41 * choosing a column that induces the lexicographically smallest42 * increment to the sample solution.43 *44 * By starting out from a sample value that is lexicographically45 * smaller than any integer point in the problem space, the first46 * feasible integer sample point we find will also be the lexicographically47 * smallest. If all variables can be assumed to be non-negative,48 * then the initial sample value may be chosen equal to zero.49 * However, we will not make this assumption. Instead, we apply50 * the "big parameter" trick. Any variable x is then not directly51 * used in the tableau, but instead it is represented by another52 * variable x' = M + x, where M is an arbitrarily large (positive)53 * value. x' is therefore always non-negative, whatever the value of x.54 * Taking as initial sample value x' = 0 corresponds to x = -M,55 * which is always smaller than any possible value of x.56 *57 * The big parameter trick is used in the main tableau and58 * also in the context tableau if isl_context_lex is used.59 * In this case, each tableaus has its own big parameter.60 * Before doing any real work, we check if all the parameters61 * happen to be non-negative. If so, we drop the column corresponding62 * to M from the initial context tableau.63 * If isl_context_gbr is used, then the big parameter trick is only64 * used in the main tableau.65 */66 67struct isl_context;68struct isl_context_op {69 /* detect nonnegative parameters in context and mark them in tab */70 struct isl_tab *(*detect_nonnegative_parameters)(71 struct isl_context *context, struct isl_tab *tab);72 /* return temporary reference to basic set representation of context */73 struct isl_basic_set *(*peek_basic_set)(struct isl_context *context);74 /* return temporary reference to tableau representation of context */75 struct isl_tab *(*peek_tab)(struct isl_context *context);76 /* add equality; check is 1 if eq may not be valid;77 * update is 1 if we may want to call ineq_sign on context later.78 */79 void (*add_eq)(struct isl_context *context, isl_int *eq,80 int check, int update);81 /* add inequality; check is 1 if ineq may not be valid;82 * update is 1 if we may want to call ineq_sign on context later.83 */84 void (*add_ineq)(struct isl_context *context, isl_int *ineq,85 int check, int update);86 /* check sign of ineq based on previous information.87 * strict is 1 if saturation should be treated as a positive sign.88 */89 enum isl_tab_row_sign (*ineq_sign)(struct isl_context *context,90 isl_int *ineq, int strict);91 /* check if inequality maintains feasibility */92 int (*test_ineq)(struct isl_context *context, isl_int *ineq);93 /* return index of a div that corresponds to "div" */94 int (*get_div)(struct isl_context *context, struct isl_tab *tab,95 struct isl_vec *div);96 /* insert div "div" to context at "pos" and return non-negativity */97 isl_bool (*insert_div)(struct isl_context *context, int pos,98 __isl_keep isl_vec *div);99 int (*detect_equalities)(struct isl_context *context,100 struct isl_tab *tab);101 /* return row index of "best" split */102 int (*best_split)(struct isl_context *context, struct isl_tab *tab);103 /* check if context has already been determined to be empty */104 int (*is_empty)(struct isl_context *context);105 /* check if context is still usable */106 int (*is_ok)(struct isl_context *context);107 /* save a copy/snapshot of context */108 void *(*save)(struct isl_context *context);109 /* restore saved context */110 void (*restore)(struct isl_context *context, void *);111 /* discard saved context */112 void (*discard)(void *);113 /* invalidate context */114 void (*invalidate)(struct isl_context *context);115 /* free context */116 __isl_null struct isl_context *(*free)(struct isl_context *context);117};118 119/* Shared parts of context representation.120 *121 * "n_unknown" is the number of final unknown integer divisions122 * in the input domain.123 */124struct isl_context {125 struct isl_context_op *op;126 int n_unknown;127};128 129struct isl_context_lex {130 struct isl_context context;131 struct isl_tab *tab;132};133 134/* A stack (linked list) of solutions of subtrees of the search space.135 *136 * "ma" describes the solution as a function of "dom".137 * In particular, the domain space of "ma" is equal to the space of "dom".138 *139 * If "ma" is NULL, then there is no solution on "dom".140 */141struct isl_partial_sol {142 int level;143 struct isl_basic_set *dom;144 isl_multi_aff *ma;145 146 struct isl_partial_sol *next;147};148 149struct isl_sol;150struct isl_sol_callback {151 struct isl_tab_callback callback;152 struct isl_sol *sol;153};154 155/* isl_sol is an interface for constructing a solution to156 * a parametric integer linear programming problem.157 * Every time the algorithm reaches a state where a solution158 * can be read off from the tableau, the function "add" is called159 * on the isl_sol passed to find_solutions_main. In a state where160 * the tableau is empty, "add_empty" is called instead.161 * "free" is called to free the implementation specific fields, if any.162 *163 * "error" is set if some error has occurred. This flag invalidates164 * the remainder of the data structure.165 * If "rational" is set, then a rational optimization is being performed.166 * "level" is the current level in the tree with nodes for each167 * split in the context.168 * If "max" is set, then a maximization problem is being solved, rather than169 * a minimization problem, which means that the variables in the170 * tableau have value "M - x" rather than "M + x".171 * "n_out" is the number of output dimensions in the input.172 * "space" is the space in which the solution (and also the input) lives.173 *174 * The context tableau is owned by isl_sol and is updated incrementally.175 *176 * There are currently two implementations of this interface,177 * isl_sol_map, which simply collects the solutions in an isl_map178 * and (optionally) the parts of the context where there is no solution179 * in an isl_set, and180 * isl_sol_pma, which collects an isl_pw_multi_aff instead.181 */182struct isl_sol {183 int error;184 int rational;185 int level;186 int max;187 isl_size n_out;188 isl_space *space;189 struct isl_context *context;190 struct isl_partial_sol *partial;191 void (*add)(struct isl_sol *sol,192 __isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma);193 void (*add_empty)(struct isl_sol *sol, struct isl_basic_set *bset);194 void (*free)(struct isl_sol *sol);195 struct isl_sol_callback dec_level;196};197 198static void sol_free(struct isl_sol *sol)199{200 struct isl_partial_sol *partial, *next;201 if (!sol)202 return;203 for (partial = sol->partial; partial; partial = next) {204 next = partial->next;205 isl_basic_set_free(partial->dom);206 isl_multi_aff_free(partial->ma);207 free(partial);208 }209 isl_space_free(sol->space);210 if (sol->context)211 sol->context->op->free(sol->context);212 sol->free(sol);213 free(sol);214}215 216/* Push a partial solution represented by a domain and function "ma"217 * onto the stack of partial solutions.218 * If "ma" is NULL, then "dom" represents a part of the domain219 * with no solution.220 */221static void sol_push_sol(struct isl_sol *sol,222 __isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma)223{224 struct isl_partial_sol *partial;225 226 if (sol->error || !dom)227 goto error;228 229 partial = isl_alloc_type(dom->ctx, struct isl_partial_sol);230 if (!partial)231 goto error;232 233 partial->level = sol->level;234 partial->dom = dom;235 partial->ma = ma;236 partial->next = sol->partial;237 238 sol->partial = partial;239 240 return;241error:242 isl_basic_set_free(dom);243 isl_multi_aff_free(ma);244 sol->error = 1;245}246 247/* Check that the final columns of "M", starting at "first", are zero.248 */249static isl_stat check_final_columns_are_zero(__isl_keep isl_mat *M,250 unsigned first)251{252 int i;253 isl_size rows, cols;254 unsigned n;255 256 rows = isl_mat_rows(M);257 cols = isl_mat_cols(M);258 if (rows < 0 || cols < 0)259 return isl_stat_error;260 n = cols - first;261 for (i = 0; i < rows; ++i)262 if (isl_seq_first_non_zero(M->row[i] + first, n) != -1)263 isl_die(isl_mat_get_ctx(M), isl_error_internal,264 "final columns should be zero",265 return isl_stat_error);266 return isl_stat_ok;267}268 269/* Set the affine expressions in "ma" according to the rows in "M", which270 * are defined over the local space "ls".271 * The matrix "M" may have extra (zero) columns beyond the number272 * of variables in "ls".273 */274static __isl_give isl_multi_aff *set_from_affine_matrix(275 __isl_take isl_multi_aff *ma, __isl_take isl_local_space *ls,276 __isl_take isl_mat *M)277{278 int i;279 isl_size dim;280 isl_aff *aff;281 282 dim = isl_local_space_dim(ls, isl_dim_all);283 if (!ma || dim < 0 || !M)284 goto error;285 286 if (check_final_columns_are_zero(M, 1 + dim) < 0)287 goto error;288 for (i = 1; i < M->n_row; ++i) {289 aff = isl_aff_alloc(isl_local_space_copy(ls));290 if (aff) {291 isl_int_set(aff->v->el[0], M->row[0][0]);292 isl_seq_cpy(aff->v->el + 1, M->row[i], 1 + dim);293 }294 aff = isl_aff_normalize(aff);295 ma = isl_multi_aff_set_aff(ma, i - 1, aff);296 }297 isl_local_space_free(ls);298 isl_mat_free(M);299 300 return ma;301error:302 isl_local_space_free(ls);303 isl_mat_free(M);304 isl_multi_aff_free(ma);305 return NULL;306}307 308/* Push a partial solution represented by a domain and mapping M309 * onto the stack of partial solutions.310 *311 * The affine matrix "M" maps the dimensions of the context312 * to the output variables. Convert it into an isl_multi_aff and313 * then call sol_push_sol.314 *315 * Note that the description of the initial context may have involved316 * existentially quantified variables, in which case they also appear317 * in "dom". These need to be removed before creating the affine318 * expression because an affine expression cannot be defined in terms319 * of existentially quantified variables without a known representation.320 * Since newly added integer divisions are inserted before these321 * existentially quantified variables, they are still in the final322 * positions and the corresponding final columns of "M" are zero323 * because align_context_divs adds the existentially quantified324 * variables of the context to the main tableau without any constraints and325 * any equality constraints that are added later on can only serve326 * to eliminate these existentially quantified variables.327 */328static void sol_push_sol_mat(struct isl_sol *sol,329 __isl_take isl_basic_set *dom, __isl_take isl_mat *M)330{331 isl_local_space *ls;332 isl_multi_aff *ma;333 isl_size n_div;334 int n_known;335 336 n_div = isl_basic_set_dim(dom, isl_dim_div);337 if (n_div < 0)338 goto error;339 n_known = n_div - sol->context->n_unknown;340 341 ma = isl_multi_aff_alloc(isl_space_copy(sol->space));342 ls = isl_basic_set_get_local_space(dom);343 ls = isl_local_space_drop_dims(ls, isl_dim_div,344 n_known, n_div - n_known);345 ma = set_from_affine_matrix(ma, ls, M);346 347 if (!ma)348 dom = isl_basic_set_free(dom);349 sol_push_sol(sol, dom, ma);350 return;351error:352 isl_basic_set_free(dom);353 isl_mat_free(M);354 sol_push_sol(sol, NULL, NULL);355}356 357/* Pop one partial solution from the partial solution stack and358 * pass it on to sol->add or sol->add_empty.359 */360static void sol_pop_one(struct isl_sol *sol)361{362 struct isl_partial_sol *partial;363 364 partial = sol->partial;365 sol->partial = partial->next;366 367 if (partial->ma)368 sol->add(sol, partial->dom, partial->ma);369 else370 sol->add_empty(sol, partial->dom);371 free(partial);372}373 374/* Return a fresh copy of the domain represented by the context tableau.375 */376static struct isl_basic_set *sol_domain(struct isl_sol *sol)377{378 struct isl_basic_set *bset;379 380 if (sol->error)381 return NULL;382 383 bset = isl_basic_set_dup(sol->context->op->peek_basic_set(sol->context));384 bset = isl_basic_set_update_from_tab(bset,385 sol->context->op->peek_tab(sol->context));386 387 return bset;388}389 390/* Check whether two partial solutions have the same affine expressions.391 */392static isl_bool same_solution(struct isl_partial_sol *s1,393 struct isl_partial_sol *s2)394{395 if (!s1->ma != !s2->ma)396 return isl_bool_false;397 if (!s1->ma)398 return isl_bool_true;399 400 return isl_multi_aff_plain_is_equal(s1->ma, s2->ma);401}402 403/* Swap the initial two partial solutions in "sol".404 *405 * That is, go from406 *407 * sol->partial = p1; p1->next = p2; p2->next = p3408 *409 * to410 *411 * sol->partial = p2; p2->next = p1; p1->next = p3412 */413static void swap_initial(struct isl_sol *sol)414{415 struct isl_partial_sol *partial;416 417 partial = sol->partial;418 sol->partial = partial->next;419 partial->next = partial->next->next;420 sol->partial->next = partial;421}422 423/* Combine the initial two partial solution of "sol" into424 * a partial solution with the current context domain of "sol" and425 * the function description of the second partial solution in the list.426 * The level of the new partial solution is set to the current level.427 *428 * That is, the first two partial solutions (D1,M1) and (D2,M2) are429 * replaced by (D,M2), where D is the domain of "sol", which is assumed430 * to be the union of D1 and D2, while M1 is assumed to be equal to M2431 * (at least on D1).432 */433static isl_stat combine_initial_into_second(struct isl_sol *sol)434{435 struct isl_partial_sol *partial;436 isl_basic_set *bset;437 438 partial = sol->partial;439 440 bset = sol_domain(sol);441 isl_basic_set_free(partial->next->dom);442 partial->next->dom = bset;443 partial->next->level = sol->level;444 445 if (!bset)446 return isl_stat_error;447 448 sol->partial = partial->next;449 isl_basic_set_free(partial->dom);450 isl_multi_aff_free(partial->ma);451 free(partial);452 453 return isl_stat_ok;454}455 456/* Are "ma1" and "ma2" equal to each other on "dom"?457 *458 * Combine "ma1" and "ma2" with "dom" and check if the results are the same.459 * "dom" may have existentially quantified variables. Eliminate them first460 * as otherwise they would have to be eliminated twice, in a more complicated461 * context.462 */463static isl_bool equal_on_domain(__isl_keep isl_multi_aff *ma1,464 __isl_keep isl_multi_aff *ma2, __isl_keep isl_basic_set *dom)465{466 isl_set *set;467 isl_pw_multi_aff *pma1, *pma2;468 isl_bool equal;469 470 set = isl_basic_set_compute_divs(isl_basic_set_copy(dom));471 pma1 = isl_pw_multi_aff_alloc(isl_set_copy(set),472 isl_multi_aff_copy(ma1));473 pma2 = isl_pw_multi_aff_alloc(set, isl_multi_aff_copy(ma2));474 equal = isl_pw_multi_aff_is_equal(pma1, pma2);475 isl_pw_multi_aff_free(pma1);476 isl_pw_multi_aff_free(pma2);477 478 return equal;479}480 481/* The initial two partial solutions of "sol" are known to be at482 * the same level.483 * If they represent the same solution (on different parts of the domain),484 * then combine them into a single solution at the current level.485 * Otherwise, pop them both.486 *487 * Even if the two partial solution are not obviously the same,488 * one may still be a simplification of the other over its own domain.489 * Also check if the two sets of affine functions are equal when490 * restricted to one of the domains. If so, combine the two491 * using the set of affine functions on the other domain.492 * That is, for two partial solutions (D1,M1) and (D2,M2),493 * if M1 = M2 on D1, then the pair of partial solutions can494 * be replaced by (D1+D2,M2) and similarly when M1 = M2 on D2.495 */496static isl_stat combine_initial_if_equal(struct isl_sol *sol)497{498 struct isl_partial_sol *partial;499 isl_bool same;500 501 partial = sol->partial;502 503 same = same_solution(partial, partial->next);504 if (same < 0)505 return isl_stat_error;506 if (same)507 return combine_initial_into_second(sol);508 if (partial->ma && partial->next->ma) {509 same = equal_on_domain(partial->ma, partial->next->ma,510 partial->dom);511 if (same < 0)512 return isl_stat_error;513 if (same)514 return combine_initial_into_second(sol);515 same = equal_on_domain(partial->ma, partial->next->ma,516 partial->next->dom);517 if (same) {518 swap_initial(sol);519 return combine_initial_into_second(sol);520 }521 }522 523 sol_pop_one(sol);524 sol_pop_one(sol);525 526 return isl_stat_ok;527}528 529/* Pop all solutions from the partial solution stack that were pushed onto530 * the stack at levels that are deeper than the current level.531 * If the two topmost elements on the stack have the same level532 * and represent the same solution, then their domains are combined.533 * This combined domain is the same as the current context domain534 * as sol_pop is called each time we move back to a higher level.535 * If the outer level (0) has been reached, then all partial solutions536 * at the current level are also popped off.537 */538static void sol_pop(struct isl_sol *sol)539{540 struct isl_partial_sol *partial;541 542 if (sol->error)543 return;544 545 partial = sol->partial;546 if (!partial)547 return;548 549 if (partial->level == 0 && sol->level == 0) {550 for (partial = sol->partial; partial; partial = sol->partial)551 sol_pop_one(sol);552 return;553 }554 555 if (partial->level <= sol->level)556 return;557 558 if (partial->next && partial->next->level == partial->level) {559 if (combine_initial_if_equal(sol) < 0)560 goto error;561 } else562 sol_pop_one(sol);563 564 if (sol->level == 0) {565 for (partial = sol->partial; partial; partial = sol->partial)566 sol_pop_one(sol);567 return;568 }569 570 if (0)571error: sol->error = 1;572}573 574static void sol_dec_level(struct isl_sol *sol)575{576 if (sol->error)577 return;578 579 sol->level--;580 581 sol_pop(sol);582}583 584static isl_stat sol_dec_level_wrap(struct isl_tab_callback *cb)585{586 struct isl_sol_callback *callback = (struct isl_sol_callback *)cb;587 588 sol_dec_level(callback->sol);589 590 return callback->sol->error ? isl_stat_error : isl_stat_ok;591}592 593/* Move down to next level and push callback onto context tableau594 * to decrease the level again when it gets rolled back across595 * the current state. That is, dec_level will be called with596 * the context tableau in the same state as it is when inc_level597 * is called.598 */599static void sol_inc_level(struct isl_sol *sol)600{601 struct isl_tab *tab;602 603 if (sol->error)604 return;605 606 sol->level++;607 tab = sol->context->op->peek_tab(sol->context);608 if (isl_tab_push_callback(tab, &sol->dec_level.callback) < 0)609 sol->error = 1;610}611 612static void scale_rows(struct isl_mat *mat, isl_int m, int n_row)613{614 int i;615 616 if (isl_int_is_one(m))617 return;618 619 for (i = 0; i < n_row; ++i)620 isl_seq_scale(mat->row[i], mat->row[i], m, mat->n_col);621}622 623/* Add the solution identified by the tableau and the context tableau.624 *625 * The layout of the variables is as follows.626 * tab->n_var is equal to the total number of variables in the input627 * map (including divs that were copied from the context)628 * + the number of extra divs constructed629 * Of these, the first tab->n_param and the last tab->n_div variables630 * correspond to the variables in the context, i.e.,631 * tab->n_param + tab->n_div = context_tab->n_var632 * tab->n_param is equal to the number of parameters and input633 * dimensions in the input map634 * tab->n_div is equal to the number of divs in the context635 *636 * If there is no solution, then call add_empty with a basic set637 * that corresponds to the context tableau. (If add_empty is NULL,638 * then do nothing).639 *640 * If there is a solution, then first construct a matrix that maps641 * all dimensions of the context to the output variables, i.e.,642 * the output dimensions in the input map.643 * The divs in the input map (if any) that do not correspond to any644 * div in the context do not appear in the solution.645 * The algorithm will make sure that they have an integer value,646 * but these values themselves are of no interest.647 * We have to be careful not to drop or rearrange any divs in the648 * context because that would change the meaning of the matrix.649 *650 * To extract the value of the output variables, it should be noted651 * that we always use a big parameter M in the main tableau and so652 * the variable stored in this tableau is not an output variable x itself, but653 * x' = M + x (in case of minimization)654 * or655 * x' = M - x (in case of maximization)656 * If x' appears in a column, then its optimal value is zero,657 * which means that the optimal value of x is an unbounded number658 * (-M for minimization and M for maximization).659 * We currently assume that the output dimensions in the original map660 * are bounded, so this cannot occur.661 * Similarly, when x' appears in a row, then the coefficient of M in that662 * row is necessarily 1.663 * If the row in the tableau represents664 * d x' = c + d M + e(y)665 * then, in case of minimization, the corresponding row in the matrix666 * will be667 * a c + a e(y)668 * with a d = m, the (updated) common denominator of the matrix.669 * In case of maximization, the row will be670 * -a c - a e(y)671 */672static void sol_add(struct isl_sol *sol, struct isl_tab *tab)673{674 struct isl_basic_set *bset = NULL;675 struct isl_mat *mat = NULL;676 unsigned off;677 int row;678 isl_int m;679 680 if (sol->error || !tab)681 goto error;682 683 if (tab->empty && !sol->add_empty)684 return;685 if (sol->context->op->is_empty(sol->context))686 return;687 688 bset = sol_domain(sol);689 690 if (tab->empty) {691 sol_push_sol(sol, bset, NULL);692 return;693 }694 695 off = 2 + tab->M;696 697 mat = isl_mat_alloc(tab->mat->ctx, 1 + sol->n_out,698 1 + tab->n_param + tab->n_div);699 if (!mat)700 goto error;701 702 isl_int_init(m);703 704 isl_seq_clr(mat->row[0] + 1, mat->n_col - 1);705 isl_int_set_si(mat->row[0][0], 1);706 for (row = 0; row < sol->n_out; ++row) {707 int i = tab->n_param + row;708 int r, j;709 710 isl_seq_clr(mat->row[1 + row], mat->n_col);711 if (!tab->var[i].is_row) {712 if (tab->M)713 isl_die(mat->ctx, isl_error_invalid,714 "unbounded optimum", goto error2);715 continue;716 }717 718 r = tab->var[i].index;719 if (tab->M &&720 isl_int_ne(tab->mat->row[r][2], tab->mat->row[r][0]))721 isl_die(mat->ctx, isl_error_invalid,722 "unbounded optimum", goto error2);723 isl_int_gcd(m, mat->row[0][0], tab->mat->row[r][0]);724 isl_int_divexact(m, tab->mat->row[r][0], m);725 scale_rows(mat, m, 1 + row);726 isl_int_divexact(m, mat->row[0][0], tab->mat->row[r][0]);727 isl_int_mul(mat->row[1 + row][0], m, tab->mat->row[r][1]);728 for (j = 0; j < tab->n_param; ++j) {729 int col;730 if (tab->var[j].is_row)731 continue;732 col = tab->var[j].index;733 isl_int_mul(mat->row[1 + row][1 + j], m,734 tab->mat->row[r][off + col]);735 }736 for (j = 0; j < tab->n_div; ++j) {737 int col;738 if (tab->var[tab->n_var - tab->n_div+j].is_row)739 continue;740 col = tab->var[tab->n_var - tab->n_div+j].index;741 isl_int_mul(mat->row[1 + row][1 + tab->n_param + j], m,742 tab->mat->row[r][off + col]);743 }744 if (sol->max)745 isl_seq_neg(mat->row[1 + row], mat->row[1 + row],746 mat->n_col);747 }748 749 isl_int_clear(m);750 751 sol_push_sol_mat(sol, bset, mat);752 return;753error2:754 isl_int_clear(m);755error:756 isl_basic_set_free(bset);757 isl_mat_free(mat);758 sol->error = 1;759}760 761struct isl_sol_map {762 struct isl_sol sol;763 struct isl_map *map;764 struct isl_set *empty;765};766 767static void sol_map_free(struct isl_sol *sol)768{769 struct isl_sol_map *sol_map = (struct isl_sol_map *) sol;770 isl_map_free(sol_map->map);771 isl_set_free(sol_map->empty);772}773 774/* This function is called for parts of the context where there is775 * no solution, with "bset" corresponding to the context tableau.776 * Simply add the basic set to the set "empty".777 */778static void sol_map_add_empty(struct isl_sol_map *sol,779 struct isl_basic_set *bset)780{781 if (!bset || !sol->empty)782 goto error;783 784 sol->empty = isl_set_grow(sol->empty, 1);785 bset = isl_basic_set_simplify(bset);786 bset = isl_basic_set_finalize(bset);787 sol->empty = isl_set_add_basic_set(sol->empty, isl_basic_set_copy(bset));788 if (!sol->empty)789 goto error;790 isl_basic_set_free(bset);791 return;792error:793 isl_basic_set_free(bset);794 sol->sol.error = 1;795}796 797static void sol_map_add_empty_wrap(struct isl_sol *sol,798 struct isl_basic_set *bset)799{800 sol_map_add_empty((struct isl_sol_map *)sol, bset);801}802 803/* Given a basic set "dom" that represents the context and a tuple of804 * affine expressions "ma" defined over this domain, construct a basic map805 * that expresses this function on the domain.806 */807static void sol_map_add(struct isl_sol_map *sol,808 __isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma)809{810 isl_basic_map *bmap;811 812 if (sol->sol.error || !dom || !ma)813 goto error;814 815 bmap = isl_basic_map_from_multi_aff2(ma, sol->sol.rational);816 bmap = isl_basic_map_intersect_domain(bmap, dom);817 sol->map = isl_map_grow(sol->map, 1);818 sol->map = isl_map_add_basic_map(sol->map, bmap);819 if (!sol->map)820 sol->sol.error = 1;821 return;822error:823 isl_basic_set_free(dom);824 isl_multi_aff_free(ma);825 sol->sol.error = 1;826}827 828static void sol_map_add_wrap(struct isl_sol *sol,829 __isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma)830{831 sol_map_add((struct isl_sol_map *)sol, dom, ma);832}833 834 835/* Store the "parametric constant" of row "row" of tableau "tab" in "line",836 * i.e., the constant term and the coefficients of all variables that837 * appear in the context tableau.838 * Note that the coefficient of the big parameter M is NOT copied.839 * The context tableau may not have a big parameter and even when it840 * does, it is a different big parameter.841 */842static void get_row_parameter_line(struct isl_tab *tab, int row, isl_int *line)843{844 int i;845 unsigned off = 2 + tab->M;846 847 isl_int_set(line[0], tab->mat->row[row][1]);848 for (i = 0; i < tab->n_param; ++i) {849 if (tab->var[i].is_row)850 isl_int_set_si(line[1 + i], 0);851 else {852 int col = tab->var[i].index;853 isl_int_set(line[1 + i], tab->mat->row[row][off + col]);854 }855 }856 for (i = 0; i < tab->n_div; ++i) {857 if (tab->var[tab->n_var - tab->n_div + i].is_row)858 isl_int_set_si(line[1 + tab->n_param + i], 0);859 else {860 int col = tab->var[tab->n_var - tab->n_div + i].index;861 isl_int_set(line[1 + tab->n_param + i],862 tab->mat->row[row][off + col]);863 }864 }865}866 867/* Check if rows "row1" and "row2" have identical "parametric constants",868 * as explained above.869 * In this case, we also insist that the coefficients of the big parameter870 * be the same as the values of the constants will only be the same871 * if these coefficients are also the same.872 */873static int identical_parameter_line(struct isl_tab *tab, int row1, int row2)874{875 int i;876 unsigned off = 2 + tab->M;877 878 if (isl_int_ne(tab->mat->row[row1][1], tab->mat->row[row2][1]))879 return 0;880 881 if (tab->M && isl_int_ne(tab->mat->row[row1][2],882 tab->mat->row[row2][2]))883 return 0;884 885 for (i = 0; i < tab->n_param + tab->n_div; ++i) {886 int pos = i < tab->n_param ? i :887 tab->n_var - tab->n_div + i - tab->n_param;888 int col;889 890 if (tab->var[pos].is_row)891 continue;892 col = tab->var[pos].index;893 if (isl_int_ne(tab->mat->row[row1][off + col],894 tab->mat->row[row2][off + col]))895 return 0;896 }897 return 1;898}899 900/* Return an inequality that expresses that the "parametric constant"901 * should be non-negative.902 * This function is only called when the coefficient of the big parameter903 * is equal to zero.904 */905static struct isl_vec *get_row_parameter_ineq(struct isl_tab *tab, int row)906{907 struct isl_vec *ineq;908 909 ineq = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_param + tab->n_div);910 if (!ineq)911 return NULL;912 913 get_row_parameter_line(tab, row, ineq->el);914 if (ineq)915 ineq = isl_vec_normalize(ineq);916 917 return ineq;918}919 920/* Normalize a div expression of the form921 *922 * [(g*f(x) + c)/(g * m)]923 *924 * with c the constant term and f(x) the remaining coefficients, to925 *926 * [(f(x) + [c/g])/m]927 */928static void normalize_div(__isl_keep isl_vec *div)929{930 isl_ctx *ctx = isl_vec_get_ctx(div);931 int len = div->size - 2;932 933 isl_seq_gcd(div->el + 2, len, &ctx->normalize_gcd);934 isl_int_gcd(ctx->normalize_gcd, ctx->normalize_gcd, div->el[0]);935 936 if (isl_int_is_one(ctx->normalize_gcd))937 return;938 939 isl_int_divexact(div->el[0], div->el[0], ctx->normalize_gcd);940 isl_int_fdiv_q(div->el[1], div->el[1], ctx->normalize_gcd);941 isl_seq_scale_down(div->el + 2, div->el + 2, ctx->normalize_gcd, len);942}943 944/* Return an integer division for use in a parametric cut based945 * on the given row.946 * In particular, let the parametric constant of the row be947 *948 * \sum_i a_i y_i949 *950 * where y_0 = 1, but none of the y_i corresponds to the big parameter M.951 * The div returned is equal to952 *953 * floor(\sum_i {-a_i} y_i) = floor((\sum_i (-a_i mod d) y_i)/d)954 */955static struct isl_vec *get_row_parameter_div(struct isl_tab *tab, int row)956{957 struct isl_vec *div;958 959 div = isl_vec_alloc(tab->mat->ctx, 1 + 1 + tab->n_param + tab->n_div);960 if (!div)961 return NULL;962 963 isl_int_set(div->el[0], tab->mat->row[row][0]);964 get_row_parameter_line(tab, row, div->el + 1);965 isl_seq_neg(div->el + 1, div->el + 1, div->size - 1);966 normalize_div(div);967 isl_seq_fdiv_r(div->el + 1, div->el + 1, div->el[0], div->size - 1);968 969 return div;970}971 972/* Return an integer division for use in transferring an integrality constraint973 * to the context.974 * In particular, let the parametric constant of the row be975 *976 * \sum_i a_i y_i977 *978 * where y_0 = 1, but none of the y_i corresponds to the big parameter M.979 * The the returned div is equal to980 *981 * floor(\sum_i {a_i} y_i) = floor((\sum_i (a_i mod d) y_i)/d)982 */983static struct isl_vec *get_row_split_div(struct isl_tab *tab, int row)984{985 struct isl_vec *div;986 987 div = isl_vec_alloc(tab->mat->ctx, 1 + 1 + tab->n_param + tab->n_div);988 if (!div)989 return NULL;990 991 isl_int_set(div->el[0], tab->mat->row[row][0]);992 get_row_parameter_line(tab, row, div->el + 1);993 normalize_div(div);994 isl_seq_fdiv_r(div->el + 1, div->el + 1, div->el[0], div->size - 1);995 996 return div;997}998 999/* Construct and return an inequality that expresses an upper bound1000 * on the given div.1001 * In particular, if the div is given by1002 *1003 * d = floor(e/m)1004 *1005 * then the inequality expresses1006 *1007 * m d <= e1008 */1009static __isl_give isl_vec *ineq_for_div(__isl_keep isl_basic_set *bset,1010 unsigned div)1011{1012 isl_size total;1013 unsigned div_pos;1014 struct isl_vec *ineq;1015 1016 total = isl_basic_set_dim(bset, isl_dim_all);1017 if (total < 0)1018 return NULL;1019 1020 div_pos = 1 + total - bset->n_div + div;1021 1022 ineq = isl_vec_alloc(bset->ctx, 1 + total);1023 if (!ineq)1024 return NULL;1025 1026 isl_seq_cpy(ineq->el, bset->div[div] + 1, 1 + total);1027 isl_int_neg(ineq->el[div_pos], bset->div[div][0]);1028 return ineq;1029}1030 1031/* Given a row in the tableau and a div that was created1032 * using get_row_split_div and that has been constrained to equality, i.e.,1033 *1034 * d = floor(\sum_i {a_i} y_i) = \sum_i {a_i} y_i1035 *1036 * replace the expression "\sum_i {a_i} y_i" in the row by d,1037 * i.e., we subtract "\sum_i {a_i} y_i" and add 1 d.1038 * The coefficients of the non-parameters in the tableau have been1039 * verified to be integral. We can therefore simply replace coefficient b1040 * by floor(b). For the coefficients of the parameters we have1041 * floor(a_i) = a_i - {a_i}, while for the other coefficients, we have1042 * floor(b) = b.1043 */1044static struct isl_tab *set_row_cst_to_div(struct isl_tab *tab, int row, int div)1045{1046 isl_seq_fdiv_q(tab->mat->row[row] + 1, tab->mat->row[row] + 1,1047 tab->mat->row[row][0], 1 + tab->M + tab->n_col);1048 1049 isl_int_set_si(tab->mat->row[row][0], 1);1050 1051 if (tab->var[tab->n_var - tab->n_div + div].is_row) {1052 int drow = tab->var[tab->n_var - tab->n_div + div].index;1053 1054 isl_assert(tab->mat->ctx,1055 isl_int_is_one(tab->mat->row[drow][0]), goto error);1056 isl_seq_combine(tab->mat->row[row] + 1,1057 tab->mat->ctx->one, tab->mat->row[row] + 1,1058 tab->mat->ctx->one, tab->mat->row[drow] + 1,1059 1 + tab->M + tab->n_col);1060 } else {1061 int dcol = tab->var[tab->n_var - tab->n_div + div].index;1062 1063 isl_int_add_ui(tab->mat->row[row][2 + tab->M + dcol],1064 tab->mat->row[row][2 + tab->M + dcol], 1);1065 }1066 1067 return tab;1068error:1069 isl_tab_free(tab);1070 return NULL;1071}1072 1073/* Check if the (parametric) constant of the given row is obviously1074 * negative, meaning that we don't need to consult the context tableau.1075 * If there is a big parameter and its coefficient is non-zero,1076 * then this coefficient determines the outcome.1077 * Otherwise, we check whether the constant is negative and1078 * all non-zero coefficients of parameters are negative and1079 * belong to non-negative parameters.1080 */1081static int is_obviously_neg(struct isl_tab *tab, int row)1082{1083 int i;1084 int col;1085 unsigned off = 2 + tab->M;1086 1087 if (tab->M) {1088 if (isl_int_is_pos(tab->mat->row[row][2]))1089 return 0;1090 if (isl_int_is_neg(tab->mat->row[row][2]))1091 return 1;1092 }1093 1094 if (isl_int_is_nonneg(tab->mat->row[row][1]))1095 return 0;1096 for (i = 0; i < tab->n_param; ++i) {1097 /* Eliminated parameter */1098 if (tab->var[i].is_row)1099 continue;1100 col = tab->var[i].index;1101 if (isl_int_is_zero(tab->mat->row[row][off + col]))1102 continue;1103 if (!tab->var[i].is_nonneg)1104 return 0;1105 if (isl_int_is_pos(tab->mat->row[row][off + col]))1106 return 0;1107 }1108 for (i = 0; i < tab->n_div; ++i) {1109 if (tab->var[tab->n_var - tab->n_div + i].is_row)1110 continue;1111 col = tab->var[tab->n_var - tab->n_div + i].index;1112 if (isl_int_is_zero(tab->mat->row[row][off + col]))1113 continue;1114 if (!tab->var[tab->n_var - tab->n_div + i].is_nonneg)1115 return 0;1116 if (isl_int_is_pos(tab->mat->row[row][off + col]))1117 return 0;1118 }1119 return 1;1120}1121 1122/* Check if the (parametric) constant of the given row is obviously1123 * non-negative, meaning that we don't need to consult the context tableau.1124 * If there is a big parameter and its coefficient is non-zero,1125 * then this coefficient determines the outcome.1126 * Otherwise, we check whether the constant is non-negative and1127 * all non-zero coefficients of parameters are positive and1128 * belong to non-negative parameters.1129 */1130static int is_obviously_nonneg(struct isl_tab *tab, int row)1131{1132 int i;1133 int col;1134 unsigned off = 2 + tab->M;1135 1136 if (tab->M) {1137 if (isl_int_is_pos(tab->mat->row[row][2]))1138 return 1;1139 if (isl_int_is_neg(tab->mat->row[row][2]))1140 return 0;1141 }1142 1143 if (isl_int_is_neg(tab->mat->row[row][1]))1144 return 0;1145 for (i = 0; i < tab->n_param; ++i) {1146 /* Eliminated parameter */1147 if (tab->var[i].is_row)1148 continue;1149 col = tab->var[i].index;1150 if (isl_int_is_zero(tab->mat->row[row][off + col]))1151 continue;1152 if (!tab->var[i].is_nonneg)1153 return 0;1154 if (isl_int_is_neg(tab->mat->row[row][off + col]))1155 return 0;1156 }1157 for (i = 0; i < tab->n_div; ++i) {1158 if (tab->var[tab->n_var - tab->n_div + i].is_row)1159 continue;1160 col = tab->var[tab->n_var - tab->n_div + i].index;1161 if (isl_int_is_zero(tab->mat->row[row][off + col]))1162 continue;1163 if (!tab->var[tab->n_var - tab->n_div + i].is_nonneg)1164 return 0;1165 if (isl_int_is_neg(tab->mat->row[row][off + col]))1166 return 0;1167 }1168 return 1;1169}1170 1171/* Given a row r and two columns, return the column that would1172 * lead to the lexicographically smallest increment in the sample1173 * solution when leaving the basis in favor of the row.1174 * Pivoting with column c will increment the sample value by a non-negative1175 * constant times a_{V,c}/a_{r,c}, with a_{V,c} the elements of column c1176 * corresponding to the non-parametric variables.1177 * If variable v appears in a column c_v, then a_{v,c} = 1 iff c = c_v,1178 * with all other entries in this virtual row equal to zero.1179 * If variable v appears in a row, then a_{v,c} is the element in column c1180 * of that row.1181 *1182 * Let v be the first variable with a_{v,c1}/a_{r,c1} != a_{v,c2}/a_{r,c2}.1183 * Then if a_{v,c1}/a_{r,c1} < a_{v,c2}/a_{r,c2}, i.e.,1184 * a_{v,c2} a_{r,c1} - a_{v,c1} a_{r,c2} > 0, c1 results in the minimal1185 * increment. Otherwise, it's c2.1186 */1187static int lexmin_col_pair(struct isl_tab *tab,1188 int row, int col1, int col2, isl_int tmp)1189{1190 int i;1191 isl_int *tr;1192 1193 tr = tab->mat->row[row] + 2 + tab->M;1194 1195 for (i = tab->n_param; i < tab->n_var - tab->n_div; ++i) {1196 int s1, s2;1197 isl_int *r;1198 1199 if (!tab->var[i].is_row) {1200 if (tab->var[i].index == col1)1201 return col2;1202 if (tab->var[i].index == col2)1203 return col1;1204 continue;1205 }1206 1207 if (tab->var[i].index == row)1208 continue;1209 1210 r = tab->mat->row[tab->var[i].index] + 2 + tab->M;1211 s1 = isl_int_sgn(r[col1]);1212 s2 = isl_int_sgn(r[col2]);1213 if (s1 == 0 && s2 == 0)1214 continue;1215 if (s1 < s2)1216 return col1;1217 if (s2 < s1)1218 return col2;1219 1220 isl_int_mul(tmp, r[col2], tr[col1]);1221 isl_int_submul(tmp, r[col1], tr[col2]);1222 if (isl_int_is_pos(tmp))1223 return col1;1224 if (isl_int_is_neg(tmp))1225 return col2;1226 }1227 return -1;1228}1229 1230/* Does the index into the tab->var or tab->con array "index"1231 * correspond to a variable in the context tableau?1232 * In particular, it needs to be an index into the tab->var array and1233 * it needs to refer to either one of the first tab->n_param variables or1234 * one of the last tab->n_div variables.1235 */1236static int is_parameter_var(struct isl_tab *tab, int index)1237{1238 if (index < 0)1239 return 0;1240 if (index < tab->n_param)1241 return 1;1242 if (index >= tab->n_var - tab->n_div)1243 return 1;1244 return 0;1245}1246 1247/* Does column "col" of "tab" refer to a variable in the context tableau?1248 */1249static int col_is_parameter_var(struct isl_tab *tab, int col)1250{1251 return is_parameter_var(tab, tab->col_var[col]);1252}1253 1254/* Does row "row" of "tab" refer to a variable in the context tableau?1255 */1256static int row_is_parameter_var(struct isl_tab *tab, int row)1257{1258 return is_parameter_var(tab, tab->row_var[row]);1259}1260 1261/* Given a row in the tableau, find and return the column that would1262 * result in the lexicographically smallest, but positive, increment1263 * in the sample point.1264 * If there is no such column, then return tab->n_col.1265 * If anything goes wrong, return -1.1266 */1267static int lexmin_pivot_col(struct isl_tab *tab, int row)1268{1269 int j;1270 int col = tab->n_col;1271 isl_int *tr;1272 isl_int tmp;1273 1274 tr = tab->mat->row[row] + 2 + tab->M;1275 1276 isl_int_init(tmp);1277 1278 for (j = tab->n_dead; j < tab->n_col; ++j) {1279 if (col_is_parameter_var(tab, j))1280 continue;1281 1282 if (!isl_int_is_pos(tr[j]))1283 continue;1284 1285 if (col == tab->n_col)1286 col = j;1287 else1288 col = lexmin_col_pair(tab, row, col, j, tmp);1289 isl_assert(tab->mat->ctx, col >= 0, goto error);1290 }1291 1292 isl_int_clear(tmp);1293 return col;1294error:1295 isl_int_clear(tmp);1296 return -1;1297}1298 1299/* Return the first known violated constraint, i.e., a non-negative1300 * constraint that currently has an either obviously negative value1301 * or a previously determined to be negative value.1302 *1303 * If any constraint has a negative coefficient for the big parameter,1304 * if any, then we return one of these first.1305 */1306static int first_neg(struct isl_tab *tab)1307{1308 int row;1309 1310 if (tab->M)1311 for (row = tab->n_redundant; row < tab->n_row; ++row) {1312 if (!isl_tab_var_from_row(tab, row)->is_nonneg)1313 continue;1314 if (!isl_int_is_neg(tab->mat->row[row][2]))1315 continue;1316 if (tab->row_sign)1317 tab->row_sign[row] = isl_tab_row_neg;1318 return row;1319 }1320 for (row = tab->n_redundant; row < tab->n_row; ++row) {1321 if (!isl_tab_var_from_row(tab, row)->is_nonneg)1322 continue;1323 if (tab->row_sign) {1324 if (tab->row_sign[row] == 0 &&1325 is_obviously_neg(tab, row))1326 tab->row_sign[row] = isl_tab_row_neg;1327 if (tab->row_sign[row] != isl_tab_row_neg)1328 continue;1329 } else if (!is_obviously_neg(tab, row))1330 continue;1331 return row;1332 }1333 return -1;1334}1335 1336/* Check whether the invariant that all columns are lexico-positive1337 * is satisfied. This function is not called from the current code1338 * but is useful during debugging.1339 */1340static void check_lexpos(struct isl_tab *tab) __attribute__ ((unused));1341static void check_lexpos(struct isl_tab *tab)1342{1343 unsigned off = 2 + tab->M;1344 int col;1345 int var;1346 int row;1347 1348 for (col = tab->n_dead; col < tab->n_col; ++col) {1349 if (col_is_parameter_var(tab, col))1350 continue;1351 for (var = tab->n_param; var < tab->n_var - tab->n_div; ++var) {1352 if (!tab->var[var].is_row) {1353 if (tab->var[var].index == col)1354 break;1355 else1356 continue;1357 }1358 row = tab->var[var].index;1359 if (isl_int_is_zero(tab->mat->row[row][off + col]))1360 continue;1361 if (isl_int_is_pos(tab->mat->row[row][off + col]))1362 break;1363 fprintf(stderr, "lexneg column %d (row %d)\n",1364 col, row);1365 }1366 if (var >= tab->n_var - tab->n_div)1367 fprintf(stderr, "zero column %d\n", col);1368 }1369}1370 1371/* Report to the caller that the given constraint is part of an encountered1372 * conflict.1373 */1374static int report_conflicting_constraint(struct isl_tab *tab, int con)1375{1376 return tab->conflict(con, tab->conflict_user);1377}1378 1379/* Given a conflicting row in the tableau, report all constraints1380 * involved in the row to the caller. That is, the row itself1381 * (if it represents a constraint) and all constraint columns with1382 * non-zero (and therefore negative) coefficients.1383 */1384static int report_conflict(struct isl_tab *tab, int row)1385{1386 int j;1387 isl_int *tr;1388 1389 if (!tab->conflict)1390 return 0;1391 1392 if (tab->row_var[row] < 0 &&1393 report_conflicting_constraint(tab, ~tab->row_var[row]) < 0)1394 return -1;1395 1396 tr = tab->mat->row[row] + 2 + tab->M;1397 1398 for (j = tab->n_dead; j < tab->n_col; ++j) {1399 if (col_is_parameter_var(tab, j))1400 continue;1401 1402 if (!isl_int_is_neg(tr[j]))1403 continue;1404 1405 if (tab->col_var[j] < 0 &&1406 report_conflicting_constraint(tab, ~tab->col_var[j]) < 0)1407 return -1;1408 }1409 1410 return 0;1411}1412 1413/* Resolve all known or obviously violated constraints through pivoting.1414 * In particular, as long as we can find any violated constraint, we1415 * look for a pivoting column that would result in the lexicographically1416 * smallest increment in the sample point. If there is no such column1417 * then the tableau is infeasible.1418 */1419static int restore_lexmin(struct isl_tab *tab) WARN_UNUSED;1420static int restore_lexmin(struct isl_tab *tab)1421{1422 int row, col;1423 1424 if (!tab)1425 return -1;1426 if (tab->empty)1427 return 0;1428 while ((row = first_neg(tab)) != -1) {1429 col = lexmin_pivot_col(tab, row);1430 if (col >= tab->n_col) {1431 if (report_conflict(tab, row) < 0)1432 return -1;1433 if (isl_tab_mark_empty(tab) < 0)1434 return -1;1435 return 0;1436 }1437 if (col < 0)1438 return -1;1439 if (isl_tab_pivot(tab, row, col) < 0)1440 return -1;1441 }1442 return 0;1443}1444 1445/* Given a row that represents an equality, look for an appropriate1446 * pivoting column.1447 * In particular, if there are any non-zero coefficients among1448 * the non-parameter variables, then we take the last of these1449 * variables. Eliminating this variable in terms of the other1450 * variables and/or parameters does not influence the property1451 * that all column in the initial tableau are lexicographically1452 * positive. The row corresponding to the eliminated variable1453 * will only have non-zero entries below the diagonal of the1454 * initial tableau. That is, we transform1455 *1456 * I I1457 * 1 into a1458 * I I1459 *1460 * If there is no such non-parameter variable, then we are dealing with1461 * pure parameter equality and we pick any parameter with coefficient 1 or -11462 * for elimination. This will ensure that the eliminated parameter1463 * always has an integer value whenever all the other parameters are integral.1464 * If there is no such parameter then we return -1.1465 */1466static int last_var_col_or_int_par_col(struct isl_tab *tab, int row)1467{1468 unsigned off = 2 + tab->M;1469 int i;1470 1471 for (i = tab->n_var - tab->n_div - 1; i >= 0 && i >= tab->n_param; --i) {1472 int col;1473 if (tab->var[i].is_row)1474 continue;1475 col = tab->var[i].index;1476 if (col <= tab->n_dead)1477 continue;1478 if (!isl_int_is_zero(tab->mat->row[row][off + col]))1479 return col;1480 }1481 for (i = tab->n_dead; i < tab->n_col; ++i) {1482 if (isl_int_is_one(tab->mat->row[row][off + i]))1483 return i;1484 if (isl_int_is_negone(tab->mat->row[row][off + i]))1485 return i;1486 }1487 return -1;1488}1489 1490/* Add an equality that is known to be valid to the tableau.1491 * We first check if we can eliminate a variable or a parameter.1492 * If not, we add the equality as two inequalities.1493 * In this case, the equality was a pure parameter equality and there1494 * is no need to resolve any constraint violations.1495 *1496 * This function assumes that at least two more rows and at least1497 * two more elements in the constraint array are available in the tableau.1498 */1499static struct isl_tab *add_lexmin_valid_eq(struct isl_tab *tab, isl_int *eq)1500{1501 int i;1502 int r;1503 1504 if (!tab)1505 return NULL;1506 r = isl_tab_add_row(tab, eq);1507 if (r < 0)1508 goto error;1509 1510 r = tab->con[r].index;1511 i = last_var_col_or_int_par_col(tab, r);1512 if (i < 0) {1513 tab->con[r].is_nonneg = 1;1514 if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)1515 goto error;1516 isl_seq_neg(eq, eq, 1 + tab->n_var);1517 r = isl_tab_add_row(tab, eq);1518 if (r < 0)1519 goto error;1520 tab->con[r].is_nonneg = 1;1521 if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)1522 goto error;1523 } else {1524 if (isl_tab_pivot(tab, r, i) < 0)1525 goto error;1526 if (isl_tab_kill_col(tab, i) < 0)1527 goto error;1528 tab->n_eq++;1529 }1530 1531 return tab;1532error:1533 isl_tab_free(tab);1534 return NULL;1535}1536 1537/* Check if the given row is a pure constant.1538 */1539static int is_constant(struct isl_tab *tab, int row)1540{1541 unsigned off = 2 + tab->M;1542 1543 return isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead,1544 tab->n_col - tab->n_dead) == -1;1545}1546 1547/* Is the given row a parametric constant?1548 * That is, does it only involve variables that also appear in the context?1549 */1550static int is_parametric_constant(struct isl_tab *tab, int row)1551{1552 unsigned off = 2 + tab->M;1553 int col;1554 1555 for (col = tab->n_dead; col < tab->n_col; ++col) {1556 if (col_is_parameter_var(tab, col))1557 continue;1558 if (isl_int_is_zero(tab->mat->row[row][off + col]))1559 continue;1560 return 0;1561 }1562 1563 return 1;1564}1565 1566/* Add an equality that may or may not be valid to the tableau.1567 * If the resulting row is a pure constant, then it must be zero.1568 * Otherwise, the resulting tableau is empty.1569 *1570 * If the row is not a pure constant, then we add two inequalities,1571 * each time checking that they can be satisfied.1572 * In the end we try to use one of the two constraints to eliminate1573 * a column.1574 *1575 * This function assumes that at least two more rows and at least1576 * two more elements in the constraint array are available in the tableau.1577 */1578static int add_lexmin_eq(struct isl_tab *tab, isl_int *eq) WARN_UNUSED;1579static int add_lexmin_eq(struct isl_tab *tab, isl_int *eq)1580{1581 int r1, r2;1582 int row;1583 struct isl_tab_undo *snap;1584 1585 if (!tab)1586 return -1;1587 snap = isl_tab_snap(tab);1588 r1 = isl_tab_add_row(tab, eq);1589 if (r1 < 0)1590 return -1;1591 tab->con[r1].is_nonneg = 1;1592 if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r1]) < 0)1593 return -1;1594 1595 row = tab->con[r1].index;1596 if (is_constant(tab, row)) {1597 if (!isl_int_is_zero(tab->mat->row[row][1]) ||1598 (tab->M && !isl_int_is_zero(tab->mat->row[row][2]))) {1599 if (isl_tab_mark_empty(tab) < 0)1600 return -1;1601 return 0;1602 }1603 if (isl_tab_rollback(tab, snap) < 0)1604 return -1;1605 return 0;1606 }1607 1608 if (restore_lexmin(tab) < 0)1609 return -1;1610 if (tab->empty)1611 return 0;1612 1613 isl_seq_neg(eq, eq, 1 + tab->n_var);1614 1615 r2 = isl_tab_add_row(tab, eq);1616 if (r2 < 0)1617 return -1;1618 tab->con[r2].is_nonneg = 1;1619 if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r2]) < 0)1620 return -1;1621 1622 if (restore_lexmin(tab) < 0)1623 return -1;1624 if (tab->empty)1625 return 0;1626 1627 if (!tab->con[r1].is_row) {1628 if (isl_tab_kill_col(tab, tab->con[r1].index) < 0)1629 return -1;1630 } else if (!tab->con[r2].is_row) {1631 if (isl_tab_kill_col(tab, tab->con[r2].index) < 0)1632 return -1;1633 }1634 1635 if (tab->bmap) {1636 tab->bmap = isl_basic_map_add_ineq(tab->bmap, eq);1637 if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)1638 return -1;1639 isl_seq_neg(eq, eq, 1 + tab->n_var);1640 tab->bmap = isl_basic_map_add_ineq(tab->bmap, eq);1641 isl_seq_neg(eq, eq, 1 + tab->n_var);1642 if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)1643 return -1;1644 if (!tab->bmap)1645 return -1;1646 }1647 1648 return 0;1649}1650 1651/* Add an inequality to the tableau, resolving violations using1652 * restore_lexmin.1653 *1654 * This function assumes that at least one more row and at least1655 * one more element in the constraint array are available in the tableau.1656 */1657static struct isl_tab *add_lexmin_ineq(struct isl_tab *tab, isl_int *ineq)1658{1659 int r;1660 1661 if (!tab)1662 return NULL;1663 if (tab->bmap) {1664 tab->bmap = isl_basic_map_add_ineq(tab->bmap, ineq);1665 if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)1666 goto error;1667 if (!tab->bmap)1668 goto error;1669 }1670 r = isl_tab_add_row(tab, ineq);1671 if (r < 0)1672 goto error;1673 tab->con[r].is_nonneg = 1;1674 if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)1675 goto error;1676 if (isl_tab_row_is_redundant(tab, tab->con[r].index)) {1677 if (isl_tab_mark_redundant(tab, tab->con[r].index) < 0)1678 goto error;1679 return tab;1680 }1681 1682 if (restore_lexmin(tab) < 0)1683 goto error;1684 if (!tab->empty && tab->con[r].is_row &&1685 isl_tab_row_is_redundant(tab, tab->con[r].index))1686 if (isl_tab_mark_redundant(tab, tab->con[r].index) < 0)1687 goto error;1688 return tab;1689error:1690 isl_tab_free(tab);1691 return NULL;1692}1693 1694/* Check if the coefficients of the parameters are all integral.1695 */1696static int integer_parameter(struct isl_tab *tab, int row)1697{1698 int i;1699 int col;1700 unsigned off = 2 + tab->M;1701 1702 for (i = 0; i < tab->n_param; ++i) {1703 /* Eliminated parameter */1704 if (tab->var[i].is_row)1705 continue;1706 col = tab->var[i].index;1707 if (!isl_int_is_divisible_by(tab->mat->row[row][off + col],1708 tab->mat->row[row][0]))1709 return 0;1710 }1711 for (i = 0; i < tab->n_div; ++i) {1712 if (tab->var[tab->n_var - tab->n_div + i].is_row)1713 continue;1714 col = tab->var[tab->n_var - tab->n_div + i].index;1715 if (!isl_int_is_divisible_by(tab->mat->row[row][off + col],1716 tab->mat->row[row][0]))1717 return 0;1718 }1719 return 1;1720}1721 1722/* Check if the coefficients of the non-parameter variables are all integral.1723 */1724static int integer_variable(struct isl_tab *tab, int row)1725{1726 int i;1727 unsigned off = 2 + tab->M;1728 1729 for (i = tab->n_dead; i < tab->n_col; ++i) {1730 if (col_is_parameter_var(tab, i))1731 continue;1732 if (!isl_int_is_divisible_by(tab->mat->row[row][off + i],1733 tab->mat->row[row][0]))1734 return 0;1735 }1736 return 1;1737}1738 1739/* Check if the constant term is integral.1740 */1741static int integer_constant(struct isl_tab *tab, int row)1742{1743 return isl_int_is_divisible_by(tab->mat->row[row][1],1744 tab->mat->row[row][0]);1745}1746 1747#define I_CST 1 << 01748#define I_PAR 1 << 11749#define I_VAR 1 << 21750 1751/* Check for next (non-parameter) variable after "var" (first if var == -1)1752 * that is non-integer and therefore requires a cut and return1753 * the index of the variable.1754 * For parametric tableaus, there are three parts in a row,1755 * the constant, the coefficients of the parameters and the rest.1756 * For each part, we check whether the coefficients in that part1757 * are all integral and if so, set the corresponding flag in *f.1758 * If the constant and the parameter part are integral, then the1759 * current sample value is integral and no cut is required1760 * (irrespective of whether the variable part is integral).1761 */1762static int next_non_integer_var(struct isl_tab *tab, int var, int *f)1763{1764 var = var < 0 ? tab->n_param : var + 1;1765 1766 for (; var < tab->n_var - tab->n_div; ++var) {1767 int flags = 0;1768 int row;1769 if (!tab->var[var].is_row)1770 continue;1771 row = tab->var[var].index;1772 if (integer_constant(tab, row))1773 ISL_FL_SET(flags, I_CST);1774 if (integer_parameter(tab, row))1775 ISL_FL_SET(flags, I_PAR);1776 if (ISL_FL_ISSET(flags, I_CST) && ISL_FL_ISSET(flags, I_PAR))1777 continue;1778 if (integer_variable(tab, row))1779 ISL_FL_SET(flags, I_VAR);1780 *f = flags;1781 return var;1782 }1783 return -1;1784}1785 1786/* Check for first (non-parameter) variable that is non-integer and1787 * therefore requires a cut and return the corresponding row.1788 * For parametric tableaus, there are three parts in a row,1789 * the constant, the coefficients of the parameters and the rest.1790 * For each part, we check whether the coefficients in that part1791 * are all integral and if so, set the corresponding flag in *f.1792 * If the constant and the parameter part are integral, then the1793 * current sample value is integral and no cut is required1794 * (irrespective of whether the variable part is integral).1795 */1796static int first_non_integer_row(struct isl_tab *tab, int *f)1797{1798 int var = next_non_integer_var(tab, -1, f);1799 1800 return var < 0 ? -1 : tab->var[var].index;1801}1802 1803/* Add a (non-parametric) cut to cut away the non-integral sample1804 * value of the given row.1805 *1806 * If the row is given by1807 *1808 * m r = f + \sum_i a_i y_i1809 *1810 * then the cut is1811 *1812 * c = - {-f/m} + \sum_i {a_i/m} y_i >= 01813 *1814 * The big parameter, if any, is ignored, since it is assumed to be big1815 * enough to be divisible by any integer.1816 * If the tableau is actually a parametric tableau, then this function1817 * is only called when all coefficients of the parameters are integral.1818 * The cut therefore has zero coefficients for the parameters.1819 *1820 * The current value is known to be negative, so row_sign, if it1821 * exists, is set accordingly.1822 *1823 * Return the row of the cut or -1.1824 */1825static int add_cut(struct isl_tab *tab, int row)1826{1827 int i;1828 int r;1829 isl_int *r_row;1830 unsigned off = 2 + tab->M;1831 1832 if (isl_tab_extend_cons(tab, 1) < 0)1833 return -1;1834 r = isl_tab_allocate_con(tab);1835 if (r < 0)1836 return -1;1837 1838 r_row = tab->mat->row[tab->con[r].index];1839 isl_int_set(r_row[0], tab->mat->row[row][0]);1840 isl_int_neg(r_row[1], tab->mat->row[row][1]);1841 isl_int_fdiv_r(r_row[1], r_row[1], tab->mat->row[row][0]);1842 isl_int_neg(r_row[1], r_row[1]);1843 if (tab->M)1844 isl_int_set_si(r_row[2], 0);1845 for (i = 0; i < tab->n_col; ++i)1846 isl_int_fdiv_r(r_row[off + i],1847 tab->mat->row[row][off + i], tab->mat->row[row][0]);1848 1849 tab->con[r].is_nonneg = 1;1850 if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)1851 return -1;1852 if (tab->row_sign)1853 tab->row_sign[tab->con[r].index] = isl_tab_row_neg;1854 1855 return tab->con[r].index;1856}1857 1858#define CUT_ALL 11859#define CUT_ONE 01860 1861/* Given a non-parametric tableau, add cuts until an integer1862 * sample point is obtained or until the tableau is determined1863 * to be integer infeasible.1864 * As long as there is any non-integer value in the sample point,1865 * we add appropriate cuts, if possible, for each of these1866 * non-integer values and then resolve the violated1867 * cut constraints using restore_lexmin.1868 * If one of the corresponding rows is equal to an integral1869 * combination of variables/constraints plus a non-integral constant,1870 * then there is no way to obtain an integer point and we return1871 * a tableau that is marked empty.1872 * The parameter cutting_strategy controls the strategy used when adding cuts1873 * to remove non-integer points. CUT_ALL adds all possible cuts1874 * before continuing the search. CUT_ONE adds only one cut at a time.1875 */1876static struct isl_tab *cut_to_integer_lexmin(struct isl_tab *tab,1877 int cutting_strategy)1878{1879 int var;1880 int row;1881 int flags;1882 1883 if (!tab)1884 return NULL;1885 if (tab->empty)1886 return tab;1887 1888 while ((var = next_non_integer_var(tab, -1, &flags)) != -1) {1889 do {1890 if (ISL_FL_ISSET(flags, I_VAR)) {1891 if (isl_tab_mark_empty(tab) < 0)1892 goto error;1893 return tab;1894 }1895 row = tab->var[var].index;1896 row = add_cut(tab, row);1897 if (row < 0)1898 goto error;1899 if (cutting_strategy == CUT_ONE)1900 break;1901 } while ((var = next_non_integer_var(tab, var, &flags)) != -1);1902 if (restore_lexmin(tab) < 0)1903 goto error;1904 if (tab->empty)1905 break;1906 }1907 return tab;1908error:1909 isl_tab_free(tab);1910 return NULL;1911}1912 1913/* Check whether all the currently active samples also satisfy the inequality1914 * "ineq" (treated as an equality if eq is set).1915 * Remove those samples that do not.1916 */1917static struct isl_tab *check_samples(struct isl_tab *tab, isl_int *ineq, int eq)1918{1919 int i;1920 isl_int v;1921 1922 if (!tab)1923 return NULL;1924 1925 isl_assert(tab->mat->ctx, tab->bmap, goto error);1926 isl_assert(tab->mat->ctx, tab->samples, goto error);1927 isl_assert(tab->mat->ctx, tab->samples->n_col == 1 + tab->n_var, goto error);1928 1929 isl_int_init(v);1930 for (i = tab->n_outside; i < tab->n_sample; ++i) {1931 int sgn;1932 isl_seq_inner_product(ineq, tab->samples->row[i],1933 1 + tab->n_var, &v);1934 sgn = isl_int_sgn(v);1935 if (eq ? (sgn == 0) : (sgn >= 0))1936 continue;1937 tab = isl_tab_drop_sample(tab, i);1938 if (!tab)1939 break;1940 }1941 isl_int_clear(v);1942 1943 return tab;1944error:1945 isl_tab_free(tab);1946 return NULL;1947}1948 1949/* Check whether the sample value of the tableau is finite,1950 * i.e., either the tableau does not use a big parameter, or1951 * all values of the variables are equal to the big parameter plus1952 * some constant. This constant is the actual sample value.1953 */1954static int sample_is_finite(struct isl_tab *tab)1955{1956 int i;1957 1958 if (!tab->M)1959 return 1;1960 1961 for (i = 0; i < tab->n_var; ++i) {1962 int row;1963 if (!tab->var[i].is_row)1964 return 0;1965 row = tab->var[i].index;1966 if (isl_int_ne(tab->mat->row[row][0], tab->mat->row[row][2]))1967 return 0;1968 }1969 return 1;1970}1971 1972/* Check if the context tableau of sol has any integer points.1973 * Leave tab in empty state if no integer point can be found.1974 * If an integer point can be found and if moreover it is finite,1975 * then it is added to the list of sample values.1976 *1977 * This function is only called when none of the currently active sample1978 * values satisfies the most recently added constraint.1979 */1980static struct isl_tab *check_integer_feasible(struct isl_tab *tab)1981{1982 struct isl_tab_undo *snap;1983 1984 if (!tab)1985 return NULL;1986 1987 snap = isl_tab_snap(tab);1988 if (isl_tab_push_basis(tab) < 0)1989 goto error;1990 1991 tab = cut_to_integer_lexmin(tab, CUT_ALL);1992 if (!tab)1993 goto error;1994 1995 if (!tab->empty && sample_is_finite(tab)) {1996 struct isl_vec *sample;1997 1998 sample = isl_tab_get_sample_value(tab);1999 2000 if (isl_tab_add_sample(tab, sample) < 0)2001 goto error;2002 }2003 2004 if (!tab->empty && isl_tab_rollback(tab, snap) < 0)2005 goto error;2006 2007 return tab;2008error:2009 isl_tab_free(tab);2010 return NULL;2011}2012 2013/* Check if any of the currently active sample values satisfies2014 * the inequality "ineq" (an equality if eq is set).2015 */2016static int tab_has_valid_sample(struct isl_tab *tab, isl_int *ineq, int eq)2017{2018 int i;2019 isl_int v;2020 2021 if (!tab)2022 return -1;2023 2024 isl_assert(tab->mat->ctx, tab->bmap, return -1);2025 isl_assert(tab->mat->ctx, tab->samples, return -1);2026 isl_assert(tab->mat->ctx, tab->samples->n_col == 1 + tab->n_var, return -1);2027 2028 isl_int_init(v);2029 for (i = tab->n_outside; i < tab->n_sample; ++i) {2030 int sgn;2031 isl_seq_inner_product(ineq, tab->samples->row[i],2032 1 + tab->n_var, &v);2033 sgn = isl_int_sgn(v);2034 if (eq ? (sgn == 0) : (sgn >= 0))2035 break;2036 }2037 isl_int_clear(v);2038 2039 return i < tab->n_sample;2040}2041 2042/* Insert a div specified by "div" to the tableau "tab" at position "pos" and2043 * return isl_bool_true if the div is obviously non-negative.2044 */2045static isl_bool context_tab_insert_div(struct isl_tab *tab, int pos,2046 __isl_keep isl_vec *div,2047 isl_stat (*add_ineq)(void *user, isl_int *), void *user)2048{2049 int i;2050 int r;2051 struct isl_mat *samples;2052 int nonneg;2053 2054 r = isl_tab_insert_div(tab, pos, div, add_ineq, user);2055 if (r < 0)2056 return isl_bool_error;2057 nonneg = tab->var[r].is_nonneg;2058 tab->var[r].frozen = 1;2059 2060 samples = isl_mat_extend(tab->samples,2061 tab->n_sample, 1 + tab->n_var);2062 tab->samples = samples;2063 if (!samples)2064 return isl_bool_error;2065 for (i = tab->n_outside; i < samples->n_row; ++i) {2066 isl_seq_inner_product(div->el + 1, samples->row[i],2067 div->size - 1, &samples->row[i][samples->n_col - 1]);2068 isl_int_fdiv_q(samples->row[i][samples->n_col - 1],2069 samples->row[i][samples->n_col - 1], div->el[0]);2070 }2071 tab->samples = isl_mat_move_cols(tab->samples, 1 + pos,2072 1 + tab->n_var - 1, 1);2073 if (!tab->samples)2074 return isl_bool_error;2075 2076 return isl_bool_ok(nonneg);2077}2078 2079/* Add a div specified by "div" to both the main tableau and2080 * the context tableau. In case of the main tableau, we only2081 * need to add an extra div. In the context tableau, we also2082 * need to express the meaning of the div.2083 * Return the index of the div or -1 if anything went wrong.2084 *2085 * The new integer division is added before any unknown integer2086 * divisions in the context to ensure that it does not get2087 * equated to some linear combination involving unknown integer2088 * divisions.2089 */2090static int add_div(struct isl_tab *tab, struct isl_context *context,2091 __isl_keep isl_vec *div)2092{2093 int r;2094 int pos;2095 isl_bool nonneg;2096 struct isl_tab *context_tab = context->op->peek_tab(context);2097 2098 if (!tab || !context_tab)2099 goto error;2100 2101 pos = context_tab->n_var - context->n_unknown;2102 if ((nonneg = context->op->insert_div(context, pos, div)) < 0)2103 goto error;2104 2105 if (!context->op->is_ok(context))2106 goto error;2107 2108 pos = tab->n_var - context->n_unknown;2109 if (isl_tab_extend_vars(tab, 1) < 0)2110 goto error;2111 r = isl_tab_insert_var(tab, pos);2112 if (r < 0)2113 goto error;2114 if (nonneg)2115 tab->var[r].is_nonneg = 1;2116 tab->var[r].frozen = 1;2117 tab->n_div++;2118 2119 return tab->n_div - 1 - context->n_unknown;2120error:2121 context->op->invalidate(context);2122 return -1;2123}2124 2125/* Return the position of the integer division that is equal to div/denom2126 * if there is one. Otherwise, return a position beyond the integer divisions.2127 */2128static int find_div(struct isl_tab *tab, isl_int *div, isl_int denom)2129{2130 int i;2131 isl_size total = isl_basic_map_dim(tab->bmap, isl_dim_all);2132 isl_size n_div;2133 2134 n_div = isl_basic_map_dim(tab->bmap, isl_dim_div);2135 if (total < 0 || n_div < 0)2136 return -1;2137 for (i = 0; i < n_div; ++i) {2138 if (isl_int_ne(tab->bmap->div[i][0], denom))2139 continue;2140 if (!isl_seq_eq(tab->bmap->div[i] + 1, div, 1 + total))2141 continue;2142 return i;2143 }2144 return n_div;2145}2146 2147/* Return the index of a div that corresponds to "div".2148 * We first check if we already have such a div and if not, we create one.2149 */2150static int get_div(struct isl_tab *tab, struct isl_context *context,2151 struct isl_vec *div)2152{2153 int d;2154 struct isl_tab *context_tab = context->op->peek_tab(context);2155 unsigned n_div;2156 2157 if (!context_tab)2158 return -1;2159 2160 n_div = isl_basic_map_dim(context_tab->bmap, isl_dim_div);2161 d = find_div(context_tab, div->el + 1, div->el[0]);2162 if (d < 0)2163 return -1;2164 if (d < n_div)2165 return d;2166 2167 return add_div(tab, context, div);2168}2169 2170/* Add a parametric cut to cut away the non-integral sample value2171 * of the given row.2172 * Let a_i be the coefficients of the constant term and the parameters2173 * and let b_i be the coefficients of the variables or constraints2174 * in basis of the tableau.2175 * Let q be the div q = floor(\sum_i {-a_i} y_i).2176 *2177 * The cut is expressed as2178 *2179 * c = \sum_i -{-a_i} y_i + \sum_i {b_i} x_i + q >= 02180 *2181 * If q did not already exist in the context tableau, then it is added first.2182 * If q is in a column of the main tableau then the "+ q" can be accomplished2183 * by setting the corresponding entry to the denominator of the constraint.2184 * If q happens to be in a row of the main tableau, then the corresponding2185 * row needs to be added instead (taking care of the denominators).2186 * Note that this is very unlikely, but perhaps not entirely impossible.2187 *2188 * The current value of the cut is known to be negative (or at least2189 * non-positive), so row_sign is set accordingly.2190 *2191 * Return the row of the cut or -1.2192 */2193static int add_parametric_cut(struct isl_tab *tab, int row,2194 struct isl_context *context)2195{2196 struct isl_vec *div;2197 int d;2198 int i;2199 int r;2200 isl_int *r_row;2201 int col;2202 int n;2203 unsigned off = 2 + tab->M;2204 2205 if (!context)2206 return -1;2207 2208 div = get_row_parameter_div(tab, row);2209 if (!div)2210 return -1;2211 2212 n = tab->n_div - context->n_unknown;2213 d = context->op->get_div(context, tab, div);2214 isl_vec_free(div);2215 if (d < 0)2216 return -1;2217 2218 if (isl_tab_extend_cons(tab, 1) < 0)2219 return -1;2220 r = isl_tab_allocate_con(tab);2221 if (r < 0)2222 return -1;2223 2224 r_row = tab->mat->row[tab->con[r].index];2225 isl_int_set(r_row[0], tab->mat->row[row][0]);2226 isl_int_neg(r_row[1], tab->mat->row[row][1]);2227 isl_int_fdiv_r(r_row[1], r_row[1], tab->mat->row[row][0]);2228 isl_int_neg(r_row[1], r_row[1]);2229 if (tab->M)2230 isl_int_set_si(r_row[2], 0);2231 for (i = 0; i < tab->n_param; ++i) {2232 if (tab->var[i].is_row)2233 continue;2234 col = tab->var[i].index;2235 isl_int_neg(r_row[off + col], tab->mat->row[row][off + col]);2236 isl_int_fdiv_r(r_row[off + col], r_row[off + col],2237 tab->mat->row[row][0]);2238 isl_int_neg(r_row[off + col], r_row[off + col]);2239 }2240 for (i = 0; i < tab->n_div; ++i) {2241 if (tab->var[tab->n_var - tab->n_div + i].is_row)2242 continue;2243 col = tab->var[tab->n_var - tab->n_div + i].index;2244 isl_int_neg(r_row[off + col], tab->mat->row[row][off + col]);2245 isl_int_fdiv_r(r_row[off + col], r_row[off + col],2246 tab->mat->row[row][0]);2247 isl_int_neg(r_row[off + col], r_row[off + col]);2248 }2249 for (i = 0; i < tab->n_col; ++i) {2250 if (tab->col_var[i] >= 0 &&2251 (tab->col_var[i] < tab->n_param ||2252 tab->col_var[i] >= tab->n_var - tab->n_div))2253 continue;2254 isl_int_fdiv_r(r_row[off + i],2255 tab->mat->row[row][off + i], tab->mat->row[row][0]);2256 }2257 if (tab->var[tab->n_var - tab->n_div + d].is_row) {2258 isl_int gcd;2259 int d_row = tab->var[tab->n_var - tab->n_div + d].index;2260 isl_int_init(gcd);2261 isl_int_gcd(gcd, tab->mat->row[d_row][0], r_row[0]);2262 isl_int_divexact(r_row[0], r_row[0], gcd);2263 isl_int_divexact(gcd, tab->mat->row[d_row][0], gcd);2264 isl_seq_combine(r_row + 1, gcd, r_row + 1,2265 r_row[0], tab->mat->row[d_row] + 1,2266 off - 1 + tab->n_col);2267 isl_int_mul(r_row[0], r_row[0], tab->mat->row[d_row][0]);2268 isl_int_clear(gcd);2269 } else {2270 col = tab->var[tab->n_var - tab->n_div + d].index;2271 isl_int_set(r_row[off + col], tab->mat->row[row][0]);2272 }2273 2274 tab->con[r].is_nonneg = 1;2275 if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)2276 return -1;2277 if (tab->row_sign)2278 tab->row_sign[tab->con[r].index] = isl_tab_row_neg;2279 2280 row = tab->con[r].index;2281 2282 if (d >= n && context->op->detect_equalities(context, tab) < 0)2283 return -1;2284 2285 return row;2286}2287 2288/* Construct a tableau for bmap that can be used for computing2289 * the lexicographic minimum (or maximum) of bmap.2290 * If not NULL, then dom is the domain where the minimum2291 * should be computed. In this case, we set up a parametric2292 * tableau with row signs (initialized to "unknown").2293 * If M is set, then the tableau will use a big parameter.2294 * If max is set, then a maximum should be computed instead of a minimum.2295 * This means that for each variable x, the tableau will contain the variable2296 * x' = M - x, rather than x' = M + x. This in turn means that the coefficient2297 * of the variables in all constraints are negated prior to adding them2298 * to the tableau.2299 */2300static __isl_give struct isl_tab *tab_for_lexmin(__isl_keep isl_basic_map *bmap,2301 __isl_keep isl_basic_set *dom, unsigned M, int max)2302{2303 int i;2304 struct isl_tab *tab;2305 unsigned n_var;2306 unsigned o_var;2307 isl_size total;2308 2309 total = isl_basic_map_dim(bmap, isl_dim_all);2310 if (total < 0)2311 return NULL;2312 tab = isl_tab_alloc(bmap->ctx, 2 * bmap->n_eq + bmap->n_ineq + 1,2313 total, M);2314 if (!tab)2315 return NULL;2316 2317 tab->rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);2318 if (dom) {2319 isl_size dom_total;2320 dom_total = isl_basic_set_dim(dom, isl_dim_all);2321 if (dom_total < 0)2322 goto error;2323 tab->n_param = dom_total - dom->n_div;2324 tab->n_div = dom->n_div;2325 tab->row_sign = isl_calloc_array(bmap->ctx,2326 enum isl_tab_row_sign, tab->mat->n_row);2327 if (tab->mat->n_row && !tab->row_sign)2328 goto error;2329 }2330 if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) {2331 if (isl_tab_mark_empty(tab) < 0)2332 goto error;2333 return tab;2334 }2335 2336 for (i = tab->n_param; i < tab->n_var - tab->n_div; ++i) {2337 tab->var[i].is_nonneg = 1;2338 tab->var[i].frozen = 1;2339 }2340 o_var = 1 + tab->n_param;2341 n_var = tab->n_var - tab->n_param - tab->n_div;2342 for (i = 0; i < bmap->n_eq; ++i) {2343 if (max)2344 isl_seq_neg(bmap->eq[i] + o_var,2345 bmap->eq[i] + o_var, n_var);2346 tab = add_lexmin_valid_eq(tab, bmap->eq[i]);2347 if (max)2348 isl_seq_neg(bmap->eq[i] + o_var,2349 bmap->eq[i] + o_var, n_var);2350 if (!tab || tab->empty)2351 return tab;2352 }2353 if (bmap->n_eq && restore_lexmin(tab) < 0)2354 goto error;2355 for (i = 0; i < bmap->n_ineq; ++i) {2356 if (max)2357 isl_seq_neg(bmap->ineq[i] + o_var,2358 bmap->ineq[i] + o_var, n_var);2359 tab = add_lexmin_ineq(tab, bmap->ineq[i]);2360 if (max)2361 isl_seq_neg(bmap->ineq[i] + o_var,2362 bmap->ineq[i] + o_var, n_var);2363 if (!tab || tab->empty)2364 return tab;2365 }2366 return tab;2367error:2368 isl_tab_free(tab);2369 return NULL;2370}2371 2372/* Given a main tableau where more than one row requires a split,2373 * determine and return the "best" row to split on.2374 *2375 * If any of the rows requiring a split only involves2376 * variables that also appear in the context tableau,2377 * then the negative part is guaranteed not to have a solution.2378 * It is therefore best to split on any of these rows first.2379 *2380 * Otherwise,2381 * given two rows in the main tableau, if the inequality corresponding2382 * to the first row is redundant with respect to that of the second row2383 * in the current tableau, then it is better to split on the second row,2384 * since in the positive part, both rows will be positive.2385 * (In the negative part a pivot will have to be performed and just about2386 * anything can happen to the sign of the other row.)2387 *2388 * As a simple heuristic, we therefore select the row that makes the most2389 * of the other rows redundant.2390 *2391 * Perhaps it would also be useful to look at the number of constraints2392 * that conflict with any given constraint.2393 *2394 * best is the best row so far (-1 when we have not found any row yet).2395 * best_r is the number of other rows made redundant by row best.2396 * When best is still -1, bset_r is meaningless, but it is initialized2397 * to some arbitrary value (0) anyway. Without this redundant initialization2398 * valgrind may warn about uninitialized memory accesses when isl2399 * is compiled with some versions of gcc.2400 */2401static int best_split(struct isl_tab *tab, struct isl_tab *context_tab)2402{2403 struct isl_tab_undo *snap;2404 int split;2405 int row;2406 int best = -1;2407 int best_r = 0;2408 2409 if (isl_tab_extend_cons(context_tab, 2) < 0)2410 return -1;2411 2412 snap = isl_tab_snap(context_tab);2413 2414 for (split = tab->n_redundant; split < tab->n_row; ++split) {2415 struct isl_tab_undo *snap2;2416 struct isl_vec *ineq = NULL;2417 int r = 0;2418 int ok;2419 2420 if (!isl_tab_var_from_row(tab, split)->is_nonneg)2421 continue;2422 if (tab->row_sign[split] != isl_tab_row_any)2423 continue;2424 2425 if (is_parametric_constant(tab, split))2426 return split;2427 2428 ineq = get_row_parameter_ineq(tab, split);2429 if (!ineq)2430 return -1;2431 ok = isl_tab_add_ineq(context_tab, ineq->el) >= 0;2432 isl_vec_free(ineq);2433 if (!ok)2434 return -1;2435 2436 snap2 = isl_tab_snap(context_tab);2437 2438 for (row = tab->n_redundant; row < tab->n_row; ++row) {2439 struct isl_tab_var *var;2440 2441 if (row == split)2442 continue;2443 if (!isl_tab_var_from_row(tab, row)->is_nonneg)2444 continue;2445 if (tab->row_sign[row] != isl_tab_row_any)2446 continue;2447 2448 ineq = get_row_parameter_ineq(tab, row);2449 if (!ineq)2450 return -1;2451 ok = isl_tab_add_ineq(context_tab, ineq->el) >= 0;2452 isl_vec_free(ineq);2453 if (!ok)2454 return -1;2455 var = &context_tab->con[context_tab->n_con - 1];2456 if (!context_tab->empty &&2457 !isl_tab_min_at_most_neg_one(context_tab, var))2458 r++;2459 if (isl_tab_rollback(context_tab, snap2) < 0)2460 return -1;2461 }2462 if (best == -1 || r > best_r) {2463 best = split;2464 best_r = r;2465 }2466 if (isl_tab_rollback(context_tab, snap) < 0)2467 return -1;2468 }2469 2470 return best;2471}2472 2473static struct isl_basic_set *context_lex_peek_basic_set(2474 struct isl_context *context)2475{2476 struct isl_context_lex *clex = (struct isl_context_lex *)context;2477 if (!clex->tab)2478 return NULL;2479 return isl_tab_peek_bset(clex->tab);2480}2481 2482static struct isl_tab *context_lex_peek_tab(struct isl_context *context)2483{2484 struct isl_context_lex *clex = (struct isl_context_lex *)context;2485 return clex->tab;2486}2487 2488static void context_lex_add_eq(struct isl_context *context, isl_int *eq,2489 int check, int update)2490{2491 struct isl_context_lex *clex = (struct isl_context_lex *)context;2492 if (isl_tab_extend_cons(clex->tab, 2) < 0)2493 goto error;2494 if (add_lexmin_eq(clex->tab, eq) < 0)2495 goto error;2496 if (check) {2497 int v = tab_has_valid_sample(clex->tab, eq, 1);2498 if (v < 0)2499 goto error;2500 if (!v)2501 clex->tab = check_integer_feasible(clex->tab);2502 }2503 if (update)2504 clex->tab = check_samples(clex->tab, eq, 1);2505 return;2506error:2507 isl_tab_free(clex->tab);2508 clex->tab = NULL;2509}2510 2511static void context_lex_add_ineq(struct isl_context *context, isl_int *ineq,2512 int check, int update)2513{2514 struct isl_context_lex *clex = (struct isl_context_lex *)context;2515 if (isl_tab_extend_cons(clex->tab, 1) < 0)2516 goto error;2517 clex->tab = add_lexmin_ineq(clex->tab, ineq);2518 if (check) {2519 int v = tab_has_valid_sample(clex->tab, ineq, 0);2520 if (v < 0)2521 goto error;2522 if (!v)2523 clex->tab = check_integer_feasible(clex->tab);2524 }2525 if (update)2526 clex->tab = check_samples(clex->tab, ineq, 0);2527 return;2528error:2529 isl_tab_free(clex->tab);2530 clex->tab = NULL;2531}2532 2533static isl_stat context_lex_add_ineq_wrap(void *user, isl_int *ineq)2534{2535 struct isl_context *context = (struct isl_context *)user;2536 context_lex_add_ineq(context, ineq, 0, 0);2537 return context->op->is_ok(context) ? isl_stat_ok : isl_stat_error;2538}2539 2540/* Check which signs can be obtained by "ineq" on all the currently2541 * active sample values. See row_sign for more information.2542 */2543static enum isl_tab_row_sign tab_ineq_sign(struct isl_tab *tab, isl_int *ineq,2544 int strict)2545{2546 int i;2547 int sgn;2548 isl_int tmp;2549 enum isl_tab_row_sign res = isl_tab_row_unknown;2550 2551 isl_assert(tab->mat->ctx, tab->samples, return isl_tab_row_unknown);2552 isl_assert(tab->mat->ctx, tab->samples->n_col == 1 + tab->n_var,2553 return isl_tab_row_unknown);2554 2555 isl_int_init(tmp);2556 for (i = tab->n_outside; i < tab->n_sample; ++i) {2557 isl_seq_inner_product(tab->samples->row[i], ineq,2558 1 + tab->n_var, &tmp);2559 sgn = isl_int_sgn(tmp);2560 if (sgn > 0 || (sgn == 0 && strict)) {2561 if (res == isl_tab_row_unknown)2562 res = isl_tab_row_pos;2563 if (res == isl_tab_row_neg)2564 res = isl_tab_row_any;2565 }2566 if (sgn < 0) {2567 if (res == isl_tab_row_unknown)2568 res = isl_tab_row_neg;2569 if (res == isl_tab_row_pos)2570 res = isl_tab_row_any;2571 }2572 if (res == isl_tab_row_any)2573 break;2574 }2575 isl_int_clear(tmp);2576 2577 return res;2578}2579 2580static enum isl_tab_row_sign context_lex_ineq_sign(struct isl_context *context,2581 isl_int *ineq, int strict)2582{2583 struct isl_context_lex *clex = (struct isl_context_lex *)context;2584 return tab_ineq_sign(clex->tab, ineq, strict);2585}2586 2587/* Check whether "ineq" can be added to the tableau without rendering2588 * it infeasible.2589 */2590static int context_lex_test_ineq(struct isl_context *context, isl_int *ineq)2591{2592 struct isl_context_lex *clex = (struct isl_context_lex *)context;2593 struct isl_tab_undo *snap;2594 int feasible;2595 2596 if (!clex->tab)2597 return -1;2598 2599 if (isl_tab_extend_cons(clex->tab, 1) < 0)2600 return -1;2601 2602 snap = isl_tab_snap(clex->tab);2603 if (isl_tab_push_basis(clex->tab) < 0)2604 return -1;2605 clex->tab = add_lexmin_ineq(clex->tab, ineq);2606 clex->tab = check_integer_feasible(clex->tab);2607 if (!clex->tab)2608 return -1;2609 feasible = !clex->tab->empty;2610 if (isl_tab_rollback(clex->tab, snap) < 0)2611 return -1;2612 2613 return feasible;2614}2615 2616static int context_lex_get_div(struct isl_context *context, struct isl_tab *tab,2617 struct isl_vec *div)2618{2619 return get_div(tab, context, div);2620}2621 2622/* Insert a div specified by "div" to the context tableau at position "pos" and2623 * return isl_bool_true if the div is obviously non-negative.2624 * context_tab_add_div will always return isl_bool_true, because all variables2625 * in a isl_context_lex tableau are non-negative.2626 * However, if we are using a big parameter in the context, then this only2627 * reflects the non-negativity of the variable used to _encode_ the2628 * div, i.e., div' = M + div, so we can't draw any conclusions.2629 */2630static isl_bool context_lex_insert_div(struct isl_context *context, int pos,2631 __isl_keep isl_vec *div)2632{2633 struct isl_context_lex *clex = (struct isl_context_lex *)context;2634 isl_bool nonneg;2635 nonneg = context_tab_insert_div(clex->tab, pos, div,2636 context_lex_add_ineq_wrap, context);2637 if (nonneg < 0)2638 return isl_bool_error;2639 if (clex->tab->M)2640 return isl_bool_false;2641 return nonneg;2642}2643 2644static int context_lex_detect_equalities(struct isl_context *context,2645 struct isl_tab *tab)2646{2647 return 0;2648}2649 2650static int context_lex_best_split(struct isl_context *context,2651 struct isl_tab *tab)2652{2653 struct isl_context_lex *clex = (struct isl_context_lex *)context;2654 struct isl_tab_undo *snap;2655 int r;2656 2657 snap = isl_tab_snap(clex->tab);2658 if (isl_tab_push_basis(clex->tab) < 0)2659 return -1;2660 r = best_split(tab, clex->tab);2661 2662 if (r >= 0 && isl_tab_rollback(clex->tab, snap) < 0)2663 return -1;2664 2665 return r;2666}2667 2668static int context_lex_is_empty(struct isl_context *context)2669{2670 struct isl_context_lex *clex = (struct isl_context_lex *)context;2671 if (!clex->tab)2672 return -1;2673 return clex->tab->empty;2674}2675 2676static void *context_lex_save(struct isl_context *context)2677{2678 struct isl_context_lex *clex = (struct isl_context_lex *)context;2679 struct isl_tab_undo *snap;2680 2681 snap = isl_tab_snap(clex->tab);2682 if (isl_tab_push_basis(clex->tab) < 0)2683 return NULL;2684 if (isl_tab_save_samples(clex->tab) < 0)2685 return NULL;2686 2687 return snap;2688}2689 2690static void context_lex_restore(struct isl_context *context, void *save)2691{2692 struct isl_context_lex *clex = (struct isl_context_lex *)context;2693 if (isl_tab_rollback(clex->tab, (struct isl_tab_undo *)save) < 0) {2694 isl_tab_free(clex->tab);2695 clex->tab = NULL;2696 }2697}2698 2699static void context_lex_discard(void *save)2700{2701}2702 2703static int context_lex_is_ok(struct isl_context *context)2704{2705 struct isl_context_lex *clex = (struct isl_context_lex *)context;2706 return !!clex->tab;2707}2708 2709/* For each variable in the context tableau, check if the variable can2710 * only attain non-negative values. If so, mark the parameter as non-negative2711 * in the main tableau. This allows for a more direct identification of some2712 * cases of violated constraints.2713 */2714static struct isl_tab *tab_detect_nonnegative_parameters(struct isl_tab *tab,2715 struct isl_tab *context_tab)2716{2717 int i;2718 struct isl_tab_undo *snap;2719 struct isl_vec *ineq = NULL;2720 struct isl_tab_var *var;2721 int n;2722 2723 if (context_tab->n_var == 0)2724 return tab;2725 2726 ineq = isl_vec_alloc(tab->mat->ctx, 1 + context_tab->n_var);2727 if (!ineq)2728 goto error;2729 2730 if (isl_tab_extend_cons(context_tab, 1) < 0)2731 goto error;2732 2733 snap = isl_tab_snap(context_tab);2734 2735 n = 0;2736 isl_seq_clr(ineq->el, ineq->size);2737 for (i = 0; i < context_tab->n_var; ++i) {2738 isl_int_set_si(ineq->el[1 + i], 1);2739 if (isl_tab_add_ineq(context_tab, ineq->el) < 0)2740 goto error;2741 var = &context_tab->con[context_tab->n_con - 1];2742 if (!context_tab->empty &&2743 !isl_tab_min_at_most_neg_one(context_tab, var)) {2744 int j = i;2745 if (i >= tab->n_param)2746 j = i - tab->n_param + tab->n_var - tab->n_div;2747 tab->var[j].is_nonneg = 1;2748 n++;2749 }2750 isl_int_set_si(ineq->el[1 + i], 0);2751 if (isl_tab_rollback(context_tab, snap) < 0)2752 goto error;2753 }2754 2755 if (context_tab->M && n == context_tab->n_var) {2756 context_tab->mat = isl_mat_drop_cols(context_tab->mat, 2, 1);2757 context_tab->M = 0;2758 }2759 2760 isl_vec_free(ineq);2761 return tab;2762error:2763 isl_vec_free(ineq);2764 isl_tab_free(tab);2765 return NULL;2766}2767 2768static struct isl_tab *context_lex_detect_nonnegative_parameters(2769 struct isl_context *context, struct isl_tab *tab)2770{2771 struct isl_context_lex *clex = (struct isl_context_lex *)context;2772 struct isl_tab_undo *snap;2773 2774 if (!tab)2775 return NULL;2776 2777 snap = isl_tab_snap(clex->tab);2778 if (isl_tab_push_basis(clex->tab) < 0)2779 goto error;2780 2781 tab = tab_detect_nonnegative_parameters(tab, clex->tab);2782 2783 if (isl_tab_rollback(clex->tab, snap) < 0)2784 goto error;2785 2786 return tab;2787error:2788 isl_tab_free(tab);2789 return NULL;2790}2791 2792static void context_lex_invalidate(struct isl_context *context)2793{2794 struct isl_context_lex *clex = (struct isl_context_lex *)context;2795 isl_tab_free(clex->tab);2796 clex->tab = NULL;2797}2798 2799static __isl_null struct isl_context *context_lex_free(2800 struct isl_context *context)2801{2802 struct isl_context_lex *clex = (struct isl_context_lex *)context;2803 isl_tab_free(clex->tab);2804 free(clex);2805 2806 return NULL;2807}2808 2809struct isl_context_op isl_context_lex_op = {2810 context_lex_detect_nonnegative_parameters,2811 context_lex_peek_basic_set,2812 context_lex_peek_tab,2813 context_lex_add_eq,2814 context_lex_add_ineq,2815 context_lex_ineq_sign,2816 context_lex_test_ineq,2817 context_lex_get_div,2818 context_lex_insert_div,2819 context_lex_detect_equalities,2820 context_lex_best_split,2821 context_lex_is_empty,2822 context_lex_is_ok,2823 context_lex_save,2824 context_lex_restore,2825 context_lex_discard,2826 context_lex_invalidate,2827 context_lex_free,2828};2829 2830static struct isl_tab *context_tab_for_lexmin(__isl_take isl_basic_set *bset)2831{2832 struct isl_tab *tab;2833 2834 if (!bset)2835 return NULL;2836 tab = tab_for_lexmin(bset_to_bmap(bset), NULL, 1, 0);2837 if (isl_tab_track_bset(tab, bset) < 0)2838 goto error;2839 tab = isl_tab_init_samples(tab);2840 return tab;2841error:2842 isl_tab_free(tab);2843 return NULL;2844}2845 2846static struct isl_context *isl_context_lex_alloc(struct isl_basic_set *dom)2847{2848 struct isl_context_lex *clex;2849 2850 if (!dom)2851 return NULL;2852 2853 clex = isl_alloc_type(dom->ctx, struct isl_context_lex);2854 if (!clex)2855 return NULL;2856 2857 clex->context.op = &isl_context_lex_op;2858 2859 clex->tab = context_tab_for_lexmin(isl_basic_set_copy(dom));2860 if (restore_lexmin(clex->tab) < 0)2861 goto error;2862 clex->tab = check_integer_feasible(clex->tab);2863 if (!clex->tab)2864 goto error;2865 2866 return &clex->context;2867error:2868 clex->context.op->free(&clex->context);2869 return NULL;2870}2871 2872/* Representation of the context when using generalized basis reduction.2873 *2874 * "shifted" contains the offsets of the unit hypercubes that lie inside the2875 * context. Any rational point in "shifted" can therefore be rounded2876 * up to an integer point in the context.2877 * If the context is constrained by any equality, then "shifted" is not used2878 * as it would be empty.2879 */2880struct isl_context_gbr {2881 struct isl_context context;2882 struct isl_tab *tab;2883 struct isl_tab *shifted;2884 struct isl_tab *cone;2885};2886 2887static struct isl_tab *context_gbr_detect_nonnegative_parameters(2888 struct isl_context *context, struct isl_tab *tab)2889{2890 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;2891 if (!tab)2892 return NULL;2893 return tab_detect_nonnegative_parameters(tab, cgbr->tab);2894}2895 2896static struct isl_basic_set *context_gbr_peek_basic_set(2897 struct isl_context *context)2898{2899 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;2900 if (!cgbr->tab)2901 return NULL;2902 return isl_tab_peek_bset(cgbr->tab);2903}2904 2905static struct isl_tab *context_gbr_peek_tab(struct isl_context *context)2906{2907 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;2908 return cgbr->tab;2909}2910 2911/* Initialize the "shifted" tableau of the context, which2912 * contains the constraints of the original tableau shifted2913 * by the sum of all negative coefficients. This ensures2914 * that any rational point in the shifted tableau can2915 * be rounded up to yield an integer point in the original tableau.2916 */2917static void gbr_init_shifted(struct isl_context_gbr *cgbr)2918{2919 int i, j;2920 struct isl_vec *cst;2921 struct isl_basic_set *bset = isl_tab_peek_bset(cgbr->tab);2922 isl_size dim = isl_basic_set_dim(bset, isl_dim_all);2923 2924 if (dim < 0)2925 return;2926 cst = isl_vec_alloc(cgbr->tab->mat->ctx, bset->n_ineq);2927 if (!cst)2928 return;2929 2930 for (i = 0; i < bset->n_ineq; ++i) {2931 isl_int_set(cst->el[i], bset->ineq[i][0]);2932 for (j = 0; j < dim; ++j) {2933 if (!isl_int_is_neg(bset->ineq[i][1 + j]))2934 continue;2935 isl_int_add(bset->ineq[i][0], bset->ineq[i][0],2936 bset->ineq[i][1 + j]);2937 }2938 }2939 2940 cgbr->shifted = isl_tab_from_basic_set(bset, 0);2941 2942 for (i = 0; i < bset->n_ineq; ++i)2943 isl_int_set(bset->ineq[i][0], cst->el[i]);2944 2945 isl_vec_free(cst);2946}2947 2948/* Check if the shifted tableau is non-empty, and if so2949 * use the sample point to construct an integer point2950 * of the context tableau.2951 */2952static struct isl_vec *gbr_get_shifted_sample(struct isl_context_gbr *cgbr)2953{2954 struct isl_vec *sample;2955 2956 if (!cgbr->shifted)2957 gbr_init_shifted(cgbr);2958 if (!cgbr->shifted)2959 return NULL;2960 if (cgbr->shifted->empty)2961 return isl_vec_alloc(cgbr->tab->mat->ctx, 0);2962 2963 sample = isl_tab_get_sample_value(cgbr->shifted);2964 sample = isl_vec_ceil(sample);2965 2966 return sample;2967}2968 2969static __isl_give isl_basic_set *drop_constant_terms(2970 __isl_take isl_basic_set *bset)2971{2972 int i;2973 2974 if (!bset)2975 return NULL;2976 2977 for (i = 0; i < bset->n_eq; ++i)2978 isl_int_set_si(bset->eq[i][0], 0);2979 2980 for (i = 0; i < bset->n_ineq; ++i)2981 isl_int_set_si(bset->ineq[i][0], 0);2982 2983 return bset;2984}2985 2986static int use_shifted(struct isl_context_gbr *cgbr)2987{2988 if (!cgbr->tab)2989 return 0;2990 return cgbr->tab->bmap->n_eq == 0 && cgbr->tab->bmap->n_div == 0;2991}2992 2993static struct isl_vec *gbr_get_sample(struct isl_context_gbr *cgbr)2994{2995 struct isl_basic_set *bset;2996 struct isl_basic_set *cone;2997 2998 if (isl_tab_sample_is_integer(cgbr->tab))2999 return isl_tab_get_sample_value(cgbr->tab);3000 3001 if (use_shifted(cgbr)) {3002 struct isl_vec *sample;3003 3004 sample = gbr_get_shifted_sample(cgbr);3005 if (!sample || sample->size > 0)3006 return sample;3007 3008 isl_vec_free(sample);3009 }3010 3011 if (!cgbr->cone) {3012 bset = isl_tab_peek_bset(cgbr->tab);3013 cgbr->cone = isl_tab_from_recession_cone(bset, 0);3014 if (!cgbr->cone)3015 return NULL;3016 if (isl_tab_track_bset(cgbr->cone,3017 isl_basic_set_copy(bset)) < 0)3018 return NULL;3019 }3020 if (isl_tab_detect_implicit_equalities(cgbr->cone) < 0)3021 return NULL;3022 3023 if (cgbr->cone->n_dead == cgbr->cone->n_col) {3024 struct isl_vec *sample;3025 struct isl_tab_undo *snap;3026 3027 if (cgbr->tab->basis) {3028 if (cgbr->tab->basis->n_col != 1 + cgbr->tab->n_var) {3029 isl_mat_free(cgbr->tab->basis);3030 cgbr->tab->basis = NULL;3031 }3032 cgbr->tab->n_zero = 0;3033 cgbr->tab->n_unbounded = 0;3034 }3035 3036 snap = isl_tab_snap(cgbr->tab);3037 3038 sample = isl_tab_sample(cgbr->tab);3039 3040 if (!sample || isl_tab_rollback(cgbr->tab, snap) < 0) {3041 isl_vec_free(sample);3042 return NULL;3043 }3044 3045 return sample;3046 }3047 3048 cone = isl_basic_set_dup(isl_tab_peek_bset(cgbr->cone));3049 cone = drop_constant_terms(cone);3050 cone = isl_basic_set_update_from_tab(cone, cgbr->cone);3051 cone = isl_basic_set_underlying_set(cone);3052 cone = isl_basic_set_gauss(cone, NULL);3053 3054 bset = isl_basic_set_dup(isl_tab_peek_bset(cgbr->tab));3055 bset = isl_basic_set_update_from_tab(bset, cgbr->tab);3056 bset = isl_basic_set_underlying_set(bset);3057 bset = isl_basic_set_gauss(bset, NULL);3058 3059 return isl_basic_set_sample_with_cone(bset, cone);3060}3061 3062static void check_gbr_integer_feasible(struct isl_context_gbr *cgbr)3063{3064 struct isl_vec *sample;3065 3066 if (!cgbr->tab)3067 return;3068 3069 if (cgbr->tab->empty)3070 return;3071 3072 sample = gbr_get_sample(cgbr);3073 if (!sample)3074 goto error;3075 3076 if (sample->size == 0) {3077 isl_vec_free(sample);3078 if (isl_tab_mark_empty(cgbr->tab) < 0)3079 goto error;3080 return;3081 }3082 3083 if (isl_tab_add_sample(cgbr->tab, sample) < 0)3084 goto error;3085 3086 return;3087error:3088 isl_tab_free(cgbr->tab);3089 cgbr->tab = NULL;3090}3091 3092static struct isl_tab *add_gbr_eq(struct isl_tab *tab, isl_int *eq)3093{3094 if (!tab)3095 return NULL;3096 3097 if (isl_tab_extend_cons(tab, 2) < 0)3098 goto error;3099 3100 if (isl_tab_add_eq(tab, eq) < 0)3101 goto error;3102 3103 return tab;3104error:3105 isl_tab_free(tab);3106 return NULL;3107}3108 3109/* Add the equality described by "eq" to the context.3110 * If "check" is set, then we check if the context is empty after3111 * adding the equality.3112 * If "update" is set, then we check if the samples are still valid.3113 *3114 * We do not explicitly add shifted copies of the equality to3115 * cgbr->shifted since they would conflict with each other.3116 * Instead, we directly mark cgbr->shifted empty.3117 */3118static void context_gbr_add_eq(struct isl_context *context, isl_int *eq,3119 int check, int update)3120{3121 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3122 3123 cgbr->tab = add_gbr_eq(cgbr->tab, eq);3124 3125 if (cgbr->shifted && !cgbr->shifted->empty && use_shifted(cgbr)) {3126 if (isl_tab_mark_empty(cgbr->shifted) < 0)3127 goto error;3128 }3129 3130 if (cgbr->cone && cgbr->cone->n_col != cgbr->cone->n_dead) {3131 if (isl_tab_extend_cons(cgbr->cone, 2) < 0)3132 goto error;3133 if (isl_tab_add_eq(cgbr->cone, eq) < 0)3134 goto error;3135 }3136 3137 if (check) {3138 int v = tab_has_valid_sample(cgbr->tab, eq, 1);3139 if (v < 0)3140 goto error;3141 if (!v)3142 check_gbr_integer_feasible(cgbr);3143 }3144 if (update)3145 cgbr->tab = check_samples(cgbr->tab, eq, 1);3146 return;3147error:3148 isl_tab_free(cgbr->tab);3149 cgbr->tab = NULL;3150}3151 3152static void add_gbr_ineq(struct isl_context_gbr *cgbr, isl_int *ineq)3153{3154 if (!cgbr->tab)3155 return;3156 3157 if (isl_tab_extend_cons(cgbr->tab, 1) < 0)3158 goto error;3159 3160 if (isl_tab_add_ineq(cgbr->tab, ineq) < 0)3161 goto error;3162 3163 if (cgbr->shifted && !cgbr->shifted->empty && use_shifted(cgbr)) {3164 int i;3165 isl_size dim;3166 dim = isl_basic_map_dim(cgbr->tab->bmap, isl_dim_all);3167 if (dim < 0)3168 goto error;3169 3170 if (isl_tab_extend_cons(cgbr->shifted, 1) < 0)3171 goto error;3172 3173 for (i = 0; i < dim; ++i) {3174 if (!isl_int_is_neg(ineq[1 + i]))3175 continue;3176 isl_int_add(ineq[0], ineq[0], ineq[1 + i]);3177 }3178 3179 if (isl_tab_add_ineq(cgbr->shifted, ineq) < 0)3180 goto error;3181 3182 for (i = 0; i < dim; ++i) {3183 if (!isl_int_is_neg(ineq[1 + i]))3184 continue;3185 isl_int_sub(ineq[0], ineq[0], ineq[1 + i]);3186 }3187 }3188 3189 if (cgbr->cone && cgbr->cone->n_col != cgbr->cone->n_dead) {3190 if (isl_tab_extend_cons(cgbr->cone, 1) < 0)3191 goto error;3192 if (isl_tab_add_ineq(cgbr->cone, ineq) < 0)3193 goto error;3194 }3195 3196 return;3197error:3198 isl_tab_free(cgbr->tab);3199 cgbr->tab = NULL;3200}3201 3202static void context_gbr_add_ineq(struct isl_context *context, isl_int *ineq,3203 int check, int update)3204{3205 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3206 3207 add_gbr_ineq(cgbr, ineq);3208 if (!cgbr->tab)3209 return;3210 3211 if (check) {3212 int v = tab_has_valid_sample(cgbr->tab, ineq, 0);3213 if (v < 0)3214 goto error;3215 if (!v)3216 check_gbr_integer_feasible(cgbr);3217 }3218 if (update)3219 cgbr->tab = check_samples(cgbr->tab, ineq, 0);3220 return;3221error:3222 isl_tab_free(cgbr->tab);3223 cgbr->tab = NULL;3224}3225 3226static isl_stat context_gbr_add_ineq_wrap(void *user, isl_int *ineq)3227{3228 struct isl_context *context = (struct isl_context *)user;3229 context_gbr_add_ineq(context, ineq, 0, 0);3230 return context->op->is_ok(context) ? isl_stat_ok : isl_stat_error;3231}3232 3233static enum isl_tab_row_sign context_gbr_ineq_sign(struct isl_context *context,3234 isl_int *ineq, int strict)3235{3236 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3237 return tab_ineq_sign(cgbr->tab, ineq, strict);3238}3239 3240/* Check whether "ineq" can be added to the tableau without rendering3241 * it infeasible.3242 */3243static int context_gbr_test_ineq(struct isl_context *context, isl_int *ineq)3244{3245 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3246 struct isl_tab_undo *snap;3247 struct isl_tab_undo *shifted_snap = NULL;3248 struct isl_tab_undo *cone_snap = NULL;3249 int feasible;3250 3251 if (!cgbr->tab)3252 return -1;3253 3254 if (isl_tab_extend_cons(cgbr->tab, 1) < 0)3255 return -1;3256 3257 snap = isl_tab_snap(cgbr->tab);3258 if (cgbr->shifted)3259 shifted_snap = isl_tab_snap(cgbr->shifted);3260 if (cgbr->cone)3261 cone_snap = isl_tab_snap(cgbr->cone);3262 add_gbr_ineq(cgbr, ineq);3263 check_gbr_integer_feasible(cgbr);3264 if (!cgbr->tab)3265 return -1;3266 feasible = !cgbr->tab->empty;3267 if (isl_tab_rollback(cgbr->tab, snap) < 0)3268 return -1;3269 if (shifted_snap) {3270 if (isl_tab_rollback(cgbr->shifted, shifted_snap))3271 return -1;3272 } else if (cgbr->shifted) {3273 isl_tab_free(cgbr->shifted);3274 cgbr->shifted = NULL;3275 }3276 if (cone_snap) {3277 if (isl_tab_rollback(cgbr->cone, cone_snap))3278 return -1;3279 } else if (cgbr->cone) {3280 isl_tab_free(cgbr->cone);3281 cgbr->cone = NULL;3282 }3283 3284 return feasible;3285}3286 3287/* Return the column of the last of the variables associated to3288 * a column that has a non-zero coefficient.3289 * This function is called in a context where only coefficients3290 * of parameters or divs can be non-zero.3291 */3292static int last_non_zero_var_col(struct isl_tab *tab, isl_int *p)3293{3294 int i;3295 int col;3296 3297 if (tab->n_var == 0)3298 return -1;3299 3300 for (i = tab->n_var - 1; i >= 0; --i) {3301 if (i >= tab->n_param && i < tab->n_var - tab->n_div)3302 continue;3303 if (tab->var[i].is_row)3304 continue;3305 col = tab->var[i].index;3306 if (!isl_int_is_zero(p[col]))3307 return col;3308 }3309 3310 return -1;3311}3312 3313/* Look through all the recently added equalities in the context3314 * to see if we can propagate any of them to the main tableau.3315 *3316 * The newly added equalities in the context are encoded as pairs3317 * of inequalities starting at inequality "first".3318 *3319 * We tentatively add each of these equalities to the main tableau3320 * and if this happens to result in a row with a final coefficient3321 * that is one or negative one, we use it to kill a column3322 * in the main tableau. Otherwise, we discard the tentatively3323 * added row.3324 * This tentative addition of equality constraints turns3325 * on the undo facility of the tableau. Turn it off again3326 * at the end, assuming it was turned off to begin with.3327 *3328 * Return 0 on success and -1 on failure.3329 */3330static int propagate_equalities(struct isl_context_gbr *cgbr,3331 struct isl_tab *tab, unsigned first)3332{3333 int i;3334 struct isl_vec *eq = NULL;3335 isl_bool needs_undo;3336 3337 needs_undo = isl_tab_need_undo(tab);3338 if (needs_undo < 0)3339 goto error;3340 eq = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var);3341 if (!eq)3342 goto error;3343 3344 if (isl_tab_extend_cons(tab, (cgbr->tab->bmap->n_ineq - first)/2) < 0)3345 goto error;3346 3347 isl_seq_clr(eq->el + 1 + tab->n_param,3348 tab->n_var - tab->n_param - tab->n_div);3349 for (i = first; i < cgbr->tab->bmap->n_ineq; i += 2) {3350 int j;3351 int r;3352 struct isl_tab_undo *snap;3353 snap = isl_tab_snap(tab);3354 3355 isl_seq_cpy(eq->el, cgbr->tab->bmap->ineq[i], 1 + tab->n_param);3356 isl_seq_cpy(eq->el + 1 + tab->n_var - tab->n_div,3357 cgbr->tab->bmap->ineq[i] + 1 + tab->n_param,3358 tab->n_div);3359 3360 r = isl_tab_add_row(tab, eq->el);3361 if (r < 0)3362 goto error;3363 r = tab->con[r].index;3364 j = last_non_zero_var_col(tab, tab->mat->row[r] + 2 + tab->M);3365 if (j < 0 || j < tab->n_dead ||3366 !isl_int_is_one(tab->mat->row[r][0]) ||3367 (!isl_int_is_one(tab->mat->row[r][2 + tab->M + j]) &&3368 !isl_int_is_negone(tab->mat->row[r][2 + tab->M + j]))) {3369 if (isl_tab_rollback(tab, snap) < 0)3370 goto error;3371 continue;3372 }3373 if (isl_tab_pivot(tab, r, j) < 0)3374 goto error;3375 if (isl_tab_kill_col(tab, j) < 0)3376 goto error;3377 3378 if (restore_lexmin(tab) < 0)3379 goto error;3380 }3381 3382 if (!needs_undo)3383 isl_tab_clear_undo(tab);3384 isl_vec_free(eq);3385 3386 return 0;3387error:3388 isl_vec_free(eq);3389 isl_tab_free(cgbr->tab);3390 cgbr->tab = NULL;3391 return -1;3392}3393 3394static int context_gbr_detect_equalities(struct isl_context *context,3395 struct isl_tab *tab)3396{3397 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3398 unsigned n_ineq;3399 3400 if (!cgbr->cone) {3401 struct isl_basic_set *bset = isl_tab_peek_bset(cgbr->tab);3402 cgbr->cone = isl_tab_from_recession_cone(bset, 0);3403 if (!cgbr->cone)3404 goto error;3405 if (isl_tab_track_bset(cgbr->cone,3406 isl_basic_set_copy(bset)) < 0)3407 goto error;3408 }3409 if (isl_tab_detect_implicit_equalities(cgbr->cone) < 0)3410 goto error;3411 3412 n_ineq = cgbr->tab->bmap->n_ineq;3413 cgbr->tab = isl_tab_detect_equalities(cgbr->tab, cgbr->cone);3414 if (!cgbr->tab)3415 return -1;3416 if (cgbr->tab->bmap->n_ineq > n_ineq &&3417 propagate_equalities(cgbr, tab, n_ineq) < 0)3418 return -1;3419 3420 return 0;3421error:3422 isl_tab_free(cgbr->tab);3423 cgbr->tab = NULL;3424 return -1;3425}3426 3427static int context_gbr_get_div(struct isl_context *context, struct isl_tab *tab,3428 struct isl_vec *div)3429{3430 return get_div(tab, context, div);3431}3432 3433static isl_bool context_gbr_insert_div(struct isl_context *context, int pos,3434 __isl_keep isl_vec *div)3435{3436 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3437 if (cgbr->cone) {3438 int r, o_div;3439 isl_size n_div;3440 3441 n_div = isl_basic_map_dim(cgbr->cone->bmap, isl_dim_div);3442 if (n_div < 0)3443 return isl_bool_error;3444 o_div = cgbr->cone->n_var - n_div;3445 3446 if (isl_tab_extend_cons(cgbr->cone, 3) < 0)3447 return isl_bool_error;3448 if (isl_tab_extend_vars(cgbr->cone, 1) < 0)3449 return isl_bool_error;3450 if ((r = isl_tab_insert_var(cgbr->cone, pos)) <0)3451 return isl_bool_error;3452 3453 cgbr->cone->bmap = isl_basic_map_insert_div(cgbr->cone->bmap,3454 r - o_div, div);3455 if (!cgbr->cone->bmap)3456 return isl_bool_error;3457 if (isl_tab_push_var(cgbr->cone, isl_tab_undo_bmap_div,3458 &cgbr->cone->var[r]) < 0)3459 return isl_bool_error;3460 }3461 return context_tab_insert_div(cgbr->tab, pos, div,3462 context_gbr_add_ineq_wrap, context);3463}3464 3465static int context_gbr_best_split(struct isl_context *context,3466 struct isl_tab *tab)3467{3468 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3469 struct isl_tab_undo *snap;3470 int r;3471 3472 snap = isl_tab_snap(cgbr->tab);3473 r = best_split(tab, cgbr->tab);3474 3475 if (r >= 0 && isl_tab_rollback(cgbr->tab, snap) < 0)3476 return -1;3477 3478 return r;3479}3480 3481static int context_gbr_is_empty(struct isl_context *context)3482{3483 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3484 if (!cgbr->tab)3485 return -1;3486 return cgbr->tab->empty;3487}3488 3489struct isl_gbr_tab_undo {3490 struct isl_tab_undo *tab_snap;3491 struct isl_tab_undo *shifted_snap;3492 struct isl_tab_undo *cone_snap;3493};3494 3495static void *context_gbr_save(struct isl_context *context)3496{3497 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3498 struct isl_gbr_tab_undo *snap;3499 3500 if (!cgbr->tab)3501 return NULL;3502 3503 snap = isl_alloc_type(cgbr->tab->mat->ctx, struct isl_gbr_tab_undo);3504 if (!snap)3505 return NULL;3506 3507 snap->tab_snap = isl_tab_snap(cgbr->tab);3508 if (isl_tab_save_samples(cgbr->tab) < 0)3509 goto error;3510 3511 if (cgbr->shifted)3512 snap->shifted_snap = isl_tab_snap(cgbr->shifted);3513 else3514 snap->shifted_snap = NULL;3515 3516 if (cgbr->cone)3517 snap->cone_snap = isl_tab_snap(cgbr->cone);3518 else3519 snap->cone_snap = NULL;3520 3521 return snap;3522error:3523 free(snap);3524 return NULL;3525}3526 3527static void context_gbr_restore(struct isl_context *context, void *save)3528{3529 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3530 struct isl_gbr_tab_undo *snap = (struct isl_gbr_tab_undo *)save;3531 if (!snap)3532 goto error;3533 if (isl_tab_rollback(cgbr->tab, snap->tab_snap) < 0)3534 goto error;3535 3536 if (snap->shifted_snap) {3537 if (isl_tab_rollback(cgbr->shifted, snap->shifted_snap) < 0)3538 goto error;3539 } else if (cgbr->shifted) {3540 isl_tab_free(cgbr->shifted);3541 cgbr->shifted = NULL;3542 }3543 3544 if (snap->cone_snap) {3545 if (isl_tab_rollback(cgbr->cone, snap->cone_snap) < 0)3546 goto error;3547 } else if (cgbr->cone) {3548 isl_tab_free(cgbr->cone);3549 cgbr->cone = NULL;3550 }3551 3552 free(snap);3553 3554 return;3555error:3556 free(snap);3557 isl_tab_free(cgbr->tab);3558 cgbr->tab = NULL;3559}3560 3561static void context_gbr_discard(void *save)3562{3563 struct isl_gbr_tab_undo *snap = (struct isl_gbr_tab_undo *)save;3564 free(snap);3565}3566 3567static int context_gbr_is_ok(struct isl_context *context)3568{3569 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3570 return !!cgbr->tab;3571}3572 3573static void context_gbr_invalidate(struct isl_context *context)3574{3575 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3576 isl_tab_free(cgbr->tab);3577 cgbr->tab = NULL;3578}3579 3580static __isl_null struct isl_context *context_gbr_free(3581 struct isl_context *context)3582{3583 struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;3584 isl_tab_free(cgbr->tab);3585 isl_tab_free(cgbr->shifted);3586 isl_tab_free(cgbr->cone);3587 free(cgbr);3588 3589 return NULL;3590}3591 3592struct isl_context_op isl_context_gbr_op = {3593 context_gbr_detect_nonnegative_parameters,3594 context_gbr_peek_basic_set,3595 context_gbr_peek_tab,3596 context_gbr_add_eq,3597 context_gbr_add_ineq,3598 context_gbr_ineq_sign,3599 context_gbr_test_ineq,3600 context_gbr_get_div,3601 context_gbr_insert_div,3602 context_gbr_detect_equalities,3603 context_gbr_best_split,3604 context_gbr_is_empty,3605 context_gbr_is_ok,3606 context_gbr_save,3607 context_gbr_restore,3608 context_gbr_discard,3609 context_gbr_invalidate,3610 context_gbr_free,3611};3612 3613static struct isl_context *isl_context_gbr_alloc(__isl_keep isl_basic_set *dom)3614{3615 struct isl_context_gbr *cgbr;3616 3617 if (!dom)3618 return NULL;3619 3620 cgbr = isl_calloc_type(dom->ctx, struct isl_context_gbr);3621 if (!cgbr)3622 return NULL;3623 3624 cgbr->context.op = &isl_context_gbr_op;3625 3626 cgbr->shifted = NULL;3627 cgbr->cone = NULL;3628 cgbr->tab = isl_tab_from_basic_set(dom, 1);3629 cgbr->tab = isl_tab_init_samples(cgbr->tab);3630 if (!cgbr->tab)3631 goto error;3632 check_gbr_integer_feasible(cgbr);3633 3634 return &cgbr->context;3635error:3636 cgbr->context.op->free(&cgbr->context);3637 return NULL;3638}3639 3640/* Allocate a context corresponding to "dom".3641 * The representation specific fields are initialized by3642 * isl_context_lex_alloc or isl_context_gbr_alloc.3643 * The shared "n_unknown" field is initialized to the number3644 * of final unknown integer divisions in "dom".3645 */3646static struct isl_context *isl_context_alloc(__isl_keep isl_basic_set *dom)3647{3648 struct isl_context *context;3649 int first;3650 isl_size n_div;3651 3652 if (!dom)3653 return NULL;3654 3655 if (dom->ctx->opt->context == ISL_CONTEXT_LEXMIN)3656 context = isl_context_lex_alloc(dom);3657 else3658 context = isl_context_gbr_alloc(dom);3659 3660 if (!context)3661 return NULL;3662 3663 first = isl_basic_set_first_unknown_div(dom);3664 n_div = isl_basic_set_dim(dom, isl_dim_div);3665 if (first < 0 || n_div < 0)3666 return context->op->free(context);3667 context->n_unknown = n_div - first;3668 3669 return context;3670}3671 3672/* Initialize some common fields of "sol", which keeps track3673 * of the solution of an optimization problem on "bmap" over3674 * the domain "dom".3675 * If "max" is set, then a maximization problem is being solved, rather than3676 * a minimization problem, which means that the variables in the3677 * tableau have value "M - x" rather than "M + x".3678 */3679static isl_stat sol_init(struct isl_sol *sol, __isl_keep isl_basic_map *bmap,3680 __isl_keep isl_basic_set *dom, int max)3681{3682 sol->rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);3683 sol->dec_level.callback.run = &sol_dec_level_wrap;3684 sol->dec_level.sol = sol;3685 sol->max = max;3686 sol->n_out = isl_basic_map_dim(bmap, isl_dim_out);3687 sol->space = isl_basic_map_get_space(bmap);3688 3689 sol->context = isl_context_alloc(dom);3690 if (sol->n_out < 0 || !sol->space || !sol->context)3691 return isl_stat_error;3692 3693 return isl_stat_ok;3694}3695 3696/* Construct an isl_sol_map structure for accumulating the solution.3697 * If track_empty is set, then we also keep track of the parts3698 * of the context where there is no solution.3699 * If max is set, then we are solving a maximization, rather than3700 * a minimization problem, which means that the variables in the3701 * tableau have value "M - x" rather than "M + x".3702 */3703static struct isl_sol *sol_map_init(__isl_keep isl_basic_map *bmap,3704 __isl_take isl_basic_set *dom, int track_empty, int max)3705{3706 struct isl_sol_map *sol_map = NULL;3707 isl_space *space;3708 3709 if (!bmap)3710 goto error;3711 3712 sol_map = isl_calloc_type(bmap->ctx, struct isl_sol_map);3713 if (!sol_map)3714 goto error;3715 3716 sol_map->sol.free = &sol_map_free;3717 if (sol_init(&sol_map->sol, bmap, dom, max) < 0)3718 goto error;3719 sol_map->sol.add = &sol_map_add_wrap;3720 sol_map->sol.add_empty = track_empty ? &sol_map_add_empty_wrap : NULL;3721 space = isl_space_copy(sol_map->sol.space);3722 sol_map->map = isl_map_alloc_space(space, 1, ISL_MAP_DISJOINT);3723 if (!sol_map->map)3724 goto error;3725 3726 if (track_empty) {3727 sol_map->empty = isl_set_alloc_space(isl_basic_set_get_space(dom),3728 1, ISL_SET_DISJOINT);3729 if (!sol_map->empty)3730 goto error;3731 }3732 3733 isl_basic_set_free(dom);3734 return &sol_map->sol;3735error:3736 isl_basic_set_free(dom);3737 sol_free(&sol_map->sol);3738 return NULL;3739}3740 3741/* Check whether all coefficients of (non-parameter) variables3742 * are non-positive, meaning that no pivots can be performed on the row.3743 */3744static int is_critical(struct isl_tab *tab, int row)3745{3746 int j;3747 unsigned off = 2 + tab->M;3748 3749 for (j = tab->n_dead; j < tab->n_col; ++j) {3750 if (col_is_parameter_var(tab, j))3751 continue;3752 3753 if (isl_int_is_pos(tab->mat->row[row][off + j]))3754 return 0;3755 }3756 3757 return 1;3758}3759 3760/* Check whether the inequality represented by vec is strict over the integers,3761 * i.e., there are no integer values satisfying the constraint with3762 * equality. This happens if the gcd of the coefficients is not a divisor3763 * of the constant term. If so, scale the constraint down by the gcd3764 * of the coefficients.3765 */3766static int is_strict(struct isl_vec *vec)3767{3768 isl_int gcd;3769 int strict = 0;3770 3771 isl_int_init(gcd);3772 isl_seq_gcd(vec->el + 1, vec->size - 1, &gcd);3773 if (!isl_int_is_one(gcd)) {3774 strict = !isl_int_is_divisible_by(vec->el[0], gcd);3775 isl_int_fdiv_q(vec->el[0], vec->el[0], gcd);3776 isl_seq_scale_down(vec->el + 1, vec->el + 1, gcd, vec->size-1);3777 }3778 isl_int_clear(gcd);3779 3780 return strict;3781}3782 3783/* Determine the sign of the given row of the main tableau.3784 * The result is one of3785 * isl_tab_row_pos: always non-negative; no pivot needed3786 * isl_tab_row_neg: always non-positive; pivot3787 * isl_tab_row_any: can be both positive and negative; split3788 *3789 * We first handle some simple cases3790 * - the row sign may be known already3791 * - the row may be obviously non-negative3792 * - the parametric constant may be equal to that of another row3793 * for which we know the sign. This sign will be either "pos" or3794 * "any". If it had been "neg" then we would have pivoted before.3795 *3796 * If none of these cases hold, we check the value of the row for each3797 * of the currently active samples. Based on the signs of these values3798 * we make an initial determination of the sign of the row.3799 *3800 * all zero -> unk(nown)3801 * all non-negative -> pos3802 * all non-positive -> neg3803 * both negative and positive -> all3804 *3805 * If we end up with "all", we are done.3806 * Otherwise, we perform a check for positive and/or negative3807 * values as follows.3808 *3809 * samples neg unk pos3810 * <0 ? Y N Y N3811 * pos any pos3812 * >0 ? Y N Y N3813 * any neg any neg3814 *3815 * There is no special sign for "zero", because we can usually treat zero3816 * as either non-negative or non-positive, whatever works out best.3817 * However, if the row is "critical", meaning that pivoting is impossible3818 * then we don't want to limp zero with the non-positive case, because3819 * then we we would lose the solution for those values of the parameters3820 * where the value of the row is zero. Instead, we treat 0 as non-negative3821 * ensuring a split if the row can attain both zero and negative values.3822 * The same happens when the original constraint was one that could not3823 * be satisfied with equality by any integer values of the parameters.3824 * In this case, we normalize the constraint, but then a value of zero3825 * for the normalized constraint is actually a positive value for the3826 * original constraint, so again we need to treat zero as non-negative.3827 * In both these cases, we have the following decision tree instead:3828 *3829 * all non-negative -> pos3830 * all negative -> neg3831 * both negative and non-negative -> all3832 *3833 * samples neg pos3834 * <0 ? Y N3835 * any pos3836 * >=0 ? Y N3837 * any neg3838 */3839static enum isl_tab_row_sign row_sign(struct isl_tab *tab,3840 struct isl_sol *sol, int row)3841{3842 struct isl_vec *ineq = NULL;3843 enum isl_tab_row_sign res = isl_tab_row_unknown;3844 int critical;3845 int strict;3846 int row2;3847 3848 if (tab->row_sign[row] != isl_tab_row_unknown)3849 return tab->row_sign[row];3850 if (is_obviously_nonneg(tab, row))3851 return isl_tab_row_pos;3852 for (row2 = tab->n_redundant; row2 < tab->n_row; ++row2) {3853 if (tab->row_sign[row2] == isl_tab_row_unknown)3854 continue;3855 if (identical_parameter_line(tab, row, row2))3856 return tab->row_sign[row2];3857 }3858 3859 critical = is_critical(tab, row);3860 3861 ineq = get_row_parameter_ineq(tab, row);3862 if (!ineq)3863 goto error;3864 3865 strict = is_strict(ineq);3866 3867 res = sol->context->op->ineq_sign(sol->context, ineq->el,3868 critical || strict);3869 3870 if (res == isl_tab_row_unknown || res == isl_tab_row_pos) {3871 /* test for negative values */3872 int feasible;3873 isl_seq_neg(ineq->el, ineq->el, ineq->size);3874 isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);3875 3876 feasible = sol->context->op->test_ineq(sol->context, ineq->el);3877 if (feasible < 0)3878 goto error;3879 if (!feasible)3880 res = isl_tab_row_pos;3881 else3882 res = (res == isl_tab_row_unknown) ? isl_tab_row_neg3883 : isl_tab_row_any;3884 if (res == isl_tab_row_neg) {3885 isl_seq_neg(ineq->el, ineq->el, ineq->size);3886 isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);3887 }3888 }3889 3890 if (res == isl_tab_row_neg) {3891 /* test for positive values */3892 int feasible;3893 if (!critical && !strict)3894 isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);3895 3896 feasible = sol->context->op->test_ineq(sol->context, ineq->el);3897 if (feasible < 0)3898 goto error;3899 if (feasible)3900 res = isl_tab_row_any;3901 }3902 3903 isl_vec_free(ineq);3904 return res;3905error:3906 isl_vec_free(ineq);3907 return isl_tab_row_unknown;3908}3909 3910static void find_solutions(struct isl_sol *sol, struct isl_tab *tab);3911 3912/* Find solutions for values of the parameters that satisfy the given3913 * inequality.3914 *3915 * We currently take a snapshot of the context tableau that is reset3916 * when we return from this function, while we make a copy of the main3917 * tableau, leaving the original main tableau untouched.3918 * These are fairly arbitrary choices. Making a copy also of the context3919 * tableau would obviate the need to undo any changes made to it later,3920 * while taking a snapshot of the main tableau could reduce memory usage.3921 * If we were to switch to taking a snapshot of the main tableau,3922 * we would have to keep in mind that we need to save the row signs3923 * and that we need to do this before saving the current basis3924 * such that the basis has been restore before we restore the row signs.3925 */3926static void find_in_pos(struct isl_sol *sol, struct isl_tab *tab, isl_int *ineq)3927{3928 void *saved;3929 3930 if (!sol->context)3931 goto error;3932 saved = sol->context->op->save(sol->context);3933 3934 tab = isl_tab_dup(tab);3935 if (!tab)3936 goto error;3937 3938 sol->context->op->add_ineq(sol->context, ineq, 0, 1);3939 3940 find_solutions(sol, tab);3941 3942 if (!sol->error)3943 sol->context->op->restore(sol->context, saved);3944 else3945 sol->context->op->discard(saved);3946 return;3947error:3948 sol->error = 1;3949}3950 3951/* Record the absence of solutions for those values of the parameters3952 * that do not satisfy the given inequality with equality.3953 */3954static void no_sol_in_strict(struct isl_sol *sol,3955 struct isl_tab *tab, struct isl_vec *ineq)3956{3957 int empty;3958 void *saved;3959 3960 if (!sol->context || sol->error)3961 goto error;3962 saved = sol->context->op->save(sol->context);3963 3964 isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);3965 3966 sol->context->op->add_ineq(sol->context, ineq->el, 1, 0);3967 if (!sol->context)3968 goto error;3969 3970 empty = tab->empty;3971 tab->empty = 1;3972 sol_add(sol, tab);3973 tab->empty = empty;3974 3975 isl_int_add_ui(ineq->el[0], ineq->el[0], 1);3976 3977 sol->context->op->restore(sol->context, saved);3978 return;3979error:3980 sol->error = 1;3981}3982 3983/* Reset all row variables that are marked to have a sign that may3984 * be both positive and negative to have an unknown sign.3985 */3986static void reset_any_to_unknown(struct isl_tab *tab)3987{3988 int row;3989 3990 for (row = tab->n_redundant; row < tab->n_row; ++row) {3991 if (!isl_tab_var_from_row(tab, row)->is_nonneg)3992 continue;3993 if (tab->row_sign[row] == isl_tab_row_any)3994 tab->row_sign[row] = isl_tab_row_unknown;3995 }3996}3997 3998/* Compute the lexicographic minimum of the set represented by the main3999 * tableau "tab" within the context "sol->context_tab".4000 * On entry the sample value of the main tableau is lexicographically4001 * less than or equal to this lexicographic minimum.4002 * Pivots are performed until a feasible point is found, which is then4003 * necessarily equal to the minimum, or until the tableau is found to4004 * be infeasible. Some pivots may need to be performed for only some4005 * feasible values of the context tableau. If so, the context tableau4006 * is split into a part where the pivot is needed and a part where it is not.4007 *4008 * Whenever we enter the main loop, the main tableau is such that no4009 * "obvious" pivots need to be performed on it, where "obvious" means4010 * that the given row can be seen to be negative without looking at4011 * the context tableau. In particular, for non-parametric problems,4012 * no pivots need to be performed on the main tableau.4013 * The caller of find_solutions is responsible for making this property4014 * hold prior to the first iteration of the loop, while restore_lexmin4015 * is called before every other iteration.4016 *4017 * Inside the main loop, we first examine the signs of the rows of4018 * the main tableau within the context of the context tableau.4019 * If we find a row that is always non-positive for all values of4020 * the parameters satisfying the context tableau and negative for at4021 * least one value of the parameters, we perform the appropriate pivot4022 * and start over. An exception is the case where no pivot can be4023 * performed on the row. In this case, we require that the sign of4024 * the row is negative for all values of the parameters (rather than just4025 * non-positive). This special case is handled inside row_sign, which4026 * will say that the row can have any sign if it determines that it can4027 * attain both negative and zero values.4028 *4029 * If we can't find a row that always requires a pivot, but we can find4030 * one or more rows that require a pivot for some values of the parameters4031 * (i.e., the row can attain both positive and negative signs), then we split4032 * the context tableau into two parts, one where we force the sign to be4033 * non-negative and one where we force is to be negative.4034 * The non-negative part is handled by a recursive call (through find_in_pos).4035 * Upon returning from this call, we continue with the negative part and4036 * perform the required pivot.4037 *4038 * If no such rows can be found, all rows are non-negative and we have4039 * found a (rational) feasible point. If we only wanted a rational point4040 * then we are done.4041 * Otherwise, we check if all values of the sample point of the tableau4042 * are integral for the variables. If so, we have found the minimal4043 * integral point and we are done.4044 * If the sample point is not integral, then we need to make a distinction4045 * based on whether the constant term is non-integral or the coefficients4046 * of the parameters. Furthermore, in order to decide how to handle4047 * the non-integrality, we also need to know whether the coefficients4048 * of the other columns in the tableau are integral. This leads4049 * to the following table. The first two rows do not correspond4050 * to a non-integral sample point and are only mentioned for completeness.4051 *4052 * constant parameters other4053 *4054 * int int int |4055 * int int rat | -> no problem4056 *4057 * rat int int -> fail4058 *4059 * rat int rat -> cut4060 *4061 * int rat rat |4062 * rat rat rat | -> parametric cut4063 *4064 * int rat int |4065 * rat rat int | -> split context4066 *4067 * If the parametric constant is completely integral, then there is nothing4068 * to be done. If the constant term is non-integral, but all the other4069 * coefficient are integral, then there is nothing that can be done4070 * and the tableau has no integral solution.4071 * If, on the other hand, one or more of the other columns have rational4072 * coefficients, but the parameter coefficients are all integral, then4073 * we can perform a regular (non-parametric) cut.4074 * Finally, if there is any parameter coefficient that is non-integral,4075 * then we need to involve the context tableau. There are two cases here.4076 * If at least one other column has a rational coefficient, then we4077 * can perform a parametric cut in the main tableau by adding a new4078 * integer division in the context tableau.4079 * If all other columns have integral coefficients, then we need to4080 * enforce that the rational combination of parameters (c + \sum a_i y_i)/m4081 * is always integral. We do this by introducing an integer division4082 * q = floor((c + \sum a_i y_i)/m) and stipulating that its argument should4083 * always be integral in the context tableau, i.e., m q = c + \sum a_i y_i.4084 * Since q is expressed in the tableau as4085 * c + \sum a_i y_i - m q >= 04086 * -c - \sum a_i y_i + m q + m - 1 >= 04087 * it is sufficient to add the inequality4088 * -c - \sum a_i y_i + m q >= 04089 * In the part of the context where this inequality does not hold, the4090 * main tableau is marked as being empty.4091 */4092static void find_solutions(struct isl_sol *sol, struct isl_tab *tab)4093{4094 struct isl_context *context;4095 int r;4096 4097 if (!tab || sol->error)4098 goto error;4099 4100 context = sol->context;4101 4102 if (tab->empty)4103 goto done;4104 if (context->op->is_empty(context))4105 goto done;4106 4107 for (r = 0; r >= 0 && tab && !tab->empty; r = restore_lexmin(tab)) {4108 int flags;4109 int row;4110 enum isl_tab_row_sign sgn;4111 int split = -1;4112 int n_split = 0;4113 4114 for (row = tab->n_redundant; row < tab->n_row; ++row) {4115 if (!isl_tab_var_from_row(tab, row)->is_nonneg)4116 continue;4117 sgn = row_sign(tab, sol, row);4118 if (!sgn)4119 goto error;4120 tab->row_sign[row] = sgn;4121 if (sgn == isl_tab_row_any)4122 n_split++;4123 if (sgn == isl_tab_row_any && split == -1)4124 split = row;4125 if (sgn == isl_tab_row_neg)4126 break;4127 }4128 if (row < tab->n_row)4129 continue;4130 if (split != -1) {4131 struct isl_vec *ineq;4132 if (n_split != 1)4133 split = context->op->best_split(context, tab);4134 if (split < 0)4135 goto error;4136 ineq = get_row_parameter_ineq(tab, split);4137 if (!ineq)4138 goto error;4139 is_strict(ineq);4140 reset_any_to_unknown(tab);4141 tab->row_sign[split] = isl_tab_row_pos;4142 sol_inc_level(sol);4143 find_in_pos(sol, tab, ineq->el);4144 tab->row_sign[split] = isl_tab_row_neg;4145 isl_seq_neg(ineq->el, ineq->el, ineq->size);4146 isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);4147 if (!sol->error)4148 context->op->add_ineq(context, ineq->el, 0, 1);4149 isl_vec_free(ineq);4150 if (sol->error)4151 goto error;4152 continue;4153 }4154 if (tab->rational)4155 break;4156 row = first_non_integer_row(tab, &flags);4157 if (row < 0)4158 break;4159 if (ISL_FL_ISSET(flags, I_PAR)) {4160 if (ISL_FL_ISSET(flags, I_VAR)) {4161 if (isl_tab_mark_empty(tab) < 0)4162 goto error;4163 break;4164 }4165 row = add_cut(tab, row);4166 } else if (ISL_FL_ISSET(flags, I_VAR)) {4167 struct isl_vec *div;4168 struct isl_vec *ineq;4169 int d;4170 div = get_row_split_div(tab, row);4171 if (!div)4172 goto error;4173 d = context->op->get_div(context, tab, div);4174 isl_vec_free(div);4175 if (d < 0)4176 goto error;4177 ineq = ineq_for_div(context->op->peek_basic_set(context), d);4178 if (!ineq)4179 goto error;4180 sol_inc_level(sol);4181 no_sol_in_strict(sol, tab, ineq);4182 isl_seq_neg(ineq->el, ineq->el, ineq->size);4183 context->op->add_ineq(context, ineq->el, 1, 1);4184 isl_vec_free(ineq);4185 if (sol->error || !context->op->is_ok(context))4186 goto error;4187 tab = set_row_cst_to_div(tab, row, d);4188 if (context->op->is_empty(context))4189 break;4190 } else4191 row = add_parametric_cut(tab, row, context);4192 if (row < 0)4193 goto error;4194 }4195 if (r < 0)4196 goto error;4197done:4198 sol_add(sol, tab);4199 isl_tab_free(tab);4200 return;4201error:4202 isl_tab_free(tab);4203 sol->error = 1;4204}4205 4206/* Does "sol" contain a pair of partial solutions that could potentially4207 * be merged?4208 *4209 * We currently only check that "sol" is not in an error state4210 * and that there are at least two partial solutions of which the final two4211 * are defined at the same level.4212 */4213static int sol_has_mergeable_solutions(struct isl_sol *sol)4214{4215 if (sol->error)4216 return 0;4217 if (!sol->partial)4218 return 0;4219 if (!sol->partial->next)4220 return 0;4221 return sol->partial->level == sol->partial->next->level;4222}4223 4224/* Compute the lexicographic minimum of the set represented by the main4225 * tableau "tab" within the context "sol->context_tab".4226 *4227 * As a preprocessing step, we first transfer all the purely parametric4228 * equalities from the main tableau to the context tableau, i.e.,4229 * parameters that have been pivoted to a row.4230 * These equalities are ignored by the main algorithm, because the4231 * corresponding rows may not be marked as being non-negative.4232 * In parts of the context where the added equality does not hold,4233 * the main tableau is marked as being empty.4234 *4235 * Before we embark on the actual computation, we save a copy4236 * of the context. When we return, we check if there are any4237 * partial solutions that can potentially be merged. If so,4238 * we perform a rollback to the initial state of the context.4239 * The merging of partial solutions happens inside calls to4240 * sol_dec_level that are pushed onto the undo stack of the context.4241 * If there are no partial solutions that can potentially be merged4242 * then the rollback is skipped as it would just be wasted effort.4243 */4244static void find_solutions_main(struct isl_sol *sol, struct isl_tab *tab)4245{4246 int row;4247 void *saved;4248 4249 if (!tab)4250 goto error;4251 4252 sol->level = 0;4253 4254 for (row = tab->n_redundant; row < tab->n_row; ++row) {4255 int p;4256 struct isl_vec *eq;4257 4258 if (!row_is_parameter_var(tab, row))4259 continue;4260 if (tab->row_var[row] < tab->n_param)4261 p = tab->row_var[row];4262 else4263 p = tab->row_var[row]4264 + tab->n_param - (tab->n_var - tab->n_div);4265 4266 eq = isl_vec_alloc(tab->mat->ctx, 1+tab->n_param+tab->n_div);4267 if (!eq)4268 goto error;4269 get_row_parameter_line(tab, row, eq->el);4270 isl_int_neg(eq->el[1 + p], tab->mat->row[row][0]);4271 eq = isl_vec_normalize(eq);4272 4273 sol_inc_level(sol);4274 no_sol_in_strict(sol, tab, eq);4275 4276 isl_seq_neg(eq->el, eq->el, eq->size);4277 sol_inc_level(sol);4278 no_sol_in_strict(sol, tab, eq);4279 isl_seq_neg(eq->el, eq->el, eq->size);4280 4281 sol->context->op->add_eq(sol->context, eq->el, 1, 1);4282 4283 isl_vec_free(eq);4284 4285 if (isl_tab_mark_redundant(tab, row) < 0)4286 goto error;4287 4288 if (sol->context->op->is_empty(sol->context))4289 break;4290 4291 row = tab->n_redundant - 1;4292 }4293 4294 saved = sol->context->op->save(sol->context);4295 4296 find_solutions(sol, tab);4297 4298 if (sol_has_mergeable_solutions(sol))4299 sol->context->op->restore(sol->context, saved);4300 else4301 sol->context->op->discard(saved);4302 4303 sol->level = 0;4304 sol_pop(sol);4305 4306 return;4307error:4308 isl_tab_free(tab);4309 sol->error = 1;4310}4311 4312/* Check if integer division "div" of "dom" also occurs in "bmap".4313 * If so, return its position within the divs.4314 * Otherwise, return a position beyond the integer divisions.4315 */4316static int find_context_div(__isl_keep isl_basic_map *bmap,4317 __isl_keep isl_basic_set *dom, unsigned div)4318{4319 int i;4320 isl_size b_v_div, d_v_div;4321 isl_size n_div;4322 4323 b_v_div = isl_basic_map_var_offset(bmap, isl_dim_div);4324 d_v_div = isl_basic_set_var_offset(dom, isl_dim_div);4325 n_div = isl_basic_map_dim(bmap, isl_dim_div);4326 if (b_v_div < 0 || d_v_div < 0 || n_div < 0)4327 return -1;4328 4329 if (isl_int_is_zero(dom->div[div][0]))4330 return n_div;4331 if (isl_seq_first_non_zero(dom->div[div] + 2 + d_v_div,4332 dom->n_div) != -1)4333 return n_div;4334 4335 for (i = 0; i < n_div; ++i) {4336 if (isl_int_is_zero(bmap->div[i][0]))4337 continue;4338 if (isl_seq_first_non_zero(bmap->div[i] + 2 + d_v_div,4339 (b_v_div - d_v_div) + n_div) != -1)4340 continue;4341 if (isl_seq_eq(bmap->div[i], dom->div[div], 2 + d_v_div))4342 return i;4343 }4344 return n_div;4345}4346 4347/* The correspondence between the variables in the main tableau,4348 * the context tableau, and the input map and domain is as follows.4349 * The first n_param and the last n_div variables of the main tableau4350 * form the variables of the context tableau.4351 * In the basic map, these n_param variables correspond to the4352 * parameters and the input dimensions. In the domain, they correspond4353 * to the parameters and the set dimensions.4354 * The n_div variables correspond to the integer divisions in the domain.4355 * To ensure that everything lines up, we may need to copy some of the4356 * integer divisions of the domain to the map. These have to be placed4357 * in the same order as those in the context and they have to be placed4358 * after any other integer divisions that the map may have.4359 * This function performs the required reordering.4360 */4361static __isl_give isl_basic_map *align_context_divs(4362 __isl_take isl_basic_map *bmap, __isl_keep isl_basic_set *dom)4363{4364 int i;4365 int common = 0;4366 int other;4367 unsigned bmap_n_div;4368 4369 bmap_n_div = isl_basic_map_dim(bmap, isl_dim_div);4370 4371 for (i = 0; i < dom->n_div; ++i) {4372 int pos;4373 4374 pos = find_context_div(bmap, dom, i);4375 if (pos < 0)4376 return isl_basic_map_free(bmap);4377 if (pos < bmap_n_div)4378 common++;4379 }4380 other = bmap_n_div - common;4381 if (dom->n_div - common > 0) {4382 bmap = isl_basic_map_cow(bmap);4383 bmap = isl_basic_map_extend(bmap, dom->n_div - common, 0, 0);4384 if (!bmap)4385 return NULL;4386 }4387 for (i = 0; i < dom->n_div; ++i) {4388 int pos = find_context_div(bmap, dom, i);4389 if (pos < 0)4390 bmap = isl_basic_map_free(bmap);4391 if (pos >= bmap_n_div) {4392 pos = isl_basic_map_alloc_div(bmap);4393 if (pos < 0)4394 goto error;4395 isl_int_set_si(bmap->div[pos][0], 0);4396 bmap_n_div++;4397 }4398 if (pos != other + i)4399 bmap = isl_basic_map_swap_div(bmap, pos, other + i);4400 }4401 return bmap;4402error:4403 isl_basic_map_free(bmap);4404 return NULL;4405}4406 4407/* Base case of isl_tab_basic_map_partial_lexopt, after removing4408 * some obvious symmetries.4409 *4410 * We make sure the divs in the domain are properly ordered,4411 * because they will be added one by one in the given order4412 * during the construction of the solution map.4413 * Furthermore, make sure that the known integer divisions4414 * appear before any unknown integer division because the solution4415 * may depend on the known integer divisions, while anything that4416 * depends on any variable starting from the first unknown integer4417 * division is ignored in sol_pma_add.4418 */4419static struct isl_sol *basic_map_partial_lexopt_base_sol(4420 __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,4421 __isl_give isl_set **empty, int max,4422 struct isl_sol *(*init)(__isl_keep isl_basic_map *bmap,4423 __isl_take isl_basic_set *dom, int track_empty, int max))4424{4425 struct isl_tab *tab;4426 struct isl_sol *sol = NULL;4427 struct isl_context *context;4428 4429 if (dom->n_div) {4430 dom = isl_basic_set_sort_divs(dom);4431 bmap = align_context_divs(bmap, dom);4432 }4433 sol = init(bmap, dom, !!empty, max);4434 if (!sol)4435 goto error;4436 4437 context = sol->context;4438 if (isl_basic_set_plain_is_empty(context->op->peek_basic_set(context)))4439 /* nothing */;4440 else if (isl_basic_map_plain_is_empty(bmap)) {4441 if (sol->add_empty)4442 sol->add_empty(sol,4443 isl_basic_set_copy(context->op->peek_basic_set(context)));4444 } else {4445 tab = tab_for_lexmin(bmap,4446 context->op->peek_basic_set(context), 1, max);4447 tab = context->op->detect_nonnegative_parameters(context, tab);4448 find_solutions_main(sol, tab);4449 }4450 if (sol->error)4451 goto error;4452 4453 isl_basic_map_free(bmap);4454 return sol;4455error:4456 sol_free(sol);4457 isl_basic_map_free(bmap);4458 return NULL;4459}4460 4461/* Base case of isl_tab_basic_map_partial_lexopt, after removing4462 * some obvious symmetries.4463 *4464 * We call basic_map_partial_lexopt_base_sol and extract the results.4465 */4466static __isl_give isl_map *basic_map_partial_lexopt_base(4467 __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,4468 __isl_give isl_set **empty, int max)4469{4470 isl_map *result = NULL;4471 struct isl_sol *sol;4472 struct isl_sol_map *sol_map;4473 4474 sol = basic_map_partial_lexopt_base_sol(bmap, dom, empty, max,4475 &sol_map_init);4476 if (!sol)4477 return NULL;4478 sol_map = (struct isl_sol_map *) sol;4479 4480 result = isl_map_copy(sol_map->map);4481 if (empty)4482 *empty = isl_set_copy(sol_map->empty);4483 sol_free(&sol_map->sol);4484 return result;4485}4486 4487/* Return a count of the number of occurrences of the "n" first4488 * variables in the inequality constraints of "bmap".4489 */4490static __isl_give int *count_occurrences(__isl_keep isl_basic_map *bmap,4491 int n)4492{4493 int i, j;4494 isl_ctx *ctx;4495 int *occurrences;4496 4497 if (!bmap)4498 return NULL;4499 ctx = isl_basic_map_get_ctx(bmap);4500 occurrences = isl_calloc_array(ctx, int, n);4501 if (!occurrences)4502 return NULL;4503 4504 for (i = 0; i < bmap->n_ineq; ++i) {4505 for (j = 0; j < n; ++j) {4506 if (!isl_int_is_zero(bmap->ineq[i][1 + j]))4507 occurrences[j]++;4508 }4509 }4510 4511 return occurrences;4512}4513 4514/* Do all of the "n" variables with non-zero coefficients in "c"4515 * occur in exactly a single constraint.4516 * "occurrences" is an array of length "n" containing the number4517 * of occurrences of each of the variables in the inequality constraints.4518 */4519static int single_occurrence(int n, isl_int *c, int *occurrences)4520{4521 int i;4522 4523 for (i = 0; i < n; ++i) {4524 if (isl_int_is_zero(c[i]))4525 continue;4526 if (occurrences[i] != 1)4527 return 0;4528 }4529 4530 return 1;4531}4532 4533/* Do all of the "n" initial variables that occur in inequality constraint4534 * "ineq" of "bmap" only occur in that constraint?4535 */4536static int all_single_occurrence(__isl_keep isl_basic_map *bmap, int ineq,4537 int n)4538{4539 int i, j;4540 4541 for (i = 0; i < n; ++i) {4542 if (isl_int_is_zero(bmap->ineq[ineq][1 + i]))4543 continue;4544 for (j = 0; j < bmap->n_ineq; ++j) {4545 if (j == ineq)4546 continue;4547 if (!isl_int_is_zero(bmap->ineq[j][1 + i]))4548 return 0;4549 }4550 }4551 4552 return 1;4553}4554 4555/* Structure used during detection of parallel constraints.4556 * n_in: number of "input" variables: isl_dim_param + isl_dim_in4557 * n_out: number of "output" variables: isl_dim_out + isl_dim_div4558 * val: the coefficients of the output variables4559 */4560struct isl_constraint_equal_info {4561 unsigned n_in;4562 unsigned n_out;4563 isl_int *val;4564};4565 4566/* Check whether the coefficients of the output variables4567 * of the constraint in "entry" are equal to info->val.4568 */4569static isl_bool constraint_equal(const void *entry, const void *val)4570{4571 isl_int **row = (isl_int **)entry;4572 const struct isl_constraint_equal_info *info = val;4573 int eq;4574 4575 eq = isl_seq_eq((*row) + 1 + info->n_in, info->val, info->n_out);4576 return isl_bool_ok(eq);4577}4578 4579/* Check whether "bmap" has a pair of constraints that have4580 * the same coefficients for the output variables.4581 * Note that the coefficients of the existentially quantified4582 * variables need to be zero since the existentially quantified4583 * of the result are usually not the same as those of the input.4584 * Furthermore, check that each of the input variables that occur4585 * in those constraints does not occur in any other constraint.4586 * If so, return true and return the row indices of the two constraints4587 * in *first and *second.4588 */4589static isl_bool parallel_constraints(__isl_keep isl_basic_map *bmap,4590 int *first, int *second)4591{4592 int i;4593 isl_ctx *ctx;4594 int *occurrences = NULL;4595 struct isl_hash_table *table = NULL;4596 struct isl_hash_table_entry *entry;4597 struct isl_constraint_equal_info info;4598 isl_size nparam, n_in, n_out, n_div;4599 4600 ctx = isl_basic_map_get_ctx(bmap);4601 table = isl_hash_table_alloc(ctx, bmap->n_ineq);4602 if (!table)4603 goto error;4604 4605 nparam = isl_basic_map_dim(bmap, isl_dim_param);4606 n_in = isl_basic_map_dim(bmap, isl_dim_in);4607 n_out = isl_basic_map_dim(bmap, isl_dim_out);4608 n_div = isl_basic_map_dim(bmap, isl_dim_div);4609 if (nparam < 0 || n_in < 0 || n_out < 0 || n_div < 0)4610 goto error;4611 info.n_in = nparam + n_in;4612 occurrences = count_occurrences(bmap, info.n_in);4613 if (info.n_in && !occurrences)4614 goto error;4615 info.n_out = n_out + n_div;4616 for (i = 0; i < bmap->n_ineq; ++i) {4617 uint32_t hash;4618 4619 info.val = bmap->ineq[i] + 1 + info.n_in;4620 if (isl_seq_first_non_zero(info.val, n_out) < 0)4621 continue;4622 if (isl_seq_first_non_zero(info.val + n_out, n_div) >= 0)4623 continue;4624 if (!single_occurrence(info.n_in, bmap->ineq[i] + 1,4625 occurrences))4626 continue;4627 hash = isl_seq_get_hash(info.val, info.n_out);4628 entry = isl_hash_table_find(ctx, table, hash,4629 constraint_equal, &info, 1);4630 if (!entry)4631 goto error;4632 if (entry->data)4633 break;4634 entry->data = &bmap->ineq[i];4635 }4636 4637 if (i < bmap->n_ineq) {4638 *first = ((isl_int **)entry->data) - bmap->ineq; 4639 *second = i;4640 }4641 4642 isl_hash_table_free(ctx, table);4643 free(occurrences);4644 4645 return isl_bool_ok(i < bmap->n_ineq);4646error:4647 isl_hash_table_free(ctx, table);4648 free(occurrences);4649 return isl_bool_error;4650}4651 4652/* Given a set of upper bounds in "var", add constraints to "bset"4653 * that make the i-th bound smallest.4654 *4655 * In particular, if there are n bounds b_i, then add the constraints4656 *4657 * b_i <= b_j for j > i4658 * b_i < b_j for j < i4659 */4660static __isl_give isl_basic_set *select_minimum(__isl_take isl_basic_set *bset,4661 __isl_keep isl_mat *var, int i)4662{4663 isl_ctx *ctx;4664 int j, k;4665 4666 ctx = isl_mat_get_ctx(var);4667 4668 for (j = 0; j < var->n_row; ++j) {4669 if (j == i)4670 continue;4671 k = isl_basic_set_alloc_inequality(bset);4672 if (k < 0)4673 goto error;4674 isl_seq_combine(bset->ineq[k], ctx->one, var->row[j],4675 ctx->negone, var->row[i], var->n_col);4676 isl_int_set_si(bset->ineq[k][var->n_col], 0);4677 if (j < i)4678 isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1);4679 }4680 4681 bset = isl_basic_set_finalize(bset);4682 4683 return bset;4684error:4685 isl_basic_set_free(bset);4686 return NULL;4687}4688 4689/* Given a set of upper bounds on the last "input" variable m,4690 * construct a set that assigns the minimal upper bound to m, i.e.,4691 * construct a set that divides the space into cells where one4692 * of the upper bounds is smaller than all the others and assign4693 * this upper bound to m.4694 *4695 * In particular, if there are n bounds b_i, then the result4696 * consists of n basic sets, each one of the form4697 *4698 * m = b_i4699 * b_i <= b_j for j > i4700 * b_i < b_j for j < i4701 */4702static __isl_give isl_set *set_minimum(__isl_take isl_space *space,4703 __isl_take isl_mat *var)4704{4705 int i, k;4706 isl_basic_set *bset = NULL;4707 isl_set *set = NULL;4708 4709 if (!space || !var)4710 goto error;4711 4712 set = isl_set_alloc_space(isl_space_copy(space),4713 var->n_row, ISL_SET_DISJOINT);4714 4715 for (i = 0; i < var->n_row; ++i) {4716 bset = isl_basic_set_alloc_space(isl_space_copy(space), 0,4717 1, var->n_row - 1);4718 k = isl_basic_set_alloc_equality(bset);4719 if (k < 0)4720 goto error;4721 isl_seq_cpy(bset->eq[k], var->row[i], var->n_col);4722 isl_int_set_si(bset->eq[k][var->n_col], -1);4723 bset = select_minimum(bset, var, i);4724 set = isl_set_add_basic_set(set, bset);4725 }4726 4727 isl_space_free(space);4728 isl_mat_free(var);4729 return set;4730error:4731 isl_basic_set_free(bset);4732 isl_set_free(set);4733 isl_space_free(space);4734 isl_mat_free(var);4735 return NULL;4736}4737 4738/* Given that the last input variable of "bmap" represents the minimum4739 * of the bounds in "cst", check whether we need to split the domain4740 * based on which bound attains the minimum.4741 *4742 * A split is needed when the minimum appears in an integer division4743 * or in an equality. Otherwise, it is only needed if it appears in4744 * an upper bound that is different from the upper bounds on which it4745 * is defined.4746 */4747static isl_bool need_split_basic_map(__isl_keep isl_basic_map *bmap,4748 __isl_keep isl_mat *cst)4749{4750 int i, j;4751 isl_size total;4752 unsigned pos;4753 4754 pos = cst->n_col - 1;4755 total = isl_basic_map_dim(bmap, isl_dim_all);4756 if (total < 0)4757 return isl_bool_error;4758 4759 for (i = 0; i < bmap->n_div; ++i)4760 if (!isl_int_is_zero(bmap->div[i][2 + pos]))4761 return isl_bool_true;4762 4763 for (i = 0; i < bmap->n_eq; ++i)4764 if (!isl_int_is_zero(bmap->eq[i][1 + pos]))4765 return isl_bool_true;4766 4767 for (i = 0; i < bmap->n_ineq; ++i) {4768 if (isl_int_is_nonneg(bmap->ineq[i][1 + pos]))4769 continue;4770 if (!isl_int_is_negone(bmap->ineq[i][1 + pos]))4771 return isl_bool_true;4772 if (isl_seq_first_non_zero(bmap->ineq[i] + 1 + pos + 1,4773 total - pos - 1) >= 0)4774 return isl_bool_true;4775 4776 for (j = 0; j < cst->n_row; ++j)4777 if (isl_seq_eq(bmap->ineq[i], cst->row[j], cst->n_col))4778 break;4779 if (j >= cst->n_row)4780 return isl_bool_true;4781 }4782 4783 return isl_bool_false;4784}4785 4786/* Given that the last set variable of "bset" represents the minimum4787 * of the bounds in "cst", check whether we need to split the domain4788 * based on which bound attains the minimum.4789 *4790 * We simply call need_split_basic_map here. This is safe because4791 * the position of the minimum is computed from "cst" and not4792 * from "bmap".4793 */4794static isl_bool need_split_basic_set(__isl_keep isl_basic_set *bset,4795 __isl_keep isl_mat *cst)4796{4797 return need_split_basic_map(bset_to_bmap(bset), cst);4798}4799 4800/* Given that the last set variable of "set" represents the minimum4801 * of the bounds in "cst", check whether we need to split the domain4802 * based on which bound attains the minimum.4803 */4804static isl_bool need_split_set(__isl_keep isl_set *set, __isl_keep isl_mat *cst)4805{4806 int i;4807 4808 for (i = 0; i < set->n; ++i) {4809 isl_bool split;4810 4811 split = need_split_basic_set(set->p[i], cst);4812 if (split < 0 || split)4813 return split;4814 }4815 4816 return isl_bool_false;4817}4818 4819/* Given a map of which the last input variable is the minimum4820 * of the bounds in "cst", split each basic set in the set4821 * in pieces where one of the bounds is (strictly) smaller than the others.4822 * This subdivision is given in "min_expr".4823 * The variable is subsequently projected out.4824 *4825 * We only do the split when it is needed.4826 * For example if the last input variable m = min(a,b) and the only4827 * constraints in the given basic set are lower bounds on m,4828 * i.e., l <= m = min(a,b), then we can simply project out m4829 * to obtain l <= a and l <= b, without having to split on whether4830 * m is equal to a or b.4831 */4832static __isl_give isl_map *split_domain(__isl_take isl_map *opt,4833 __isl_take isl_set *min_expr, __isl_take isl_mat *cst)4834{4835 isl_size n_in;4836 int i;4837 isl_space *space;4838 isl_map *res;4839 4840 n_in = isl_map_dim(opt, isl_dim_in);4841 if (n_in < 0 || !min_expr || !cst)4842 goto error;4843 4844 space = isl_map_get_space(opt);4845 space = isl_space_drop_dims(space, isl_dim_in, n_in - 1, 1);4846 res = isl_map_empty(space);4847 4848 for (i = 0; i < opt->n; ++i) {4849 isl_map *map;4850 isl_bool split;4851 4852 map = isl_map_from_basic_map(isl_basic_map_copy(opt->p[i]));4853 split = need_split_basic_map(opt->p[i], cst);4854 if (split < 0)4855 map = isl_map_free(map);4856 else if (split)4857 map = isl_map_intersect_domain(map,4858 isl_set_copy(min_expr));4859 map = isl_map_remove_dims(map, isl_dim_in, n_in - 1, 1);4860 4861 res = isl_map_union_disjoint(res, map);4862 }4863 4864 isl_map_free(opt);4865 isl_set_free(min_expr);4866 isl_mat_free(cst);4867 return res;4868error:4869 isl_map_free(opt);4870 isl_set_free(min_expr);4871 isl_mat_free(cst);4872 return NULL;4873}4874 4875/* Given a set of which the last set variable is the minimum4876 * of the bounds in "cst", split each basic set in the set4877 * in pieces where one of the bounds is (strictly) smaller than the others.4878 * This subdivision is given in "min_expr".4879 * The variable is subsequently projected out.4880 */4881static __isl_give isl_set *split(__isl_take isl_set *empty,4882 __isl_take isl_set *min_expr, __isl_take isl_mat *cst)4883{4884 isl_map *map;4885 4886 map = isl_map_from_domain(empty);4887 map = split_domain(map, min_expr, cst);4888 empty = isl_map_domain(map);4889 4890 return empty;4891}4892 4893static __isl_give isl_map *basic_map_partial_lexopt(4894 __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,4895 __isl_give isl_set **empty, int max);4896 4897/* This function is called from basic_map_partial_lexopt_symm.4898 * The last variable of "bmap" and "dom" corresponds to the minimum4899 * of the bounds in "cst". "map_space" is the space of the original4900 * input relation (of basic_map_partial_lexopt_symm) and "set_space"4901 * is the space of the original domain.4902 *4903 * We recursively call basic_map_partial_lexopt and then plug in4904 * the definition of the minimum in the result.4905 */4906static __isl_give isl_map *basic_map_partial_lexopt_symm_core(4907 __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,4908 __isl_give isl_set **empty, int max, __isl_take isl_mat *cst,4909 __isl_take isl_space *map_space, __isl_take isl_space *set_space)4910{4911 isl_map *opt;4912 isl_set *min_expr;4913 4914 min_expr = set_minimum(isl_basic_set_get_space(dom), isl_mat_copy(cst));4915 4916 opt = basic_map_partial_lexopt(bmap, dom, empty, max);4917 4918 if (empty) {4919 *empty = split(*empty,4920 isl_set_copy(min_expr), isl_mat_copy(cst));4921 *empty = isl_set_reset_space(*empty, set_space);4922 }4923 4924 opt = split_domain(opt, min_expr, cst);4925 opt = isl_map_reset_space(opt, map_space);4926 4927 return opt;4928}4929 4930/* Extract a domain from "bmap" for the purpose of computing4931 * a lexicographic optimum.4932 *4933 * This function is only called when the caller wants to compute a full4934 * lexicographic optimum, i.e., without specifying a domain. In this case,4935 * the caller is not interested in the part of the domain space where4936 * there is no solution and the domain can be initialized to those constraints4937 * of "bmap" that only involve the parameters and the input dimensions.4938 * This relieves the parametric programming engine from detecting those4939 * inequalities and transferring them to the context. More importantly,4940 * it ensures that those inequalities are transferred first and not4941 * intermixed with inequalities that actually split the domain.4942 *4943 * If the caller does not require the absence of existentially quantified4944 * variables in the result (i.e., if ISL_OPT_QE is not set in "flags"),4945 * then the actual domain of "bmap" can be used. This ensures that4946 * the domain does not need to be split at all just to separate out4947 * pieces of the domain that do not have a solution from piece that do.4948 * This domain cannot be used in general because it may involve4949 * (unknown) existentially quantified variables which will then also4950 * appear in the solution.4951 */4952static __isl_give isl_basic_set *extract_domain(__isl_keep isl_basic_map *bmap,4953 unsigned flags)4954{4955 isl_size n_div;4956 isl_size n_out;4957 4958 n_div = isl_basic_map_dim(bmap, isl_dim_div);4959 n_out = isl_basic_map_dim(bmap, isl_dim_out);4960 if (n_div < 0 || n_out < 0)4961 return NULL;4962 bmap = isl_basic_map_copy(bmap);4963 if (ISL_FL_ISSET(flags, ISL_OPT_QE)) {4964 bmap = isl_basic_map_drop_constraints_involving_dims(bmap,4965 isl_dim_div, 0, n_div);4966 bmap = isl_basic_map_drop_constraints_involving_dims(bmap,4967 isl_dim_out, 0, n_out);4968 }4969 return isl_basic_map_domain(bmap);4970}4971 4972#undef TYPE4973#define TYPE isl_map4974#undef SUFFIX4975#define SUFFIX4976#include "isl_tab_lexopt_templ.c"4977 4978/* Extract the subsequence of the sample value of "tab"4979 * starting at "pos" and of length "len".4980 */4981static __isl_give isl_vec *extract_sample_sequence(struct isl_tab *tab,4982 int pos, int len)4983{4984 int i;4985 isl_ctx *ctx;4986 isl_vec *v;4987 4988 ctx = isl_tab_get_ctx(tab);4989 v = isl_vec_alloc(ctx, len);4990 if (!v)4991 return NULL;4992 for (i = 0; i < len; ++i) {4993 if (!tab->var[pos + i].is_row) {4994 isl_int_set_si(v->el[i], 0);4995 } else {4996 int row;4997 4998 row = tab->var[pos + i].index;4999 isl_int_divexact(v->el[i], tab->mat->row[row][1],5000 tab->mat->row[row][0]);5001 }5002 }5003 5004 return v;5005}5006 5007/* Check if the sequence of variables starting at "pos"5008 * represents a trivial solution according to "trivial".5009 * That is, is the result of applying "trivial" to this sequence5010 * equal to the zero vector?5011 */5012static isl_bool region_is_trivial(struct isl_tab *tab, int pos,5013 __isl_keep isl_mat *trivial)5014{5015 isl_size n, len;5016 isl_vec *v;5017 isl_bool is_trivial;5018 5019 n = isl_mat_rows(trivial);5020 if (n < 0)5021 return isl_bool_error;5022 5023 if (n == 0)5024 return isl_bool_false;5025 5026 len = isl_mat_cols(trivial);5027 if (len < 0)5028 return isl_bool_error;5029 v = extract_sample_sequence(tab, pos, len);5030 v = isl_mat_vec_product(isl_mat_copy(trivial), v);5031 is_trivial = isl_vec_is_zero(v);5032 isl_vec_free(v);5033 5034 return is_trivial;5035}5036 5037/* Global internal data for isl_tab_basic_set_non_trivial_lexmin.5038 *5039 * "n_op" is the number of initial coordinates to optimize,5040 * as passed to isl_tab_basic_set_non_trivial_lexmin.5041 * "region" is the "n_region"-sized array of regions passed5042 * to isl_tab_basic_set_non_trivial_lexmin.5043 *5044 * "tab" is the tableau that corresponds to the ILP problem.5045 * "local" is an array of local data structure, one for each5046 * (potential) level of the backtracking procedure of5047 * isl_tab_basic_set_non_trivial_lexmin.5048 * "v" is a pre-allocated vector that can be used for adding5049 * constraints to the tableau.5050 *5051 * "sol" contains the best solution found so far.5052 * It is initialized to a vector of size zero.5053 */5054struct isl_lexmin_data {5055 int n_op;5056 int n_region;5057 struct isl_trivial_region *region;5058 5059 struct isl_tab *tab;5060 struct isl_local_region *local;5061 isl_vec *v;5062 5063 isl_vec *sol;5064};5065 5066/* Return the index of the first trivial region, "n_region" if all regions5067 * are non-trivial or -1 in case of error.5068 */5069static int first_trivial_region(struct isl_lexmin_data *data)5070{5071 int i;5072 5073 for (i = 0; i < data->n_region; ++i) {5074 isl_bool trivial;5075 trivial = region_is_trivial(data->tab, data->region[i].pos,5076 data->region[i].trivial);5077 if (trivial < 0)5078 return -1;5079 if (trivial)5080 return i;5081 }5082 5083 return data->n_region;5084}5085 5086/* Check if the solution is optimal, i.e., whether the first5087 * n_op entries are zero.5088 */5089static int is_optimal(__isl_keep isl_vec *sol, int n_op)5090{5091 int i;5092 5093 for (i = 0; i < n_op; ++i)5094 if (!isl_int_is_zero(sol->el[1 + i]))5095 return 0;5096 return 1;5097}5098 5099/* Add constraints to "tab" that ensure that any solution is significantly5100 * better than that represented by "sol". That is, find the first5101 * relevant (within first n_op) non-zero coefficient and force it (along5102 * with all previous coefficients) to be zero.5103 * If the solution is already optimal (all relevant coefficients are zero),5104 * then just mark the table as empty.5105 * "n_zero" is the number of coefficients that have been forced zero5106 * by previous calls to this function at the same level.5107 * Return the updated number of forced zero coefficients or -1 on error.5108 *5109 * This function assumes that at least 2 * (n_op - n_zero) more rows and5110 * at least 2 * (n_op - n_zero) more elements in the constraint array5111 * are available in the tableau.5112 */5113static int force_better_solution(struct isl_tab *tab,5114 __isl_keep isl_vec *sol, int n_op, int n_zero)5115{5116 int i, n;5117 isl_ctx *ctx;5118 isl_vec *v = NULL;5119 5120 if (!sol)5121 return -1;5122 5123 for (i = n_zero; i < n_op; ++i)5124 if (!isl_int_is_zero(sol->el[1 + i]))5125 break;5126 5127 if (i == n_op) {5128 if (isl_tab_mark_empty(tab) < 0)5129 return -1;5130 return n_op;5131 }5132 5133 ctx = isl_vec_get_ctx(sol);5134 v = isl_vec_alloc(ctx, 1 + tab->n_var);5135 if (!v)5136 return -1;5137 5138 n = i + 1;5139 for (; i >= n_zero; --i) {5140 v = isl_vec_clr(v);5141 isl_int_set_si(v->el[1 + i], -1);5142 if (add_lexmin_eq(tab, v->el) < 0)5143 goto error;5144 }5145 5146 isl_vec_free(v);5147 return n;5148error:5149 isl_vec_free(v);5150 return -1;5151}5152 5153/* Fix triviality direction "dir" of the given region to zero.5154 *5155 * This function assumes that at least two more rows and at least5156 * two more elements in the constraint array are available in the tableau.5157 */5158static isl_stat fix_zero(struct isl_tab *tab, struct isl_trivial_region *region,5159 int dir, struct isl_lexmin_data *data)5160{5161 isl_size len;5162 5163 data->v = isl_vec_clr(data->v);5164 if (!data->v)5165 return isl_stat_error;5166 len = isl_mat_cols(region->trivial);5167 if (len < 0)5168 return isl_stat_error;5169 isl_seq_cpy(data->v->el + 1 + region->pos, region->trivial->row[dir],5170 len);5171 if (add_lexmin_eq(tab, data->v->el) < 0)5172 return isl_stat_error;5173 5174 return isl_stat_ok;5175}5176 5177/* This function selects case "side" for non-triviality region "region",5178 * assuming all the equality constraints have been imposed already.5179 * In particular, the triviality direction side/2 is made positive5180 * if side is even and made negative if side is odd.5181 *5182 * This function assumes that at least one more row and at least5183 * one more element in the constraint array are available in the tableau.5184 */5185static struct isl_tab *pos_neg(struct isl_tab *tab,5186 struct isl_trivial_region *region,5187 int side, struct isl_lexmin_data *data)5188{5189 isl_size len;5190 5191 data->v = isl_vec_clr(data->v);5192 if (!data->v)5193 goto error;5194 isl_int_set_si(data->v->el[0], -1);5195 len = isl_mat_cols(region->trivial);5196 if (len < 0)5197 goto error;5198 if (side % 2 == 0)5199 isl_seq_cpy(data->v->el + 1 + region->pos,5200 region->trivial->row[side / 2], len);5201 else5202 isl_seq_neg(data->v->el + 1 + region->pos,5203 region->trivial->row[side / 2], len);5204 return add_lexmin_ineq(tab, data->v->el);5205error:5206 isl_tab_free(tab);5207 return NULL;5208}5209 5210/* Local data at each level of the backtracking procedure of5211 * isl_tab_basic_set_non_trivial_lexmin.5212 *5213 * "update" is set if a solution has been found in the current case5214 * of this level, such that a better solution needs to be enforced5215 * in the next case.5216 * "n_zero" is the number of initial coordinates that have already5217 * been forced to be zero at this level.5218 * "region" is the non-triviality region considered at this level.5219 * "side" is the index of the current case at this level.5220 * "n" is the number of triviality directions.5221 * "snap" is a snapshot of the tableau holding a state that needs5222 * to be satisfied by all subsequent cases.5223 */5224struct isl_local_region {5225 int update;5226 int n_zero;5227 int region;5228 int side;5229 int n;5230 struct isl_tab_undo *snap;5231};5232 5233/* Initialize the global data structure "data" used while solving5234 * the ILP problem "bset".5235 */5236static isl_stat init_lexmin_data(struct isl_lexmin_data *data,5237 __isl_keep isl_basic_set *bset)5238{5239 isl_ctx *ctx;5240 5241 ctx = isl_basic_set_get_ctx(bset);5242 5243 data->tab = tab_for_lexmin(bset, NULL, 0, 0);5244 if (!data->tab)5245 return isl_stat_error;5246 5247 data->v = isl_vec_alloc(ctx, 1 + data->tab->n_var);5248 if (!data->v)5249 return isl_stat_error;5250 data->local = isl_calloc_array(ctx, struct isl_local_region,5251 data->n_region);5252 if (data->n_region && !data->local)5253 return isl_stat_error;5254 5255 data->sol = isl_vec_alloc(ctx, 0);5256 5257 return isl_stat_ok;5258}5259 5260/* Mark all outer levels as requiring a better solution5261 * in the next cases.5262 */5263static void update_outer_levels(struct isl_lexmin_data *data, int level)5264{5265 int i;5266 5267 for (i = 0; i < level; ++i)5268 data->local[i].update = 1;5269}5270 5271/* Initialize "local" to refer to region "region" and5272 * to initiate processing at this level.5273 */5274static isl_stat init_local_region(struct isl_local_region *local, int region,5275 struct isl_lexmin_data *data)5276{5277 isl_size n = isl_mat_rows(data->region[region].trivial);5278 5279 if (n < 0)5280 return isl_stat_error;5281 local->n = n;5282 local->region = region;5283 local->side = 0;5284 local->update = 0;5285 local->n_zero = 0;5286 5287 return isl_stat_ok;5288}5289 5290/* What to do next after entering a level of the backtracking procedure.5291 *5292 * error: some error has occurred; abort5293 * done: an optimal solution has been found; stop search5294 * backtrack: backtrack to the previous level5295 * handle: add the constraints for the current level and5296 * move to the next level5297 */5298enum isl_next {5299 isl_next_error = -1,5300 isl_next_done,5301 isl_next_backtrack,5302 isl_next_handle,5303};5304 5305/* Have all cases of the current region been considered?5306 * If there are n directions, then there are 2n cases.5307 *5308 * The constraints in the current tableau are imposed5309 * in all subsequent cases. This means that if the current5310 * tableau is empty, then none of those cases should be considered5311 * anymore and all cases have effectively been considered.5312 */5313static int finished_all_cases(struct isl_local_region *local,5314 struct isl_lexmin_data *data)5315{5316 if (data->tab->empty)5317 return 1;5318 return local->side >= 2 * local->n;5319}5320 5321/* Enter level "level" of the backtracking search and figure out5322 * what to do next. "init" is set if the level was entered5323 * from a higher level and needs to be initialized.5324 * Otherwise, the level is entered as a result of backtracking and5325 * the tableau needs to be restored to a position that can5326 * be used for the next case at this level.5327 * The snapshot is assumed to have been saved in the previous case,5328 * before the constraints specific to that case were added.5329 *5330 * In the initialization case, the local region is initialized5331 * to point to the first violated region.5332 * If the constraints of all regions are satisfied by the current5333 * sample of the tableau, then tell the caller to continue looking5334 * for a better solution or to stop searching if an optimal solution5335 * has been found.5336 *5337 * If the tableau is empty or if all cases at the current level5338 * have been considered, then the caller needs to backtrack as well.5339 */5340static enum isl_next enter_level(int level, int init,5341 struct isl_lexmin_data *data)5342{5343 struct isl_local_region *local = &data->local[level];5344 5345 if (init) {5346 int r;5347 5348 data->tab = cut_to_integer_lexmin(data->tab, CUT_ONE);5349 if (!data->tab)5350 return isl_next_error;5351 if (data->tab->empty)5352 return isl_next_backtrack;5353 r = first_trivial_region(data);5354 if (r < 0)5355 return isl_next_error;5356 if (r == data->n_region) {5357 update_outer_levels(data, level);5358 isl_vec_free(data->sol);5359 data->sol = isl_tab_get_sample_value(data->tab);5360 if (!data->sol)5361 return isl_next_error;5362 if (is_optimal(data->sol, data->n_op))5363 return isl_next_done;5364 return isl_next_backtrack;5365 }5366 if (level >= data->n_region)5367 isl_die(isl_vec_get_ctx(data->v), isl_error_internal,5368 "nesting level too deep",5369 return isl_next_error);5370 if (init_local_region(local, r, data) < 0)5371 return isl_next_error;5372 if (isl_tab_extend_cons(data->tab,5373 2 * local->n + 2 * data->n_op) < 0)5374 return isl_next_error;5375 } else {5376 if (isl_tab_rollback(data->tab, local->snap) < 0)5377 return isl_next_error;5378 }5379 5380 if (finished_all_cases(local, data))5381 return isl_next_backtrack;5382 return isl_next_handle;5383}5384 5385/* If a solution has been found in the previous case at this level5386 * (marked by local->update being set), then add constraints5387 * that enforce a better solution in the present and all following cases.5388 * The constraints only need to be imposed once because they are5389 * included in the snapshot (taken in pick_side) that will be used in5390 * subsequent cases.5391 */5392static isl_stat better_next_side(struct isl_local_region *local,5393 struct isl_lexmin_data *data)5394{5395 if (!local->update)5396 return isl_stat_ok;5397 5398 local->n_zero = force_better_solution(data->tab,5399 data->sol, data->n_op, local->n_zero);5400 if (local->n_zero < 0)5401 return isl_stat_error;5402 5403 local->update = 0;5404 5405 return isl_stat_ok;5406}5407 5408/* Add constraints to data->tab that select the current case (local->side)5409 * at the current level.5410 *5411 * If the linear combinations v should not be zero, then the cases are5412 * v_0 >= 15413 * v_0 <= -15414 * v_0 = 0 and v_1 >= 15415 * v_0 = 0 and v_1 <= -15416 * v_0 = 0 and v_1 = 0 and v_2 >= 15417 * v_0 = 0 and v_1 = 0 and v_2 <= -15418 * ...5419 * in this order.5420 *5421 * A snapshot is taken after the equality constraint (if any) has been added5422 * such that the next case can start off from this position.5423 * The rollback to this position is performed in enter_level.5424 */5425static isl_stat pick_side(struct isl_local_region *local,5426 struct isl_lexmin_data *data)5427{5428 struct isl_trivial_region *region;5429 int side, base;5430 5431 region = &data->region[local->region];5432 side = local->side;5433 base = 2 * (side/2);5434 5435 if (side == base && base >= 2 &&5436 fix_zero(data->tab, region, base / 2 - 1, data) < 0)5437 return isl_stat_error;5438 5439 local->snap = isl_tab_snap(data->tab);5440 if (isl_tab_push_basis(data->tab) < 0)5441 return isl_stat_error;5442 5443 data->tab = pos_neg(data->tab, region, side, data);5444 if (!data->tab)5445 return isl_stat_error;5446 return isl_stat_ok;5447}5448 5449/* Free the memory associated to "data".5450 */5451static void clear_lexmin_data(struct isl_lexmin_data *data)5452{5453 free(data->local);5454 isl_vec_free(data->v);5455 isl_tab_free(data->tab);5456}5457 5458/* Return the lexicographically smallest non-trivial solution of the5459 * given ILP problem.5460 *5461 * All variables are assumed to be non-negative.5462 *5463 * n_op is the number of initial coordinates to optimize.5464 * That is, once a solution has been found, we will only continue looking5465 * for solutions that result in significantly better values for those5466 * initial coordinates. That is, we only continue looking for solutions5467 * that increase the number of initial zeros in this sequence.5468 *5469 * A solution is non-trivial, if it is non-trivial on each of the5470 * specified regions. Each region represents a sequence of5471 * triviality directions on a sequence of variables that starts5472 * at a given position. A solution is non-trivial on such a region if5473 * at least one of the triviality directions is non-zero5474 * on that sequence of variables.5475 *5476 * Whenever a conflict is encountered, all constraints involved are5477 * reported to the caller through a call to "conflict".5478 *5479 * We perform a simple branch-and-bound backtracking search.5480 * Each level in the search represents an initially trivial region5481 * that is forced to be non-trivial.5482 * At each level we consider 2 * n cases, where n5483 * is the number of triviality directions.5484 * In terms of those n directions v_i, we consider the cases5485 * v_0 >= 15486 * v_0 <= -15487 * v_0 = 0 and v_1 >= 15488 * v_0 = 0 and v_1 <= -15489 * v_0 = 0 and v_1 = 0 and v_2 >= 15490 * v_0 = 0 and v_1 = 0 and v_2 <= -15491 * ...5492 * in this order.5493 */5494__isl_give isl_vec *isl_tab_basic_set_non_trivial_lexmin(5495 __isl_take isl_basic_set *bset, int n_op, int n_region,5496 struct isl_trivial_region *region,5497 int (*conflict)(int con, void *user), void *user)5498{5499 struct isl_lexmin_data data = { n_op, n_region, region };5500 int level, init;5501 5502 if (!bset)5503 return NULL;5504 5505 if (init_lexmin_data(&data, bset) < 0)5506 goto error;5507 data.tab->conflict = conflict;5508 data.tab->conflict_user = user;5509 5510 level = 0;5511 init = 1;5512 5513 while (level >= 0) {5514 enum isl_next next;5515 struct isl_local_region *local = &data.local[level];5516 5517 next = enter_level(level, init, &data);5518 if (next < 0)5519 goto error;5520 if (next == isl_next_done)5521 break;5522 if (next == isl_next_backtrack) {5523 level--;5524 init = 0;5525 continue;5526 }5527 5528 if (better_next_side(local, &data) < 0)5529 goto error;5530 if (pick_side(local, &data) < 0)5531 goto error;5532 5533 local->side++;5534 level++;5535 init = 1;5536 }5537 5538 clear_lexmin_data(&data);5539 isl_basic_set_free(bset);5540 5541 return data.sol;5542error:5543 clear_lexmin_data(&data);5544 isl_basic_set_free(bset);5545 isl_vec_free(data.sol);5546 return NULL;5547}5548 5549/* Wrapper for a tableau that is used for computing5550 * the lexicographically smallest rational point of a non-negative set.5551 * This point is represented by the sample value of "tab",5552 * unless "tab" is empty.5553 */5554struct isl_tab_lexmin {5555 isl_ctx *ctx;5556 struct isl_tab *tab;5557};5558 5559/* Free "tl" and return NULL.5560 */5561__isl_null isl_tab_lexmin *isl_tab_lexmin_free(__isl_take isl_tab_lexmin *tl)5562{5563 if (!tl)5564 return NULL;5565 isl_ctx_deref(tl->ctx);5566 isl_tab_free(tl->tab);5567 free(tl);5568 5569 return NULL;5570}5571 5572/* Construct an isl_tab_lexmin for computing5573 * the lexicographically smallest rational point in "bset",5574 * assuming that all variables are non-negative.5575 */5576__isl_give isl_tab_lexmin *isl_tab_lexmin_from_basic_set(5577 __isl_take isl_basic_set *bset)5578{5579 isl_ctx *ctx;5580 isl_tab_lexmin *tl;5581 5582 if (!bset)5583 return NULL;5584 5585 ctx = isl_basic_set_get_ctx(bset);5586 tl = isl_calloc_type(ctx, struct isl_tab_lexmin);5587 if (!tl)5588 goto error;5589 tl->ctx = ctx;5590 isl_ctx_ref(ctx);5591 tl->tab = tab_for_lexmin(bset, NULL, 0, 0);5592 isl_basic_set_free(bset);5593 if (!tl->tab)5594 return isl_tab_lexmin_free(tl);5595 return tl;5596error:5597 isl_basic_set_free(bset);5598 isl_tab_lexmin_free(tl);5599 return NULL;5600}5601 5602/* Return the dimension of the set represented by "tl".5603 */5604int isl_tab_lexmin_dim(__isl_keep isl_tab_lexmin *tl)5605{5606 return tl ? tl->tab->n_var : -1;5607}5608 5609/* Add the equality with coefficients "eq" to "tl", updating the optimal5610 * solution if needed.5611 * The equality is added as two opposite inequality constraints.5612 */5613__isl_give isl_tab_lexmin *isl_tab_lexmin_add_eq(__isl_take isl_tab_lexmin *tl,5614 isl_int *eq)5615{5616 unsigned n_var;5617 5618 if (!tl || !eq)5619 return isl_tab_lexmin_free(tl);5620 5621 if (isl_tab_extend_cons(tl->tab, 2) < 0)5622 return isl_tab_lexmin_free(tl);5623 n_var = tl->tab->n_var;5624 isl_seq_neg(eq, eq, 1 + n_var);5625 tl->tab = add_lexmin_ineq(tl->tab, eq);5626 isl_seq_neg(eq, eq, 1 + n_var);5627 tl->tab = add_lexmin_ineq(tl->tab, eq);5628 5629 if (!tl->tab)5630 return isl_tab_lexmin_free(tl);5631 5632 return tl;5633}5634 5635/* Add cuts to "tl" until the sample value reaches an integer value or5636 * until the result becomes empty.5637 */5638__isl_give isl_tab_lexmin *isl_tab_lexmin_cut_to_integer(5639 __isl_take isl_tab_lexmin *tl)5640{5641 if (!tl)5642 return NULL;5643 tl->tab = cut_to_integer_lexmin(tl->tab, CUT_ONE);5644 if (!tl->tab)5645 return isl_tab_lexmin_free(tl);5646 return tl;5647}5648 5649/* Return the lexicographically smallest rational point in the basic set5650 * from which "tl" was constructed.5651 * If the original input was empty, then return a zero-length vector.5652 */5653__isl_give isl_vec *isl_tab_lexmin_get_solution(__isl_keep isl_tab_lexmin *tl)5654{5655 if (!tl)5656 return NULL;5657 if (tl->tab->empty)5658 return isl_vec_alloc(tl->ctx, 0);5659 else5660 return isl_tab_get_sample_value(tl->tab);5661}5662 5663struct isl_sol_pma {5664 struct isl_sol sol;5665 isl_pw_multi_aff *pma;5666 isl_set *empty;5667};5668 5669static void sol_pma_free(struct isl_sol *sol)5670{5671 struct isl_sol_pma *sol_pma = (struct isl_sol_pma *) sol;5672 isl_pw_multi_aff_free(sol_pma->pma);5673 isl_set_free(sol_pma->empty);5674}5675 5676/* This function is called for parts of the context where there is5677 * no solution, with "bset" corresponding to the context tableau.5678 * Simply add the basic set to the set "empty".5679 */5680static void sol_pma_add_empty(struct isl_sol_pma *sol,5681 __isl_take isl_basic_set *bset)5682{5683 if (!bset || !sol->empty)5684 goto error;5685 5686 sol->empty = isl_set_grow(sol->empty, 1);5687 bset = isl_basic_set_simplify(bset);5688 bset = isl_basic_set_finalize(bset);5689 sol->empty = isl_set_add_basic_set(sol->empty, bset);5690 if (!sol->empty)5691 sol->sol.error = 1;5692 return;5693error:5694 isl_basic_set_free(bset);5695 sol->sol.error = 1;5696}5697 5698/* Given a basic set "dom" that represents the context and a tuple of5699 * affine expressions "maff" defined over this domain, construct5700 * an isl_pw_multi_aff with a single cell corresponding to "dom" and5701 * the affine expressions in "maff".5702 */5703static void sol_pma_add(struct isl_sol_pma *sol,5704 __isl_take isl_basic_set *dom, __isl_take isl_multi_aff *maff)5705{5706 isl_pw_multi_aff *pma;5707 5708 dom = isl_basic_set_simplify(dom);5709 dom = isl_basic_set_finalize(dom);5710 pma = isl_pw_multi_aff_alloc(isl_set_from_basic_set(dom), maff);5711 sol->pma = isl_pw_multi_aff_add_disjoint(sol->pma, pma);5712 if (!sol->pma)5713 sol->sol.error = 1;5714}5715 5716static void sol_pma_add_empty_wrap(struct isl_sol *sol,5717 __isl_take isl_basic_set *bset)5718{5719 sol_pma_add_empty((struct isl_sol_pma *)sol, bset);5720}5721 5722static void sol_pma_add_wrap(struct isl_sol *sol,5723 __isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma)5724{5725 sol_pma_add((struct isl_sol_pma *)sol, dom, ma);5726}5727 5728/* Construct an isl_sol_pma structure for accumulating the solution.5729 * If track_empty is set, then we also keep track of the parts5730 * of the context where there is no solution.5731 * If max is set, then we are solving a maximization, rather than5732 * a minimization problem, which means that the variables in the5733 * tableau have value "M - x" rather than "M + x".5734 */5735static struct isl_sol *sol_pma_init(__isl_keep isl_basic_map *bmap,5736 __isl_take isl_basic_set *dom, int track_empty, int max)5737{5738 struct isl_sol_pma *sol_pma = NULL;5739 isl_space *space;5740 5741 if (!bmap)5742 goto error;5743 5744 sol_pma = isl_calloc_type(bmap->ctx, struct isl_sol_pma);5745 if (!sol_pma)5746 goto error;5747 5748 sol_pma->sol.free = &sol_pma_free;5749 if (sol_init(&sol_pma->sol, bmap, dom, max) < 0)5750 goto error;5751 sol_pma->sol.add = &sol_pma_add_wrap;5752 sol_pma->sol.add_empty = track_empty ? &sol_pma_add_empty_wrap : NULL;5753 space = isl_space_copy(sol_pma->sol.space);5754 sol_pma->pma = isl_pw_multi_aff_empty(space);5755 if (!sol_pma->pma)5756 goto error;5757 5758 if (track_empty) {5759 sol_pma->empty = isl_set_alloc_space(isl_basic_set_get_space(dom),5760 1, ISL_SET_DISJOINT);5761 if (!sol_pma->empty)5762 goto error;5763 }5764 5765 isl_basic_set_free(dom);5766 return &sol_pma->sol;5767error:5768 isl_basic_set_free(dom);5769 sol_free(&sol_pma->sol);5770 return NULL;5771}5772 5773/* Base case of isl_tab_basic_map_partial_lexopt, after removing5774 * some obvious symmetries.5775 *5776 * We call basic_map_partial_lexopt_base_sol and extract the results.5777 */5778static __isl_give isl_pw_multi_aff *basic_map_partial_lexopt_base_pw_multi_aff(5779 __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,5780 __isl_give isl_set **empty, int max)5781{5782 isl_pw_multi_aff *result = NULL;5783 struct isl_sol *sol;5784 struct isl_sol_pma *sol_pma;5785 5786 sol = basic_map_partial_lexopt_base_sol(bmap, dom, empty, max,5787 &sol_pma_init);5788 if (!sol)5789 return NULL;5790 sol_pma = (struct isl_sol_pma *) sol;5791 5792 result = isl_pw_multi_aff_copy(sol_pma->pma);5793 if (empty)5794 *empty = isl_set_copy(sol_pma->empty);5795 sol_free(&sol_pma->sol);5796 return result;5797}5798 5799/* Given that the last input variable of "maff" represents the minimum5800 * of some bounds, check whether we need to plug in the expression5801 * of the minimum.5802 *5803 * In particular, check if the last input variable appears in any5804 * of the expressions in "maff".5805 */5806static isl_bool need_substitution(__isl_keep isl_multi_aff *maff)5807{5808 int i;5809 isl_size n_in;5810 unsigned pos;5811 5812 n_in = isl_multi_aff_dim(maff, isl_dim_in);5813 if (n_in < 0)5814 return isl_bool_error;5815 pos = n_in - 1;5816 5817 for (i = 0; i < maff->n; ++i) {5818 isl_bool involves;5819 5820 involves = isl_aff_involves_dims(maff->u.p[i],5821 isl_dim_in, pos, 1);5822 if (involves < 0 || involves)5823 return involves;5824 }5825 5826 return isl_bool_false;5827}5828 5829/* Given a set of upper bounds on the last "input" variable m,5830 * construct a piecewise affine expression that selects5831 * the minimal upper bound to m, i.e.,5832 * divide the space into cells where one5833 * of the upper bounds is smaller than all the others and select5834 * this upper bound on that cell.5835 *5836 * In particular, if there are n bounds b_i, then the result5837 * consists of n cell, each one of the form5838 *5839 * b_i <= b_j for j > i5840 * b_i < b_j for j < i5841 *5842 * The affine expression on this cell is5843 *5844 * b_i5845 */5846static __isl_give isl_pw_aff *set_minimum_pa(__isl_take isl_space *space,5847 __isl_take isl_mat *var)5848{5849 int i;5850 isl_aff *aff = NULL;5851 isl_basic_set *bset = NULL;5852 isl_pw_aff *paff = NULL;5853 isl_space *pw_space;5854 isl_local_space *ls = NULL;5855 5856 if (!space || !var)5857 goto error;5858 5859 ls = isl_local_space_from_space(isl_space_copy(space));5860 pw_space = isl_space_copy(space);5861 pw_space = isl_space_from_domain(pw_space);5862 pw_space = isl_space_add_dims(pw_space, isl_dim_out, 1);5863 paff = isl_pw_aff_alloc_size(pw_space, var->n_row);5864 5865 for (i = 0; i < var->n_row; ++i) {5866 isl_pw_aff *paff_i;5867 5868 aff = isl_aff_alloc(isl_local_space_copy(ls));5869 bset = isl_basic_set_alloc_space(isl_space_copy(space), 0,5870 0, var->n_row - 1);5871 if (!aff || !bset)5872 goto error;5873 isl_int_set_si(aff->v->el[0], 1);5874 isl_seq_cpy(aff->v->el + 1, var->row[i], var->n_col);5875 isl_int_set_si(aff->v->el[1 + var->n_col], 0);5876 bset = select_minimum(bset, var, i);5877 paff_i = isl_pw_aff_alloc(isl_set_from_basic_set(bset), aff);5878 paff = isl_pw_aff_add_disjoint(paff, paff_i);5879 }5880 5881 isl_local_space_free(ls);5882 isl_space_free(space);5883 isl_mat_free(var);5884 return paff;5885error:5886 isl_aff_free(aff);5887 isl_basic_set_free(bset);5888 isl_pw_aff_free(paff);5889 isl_local_space_free(ls);5890 isl_space_free(space);5891 isl_mat_free(var);5892 return NULL;5893}5894 5895/* Given a piecewise multi-affine expression of which the last input variable5896 * is the minimum of the bounds in "cst", plug in the value of the minimum.5897 * This minimum expression is given in "min_expr_pa".5898 * The set "min_expr" contains the same information, but in the form of a set.5899 * The variable is subsequently projected out.5900 *5901 * The implementation is similar to those of "split" and "split_domain".5902 * If the variable appears in a given expression, then minimum expression5903 * is plugged in. Otherwise, if the variable appears in the constraints5904 * and a split is required, then the domain is split. Otherwise, no split5905 * is performed.5906 */5907static __isl_give isl_pw_multi_aff *split_domain_pma(5908 __isl_take isl_pw_multi_aff *opt, __isl_take isl_pw_aff *min_expr_pa,5909 __isl_take isl_set *min_expr, __isl_take isl_mat *cst)5910{5911 isl_size n_in;5912 int i;5913 isl_space *space;5914 isl_pw_multi_aff *res;5915 5916 if (!opt || !min_expr || !cst)5917 goto error;5918 5919 n_in = isl_pw_multi_aff_dim(opt, isl_dim_in);5920 if (n_in < 0)5921 goto error;5922 space = isl_pw_multi_aff_get_space(opt);5923 space = isl_space_drop_dims(space, isl_dim_in, n_in - 1, 1);5924 res = isl_pw_multi_aff_empty(space);5925 5926 for (i = 0; i < opt->n; ++i) {5927 isl_bool subs;5928 isl_pw_multi_aff *pma;5929 5930 pma = isl_pw_multi_aff_alloc(isl_set_copy(opt->p[i].set),5931 isl_multi_aff_copy(opt->p[i].maff));5932 subs = need_substitution(opt->p[i].maff);5933 if (subs < 0) {5934 pma = isl_pw_multi_aff_free(pma);5935 } else if (subs) {5936 pma = isl_pw_multi_aff_substitute(pma,5937 n_in - 1, min_expr_pa);5938 } else {5939 isl_bool split;5940 split = need_split_set(opt->p[i].set, cst);5941 if (split < 0)5942 pma = isl_pw_multi_aff_free(pma);5943 else if (split)5944 pma = isl_pw_multi_aff_intersect_domain(pma,5945 isl_set_copy(min_expr));5946 }5947 pma = isl_pw_multi_aff_project_out(pma,5948 isl_dim_in, n_in - 1, 1);5949 5950 res = isl_pw_multi_aff_add_disjoint(res, pma);5951 }5952 5953 isl_pw_multi_aff_free(opt);5954 isl_pw_aff_free(min_expr_pa);5955 isl_set_free(min_expr);5956 isl_mat_free(cst);5957 return res;5958error:5959 isl_pw_multi_aff_free(opt);5960 isl_pw_aff_free(min_expr_pa);5961 isl_set_free(min_expr);5962 isl_mat_free(cst);5963 return NULL;5964}5965 5966static __isl_give isl_pw_multi_aff *basic_map_partial_lexopt_pw_multi_aff(5967 __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,5968 __isl_give isl_set **empty, int max);5969 5970/* This function is called from basic_map_partial_lexopt_symm.5971 * The last variable of "bmap" and "dom" corresponds to the minimum5972 * of the bounds in "cst". "map_space" is the space of the original5973 * input relation (of basic_map_partial_lexopt_symm) and "set_space"5974 * is the space of the original domain.5975 *5976 * We recursively call basic_map_partial_lexopt and then plug in5977 * the definition of the minimum in the result.5978 */5979static __isl_give isl_pw_multi_aff *5980basic_map_partial_lexopt_symm_core_pw_multi_aff(5981 __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,5982 __isl_give isl_set **empty, int max, __isl_take isl_mat *cst,5983 __isl_take isl_space *map_space, __isl_take isl_space *set_space)5984{5985 isl_pw_multi_aff *opt;5986 isl_pw_aff *min_expr_pa;5987 isl_set *min_expr;5988 5989 min_expr = set_minimum(isl_basic_set_get_space(dom), isl_mat_copy(cst));5990 min_expr_pa = set_minimum_pa(isl_basic_set_get_space(dom),5991 isl_mat_copy(cst));5992 5993 opt = basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, max);5994 5995 if (empty) {5996 *empty = split(*empty,5997 isl_set_copy(min_expr), isl_mat_copy(cst));5998 *empty = isl_set_reset_space(*empty, set_space);5999 }6000 6001 opt = split_domain_pma(opt, min_expr_pa, min_expr, cst);6002 opt = isl_pw_multi_aff_reset_space(opt, map_space);6003 6004 return opt;6005}6006 6007#undef TYPE6008#define TYPE isl_pw_multi_aff6009#undef SUFFIX6010#define SUFFIX _pw_multi_aff6011#include "isl_tab_lexopt_templ.c"6012