examples/cplex/cplex.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
     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 */