void lpx_get_col_info(glp_prob *lp, int j, int *tagx, double *vx, double *dx) { /* obtain column solution information */ if (tagx != NULL) *tagx = lpx_get_col_stat(lp, j); if (vx != NULL) *vx = lpx_get_col_prim(lp, j); if (dx != NULL) *dx = lpx_get_col_dual(lp, j); return; }
void lpx_eval_b_dual(LPX *lp, double row_dual[], double col_dual[]) { int i, j, k, m, n, len, *ind; double dj, *cB, *pi, *val; if (!lpx_is_b_avail(lp)) xfault("lpx_eval_b_dual: LP basis is not available\n"); m = lpx_get_num_rows(lp); n = lpx_get_num_cols(lp); /* store zero reduced costs of basic auxiliary and structural variables and build the vector cB of objective coefficients at basic variables */ cB = xcalloc(1+m, sizeof(double)); for (i = 1; i <= m; i++) { k = lpx_get_b_info(lp, i); /* xB[i] is k-th original variable */ xassert(1 <= k && k <= m+n); if (k <= m) { row_dual[k] = 0.0; cB[i] = 0.0; } else { col_dual[k-m] = 0.0; cB[i] = lpx_get_obj_coef(lp, k-m); } } /* solve the system B'*pi = cB to compute the vector pi */ pi = cB, lpx_btran(lp, pi); /* compute reduced costs of non-basic auxiliary variables */ for (i = 1; i <= m; i++) { if (lpx_get_row_stat(lp, i) != LPX_BS) row_dual[i] = - pi[i]; } /* compute reduced costs of non-basic structural variables */ ind = xcalloc(1+m, sizeof(int)); val = xcalloc(1+m, sizeof(double)); for (j = 1; j <= n; j++) { if (lpx_get_col_stat(lp, j) != LPX_BS) { dj = lpx_get_obj_coef(lp, j); len = lpx_get_mat_col(lp, j, ind, val); for (k = 1; k <= len; k++) dj += val[k] * pi[ind[k]]; col_dual[j] = dj; } } xfree(ind); xfree(val); xfree(cB); 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; }
int lpx_dual_ratio_test(LPX *lp, int len, const int ind[], const double val[], int how, double tol) { int k, m, n, t, q, tagx; double dir, alfa_j, abs_alfa_j, big, eps, cbar_j, temp, teta; if (!lpx_is_b_avail(lp)) xfault("lpx_dual_ratio_test: LP basis is not available\n"); if (lpx_get_dual_stat(lp) != LPX_D_FEAS) xfault("lpx_dual_ratio_test: current basic solution is not dua" "l feasible\n"); if (!(how == +1 || how == -1)) xfault("lpx_dual_ratio_test: how = %d; invalid parameter\n", how); m = lpx_get_num_rows(lp); n = lpx_get_num_cols(lp); dir = (lpx_get_obj_dir(lp) == LPX_MIN ? +1.0 : -1.0); /* 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 row */ if (!(0.0 < tol && tol < 1.0)) xfault("lpx_dual_ratio_test: tol = %g; invalid tolerance\n", tol); eps = tol * (1.0 + big); /* initial settings */ q = 0, teta = DBL_MAX, big = 0.0; /* walk through the entries of the specified row */ for (t = 1; t <= len; t++) { /* get ordinal number of non-basic variable */ k = ind[t]; if (!(1 <= k && k <= m+n)) xfault("lpx_dual_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_dual_ratio_test: ind[%d] = %d; basic variable n" "ot allowed\n", t, k); /* determine unscaled reduced cost of the non-basic variable x[k] = xN[j] in the current basic solution */ if (k <= m) cbar_j = lpx_get_row_dual(lp, k); else cbar_j = lpx_get_col_dual(lp, k-m); /* determine influence coefficient at the non-basic variable x[k] = xN[j] in the explicitly specified row and turn to the case of increasing the variable y in order to simplify program logic */ alfa_j = (how > 0 ? +val[t] : -val[t]); abs_alfa_j = (alfa_j > 0.0 ? +alfa_j : -alfa_j); /* analyze main cases */ switch (tagx) { case LPX_NL: /* xN[j] is on its lower bound */ if (alfa_j < +eps) continue; temp = (dir * cbar_j) / alfa_j; break; case LPX_NU: /* xN[j] is on its upper bound */ if (alfa_j > -eps) continue; temp = (dir * cbar_j) / alfa_j; break; case LPX_NF: /* xN[j] is non-basic free variable */ if (abs_alfa_j < eps) continue; temp = 0.0; break; case LPX_NS: /* xN[j] is non-basic fixed variable */ continue; default: xassert(tagx != tagx); } /* if the reduced cost of the variable xN[j] violates its zero bound (slightly, because the current basis is assumed to be dual feasible), temp is negative; we can think this happens due to round-off errors and the reduced cost is exact zero; 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_j) q = k, teta = temp, big = abs_alfa_j; } /* return the ordinal number of the chosen non-basic variable */ return q; }
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; }
void lpx_eval_b_prim(LPX *lp, double row_prim[], double col_prim[]) { int i, j, k, m, n, stat, len, *ind; double xN, *NxN, *xB, *val; if (!lpx_is_b_avail(lp)) xfault("lpx_eval_b_prim: LP basis is not available\n"); m = lpx_get_num_rows(lp); n = lpx_get_num_cols(lp); /* store values of non-basic auxiliary and structural variables and compute the right-hand side vector (-N*xN) */ NxN = xcalloc(1+m, sizeof(double)); for (i = 1; i <= m; i++) NxN[i] = 0.0; /* walk through auxiliary variables */ for (i = 1; i <= m; i++) { /* obtain status of i-th auxiliary variable */ stat = lpx_get_row_stat(lp, i); /* if it is basic, skip it */ if (stat == LPX_BS) continue; /* i-th auxiliary variable is non-basic; get its value */ switch (stat) { case LPX_NL: xN = lpx_get_row_lb(lp, i); break; case LPX_NU: xN = lpx_get_row_ub(lp, i); break; case LPX_NF: xN = 0.0; break; case LPX_NS: xN = lpx_get_row_lb(lp, i); break; default: xassert(lp != lp); } /* store the value of non-basic auxiliary variable */ row_prim[i] = xN; /* and add corresponding term to the right-hand side vector */ NxN[i] -= xN; } /* walk through structural variables */ ind = xcalloc(1+m, sizeof(int)); val = xcalloc(1+m, sizeof(double)); for (j = 1; j <= n; j++) { /* obtain status of j-th structural variable */ stat = lpx_get_col_stat(lp, j); /* if it basic, skip it */ if (stat == LPX_BS) continue; /* j-th structural variable is non-basic; get its value */ switch (stat) { case LPX_NL: xN = lpx_get_col_lb(lp, j); break; case LPX_NU: xN = lpx_get_col_ub(lp, j); break; case LPX_NF: xN = 0.0; break; case LPX_NS: xN = lpx_get_col_lb(lp, j); break; default: xassert(lp != lp); } /* store the value of non-basic structural variable */ col_prim[j] = xN; /* and add corresponding term to the right-hand side vector */ if (xN != 0.0) { len = lpx_get_mat_col(lp, j, ind, val); for (k = 1; k <= len; k++) NxN[ind[k]] += val[k] * xN; } } xfree(ind); xfree(val); /* solve the system B*xB = (-N*xN) to compute the vector xB */ xB = NxN, lpx_ftran(lp, xB); /* store values of basic auxiliary and structural variables */ for (i = 1; i <= m; i++) { k = lpx_get_b_info(lp, i); xassert(1 <= k && k <= m+n); if (k <= m) row_prim[k] = xB[i]; else col_prim[k-m] = xB[i]; } xfree(NxN); return; }
int lpx_transform_row(LPX *lp, int len, int ind[], double val[]) { int i, j, k, m, n, t, lll, *iii; double alfa, *a, *aB, *rho, *vvv; if (!lpx_is_b_avail(lp)) xfault("lpx_transform_row: LP basis is not available\n"); m = lpx_get_num_rows(lp); n = lpx_get_num_cols(lp); /* unpack the row to be transformed to the array a */ a = xcalloc(1+n, sizeof(double)); for (j = 1; j <= n; j++) a[j] = 0.0; if (!(0 <= len && len <= n)) xfault("lpx_transform_row: len = %d; invalid row length\n", len); for (t = 1; t <= len; t++) { j = ind[t]; if (!(1 <= j && j <= n)) xfault("lpx_transform_row: ind[%d] = %d; column index out o" "f range\n", t, j); if (val[t] == 0.0) xfault("lpx_transform_row: val[%d] = 0; zero coefficient no" "t allowed\n", t); if (a[j] != 0.0) xfault("lpx_transform_row: ind[%d] = %d; duplicate column i" "ndices not allowed\n", t, j); a[j] = val[t]; } /* construct the vector aB */ aB = xcalloc(1+m, sizeof(double)); for (i = 1; i <= m; i++) { k = lpx_get_b_info(lp, i); /* xB[i] is k-th original variable */ xassert(1 <= k && k <= m+n); aB[i] = (k <= m ? 0.0 : a[k-m]); } /* solve the system B'*rho = aB to compute the vector rho */ rho = aB, lpx_btran(lp, rho); /* compute coefficients at non-basic auxiliary variables */ len = 0; for (i = 1; i <= m; i++) { if (lpx_get_row_stat(lp, i) != LPX_BS) { alfa = - rho[i]; if (alfa != 0.0) { len++; ind[len] = i; val[len] = alfa; } } } /* compute coefficients at non-basic structural variables */ iii = xcalloc(1+m, sizeof(int)); vvv = xcalloc(1+m, sizeof(double)); for (j = 1; j <= n; j++) { if (lpx_get_col_stat(lp, j) != LPX_BS) { alfa = a[j]; lll = lpx_get_mat_col(lp, j, iii, vvv); for (t = 1; t <= lll; t++) alfa += vvv[t] * rho[iii[t]]; if (alfa != 0.0) { len++; ind[len] = m+j; val[len] = alfa; } } } xassert(len <= n); xfree(iii); xfree(vvv); xfree(aB); xfree(a); return len; }
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; }
int lpx_gomory_cut(LPX *lp, int len, int ind[], double val[], double work[]) { int m = lpx_get_num_rows(lp); int n = lpx_get_num_cols(lp); int k, t, stat; double lb, ub, *alfa, beta, alfa_j, f0, fj, *a, b, a_j; /* on entry the specified row of the simplex table has the form: y = alfa[1]*xN[1] + ... + alfa[n]*xN[n]; convert this row to the form: y + alfa'[1]*xN'[1] + ... + alfa'[n]*xN'[n] = beta, where all new (stroked) non-basic variables are non-negative (this is not needed for y, because it has integer bounds and only fractional part of beta is used); note that beta is the value of y in the current basic solution */ alfa = val; beta = 0.0; for (t = 1; t <= len; t++) { /* get index of some non-basic variable x[k] = xN[j] */ k = ind[t]; if (!(1 <= k && k <= m+n)) fault("lpx_gomory_cut: ind[%d] = %d; variable number out of" " range", t, k); /* get the original influence coefficient alfa[j] */ alfa_j = alfa[t]; /* obtain status and bounds of x[k] = xN[j] */ if (k <= m) { stat = lpx_get_row_stat(lp, k); lb = lpx_get_row_lb(lp, k); ub = lpx_get_row_ub(lp, k); } else { stat = lpx_get_col_stat(lp, k-m); lb = lpx_get_col_lb(lp, k-m); ub = lpx_get_col_ub(lp, k-m); } /* perform conversion */ if (stat == LPX_BS) fault("lpx_gomory_cut: ind[%d] = %d; variable must be non-b" "asic", t, k); switch (stat) { case LPX_NL: /* xN[j] is on its lower bound */ /* substitute xN[j] = lb[k] + xN'[j] */ alfa[t] = - alfa_j; beta += alfa_j * lb; break; case LPX_NU: /* xN[j] is on its upper bound */ /* substitute xN[j] = ub[k] - xN'[j] */ alfa[t] = + alfa_j; beta += alfa_j * ub; break; case LPX_NF: /* xN[j] is free non-basic variable */ return -1; case LPX_NS: /* xN[j] is fixed non-basic variable */ /* substitute xN[j] = lb[k] */ alfa[t] = 0.0; beta += alfa_j * lb; break; default: insist(stat != stat); } } /* now the converted row of the simplex table has the form: y + alfa'[1]*xN'[1] + ... + alfa'[n]*xN'[n] = beta, where all xN'[j] >= 0; generate Gomory's mixed integer cut in the form of inequality: a'[1]*xN'[1] + ... + a'[n]*xN'[n] >= b' */ a = val; /* f0 is fractional part of beta, where beta is the value of the variable y in the current basic solution; if f0 is close to zero or to one, i.e. if y is near to a closest integer point, the corresponding cutting plane may be unreliable */ f0 = beta - floor(beta); if (!(0.00001 <= f0 && f0 <= 0.99999)) return -2; for (t = 1; t <= len; t++) { alfa_j = alfa[t]; if (alfa_j == 0.0) { a[t] = 0.0; continue; } k = ind[t]; insist(1 <= k && k <= m+n); if (k > m && lpx_get_col_kind(lp, k-m) == LPX_IV) { /* xN[j] is integer */ fj = alfa_j - floor(alfa_j); if (fj <= f0) a[t] = fj; else a[t] = (f0 / (1.0 - f0)) * (1.0 - fj); } else { /* xN[j] is continuous */ if (alfa_j > 0.0) a[t] = alfa_j; else a[t] = - (f0 / (1.0 - f0)) * alfa_j; } } b = f0; /* now the generated cutting plane has the form of an inequality: a'[1]*xN'[1] + ... + a'[n]*xN'[n] >= b'; convert this inequality back to the form expressed through the original non-basic variables: a[1]*xN[1] + ... + a[n]*xN[n] >= b */ for (t = 1; t <= len; t++) { a_j = a[t]; if (a_j == 0.0) continue; k = ind[t]; /* x[k] = xN[j] */ /* obtain status and bounds of x[k] = xN[j] */ if (k <= m) { stat = lpx_get_row_stat(lp, k); lb = lpx_get_row_lb(lp, k); ub = lpx_get_row_ub(lp, k); } else { stat = lpx_get_col_stat(lp, k-m); lb = lpx_get_col_lb(lp, k-m); ub = lpx_get_col_ub(lp, k-m); } /* perform conversion */ switch (stat) { case LPX_NL: /* xN[j] is on its lower bound */ /* substitute xN'[j] = xN[j] - lb[k] */ val[t] = + a_j; b += a_j * lb; break; case LPX_NU: /* xN[j] is on its upper bound */ /* substitute xN'[j] = ub[k] - xN[j] */ val[t] = - a_j; b -= a_j * ub; break; default: insist(stat != stat); } } /* substitute auxiliary (non-basic) variables to the generated inequality constraint a[1]*xN[1] + ... + a[n]*xN[n] >= b using the equality constraints of the specified LP problem object in order to express the generated constraint through structural variables only */ len = lpx_reduce_form(lp, len, ind, val, work); /* store the right-hand side */ ind[0] = 0, val[0] = b; /* return to the calling program */ return len; }
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; }