src/glpapi07.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

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