COIN-OR::LEMON - Graph Library

source: glpk-cmake/examples/cplex/cplex.c @ 1:c445c931472f

Last change on this file since 1:c445c931472f was 1:c445c931472f, checked in by Alpar Juttner <alpar@…>, 10 years ago

Import glpk-4.45

  • Generated files and doc/notes are removed
File size: 63.8 KB
Line 
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
33struct 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
43struct 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
69struct intparam
70{     int which;
71      int defv;
72      int minv;
73      int maxv;
74};
75
76struct dblparam
77{     int which;
78      double defv;
79      double minv;
80      double maxv;
81};
82
83struct errstring
84{     int code;
85      const char *string;
86};
87
88#define BIGINT 2100000000
89#define BIGDBL 1e75
90
91static 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
108static 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
116static 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
157static 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
165static 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
173static 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
181static 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
189static 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
199static 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
212static 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
221static 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);
227done: return errcode;
228}
229
230static void invalidate(CPXLP *lp)
231{     lp->stat = 0;
232      lp->meth = CPX_ALG_NONE;
233      return;
234}
235
236static 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
254static 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
270int 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      }
357done: return errcode;
358}
359
360int 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      }
475done: return errcode;
476}
477
478int 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
486int 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
496int 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      }
553done: return errcode;
554}
555
556int 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);
710done: return errcode;
711}
712
713void 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);
727done: xassert(errcode == errcode);
728      return;
729}
730
731int 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      }
799done: return errcode;
800}
801
802int 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;
823done: return errcode;
824}
825
826int 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      }
877done: return errcode;
878}
879
880int 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
888int 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
900int 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      }
1063done: return errcode;
1064}
1065
1066CPXLP *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);
1083done: if (status != NULL) *status = errcode;
1084      return lp;
1085}
1086
1087int 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;
1104done: return errcode;
1105}
1106
1107int 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];
1126done: return errcode;
1127}
1128
1129int 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
1138int 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;
1165done: return errcode;
1166}
1167
1168int CPXdualopt(CPXENV *env, CPXLP *lp);
1169
1170int 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;
1198done: return errcode;
1199}
1200
1201int 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      }
1242done: return errcode;
1243}
1244
1245int 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      }
1254done: return errcode;
1255}
1256
1257int 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
1267int 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];
1279done: return errcode;
1280}
1281
1282int 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);
1304done: return errcode;
1305}
1306
1307char *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
1318int 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
1328int 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];
1340done: return errcode;
1341}
1342
1343int 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
1354int 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
1363int 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
1372int 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
1381int 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
1390int 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);
1405done: return errcode;
1406}
1407
1408int 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);
1430done: return errcode;
1431}
1432
1433int 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
1445int 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);
1493done: return errcode;
1494}
1495
1496int 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
1505int 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
1516int 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
1532int 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);
1554done: return errcode;
1555}
1556
1557int 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;
1574done: return errcode;
1575}
1576
1577int 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;
1594done: return errcode;
1595}
1596
1597int 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
1612int 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      }
1673done: return errcode;
1674}
1675
1676int 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      }
1743done: return errcode;
1744}
1745
1746CPXENV *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
1763int 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      }
1791done: return errcode;
1792}
1793
1794int 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      }
1824done: return errcode;
1825}
1826
1827int CPXprimopt(CPXENV *env, CPXLP *lp);
1828
1829int 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
1838int 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;
1857done: return errcode;
1858}
1859
1860int 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;
1879done: return errcode;
1880}
1881
1882int 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;
1905done: return errcode;
1906}
1907
1908int 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);
1936done: return errcode;
1937}
1938
1939int 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
1955static 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
1965static 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
1986int 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);
2033done: return errcode;
2034}
2035
2036/**********************************************************************/
2037
2038static 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      }
2109done: return errcode;
2110}
2111
2112int CPXprimopt(CPXENV *env, CPXLP *lp)
2113{     int errcode;
2114      errcode = solvelp(env, lp, CPX_ALG_PRIMAL);
2115      return errcode;
2116}
2117
2118int CPXdualopt(CPXENV *env, CPXLP *lp)
2119{     int errcode;
2120      errcode = solvelp(env, lp, CPX_ALG_DUAL);
2121      return errcode;
2122}
2123
2124int CPXlpopt(CPXENV *env, CPXLP *lp)
2125{     int errcode;
2126      errcode = solvelp(env, lp, CPX_ALG_PRIMAL);
2127      return errcode;
2128}
2129
2130/* eof */
Note: See TracBrowser for help on using the repository browser.