src/glpapi07.c
changeset 1 c445c931472f
equal deleted inserted replaced
-1:000000000000 0:a651d1574f45
       
     1 /* glpapi07.c (exact simplex solver) */
       
     2 
       
     3 /***********************************************************************
       
     4 *  This code is part of GLPK (GNU Linear Programming Kit).
       
     5 *
       
     6 *  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
       
     7 *  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
       
     8 *  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
       
     9 *  E-mail: <mao@gnu.org>.
       
    10 *
       
    11 *  GLPK is free software: you can redistribute it and/or modify it
       
    12 *  under the terms of the GNU General Public License as published by
       
    13 *  the Free Software Foundation, either version 3 of the License, or
       
    14 *  (at your option) any later version.
       
    15 *
       
    16 *  GLPK is distributed in the hope that it will be useful, but WITHOUT
       
    17 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
       
    18 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
       
    19 *  License for more details.
       
    20 *
       
    21 *  You should have received a copy of the GNU General Public License
       
    22 *  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
       
    23 ***********************************************************************/
       
    24 
       
    25 #include "glpapi.h"
       
    26 #include "glpssx.h"
       
    27 
       
    28 /***********************************************************************
       
    29 *  NAME
       
    30 *
       
    31 *  glp_exact - solve LP problem in exact arithmetic
       
    32 *
       
    33 *  SYNOPSIS
       
    34 *
       
    35 *  int glp_exact(glp_prob *lp, const glp_smcp *parm);
       
    36 *
       
    37 *  DESCRIPTION
       
    38 *
       
    39 *  The routine glp_exact is a tentative implementation of the primal
       
    40 *  two-phase simplex method based on exact (rational) arithmetic. It is
       
    41 *  similar to the routine glp_simplex, however, for all internal
       
    42 *  computations it uses arithmetic of rational numbers, which is exact
       
    43 *  in mathematical sense, i.e. free of round-off errors unlike floating
       
    44 *  point arithmetic.
       
    45 *
       
    46 *  Note that the routine glp_exact uses inly two control parameters
       
    47 *  passed in the structure glp_smcp, namely, it_lim and tm_lim.
       
    48 *
       
    49 *  RETURNS
       
    50 *
       
    51 *  0  The LP problem instance has been successfully solved. This code
       
    52 *     does not necessarily mean that the solver has found optimal
       
    53 *     solution. It only means that the solution process was successful.
       
    54 *
       
    55 *  GLP_EBADB
       
    56 *     Unable to start the search, because the initial basis specified
       
    57 *     in the problem object is invalid--the number of basic (auxiliary
       
    58 *     and structural) variables is not the same as the number of rows in
       
    59 *     the problem object.
       
    60 *
       
    61 *  GLP_ESING
       
    62 *     Unable to start the search, because the basis matrix correspodning
       
    63 *     to the initial basis is exactly singular.
       
    64 *
       
    65 *  GLP_EBOUND
       
    66 *     Unable to start the search, because some double-bounded variables
       
    67 *     have incorrect bounds.
       
    68 *
       
    69 *  GLP_EFAIL
       
    70 *     The problem has no rows/columns.
       
    71 *
       
    72 *  GLP_EITLIM
       
    73 *     The search was prematurely terminated, because the simplex
       
    74 *     iteration limit has been exceeded.
       
    75 *
       
    76 *  GLP_ETMLIM
       
    77 *     The search was prematurely terminated, because the time limit has
       
    78 *     been exceeded. */
       
    79 
       
    80 static void set_d_eps(mpq_t x, double val)
       
    81 {     /* convert double val to rational x obtaining a more adequate
       
    82          fraction than provided by mpq_set_d due to allowing a small
       
    83          approximation error specified by a given relative tolerance;
       
    84          for example, mpq_set_d would give the following
       
    85          1/3 ~= 0.333333333333333314829616256247391... ->
       
    86              -> 6004799503160661/18014398509481984
       
    87          while this routine gives exactly 1/3 */
       
    88       int s, n, j;
       
    89       double f, p, q, eps = 1e-9;
       
    90       mpq_t temp;
       
    91       xassert(-DBL_MAX <= val && val <= +DBL_MAX);
       
    92 #if 1 /* 30/VII-2008 */
       
    93       if (val == floor(val))
       
    94       {  /* if val is integral, do not approximate */
       
    95          mpq_set_d(x, val);
       
    96          goto done;
       
    97       }
       
    98 #endif
       
    99       if (val > 0.0)
       
   100          s = +1;
       
   101       else if (val < 0.0)
       
   102          s = -1;
       
   103       else
       
   104       {  mpq_set_si(x, 0, 1);
       
   105          goto done;
       
   106       }
       
   107       f = frexp(fabs(val), &n);
       
   108       /* |val| = f * 2^n, where 0.5 <= f < 1.0 */
       
   109       fp2rat(f, 0.1 * eps, &p, &q);
       
   110       /* f ~= p / q, where p and q are integers */
       
   111       mpq_init(temp);
       
   112       mpq_set_d(x, p);
       
   113       mpq_set_d(temp, q);
       
   114       mpq_div(x, x, temp);
       
   115       mpq_set_si(temp, 1, 1);
       
   116       for (j = 1; j <= abs(n); j++)
       
   117          mpq_add(temp, temp, temp);
       
   118       if (n > 0)
       
   119          mpq_mul(x, x, temp);
       
   120       else if (n < 0)
       
   121          mpq_div(x, x, temp);
       
   122       mpq_clear(temp);
       
   123       if (s < 0) mpq_neg(x, x);
       
   124       /* check that the desired tolerance has been attained */
       
   125       xassert(fabs(val - mpq_get_d(x)) <= eps * (1.0 + fabs(val)));
       
   126 done: return;
       
   127 }
       
   128 
       
   129 static void load_data(SSX *ssx, LPX *lp)
       
   130 {     /* load LP problem data into simplex solver workspace */
       
   131       int m = ssx->m;
       
   132       int n = ssx->n;
       
   133       int nnz = ssx->A_ptr[n+1]-1;
       
   134       int j, k, type, loc, len, *ind;
       
   135       double lb, ub, coef, *val;
       
   136       xassert(lpx_get_num_rows(lp) == m);
       
   137       xassert(lpx_get_num_cols(lp) == n);
       
   138       xassert(lpx_get_num_nz(lp) == nnz);
       
   139       /* types and bounds of rows and columns */
       
   140       for (k = 1; k <= m+n; k++)
       
   141       {  if (k <= m)
       
   142          {  type = lpx_get_row_type(lp, k);
       
   143             lb = lpx_get_row_lb(lp, k);
       
   144             ub = lpx_get_row_ub(lp, k);
       
   145          }
       
   146          else
       
   147          {  type = lpx_get_col_type(lp, k-m);
       
   148             lb = lpx_get_col_lb(lp, k-m);
       
   149             ub = lpx_get_col_ub(lp, k-m);
       
   150          }
       
   151          switch (type)
       
   152          {  case LPX_FR: type = SSX_FR; break;
       
   153             case LPX_LO: type = SSX_LO; break;
       
   154             case LPX_UP: type = SSX_UP; break;
       
   155             case LPX_DB: type = SSX_DB; break;
       
   156             case LPX_FX: type = SSX_FX; break;
       
   157             default: xassert(type != type);
       
   158          }
       
   159          ssx->type[k] = type;
       
   160          set_d_eps(ssx->lb[k], lb);
       
   161          set_d_eps(ssx->ub[k], ub);
       
   162       }
       
   163       /* optimization direction */
       
   164       switch (lpx_get_obj_dir(lp))
       
   165       {  case LPX_MIN: ssx->dir = SSX_MIN; break;
       
   166          case LPX_MAX: ssx->dir = SSX_MAX; break;
       
   167          default: xassert(lp != lp);
       
   168       }
       
   169       /* objective coefficients */
       
   170       for (k = 0; k <= m+n; k++)
       
   171       {  if (k == 0)
       
   172             coef = lpx_get_obj_coef(lp, 0);
       
   173          else if (k <= m)
       
   174             coef = 0.0;
       
   175          else
       
   176             coef = lpx_get_obj_coef(lp, k-m);
       
   177          set_d_eps(ssx->coef[k], coef);
       
   178       }
       
   179       /* constraint coefficients */
       
   180       ind = xcalloc(1+m, sizeof(int));
       
   181       val = xcalloc(1+m, sizeof(double));
       
   182       loc = 0;
       
   183       for (j = 1; j <= n; j++)
       
   184       {  ssx->A_ptr[j] = loc+1;
       
   185          len = lpx_get_mat_col(lp, j, ind, val);
       
   186          for (k = 1; k <= len; k++)
       
   187          {  loc++;
       
   188             ssx->A_ind[loc] = ind[k];
       
   189             set_d_eps(ssx->A_val[loc], val[k]);
       
   190          }
       
   191       }
       
   192       xassert(loc == nnz);
       
   193       xfree(ind);
       
   194       xfree(val);
       
   195       return;
       
   196 }
       
   197 
       
   198 static int load_basis(SSX *ssx, LPX *lp)
       
   199 {     /* load current LP basis into simplex solver workspace */
       
   200       int m = ssx->m;
       
   201       int n = ssx->n;
       
   202       int *type = ssx->type;
       
   203       int *stat = ssx->stat;
       
   204       int *Q_row = ssx->Q_row;
       
   205       int *Q_col = ssx->Q_col;
       
   206       int i, j, k;
       
   207       xassert(lpx_get_num_rows(lp) == m);
       
   208       xassert(lpx_get_num_cols(lp) == n);
       
   209       /* statuses of rows and columns */
       
   210       for (k = 1; k <= m+n; k++)
       
   211       {  if (k <= m)
       
   212             stat[k] = lpx_get_row_stat(lp, k);
       
   213          else
       
   214             stat[k] = lpx_get_col_stat(lp, k-m);
       
   215          switch (stat[k])
       
   216          {  case LPX_BS:
       
   217                stat[k] = SSX_BS;
       
   218                break;
       
   219             case LPX_NL:
       
   220                stat[k] = SSX_NL;
       
   221                xassert(type[k] == SSX_LO || type[k] == SSX_DB);
       
   222                break;
       
   223             case LPX_NU:
       
   224                stat[k] = SSX_NU;
       
   225                xassert(type[k] == SSX_UP || type[k] == SSX_DB);
       
   226                break;
       
   227             case LPX_NF:
       
   228                stat[k] = SSX_NF;
       
   229                xassert(type[k] == SSX_FR);
       
   230                break;
       
   231             case LPX_NS:
       
   232                stat[k] = SSX_NS;
       
   233                xassert(type[k] == SSX_FX);
       
   234                break;
       
   235             default:
       
   236                xassert(stat != stat);
       
   237          }
       
   238       }
       
   239       /* build permutation matix Q */
       
   240       i = j = 0;
       
   241       for (k = 1; k <= m+n; k++)
       
   242       {  if (stat[k] == SSX_BS)
       
   243          {  i++;
       
   244             if (i > m) return 1;
       
   245             Q_row[k] = i, Q_col[i] = k;
       
   246          }
       
   247          else
       
   248          {  j++;
       
   249             if (j > n) return 1;
       
   250             Q_row[k] = m+j, Q_col[m+j] = k;
       
   251          }
       
   252       }
       
   253       xassert(i == m && j == n);
       
   254       return 0;
       
   255 }
       
   256 
       
   257 int glp_exact(glp_prob *lp, const glp_smcp *parm)
       
   258 {     glp_smcp _parm;
       
   259       SSX *ssx;
       
   260       int m = lpx_get_num_rows(lp);
       
   261       int n = lpx_get_num_cols(lp);
       
   262       int nnz = lpx_get_num_nz(lp);
       
   263       int i, j, k, type, pst, dst, ret, *stat;
       
   264       double lb, ub, *prim, *dual, sum;
       
   265       if (parm == NULL)
       
   266          parm = &_parm, glp_init_smcp((glp_smcp *)parm);
       
   267       /* check control parameters */
       
   268       if (parm->it_lim < 0)
       
   269          xerror("glp_exact: it_lim = %d; invalid parameter\n",
       
   270             parm->it_lim);
       
   271       if (parm->tm_lim < 0)
       
   272          xerror("glp_exact: tm_lim = %d; invalid parameter\n",
       
   273             parm->tm_lim);
       
   274       /* the problem must have at least one row and one column */
       
   275       if (!(m > 0 && n > 0))
       
   276       {  xprintf("glp_exact: problem has no rows/columns\n");
       
   277          return GLP_EFAIL;
       
   278       }
       
   279 #if 1
       
   280       /* basic solution is currently undefined */
       
   281       lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
       
   282       lp->obj_val = 0.0;
       
   283       lp->some = 0;
       
   284 #endif
       
   285       /* check that all double-bounded variables have correct bounds */
       
   286       for (k = 1; k <= m+n; k++)
       
   287       {  if (k <= m)
       
   288          {  type = lpx_get_row_type(lp, k);
       
   289             lb = lpx_get_row_lb(lp, k);
       
   290             ub = lpx_get_row_ub(lp, k);
       
   291          }
       
   292          else
       
   293          {  type = lpx_get_col_type(lp, k-m);
       
   294             lb = lpx_get_col_lb(lp, k-m);
       
   295             ub = lpx_get_col_ub(lp, k-m);
       
   296          }
       
   297          if (type == LPX_DB && lb >= ub)
       
   298          {  xprintf("glp_exact: %s %d has invalid bounds\n",
       
   299                k <= m ? "row" : "column", k <= m ? k : k-m);
       
   300             return GLP_EBOUND;
       
   301          }
       
   302       }
       
   303       /* create the simplex solver workspace */
       
   304       xprintf("glp_exact: %d rows, %d columns, %d non-zeros\n",
       
   305          m, n, nnz);
       
   306 #ifdef HAVE_GMP
       
   307       xprintf("GNU MP bignum library is being used\n");
       
   308 #else
       
   309       xprintf("GLPK bignum module is being used\n");
       
   310       xprintf("(Consider installing GNU MP to attain a much better perf"
       
   311          "ormance.)\n");
       
   312 #endif
       
   313       ssx = ssx_create(m, n, nnz);
       
   314       /* load LP problem data into the workspace */
       
   315       load_data(ssx, lp);
       
   316       /* load current LP basis into the workspace */
       
   317       if (load_basis(ssx, lp))
       
   318       {  xprintf("glp_exact: initial LP basis is invalid\n");
       
   319          ret = GLP_EBADB;
       
   320          goto done;
       
   321       }
       
   322       /* inherit some control parameters from the LP object */
       
   323 #if 0
       
   324       ssx->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM);
       
   325       ssx->it_cnt = lpx_get_int_parm(lp, LPX_K_ITCNT);
       
   326       ssx->tm_lim = lpx_get_real_parm(lp, LPX_K_TMLIM);
       
   327 #else
       
   328       ssx->it_lim = parm->it_lim;
       
   329       ssx->it_cnt = lp->it_cnt;
       
   330       ssx->tm_lim = (double)parm->tm_lim / 1000.0;
       
   331 #endif
       
   332       ssx->out_frq = 5.0;
       
   333       ssx->tm_beg = xtime();
       
   334       ssx->tm_lag = xlset(0);
       
   335       /* solve LP */
       
   336       ret = ssx_driver(ssx);
       
   337       /* copy back some statistics to the LP object */
       
   338 #if 0
       
   339       lpx_set_int_parm(lp, LPX_K_ITLIM, ssx->it_lim);
       
   340       lpx_set_int_parm(lp, LPX_K_ITCNT, ssx->it_cnt);
       
   341       lpx_set_real_parm(lp, LPX_K_TMLIM, ssx->tm_lim);
       
   342 #else
       
   343       lp->it_cnt = ssx->it_cnt;
       
   344 #endif
       
   345       /* analyze the return code */
       
   346       switch (ret)
       
   347       {  case 0:
       
   348             /* optimal solution found */
       
   349             ret = 0;
       
   350             pst = LPX_P_FEAS, dst = LPX_D_FEAS;
       
   351             break;
       
   352          case 1:
       
   353             /* problem has no feasible solution */
       
   354             ret = 0;
       
   355             pst = LPX_P_NOFEAS, dst = LPX_D_INFEAS;
       
   356             break;
       
   357          case 2:
       
   358             /* problem has unbounded solution */
       
   359             ret = 0;
       
   360             pst = LPX_P_FEAS, dst = LPX_D_NOFEAS;
       
   361 #if 1
       
   362             xassert(1 <= ssx->q && ssx->q <= n);
       
   363             lp->some = ssx->Q_col[m + ssx->q];
       
   364             xassert(1 <= lp->some && lp->some <= m+n);
       
   365 #endif
       
   366             break;
       
   367          case 3:
       
   368             /* iteration limit exceeded (phase I) */
       
   369             ret = GLP_EITLIM;
       
   370             pst = LPX_P_INFEAS, dst = LPX_D_INFEAS;
       
   371             break;
       
   372          case 4:
       
   373             /* iteration limit exceeded (phase II) */
       
   374             ret = GLP_EITLIM;
       
   375             pst = LPX_P_FEAS, dst = LPX_D_INFEAS;
       
   376             break;
       
   377          case 5:
       
   378             /* time limit exceeded (phase I) */
       
   379             ret = GLP_ETMLIM;
       
   380             pst = LPX_P_INFEAS, dst = LPX_D_INFEAS;
       
   381             break;
       
   382          case 6:
       
   383             /* time limit exceeded (phase II) */
       
   384             ret = GLP_ETMLIM;
       
   385             pst = LPX_P_FEAS, dst = LPX_D_INFEAS;
       
   386             break;
       
   387          case 7:
       
   388             /* initial basis matrix is singular */
       
   389             ret = GLP_ESING;
       
   390             goto done;
       
   391          default:
       
   392             xassert(ret != ret);
       
   393       }
       
   394       /* obtain final basic solution components */
       
   395       stat = xcalloc(1+m+n, sizeof(int));
       
   396       prim = xcalloc(1+m+n, sizeof(double));
       
   397       dual = xcalloc(1+m+n, sizeof(double));
       
   398       for (k = 1; k <= m+n; k++)
       
   399       {  if (ssx->stat[k] == SSX_BS)
       
   400          {  i = ssx->Q_row[k]; /* x[k] = xB[i] */
       
   401             xassert(1 <= i && i <= m);
       
   402             stat[k] = LPX_BS;
       
   403             prim[k] = mpq_get_d(ssx->bbar[i]);
       
   404             dual[k] = 0.0;
       
   405          }
       
   406          else
       
   407          {  j = ssx->Q_row[k] - m; /* x[k] = xN[j] */
       
   408             xassert(1 <= j && j <= n);
       
   409             switch (ssx->stat[k])
       
   410             {  case SSX_NF:
       
   411                   stat[k] = LPX_NF;
       
   412                   prim[k] = 0.0;
       
   413                   break;
       
   414                case SSX_NL:
       
   415                   stat[k] = LPX_NL;
       
   416                   prim[k] = mpq_get_d(ssx->lb[k]);
       
   417                   break;
       
   418                case SSX_NU:
       
   419                   stat[k] = LPX_NU;
       
   420                   prim[k] = mpq_get_d(ssx->ub[k]);
       
   421                   break;
       
   422                case SSX_NS:
       
   423                   stat[k] = LPX_NS;
       
   424                   prim[k] = mpq_get_d(ssx->lb[k]);
       
   425                   break;
       
   426                default:
       
   427                   xassert(ssx != ssx);
       
   428             }
       
   429             dual[k] = mpq_get_d(ssx->cbar[j]);
       
   430          }
       
   431       }
       
   432       /* and store them into the LP object */
       
   433       pst = pst - LPX_P_UNDEF + GLP_UNDEF;
       
   434       dst = dst - LPX_D_UNDEF + GLP_UNDEF;
       
   435       for (k = 1; k <= m+n; k++)
       
   436          stat[k] = stat[k] - LPX_BS + GLP_BS;
       
   437       sum = lpx_get_obj_coef(lp, 0);
       
   438       for (j = 1; j <= n; j++)
       
   439          sum += lpx_get_obj_coef(lp, j) * prim[m+j];
       
   440       lpx_put_solution(lp, 1, &pst, &dst, &sum,
       
   441          &stat[0], &prim[0], &dual[0], &stat[m], &prim[m], &dual[m]);
       
   442       xfree(stat);
       
   443       xfree(prim);
       
   444       xfree(dual);
       
   445 done: /* delete the simplex solver workspace */
       
   446       ssx_delete(ssx);
       
   447       /* return to the application program */
       
   448       return ret;
       
   449 }
       
   450 
       
   451 /* eof */