examples/cplex/cplex.c
changeset 1 c445c931472f
equal deleted inserted replaced
-1:000000000000 0:2ccd9aeb5b79
       
     1 /* cplex.c (CPLEX-like interface to GLPK API) */
       
     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 <ctype.h>
       
    26 #include <stdarg.h>
       
    27 #include <stdio.h>
       
    28 #include <stdlib.h>
       
    29 #include <string.h>
       
    30 #include <glpk.h>
       
    31 #include "cplex.h"
       
    32 
       
    33 struct CPXENV
       
    34 {     /* environment block */
       
    35       CPXLP *list;
       
    36       /* linked list of problem objects */
       
    37       int *intparam; /* int intparam[]; */
       
    38       /* integer control parameters */
       
    39       double *dblparam; /* double dblparam[]; */
       
    40       /* floating-point control parameters */
       
    41 };
       
    42 
       
    43 struct CPXLP
       
    44 {     /* problem object */
       
    45       CPXENV *env;
       
    46       /* pointer to environment block */
       
    47       glp_prob *prob;
       
    48       /* pointer to underlying GLPK problem object */
       
    49       int rflen;
       
    50       /* length of the array rflag */
       
    51       char *rflag; /* char rflag[rflen]; */
       
    52       /* rflag[i], i = 0,...,nrows-1, is a flag of i-th row: */
       
    53 #define RF_NOT_RANGED   0  /* not ranged */
       
    54 #define RF_RANGED_POS   1  /* ranged, RHS = lower bound */
       
    55 #define RF_RANGED_NEG   2  /* ranged, RHS = upper bound */
       
    56       int stat;
       
    57       /* solution status reported by CPXgetstat; zero means no solution
       
    58          exists */
       
    59       int meth;
       
    60       /* method indicator reported by CPXgetmethod */
       
    61       int iwlen;
       
    62       /* length of the working array */
       
    63       int *iwork; /* int iwork[iwlen] */
       
    64       /* working array initialized by binary zeros */
       
    65       CPXLP *link;
       
    66       /* pointer to another problem object */
       
    67 };
       
    68 
       
    69 struct intparam
       
    70 {     int which;
       
    71       int defv;
       
    72       int minv;
       
    73       int maxv;
       
    74 };
       
    75 
       
    76 struct dblparam
       
    77 {     int which;
       
    78       double defv;
       
    79       double minv;
       
    80       double maxv;
       
    81 };
       
    82 
       
    83 struct errstring
       
    84 {     int code;
       
    85       const char *string;
       
    86 };
       
    87 
       
    88 #define BIGINT 2100000000
       
    89 #define BIGDBL 1e75
       
    90 
       
    91 static const struct intparam intparam[] =
       
    92 {     {CPX_PARAM_ADVIND, 0, 0, 2},
       
    93       {CPX_PARAM_AGGIND, -1, -1, BIGINT},
       
    94       {CPX_PARAM_DATACHECK, CPX_OFF, CPX_OFF, CPX_ON},
       
    95       {CPX_PARAM_DPRIIND, CPX_DPRIIND_AUTO, CPX_DPRIIND_AUTO,
       
    96          CPX_DPRIIND_DEVEX},
       
    97       {CPX_PARAM_FASTMIP, CPX_OFF, CPX_OFF, CPX_ON}, /* ??? */
       
    98       {CPX_PARAM_ITLIM, BIGINT, 0, BIGINT},
       
    99       {CPX_PARAM_PERIND, CPX_OFF, CPX_OFF, CPX_ON},
       
   100       {CPX_PARAM_PPRIIND, CPX_PPRIIND_AUTO, CPX_PPRIIND_PARTIAL,
       
   101          CPX_PPRIIND_FULL},
       
   102       {CPX_PARAM_PREIND, CPX_ON, CPX_OFF, CPX_ON},
       
   103       {CPX_PARAM_REINV, 0, 0, 10000},
       
   104       {CPX_PARAM_SCRIND, CPX_OFF, CPX_OFF, CPX_ON},
       
   105       {CPX_PARAM_SIMDISPLAY, 1, 0, 2},
       
   106 };
       
   107 
       
   108 static const struct dblparam dblparam[] =
       
   109 {     {CPX_PARAM_EPOPT, 1e-6, 1e-9, 1e-1},
       
   110       {CPX_PARAM_EPPER, 1e-6, 1e-8, BIGDBL},
       
   111       {CPX_PARAM_EPRHS, 1e-6, 1e-9, 1e-1},
       
   112       {CPX_PARAM_OBJLLIM, -BIGDBL, -BIGDBL, +BIGDBL},
       
   113       {CPX_PARAM_OBJULIM, +BIGDBL, -BIGDBL, +BIGDBL},
       
   114 };
       
   115 
       
   116 static const struct errstring errstring[] =
       
   117 {     {CPXERR_ARRAY_NOT_ASCENDING, "Array entry %d not ascending"},
       
   118       {CPXERR_BAD_ARGUMENT, "Invalid argument"},
       
   119       {CPXERR_BAD_CTYPE, "Invalid ctype entry %d"},
       
   120       {CPXERR_BAD_FILETYPE, "Invalid filetype"},
       
   121       {CPXERR_BAD_LUB, "Invalid bound change indicator entry %d"},
       
   122       {CPXERR_BAD_PARAM_NUM, "Invalid parameter number"},
       
   123       {CPXERR_BAD_SENSE, "Invalid sense entry %d"},
       
   124       {CPXERR_BAD_STATUS, "Invalid status entry %d for basis specificat"
       
   125          "ion"},
       
   126       {CPXERR_COL_INDEX_RANGE, "Column index %d out of range"},
       
   127       {CPXERR_COUNT_RANGE, "Count entry %d negative or larger than allo"
       
   128          "wed"},
       
   129       {CPXERR_DUP_ENTRY, "Duplicate entry"},
       
   130       {CPXERR_FAIL_OPEN_WRITE, "Could not open file '%s' for writing"},
       
   131       {CPXERR_INDEX_RANGE, "Index is outside range of valid values"},
       
   132       {CPXERR_NEGATIVE_SURPLUS, "Insufficient array length"},
       
   133       {CPXERR_NO_BASIC_SOLN, "No basic solution exists"},
       
   134       {CPXERR_NO_ENVIRONMENT, "No environment exists"},
       
   135       {CPXERR_NO_FILENAME, "File name not specified"},
       
   136       {CPXERR_NO_MEMORY, "Out of memory"},
       
   137       {CPXERR_NO_PROBLEM, "No problem exists"},
       
   138       {CPXERR_NO_SOLN, "No solution exists"},
       
   139       {CPXERR_NOT_FIXED, "Only fixed variables are pivoted out"},
       
   140       {CPXERR_NULL_NAME, "Null pointer %d in name array"},
       
   141       {CPXERR_NULL_POINTER, "Null pointer for required data"},
       
   142       {CPXERR_PARAM_TOO_BIG, "Parameter value too big"},
       
   143       {CPXERR_PARAM_TOO_SMALL, "Parameter value too small"},
       
   144       {CPXERR_ROW_INDEX_RANGE, "Row index %d out of range"},
       
   145 };
       
   146 
       
   147 /**********************************************************************/
       
   148 
       
   149 #define xassert glp_assert
       
   150 #define xprintf glp_printf
       
   151 #define xmalloc glp_malloc
       
   152 #define xcalloc glp_calloc
       
   153 #define xfree   glp_free
       
   154 
       
   155 /**********************************************************************/
       
   156 
       
   157 static int findintparam(int whichparam)
       
   158 {     int k, card;
       
   159       card = sizeof(intparam) / sizeof(struct intparam);
       
   160       for (k = 0; k < card; k++)
       
   161          if (intparam[k].which == whichparam) return k;
       
   162       return -1;
       
   163 }
       
   164 
       
   165 static int getintparam(CPXENV *env, int whichparam)
       
   166 {     int k;
       
   167       xassert(env != NULL);
       
   168       k = findintparam(whichparam);
       
   169       xassert(k >= 0);
       
   170       return env->intparam[k];
       
   171 }
       
   172 
       
   173 static int finddblparam(int whichparam)
       
   174 {     int k, card;
       
   175       card = sizeof(dblparam) / sizeof(struct dblparam);
       
   176       for (k = 0; k < card; k++)
       
   177          if (dblparam[k].which == whichparam) return k;
       
   178       return -1;
       
   179 }
       
   180 
       
   181 static double getdblparam(CPXENV *env, int whichparam)
       
   182 {     int k;
       
   183       xassert(env != NULL);
       
   184       k = finddblparam(whichparam);
       
   185       xassert(k >= 0);
       
   186       return env->dblparam[k];
       
   187 }
       
   188 
       
   189 static const char *finderrstring(int errcode)
       
   190 {     int k, card;
       
   191       card = sizeof(errstring) / sizeof(struct errstring);
       
   192       for (k = 0; k < card; k++)
       
   193       {  if (errstring[k].code == errcode)
       
   194             return errstring[k].string;
       
   195       }
       
   196       return NULL;
       
   197 }
       
   198 
       
   199 static int error(CPXENV *env, int errcode, ...)
       
   200 {     va_list arg;
       
   201       char buffer[510];
       
   202       xassert(env != NULL);
       
   203       if (getintparam(env, CPX_PARAM_SCRIND) == CPX_ON)
       
   204       {  xassert(CPXgeterrorstring(env, errcode, buffer) == buffer);
       
   205          va_start(arg, errcode);
       
   206          vprintf(buffer, arg);
       
   207          va_end(arg);
       
   208       }
       
   209       return errcode;
       
   210 }
       
   211 
       
   212 static int checkenv(CPXENV *env)
       
   213 {     int errcode;
       
   214       if (env == NULL)
       
   215          errcode = CPXERR_NO_ENVIRONMENT;
       
   216       else
       
   217          errcode = 0;
       
   218       return errcode;
       
   219 }
       
   220 
       
   221 static checklp(CPXENV *env, CPXLP *lp)
       
   222 {     int errcode;
       
   223       errcode = checkenv(env);
       
   224       if (errcode) goto done;
       
   225       if (lp == NULL)
       
   226          errcode = error(env, CPXERR_NO_PROBLEM);
       
   227 done: return errcode;
       
   228 }
       
   229 
       
   230 static void invalidate(CPXLP *lp)
       
   231 {     lp->stat = 0;
       
   232       lp->meth = CPX_ALG_NONE;
       
   233       return;
       
   234 }
       
   235 
       
   236 static void enlargerflag(CPXLP *lp)
       
   237 {     int m;
       
   238       xassert(lp != NULL);
       
   239       m = glp_get_num_rows(lp->prob);
       
   240       if (lp->rflen < m)
       
   241       {  int rflen = lp->rflen;
       
   242          char *rflag = lp->rflag;
       
   243          while (lp->rflen < m)
       
   244          {  lp->rflen += lp->rflen;
       
   245             xassert(lp->rflen > 0);
       
   246          }
       
   247          lp->rflag = xcalloc(lp->rflen, sizeof(char));
       
   248          memcpy(lp->rflag, rflag, rflen);
       
   249          xfree(rflag);
       
   250       }
       
   251       return;
       
   252 }
       
   253 
       
   254 static void enlargeiwork(CPXLP *lp, int len)
       
   255 {     xassert(len >= 0);
       
   256       if (lp->iwlen < len)
       
   257       {  xfree(lp->iwork);
       
   258          while (lp->iwlen < len)
       
   259          {  lp->iwlen += lp->iwlen;
       
   260             xassert(lp->iwlen > 0);
       
   261          }
       
   262          lp->iwork = xcalloc(lp->iwlen, sizeof(int));
       
   263          memset(lp->iwork, 0, lp->iwlen * sizeof(int));
       
   264       }
       
   265       return;
       
   266 }
       
   267 
       
   268 /**********************************************************************/
       
   269 
       
   270 int CPXaddcols(CPXENV *env, CPXLP *lp, int ccnt, int nzcnt,
       
   271       const double obj[], const int cmatbeg[], const int cmatind[],
       
   272       const double cmatval[], const double lb[], const double ub[],
       
   273       char *colname[])
       
   274 {     int j, k, m, n, beg, end, type, errcode;
       
   275       double lbnd, ubnd;
       
   276       errcode = checklp(env, lp);
       
   277       if (errcode) goto done;
       
   278       if (ccnt < 0 || nzcnt < 0)
       
   279       {  errcode = error(env, CPXERR_BAD_ARGUMENT);
       
   280          goto done;
       
   281       }
       
   282       if (ccnt > 0)
       
   283       {  if (cmatbeg == NULL || cmatind == NULL || cmatval == NULL)
       
   284          {  errcode = error(env, CPXERR_NULL_POINTER);
       
   285             goto done;
       
   286          }
       
   287       }
       
   288       m = glp_get_num_rows(lp->prob);
       
   289       n = glp_get_num_cols(lp->prob);
       
   290       enlargeiwork(lp, m);
       
   291       for (j = 0; j < ccnt; j++)
       
   292       {  beg = cmatbeg[j];
       
   293          if (j > 0 && !(cmatbeg[j-1] <= beg))
       
   294          {  errcode = error(env, CPXERR_ARRAY_NOT_ASCENDING, j);
       
   295             goto done;
       
   296          }
       
   297          if (!(0 <= beg && beg <= nzcnt))
       
   298          {  errcode = error(env, CPXERR_INDEX_RANGE);
       
   299             goto done;
       
   300          }
       
   301          end = (j < ccnt-1 ? cmatbeg[j+1] : nzcnt);
       
   302          for (k = beg; k < end; k++)
       
   303          {  if (!(0 <= cmatind[k] && cmatind[k] < m))
       
   304             {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, k);
       
   305                goto done;
       
   306             }
       
   307          }
       
   308          errcode = 0;
       
   309          for (k = beg; k < end; k++)
       
   310          {  if (lp->iwork[cmatind[k]])
       
   311             {  errcode = error(env, CPXERR_DUP_ENTRY);
       
   312                break;
       
   313             }
       
   314             lp->iwork[cmatind[k]] = 1;
       
   315          }
       
   316          for (k = beg; k < end; k++)
       
   317             lp->iwork[cmatind[k]] = 0;
       
   318          if (errcode) goto done;
       
   319          if (colname != NULL)
       
   320          {  if (colname[j] == NULL)
       
   321             {  errcode = error(env, CPXERR_NULL_NAME, j);
       
   322                goto done;
       
   323             }
       
   324          }
       
   325       }
       
   326       errcode = 0;
       
   327       invalidate(lp);
       
   328       if (ccnt > 0)
       
   329          glp_add_cols(lp->prob, ccnt);
       
   330       for (j = 0; j < ccnt; j++)
       
   331       {  if (colname != NULL)
       
   332             glp_set_col_name(lp->prob, n+j+1, colname[j]);
       
   333          lbnd = (lb == NULL ? 0.0 : lb[j]);
       
   334          ubnd = (ub == NULL ? +CPX_INFBOUND : ub[j]);
       
   335          if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
       
   336             type = GLP_FR;
       
   337          else if (ubnd >= +CPX_INFBOUND)
       
   338             type = GLP_LO;
       
   339          else if (lbnd <= -CPX_INFBOUND)
       
   340             type = GLP_UP;
       
   341          else if (lbnd != ubnd)
       
   342             type = GLP_DB;
       
   343          else
       
   344             type = GLP_FX;
       
   345          glp_set_col_bnds(lp->prob, n+j+1, type, lbnd, ubnd);
       
   346          if (obj != NULL)
       
   347             glp_set_obj_coef(lp->prob, n+j+1, obj[j]);
       
   348          beg = cmatbeg[j];
       
   349          end = (j < ccnt-1 ? cmatbeg[j+1] : nzcnt);
       
   350          for (k = beg; k < end; k++)
       
   351             lp->iwork[k-beg] = cmatind[k]+1;
       
   352          glp_set_mat_col(lp->prob, n+j+1, end-beg, lp->iwork-1,
       
   353             cmatval+beg-1);
       
   354          for (k = beg; k < end; k++)
       
   355             lp->iwork[k-beg] = 0;
       
   356       }
       
   357 done: return errcode;
       
   358 }
       
   359 
       
   360 int CPXaddrows(CPXENV *env, CPXLP *lp, int ccnt, int rcnt, int nzcnt,
       
   361       const double rhs[], const char sense[], const int rmatbeg[],
       
   362       const int rmatind[], const double rmatval[], char *colname[],
       
   363       char *rowname[])
       
   364 {     int i, j, k, m, n, beg, end, type, errcode;
       
   365       double temp;
       
   366       errcode = checklp(env, lp);
       
   367       if (errcode) goto done;
       
   368       if (ccnt < 0 || rcnt < 0 || nzcnt < 0)
       
   369       {  errcode = error(env, CPXERR_BAD_ARGUMENT);
       
   370          goto done;
       
   371       }
       
   372       if (rcnt > 0)
       
   373       {  if (rmatbeg == NULL || rmatind == NULL || rmatval == NULL)
       
   374          {  errcode = error(env, CPXERR_NULL_POINTER);
       
   375             goto done;
       
   376          }
       
   377       }
       
   378       m = glp_get_num_rows(lp->prob);
       
   379       n = glp_get_num_cols(lp->prob);
       
   380       enlargeiwork(lp, n+ccnt);
       
   381       for (i = 0; i < rcnt; i++)
       
   382       {  if (sense != NULL)
       
   383          {  if (!(sense[i] == 'L' || sense[i] == 'E' ||
       
   384                   sense[i] == 'G' || sense[i] == 'R'))
       
   385             {  errcode = error(env, CPXERR_BAD_SENSE, i);
       
   386                goto done;
       
   387             }
       
   388          }
       
   389          beg = rmatbeg[i];
       
   390          if (i > 0 && !(rmatbeg[i-1] <= beg))
       
   391          {  errcode = error(env, CPXERR_ARRAY_NOT_ASCENDING, i);
       
   392             goto done;
       
   393          }
       
   394          if (!(0 <= beg && beg <= nzcnt))
       
   395          {  errcode = error(env, CPXERR_INDEX_RANGE);
       
   396             goto done;
       
   397          }
       
   398          end = (i < rcnt-1 ? rmatbeg[i+1] : nzcnt);
       
   399          for (k = beg; k < end; k++)
       
   400          {  if (!(0 <= rmatind[k] && rmatind[k] < n+ccnt))
       
   401             {  errcode = error(env, CPXERR_COL_INDEX_RANGE, k);
       
   402                goto done;
       
   403             }
       
   404          }
       
   405          errcode = 0;
       
   406          for (k = beg; k < end; k++)
       
   407          {  if (lp->iwork[rmatind[k]])
       
   408             {  errcode = error(env, CPXERR_DUP_ENTRY);
       
   409                break;
       
   410             }
       
   411             lp->iwork[rmatind[k]] = 1;
       
   412          }
       
   413          for (k = beg; k < end; k++)
       
   414             lp->iwork[rmatind[k]] = 0;
       
   415          if (errcode) goto done;
       
   416          if (rowname != NULL)
       
   417          {  if (rowname[i] == NULL)
       
   418             {  errcode = error(env, CPXERR_NULL_NAME, i);
       
   419                goto done;
       
   420             }
       
   421          }
       
   422       }
       
   423       for (j = 0; j < ccnt; j++)
       
   424       {  if (colname != NULL)
       
   425          {  if (colname[j] == NULL)
       
   426             {  errcode = error(env, CPXERR_NULL_NAME, j);
       
   427                goto done;
       
   428             }
       
   429          }
       
   430       }
       
   431       errcode = 0;
       
   432       invalidate(lp);
       
   433       if (rcnt > 0)
       
   434          glp_add_rows(lp->prob, rcnt);
       
   435       if (ccnt > 0)
       
   436          glp_add_cols(lp->prob, ccnt);
       
   437       enlargerflag(lp);
       
   438       for (i = 0; i < rcnt; i++)
       
   439       {  if (rowname != NULL)
       
   440             glp_set_row_name(lp->prob, m+i+1, rowname[i]);
       
   441          temp = (rhs == NULL ? 0.0 : rhs[i]);
       
   442          if (sense == NULL || sense[i] == 'E')
       
   443          {  lp->rflag[m+i] = RF_NOT_RANGED;
       
   444             type = GLP_FX;
       
   445          }
       
   446          else if (sense[i] == 'L')
       
   447          {  lp->rflag[m+i] = RF_NOT_RANGED;
       
   448             type = GLP_UP;
       
   449          }
       
   450          else if (sense[i] == 'G')
       
   451          {  lp->rflag[m+i] = RF_NOT_RANGED;
       
   452             type = GLP_LO;
       
   453          }
       
   454          else if (sense[i] == 'R')
       
   455          {  lp->rflag[m+i] = RF_RANGED_POS;
       
   456             type = GLP_FX;
       
   457          }
       
   458          else
       
   459             xassert(sense != sense);
       
   460          glp_set_row_bnds(lp->prob, m+i+1, type, temp, temp);
       
   461          beg = rmatbeg[i];
       
   462          end = (i < rcnt-1 ? rmatbeg[i+1] : nzcnt);
       
   463          for (k = beg; k < end; k++)
       
   464             lp->iwork[k-beg] = rmatind[k]+1;
       
   465          glp_set_mat_row(lp->prob, m+i+1, end-beg, lp->iwork-1,
       
   466             rmatval+beg-1);
       
   467          for (k = beg; k < end; k++)
       
   468             lp->iwork[k-beg] = 0;
       
   469       }
       
   470       for (j = 0; j < ccnt; j++)
       
   471       {  if (colname != NULL)
       
   472             glp_set_col_name(lp->prob, n+j+1, colname[j]);
       
   473          glp_set_col_bnds(lp->prob, n+j+1, GLP_LO, 0.0, 0.0);
       
   474       }
       
   475 done: return errcode;
       
   476 }
       
   477 
       
   478 int CPXbaropt(CPXENV *env, CPXLP *lp)
       
   479 {     xassert(env == env);
       
   480       xassert(lp == lp);
       
   481       xprintf("CPXbaropt: not implemented yet\n");
       
   482       exit(EXIT_FAILURE);
       
   483       return -1;
       
   484 }
       
   485 
       
   486 int CPXbinvrow(CPXENV *env, CPXLP *lp, int i, double y[])
       
   487 {     xassert(env == env);
       
   488       xassert(lp == lp);
       
   489       xassert(i == i);
       
   490       xassert(y == y);
       
   491       xprintf("CPXbinvrow: not implemented yet\n");
       
   492       exit(EXIT_FAILURE);
       
   493       return -1;
       
   494 }
       
   495 
       
   496 int CPXchgbds(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
       
   497       const char lu[], const double bd[])
       
   498 {     int j, n, type, errcode;
       
   499       double lbnd, ubnd;
       
   500       errcode = checklp(env, lp);
       
   501       if (errcode) goto done;
       
   502       if (cnt < 0)
       
   503       {  errcode = error(env, CPXERR_BAD_ARGUMENT);
       
   504          goto done;
       
   505       }
       
   506       if (cnt > 0)
       
   507       {  if (indices == NULL || lu == NULL || bd == NULL)
       
   508          {  errcode = error(env, CPXERR_NULL_POINTER);
       
   509             goto done;
       
   510          }
       
   511       }
       
   512       n = glp_get_num_cols(lp->prob);
       
   513       for (j = 0; j < cnt; j++)
       
   514       {  if (!(0 <= indices[j] && indices[j] < n))
       
   515          {  errcode = error(env, CPXERR_COL_INDEX_RANGE, j);
       
   516             goto done;
       
   517          }
       
   518          if (!(lu[j] == 'L' || lu[j] == 'U' || lu[j] == 'B'))
       
   519          {  errcode = error(env, CPXERR_BAD_LUB, j);
       
   520             goto done;
       
   521          }
       
   522       }
       
   523       errcode = 0;
       
   524       invalidate(lp);
       
   525       for (j = 0; j < cnt; j++)
       
   526       {  type = glp_get_col_type(lp->prob, indices[j]+1);
       
   527          lbnd = glp_get_col_lb(lp->prob, indices[j]+1);
       
   528          ubnd = glp_get_col_ub(lp->prob, indices[j]+1);
       
   529          if (type == GLP_FR || type == GLP_UP)
       
   530             lbnd = -CPX_INFBOUND;
       
   531          if (type == GLP_FR || type == GLP_LO)
       
   532             ubnd = +CPX_INFBOUND;
       
   533          if (lu[j] == 'L')
       
   534             lbnd = bd[j];
       
   535          else if (lu[j] == 'U')
       
   536             ubnd = bd[j];
       
   537          else if (lu[j] == 'B')
       
   538             lbnd = ubnd = bd[j];
       
   539          else
       
   540             xassert(lu != lu);
       
   541          if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
       
   542             type = GLP_FR;
       
   543          else if (ubnd >= +CPX_INFBOUND)
       
   544             type = GLP_LO;
       
   545          else if (lbnd <= -CPX_INFBOUND)
       
   546             type = GLP_UP;
       
   547          else if (lbnd != ubnd)
       
   548             type = GLP_DB;
       
   549          else
       
   550             type = GLP_FX;
       
   551          glp_set_col_bnds(lp->prob, indices[j]+1, type, lbnd, ubnd);
       
   552       }
       
   553 done: return errcode;
       
   554 }
       
   555 
       
   556 int CPXchgcoeflist(CPXENV *env, CPXLP *lp, int numcoefs,
       
   557       const int rowlist[], const int collist[], const double vallist[])
       
   558 {     int i, j, k, m, n, rcnt, ccnt, len, ptr, errcode;
       
   559       int *head, *next, *ind;
       
   560       double *val;
       
   561       errcode = checklp(env, lp);
       
   562       if (errcode) goto done;
       
   563       if (numcoefs < 0)
       
   564       {  errcode = error(env, CPXERR_BAD_ARGUMENT);
       
   565          goto done;
       
   566       }
       
   567       if (numcoefs == 0)
       
   568       {  errcode = 0;
       
   569          goto done;
       
   570       }
       
   571       if (rowlist == NULL || collist == NULL || vallist == NULL)
       
   572       {  errcode = error(env, CPXERR_NULL_POINTER);
       
   573          goto done;
       
   574       }
       
   575       /* check triplets and determine the number of rows and columns
       
   576          to be changed */
       
   577       m = glp_get_num_rows(lp->prob);
       
   578       n = glp_get_num_cols(lp->prob);
       
   579       enlargeiwork(lp, m);
       
   580       enlargeiwork(lp, n);
       
   581       rcnt = ccnt = 0;
       
   582       for (k = 0; k < numcoefs; k++)
       
   583       {  i = rowlist[k];
       
   584          if (!(0 <= i && i < m))
       
   585          {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, i);
       
   586             goto done;
       
   587          }
       
   588          if (!(lp->iwork[i] & 0x01))
       
   589             rcnt++, lp->iwork[i] |= 0x01;
       
   590          j = collist[k];
       
   591          if (!(0 <= j && j < n))
       
   592          {  errcode = error(env, CPXERR_COL_INDEX_RANGE, j);
       
   593             goto done;
       
   594          }
       
   595          if (!(lp->iwork[j] & 0x02))
       
   596             ccnt++, lp->iwork[j] |= 0x02;
       
   597       }
       
   598       memset(lp->iwork, 0, m * sizeof(int));
       
   599       memset(lp->iwork, 0, n * sizeof(int));
       
   600       errcode = 0;
       
   601       invalidate(lp);
       
   602       if (rcnt <= ccnt)
       
   603       {  /* change the matrix by rows */
       
   604          /* build the linked list of triplets:
       
   605             head[i] is a pointer to first triplet for row i
       
   606             next[k] is a pointer to next triplet for the same row */
       
   607          head = xcalloc(m, sizeof(int));
       
   608          for (i = 0; i < m; i++)
       
   609             head[i] = -1;
       
   610          next = xcalloc(numcoefs, sizeof(int));
       
   611          for (k = 0; k < numcoefs; k++)
       
   612          {  i = rowlist[k];
       
   613             next[k] = head[i];
       
   614             head[i] = k;
       
   615          }
       
   616          /* check duplicate columns */
       
   617          for (i = 0; i < m; i++)
       
   618          {  for (k = head[i]; k >= 0; k = next[k])
       
   619             {  j = collist[k];
       
   620                if (lp->iwork[j])
       
   621                {  xfree(head);
       
   622                   xfree(next);
       
   623                   errcode = error(env, CPXERR_DUP_ENTRY);
       
   624                   goto done;
       
   625                }
       
   626                lp->iwork[j] = 1;
       
   627             }
       
   628             for (k = head[i]; k >= 0; k = next[k])
       
   629                lp->iwork[collist[k]] = 0;
       
   630          }
       
   631          /* perform operation */
       
   632          ind = xcalloc(1+n, sizeof(int));
       
   633          val = xcalloc(1+n, sizeof(double));
       
   634          for (i = 0; i < m; i++)
       
   635          {  if (head[i] < 0) continue;
       
   636             len = glp_get_mat_row(lp->prob, i+1, ind, val);
       
   637             for (ptr = 1; ptr <= len; ptr++)
       
   638             {  j = ind[ptr]-1;
       
   639                xassert(lp->iwork[j] == 0);
       
   640                lp->iwork[j] = ptr;
       
   641             }
       
   642             for (k = head[i]; k >= 0; k = next[k])
       
   643             {  j = collist[k];
       
   644                if (lp->iwork[j] == 0)
       
   645                   lp->iwork[j] = ++len;
       
   646                ptr = lp->iwork[j];
       
   647                ind[ptr] = j+1, val[ptr] = vallist[k];
       
   648             }
       
   649             glp_set_mat_row(lp->prob, i+1, len, ind, val);
       
   650             for (ptr = 1; ptr <= len; ptr++)
       
   651                lp->iwork[ind[ptr]-1] = 0;
       
   652          }
       
   653       }
       
   654       else
       
   655       {  /* change the matrix by columns */
       
   656          /* build the linked lists of triplets:
       
   657             head[j] is a pointer to first triplet for column j
       
   658             next[k] is a pointer to next triplet for the same column */
       
   659          head = xcalloc(n, sizeof(int));
       
   660          for (j = 0; j < n; j++)
       
   661             head[j] = -1;
       
   662          next = xcalloc(numcoefs, sizeof(int));
       
   663          for (k = 0; k < numcoefs; k++)
       
   664          {  j = collist[k];
       
   665             next[k] = head[j];
       
   666             head[j] = k;
       
   667          }
       
   668          /* check duplicate rows */
       
   669          for (j = 0; j < n; j++)
       
   670          {  for (k = head[j]; k >= 0; k = next[k])
       
   671             {  i = rowlist[k];
       
   672                if (lp->iwork[i])
       
   673                {  xfree(head);
       
   674                   xfree(next);
       
   675                   errcode = error(env, CPXERR_DUP_ENTRY);
       
   676                   goto done;
       
   677                }
       
   678                lp->iwork[i] = 1;
       
   679             }
       
   680             for (k = head[j]; k >= 0; k = next[k])
       
   681                lp->iwork[rowlist[k]] = 0;
       
   682          }
       
   683          /* perform operation */
       
   684          ind = xcalloc(1+m, sizeof(int));
       
   685          val = xcalloc(1+m, sizeof(double));
       
   686          for (j = 0; j < n; j++)
       
   687          {  if (head[j] < 0) continue;
       
   688             len = glp_get_mat_col(lp->prob, j+1, ind, val);
       
   689             for (ptr = 1; ptr <= len; ptr++)
       
   690             {  i = ind[ptr]-1;
       
   691                xassert(lp->iwork[i] == 0);
       
   692                lp->iwork[i] = ptr;
       
   693             }
       
   694             for (k = head[j]; k >= 0; k = next[k])
       
   695             {  i = rowlist[k];
       
   696                if (lp->iwork[i] == 0)
       
   697                   lp->iwork[i] = ++len;
       
   698                ptr = lp->iwork[i];
       
   699                ind[ptr] = i+1, val[ptr] = vallist[k];
       
   700             }
       
   701             glp_set_mat_col(lp->prob, j+1, len, ind, val);
       
   702             for (ptr = 1; ptr <= len; ptr++)
       
   703                lp->iwork[ind[ptr]-1] = 0;
       
   704          }
       
   705       }
       
   706       xfree(head);
       
   707       xfree(next);
       
   708       xfree(ind);
       
   709       xfree(val);
       
   710 done: return errcode;
       
   711 }
       
   712 
       
   713 void CPXchgobjsen(CPXENV *env, CPXLP *lp, int maxormin)
       
   714 {     int errcode;
       
   715       errcode = checklp(env, lp);
       
   716       if (errcode) goto done;
       
   717       if (!(maxormin == CPX_MIN || maxormin == CPX_MAX))
       
   718       {  errcode = error(env, CPXERR_BAD_ARGUMENT);
       
   719          goto done;
       
   720       }
       
   721       errcode = 0;
       
   722       invalidate(lp);
       
   723       if (maxormin == CPX_MIN)
       
   724          glp_set_obj_dir(lp->prob, GLP_MIN);
       
   725       else
       
   726          glp_set_obj_dir(lp->prob, GLP_MAX);
       
   727 done: xassert(errcode == errcode);
       
   728       return;
       
   729 }
       
   730 
       
   731 int CPXchgsense(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
       
   732       const char sense[])
       
   733 {     int i, m, type, errcode;
       
   734       double rhs;
       
   735       errcode = checklp(env, lp);
       
   736       if (errcode) goto done;
       
   737       if (cnt < 0)
       
   738       {  errcode = error(env, CPXERR_BAD_ARGUMENT);
       
   739          goto done;
       
   740       }
       
   741       if (cnt > 0 && (indices == NULL || sense == NULL))
       
   742       {  errcode = error(env, CPXERR_NULL_POINTER);
       
   743          goto done;
       
   744       }
       
   745       m = glp_get_num_rows(lp->prob);
       
   746       for (i = 0; i < cnt; i++)
       
   747       {  if (!(0 <= indices[i] && indices[i] < m))
       
   748          {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, i);
       
   749             goto done;
       
   750          }
       
   751          if (!(sense[i] == 'L' || sense[i] == 'E' || sense[i] == 'G' ||
       
   752                sense[i] == 'R'))
       
   753          {  errcode = error(env, CPXERR_BAD_SENSE, i);
       
   754             goto done;
       
   755          }
       
   756       }
       
   757       errcode = 0;
       
   758       invalidate(lp);
       
   759       for (i = 0; i < cnt; i++)
       
   760       {  type = glp_get_row_type(lp->prob, indices[i]+1);
       
   761          if (lp->rflag[indices[i]] == RF_NOT_RANGED)
       
   762          {  if (type == GLP_LO || type == GLP_FX)
       
   763                rhs = glp_get_row_lb(lp->prob, indices[i]+1);
       
   764             else if (type == GLP_UP)
       
   765                rhs = glp_get_row_ub(lp->prob, indices[i]+1);
       
   766             else
       
   767                xassert(type != type);
       
   768          }
       
   769          else if (lp->rflag[indices[i]] == RF_RANGED_POS)
       
   770          {  xassert(type == GLP_DB || type == GLP_FX);
       
   771             rhs = glp_get_row_lb(lp->prob, indices[i]+1);
       
   772          }
       
   773          else if (lp->rflag[indices[i]] == RF_RANGED_NEG)
       
   774          {  xassert(type == GLP_DB);
       
   775             rhs = glp_get_row_ub(lp->prob, indices[i]+1);
       
   776          }
       
   777          else
       
   778             xassert(lp != lp);
       
   779          if (sense[i] == 'L')
       
   780          {  lp->rflag[indices[i]] = RF_NOT_RANGED;
       
   781             type = GLP_UP;
       
   782          }
       
   783          else if (sense[i] == 'E')
       
   784          {  lp->rflag[indices[i]] = RF_NOT_RANGED;
       
   785             type = GLP_FX;
       
   786          }
       
   787          else if (sense[i] == 'G')
       
   788          {  lp->rflag[indices[i]] = RF_NOT_RANGED;
       
   789             type = GLP_LO;
       
   790          }
       
   791          else if (sense[i] == 'R')
       
   792          {  lp->rflag[indices[i]] = RF_RANGED_POS;
       
   793             type = GLP_FX;
       
   794          }
       
   795          else
       
   796             xassert(sense != sense);
       
   797          glp_set_row_bnds(lp->prob, indices[i]+1, type, rhs, rhs);
       
   798       }
       
   799 done: return errcode;
       
   800 }
       
   801 
       
   802 int CPXcloseCPLEX(CPXENV **_env)
       
   803 {     CPXENV *env;
       
   804       CPXLP *lp;
       
   805       int errcode;
       
   806       if (_env == NULL)
       
   807       {  errcode = CPXERR_NULL_POINTER;
       
   808          goto done;
       
   809       }
       
   810       env = *_env;
       
   811       errcode = checkenv(env);
       
   812       if (errcode) goto done;
       
   813       while (env->list != NULL)
       
   814       {  lp = env->list;
       
   815          errcode = CPXfreeprob(env, &lp);
       
   816          xassert(!errcode);
       
   817       }
       
   818       xfree(env->intparam);
       
   819       xfree(env->dblparam);
       
   820       xfree(env);
       
   821       *_env = NULL;
       
   822       errcode = 0;
       
   823 done: return errcode;
       
   824 }
       
   825 
       
   826 int CPXcopybase(CPXENV *env, CPXLP *lp, const int cstat[],
       
   827       const int rstat[])
       
   828 {     int i, j, m, n, stat, errcode;
       
   829       errcode = checklp(env, lp);
       
   830       if (errcode) goto done;
       
   831       m = glp_get_num_rows(lp->prob);
       
   832       n = glp_get_num_cols(lp->prob);
       
   833       if (m > 0 && rstat == NULL || n > 0 && cstat == NULL)
       
   834       {  errcode = error(env, CPXERR_NULL_POINTER);
       
   835          goto done;
       
   836       }
       
   837       for (i = 0; i < m; i++)
       
   838       {  if (!(rstat[i] == CPX_AT_LOWER || rstat[i] == CPX_BASIC ||
       
   839                rstat[i] == CPX_AT_UPPER))
       
   840          {  errcode = error(env, CPXERR_BAD_STATUS, i);
       
   841             goto done;
       
   842          }
       
   843       }
       
   844       for (j = 0; j < n; j++)
       
   845       {  if (!(cstat[j] == CPX_AT_LOWER || cstat[j] == CPX_BASIC ||
       
   846                cstat[j] == CPX_AT_UPPER || cstat[j] == CPX_FREE_SUPER))
       
   847          {  errcode = error(env, CPXERR_BAD_STATUS, j);
       
   848             goto done;
       
   849          }
       
   850       }
       
   851       errcode = 0;
       
   852       invalidate(lp);
       
   853       for (i = 0; i < m; i++)
       
   854       {  if (rstat[i] == CPX_AT_LOWER)
       
   855             stat = GLP_NL;
       
   856          else if (rstat[i] == CPX_BASIC)
       
   857             stat = GLP_BS;
       
   858          else if (rstat[i] == CPX_AT_UPPER)
       
   859             stat = GLP_NU;
       
   860          else
       
   861             xassert(rstat != rstat);
       
   862          glp_set_row_stat(lp->prob, i+1, stat);
       
   863       }
       
   864       for (j = 0; j < n; j++)
       
   865       {  if (cstat[j] == CPX_AT_LOWER)
       
   866             stat = GLP_NL;
       
   867          else if (cstat[j] == CPX_BASIC)
       
   868             stat = GLP_BS;
       
   869          else if (cstat[j] == CPX_AT_UPPER)
       
   870             stat = GLP_NU;
       
   871          else if (cstat[j] == CPX_FREE_SUPER)
       
   872             stat = GLP_NF;
       
   873          else
       
   874             xassert(cstat != cstat);
       
   875          glp_set_col_stat(lp->prob, j+1, stat);
       
   876       }
       
   877 done: return errcode;
       
   878 }
       
   879 
       
   880 int CPXcopybasednorms(CPXENV *env, CPXLP *lp, const int cstat[],
       
   881       const int rstat[], const double dnorm[])
       
   882 {     int errcode;
       
   883       errcode = CPXcopybase(env, lp, cstat, rstat);
       
   884       xassert(dnorm == dnorm);
       
   885       return errcode;
       
   886 }
       
   887 
       
   888 int CPXcopylp(CPXENV *env, CPXLP *lp, int numcols, int numrows,
       
   889       int objsen, const double obj[], const double rhs[],
       
   890       const char sense[], const int matbeg[], const int matcnt[],
       
   891       const int matind[], const double matval[], const double lb[],
       
   892       const double ub[], const double rngval[])
       
   893 {     int errcode;
       
   894       errcode = CPXcopylpwnames(env, lp, numcols, numrows, objsen, obj,
       
   895          rhs, sense, matbeg, matcnt, matind, matval, lb, ub, rngval,
       
   896          NULL, NULL);
       
   897       return errcode;
       
   898 }
       
   899 
       
   900 int CPXcopylpwnames(CPXENV *env, CPXLP *lp, int numcols, int numrows,
       
   901       int objsen, const double obj[], const double rhs[],
       
   902       const char sense[], const int matbeg[], const int matcnt[],
       
   903       const int matind[], const double matval[], const double lb[],
       
   904       const double ub[], const double rngval[], char *colname[],
       
   905       char *rowname[])
       
   906 {     int i, j, k, beg, end, type, errcode;
       
   907       double lbnd, ubnd;
       
   908       char name[255+1];
       
   909       errcode = checklp(env, lp);
       
   910       if (errcode) goto done;
       
   911       if (numcols < 0 || numrows < 0)
       
   912       {  errcode = error(env, CPXERR_BAD_ARGUMENT);
       
   913          goto done;
       
   914       }
       
   915       if (!(objsen == CPX_MIN || objsen == CPX_MAX))
       
   916       {  errcode = error(env, CPXERR_BAD_ARGUMENT);
       
   917          goto done;
       
   918       }
       
   919       if (numcols > 0)
       
   920       {  if (matbeg == NULL || matcnt == NULL || matind == NULL ||
       
   921                matval == NULL)
       
   922          {  errcode = error(env, CPXERR_NULL_POINTER);
       
   923             goto done;
       
   924          }
       
   925       }
       
   926       for (i = 0; i < numrows; i++)
       
   927       {  if (sense != NULL)
       
   928          {  if (!(sense[i] == 'L' || sense[i] == 'E' ||
       
   929                   sense[i] == 'G' || sense[i] == 'R'))
       
   930             {  errcode = error(env, CPXERR_BAD_SENSE, i);
       
   931                goto done;
       
   932             }
       
   933          }
       
   934          if (rowname != NULL)
       
   935          {  if (rowname[i] == NULL)
       
   936             {  errcode = error(env, CPXERR_NULL_NAME, i);
       
   937                goto done;
       
   938             }
       
   939          }
       
   940       }
       
   941       enlargeiwork(lp, numrows);
       
   942       for (j = 0; j < numcols; j++)
       
   943       {  beg = matbeg[j];
       
   944          if (j > 0 && !(matbeg[j-1] <= beg))
       
   945          {  errcode = error(env, CPXERR_ARRAY_NOT_ASCENDING, j);
       
   946             goto done;
       
   947          }
       
   948          if (beg < 0)
       
   949          {  errcode = error(env, CPXERR_INDEX_RANGE);
       
   950             goto done;
       
   951          }
       
   952          end = beg + matcnt[j];
       
   953          if (!(beg <= end) || j < numcols-1 && !(end <= matbeg[j+1]))
       
   954          {  errcode = error(env, CPXERR_COUNT_RANGE, j);
       
   955             goto done;
       
   956          }
       
   957          for (k = beg; k < end; k++)
       
   958          {  if (!(0 <= matind[k] && matind[k] < numrows))
       
   959             {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, k);
       
   960                goto done;
       
   961             }
       
   962          }
       
   963          errcode = 0;
       
   964          for (k = beg; k < end; k++)
       
   965          {  if (lp->iwork[matind[k]])
       
   966             {  errcode = error(env, CPXERR_DUP_ENTRY);
       
   967                break;
       
   968             }
       
   969             lp->iwork[matind[k]] = 1;
       
   970          }
       
   971          for (k = beg; k < end; k++)
       
   972             lp->iwork[matind[k]] = 0;
       
   973          if (errcode) goto done;
       
   974          if (colname != NULL)
       
   975          {  if (colname[j] != NULL)
       
   976             {  errcode = error(env, CPXERR_NULL_NAME, j);
       
   977                goto done;
       
   978             }
       
   979          }
       
   980       }
       
   981       errcode = 0;
       
   982       invalidate(lp);
       
   983       if (glp_get_prob_name(lp->prob) == NULL)
       
   984          name[0] = '\0';
       
   985       else
       
   986          strcpy(name, glp_get_prob_name(lp->prob));
       
   987       glp_erase_prob(lp->prob);
       
   988       glp_set_prob_name(lp->prob, name);
       
   989       if (objsen == CPX_MIN)
       
   990          glp_set_obj_dir(lp->prob, GLP_MIN);
       
   991       else if (objsen == CPX_MAX)
       
   992          glp_set_obj_dir(lp->prob, GLP_MAX);
       
   993       else
       
   994          xassert(objsen != objsen);
       
   995       if (numrows > 0)
       
   996          glp_add_rows(lp->prob, numrows);
       
   997       enlargerflag(lp);
       
   998       for (i = 0; i < numrows; i++)
       
   999       {  if (rowname != NULL)
       
  1000             glp_set_row_name(lp->prob, i+1, rowname[i]);
       
  1001          lbnd = ubnd = (rhs == NULL ? 0.0 : rhs[i]);
       
  1002          if (sense == NULL || sense[i] == 'E')
       
  1003          {  lp->rflag[i] = RF_NOT_RANGED;
       
  1004             type = GLP_FX;
       
  1005          }
       
  1006          else if (sense[i] == 'L')
       
  1007          {  lp->rflag[i] = RF_NOT_RANGED;
       
  1008             type = GLP_UP;
       
  1009          }
       
  1010          else if (sense[i] == 'G')
       
  1011          {  lp->rflag[i] = RF_NOT_RANGED;
       
  1012             type = GLP_LO;
       
  1013          }
       
  1014          else if (sense[i] == 'R')
       
  1015          {  if (rngval == NULL || rngval[i] == 0.0)
       
  1016             {  lp->rflag[i] = RF_RANGED_POS;
       
  1017                type = GLP_FX;
       
  1018             }
       
  1019             else if (rngval[i] > 0.0)
       
  1020             {  lp->rflag[i] = RF_RANGED_POS;
       
  1021                type = GLP_DB;
       
  1022                ubnd += rngval[i];
       
  1023             }
       
  1024             else /* rngval[i] < 0.0 */
       
  1025             {  lp->rflag[i] = RF_RANGED_NEG;
       
  1026                type = GLP_DB;
       
  1027                lbnd += rngval[i];
       
  1028             }
       
  1029          }
       
  1030          else
       
  1031             xassert(sense != sense);
       
  1032          glp_set_row_bnds(lp->prob, i+1, type, lbnd, ubnd);
       
  1033       }
       
  1034       if (numcols > 0)
       
  1035          glp_add_cols(lp->prob, numcols);
       
  1036       for (j = 0; j < numcols; j++)
       
  1037       {  if (colname != NULL)
       
  1038             glp_set_col_name(lp->prob, j+1, colname[j]);
       
  1039          lbnd = (lb == NULL ? 0.0 : lb[j]);
       
  1040          ubnd = (ub == NULL ? +CPX_INFBOUND : ub[j]);
       
  1041          if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
       
  1042             type = GLP_FR;
       
  1043          else if (ubnd >= +CPX_INFBOUND)
       
  1044             type = GLP_LO;
       
  1045          else if (lbnd <= -CPX_INFBOUND)
       
  1046             type = GLP_UP;
       
  1047          else if (lbnd != ubnd)
       
  1048             type = GLP_DB;
       
  1049          else
       
  1050             type = GLP_FX;
       
  1051          glp_set_col_bnds(lp->prob, j+1, type, lbnd, ubnd);
       
  1052          if (obj != NULL)
       
  1053             glp_set_obj_coef(lp->prob, j+1, obj[j]);
       
  1054          beg = matbeg[j];
       
  1055          end = beg + matcnt[j];
       
  1056          for (k = beg; k < end; k++)
       
  1057             lp->iwork[k-beg] = matind[k]+1;
       
  1058          glp_set_mat_col(lp->prob, j+1, end-beg, lp->iwork-1,
       
  1059             matval+beg-1);
       
  1060          for (k = beg; k < end; k++)
       
  1061             lp->iwork[k-beg] = 0;
       
  1062       }
       
  1063 done: return errcode;
       
  1064 }
       
  1065 
       
  1066 CPXLP *CPXcreateprob(CPXENV *env, int *status, const char *probname)
       
  1067 {     CPXLP *lp = NULL;
       
  1068       int errcode;
       
  1069       errcode = checkenv(env);
       
  1070       if (errcode) goto done;
       
  1071       lp = xmalloc(sizeof(struct CPXLP));
       
  1072       lp->env = env;
       
  1073       lp->prob = glp_create_prob();
       
  1074       glp_set_prob_name(lp->prob, probname);
       
  1075       lp->rflen = 100;
       
  1076       lp->rflag = xcalloc(lp->rflen, sizeof(char));
       
  1077       lp->iwlen = 100;
       
  1078       lp->iwork = xcalloc(lp->iwlen, sizeof(int));
       
  1079       memset(lp->iwork, 0, lp->iwlen * sizeof(int));
       
  1080       lp->link = env->list;
       
  1081       env->list = lp;
       
  1082       invalidate(lp);
       
  1083 done: if (status != NULL) *status = errcode;
       
  1084       return lp;
       
  1085 }
       
  1086 
       
  1087 int CPXdelcols(CPXENV *env, CPXLP *lp, int begin, int end)
       
  1088 {     int j, n, errcode;
       
  1089       errcode = checklp(env, lp);
       
  1090       if (errcode) goto done;
       
  1091       n = glp_get_num_cols(lp->prob);
       
  1092       if (!(0 <= begin && begin <= end && end < n))
       
  1093       {  errcode = error(env, CPXERR_INDEX_RANGE);
       
  1094          goto done;
       
  1095       }
       
  1096       errcode = 0;
       
  1097       invalidate(lp);
       
  1098       enlargeiwork(lp, end-begin+1);
       
  1099       for (j = begin; j <= end; j++)
       
  1100          lp->iwork[j-begin] = j+1;
       
  1101       glp_del_cols(lp->prob, end-begin+1, lp->iwork-1);
       
  1102       for (j = begin; j <= end; j++)
       
  1103          lp->iwork[j-begin] = 0;
       
  1104 done: return errcode;
       
  1105 }
       
  1106 
       
  1107 int CPXdelrows(CPXENV *env, CPXLP *lp, int begin, int end)
       
  1108 {     int i, m, errcode;
       
  1109       errcode = checklp(env, lp);
       
  1110       if (errcode) goto done;
       
  1111       m = glp_get_num_rows(lp->prob);
       
  1112       if (!(0 <= begin && begin <= end && end < m))
       
  1113       {  errcode = error(env, CPXERR_INDEX_RANGE);
       
  1114          goto done;
       
  1115       }
       
  1116       errcode = 0;
       
  1117       invalidate(lp);
       
  1118       enlargeiwork(lp, end-begin+1);
       
  1119       for (i = begin; i <= end; i++)
       
  1120          lp->iwork[i-begin] = i+1;
       
  1121       glp_del_rows(lp->prob, end-begin+1, lp->iwork-1);
       
  1122       for (i = begin; i <= end; i++)
       
  1123          lp->iwork[i-begin] = 0;
       
  1124       for (i = end+1; i < m; i++)
       
  1125          lp->rflag[i-(end-begin+1)] = lp->rflag[i];
       
  1126 done: return errcode;
       
  1127 }
       
  1128 
       
  1129 int CPXdelsetcols(CPXENV *env, CPXLP *lp, int delstat[])
       
  1130 {     xassert(env == env);
       
  1131       xassert(lp == lp);
       
  1132       xassert(delstat == delstat);
       
  1133       xprintf("CPXdelsetcols: not implemented yet\n");
       
  1134       exit(EXIT_FAILURE);
       
  1135       return -1;
       
  1136 }
       
  1137 
       
  1138 int CPXdelsetrows(CPXENV *env, CPXLP *lp, int delstat[])
       
  1139 {     int i, m, cnt, ind, errcode;
       
  1140       errcode = checklp(env, lp);
       
  1141       if (errcode) goto done;
       
  1142       m = glp_get_num_rows(lp->prob);
       
  1143       if (m > 0 && delstat == NULL)
       
  1144       {  errcode = error(env, CPXERR_NULL_POINTER);
       
  1145          goto done;
       
  1146       }
       
  1147       errcode = 0;
       
  1148       invalidate(lp);
       
  1149       enlargeiwork(lp, m);
       
  1150       cnt = ind = 0;
       
  1151       for (i = 0; i < m; i++)
       
  1152       {  if (delstat[i] == 1)
       
  1153          {  delstat[i] = -1;
       
  1154             lp->iwork[cnt++] = i+1;
       
  1155          }
       
  1156          else
       
  1157          {  delstat[i] = ind;
       
  1158             lp->rflag[ind++] = lp->rflag[i];
       
  1159          }
       
  1160       }
       
  1161       if (cnt > 0)
       
  1162          glp_del_rows(lp->prob, cnt, lp->iwork-1);
       
  1163       for (i = 0; i < cnt; i++)
       
  1164          lp->iwork[i] = 0;
       
  1165 done: return errcode;
       
  1166 }
       
  1167 
       
  1168 int CPXdualopt(CPXENV *env, CPXLP *lp);
       
  1169 
       
  1170 int CPXfreeprob(CPXENV *env, CPXLP **_lp)
       
  1171 {     CPXLP *lp;
       
  1172       int errcode;
       
  1173       errcode = checkenv(env);
       
  1174       if (errcode) goto done;
       
  1175       if (_lp == NULL)
       
  1176       {  errcode = error(env, CPXERR_NULL_POINTER);
       
  1177          goto done;
       
  1178       }
       
  1179       lp = *_lp;
       
  1180       errcode = checklp(env, lp);
       
  1181       if (errcode) goto done;
       
  1182       errcode = 0;
       
  1183       env = lp->env;
       
  1184       if (env->list == lp)
       
  1185          env->list = lp->link;
       
  1186       else
       
  1187       {  CPXLP *pp;
       
  1188          for (pp = env->list; pp != NULL; pp = pp->link)
       
  1189             if (pp->link == lp) break;
       
  1190          xassert(pp != NULL);
       
  1191          pp->link = lp->link;
       
  1192       }
       
  1193       glp_delete_prob(lp->prob);
       
  1194       xfree(lp->rflag);
       
  1195       xfree(lp->iwork);
       
  1196       xfree(lp);
       
  1197       *_lp = NULL;
       
  1198 done: return errcode;
       
  1199 }
       
  1200 
       
  1201 int CPXgetbase(CPXENV *env, CPXLP *lp, int cstat[], int rstat[])
       
  1202 {     int i, j, m, n, stat, errcode;
       
  1203       errcode = checklp(env, lp);
       
  1204       if (errcode) goto done;
       
  1205       if (!lp->stat)
       
  1206       {  errcode = error(env, CPXERR_NO_SOLN);
       
  1207          goto done;
       
  1208       }
       
  1209       if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
       
  1210          ;
       
  1211       else
       
  1212       {  errcode = error(env, CPXERR_NO_BASIC_SOLN);
       
  1213          goto done;
       
  1214       }
       
  1215       errcode = 0;
       
  1216       if (rstat != NULL)
       
  1217       {  m = glp_get_num_rows(lp->prob);
       
  1218          for (i = 0; i < m; i++)
       
  1219          {  stat = glp_get_row_stat(lp->prob, i+1);
       
  1220             if (stat == GLP_BS)
       
  1221                rstat[i] = CPX_BASIC;
       
  1222             else if (lp->rflag[i] == RF_NOT_RANGED || stat != GLP_NU)
       
  1223                rstat[i] = CPX_AT_LOWER;
       
  1224             else
       
  1225                rstat[i] = CPX_AT_UPPER;
       
  1226          }
       
  1227       }
       
  1228       if (cstat != NULL)
       
  1229       {  n = glp_get_num_cols(lp->prob);
       
  1230          for (j = 0; j < n; j++)
       
  1231          {  stat = glp_get_col_stat(lp->prob, j+1);
       
  1232             if (stat == GLP_BS)
       
  1233                cstat[j] = CPX_BASIC;
       
  1234             else if (stat == GLP_NU)
       
  1235                cstat[j] = CPX_AT_UPPER;
       
  1236             else if (stat == GLP_NF)
       
  1237                cstat[j] = CPX_FREE_SUPER;
       
  1238             else
       
  1239                cstat[j] = CPX_AT_LOWER;
       
  1240          }
       
  1241       }
       
  1242 done: return errcode;
       
  1243 }
       
  1244 
       
  1245 int CPXgetbasednorms(CPXENV *env, CPXLP *lp, int cstat[], int rstat[],
       
  1246       double dnorm[])
       
  1247 {     int i, m, errcode;
       
  1248       errcode = CPXgetbase(env, lp, cstat, rstat);
       
  1249       if (errcode) goto done;
       
  1250       if (dnorm != NULL)
       
  1251       {  m = glp_get_num_rows(lp->prob);
       
  1252          for (i = 0; i < m; i++) dnorm[i] = 1.0;
       
  1253       }
       
  1254 done: return errcode;
       
  1255 }
       
  1256 
       
  1257 int CPXgetbhead(CPXENV *env, CPXLP *lp, int head[], double x[])
       
  1258 {     xassert(env == env);
       
  1259       xassert(lp == lp);
       
  1260       xassert(head == head);
       
  1261       xassert(x == x);
       
  1262       xprintf("CPXgetbhead: not implemented yet\n");
       
  1263       exit(EXIT_FAILURE);
       
  1264       return -1;
       
  1265 }
       
  1266 
       
  1267 int CPXgetdblparam(CPXENV *env, int whichparam, double *value)
       
  1268 {     int k, errcode;
       
  1269       errcode = checkenv(env);
       
  1270       if (errcode) goto done;
       
  1271       k = finddblparam(whichparam);
       
  1272       if (k < 0)
       
  1273       {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
       
  1274          goto done;
       
  1275       }
       
  1276       errcode = 0;
       
  1277       if (value != NULL)
       
  1278          *value = env->dblparam[k];
       
  1279 done: return errcode;
       
  1280 }
       
  1281 
       
  1282 int CPXgetdj(CPXENV *env, CPXLP *lp, double dj[], int begin, int end)
       
  1283 {     int j, n, errcode;
       
  1284       errcode = checklp(env, lp);
       
  1285       if (errcode) goto done;
       
  1286       n = glp_get_num_cols(lp->prob);
       
  1287       if (!(0 <= begin && begin <= end && end < n))
       
  1288       {  errcode = error(env, CPXERR_INDEX_RANGE);
       
  1289          goto done;
       
  1290       }
       
  1291       if (!lp->stat)
       
  1292       {  errcode = error(env, CPXERR_NO_SOLN);
       
  1293          goto done;
       
  1294       }
       
  1295       errcode = 0;
       
  1296       if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
       
  1297       {  if (dj != NULL)
       
  1298          {  for (j = begin; j <= end; j++)
       
  1299                dj[j-begin] = glp_get_col_dual(lp->prob, j+1);
       
  1300          }
       
  1301       }
       
  1302       else
       
  1303          xassert(lp != lp);
       
  1304 done: return errcode;
       
  1305 }
       
  1306 
       
  1307 char *CPXgeterrorstring(CPXENV *env, int errcode, char *buffer)
       
  1308 {     const char *string;
       
  1309       xassert(env == env);
       
  1310       string = finderrstring(errcode);
       
  1311       if (string == NULL)
       
  1312          buffer = NULL;
       
  1313       else
       
  1314          sprintf(buffer, "CPLEX Error %5d:  %s.\n", errcode, string);
       
  1315       return buffer;
       
  1316 }
       
  1317 
       
  1318 int CPXgetijdiv(CPXENV *env, CPXLP *lp, int *idiv, int *jdiv)
       
  1319 {     xassert(env == env);
       
  1320       xassert(lp == lp);
       
  1321       xassert(idiv == idiv);
       
  1322       xassert(jdiv == jdiv);
       
  1323       xprintf("CPXgetijdiv: not implemented yet\n");
       
  1324       exit(EXIT_FAILURE);
       
  1325       return -1;
       
  1326 }
       
  1327 
       
  1328 int CPXgetintparam(CPXENV *env, int whichparam, int *value)
       
  1329 {     int k, errcode;
       
  1330       errcode = checkenv(env);
       
  1331       if (errcode) goto done;
       
  1332       k = findintparam(whichparam);
       
  1333       if (k < 0)
       
  1334       {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
       
  1335          goto done;
       
  1336       }
       
  1337       errcode = 0;
       
  1338       if (value != NULL)
       
  1339          *value = env->intparam[k];
       
  1340 done: return errcode;
       
  1341 }
       
  1342 
       
  1343 int CPXgetlb(CPXENV *env, CPXLP *lp, double lb[], int begin, int end)
       
  1344 {     xassert(env == env);
       
  1345       xassert(lp == lp);
       
  1346       xassert(lb == lb);
       
  1347       xassert(begin == begin);
       
  1348       xassert(end == end);
       
  1349       xprintf("CPXgetlb: not implemented yet\n");
       
  1350       exit(EXIT_FAILURE);
       
  1351       return -1;
       
  1352 }
       
  1353 
       
  1354 int CPXgetmethod(CPXENV *env, CPXLP *lp)
       
  1355 {     int method;
       
  1356       if (checklp(env, lp))
       
  1357          method = CPX_ALG_NONE;
       
  1358       else
       
  1359          method = lp->meth;
       
  1360       return method;
       
  1361 }
       
  1362 
       
  1363 int CPXgetnumcols(CPXENV *env, CPXLP *lp)
       
  1364 {     int numcols;
       
  1365       if (checklp(env, lp))
       
  1366          numcols = 0;
       
  1367       else
       
  1368          numcols = glp_get_num_cols(lp->prob);
       
  1369       return numcols;
       
  1370 }
       
  1371 
       
  1372 int CPXgetnumnz(CPXENV *env, CPXLP *lp)
       
  1373 {     int numnz;
       
  1374       if (checklp(env, lp))
       
  1375          numnz = 0;
       
  1376       else
       
  1377          numnz = glp_get_num_nz(lp->prob);
       
  1378       return numnz;
       
  1379 }
       
  1380 
       
  1381 int CPXgetnumrows(CPXENV *env, CPXLP *lp)
       
  1382 {     int numrows;
       
  1383       if (checklp(env, lp))
       
  1384          numrows = 0;
       
  1385       else
       
  1386          numrows = glp_get_num_rows(lp->prob);
       
  1387       return numrows;
       
  1388 }
       
  1389 
       
  1390 int CPXgetobjval(CPXENV *env, CPXLP *lp, double *objval)
       
  1391 {     int errcode;
       
  1392       errcode = checklp(env, lp);
       
  1393       if (errcode) goto done;
       
  1394       if (!lp->stat)
       
  1395       {  errcode = error(env, CPXERR_NO_SOLN);
       
  1396          goto done;
       
  1397       }
       
  1398       errcode = 0;
       
  1399       if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
       
  1400       {  if (objval != NULL)
       
  1401             *objval = glp_get_obj_val(lp->prob);
       
  1402       }
       
  1403       else
       
  1404          xassert(lp != lp);
       
  1405 done: return errcode;
       
  1406 }
       
  1407 
       
  1408 int CPXgetpi(CPXENV *env, CPXLP *lp, double pi[], int begin, int end)
       
  1409 {     int i, m, errcode;
       
  1410       errcode = checklp(env, lp);
       
  1411       if (errcode) goto done;
       
  1412       m = glp_get_num_rows(lp->prob);
       
  1413       if (!(0 <= begin && begin <= end && end < m))
       
  1414       {  errcode = error(env, CPXERR_INDEX_RANGE);
       
  1415          goto done;
       
  1416       }
       
  1417       if (!lp->stat)
       
  1418       {  errcode = error(env, CPXERR_NO_SOLN);
       
  1419          goto done;
       
  1420       }
       
  1421       errcode = 0;
       
  1422       if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
       
  1423       {  if (pi != NULL)
       
  1424          {  for (i = begin; i <= end; i++)
       
  1425                pi[i-begin] = glp_get_row_dual(lp->prob, i+1);
       
  1426          }
       
  1427       }
       
  1428       else
       
  1429          xassert(lp != lp);
       
  1430 done: return errcode;
       
  1431 }
       
  1432 
       
  1433 int CPXgetsense(CPXENV *env, CPXLP *lp, char sense[], int begin,
       
  1434       int end)
       
  1435 {     xassert(env == env);
       
  1436       xassert(lp == lp);
       
  1437       xassert(sense == sense);
       
  1438       xassert(begin == begin);
       
  1439       xassert(end == end);
       
  1440       xprintf("CPXgetsense: not implemented yet\n");
       
  1441       exit(EXIT_FAILURE);
       
  1442       return -1;
       
  1443 }
       
  1444 
       
  1445 int CPXgetslack(CPXENV *env, CPXLP *lp, double slack[], int begin,
       
  1446       int end)
       
  1447 {     int i, m, type, errcode;
       
  1448       double temp;
       
  1449       errcode = checklp(env, lp);
       
  1450       if (errcode) goto done;
       
  1451       m = glp_get_num_rows(lp->prob);
       
  1452       if (!(0 <= begin && begin <= end && end < m))
       
  1453       {  errcode = error(env, CPXERR_INDEX_RANGE);
       
  1454          goto done;
       
  1455       }
       
  1456       if (!lp->stat)
       
  1457       {  errcode = error(env, CPXERR_NO_SOLN);
       
  1458          goto done;
       
  1459       }
       
  1460       errcode = 0;
       
  1461       if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
       
  1462       {  if (slack != NULL)
       
  1463          {  for (i = begin; i <= end; i++)
       
  1464             {  type = glp_get_row_type(lp->prob, i+1);
       
  1465                temp = glp_get_row_prim(lp->prob, i+1);
       
  1466                if (lp->rflag[i] == RF_NOT_RANGED)
       
  1467                {  if (type == GLP_LO || type == GLP_FX)
       
  1468                      slack[i-begin] =
       
  1469                         glp_get_row_lb(lp->prob, i+1) - temp;
       
  1470                   else if (type == GLP_UP)
       
  1471                      slack[i-begin] =
       
  1472                         glp_get_row_ub(lp->prob, i+1) - temp;
       
  1473                   else
       
  1474                      xassert(type != type);
       
  1475                }
       
  1476                else if (lp->rflag[i] == RF_RANGED_POS)
       
  1477                {  xassert(type == GLP_DB || type == GLP_FX);
       
  1478                   slack[i-begin] =
       
  1479                      temp - glp_get_row_lb(lp->prob, i+1);
       
  1480                }
       
  1481                else if (lp->rflag[i] == RF_RANGED_NEG)
       
  1482                {  xassert(type == GLP_DB);
       
  1483                   slack[i-begin] =
       
  1484                      temp - glp_get_row_ub(lp->prob, i+1);
       
  1485                }
       
  1486                else
       
  1487                   xassert(lp != lp);
       
  1488             }
       
  1489          }
       
  1490       }
       
  1491       else
       
  1492          xassert(lp != lp);
       
  1493 done: return errcode;
       
  1494 }
       
  1495 
       
  1496 int CPXgetstat(CPXENV *env, CPXLP *lp)
       
  1497 {     int stat;
       
  1498       if (checklp(env, lp))
       
  1499          stat = 0;
       
  1500       else
       
  1501          stat = lp->stat;
       
  1502       return stat;
       
  1503 }
       
  1504 
       
  1505 int CPXgetub(CPXENV *env, CPXLP *lp, double ub[], int begin, int end)
       
  1506 {     xassert(env == env);
       
  1507       xassert(lp == lp);
       
  1508       xassert(ub == ub);
       
  1509       xassert(begin == begin);
       
  1510       xassert(end == end);
       
  1511       xprintf("CPXgetub: not implemented yet\n");
       
  1512       exit(EXIT_FAILURE);
       
  1513       return -1;
       
  1514 }
       
  1515 
       
  1516 int CPXgetweight(CPXENV *env, CPXLP *lp, int rcnt, const int rmatbeg[],
       
  1517       const int rmatind[], const double rmatval[], double weight[],
       
  1518       int dpriind)
       
  1519 {     xassert(env == env);
       
  1520       xassert(lp == lp);
       
  1521       xassert(rcnt == rcnt);
       
  1522       xassert(rmatbeg == rmatbeg);
       
  1523       xassert(rmatind == rmatind);
       
  1524       xassert(rmatval == rmatval);
       
  1525       xassert(weight == weight);
       
  1526       xassert(dpriind == dpriind);
       
  1527       xprintf("CPXgetweight: not implemented yet\n");
       
  1528       exit(EXIT_FAILURE);
       
  1529       return -1;
       
  1530 }
       
  1531 
       
  1532 int CPXgetx(CPXENV *env, CPXLP *lp, double x[], int begin, int end)
       
  1533 {     int j, n, errcode;
       
  1534       errcode = checklp(env, lp);
       
  1535       if (errcode) goto done;
       
  1536       n = glp_get_num_cols(lp->prob);
       
  1537       if (!(0 <= begin && begin <= end && end < n))
       
  1538       {  errcode = error(env, CPXERR_INDEX_RANGE);
       
  1539          goto done;
       
  1540       }
       
  1541       if (!lp->stat)
       
  1542       {  errcode = error(env, CPXERR_NO_SOLN);
       
  1543          goto done;
       
  1544       }
       
  1545       errcode = 0;
       
  1546       if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
       
  1547       {  if (x != NULL)
       
  1548          {  for (j = begin; j <= end; j++)
       
  1549                x[j-begin] = glp_get_col_prim(lp->prob, j+1);
       
  1550          }
       
  1551       }
       
  1552       else
       
  1553          xassert(lp != lp);
       
  1554 done: return errcode;
       
  1555 }
       
  1556 
       
  1557 int CPXinfodblparam(CPXENV *env, int whichparam, double *defvalue,
       
  1558       double *minvalue, double *maxvalue)
       
  1559 {     int k, errcode;
       
  1560       errcode = checkenv(env);
       
  1561       if (errcode) goto done;
       
  1562       k = finddblparam(whichparam);
       
  1563       if (k < 0)
       
  1564       {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
       
  1565          goto done;
       
  1566       }
       
  1567       errcode = 0;
       
  1568       if (defvalue != NULL)
       
  1569          *defvalue = dblparam[k].defv;
       
  1570       if (minvalue != NULL)
       
  1571          *minvalue = dblparam[k].minv;
       
  1572       if (maxvalue != NULL)
       
  1573          *maxvalue = dblparam[k].maxv;
       
  1574 done: return errcode;
       
  1575 }
       
  1576 
       
  1577 int CPXinfointparam(CPXENV *env, int whichparam, int *defvalue,
       
  1578       int *minvalue, int *maxvalue)
       
  1579 {     int k, errcode;
       
  1580       errcode = checkenv(env);
       
  1581       if (errcode) goto done;
       
  1582       k = findintparam(whichparam);
       
  1583       if (k < 0)
       
  1584       {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
       
  1585          goto done;
       
  1586       }
       
  1587       errcode = 0;
       
  1588       if (defvalue != NULL)
       
  1589          *defvalue = intparam[k].defv;
       
  1590       if (minvalue != NULL)
       
  1591          *minvalue = intparam[k].minv;
       
  1592       if (maxvalue != NULL)
       
  1593          *maxvalue = intparam[k].maxv;
       
  1594 done: return errcode;
       
  1595 }
       
  1596 
       
  1597 int CPXmdleave(const CPXENV *env, CPXLP *lp, const int goodlist[],
       
  1598       int goodlen, double downratio[], double upratio[])
       
  1599 {     int k;
       
  1600       xassert(env == env);
       
  1601       xassert(lp == lp);
       
  1602       xassert(goodlist == goodlist);
       
  1603       xassert(goodlen >= 0);
       
  1604       xassert(downratio != NULL);
       
  1605       xassert(upratio != NULL);
       
  1606       /* not implemented yet */
       
  1607       for (k = 0; k < goodlen; k++)
       
  1608          downratio[k] = upratio[k] = 0.0;
       
  1609       return 0;
       
  1610 }
       
  1611 
       
  1612 int CPXnewcols(CPXENV *env, CPXLP *lp, int ccnt, const double obj[],
       
  1613       const double lb[], const double ub[], const char ctype[],
       
  1614       char *colname[])
       
  1615 {     int j, n, kind, type, errcode;
       
  1616       double lbnd, ubnd;
       
  1617       errcode = checklp(env, lp);
       
  1618       if (errcode) goto done;
       
  1619       if (ccnt < 0)
       
  1620       {  errcode = error(env, CPXERR_BAD_ARGUMENT);
       
  1621          goto done;
       
  1622       }
       
  1623       for (j = 0; j < ccnt; j++)
       
  1624       {  if (ctype != NULL)
       
  1625          {  if (!(ctype[j] == 'C' || ctype[j] == 'B' ||
       
  1626                   ctype[j] == 'I'))
       
  1627             {  errcode = error(env, CPXERR_BAD_CTYPE, j);
       
  1628                goto done;
       
  1629             }
       
  1630          }
       
  1631          if (colname != NULL)
       
  1632          {  if (colname[j] == NULL)
       
  1633             {  errcode = error(env, CPXERR_NULL_NAME, j);
       
  1634                goto done;
       
  1635             }
       
  1636          }
       
  1637       }
       
  1638       errcode = 0;
       
  1639       invalidate(lp);
       
  1640       n = glp_get_num_cols(lp->prob);
       
  1641       if (ccnt > 0)
       
  1642          glp_add_cols(lp->prob, ccnt);
       
  1643       for (j = 0; j < ccnt; j++)
       
  1644       {  if (colname != NULL)
       
  1645             glp_set_col_name(lp->prob, n+j+1, colname[j]);
       
  1646          if (obj != NULL)
       
  1647             glp_set_obj_coef(lp->prob, n+j+1, obj[j]);
       
  1648          lbnd = (lb == NULL ? 0.0 : lb[j]);
       
  1649          ubnd = (ub == NULL ? 0.0 : ub[j]);
       
  1650          if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
       
  1651             type = GLP_FR;
       
  1652          else if (ubnd >= +CPX_INFBOUND)
       
  1653             type = GLP_LO;
       
  1654          else if (lbnd <= -CPX_INFBOUND)
       
  1655             type = GLP_UP;
       
  1656          else if (lbnd != ubnd)
       
  1657             type = GLP_DB;
       
  1658          else
       
  1659             type = GLP_FX;
       
  1660          glp_set_col_bnds(lp->prob, n+j+1, type, lbnd, ubnd);
       
  1661          if (ctype != NULL)
       
  1662          {  if (ctype[j] == 'C')
       
  1663                kind = GLP_CV;
       
  1664             else if (ctype[j] == 'B')
       
  1665                kind = GLP_BV;
       
  1666             else if (ctype[j] == 'I')
       
  1667                kind = GLP_IV;
       
  1668             else
       
  1669                xassert(ctype != ctype);
       
  1670             glp_set_col_kind(lp->prob, n+j+1, kind);
       
  1671          }
       
  1672       }
       
  1673 done: return errcode;
       
  1674 }
       
  1675 
       
  1676 int CPXnewrows(CPXENV *env, CPXLP *lp, int rcnt, const double rhs[],
       
  1677       const char sense[], const double rngval[], char *rowname[])
       
  1678 {     int i, m, type, errcode;
       
  1679       double lbnd, ubnd;
       
  1680       errcode = checklp(env, lp);
       
  1681       if (errcode) goto done;
       
  1682       if (rcnt < 0)
       
  1683       {  errcode = error(env, CPXERR_BAD_ARGUMENT);
       
  1684          goto done;
       
  1685       }
       
  1686       for (i = 0; i < rcnt; i++)
       
  1687       {  if (sense != NULL)
       
  1688          {  if (!(sense[i] == 'L' || sense[i] == 'E' ||
       
  1689                   sense[i] == 'G' || sense[i] == 'R'))
       
  1690             {  errcode = error(env, CPXERR_BAD_SENSE, i);
       
  1691                goto done;
       
  1692             }
       
  1693          }
       
  1694          if (rowname != NULL)
       
  1695          {  if (rowname[i] == NULL)
       
  1696             {  errcode = error(env, CPXERR_NULL_NAME, i);
       
  1697                goto done;
       
  1698             }
       
  1699          }
       
  1700       }
       
  1701       errcode = 0;
       
  1702       invalidate(lp);
       
  1703       m = glp_get_num_rows(lp->prob);
       
  1704       if (rcnt > 0)
       
  1705          glp_add_rows(lp->prob, rcnt);
       
  1706       enlargerflag(lp);
       
  1707       for (i = 0; i < rcnt; i++)
       
  1708       {  if (rowname != NULL)
       
  1709             glp_set_row_name(lp->prob, m+i+1, rowname[i]);
       
  1710          lbnd = ubnd = (rhs == NULL ? 0.0 : rhs[i]);
       
  1711          if (sense == NULL || sense[i] == 'E')
       
  1712          {  lp->rflag[m+i] = RF_NOT_RANGED;
       
  1713             type = GLP_FX;
       
  1714          }
       
  1715          else if (sense[i] == 'L')
       
  1716          {  lp->rflag[m+i] = RF_NOT_RANGED;
       
  1717             type = GLP_UP;
       
  1718          }
       
  1719          else if (sense[i] == 'G')
       
  1720          {  lp->rflag[m+i] = RF_NOT_RANGED;
       
  1721             type = GLP_LO;
       
  1722          }
       
  1723          else if (sense[i] == 'R')
       
  1724          {  if (rngval == NULL || rngval[i] == 0.0)
       
  1725             {  lp->rflag[m+i] = RF_RANGED_POS;
       
  1726                type = GLP_FX;
       
  1727             }
       
  1728             else if (rngval[i] > 0.0)
       
  1729             {  lp->rflag[m+i] = RF_RANGED_POS;
       
  1730                type = GLP_DB;
       
  1731                ubnd += rngval[i];
       
  1732             }
       
  1733             else /* rngval[i] < 0.0 */
       
  1734             {  lp->rflag[m+i] = RF_RANGED_NEG;
       
  1735                type = GLP_DB;
       
  1736                lbnd += rngval[i];
       
  1737             }
       
  1738          }
       
  1739          else
       
  1740             xassert(sense != sense);
       
  1741          glp_set_row_bnds(lp->prob, m+i+1, type, lbnd, ubnd);
       
  1742       }
       
  1743 done: return errcode;
       
  1744 }
       
  1745 
       
  1746 CPXENV *CPXopenCPLEX(int *status)
       
  1747 {     CPXENV *env;
       
  1748       int k, card;
       
  1749       env = xmalloc(sizeof(CPXENV));
       
  1750       env->list = NULL;
       
  1751       card = sizeof(intparam) / sizeof(struct intparam);
       
  1752       env->intparam = xcalloc(card, sizeof(int));
       
  1753       for (k = 0; k < card; k++)
       
  1754          env->intparam[k] = intparam[k].defv;
       
  1755       card = sizeof(dblparam) / sizeof(struct dblparam);
       
  1756       env->dblparam = xcalloc(card, sizeof(double));
       
  1757       for (k = 0; k < card; k++)
       
  1758          env->dblparam[k] = dblparam[k].defv;
       
  1759       if (status != NULL) *status = 0;
       
  1760       return env;
       
  1761 }
       
  1762 
       
  1763 int CPXpivotin(CPXENV *env, CPXLP *lp, const int rlist[], int rlen)
       
  1764 {     int i, m, errcode;
       
  1765       errcode = checklp(env, lp);
       
  1766       if (errcode) goto done;
       
  1767       if (rlen < 0)
       
  1768       {  errcode = error(env, CPXERR_BAD_ARGUMENT);
       
  1769          goto done;
       
  1770       }
       
  1771       if (rlen > 0 && rlist == NULL)
       
  1772       {  errcode = error(env, CPXERR_NULL_POINTER);
       
  1773          goto done;
       
  1774       }
       
  1775       m = glp_get_num_rows(lp->prob);
       
  1776       for (i = 0; i < rlen; i++)
       
  1777       {  if (!(0 <= rlist[i] && rlist[i] < m))
       
  1778          {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, i);
       
  1779             goto done;
       
  1780          }
       
  1781       }
       
  1782       errcode = 0;
       
  1783       for (i = 0; i < rlen; i++)
       
  1784       {  if (glp_get_row_type(lp->prob, rlist[i]+1) != GLP_FX)
       
  1785          {  if (glp_get_row_stat(lp->prob, rlist[i]+1) != GLP_BS)
       
  1786             {  /* not implemented yet */
       
  1787                break;
       
  1788             }
       
  1789          }
       
  1790       }
       
  1791 done: return errcode;
       
  1792 }
       
  1793 
       
  1794 int CPXpivotout(CPXENV *env, CPXLP *lp, const int clist[], int clen)
       
  1795 {     int j, n, errcode;
       
  1796       errcode = checklp(env, lp);
       
  1797       if (errcode) goto done;
       
  1798       if (clen < 0)
       
  1799       {  errcode = error(env, CPXERR_BAD_ARGUMENT);
       
  1800          goto done;
       
  1801       }
       
  1802       if (clen > 0 && clist == NULL)
       
  1803       {  errcode = error(env, CPXERR_NULL_POINTER);
       
  1804          goto done;
       
  1805       }
       
  1806       n = glp_get_num_cols(lp->prob);
       
  1807       for (j = 0; j < clen; j++)
       
  1808       {  if (!(0 <= clist[j] && clist[j] < n))
       
  1809          {  errcode = error(env, CPXERR_COL_INDEX_RANGE, j);
       
  1810             goto done;
       
  1811          }
       
  1812          if (glp_get_col_type(lp->prob, clist[j]+1) != GLP_FX)
       
  1813          {  errcode = error(env, CPXERR_NOT_FIXED);
       
  1814             goto done;
       
  1815          }
       
  1816       }
       
  1817       errcode = 0;
       
  1818       for (j = 0; j < clen; j++)
       
  1819       {  if (glp_get_col_stat(lp->prob, clist[j]+1) == GLP_BS)
       
  1820          {  /* not implemented yet */
       
  1821             break;
       
  1822          }
       
  1823       }
       
  1824 done: return errcode;
       
  1825 }
       
  1826 
       
  1827 int CPXprimopt(CPXENV *env, CPXLP *lp);
       
  1828 
       
  1829 int CPXsavwrite(CPXENV *env, CPXLP *lp, const char *filename)
       
  1830 {     xassert(env == env);
       
  1831       xassert(lp == lp);
       
  1832       xassert(filename == filename);
       
  1833       xprintf("CPXsavwrite: not implemented yet\n");
       
  1834       exit(EXIT_FAILURE);
       
  1835       return -1;
       
  1836 }
       
  1837 
       
  1838 int CPXsetdblparam(CPXENV *env, int whichparam, double newvalue)
       
  1839 {     int k, errcode;
       
  1840       errcode = checkenv(env);
       
  1841       if (errcode) goto done;
       
  1842       k = finddblparam(whichparam);
       
  1843       if (k < 0)
       
  1844       {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
       
  1845          goto done;
       
  1846       }
       
  1847       if (newvalue < dblparam[k].minv)
       
  1848       {  errcode = error(env, CPXERR_PARAM_TOO_SMALL);
       
  1849          goto done;
       
  1850       }
       
  1851       if (newvalue > dblparam[k].maxv)
       
  1852       {  errcode = error(env, CPXERR_PARAM_TOO_BIG);
       
  1853          goto done;
       
  1854       }
       
  1855       errcode = 0;
       
  1856       env->dblparam[k] = newvalue;
       
  1857 done: return errcode;
       
  1858 }
       
  1859 
       
  1860 int CPXsetintparam(CPXENV *env, int whichparam, int newvalue)
       
  1861 {     int k, errcode;
       
  1862       errcode = checkenv(env);
       
  1863       if (errcode) goto done;
       
  1864       k = findintparam(whichparam);
       
  1865       if (k < 0)
       
  1866       {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
       
  1867          goto done;
       
  1868       }
       
  1869       if (newvalue < intparam[k].minv)
       
  1870       {  errcode = error(env, CPXERR_PARAM_TOO_SMALL);
       
  1871          goto done;
       
  1872       }
       
  1873       if (newvalue > intparam[k].maxv)
       
  1874       {  errcode = error(env, CPXERR_PARAM_TOO_BIG);
       
  1875          goto done;
       
  1876       }
       
  1877       errcode = 0;
       
  1878       env->intparam[k] = newvalue;
       
  1879 done: return errcode;
       
  1880 }
       
  1881 
       
  1882 int CPXsolninfo(CPXENV *env, CPXLP *lp, int *solnmethod, int *solntype,
       
  1883       int *pfeasind, int *dfeasind)
       
  1884 {     int type, pfeas, dfeas, errcode;
       
  1885       errcode = checklp(env, lp);
       
  1886       if (errcode) goto done;
       
  1887       errcode = 0;
       
  1888       if (!lp->stat)
       
  1889          type = CPX_NO_SOLN, pfeas = dfeas = 0;
       
  1890       else if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
       
  1891       {  type = CPX_BASIC_SOLN;
       
  1892          pfeas = (glp_get_prim_stat(lp->prob) == GLP_FEAS);
       
  1893          dfeas = (glp_get_dual_stat(lp->prob) == GLP_FEAS);
       
  1894       }
       
  1895       else
       
  1896          xassert(lp != lp);
       
  1897       if (solnmethod != NULL)
       
  1898          *solnmethod = lp->meth;
       
  1899       if (solntype != NULL)
       
  1900          *solntype = type;
       
  1901       if (pfeasind != NULL)
       
  1902          *pfeasind = pfeas;
       
  1903       if (dfeasind != NULL)
       
  1904          *dfeasind = dfeas;
       
  1905 done: return errcode;
       
  1906 }
       
  1907 
       
  1908 int CPXsolution(CPXENV *env, CPXLP *lp, int *lpstat, double *objval,
       
  1909       double x[], double pi[], double slack[], double dj[])
       
  1910 {     int m, n, errcode;
       
  1911       errcode = checklp(env, lp);
       
  1912       if (errcode) goto done;
       
  1913       if (!lp->stat)
       
  1914       {  errcode = error(env, CPXERR_NO_SOLN);
       
  1915          goto done;
       
  1916       }
       
  1917       errcode = 0;
       
  1918       m = glp_get_num_rows(lp->prob);
       
  1919       n = glp_get_num_cols(lp->prob);
       
  1920       if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
       
  1921       {  if (lpstat != NULL)
       
  1922             *lpstat = CPXgetstat(env, lp);
       
  1923          if (objval != NULL)
       
  1924             xassert(CPXgetobjval(env, lp, objval) == 0);
       
  1925          if (x != NULL)
       
  1926             xassert(CPXgetx(env, lp, x, 0, n-1) == 0);
       
  1927          if (pi != NULL)
       
  1928             xassert(CPXgetpi(env, lp, pi, 0, m-1) == 0);
       
  1929          if (slack != NULL)
       
  1930             xassert(CPXgetslack(env, lp, slack, 0, m-1) == 0);
       
  1931          if (dj != NULL)
       
  1932             xassert(CPXgetdj(env, lp, dj, 0, n-1) == 0);
       
  1933       }
       
  1934       else
       
  1935          xassert(lp != lp);
       
  1936 done: return errcode;
       
  1937 }
       
  1938 
       
  1939 int CPXstrongbranch(CPXENV *env, CPXLP *lp, const int goodlist[],
       
  1940       int goodlen, double downpen[], double uppen[], int itlim)
       
  1941 {     int k;
       
  1942       xassert(env == env);
       
  1943       xassert(lp == lp);
       
  1944       xassert(goodlist == goodlist);
       
  1945       xassert(goodlen >= 0);
       
  1946       xassert(downpen != NULL);
       
  1947       xassert(uppen != NULL);
       
  1948       xassert(itlim == itlim);
       
  1949       /* not implemented yet */
       
  1950       for (k = 0; k < goodlen; k++)
       
  1951          downpen[k] = uppen[k] = 0.0;
       
  1952       return 0;
       
  1953 }
       
  1954 
       
  1955 static int xstrcasecmp(const char *s1, const char *s2)
       
  1956 {     int c1, c2;
       
  1957       for (;;)
       
  1958       {  c1 = toupper((unsigned char)*s1++);
       
  1959          c2 = toupper((unsigned char)*s2++);
       
  1960          if (c1 == '\0' || c1 != c2) break;
       
  1961       }
       
  1962       return c1 - c2;
       
  1963 }
       
  1964 
       
  1965 static void getfiletype(const char *filename, char type[3+1])
       
  1966 {     /* determine filetype from filename */
       
  1967       int beg, end;
       
  1968       beg = end = strlen(filename);
       
  1969       while (beg > 0 && filename[beg-1] != '.' && end - beg < 3)
       
  1970          beg--;
       
  1971       if (beg > 0 && filename[beg-1] == '.' &&
       
  1972           xstrcasecmp(&filename[beg], "gz") == 0)
       
  1973       {  end = --beg;
       
  1974          while (beg > 0 && filename[beg-1] != '.' && end - beg < 3)
       
  1975             beg--;
       
  1976       }
       
  1977       if (beg > 0 && filename[beg-1] == '.')
       
  1978       {  memcpy(type, &filename[beg], end - beg);
       
  1979          type[end - beg] = '\0';
       
  1980       }
       
  1981       else
       
  1982          type[0] = '\0';
       
  1983       return;
       
  1984 }
       
  1985 
       
  1986 int CPXwriteprob(CPXENV *env, CPXLP *lp, const char *filename,
       
  1987       const char *filetype)
       
  1988 {     glp_prob *copy;
       
  1989       int errcode;
       
  1990       char type[3+1];
       
  1991       errcode = checklp(env, lp);
       
  1992       if (errcode) goto done;
       
  1993       if (filename == NULL)
       
  1994       {  errcode = error(env, CPXERR_NO_FILENAME);
       
  1995          goto done;
       
  1996       }
       
  1997       if (filetype == NULL)
       
  1998          getfiletype(filename, type), filetype = type;
       
  1999       if (xstrcasecmp(filetype, "MPS") == 0)
       
  2000       {  glp_term_out(GLP_OFF);
       
  2001          errcode = glp_write_mps(lp->prob, GLP_MPS_FILE, NULL, filename)
       
  2002             ;
       
  2003          glp_term_out(GLP_ON);
       
  2004       }
       
  2005       else if (xstrcasecmp(filetype, "LP") == 0)
       
  2006       {  glp_term_out(GLP_OFF);
       
  2007          errcode = glp_write_lp(lp->prob, NULL, filename);
       
  2008          glp_term_out(GLP_ON);
       
  2009       }
       
  2010       else if (xstrcasecmp(filetype, "RMP") == 0 ||
       
  2011                xstrcasecmp(filetype, "REW") == 0)
       
  2012       {  copy = glp_create_prob();
       
  2013          glp_copy_prob(copy, lp->prob, GLP_OFF);
       
  2014          glp_term_out(GLP_OFF);
       
  2015          errcode = glp_write_mps(copy, GLP_MPS_DECK, NULL, filename);
       
  2016          glp_term_out(GLP_ON);
       
  2017          glp_delete_prob(copy);
       
  2018       }
       
  2019       else if (xstrcasecmp(filetype, "RLP") == 0)
       
  2020       {  copy = glp_create_prob();
       
  2021          glp_copy_prob(copy, lp->prob, GLP_OFF);
       
  2022          glp_term_out(GLP_OFF);
       
  2023          errcode = glp_write_lp(copy, NULL, filename);
       
  2024          glp_term_out(GLP_ON);
       
  2025          glp_delete_prob(copy);
       
  2026       }
       
  2027       else
       
  2028       {  errcode = error(env, CPXERR_BAD_FILETYPE);
       
  2029          goto done;
       
  2030       }
       
  2031       if (errcode)
       
  2032          errcode = error(env, CPXERR_FAIL_OPEN_WRITE, filename);
       
  2033 done: return errcode;
       
  2034 }
       
  2035 
       
  2036 /**********************************************************************/
       
  2037 
       
  2038 static int solvelp(CPXENV *env, CPXLP *lp, int meth)
       
  2039 {     glp_smcp parm;
       
  2040       int errcode;
       
  2041       errcode = checklp(env, lp);
       
  2042       if (errcode) goto done;
       
  2043       errcode = 0;
       
  2044       invalidate(lp);
       
  2045       glp_init_smcp(&parm);
       
  2046       switch (meth)
       
  2047       {  case CPX_ALG_PRIMAL:
       
  2048             parm.meth = GLP_PRIMAL;
       
  2049             break;
       
  2050          case CPX_ALG_DUAL:
       
  2051             parm.meth = GLP_DUAL;
       
  2052             break;
       
  2053          default:
       
  2054             xassert(meth != meth);
       
  2055       }
       
  2056       switch (getintparam(env, CPX_PARAM_SIMDISPLAY))
       
  2057       {  case 0:
       
  2058             parm.msg_lev = GLP_MSG_OFF;
       
  2059             break;
       
  2060          case 1:
       
  2061             parm.msg_lev = GLP_MSG_ALL;
       
  2062             break;
       
  2063          case 2:
       
  2064             parm.msg_lev = GLP_MSG_ALL;
       
  2065             parm.out_frq = 1;
       
  2066             break;
       
  2067          default:
       
  2068             xassert(env != env);
       
  2069       }
       
  2070       xassert(getdblparam == getdblparam);
       
  2071       switch (getintparam(env, CPX_PARAM_ADVIND))
       
  2072       {  case 0:
       
  2073             glp_term_out(GLP_OFF);
       
  2074             glp_adv_basis(lp->prob, 0);
       
  2075             glp_term_out(GLP_ON);
       
  2076             break;
       
  2077          case 1:
       
  2078          case 2:
       
  2079             break;
       
  2080          default:
       
  2081             xassert(env != env);
       
  2082       }
       
  2083       if (!glp_bf_exists(lp->prob))
       
  2084       {  if (glp_factorize(lp->prob) != 0)
       
  2085          {  glp_term_out(GLP_OFF);
       
  2086             glp_adv_basis(lp->prob, 0);
       
  2087             glp_term_out(GLP_ON);
       
  2088             if (glp_factorize(lp->prob) != 0)
       
  2089                glp_std_basis(lp->prob);
       
  2090          }
       
  2091       }
       
  2092       xassert(glp_simplex(lp->prob, &parm) == 0);
       
  2093       switch (glp_get_status(lp->prob))
       
  2094       {  case GLP_OPT:
       
  2095             lp->stat = CPX_STAT_OPTIMAL;
       
  2096             lp->meth = meth;
       
  2097             break;
       
  2098          case GLP_NOFEAS:
       
  2099             lp->stat = CPX_STAT_INFEASIBLE;
       
  2100             lp->meth = meth;
       
  2101             break;
       
  2102          case GLP_UNBND:
       
  2103             lp->stat = CPX_STAT_UNBOUNDED;
       
  2104             lp->meth = meth;
       
  2105             break;
       
  2106          default:
       
  2107             xassert(lp != lp);
       
  2108       }
       
  2109 done: return errcode;
       
  2110 }
       
  2111 
       
  2112 int CPXprimopt(CPXENV *env, CPXLP *lp)
       
  2113 {     int errcode;
       
  2114       errcode = solvelp(env, lp, CPX_ALG_PRIMAL);
       
  2115       return errcode;
       
  2116 }
       
  2117 
       
  2118 int CPXdualopt(CPXENV *env, CPXLP *lp)
       
  2119 {     int errcode;
       
  2120       errcode = solvelp(env, lp, CPX_ALG_DUAL);
       
  2121       return errcode;
       
  2122 }
       
  2123 
       
  2124 int CPXlpopt(CPXENV *env, CPXLP *lp)
       
  2125 {     int errcode;
       
  2126       errcode = solvelp(env, lp, CPX_ALG_PRIMAL);
       
  2127       return errcode;
       
  2128 }
       
  2129 
       
  2130 /* eof */