You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2130 lines
64 KiB

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