Control: retitle python-cvxopt: glpk component doesn't work anymore Control: severity -1 important Control: tags -1 -moreinfo +confirmed +fixed-upstream +patch
I traced back the problem to release 4.53 of glpk [1], in February 2014. According to policy 8.6.2, there should have been a SONAME bump to 37 in order to have a smooth transition. Anyway, looking at the upstream source, references to lpx_create_prob have been changed to glp_create_prob in version 1.1.7 [2], but the commit is not atomic and in fact huge. Attached is a patch that replaces glpk-4.49.diff. It upgrades src/C/glpk.c and only that from version 1.1.4 to version 1.1.7, from upstream. It sure resolves the import, but I don't know how to properly test it. Julien: Can you provide a small test? [1] https://anonscm.debian.org/cgit/debian-science/packages/glpk.git/commit/?id=3f635b63468815873c9c33dd497dea8240d607fa [2] commit f3ca94fb997979a54b913f95b816132f7fd44820 on https://github.com/cvxopt/cvxopt/ -- Nirgal
Description: Bring glpk component to version 1.1.7 glpk ABI has changed and some symbols are no longer available. . That patch is the complete diff between version 1.1.4 and 1.1.7, but limited to the src/C/glpk.c file. Author: Martin Andersen <martin.skovgaard.ander...@gmail.com> Origin: upstream Bug-Debian: https://bugs.debian.org/780251 Forwarded: not-needed Reviewed-By: Jean-Michel Nirgal Vourgère <jmv_...@nirgal.com> Last-Update: 2015-03-11 Index: cvxopt-1.1.4/src/C/glpk.c =================================================================== --- cvxopt-1.1.4.orig/src/C/glpk.c +++ cvxopt-1.1.4/src/C/glpk.c @@ -1,8 +1,9 @@ /* + * Copyright 2012-2014 M. Andersen and L. Vandenberghe. * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * - * This file is part of CVXOPT version 1.1.4. + * This file is part of CVXOPT version 1.1.7. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,76 +21,36 @@ #include "cvxopt.h" #include "misc.h" -#include "glpk.h" +#include <glpk.h> +#include <float.h> +#include <limits.h> PyDoc_STRVAR(glpk__doc__, "Interface to the simplex and mixed integer LP algorithms in GLPK.\n\n" "The GLPK control parameters have the default values listed in \n" - "the GLPK documentation, except for 'LPX_K_PRESOL', which is set\n" - "to 1 and cannot be modified. The other parameters can be\n" - "modified by making an entry in the dictionary glpk.options.\n" - "For example, the command glpk.options['LPX_K_MSGLEV'] = 0 turns\n" - "off the printed output during execution of glpk.simplex().\n" - "See the documentation at www.gnu.org/software/glpk/glpk.html for\n" - "the list of GLPK control parameters and their default values."); + "the GLPK documentation (section 2.8.1 for the simplex solver and \n" + "section 2.10.5 for the MILP solver). The control parameters can \n" + "be modified by making an entry in the dictionary glpk.options.\n" + "For example, glpk.options['msg_lev'] = 'GLP_MSG_OFF' turns off the \n" + "printed output will be turned off during execution of glpk.lp().\n" + "Setting glpk.options['it_lim'] = 10 sets the simplex iteration \n" + "limit to 10. Unrecognized entries in glpk.options are ignored."); static PyObject *glpk_module; -typedef struct { - char name[20]; - int idx; - char type; -} param_tuple; - -static const param_tuple GLPK_PARAM_LIST[] = { - {"LPX_K_MSGLEV", LPX_K_MSGLEV, 'i'}, - {"LPX_K_SCALE", LPX_K_SCALE, 'i'}, - {"LPX_K_DUAL", LPX_K_DUAL, 'i'}, - {"LPX_K_PRICE", LPX_K_PRICE, 'i'}, - {"LPX_K_RELAX", LPX_K_RELAX, 'f'}, - {"LPX_K_TOLBND", LPX_K_TOLBND, 'f'}, - {"LPX_K_TOLDJ", LPX_K_TOLDJ, 'f'}, - {"LPX_K_TOLPIV", LPX_K_TOLPIV, 'f'}, - {"LPX_K_ROUND", LPX_K_ROUND, 'i'}, - {"LPX_K_OBJLL", LPX_K_OBJLL, 'f'}, - {"LPX_K_OBJUL", LPX_K_OBJUL, 'f'}, - {"LPX_K_ITLIM", LPX_K_ITLIM, 'i'}, - {"LPX_K_ITCNT", LPX_K_ITCNT, 'i'}, - {"LPX_K_TMLIM", LPX_K_TMLIM, 'f'}, - {"LPX_K_OUTFRQ", LPX_K_OUTFRQ, 'i'}, - {"LPX_K_OUTDLY", LPX_K_OUTDLY, 'f'}, - {"LPX_K_BRANCH", LPX_K_BRANCH, 'i'}, - {"LPX_K_BTRACK", LPX_K_BTRACK, 'i'}, - {"LPX_K_TOLINT", LPX_K_TOLINT, 'f'}, - {"LPX_K_TOLOBJ", LPX_K_TOLOBJ, 'f'}, - {"LPX_K_MPSINFO", LPX_K_MPSINFO, 'i'}, - {"LPX_K_MPSOBJ", LPX_K_MPSOBJ, 'i'}, - {"LPX_K_MPSORIG", LPX_K_MPSORIG, 'i'}, - {"LPX_K_MPSWIDE", LPX_K_MPSWIDE, 'i'}, - {"LPX_K_MPSFREE", LPX_K_MPSFREE, 'i'}, - {"LPX_K_MPSSKIP", LPX_K_MPSSKIP, 'i'}, - {"LPX_K_LPTORIG", LPX_K_LPTORIG, 'i'}, - {"LPX_K_PRESOL", LPX_K_PRESOL, 'i'}, -}; /* 28 paramaters */ - - #if PY_MAJOR_VERSION >= 3 -static int get_param_idx(const char *str, int *idx, char *type) -#else -static int get_param_idx(char *str, int *idx, char *type) +#define PYINT_CHECK(value) PyLong_Check(value) +#define PYINT_AS_LONG(value) PyLong_AS_LONG(value) +#define PYSTRING_FROMSTRING(str) PyUnicode_FromString(str) +#define PYSTRING_CHECK(a) PyUnicode_Check(a) +#define PYSTRING_COMPARE(a,b) PyUnicode_CompareWithASCIIString(a, b) +#else +#define PYINT_CHECK(value) PyInt_Check(value) +#define PYINT_AS_LONG(value) PyInt_AS_LONG(value) +#define PYSTRING_FROMSTRING(str) PyString_FromString(str) +#define PYSTRING_CHECK(a) PyString_Check(a) +#define PYSTRING_COMPARE(a,b) strcmp(PyString_AsString(a), b) #endif -{ - int i; - - for (i=0; i<28; i++) { - if (!strcmp(GLPK_PARAM_LIST[i].name, str)) { - *idx = GLPK_PARAM_LIST[i].idx; - *type = GLPK_PARAM_LIST[i].type; - return 1; - } - } - return 0; -} static char doc_simplex[] = @@ -97,13 +58,13 @@ static char doc_simplex[] = "(status, x, z, y) = lp(c, G, h, A, b)\n" "(status, x, z) = lp(c, G, h)\n\n" "PURPOSE\n" - "(status, x, z, y) = lp(c, G, h, A, b) solves the pair\n" - "of primal and dual LPs\n\n" + "(status, x, z, y) = lp(c, G, h, A, b) solves the pair of primal and\n" + "dual LPs\n\n" " minimize c'*x maximize -h'*z + b'*y\n" " subject to G*x <= h subject to G'*z + A'*y + c = 0\n" " A*x = b z >= 0.\n\n" - "(status, x, z) = lp(c, G, h) solves the pair of primal\n" - "and dual LPs\n\n" + "(status, x, z) = lp(c, G, h) solves the pair of primal and dual LPs" + "\n\n" " minimize c'*x maximize -h'*z \n" " subject to G*x <= h subject to G'*z + c = 0\n" " z >= 0.\n\n" @@ -112,7 +73,7 @@ static char doc_simplex[] = "G mxn dense or sparse 'd' matrix with m>=1\n\n" "h mx1 dense 'd' matrix\n\n" "A pxn dense or sparse 'd' matrix with p>=0\n\n" - "b px1 dnese 'd' matrix\n\n" + "b px1 dense 'd' matrix\n\n" "status 'optimal', 'primal infeasible', 'dual infeasible' \n" " or 'unknown'\n\n" "x if status is 'optimal', a primal optimal solution;\n" @@ -121,21 +82,15 @@ static char doc_simplex[] = " None otherwise"; -static PyObject *simplex(PyObject *self, PyObject *args, - PyObject *kwrds) +static PyObject *simplex(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *c, *h, *b=NULL, *x=NULL, *z=NULL, *y=NULL; PyObject *G, *A=NULL, *t=NULL, *param, *key, *value; - LPX *lp; - int m, n, p, i, j, k, nnz, nnzmax, *rn=NULL, *cn=NULL, param_id; + glp_prob *lp; + glp_smcp smcp; + int m, n, p, i, j, k, nnz, nnzmax, *rn=NULL, *cn=NULL; int_t pos=0; double *a=NULL, val; - char param_type, err_str[100]; -#if PY_MAJOR_VERSION >= 3 - const char *keystr; -#else - char *keystr; -#endif char *kwlist[] = {"c", "G", "h", "A", "b", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|OO", kwlist, &c, @@ -182,18 +137,18 @@ static PyObject *simplex(PyObject *self, return NULL; } - lp = lpx_create_prob(); - lpx_add_rows(lp, m+p); - lpx_add_cols(lp, n); + lp = glp_create_prob(); + glp_add_rows(lp, m+p); + glp_add_cols(lp, n); for (i=0; i<n; i++){ - lpx_set_obj_coef(lp, i+1, MAT_BUFD(c)[i]); - lpx_set_col_bnds(lp, i+1, LPX_FR, 0.0, 0.0); + glp_set_obj_coef(lp, i+1, MAT_BUFD(c)[i]); + glp_set_col_bnds(lp, i+1, GLP_FR, 0.0, 0.0); } for (i=0; i<m; i++) - lpx_set_row_bnds(lp, i+1, LPX_UP, 0.0, MAT_BUFD(h)[i]); + glp_set_row_bnds(lp, i+1, GLP_UP, 0.0, MAT_BUFD(h)[i]); for (i=0; i<p; i++) - lpx_set_row_bnds(lp, i+m+1, LPX_FX, MAT_BUFD(b)[i], + glp_set_row_bnds(lp, i+m+1, GLP_FX, MAT_BUFD(b)[i], MAT_BUFD(b)[i]); nnzmax = (SpMatrix_Check(G) ? SP_NNZ(G) : m*n ) + @@ -202,7 +157,8 @@ static PyObject *simplex(PyObject *self, rn = (int *) calloc(nnzmax+1, sizeof(int)); cn = (int *) calloc(nnzmax+1, sizeof(int)); if (!a || !rn || !cn){ - free(a); free(rn); free(cn); lpx_delete_prob(lp); + free(a); free(rn); free(cn); + glp_delete_prob(lp); return PyErr_NoMemory(); } @@ -241,153 +197,229 @@ static PyObject *simplex(PyObject *self, nnz++; } - lpx_load_matrix(lp, nnz, rn, cn, a); + glp_load_matrix(lp, nnz, rn, cn, a); free(rn); free(cn); free(a); if (!(t = PyTuple_New(A ? 4 : 3))){ - lpx_delete_prob(lp); + glp_delete_prob(lp); return PyErr_NoMemory(); } if (!(param = PyObject_GetAttrString(glpk_module, "options")) || !PyDict_Check(param)){ - lpx_delete_prob(lp); + glp_delete_prob(lp); PyErr_SetString(PyExc_AttributeError, "missing glpk.options dictionary"); return NULL; } + glp_init_smcp(&smcp); + while (PyDict_Next(param, &pos, &key, &value)) -#if PY_MAJOR_VERSION >= 3 - if ((PyUnicode_Check(key)) && - get_param_idx(_PyUnicode_AsString(key), ¶m_id, - ¶m_type)){ - keystr = _PyUnicode_AsString(key); -#else - if ((keystr = PyString_AsString(key)) && get_param_idx(keystr, - ¶m_id, ¶m_type)){ -#endif - if (param_type == 'i'){ -#if PY_MAJOR_VERSION >= 3 - if (!PyLong_Check(value)){ -#else - if (!PyInt_Check(value)){ -#endif - sprintf(err_str, "invalid value for integer " - "GLPK parameter: %-.20s", keystr); - PyErr_SetString(PyExc_ValueError, err_str); - lpx_delete_prob(lp); - Py_DECREF(param); - return NULL; - } - if (!strcmp("LPX_K_PRESOL", keystr) && -#if PY_MAJOR_VERSION >= 3 - PyLong_AS_LONG(value) != 1){ -#else - PyInt_AS_LONG(value) != 1){ -#endif - PyErr_Warn(PyExc_UserWarning, "ignoring value of " - "GLPK parameter 'LPX_K_PRESOL'"); + if (PYSTRING_CHECK(key)){ + if (!PYSTRING_COMPARE(key, "msg_lev")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_MSG_OFF")) + smcp.msg_lev = GLP_MSG_OFF; + else if (!PYSTRING_COMPARE(value, "GLP_MSG_ERR")) + smcp.msg_lev = GLP_MSG_ERR; + else if (!PYSTRING_COMPARE(value, "GLP_MSG_ON")) + smcp.msg_lev = GLP_MSG_ON; + else if (!PYSTRING_COMPARE(value, "GLP_MSG_ALL")) + smcp.msg_lev = GLP_MSG_ALL; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['msg_lev'] with default value", + 1); } - else lpx_set_int_parm(lp, param_id, -#if PY_MAJOR_VERSION >= 3 - PyLong_AS_LONG(value)); -#else - PyInt_AS_LONG(value)); -#endif - } - else { -#if PY_MAJOR_VERSION >= 3 - if (!PyLong_Check(value) && !PyFloat_Check(value)){ -#else - if (!PyInt_Check(value) && !PyFloat_Check(value)){ -#endif - sprintf(err_str, "invalid value for floating point " - "GLPK parameter: %-.20s", keystr); - PyErr_SetString(PyExc_ValueError, err_str); - lpx_delete_prob(lp); - Py_DECREF(param); - return NULL; - } - lpx_set_real_parm(lp, param_id, - PyFloat_AsDouble(value)); - } - } - lpx_set_int_parm(lp, LPX_K_PRESOL, 1); - Py_DECREF(param); - - switch (lpx_simplex(lp)){ - - case LPX_E_OK: - - x = (matrix *) Matrix_New(n,1,DOUBLE); - z = (matrix *) Matrix_New(m,1,DOUBLE); - if (A) y = (matrix *) Matrix_New(p,1,DOUBLE); - if (!x || !z || (A && !y)){ - Py_XDECREF(x); - Py_XDECREF(z); - Py_XDECREF(y); - Py_XDECREF(t); - lpx_delete_prob(lp); - return PyErr_NoMemory(); + else + PyErr_WarnEx(NULL, "replacing glpk.options['msg_lev'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "meth")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_PRIMAL")) + smcp.meth = GLP_PRIMAL; + else if (!PYSTRING_COMPARE(value, "GLP_DUAL")) + smcp.meth = GLP_DUAL; + else if (!PYSTRING_COMPARE(value, "GLP_DUALP")) + smcp.meth = GLP_DUALP; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['meth'] with default value", 1); + } + else + PyErr_WarnEx(NULL, "replacing glpk.options['meth'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "pricing")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_PT_STD")) + smcp.pricing = GLP_PT_STD; + else if (!PYSTRING_COMPARE(value, "GLP_PT_PSE")) + smcp.pricing = GLP_PT_PSE; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['pricing'] with default value", + 1); + } + else + PyErr_WarnEx(NULL, "replacing glpk.options['pricing'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "r_test")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_RT_STD")) + smcp.r_test = GLP_RT_STD; + else if (!PYSTRING_COMPARE(value, "GLP_RT_HAR")) + smcp.r_test = GLP_RT_HAR; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['r_test'] with default value", + 1); + } + else + PyErr_WarnEx(NULL, "replacing glpk.options['r_test'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "tol_bnd")) + if (PyFloat_Check(value)) + smcp.tol_bnd = PyFloat_AsDouble(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['tol_bnd'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "tol_dj")) + if (PyFloat_Check(value)) + smcp.tol_dj = PyFloat_AsDouble(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['tol_dj'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "tol_piv")) + if (PyFloat_Check(value)) + smcp.tol_piv = PyFloat_AsDouble(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['tol_piv'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "obj_ll")) + if (PyFloat_Check(value)) + smcp.obj_ll = PyFloat_AsDouble(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['obj_ll'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "obj_ul")) + if (PyFloat_Check(value)) + smcp.obj_ul = PyFloat_AsDouble(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['obj_ul'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "it_lim")) + if (PYINT_CHECK(value)) + smcp.it_lim = PYINT_AS_LONG(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['it_lim'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "tm_lim")) + if (PYINT_CHECK(value)) + smcp.tm_lim = PYINT_AS_LONG(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['tm_lim'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "out_frq")) + if (PYINT_CHECK(value)) + smcp.out_frq = PYINT_AS_LONG(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['out_frq'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "out_dly")) + if (PYINT_CHECK(value)) + smcp.out_dly = PYINT_AS_LONG(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['out_dly'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "presolve")){ + if (PYSTRING_CHECK(value)) { + if (!PYSTRING_COMPARE(value, "GLP_ON")) + smcp.presolve = GLP_ON; + else if (!PYSTRING_COMPARE(value, "GLP_OFF")) + smcp.presolve = GLP_OFF; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['presolve'] with default value", + 1); + } + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['presolve'] with default value", 1); } + } - PyTuple_SET_ITEM(t, 0, (PyObject *) -#if PY_MAJOR_VERSION >= 3 - PyUnicode_FromString("optimal")); -#else - PyString_FromString("optimal")); -#endif - - for (i=0; i<n; i++) - MAT_BUFD(x)[i] = lpx_get_col_prim(lp, i+1); - PyTuple_SET_ITEM(t, 1, (PyObject *) x); + Py_DECREF(param); - for (i=0; i<m; i++) - MAT_BUFD(z)[i] = -lpx_get_row_dual(lp, i+1); - PyTuple_SET_ITEM(t, 2, (PyObject *) z); + switch (glp_simplex(lp, &smcp)){ - if (A){ - for (i=0; i<p; i++) - MAT_BUFD(y)[i] = -lpx_get_row_dual(lp, m+i+1); - PyTuple_SET_ITEM(t, 3, (PyObject *) y); + case 0: + switch(glp_get_status(lp)){ + case GLP_OPT: + x = (matrix *) Matrix_New(n,1,DOUBLE); + z = (matrix *) Matrix_New(m,1,DOUBLE); + if (A) y = (matrix *) Matrix_New(p,1,DOUBLE); + if (!x || !z || (A && !y)){ + Py_XDECREF(x); + Py_XDECREF(z); + Py_XDECREF(y); + Py_XDECREF(t); + glp_delete_prob(lp); + return PyErr_NoMemory(); + } + + PyTuple_SET_ITEM(t, 0, (PyObject *) + PYSTRING_FROMSTRING("optimal")); + + for (i=0; i<n; i++) + MAT_BUFD(x)[i] = glp_get_col_prim(lp, i+1); + PyTuple_SET_ITEM(t, 1, (PyObject *) x); + + for (i=0; i<m; i++) + MAT_BUFD(z)[i] = -glp_get_row_dual(lp, i+1); + PyTuple_SET_ITEM(t, 2, (PyObject *) z); + + if (A){ + for (i=0; i<p; i++) + MAT_BUFD(y)[i] = -glp_get_row_dual(lp, m+i+1); + PyTuple_SET_ITEM(t, 3, (PyObject *) y); + } + glp_delete_prob(lp); + return (PyObject *) t; + break; + + case GLP_NOFEAS: + PyTuple_SET_ITEM(t, 0, (PyObject *) + PYSTRING_FROMSTRING("primal infeasible")); + break; + + case GLP_UNBND: + PyTuple_SET_ITEM(t, 0, (PyObject *) + PYSTRING_FROMSTRING("dual infeasible")); + break; + + default: + PyTuple_SET_ITEM(t, 0, (PyObject *) + PYSTRING_FROMSTRING("unknown")); } + break; - lpx_delete_prob(lp); - return (PyObject *) t; - - case LPX_E_NOPFS: - + case GLP_ENOPFS: PyTuple_SET_ITEM(t, 0, (PyObject *) -#if PY_MAJOR_VERSION >= 3 - PyUnicode_FromString("primal infeasible")); -#else - PyString_FromString("primal infeasible")); -#endif + PYSTRING_FROMSTRING("primal infeasible")); break; - case LPX_E_NODFS: - + case GLP_ENODFS: PyTuple_SET_ITEM(t, 0, (PyObject *) -#if PY_MAJOR_VERSION >= 3 - PyUnicode_FromString("dual infeasible")); -#else - PyString_FromString("dual infeasible")); -#endif + PYSTRING_FROMSTRING("dual infeasible")); break; default: - PyTuple_SET_ITEM(t, 0, (PyObject *) -#if PY_MAJOR_VERSION >= 3 - PyUnicode_FromString("unknown")); -#else - PyString_FromString("unknown")); -#endif + PYSTRING_FROMSTRING("unknown")); } - lpx_delete_prob(lp); - + glp_delete_prob(lp); PyTuple_SET_ITEM(t, 1, Py_BuildValue("")); PyTuple_SET_ITEM(t, 2, Py_BuildValue("")); if (A) PyTuple_SET_ITEM(t, 3, Py_BuildValue("")); @@ -405,21 +437,25 @@ static char doc_integer[] = " minimize c'*x\n" " subject to G*x <= h\n" " A*x = b\n" - " x[I] are all integer\n" - " x[B] are all binary\n\n" + " x[k] is integer for k in I\n" + " x[k] is binary for k in B\n\n" "ARGUMENTS\n" "c nx1 dense 'd' matrix with n>=1\n\n" "G mxn dense or sparse 'd' matrix with m>=1\n\n" "h mx1 dense 'd' matrix\n\n" "A pxn dense or sparse 'd' matrix with p>=0\n\n" "b px1 dense 'd' matrix\n\n" - "I set with indices of integer variables\n\n" - "B set with indices of binary variables\n\n" - "status 'optimal', 'primal infeasible', 'dual infeasible', \n" - " 'invalid MIP formulation', 'maxiters exceeded', \n" - " 'time limit exceeded', 'unknown'\n\n" - "x an optimal solution if status is 'optimal';\n" - " None otherwise"; + "I set of indices of integer variables\n\n" + "B set of indices of binary variables\n\n" + "status if status is 'optimal', 'feasible', or 'undefined',\n" + " a value of x is returned and the status string \n" + " gives the status of x. Other possible values of " + " status are: 'invalid formulation', \n" + " 'infeasible problem', 'LP relaxation is primal \n" + " infeasible', 'LP relaxation is dual infeasible', \n" + " 'unknown'.\n\n" + "x a (sub-)optimal solution if status is 'optimal', \n" + " 'feasible', or 'undefined'. None otherwise"; static PyObject *integer(PyObject *self, PyObject *args, PyObject *kwrds) @@ -427,16 +463,11 @@ static PyObject *integer(PyObject *self, matrix *c, *h, *b=NULL, *x=NULL; PyObject *G, *A=NULL, *IntSet=NULL, *BinSet = NULL; PyObject *t=NULL, *param, *key, *value; - LPX *lp; - int m, n, p, i, j, k, nnz, nnzmax, *rn=NULL, *cn=NULL, param_id; + glp_prob *lp; + glp_iocp iocp; + int m, n, p, i, j, k, nnz, nnzmax, *rn=NULL, *cn=NULL, info, status; int_t pos=0; double *a=NULL, val; - char param_type, err_str[100]; -#if PY_MAJOR_VERSION >= 3 - const char *keystr; -#else - char *keystr; -#endif char *kwlist[] = {"c", "G", "h", "A", "b", "I", "B", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|OOOO", kwlist, &c, @@ -484,23 +515,23 @@ static PyObject *integer(PyObject *self, } if ((IntSet) && (!PyAnySet_Check(IntSet))) - PY_ERR_TYPE("invalid integer index set"); + PY_ERR_TYPE("invalid integer index set"); if ((BinSet) && (!PyAnySet_Check(BinSet))) - PY_ERR_TYPE("invalid binary index set"); + PY_ERR_TYPE("invalid binary index set"); - lp = lpx_create_prob(); - lpx_add_rows(lp, m+p); - lpx_add_cols(lp, n); + lp = glp_create_prob(); + glp_add_rows(lp, m+p); + glp_add_cols(lp, n); for (i=0; i<n; i++){ - lpx_set_obj_coef(lp, i+1, MAT_BUFD(c)[i]); - lpx_set_col_bnds(lp, i+1, LPX_FR, 0.0, 0.0); + glp_set_obj_coef(lp, i+1, MAT_BUFD(c)[i]); + glp_set_col_bnds(lp, i+1, GLP_FR, 0.0, 0.0); } for (i=0; i<m; i++) - lpx_set_row_bnds(lp, i+1, LPX_UP, 0.0, MAT_BUFD(h)[i]); + glp_set_row_bnds(lp, i+1, GLP_UP, 0.0, MAT_BUFD(h)[i]); for (i=0; i<p; i++) - lpx_set_row_bnds(lp, i+m+1, LPX_FX, MAT_BUFD(b)[i], + glp_set_row_bnds(lp, i+m+1, GLP_FX, MAT_BUFD(b)[i], MAT_BUFD(b)[i]); nnzmax = (SpMatrix_Check(G) ? SP_NNZ(G) : m*n ) + @@ -509,7 +540,7 @@ static PyObject *integer(PyObject *self, rn = (int *) calloc(nnzmax+1, sizeof(int)); cn = (int *) calloc(nnzmax+1, sizeof(int)); if (!a || !rn || !cn){ - free(a); free(rn); free(cn); lpx_delete_prob(lp); + free(a); free(rn); free(cn); glp_delete_prob(lp); return PyErr_NoMemory(); } @@ -548,232 +579,399 @@ static PyObject *integer(PyObject *self, nnz++; } - lpx_load_matrix(lp, nnz, rn, cn, a); + glp_load_matrix(lp, nnz, rn, cn, a); free(rn); free(cn); free(a); if (!(t = PyTuple_New(2))) { - lpx_delete_prob(lp); + glp_delete_prob(lp); return PyErr_NoMemory(); } if (!(param = PyObject_GetAttrString(glpk_module, "options")) || !PyDict_Check(param)){ - lpx_delete_prob(lp); + glp_delete_prob(lp); PyErr_SetString(PyExc_AttributeError, "missing glpk.options dictionary"); return NULL; } + glp_init_iocp(&iocp); + while (PyDict_Next(param, &pos, &key, &value)) -#if PY_MAJOR_VERSION >= 3 - if ((PyUnicode_Check(key)) && (keystr = PyUnicode_AS_DATA(key)) - && get_param_idx(keystr, ¶m_id, ¶m_type)){ -#else - if ((keystr = PyString_AsString(key)) && get_param_idx(keystr, - ¶m_id, ¶m_type)){ -#endif - if (param_type == 'i'){ -#if PY_MAJOR_VERSION >= 3 - if (!PyLong_Check(value)){ -#else - if (!PyInt_Check(value)){ -#endif - sprintf(err_str, "invalid value for integer " - "GLPK parameter: %-.20s", keystr); - PyErr_SetString(PyExc_ValueError, err_str); - lpx_delete_prob(lp); - Py_DECREF(param); - return NULL; - } - if (!strcmp("LPX_K_PRESOL", keystr) && -#if PY_MAJOR_VERSION >= 3 - PyLong_AS_LONG(value) != 1){ -#else - PyInt_AS_LONG(value) != 1){ -#endif - PyErr_Warn(PyExc_UserWarning, "ignoring value of " - "GLPK parameter 'LPX_K_PRESOL'"); + if (PYSTRING_CHECK(key)){ + if (!PYSTRING_COMPARE(key, "msg_lev")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_MSG_OFF")) + iocp.msg_lev = GLP_MSG_OFF; + else if (!PYSTRING_COMPARE(value, "GLP_MSG_ERR")) + iocp.msg_lev = GLP_MSG_ERR; + else if (!PYSTRING_COMPARE(value, "GLP_MSG_ON")) + iocp.msg_lev = GLP_MSG_ON; + else if (!PYSTRING_COMPARE(value, "GLP_MSG_ALL")) + iocp.msg_lev = GLP_MSG_ALL; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['msg_lev'] with default value", + 1); } else -#if PY_MAJOR_VERSION >= 3 - lpx_set_int_parm(lp, param_id, PyLong_AS_LONG(value)); -#else - lpx_set_int_parm(lp, param_id, PyInt_AS_LONG(value)); -#endif - } - else { -#if PY_MAJOR_VERSION >= 3 - if (!PyLong_Check(value) && !PyFloat_Check(value)){ -#else - if (!PyInt_Check(value) && !PyFloat_Check(value)){ + PyErr_WarnEx(NULL, "replacing glpk.options['msg_lev'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "br_tech")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_BR_FFV")) + iocp.br_tech= GLP_BR_FFV; + else if (!PYSTRING_COMPARE(value, "GLP_BR_LFV")) + iocp.br_tech = GLP_BR_LFV; + else if (!PYSTRING_COMPARE(value, "GLP_BR_MFV")) + iocp.br_tech = GLP_BR_MFV; + else if (!PYSTRING_COMPARE(value, "GLP_BR_DTH")) + iocp.br_tech = GLP_BR_DTH; + else if (!PYSTRING_COMPARE(value, "GLP_BR_PCH")) + iocp.br_tech = GLP_BR_PCH; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['br_tech'] with default value", + 1); + } + else + PyErr_WarnEx(NULL, "replacing glpk.options['br_tech'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "bt_tech")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_BT_DFS")) + iocp.bt_tech = GLP_BT_DFS; + else if (!PYSTRING_COMPARE(value, "GLP_BT_BFS")) + iocp.bt_tech = GLP_BT_BFS; + else if (!PYSTRING_COMPARE(value, "GLP_BT_BLB")) + iocp.bt_tech = GLP_BT_BLB; + else if (!PYSTRING_COMPARE(value, "GLP_BT_BPH")) + iocp.bt_tech = GLP_BT_BPH; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['bt_tech'] with default value", + 1); + } + else + PyErr_WarnEx(NULL, "replacing glpk.options['bt_tech'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "pp_tech")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_PP_NONE")) + iocp.pp_tech = GLP_PP_NONE; + else if (!PYSTRING_COMPARE(value, "GLP_PP_ROOT")) + iocp.pp_tech = GLP_PP_ROOT; + else if (!PYSTRING_COMPARE(value, "GLP_PP_ALL")) + iocp.pp_tech = GLP_PP_ALL; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['pp_tech'] with default value", + 1); + } + else + PyErr_WarnEx(NULL, "replacing glpk.options['pp_tech'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "fp_heur")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_ON")) + iocp.fp_heur = GLP_ON; + else if (!PYSTRING_COMPARE(value, "GLP_OFF")) + iocp.fp_heur = GLP_OFF; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['fp_heur'] with default value", + 1); + } + else + PyErr_WarnEx(NULL, "replacing glpk.options['fp_heur'] " + "with default value", 1); +#if 0 + else if (!PYSTRING_COMPARE(key, "ps_heur")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_ON")) + iocp.ps_heur = GLP_ON; + else if (!PYSTRING_COMPARE(value, "GLP_OFF")) + iocp.ps_heur = GLP_OFF; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['ps_heur'] with default value", + 1); + } + else + PyErr_WarnEx(NULL, "replacing glpk.options['ps_heur'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "ps_tm_lim")) + if (PYINT_CHECK(value)) + iocp.ps_tm_lim = PYINT_AS_LONG(value); + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['ps_tm_lim'] with default value", 1); #endif - sprintf(err_str, "invalid value for floating point " - "GLPK parameter: %-.20s", keystr); - PyErr_SetString(PyExc_ValueError, err_str); - lpx_delete_prob(lp); - Py_DECREF(param); - return NULL; - } - lpx_set_real_parm(lp, param_id, - PyFloat_AsDouble(value)); - } - } - lpx_set_int_parm(lp, LPX_K_PRESOL, 1); + else if (!PYSTRING_COMPARE(key, "gmi_cuts")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_ON")) + iocp.gmi_cuts = GLP_ON; + else if (!PYSTRING_COMPARE(value, "GLP_OFF")) + iocp.gmi_cuts = GLP_OFF; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['gmi_cuts'] with default value", + 1); + } + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['gmi_cuts'] with default value", 1); + else if (!PYSTRING_COMPARE(key, "mir_cuts")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_ON")) + iocp.mir_cuts = GLP_ON; + else if (!PYSTRING_COMPARE(value, "GLP_OFF")) + iocp.mir_cuts = GLP_OFF; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['mir_cuts'] with default value", + 1); + } + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['mir_cuts'] with default value", 1); + else if (!PYSTRING_COMPARE(key, "cov_cuts")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_ON")) + iocp.cov_cuts = GLP_ON; + else if (!PYSTRING_COMPARE(value, "GLP_OFF")) + iocp.cov_cuts = GLP_OFF; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['cov_cuts'] with default value", + 1); + } + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['cov_cuts'] with default value", 1); + else if (!PYSTRING_COMPARE(key, "clq_cuts")) + if (PYSTRING_CHECK(value)){ + if (!PYSTRING_COMPARE(value, "GLP_ON")) + iocp.clq_cuts = GLP_ON; + else if (!PYSTRING_COMPARE(value, "GLP_OFF")) + iocp.clq_cuts = GLP_OFF; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['clq_cuts'] with default value", + 1); + } + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['clq_cuts'] with default value", 1); + else if (!PYSTRING_COMPARE(key, "tol_int")) + if (PyFloat_Check(value)) + iocp.tol_int = PyFloat_AsDouble(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['tol_int'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "tol_obj")) + if (PyFloat_Check(value)) + iocp.tol_obj = PyFloat_AsDouble(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['tol_obj'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "mip_gap")) + if (PyFloat_Check(value)) + iocp.mip_gap = PyFloat_AsDouble(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['mip_gap'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "tm_lim")) + if (PYINT_CHECK(value)) + iocp.tm_lim = PYINT_AS_LONG(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['tm_lim'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "out_frq")) + if (PYINT_CHECK(value)) + iocp.out_frq = PYINT_AS_LONG(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['out_frq'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "out_dly")) + if (PYINT_CHECK(value)) + iocp.out_dly = PYINT_AS_LONG(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['out_dly'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "glp_tree")) + PyErr_WarnEx(NULL, "replacing glpk.options['glp_tree'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "cb_info")) + PyErr_WarnEx(NULL, "replacing glpk.options['cb_info'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "cb_size")) + if (PYINT_CHECK(value)) + iocp.cb_size = PYINT_AS_LONG(value); + else + PyErr_WarnEx(NULL, "replacing glpk.options['cb_size'] " + "with default value", 1); + else if (!PYSTRING_COMPARE(key, "presolve")) + if (PYSTRING_CHECK(value)) { + if (!PYSTRING_COMPARE(value, "GLP_ON")) + iocp.presolve = GLP_ON; + else if (!PYSTRING_COMPARE(value, "GLP_OFF")){ + iocp.presolve = GLP_ON; + PyErr_WarnEx(NULL, "replacing " + "glpk.options['presolve'] with GLP_ON", 1); + } + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['presolve'] with GLP_ON", 1); + } + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['presolve'] with GLP_ON", 1); + else if (!PYSTRING_COMPARE(key, "binarize")) { + if (PYSTRING_CHECK(value)) { + if (!PYSTRING_COMPARE(value, "GLP_ON")) + iocp.binarize = GLP_ON; + else if (!PYSTRING_COMPARE(value, "GLP_OFF")) + iocp.binarize = GLP_OFF; + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['binarize'] with default " + "value", 1); + } + else + PyErr_WarnEx(NULL, "replacing " + "glpk.options['binarize'] with default value", 1); + } + } + Py_DECREF(param); + iocp.presolve = GLP_ON; if (IntSet) { - PyObject *iter = PySequence_Fast(IntSet, "Critical error: not sequence"); - - for (i=0; i<PySet_GET_SIZE(IntSet); i++) { - - PyObject *tmp = PySequence_Fast_GET_ITEM(iter, i); -#if PY_MAJOR_VERSION >= 3 - if (!PyLong_Check(tmp)) { -#else - if (!PyInt_Check(tmp)) { -#endif - lpx_delete_prob(lp); - Py_DECREF(iter); - PY_ERR_TYPE("non-integer element in I"); - } -#if PY_MAJOR_VERSION >= 3 - int k = PyLong_AS_LONG(tmp); -#else - int k = PyInt_AS_LONG(tmp); -#endif - if ((k < 0) || (k >= n)) { - lpx_delete_prob(lp); - Py_DECREF(iter); - PY_ERR(PyExc_IndexError, "index element out of range in I"); - } - glp_set_col_kind(lp, k+1, GLP_IV); - } - - Py_DECREF(iter); + PyObject *iter = PySequence_Fast(IntSet, + "Critical error: not sequence"); + for (i=0; i<PySet_GET_SIZE(IntSet); i++) { + PyObject *tmp = PySequence_Fast_GET_ITEM(iter, i); + if (!PYINT_CHECK(tmp)) { + glp_delete_prob(lp); + Py_DECREF(iter); + PY_ERR_TYPE("non-integer element in I"); + } + int k = PYINT_AS_LONG(tmp); + if ((k < 0) || (k >= n)) { + glp_delete_prob(lp); + Py_DECREF(iter); + PY_ERR(PyExc_IndexError, "index element out of range " + "in I"); + } + glp_set_col_kind(lp, k+1, GLP_IV); + } + Py_DECREF(iter); } - if (BinSet) { - PyObject *iter = PySequence_Fast(BinSet, "Critical error: not sequence"); - - for (i=0; i<PySet_GET_SIZE(BinSet); i++) { - - PyObject *tmp = PySequence_Fast_GET_ITEM(iter, i); -#if PY_MAJOR_VERSION >= 3 - if (!PyLong_Check(tmp)) { -#else - if (!PyInt_Check(tmp)) { -#endif - lpx_delete_prob(lp); - Py_DECREF(iter); - PY_ERR_TYPE("non-binary element in I"); - } -#if PY_MAJOR_VERSION >= 3 - int k = PyLong_AS_LONG(tmp); -#else - int k = PyInt_AS_LONG(tmp); -#endif - if ((k < 0) || (k >= n)) { - lpx_delete_prob(lp); - Py_DECREF(iter); - PY_ERR(PyExc_IndexError, "index element out of range in B"); - } - glp_set_col_kind(lp, k+1, GLP_BV); - } - - Py_DECREF(iter); - + if (BinSet){ + PyObject *iter = PySequence_Fast(BinSet, + "Critical error: not sequence"); + for (i=0; i<PySet_GET_SIZE(BinSet); i++) { + PyObject *tmp = PySequence_Fast_GET_ITEM(iter, i); + if (!PYINT_CHECK(tmp)) { + glp_delete_prob(lp); + Py_DECREF(iter); + PY_ERR_TYPE("non-binary element in I"); + } + int k = PYINT_AS_LONG(tmp); + if ((k < 0) || (k >= n)) { + glp_delete_prob(lp); + Py_DECREF(iter); + PY_ERR(PyExc_IndexError, + "index element out of range in B"); + } + glp_set_col_kind(lp, k+1, GLP_BV); + } + Py_DECREF(iter); } + info = glp_intopt(lp, &iocp); + status = glp_mip_status(lp); + switch (info){ - switch (lpx_intopt(lp)){ - - case LPX_E_OK: - - x = (matrix *) Matrix_New(n,1,DOUBLE); - if (!x) { - Py_XDECREF(t); - lpx_delete_prob(lp); - return PyErr_NoMemory(); + case 0: + case GLP_EMIPGAP: + case GLP_ETMLIM: + switch(status){ + case GLP_OPT: /* x is optimal */ + case GLP_FEAS: /* x is integer feasible */ + case GLP_UNDEF: /* x is undefined */ + x = (matrix *) Matrix_New(n,1,DOUBLE); + if (!x) { + Py_XDECREF(t); + glp_delete_prob(lp); + return PyErr_NoMemory(); + } + if (status == GLP_OPT) + PyTuple_SET_ITEM(t, 0, + (PyObject *) PYSTRING_FROMSTRING("optimal")); + else if (status == GLP_FEAS) + PyTuple_SET_ITEM(t, 0, + (PyObject *)PYSTRING_FROMSTRING("feasible")); + else + PyTuple_SET_ITEM(t, 0, + (PyObject *)PYSTRING_FROMSTRING("undefined")); + for (i=0; i<n; i++) + MAT_BUFD(x)[i] = glp_mip_col_val(lp, i+1); + PyTuple_SET_ITEM(t, 1, (PyObject *) x); + glp_delete_prob(lp); + return (PyObject *) t; + break; + + case GLP_NOFEAS: + PyTuple_SET_ITEM(t, 0, (PyObject *) + PYSTRING_FROMSTRING("infeasible problem")); + PyTuple_SET_ITEM(t, 1, Py_BuildValue("")); + break; + + default: + PyTuple_SET_ITEM(t, 1, Py_BuildValue("")); + PyTuple_SET_ITEM(t, 0, (PyObject *) + PYSTRING_FROMSTRING("unknown")); } - PyTuple_SET_ITEM(t, 0, (PyObject *) -#if PY_MAJOR_VERSION >= 3 - PyUnicode_FromString("optimal")); -#else - PyString_FromString("optimal")); -#endif - - for (i=0; i<n; i++) - MAT_BUFD(x)[i] = lpx_mip_col_val(lp, i+1); - PyTuple_SET_ITEM(t, 1, (PyObject *) x); - - lpx_delete_prob(lp); - return (PyObject *) t; + break; - case LPX_E_FAULT: - PyTuple_SET_ITEM(t, 0, (PyObject *) -#if PY_MAJOR_VERSION >= 3 - PyUnicode_FromString("invalid MIP formulation")); -#else - PyString_FromString("invalid MIP formulation")); -#endif +#if 0 + case GLP_EBADB: - case LPX_E_NOPFS: - PyTuple_SET_ITEM(t, 0, (PyObject *) -#if PY_MAJOR_VERSION >= 3 - PyUnicode_FromString("primal infeasible")); -#else - PyString_FromString("primal infeasible")); + case GLP_ECOND: #endif - case LPX_E_NODFS: - + case GLP_EBOUND: PyTuple_SET_ITEM(t, 0, (PyObject *) -#if PY_MAJOR_VERSION >= 3 - PyUnicode_FromString("dual infeasible")); -#else - PyString_FromString("dual infeasible")); -#endif - - case LPX_E_ITLIM: + PYSTRING_FROMSTRING("invalid MIP formulation")); + break; + case GLP_ENOPFS: PyTuple_SET_ITEM(t, 0, (PyObject *) -#if PY_MAJOR_VERSION >= 3 - PyUnicode_FromString("maxiters exceeded")); -#else - PyString_FromString("maxiters exceeded")); -#endif - - case LPX_E_TMLIM: + PYSTRING_FROMSTRING("LP relaxation is primal infeasible")); + break; + case GLP_ENODFS: PyTuple_SET_ITEM(t, 0, (PyObject *) -#if PY_MAJOR_VERSION >= 3 - PyUnicode_FromString("time limit exceeded")); -#else - PyString_FromString("time limit exceeded")); -#endif - - case LPX_E_SING: + PYSTRING_FROMSTRING("LP relaxation is dual infeasible")); + break; + case GLP_EFAIL: PyTuple_SET_ITEM(t, 0, (PyObject *) -#if PY_MAJOR_VERSION >= 3 - PyUnicode_FromString("singular or ill-conditioned basis")); -#else - PyString_FromString("singular or ill-conditioned basis")); -#endif + PYSTRING_FROMSTRING("solver failure")); + break; + case GLP_EROOT: /* only occurs if presolver is off */ + case GLP_ESTOP: /* only occurs when advanced interface is used */ default: - PyTuple_SET_ITEM(t, 0, (PyObject *) -#if PY_MAJOR_VERSION >= 3 - PyUnicode_FromString("unknown")); -#else - PyString_FromString("unknown")); -#endif + PYSTRING_FROMSTRING("unknown")); } - lpx_delete_prob(lp); - + glp_delete_prob(lp); PyTuple_SET_ITEM(t, 1, Py_BuildValue("")); return (PyObject *) t; }
signature.asc
Description: OpenPGP digital signature