alpar@1: /* glpini02.c */ alpar@1: alpar@1: /*********************************************************************** alpar@1: * This code is part of GLPK (GNU Linear Programming Kit). alpar@1: * alpar@1: * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, alpar@1: * 2009, 2010 Andrew Makhorin, Department for Applied Informatics, alpar@1: * Moscow Aviation Institute, Moscow, Russia. All rights reserved. alpar@1: * E-mail: . alpar@1: * alpar@1: * GLPK is free software: you can redistribute it and/or modify it alpar@1: * under the terms of the GNU General Public License as published by alpar@1: * the Free Software Foundation, either version 3 of the License, or alpar@1: * (at your option) any later version. alpar@1: * alpar@1: * GLPK is distributed in the hope that it will be useful, but WITHOUT alpar@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY alpar@1: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public alpar@1: * License for more details. alpar@1: * alpar@1: * You should have received a copy of the GNU General Public License alpar@1: * along with GLPK. If not, see . alpar@1: ***********************************************************************/ alpar@1: alpar@1: #include "glpapi.h" alpar@1: alpar@1: struct var alpar@1: { /* structural variable */ alpar@1: int j; alpar@1: /* ordinal number */ alpar@1: double q; alpar@1: /* penalty value */ alpar@1: }; alpar@1: alpar@1: static int fcmp(const void *ptr1, const void *ptr2) alpar@1: { /* this routine is passed to the qsort() function */ alpar@1: struct var *col1 = (void *)ptr1, *col2 = (void *)ptr2; alpar@1: if (col1->q < col2->q) return -1; alpar@1: if (col1->q > col2->q) return +1; alpar@1: return 0; alpar@1: } alpar@1: alpar@1: static int get_column(glp_prob *lp, int j, int ind[], double val[]) alpar@1: { /* Bixby's algorithm assumes that the constraint matrix is scaled alpar@1: such that the maximum absolute value in every non-zero row and alpar@1: column is 1 */ alpar@1: int k, len; alpar@1: double big; alpar@1: len = glp_get_mat_col(lp, j, ind, val); alpar@1: big = 0.0; alpar@1: for (k = 1; k <= len; k++) alpar@1: if (big < fabs(val[k])) big = fabs(val[k]); alpar@1: if (big == 0.0) big = 1.0; alpar@1: for (k = 1; k <= len; k++) val[k] /= big; alpar@1: return len; alpar@1: } alpar@1: alpar@1: static void cpx_basis(glp_prob *lp) alpar@1: { /* main routine */ alpar@1: struct var *C, *C2, *C3, *C4; alpar@1: int m, n, i, j, jk, k, l, ll, t, n2, n3, n4, type, len, *I, *r, alpar@1: *ind; alpar@1: double alpha, gamma, cmax, temp, *v, *val; alpar@1: xprintf("Constructing initial basis...\n"); alpar@1: /* determine the number of rows and columns */ alpar@1: m = glp_get_num_rows(lp); alpar@1: n = glp_get_num_cols(lp); alpar@1: /* allocate working arrays */ alpar@1: C = xcalloc(1+n, sizeof(struct var)); alpar@1: I = xcalloc(1+m, sizeof(int)); alpar@1: r = xcalloc(1+m, sizeof(int)); alpar@1: v = xcalloc(1+m, sizeof(double)); alpar@1: ind = xcalloc(1+m, sizeof(int)); alpar@1: val = xcalloc(1+m, sizeof(double)); alpar@1: /* make all auxiliary variables non-basic */ alpar@1: for (i = 1; i <= m; i++) alpar@1: { if (glp_get_row_type(lp, i) != GLP_DB) alpar@1: glp_set_row_stat(lp, i, GLP_NS); alpar@1: else if (fabs(glp_get_row_lb(lp, i)) <= alpar@1: fabs(glp_get_row_ub(lp, i))) alpar@1: glp_set_row_stat(lp, i, GLP_NL); alpar@1: else alpar@1: glp_set_row_stat(lp, i, GLP_NU); alpar@1: } alpar@1: /* make all structural variables non-basic */ alpar@1: for (j = 1; j <= n; j++) alpar@1: { if (glp_get_col_type(lp, j) != GLP_DB) alpar@1: glp_set_col_stat(lp, j, GLP_NS); alpar@1: else if (fabs(glp_get_col_lb(lp, j)) <= alpar@1: fabs(glp_get_col_ub(lp, j))) alpar@1: glp_set_col_stat(lp, j, GLP_NL); alpar@1: else alpar@1: glp_set_col_stat(lp, j, GLP_NU); alpar@1: } alpar@1: /* C2 is a set of free structural variables */ alpar@1: n2 = 0, C2 = C + 0; alpar@1: for (j = 1; j <= n; j++) alpar@1: { type = glp_get_col_type(lp, j); alpar@1: if (type == GLP_FR) alpar@1: { n2++; alpar@1: C2[n2].j = j; alpar@1: C2[n2].q = 0.0; alpar@1: } alpar@1: } alpar@1: /* C3 is a set of structural variables having excatly one (lower alpar@1: or upper) bound */ alpar@1: n3 = 0, C3 = C2 + n2; alpar@1: for (j = 1; j <= n; j++) alpar@1: { type = glp_get_col_type(lp, j); alpar@1: if (type == GLP_LO) alpar@1: { n3++; alpar@1: C3[n3].j = j; alpar@1: C3[n3].q = + glp_get_col_lb(lp, j); alpar@1: } alpar@1: else if (type == GLP_UP) alpar@1: { n3++; alpar@1: C3[n3].j = j; alpar@1: C3[n3].q = - glp_get_col_ub(lp, j); alpar@1: } alpar@1: } alpar@1: /* C4 is a set of structural variables having both (lower and alpar@1: upper) bounds */ alpar@1: n4 = 0, C4 = C3 + n3; alpar@1: for (j = 1; j <= n; j++) alpar@1: { type = glp_get_col_type(lp, j); alpar@1: if (type == GLP_DB) alpar@1: { n4++; alpar@1: C4[n4].j = j; alpar@1: C4[n4].q = glp_get_col_lb(lp, j) - glp_get_col_ub(lp, j); alpar@1: } alpar@1: } alpar@1: /* compute gamma = max{|c[j]|: 1 <= j <= n} */ alpar@1: gamma = 0.0; alpar@1: for (j = 1; j <= n; j++) alpar@1: { temp = fabs(glp_get_obj_coef(lp, j)); alpar@1: if (gamma < temp) gamma = temp; alpar@1: } alpar@1: /* compute cmax */ alpar@1: cmax = (gamma == 0.0 ? 1.0 : 1000.0 * gamma); alpar@1: /* compute final penalty for all structural variables within sets alpar@1: C2, C3, and C4 */ alpar@1: switch (glp_get_obj_dir(lp)) alpar@1: { case GLP_MIN: temp = +1.0; break; alpar@1: case GLP_MAX: temp = -1.0; break; alpar@1: default: xassert(lp != lp); alpar@1: } alpar@1: for (k = 1; k <= n2+n3+n4; k++) alpar@1: { j = C[k].j; alpar@1: C[k].q += (temp * glp_get_obj_coef(lp, j)) / cmax; alpar@1: } alpar@1: /* sort structural variables within C2, C3, and C4 in ascending alpar@1: order of penalty value */ alpar@1: qsort(C2+1, n2, sizeof(struct var), fcmp); alpar@1: for (k = 1; k < n2; k++) xassert(C2[k].q <= C2[k+1].q); alpar@1: qsort(C3+1, n3, sizeof(struct var), fcmp); alpar@1: for (k = 1; k < n3; k++) xassert(C3[k].q <= C3[k+1].q); alpar@1: qsort(C4+1, n4, sizeof(struct var), fcmp); alpar@1: for (k = 1; k < n4; k++) xassert(C4[k].q <= C4[k+1].q); alpar@1: /*** STEP 1 ***/ alpar@1: for (i = 1; i <= m; i++) alpar@1: { type = glp_get_row_type(lp, i); alpar@1: if (type != GLP_FX) alpar@1: { /* row i is either free or inequality constraint */ alpar@1: glp_set_row_stat(lp, i, GLP_BS); alpar@1: I[i] = 1; alpar@1: r[i] = 1; alpar@1: } alpar@1: else alpar@1: { /* row i is equality constraint */ alpar@1: I[i] = 0; alpar@1: r[i] = 0; alpar@1: } alpar@1: v[i] = +DBL_MAX; alpar@1: } alpar@1: /*** STEP 2 ***/ alpar@1: for (k = 1; k <= n2+n3+n4; k++) alpar@1: { jk = C[k].j; alpar@1: len = get_column(lp, jk, ind, val); alpar@1: /* let alpha = max{|A[l,jk]|: r[l] = 0} and let l' be such alpar@1: that alpha = |A[l',jk]| */ alpar@1: alpha = 0.0, ll = 0; alpar@1: for (t = 1; t <= len; t++) alpar@1: { l = ind[t]; alpar@1: if (r[l] == 0 && alpha < fabs(val[t])) alpar@1: alpha = fabs(val[t]), ll = l; alpar@1: } alpar@1: if (alpha >= 0.99) alpar@1: { /* B := B union {jk} */ alpar@1: glp_set_col_stat(lp, jk, GLP_BS); alpar@1: I[ll] = 1; alpar@1: v[ll] = alpha; alpar@1: /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */ alpar@1: for (t = 1; t <= len; t++) alpar@1: { l = ind[t]; alpar@1: if (val[t] != 0.0) r[l]++; alpar@1: } alpar@1: /* continue to the next k */ alpar@1: continue; alpar@1: } alpar@1: /* if |A[l,jk]| > 0.01 * v[l] for some l, continue to the alpar@1: next k */ alpar@1: for (t = 1; t <= len; t++) alpar@1: { l = ind[t]; alpar@1: if (fabs(val[t]) > 0.01 * v[l]) break; alpar@1: } alpar@1: if (t <= len) continue; alpar@1: /* otherwise, let alpha = max{|A[l,jk]|: I[l] = 0} and let l' alpar@1: be such that alpha = |A[l',jk]| */ alpar@1: alpha = 0.0, ll = 0; alpar@1: for (t = 1; t <= len; t++) alpar@1: { l = ind[t]; alpar@1: if (I[l] == 0 && alpha < fabs(val[t])) alpar@1: alpha = fabs(val[t]), ll = l; alpar@1: } alpar@1: /* if alpha = 0, continue to the next k */ alpar@1: if (alpha == 0.0) continue; alpar@1: /* B := B union {jk} */ alpar@1: glp_set_col_stat(lp, jk, GLP_BS); alpar@1: I[ll] = 1; alpar@1: v[ll] = alpha; alpar@1: /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */ alpar@1: for (t = 1; t <= len; t++) alpar@1: { l = ind[t]; alpar@1: if (val[t] != 0.0) r[l]++; alpar@1: } alpar@1: } alpar@1: /*** STEP 3 ***/ alpar@1: /* add an artificial variable (auxiliary variable for equality alpar@1: constraint) to cover each remaining uncovered row */ alpar@1: for (i = 1; i <= m; i++) alpar@1: if (I[i] == 0) glp_set_row_stat(lp, i, GLP_BS); alpar@1: /* free working arrays */ alpar@1: xfree(C); alpar@1: xfree(I); alpar@1: xfree(r); alpar@1: xfree(v); alpar@1: xfree(ind); alpar@1: xfree(val); alpar@1: return; alpar@1: } alpar@1: alpar@1: /*********************************************************************** alpar@1: * NAME alpar@1: * alpar@1: * glp_cpx_basis - construct Bixby's initial LP basis alpar@1: * alpar@1: * SYNOPSIS alpar@1: * alpar@1: * void glp_cpx_basis(glp_prob *lp); alpar@1: * alpar@1: * DESCRIPTION alpar@1: * alpar@1: * The routine glp_cpx_basis constructs an advanced initial basis for alpar@1: * the specified problem object. alpar@1: * alpar@1: * The routine is based on Bixby's algorithm described in the paper: alpar@1: * alpar@1: * Robert E. Bixby. Implementing the Simplex Method: The Initial Basis. alpar@1: * ORSA Journal on Computing, Vol. 4, No. 3, 1992, pp. 267-84. */ alpar@1: alpar@1: void glp_cpx_basis(glp_prob *lp) alpar@1: { if (lp->m == 0 || lp->n == 0) alpar@1: glp_std_basis(lp); alpar@1: else alpar@1: cpx_basis(lp); alpar@1: return; alpar@1: } alpar@1: alpar@1: /* eof */