static int is_binary(LPX *lp, int j) { /* this routine checks if variable x[j] is binary */ return lpx_get_col_kind(lp, j) == LPX_IV && lpx_get_col_type(lp, j) == LPX_DB && lpx_get_col_lb(lp, j) == 0.0 && lpx_get_col_ub(lp, j) == 1.0; }
void lpx_get_col_bnds(glp_prob *lp, int j, int *typx, double *lb, double *ub) { /* retrieve column bounds */ if (typx != NULL) *typx = lpx_get_col_type(lp, j); if (lb != NULL) *lb = lpx_get_col_lb(lp, j); if (ub != NULL) *ub = lpx_get_col_ub(lp, j); return; }
static void calc_mn(struct dsa *dsa) { /* calculate the number of constraints (m) and variables (n) for transformed LP */ LPX *lp = dsa->lp; int orig_m = dsa->orig_m; int orig_n = dsa->orig_n; int i, j, m = 0, n = 0; for (i = 1; i <= orig_m; i++) { switch (lpx_get_row_type(lp, i)) { case LPX_FR: break; case LPX_LO: m++; n++; break; case LPX_UP: m++; n++; break; case LPX_DB: m += 2; n += 2; break; case LPX_FX: m++; break; default: insist(lp != lp); } } for (j = 1; j <= orig_n; j++) { switch (lpx_get_col_type(lp, j)) { case LPX_FR: n += 2; break; case LPX_LO: n++; break; case LPX_UP: n++; break; case LPX_DB: m++; n += 2; break; case LPX_FX: break; default: insist(lp != lp); } } dsa->m = m; dsa->n = n; return; }
static double get_col_ub(LPX *lp, int j) { /* this routine returns upper bound of column j or +DBL_MAX if the column has no upper bound */ double ub; switch (lpx_get_col_type(lp, j)) { case LPX_FR: case LPX_LO: ub = +DBL_MAX; break; case LPX_UP: case LPX_DB: case LPX_FX: ub = lpx_get_col_ub(lp, j); break; default: xassert(lp != lp); } return ub; }
static double get_col_lb(LPX *lp, int j) { /* this routine returns lower bound of column j or -DBL_MAX if the column has no lower bound */ double lb; switch (lpx_get_col_type(lp, j)) { case LPX_FR: case LPX_UP: lb = -DBL_MAX; break; case LPX_LO: case LPX_DB: case LPX_FX: lb = lpx_get_col_lb(lp, j); break; default: xassert(lp != lp); } return lb; }
void lpx_std_basis(LPX *lp) { int i, j, m, n, type; double lb, ub; /* all auxiliary variables are basic */ m = lpx_get_num_rows(lp); for (i = 1; i <= m; i++) lpx_set_row_stat(lp, i, LPX_BS); /* all structural variables are non-basic */ n = lpx_get_num_cols(lp); for (j = 1; j <= n; j++) { type = lpx_get_col_type(lp, j); lb = lpx_get_col_lb(lp, j); ub = lpx_get_col_ub(lp, j); if (type != LPX_DB || fabs(lb) <= fabs(ub)) lpx_set_col_stat(lp, j, LPX_NL); else lpx_set_col_stat(lp, j, LPX_NU); } return; }
static void restore(struct dsa *dsa, double row_pval[], double row_dval[], double col_pval[], double col_dval[]) { /* restore solution of original LP */ LPX *lp = dsa->lp; int orig_m = dsa->orig_m; int orig_n = dsa->orig_n; int *ref = dsa->ref; int m = dsa->m; double *x = dsa->x; double *y = dsa->y; int dir = lpx_get_obj_dir(lp); int i, j, k, type, t, len, *ind; double lb, ub, rii, sjj, temp, *val; /* compute primal values of structural variables */ for (k = 1; k <= orig_n; k++) { j = ref[orig_m+k]; type = lpx_get_col_type(lp, k); sjj = lpx_get_sjj(lp, k); lb = lpx_get_col_lb(lp, k) / sjj; ub = lpx_get_col_ub(lp, k) / sjj; switch (type) { case LPX_FR: /* source: -inf < x < +inf */ /* result: x = x' - x'', x' >= 0, x'' >= 0 */ col_pval[k] = x[j] - x[j+1]; break; case LPX_LO: /* source: lb <= x < +inf */ /* result: x = lb + x', x' >= 0 */ col_pval[k] = lb + x[j]; break; case LPX_UP: /* source: -inf < x <= ub */ /* result: x = ub - x', x' >= 0 */ col_pval[k] = ub - x[j]; break; case LPX_DB: /* source: lb <= x <= ub */ /* result: x = lb + x', x' + x'' = ub - lb */ col_pval[k] = lb + x[j]; break; case LPX_FX: /* source: x = lb */ /* result: just substitute */ col_pval[k] = lb; break; default: insist(type != type); } } /* compute primal values of auxiliary variables */ /* xR = A * xS */ ind = ucalloc(1+orig_n, sizeof(int)); val = ucalloc(1+orig_n, sizeof(double)); for (k = 1; k <= orig_m; k++) { rii = lpx_get_rii(lp, k); temp = 0.0; len = lpx_get_mat_row(lp, k, ind, val); for (t = 1; t <= len; t++) { sjj = lpx_get_sjj(lp, ind[t]); temp += (rii * val[t] * sjj) * col_pval[ind[t]]; } row_pval[k] = temp; } ufree(ind); ufree(val); /* compute dual values of auxiliary variables */ for (k = 1; k <= orig_m; k++) { type = lpx_get_row_type(lp, k); i = ref[k]; switch (type) { case LPX_FR: insist(i == 0); row_dval[k] = 0.0; break; case LPX_LO: case LPX_UP: case LPX_DB: case LPX_FX: insist(1 <= i && i <= m); row_dval[k] = (dir == LPX_MIN ? +1.0 : -1.0) * y[i]; break; default: insist(type != type); } } /* compute dual values of structural variables */ /* dS = cS - A' * (dR - cR) */ ind = ucalloc(1+orig_m, sizeof(int)); val = ucalloc(1+orig_m, sizeof(double)); for (k = 1; k <= orig_n; k++) { sjj = lpx_get_sjj(lp, k); temp = lpx_get_obj_coef(lp, k) / sjj; len = lpx_get_mat_col(lp, k, ind, val); for (t = 1; t <= len; t++) { rii = lpx_get_rii(lp, ind[t]); temp -= (rii * val[t] * sjj) * row_dval[ind[t]]; } col_dval[k] = temp; } ufree(ind); ufree(val); /* unscale solution of original LP */ for (i = 1; i <= orig_m; i++) { rii = lpx_get_rii(lp, i); row_pval[i] /= rii; row_dval[i] *= rii; } for (j = 1; j <= orig_n; j++) { sjj = lpx_get_sjj(lp, j); col_pval[j] *= sjj; col_dval[j] /= sjj; } return; }
static void transform(struct dsa *dsa) { /* transform original LP to standard formulation */ LPX *lp = dsa->lp; int orig_m = dsa->orig_m; int orig_n = dsa->orig_n; int *ref = dsa->ref; int m = dsa->m; int n = dsa->n; double *b = dsa->b; double *c = dsa->c; int i, j, k, type, t, ii, len, *ind; double lb, ub, coef, rii, sjj, *val; /* initialize components of transformed LP */ dsa->ne = 0; for (i = 1; i <= m; i++) b[i] = 0.0; c[0] = lpx_get_obj_coef(lp, 0); for (j = 1; j <= n; j++) c[j] = 0.0; /* i and j are, respectively, ordinal number of current row and ordinal number of current column in transformed LP */ i = j = 0; /* transform rows (auxiliary variables) */ for (k = 1; k <= orig_m; k++) { type = lpx_get_row_type(lp, k); rii = lpx_get_rii(lp, k); lb = lpx_get_row_lb(lp, k) * rii; ub = lpx_get_row_ub(lp, k) * rii; switch (type) { case LPX_FR: /* source: -inf < (L.F.) < +inf */ /* result: ignore free row */ ref[k] = 0; break; case LPX_LO: /* source: lb <= (L.F.) < +inf */ /* result: (L.F.) - x' = lb, x' >= 0 */ i++; j++; ref[k] = i; new_coef(dsa, i, j, -1.0); b[i] = lb; break; case LPX_UP: /* source: -inf < (L.F.) <= ub */ /* result: (L.F.) + x' = ub, x' >= 0 */ i++; j++; ref[k] = i; new_coef(dsa, i, j, +1.0); b[i] = ub; break; case LPX_DB: /* source: lb <= (L.F.) <= ub */ /* result: (L.F.) - x' = lb, x' + x'' = ub - lb */ i++; j++; ref[k] = i; new_coef(dsa, i, j, -1.0); b[i] = lb; i++; new_coef(dsa, i, j, +1.0); j++; new_coef(dsa, i, j, +1.0); b[i] = ub - lb; break; case LPX_FX: /* source: (L.F.) = lb */ /* result: (L.F.) = lb */ i++; ref[k] = i; b[i] = lb; break; default: insist(type != type); } } /* transform columns (structural variables) */ ind = ucalloc(1+orig_m, sizeof(int)); val = ucalloc(1+orig_m, sizeof(double)); for (k = 1; k <= orig_n; k++) { type = lpx_get_col_type(lp, k); sjj = lpx_get_sjj(lp, k); lb = lpx_get_col_lb(lp, k) / sjj; ub = lpx_get_col_ub(lp, k) / sjj; coef = lpx_get_obj_coef(lp, k) * sjj; len = lpx_get_mat_col(lp, k, ind, val); for (t = 1; t <= len; t++) val[t] *= (lpx_get_rii(lp, ind[t]) * sjj); switch (type) { case LPX_FR: /* source: -inf < x < +inf */ /* result: x = x' - x'', x' >= 0, x'' >= 0 */ j++; ref[orig_m+k] = j; for (t = 1; t <= len; t++) { ii = ref[ind[t]]; if (ii != 0) new_coef(dsa, ii, j, +val[t]); } c[j] = +coef; j++; for (t = 1; t <= len; t++) { ii = ref[ind[t]]; if (ii != 0) new_coef(dsa, ii, j, -val[t]); } c[j] = -coef; break; case LPX_LO: /* source: lb <= x < +inf */ /* result: x = lb + x', x' >= 0 */ j++; ref[orig_m+k] = j; for (t = 1; t <= len; t++) { ii = ref[ind[t]]; if (ii != 0) { new_coef(dsa, ii, j, val[t]); b[ii] -= val[t] * lb; } } c[j] = +coef; c[0] += c[j] * lb; break; case LPX_UP: /* source: -inf < x <= ub */ /* result: x = ub - x', x' >= 0 */ j++; ref[orig_m+k] = j; for (t = 1; t <= len; t++) { ii = ref[ind[t]]; if (ii != 0) { new_coef(dsa, ii, j, -val[t]); b[ii] -= val[t] * ub; } } c[j] = -coef; c[0] -= c[j] * ub; break; case LPX_DB: /* source: lb <= x <= ub */ /* result: x = lb + x', x' + x'' = ub - lb */ j++; ref[orig_m+k] = j; for (t = 1; t <= len; t++) { ii = ref[ind[t]]; if (ii != 0) { new_coef(dsa, ii, j, val[t]); b[ii] -= val[t] * lb; } } c[j] = +coef; c[0] += c[j] * lb; i++; new_coef(dsa, i, j, +1.0); j++; new_coef(dsa, i, j, +1.0); b[i] = ub - lb; break; case LPX_FX: /* source: x = lb */ /* result: just substitute */ ref[orig_m+k] = 0; for (t = 1; t <= len; t++) { ii = ref[ind[t]]; if (ii != 0) b[ii] -= val[t] * lb; } c[0] += coef * lb; break; default: insist(type != type); } } ufree(ind); ufree(val); /* end of transformation */ insist(i == m && j == n); /* change the objective sign in case of maximization */ if (lpx_get_obj_dir(lp) == LPX_MAX) for (j = 0; j <= n; j++) c[j] = -c[j]; return; }
int lpx_integer(LPX *mip) { int m = lpx_get_num_rows(mip); int n = lpx_get_num_cols(mip); MIPTREE *tree; LPX *lp; int ret, i, j, stat, type, len, *ind; double lb, ub, coef, *val; #if 0 /* the problem must be of MIP class */ if (lpx_get_class(mip) != LPX_MIP) { print("lpx_integer: problem is not of MIP class"); ret = LPX_E_FAULT; goto done; } #endif /* an optimal solution of LP relaxation must be known */ if (lpx_get_status(mip) != LPX_OPT) { print("lpx_integer: optimal solution of LP relaxation required" ); ret = LPX_E_FAULT; goto done; } /* bounds of all integer variables must be integral */ for (j = 1; j <= n; j++) { if (lpx_get_col_kind(mip, j) != LPX_IV) continue; type = lpx_get_col_type(mip, j); if (type == LPX_LO || type == LPX_DB || type == LPX_FX) { lb = lpx_get_col_lb(mip, j); if (lb != floor(lb)) { print("lpx_integer: integer column %d has non-integer lo" "wer bound or fixed value %g", j, lb); ret = LPX_E_FAULT; goto done; } } if (type == LPX_UP || type == LPX_DB) { ub = lpx_get_col_ub(mip, j); if (ub != floor(ub)) { print("lpx_integer: integer column %d has non-integer up" "per bound %g", j, ub); ret = LPX_E_FAULT; goto done; } } } /* it seems all is ok */ if (lpx_get_int_parm(mip, LPX_K_MSGLEV) >= 2) print("Integer optimization begins..."); /* create the branch-and-bound tree */ tree = mip_create_tree(m, n, lpx_get_obj_dir(mip)); /* set up column kinds */ for (j = 1; j <= n; j++) tree->int_col[j] = (lpx_get_col_kind(mip, j) == LPX_IV); /* access the LP relaxation template */ lp = tree->lp; /* set up the objective function */ tree->int_obj = 1; for (j = 0; j <= tree->n; j++) { coef = lpx_get_obj_coef(mip, j); lpx_set_obj_coef(lp, j, coef); if (coef != 0.0 && !(tree->int_col[j] && coef == floor(coef))) tree->int_obj = 0; } if (lpx_get_int_parm(mip, LPX_K_MSGLEV) >= 2 && tree->int_obj) print("Objective function is integral"); /* set up the constraint matrix */ ind = xcalloc(1+n, sizeof(int)); val = xcalloc(1+n, sizeof(double)); for (i = 1; i <= m; i++) { len = lpx_get_mat_row(mip, i, ind, val); lpx_set_mat_row(lp, i, len, ind, val); } xfree(ind); xfree(val); /* set up scaling matrices */ for (i = 1; i <= m; i++) lpx_set_rii(lp, i, lpx_get_rii(mip, i)); for (j = 1; j <= n; j++) lpx_set_sjj(lp, j, lpx_get_sjj(mip, j)); /* revive the root subproblem */ mip_revive_node(tree, 1); /* set up row attributes for the root subproblem */ for (i = 1; i <= m; i++) { type = lpx_get_row_type(mip, i); lb = lpx_get_row_lb(mip, i); ub = lpx_get_row_ub(mip, i); stat = lpx_get_row_stat(mip, i); lpx_set_row_bnds(lp, i, type, lb, ub); lpx_set_row_stat(lp, i, stat); } /* set up column attributes for the root subproblem */ for (j = 1; j <= n; j++) { type = lpx_get_col_type(mip, j); lb = lpx_get_col_lb(mip, j); ub = lpx_get_col_ub(mip, j); stat = lpx_get_col_stat(mip, j); lpx_set_col_bnds(lp, j, type, lb, ub); lpx_set_col_stat(lp, j, stat); } /* freeze the root subproblem */ mip_freeze_node(tree); /* inherit some control parameters and statistics */ tree->msg_lev = lpx_get_int_parm(mip, LPX_K_MSGLEV); if (tree->msg_lev > 2) tree->msg_lev = 2; tree->branch = lpx_get_int_parm(mip, LPX_K_BRANCH); tree->btrack = lpx_get_int_parm(mip, LPX_K_BTRACK); tree->tol_int = lpx_get_real_parm(mip, LPX_K_TOLINT); tree->tol_obj = lpx_get_real_parm(mip, LPX_K_TOLOBJ); tree->tm_lim = lpx_get_real_parm(mip, LPX_K_TMLIM); lpx_set_int_parm(lp, LPX_K_BFTYPE, lpx_get_int_parm(mip, LPX_K_BFTYPE)); lpx_set_int_parm(lp, LPX_K_PRICE, lpx_get_int_parm(mip, LPX_K_PRICE)); lpx_set_real_parm(lp, LPX_K_RELAX, lpx_get_real_parm(mip, LPX_K_RELAX)); lpx_set_real_parm(lp, LPX_K_TOLBND, lpx_get_real_parm(mip, LPX_K_TOLBND)); lpx_set_real_parm(lp, LPX_K_TOLDJ, lpx_get_real_parm(mip, LPX_K_TOLDJ)); lpx_set_real_parm(lp, LPX_K_TOLPIV, lpx_get_real_parm(mip, LPX_K_TOLPIV)); lpx_set_int_parm(lp, LPX_K_ITLIM, lpx_get_int_parm(mip, LPX_K_ITLIM)); lpx_set_int_parm(lp, LPX_K_ITCNT, lpx_get_int_parm(mip, LPX_K_ITCNT)); /* reset the status of MIP solution */ lpx_put_mip_soln(mip, LPX_I_UNDEF, NULL, NULL); /* try solving the problem */ ret = mip_driver(tree); /* if an integer feasible solution has been found, copy it to the MIP problem object */ if (tree->found) lpx_put_mip_soln(mip, LPX_I_FEAS, &tree->mipx[0], &tree->mipx[m]); /* copy back statistics about spent resources */ lpx_set_real_parm(mip, LPX_K_TMLIM, tree->tm_lim); lpx_set_int_parm(mip, LPX_K_ITLIM, lpx_get_int_parm(lp, LPX_K_ITLIM)); lpx_set_int_parm(mip, LPX_K_ITCNT, lpx_get_int_parm(lp, LPX_K_ITCNT)); /* analyze exit code reported by the mip driver */ switch (ret) { case MIP_E_OK: if (tree->found) { if (lpx_get_int_parm(mip, LPX_K_MSGLEV) >= 3) print("INTEGER OPTIMAL SOLUTION FOUND"); lpx_put_mip_soln(mip, LPX_I_OPT, NULL, NULL); } else { if (lpx_get_int_parm(mip, LPX_K_MSGLEV) >= 3) print("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION"); lpx_put_mip_soln(mip, LPX_I_NOFEAS, NULL, NULL); } ret = LPX_E_OK; break; case MIP_E_ITLIM: if (lpx_get_int_parm(mip, LPX_K_MSGLEV) >= 3) print("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED"); ret = LPX_E_ITLIM; break; case MIP_E_TMLIM: if (lpx_get_int_parm(mip, LPX_K_MSGLEV) >= 3) print("TIME LIMIT EXCEEDED; SEARCH TERMINATED"); ret = LPX_E_TMLIM; break; case MIP_E_ERROR: if (lpx_get_int_parm(mip, LPX_K_MSGLEV) >= 1) print("lpx_integer: cannot solve current LP relaxation"); ret = LPX_E_SING; break; default: xassert(ret != ret); } /* delete the branch-and-bound tree */ mip_delete_tree(tree); done: /* return to the application program */ return ret; }
void lpx_check_int(LPX *lp, LPXKKT *kkt) { int m = lpx_get_num_rows(lp); int n = lpx_get_num_cols(lp); int *ind, i, len, t, j, k, type; double *val, xR_i, g_i, xS_j, temp, lb, ub, x_k, h_k; /*--------------------------------------------------------------*/ /* compute largest absolute and relative errors and corresponding row indices for the condition (KKT.PE) */ kkt->pe_ae_max = 0.0, kkt->pe_ae_row = 0; kkt->pe_re_max = 0.0, kkt->pe_re_row = 0; ind = xcalloc(1+n, sizeof(int)); val = xcalloc(1+n, sizeof(double)); for (i = 1; i <= m; i++) { /* determine xR[i] */ xR_i = lpx_mip_row_val(lp, i); /* g[i] := xR[i] */ g_i = xR_i; /* g[i] := g[i] - (i-th row of A) * xS */ len = lpx_get_mat_row(lp, i, ind, val); for (t = 1; t <= len; t++) { j = ind[t]; /* determine xS[j] */ xS_j = lpx_mip_col_val(lp, j); /* g[i] := g[i] - a[i,j] * xS[j] */ g_i -= val[t] * xS_j; } /* determine absolute error */ temp = fabs(g_i); if (kkt->pe_ae_max < temp) kkt->pe_ae_max = temp, kkt->pe_ae_row = i; /* determine relative error */ temp /= (1.0 + fabs(xR_i)); if (kkt->pe_re_max < temp) kkt->pe_re_max = temp, kkt->pe_re_row = i; } xfree(ind); xfree(val); /* estimate the solution quality */ if (kkt->pe_re_max <= 1e-9) kkt->pe_quality = 'H'; else if (kkt->pe_re_max <= 1e-6) kkt->pe_quality = 'M'; else if (kkt->pe_re_max <= 1e-3) kkt->pe_quality = 'L'; else kkt->pe_quality = '?'; /*--------------------------------------------------------------*/ /* compute largest absolute and relative errors and corresponding variable indices for the condition (KKT.PB) */ kkt->pb_ae_max = 0.0, kkt->pb_ae_ind = 0; kkt->pb_re_max = 0.0, kkt->pb_re_ind = 0; for (k = 1; k <= m+n; k++) { /* determine x[k] */ if (k <= m) { i = k; type = lpx_get_row_type(lp, i); lb = lpx_get_row_lb(lp, i); ub = lpx_get_row_ub(lp, i); x_k = lpx_mip_row_val(lp, i); } else { j = k - m; type = lpx_get_col_type(lp, j); lb = lpx_get_col_lb(lp, j); ub = lpx_get_col_ub(lp, j); x_k = lpx_mip_col_val(lp, j); } /* compute h[k] */ h_k = 0.0; switch (type) { case LPX_FR: break; case LPX_LO: if (x_k < lb) h_k = x_k - lb; break; case LPX_UP: if (x_k > ub) h_k = x_k - ub; break; case LPX_DB: case LPX_FX: if (x_k < lb) h_k = x_k - lb; if (x_k > ub) h_k = x_k - ub; break; default: xassert(type != type); } /* determine absolute error */ temp = fabs(h_k); if (kkt->pb_ae_max < temp) kkt->pb_ae_max = temp, kkt->pb_ae_ind = k; /* determine relative error */ temp /= (1.0 + fabs(x_k)); if (kkt->pb_re_max < temp) kkt->pb_re_max = temp, kkt->pb_re_ind = k; } /* estimate the solution quality */ if (kkt->pb_re_max <= 1e-9) kkt->pb_quality = 'H'; else if (kkt->pb_re_max <= 1e-6) kkt->pb_quality = 'M'; else if (kkt->pb_re_max <= 1e-3) kkt->pb_quality = 'L'; else kkt->pb_quality = '?'; return; }
void ipp_load_orig(IPP *ipp, LPX *orig) { IPPROW **row; IPPCOL *col; int i, j, k, type, len, *ind; double lb, ub, *val; /* save some information about the original problem */ ipp->orig_m = lpx_get_num_rows(orig); ipp->orig_n = lpx_get_num_cols(orig); ipp->orig_nnz = lpx_get_num_nz(orig); ipp->orig_dir = lpx_get_obj_dir(orig); /* allocate working arrays */ row = xcalloc(1+ipp->orig_m, sizeof(IPPROW *)); ind = xcalloc(1+ipp->orig_m, sizeof(int)); val = xcalloc(1+ipp->orig_m, sizeof(double)); /* copy rows of the original problem into the workspace */ for (i = 1; i <= ipp->orig_m; i++) { type = lpx_get_row_type(orig, i); if (type == LPX_FR || type == LPX_UP) lb = -DBL_MAX; else lb = lpx_get_row_lb(orig, i); if (type == LPX_FR || type == LPX_LO) ub = +DBL_MAX; else ub = lpx_get_row_ub(orig, i); row[i] = ipp_add_row(ipp, lb, ub); } /* copy columns of the original problem into the workspace; each column created in the workspace is assigned a reference number which is its ordinal number in the original problem */ for (j = 1; j <= ipp->orig_n; j++) { type = lpx_get_col_type(orig, j); if (type == LPX_FR || type == LPX_UP) lb = -DBL_MAX; else lb = lpx_get_col_lb(orig, j); if (type == LPX_FR || type == LPX_LO) ub = +DBL_MAX; else ub = lpx_get_col_ub(orig, j); col = ipp_add_col(ipp, lpx_get_col_kind(orig, j) == LPX_IV, lb, ub, lpx_get_obj_coef(orig, j)); len = lpx_get_mat_col(orig, j, ind, val); for (k = 1; k <= len; k++) ipp_add_aij(ipp, row[ind[k]], col, val[k]); } /* copy the constant term of the original objective function */ ipp->c0 = lpx_get_obj_coef(orig, 0); /* if the original problem is maximization, change the sign of the objective function, because the transformed problem to be processed by the presolver must be minimization */ if (ipp->orig_dir == LPX_MAX) { for (col = ipp->col_ptr; col != NULL; col = col->next) col->c = - col->c; ipp->c0 = - ipp->c0; } /* free working arrays */ xfree(row); xfree(ind); xfree(val); return; }
int lpx_prim_ratio_test(LPX *lp, int len, const int ind[], const double val[], int how, double tol) { int i, k, m, n, p, t, typx, tagx; double alfa_i, abs_alfa_i, big, eps, bbar_i, lb_i, ub_i, temp, teta; if (!lpx_is_b_avail(lp)) xfault("lpx_prim_ratio_test: LP basis is not available\n"); if (lpx_get_prim_stat(lp) != LPX_P_FEAS) xfault("lpx_prim_ratio_test: current basic solution is not pri" "mal feasible\n"); if (!(how == +1 || how == -1)) xfault("lpx_prim_ratio_test: how = %d; invalid parameter\n", how); m = lpx_get_num_rows(lp); n = lpx_get_num_cols(lp); /* compute the largest absolute value of the specified influence coefficients */ big = 0.0; for (t = 1; t <= len; t++) { temp = val[t]; if (temp < 0.0) temp = - temp; if (big < temp) big = temp; } /* compute the absolute tolerance eps used to skip small entries of the column */ if (!(0.0 < tol && tol < 1.0)) xfault("lpx_prim_ratio_test: tol = %g; invalid tolerance\n", tol); eps = tol * (1.0 + big); /* initial settings */ p = 0, teta = DBL_MAX, big = 0.0; /* walk through the entries of the specified column */ for (t = 1; t <= len; t++) { /* get the ordinal number of basic variable */ k = ind[t]; if (!(1 <= k && k <= m+n)) xfault("lpx_prim_ratio_test: ind[%d] = %d; variable number " "out of range\n", t, k); if (k <= m) tagx = lpx_get_row_stat(lp, k); else tagx = lpx_get_col_stat(lp, k-m); if (tagx != LPX_BS) xfault("lpx_prim_ratio_test: ind[%d] = %d; non-basic variab" "le not allowed\n", t, k); /* determine index of the variable x[k] in the vector xB */ if (k <= m) i = lpx_get_row_b_ind(lp, k); else i = lpx_get_col_b_ind(lp, k-m); xassert(1 <= i && i <= m); /* determine unscaled bounds and value of the basic variable xB[i] in the current basic solution */ if (k <= m) { typx = lpx_get_row_type(lp, k); lb_i = lpx_get_row_lb(lp, k); ub_i = lpx_get_row_ub(lp, k); bbar_i = lpx_get_row_prim(lp, k); } else { typx = lpx_get_col_type(lp, k-m); lb_i = lpx_get_col_lb(lp, k-m); ub_i = lpx_get_col_ub(lp, k-m); bbar_i = lpx_get_col_prim(lp, k-m); } /* determine influence coefficient for the basic variable x[k] = xB[i] in the explicitly specified column and turn to the case of increasing the variable y in order to simplify the program logic */ alfa_i = (how > 0 ? +val[t] : -val[t]); abs_alfa_i = (alfa_i > 0.0 ? +alfa_i : -alfa_i); /* analyze main cases */ switch (typx) { case LPX_FR: /* xB[i] is free variable */ continue; case LPX_LO: lo: /* xB[i] has an lower bound */ if (alfa_i > - eps) continue; temp = (lb_i - bbar_i) / alfa_i; break; case LPX_UP: up: /* xB[i] has an upper bound */ if (alfa_i < + eps) continue; temp = (ub_i - bbar_i) / alfa_i; break; case LPX_DB: /* xB[i] has both lower and upper bounds */ if (alfa_i < 0.0) goto lo; else goto up; case LPX_FX: /* xB[i] is fixed variable */ if (abs_alfa_i < eps) continue; temp = 0.0; break; default: xassert(typx != typx); } /* if the value of the variable xB[i] violates its lower or upper bound (slightly, because the current basis is assumed to be primal feasible), temp is negative; we can think this happens due to round-off errors and the value is exactly on the bound; this allows replacing temp by zero */ if (temp < 0.0) temp = 0.0; /* apply the minimal ratio test */ if (teta > temp || teta == temp && big < abs_alfa_i) p = k, teta = temp, big = abs_alfa_i; } /* return the ordinal number of the chosen basic variable */ return p; }
int lpx_warm_up(LPX *lp) { int m, n, j, k, ret, type, stat, p_stat, d_stat; double lb, ub, prim, dual, tol_bnd, tol_dj, dir; double *row_prim, *row_dual, *col_prim, *col_dual, sum; m = lpx_get_num_rows(lp); n = lpx_get_num_cols(lp); /* reinvert the basis matrix, if necessary */ if (lpx_is_b_avail(lp)) ret = LPX_E_OK; else { if (m == 0 || n == 0) { ret = LPX_E_EMPTY; goto done; } #if 0 ret = lpx_invert(lp); switch (ret) { case 0: ret = LPX_E_OK; break; case 1: case 2: ret = LPX_E_SING; goto done; case 3: ret = LPX_E_BADB; goto done; default: xassert(ret != ret); } #else switch (glp_factorize(lp)) { case 0: ret = LPX_E_OK; break; case GLP_EBADB: ret = LPX_E_BADB; goto done; case GLP_ESING: case GLP_ECOND: ret = LPX_E_SING; goto done; default: xassert(lp != lp); } #endif } /* allocate working arrays */ row_prim = xcalloc(1+m, sizeof(double)); row_dual = xcalloc(1+m, sizeof(double)); col_prim = xcalloc(1+n, sizeof(double)); col_dual = xcalloc(1+n, sizeof(double)); /* compute primal basic solution components */ lpx_eval_b_prim(lp, row_prim, col_prim); /* determine primal status of basic solution */ tol_bnd = 3.0 * lpx_get_real_parm(lp, LPX_K_TOLBND); p_stat = LPX_P_FEAS; for (k = 1; k <= m+n; k++) { if (k <= m) { type = lpx_get_row_type(lp, k); lb = lpx_get_row_lb(lp, k); ub = lpx_get_row_ub(lp, k); prim = row_prim[k]; } else { type = lpx_get_col_type(lp, k-m); lb = lpx_get_col_lb(lp, k-m); ub = lpx_get_col_ub(lp, k-m); prim = col_prim[k-m]; } if (type == LPX_LO || type == LPX_DB || type == LPX_FX) { /* variable x[k] has lower bound */ if (prim < lb - tol_bnd * (1.0 + fabs(lb))) { p_stat = LPX_P_INFEAS; break; } } if (type == LPX_UP || type == LPX_DB || type == LPX_FX) { /* variable x[k] has upper bound */ if (prim > ub + tol_bnd * (1.0 + fabs(ub))) { p_stat = LPX_P_INFEAS; break; } } } /* compute dual basic solution components */ lpx_eval_b_dual(lp, row_dual, col_dual); /* determine dual status of basic solution */ tol_dj = 3.0 * lpx_get_real_parm(lp, LPX_K_TOLDJ); dir = (lpx_get_obj_dir(lp) == LPX_MIN ? +1.0 : -1.0); d_stat = LPX_D_FEAS; for (k = 1; k <= m+n; k++) { if (k <= m) { stat = lpx_get_row_stat(lp, k); dual = row_dual[k]; } else { stat = lpx_get_col_stat(lp, k-m); dual = col_dual[k-m]; } if (stat == LPX_BS || stat == LPX_NL || stat == LPX_NF) { /* reduced cost of x[k] must be non-negative (minimization) or non-positive (maximization) */ if (dir * dual < - tol_dj) { d_stat = LPX_D_INFEAS; break; } } if (stat == LPX_BS || stat == LPX_NU || stat == LPX_NF) { /* reduced cost of x[k] must be non-positive (minimization) or non-negative (maximization) */ if (dir * dual > + tol_dj) { d_stat = LPX_D_INFEAS; break; } } } /* store basic solution components */ p_stat = p_stat - LPX_P_UNDEF + GLP_UNDEF; d_stat = d_stat - LPX_D_UNDEF + GLP_UNDEF; sum = lpx_get_obj_coef(lp, 0); for (j = 1; j <= n; j++) sum += lpx_get_obj_coef(lp, j) * col_prim[j]; glp_put_solution(lp, 0, &p_stat, &d_stat, &sum, NULL, row_prim, row_dual, NULL, col_prim, col_dual); xassert(lpx_is_b_avail(lp)); /* free working arrays */ xfree(row_prim); xfree(row_dual); xfree(col_prim); xfree(col_dual); done: /* return to the calling program */ return ret; }
static void gen_gomory_cut(LPX *prob, int maxlen) { int m = lpx_get_num_rows(prob); int n = lpx_get_num_cols(prob); int i, j, k, len, cut_j, *ind; double x, d, r, temp, cut_d, cut_r, *val, *work; insist(lpx_get_status(prob) == LPX_OPT); /* allocate working arrays */ ind = ucalloc(1+n, sizeof(int)); val = ucalloc(1+n, sizeof(double)); work = ucalloc(1+m+n, sizeof(double)); /* nothing is chosen so far */ cut_j = 0; cut_d = 0.0; cut_r = 0.0; /* look through all structural variables */ for (j = 1; j <= n; j++) { /* if the variable is continuous, skip it */ if (lpx_get_col_kind(prob, j) != LPX_IV) continue; /* if the variable is non-basic, skip it */ if (lpx_get_col_stat(prob, j) != LPX_BS) continue; /* if the variable is fixed, skip it */ if (lpx_get_col_type(prob, j) == LPX_FX) continue; /* obtain current primal value of the variable */ x = lpx_get_col_prim(prob, j); /* if the value is close enough to nearest integer, skip the variable */ if (fabs(x - floor(x + 0.5)) < 1e-4) continue; /* compute the row of the simplex table corresponding to the variable */ len = lpx_eval_tab_row(prob, m+j, ind, val); len = lpx_remove_tiny(len, ind, NULL, val, 1e-10); /* generate Gomory's mixed integer cut: a[1]*x[1] + ... + a[n]*x[n] >= b */ len = lpx_gomory_cut(prob, len, ind, val, work); if (len < 0) continue; insist(0 <= len && len <= n); len = lpx_remove_tiny(len, ind, NULL, val, 1e-10); if (fabs(val[0]) < 1e-10) val[0] = 0.0; /* if the cut is too long, skip it */ if (len > maxlen) continue; /* if the cut contains coefficients with too large magnitude, do not use it to prevent numeric instability */ for (k = 0; k <= len; k++) /* including rhs */ if (fabs(val[k]) > 1e+6) break; if (k <= len) continue; /* at the current point the cut inequality is violated, i.e. the residual b - (a[1]*x[1] + ... + a[n]*x[n]) > 0; note that for Gomory's cut the residual is less than 1.0 */ /* in order not to depend on the magnitude of coefficients we use scaled residual: r = [b - (a[1]*x[1] + ... + a[n]*x[n])] / max(1, |a[j]|) */ temp = 1.0; for (k = 1; k <= len; k++) if (temp < fabs(val[k])) temp = fabs(val[k]); r = (val[0] - lpx_eval_row(prob, len, ind, val)) / temp; if (r < 1e-5) continue; /* estimate degradation (worsening) of the objective function by one dual simplex step if the cut row would be introduced in the problem */ d = lpx_eval_degrad(prob, len, ind, val, LPX_LO, val[0]); /* ignore the sign of degradation */ d = fabs(d); /* which cut should be used? there are two basic cases: 1) if the degradation is non-zero, we are interested in a cut providing maximal degradation; 2) if the degradation is zero (i.e. a non-basic variable which would enter the basis in the adjacent vertex has zero reduced cost), we are interested in a cut providing maximal scaled residual; in both cases it is desired that the cut length (the number of inequality coefficients) is possibly short */ /* if both degradation and scaled residual are small, skip the cut */ if (d < 0.001 && r < 0.001) continue; /* if there is no cut chosen, choose this cut */ else if (cut_j == 0) ; /* if this cut provides stronger degradation and has shorter length, choose it */ else if (cut_d != 0.0 && cut_d < d) ; /* if this cut provides larger scaled residual and has shorter length, choose it */ else if (cut_d == 0.0 && cut_r < r) ; /* otherwise skip the cut */ else continue; /* save attributes of the cut choosen */ cut_j = j, cut_r = r, cut_d = d; } /* if a cut has been chosen, include it to the problem */ if (cut_j != 0) { j = cut_j; /* compute the row of the simplex table */ len = lpx_eval_tab_row(prob, m+j, ind, val); len = lpx_remove_tiny(len, ind, NULL, val, 1e-10); /* generate the cut */ len = lpx_gomory_cut(prob, len, ind, val, work); insist(0 <= len && len <= n); len = lpx_remove_tiny(len, ind, NULL, val, 1e-10); if (fabs(val[0]) < 1e-10) val[0] = 0.0; /* include the corresponding row in the problem */ i = lpx_add_rows(prob, 1); lpx_set_row_bnds(prob, i, LPX_LO, val[0], 0.0); lpx_set_mat_row(prob, i, len, ind, val); } /* free working arrays */ ufree(ind); ufree(val); ufree(work); return; }
int lpx_intopt(LPX *_mip) { IPP *ipp = NULL; LPX *orig = _mip, *prob = NULL; int orig_m, orig_n, i, j, ret, i_stat; /* the problem must be of MIP class */ if (lpx_get_class(orig) != LPX_MIP) { print("lpx_intopt: problem is not of MIP class"); ret = LPX_E_FAULT; goto done; } /* the problem must have at least one row and one column */ orig_m = lpx_get_num_rows(orig); orig_n = lpx_get_num_cols(orig); if (!(orig_m > 0 && orig_n > 0)) { print("lpx_intopt: problem has no rows/columns"); ret = LPX_E_FAULT; goto done; } /* check that each double-bounded row and column has bounds */ for (i = 1; i <= orig_m; i++) { if (lpx_get_row_type(orig, i) == LPX_DB) { if (lpx_get_row_lb(orig, i) >= lpx_get_row_ub(orig, i)) { print("lpx_intopt: row %d has incorrect bounds", i); ret = LPX_E_FAULT; goto done; } } } for (j = 1; j <= orig_n; j++) { if (lpx_get_col_type(orig, j) == LPX_DB) { if (lpx_get_col_lb(orig, j) >= lpx_get_col_ub(orig, j)) { print("lpx_intopt: column %d has incorrect bounds", j); ret = LPX_E_FAULT; goto done; } } } /* bounds of all integer variables must be integral */ for (j = 1; j <= orig_n; j++) { int type; double lb, ub; if (lpx_get_col_kind(orig, j) != LPX_IV) continue; type = lpx_get_col_type(orig, j); if (type == LPX_LO || type == LPX_DB || type == LPX_FX) { lb = lpx_get_col_lb(orig, j); if (lb != floor(lb)) { print("lpx_intopt: integer column %d has non-integer low" "er bound or fixed value %g", j, lb); ret = LPX_E_FAULT; goto done; } } if (type == LPX_UP || type == LPX_DB) { ub = lpx_get_col_ub(orig, j); if (ub != floor(ub)) { print("lpx_intopt: integer column %d has non-integer upp" "er bound %g", j, ub); ret = LPX_E_FAULT; goto done; } } } /* reset the status of MIP solution */ lpx_put_mip_soln(orig, LPX_I_UNDEF, NULL, NULL); /* create MIP presolver workspace */ ipp = ipp_create_wksp(); /* load the original problem into the presolver workspace */ ipp_load_orig(ipp, orig); /* perform basic MIP presolve analysis */ switch (ipp_basic_tech(ipp)) { case 0: /* no infeasibility is detected */ break; case 1: nopfs: /* primal infeasibility is detected */ print("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION"); ret = LPX_E_NOPFS; goto done; case 2: /* dual infeasibility is detected */ nodfs: print("LP RELAXATION HAS NO DUAL FEASIBLE SOLUTION"); ret = LPX_E_NODFS; goto done; default: insist(ipp != ipp); } /* reduce column bounds */ switch (ipp_reduce_bnds(ipp)) { case 0: break; case 1: goto nopfs; default: insist(ipp != ipp); } /* perform basic MIP presolve analysis */ switch (ipp_basic_tech(ipp)) { case 0: break; case 1: goto nopfs; case 2: goto nodfs; default: insist(ipp != ipp); } /* replace general integer variables by sum of binary variables, if required */ if (lpx_get_int_parm(orig, LPX_K_BINARIZE)) ipp_binarize(ipp); /* perform coefficient reduction */ ipp_reduction(ipp); /* if the resultant problem is empty, it has an empty solution, which is optimal */ if (ipp->row_ptr == NULL || ipp->col_ptr == NULL) { insist(ipp->row_ptr == NULL); insist(ipp->col_ptr == NULL); print("Objective value = %.10g", ipp->orig_dir == LPX_MIN ? +ipp->c0 : -ipp->c0); print("INTEGER OPTIMAL SOLUTION FOUND BY MIP PRESOLVER"); /* allocate recovered solution segment */ ipp->col_stat = ucalloc(1+ipp->ncols, sizeof(int)); ipp->col_mipx = ucalloc(1+ipp->ncols, sizeof(double)); for (j = 1; j <= ipp->ncols; j++) ipp->col_stat[j] = 0; /* perform MIP postsolve processing */ ipp_postsolve(ipp); /* unload recovered MIP solution and store it in the original problem object */ ipp_unload_sol(ipp, orig, LPX_I_OPT); ret = LPX_E_OK; goto done; } /* build resultant MIP problem object */ prob = ipp_build_prob(ipp); /* display some statistics */ { int m = lpx_get_num_rows(prob); int n = lpx_get_num_cols(prob); int nnz = lpx_get_num_nz(prob); int ni = lpx_get_num_int(prob); int nb = lpx_get_num_bin(prob); char s[50]; print("lpx_intopt: presolved MIP has %d row%s, %d column%s, %d" " non-zero%s", m, m == 1 ? "" : "s", n, n == 1 ? "" : "s", nnz, nnz == 1 ? "" : "s"); if (nb == 0) strcpy(s, "none of"); else if (ni == 1 && nb == 1) strcpy(s, ""); else if (nb == 1) strcpy(s, "one of"); else if (nb == ni) strcpy(s, "all of"); else sprintf(s, "%d of", nb); print("lpx_intopt: %d integer column%s, %s which %s binary", ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are"); } /* inherit some control parameters and statistics */ lpx_set_int_parm(prob, LPX_K_PRICE, lpx_get_int_parm(orig, LPX_K_PRICE)); lpx_set_real_parm(prob, LPX_K_RELAX, lpx_get_real_parm(orig, LPX_K_RELAX)); lpx_set_real_parm(prob, LPX_K_TOLBND, lpx_get_real_parm(orig, LPX_K_TOLBND)); lpx_set_real_parm(prob, LPX_K_TOLDJ, lpx_get_real_parm(orig, LPX_K_TOLDJ)); lpx_set_real_parm(prob, LPX_K_TOLPIV, lpx_get_real_parm(orig, LPX_K_TOLPIV)); lpx_set_int_parm(prob, LPX_K_ITLIM, lpx_get_int_parm(orig, LPX_K_ITLIM)); lpx_set_int_parm(prob, LPX_K_ITCNT, lpx_get_int_parm(orig, LPX_K_ITCNT)); lpx_set_real_parm(prob, LPX_K_TMLIM, lpx_get_real_parm(orig, LPX_K_TMLIM)); lpx_set_int_parm(prob, LPX_K_BRANCH, lpx_get_int_parm(orig, LPX_K_BRANCH)); lpx_set_int_parm(prob, LPX_K_BTRACK, lpx_get_int_parm(orig, LPX_K_BTRACK)); lpx_set_real_parm(prob, LPX_K_TOLINT, lpx_get_real_parm(orig, LPX_K_TOLINT)); lpx_set_real_parm(prob, LPX_K_TOLOBJ, lpx_get_real_parm(orig, LPX_K_TOLOBJ)); /* build an advanced initial basis */ lpx_adv_basis(prob); /* solve LP relaxation */ print("Solving LP relaxation..."); switch (lpx_simplex(prob)) { case LPX_E_OK: break; case LPX_E_ITLIM: ret = LPX_E_ITLIM; goto done; case LPX_E_TMLIM: ret = LPX_E_TMLIM; goto done; default: print("lpx_intopt: cannot solve LP relaxation"); ret = LPX_E_SING; goto done; } /* analyze status of the basic solution */ switch (lpx_get_status(prob)) { case LPX_OPT: break; case LPX_NOFEAS: ret = LPX_E_NOPFS; goto done; case LPX_UNBND: ret = LPX_E_NODFS; goto done; default: insist(prob != prob); } /* generate cutting planes, if necessary */ if (lpx_get_int_parm(orig, LPX_K_USECUTS)) { ret = generate_cuts(prob); if (ret != LPX_E_OK) goto done; } /* call the branch-and-bound solver */ ret = lpx_integer(prob); /* determine status of MIP solution */ i_stat = lpx_mip_status(prob); if (i_stat == LPX_I_OPT || i_stat == LPX_I_FEAS) { /* load MIP solution of the resultant problem into presolver workspace */ ipp_load_sol(ipp, prob); /* perform MIP postsolve processing */ ipp_postsolve(ipp); /* unload recovered MIP solution and store it in the original problem object */ ipp_unload_sol(ipp, orig, i_stat); } else { /* just set the status of MIP solution */ lpx_put_mip_soln(orig, i_stat, NULL, NULL); } done: /* copy back statistics about spent resources */ if (prob != NULL) { lpx_set_int_parm(orig, LPX_K_ITLIM, lpx_get_int_parm(prob, LPX_K_ITLIM)); lpx_set_int_parm(orig, LPX_K_ITCNT, lpx_get_int_parm(prob, LPX_K_ITCNT)); lpx_set_real_parm(orig, LPX_K_TMLIM, lpx_get_real_parm(prob, LPX_K_TMLIM)); } /* delete the resultant problem object */ if (prob != NULL) lpx_delete_prob(prob); /* delete MIP presolver workspace */ if (ipp != NULL) ipp_delete_wksp(ipp); return ret; }