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