Example #1
0
def get_lp_params(alternate_lp_params=False):
    'get the lp params object'

    if not hasattr(get_lp_params, 'obj'):
        params = glpk.glp_smcp()
        glpk.glp_init_smcp(params)

        #params.msg_lev = glpk.GLP_MSG_ERR
        params.msg_lev = glpk.GLP_MSG_ERR
        params.meth = glpk.GLP_PRIMAL if Settings.GLPK_FIRST_PRIMAL else glpk.GLP_DUAL

        params.tm_lim = int(Settings.GLPK_TIMEOUT * 1000)
        params.out_dly = 2 * 1000  # start printing to terminal delay

        get_lp_params.obj = params

        # make alternative params
        params2 = glpk.glp_smcp()
        glpk.glp_init_smcp(params2)
        params2.meth = glpk.GLP_DUAL if Settings.GLPK_FIRST_PRIMAL else glpk.GLP_PRIMAL
        params2.msg_lev = glpk.GLP_MSG_ON

        params2.tm_lim = int(Settings.GLPK_TIMEOUT * 1000)
        params2.out_dly = 1 * 1000  # start printing to terminal status after 1 secs

        get_lp_params.alt_obj = params2

    if alternate_lp_params:
        #glpk.glp_term_out(glpk.GLP_ON)
        rv = get_lp_params.alt_obj
    else:
        #glpk.glp_term_out(glpk.GLP_OFF)
        rv = get_lp_params.obj

    return rv
Example #2
0
    def __init__(self, quadratic_objective=False):
        if quadratic_objective:
            raise Exception('Quadratic objective not supported for GLPK')

        self._lp = glp.glp_create_prob()
        self._smcp = glp.glp_smcp()  # simplex solver control parameters
        glp.glp_init_smcp(self._smcp)
        self._smcp.msg_lev = glp.GLP_MSG_ERR
        self.simplex_iteration_limit = 10000
        self._n_vars = 0
        self._n_eq_constraints = 0

        self._flows = {}
        self._lb = {}
        self._ub = {}
        self._objective = {}
        self._materialCoeffs = defaultdict(list)
        self._materialIdxLookup = {}

        self._eqConstBuilt = False
        self._solved = False

        self.inf = np.inf

        self._lowerBoundDefault = 0
        self._upperBoundDefault = self.inf
Example #3
0
    def solve(self, sense=None):
        """Solve problem."""
        if sense is not None:
            self.set_objective_sense(sense)

        parm = swiglpk.glp_smcp()
        swiglpk.glp_init_smcp(parm)
        parm.presolve = swiglpk.GLP_ON

        logger.debug('Solving using glp_simplex()')
        r = swiglpk.glp_simplex(self._p, parm)
        if r in (swiglpk.GLP_ENOPFS, swiglpk.GLP_ENODFS):
            self._result = Result(self, r)
            return self._result
        elif r != 0:
            raise GLPKError('glp_simplex: {}'.format(r))

        if swiglpk.glp_get_num_int(self._p) == 0:
            self._result = Result(self)
        else:
            # The intopt MILP solver need an optimal solution to the LP
            # relaxation. Therefore, glp_simplex has to run before glp_intopt
            # for MILP problems.
            logger.debug('Solving using glp_intopt()')
            r = swiglpk.glp_intopt(self._p, None)
            if r != 0:
                raise GLPKError('glp_intopt: {}'.format(r))

            self._result = MIPResult(self)

        return self._result
Example #4
0
File: glpk.py Project: jonls/psamm
    def solve(self, sense=None):
        """Solve problem."""
        if sense is not None:
            self.set_objective_sense(sense)

        parm = swiglpk.glp_smcp()
        swiglpk.glp_init_smcp(parm)
        if self._do_presolve:
            parm.presolve = swiglpk.GLP_ON
            self._do_presolve = False
        else:
            parm.presolve = swiglpk.GLP_OFF

        logger.debug('Solving using glp_simplex()')
        r = swiglpk.glp_simplex(self._p, parm)
        if r in (swiglpk.GLP_ENOPFS, swiglpk.GLP_ENODFS):
            self._result = Result(self, r)
            return self._result
        elif r != 0:
            raise GLPKError('glp_simplex: {}'.format(r))

        if swiglpk.glp_get_num_int(self._p) == 0:
            self._result = Result(self)
        else:
            # The intopt MILP solver need an optimal solution to the LP
            # relaxation. Therefore, glp_simplex has to run before glp_intopt
            # for MILP problems.
            logger.debug('Solving using glp_intopt()')
            r = swiglpk.glp_intopt(self._p, None)
            if r != 0:
                raise GLPKError('glp_intopt: {}'.format(r))

            self._result = MIPResult(self)

        return self._result
	def test_swiglpk(self):
		"""Test the underlying GLPK lib and its SWIG interface based on
		the example from https://github.com/biosustain/swiglpk
		"""
		ia = glp.intArray(1 + 1000)
		ja = glp.intArray(1 + 1000)
		ar = glp.doubleArray(1 + 1000)

		lp = glp.glp_create_prob()
		smcp = glp.glp_smcp()
		glp.glp_init_smcp(smcp)
		smcp.msg_lev = glp.GLP_MSG_ALL  # use GLP_MSG_ERR?

		glp.glp_set_prob_name(lp, "sample")
		glp.glp_set_obj_dir(lp, glp.GLP_MAX)

		glp.glp_add_rows(lp, 3)
		glp.glp_set_row_name(lp, 1, "p")
		glp.glp_set_row_bnds(lp, 1, glp.GLP_UP, 0.0, 100.0)
		glp.glp_set_row_name(lp, 2, "q")
		glp.glp_set_row_bnds(lp, 2, glp.GLP_UP, 0.0, 600.0)
		glp.glp_set_row_name(lp, 3, "r")
		glp.glp_set_row_bnds(lp, 3, glp.GLP_UP, 0.0, 300.0)
		glp.glp_add_cols(lp, 3)
		glp.glp_set_col_name(lp, 1, "x1")
		glp.glp_set_col_bnds(lp, 1, glp.GLP_LO, 0.0, 0.0)
		glp.glp_set_obj_coef(lp, 1, 10.0)
		glp.glp_set_col_name(lp, 2, "x2")
		glp.glp_set_col_bnds(lp, 2, glp.GLP_LO, 0.0, 0.0)
		glp.glp_set_obj_coef(lp, 2, 6.0)
		glp.glp_set_col_name(lp, 3, "x3")
		glp.glp_set_col_bnds(lp, 3, glp.GLP_LO, 0.0, 0.0)
		glp.glp_set_obj_coef(lp, 3, 4.0)

		ia[1] = 1; ja[1] = 1; ar[1] = 1.0  # a[1,1] = 1
		ia[2] = 1; ja[2] = 2; ar[2] = 1.0  # a[1,2] = 1
		ia[3] = 1; ja[3] = 3; ar[3] = 1.0  # a[1,3] = 1
		ia[4] = 2; ja[4] = 1; ar[4] = 10.0  # a[2,1] = 10
		ia[5] = 3; ja[5] = 1; ar[5] = 2.0  # a[3,1] = 2
		ia[6] = 2; ja[6] = 2; ar[6] = 4.0  # a[2,2] = 4
		ia[7] = 3; ja[7] = 2; ar[7] = 2.0  # a[3,2] = 2
		ia[8] = 2; ja[8] = 3; ar[8] = 5.0  # a[2,3] = 5
		ia[9] = 3; ja[9] = 3; ar[9] = 6.0  # a[3,3] = 6

		glp.glp_load_matrix(lp, 9, ia, ja, ar)
		glp.glp_simplex(lp, smcp)

		Z = glp.glp_get_obj_val(lp)
		x1 = glp.glp_get_col_prim(lp, 1)
		x2 = glp.glp_get_col_prim(lp, 2)
		x3 = glp.glp_get_col_prim(lp, 3)

		self.assertAlmostEqual(Z, 733.3333, 4)
		self.assertAlmostEqual(x1, 33.3333, 4)
		self.assertAlmostEqual(x2, 66.6667, 4)
		self.assertAlmostEqual(x3, 0)

		glp.glp_delete_prob(lp)
Example #6
0
 def __init__(self, presolve="auto", verbosity=0, timeout=None, *args, **kwargs):
     super(Configuration, self).__init__(*args, **kwargs)
     self._smcp = glp_smcp()
     self._iocp = glp_iocp()
     glp_init_smcp(self._smcp)
     glp_init_iocp(self._iocp)
     self._max_time = min(self._smcp.tm_lim, self._iocp.tm_lim)
     self.presolve = presolve
     self.verbosity = verbosity
     self.timeout = timeout
 def __init__(self, presolve="auto", verbosity=0, timeout=None, *args, **kwargs):
     super(Configuration, self).__init__(*args, **kwargs)
     self._smcp = glp_smcp()
     self._iocp = glp_iocp()
     glp_init_smcp(self._smcp)
     glp_init_iocp(self._iocp)
     self._max_time = min(self._smcp.tm_lim, self._iocp.tm_lim)
     self.presolve = presolve
     self.verbosity = verbosity
     self.timeout = timeout
Example #8
0
 def check_objval(glpk_problem, model_objval):
     """
     Check that ...
     """
     smcp = glp_smcp()
     smcp.presolve = True
     glp_simplex(glpk_problem, None)
     status = glp_get_status(glpk_problem)
     if status == GLP_OPT:
         glpk_problem_objval = glp_get_obj_val(glpk_problem)
     else:
         glpk_problem_objval = None
     nose.tools.assert_almost_equal(glpk_problem_objval, model_objval, places=4)
Example #9
0
def solve_linprog(problem: SwigPyObject):
    level = level_for_parm()

    parm = lp.glp_smcp()
    lp.glp_init_smcp(parm)
    parm.msg_lev = level
    check_lp(problem, lp.glp_simplex(problem, parm))
    log_soln(problem, 'sol')

    parm = lp.glp_iocp()
    lp.glp_init_iocp(parm)
    parm.msg_lev = level
    check_lp(problem, lp.glp_intopt(problem, parm))
    log_soln(problem, 'mip')
Example #10
0
def _linprog(c, A, b, obj):

    lp = glpk.glp_create_prob()
    glpk.glp_set_obj_dir(lp, obj)

    params = glpk.glp_smcp()
    glpk.glp_init_smcp(params)
    params.msg_lev = glpk.GLP_MSG_OFF  #Only print error messages from GLPK

    num_rows = A.shape[0]
    num_cols = A.shape[1]
    mat_size = num_rows * num_cols

    glpk.glp_add_rows(lp, num_rows)

    for row_ind in range(num_rows):
        glpk.glp_set_row_bnds(lp, row_ind + 1, glpk.GLP_UP, 0.0,
                              float(b[row_ind]))

    glpk.glp_add_cols(lp, num_cols)

    for col_ind in range(num_cols):
        glpk.glp_set_col_bnds(lp, col_ind + 1, glpk.GLP_FR, 0.0, 0.0)
        glpk.glp_set_obj_coef(lp, col_ind + 1, c[col_ind])

    'Swig arrays are used for feeding constraints in GLPK'

    ia, ja, ar = [], [], []
    for i, j in product(range(num_rows), range(num_cols)):
        ia.append(i + 1)
        ja.append(j + 1)
        ar.append(float(A[i][j]))

    ia = glpk.as_intArray(ia)
    ja = glpk.as_intArray(ja)
    ar = glpk.as_doubleArray(ar)

    glpk.glp_load_matrix(lp, mat_size, ia, ja, ar)
    glpk.glp_simplex(lp, params)

    fun = glpk.glp_get_obj_val(lp)
    x = [
        i for i in map(lambda x: glpk.glp_get_col_prim(lp, x + 1),
                       range(num_cols))
    ]

    glpk.glp_delete_prob(lp)
    glpk.glp_free_env()

    return LPSolution(x, fun)
Example #11
0
    def minimize(self, direction_vec=None, columns=None, fail_on_unsat=True):
        '''minimize the lp, returning a list of assigments to each of the variables

        if direction_vec is not None, this will first assign the optimization direction (note: relative to cur_vars)
        if columns is not None, will only return the requested columns (default: all columns)
        if fail_on_unsat is True and the LP is infeasible, an UnsatError is raised
        unsat (sometimes happens in GLPK due to likely bug, see space station model)

        returns None if UNSAT, otherwise the optimization result. Use columns=[] if you're not interested in the result
        '''

        if direction_vec is not None:
            self.set_minimize_direction(direction_vec)

        Timers.tic('setup')
        # setup lp params
        params = glpk.glp_smcp()
        glpk.glp_init_smcp(params)
        params.meth = glpk.GLP_DUALP  # use dual simplex since we're reoptimizing often
        params.msg_lev = glpk.GLP_MSG_OFF
        params.tm_lim = 1000  # 1000 ms time limit
        Timers.toc('setup')

        Timers.tic('glp_simplex')
        simplex_res = glpk.glp_simplex(self.lp, params)
        Timers.toc('glp_simplex')

        # process simplex result
        Timers.tic('process_simplex_result')
        rv = self._process_simplex_result(simplex_res, columns)
        Timers.toc('process_simplex_result')

        if rv is None and fail_on_unsat:
            print(
                "Note: minimize failed with fail_on_unsat was true, resetting and retrying..."
            )

            glpk.glp_cpx_basis(self.lp)  # resets the initial basis

            rv = self.minimize(direction_vec, columns, False)

            #LpInstance.print_verbose("Note: LP was infeasible, but then feasible after resetting statuses")

        if rv is None and fail_on_unsat:
            raise UnsatError(
                "minimize returned UNSAT and fail_on_unsafe was True")

        return rv
Example #12
0
 def __init__(self, presolve="auto", verbosity=0, timeout=None, *args, **kwargs):
     super(Configuration, self).__init__(*args, **kwargs)
     self._smcp = glp_smcp()
     self._iocp = glp_iocp()
     glp_init_smcp(self._smcp)
     glp_init_iocp(self._iocp)
     self._max_time = min(self._smcp.tm_lim, self._iocp.tm_lim)
     self.presolve = presolve
     self.verbosity = verbosity
     self.timeout = timeout
     if "tolerances" in kwargs:
         for key, val in six.iteritems(kwargs["tolerances"]):
             try:
                 setattr(self.tolerances, key, val)
             except AttributeError:
                 pass
Example #13
0
    def solve_unchecked(self, sense=None):
        """Solve problem and return result.

        The user must manually check the status of the result to determine
        whether an optimal solution was found. A :class:`SolverError` may still
        be raised if the underlying solver raises an exception.
        """
        if sense is not None:
            self.set_objective_sense(sense)

        parm = swiglpk.glp_smcp()
        swiglpk.glp_init_smcp(parm)
        if self._do_presolve:
            parm.presolve = swiglpk.GLP_ON
            self._do_presolve = False
        else:
            parm.presolve = swiglpk.GLP_OFF

        parm.tol_bnd = self._feasibility_tolerance
        parm.tol_dj = self._optimality_tolerance

        logger.debug('Solving using glp_simplex()')
        r = swiglpk.glp_simplex(self._p, parm)
        if r in (swiglpk.GLP_ENOPFS, swiglpk.GLP_ENODFS):
            self._result = Result(self, r)
            return self._result
        elif r != 0:
            raise GLPKError('glp_simplex: {}'.format(r))

        if swiglpk.glp_get_num_int(self._p) == 0:
            self._result = Result(self)
        else:
            # The intopt MILP solver needs an optimal solution to the LP
            # relaxation. Therefore, glp_simplex has to run before glp_intopt
            # for MILP problems.
            logger.debug('Solving using glp_intopt()')
            parm = swiglpk.glp_iocp()
            swiglpk.glp_init_iocp(parm)
            parm.tol_int = self._integrality_tolerance
            r = swiglpk.glp_intopt(self._p, parm)
            if r != 0:
                raise GLPKError('glp_intopt: {}'.format(r))

            self._result = MIPResult(self)

        return self._result
Example #14
0
    def __init__(self, **kwargs):
        self._p = swiglpk.glp_create_prob()

        self._variables = {}
        self._constraints = {}

        self._do_presolve = True

        # Initialize simplex tolerances to default values
        parm = swiglpk.glp_smcp()
        swiglpk.glp_init_smcp(parm)
        self._feasibility_tolerance = parm.tol_bnd
        self._optimality_tolerance = parm.tol_dj

        # Initialize mip tolerance to default value
        parm = swiglpk.glp_iocp()
        swiglpk.glp_init_iocp(parm)
        self._integrality_tolerance = parm.tol_int

        self._result = None
Example #15
0
    def _solve(self):
        import swiglpk as glpk

        # An alias to the internal problem instance.
        p = self.int

        continuous = self.ext.is_continuous()

        # Select LP solver (Simplex or Interior Point Method).
        if continuous:
            if self.ext.options["lp_root_method"] == "interior":
                interior = True
            else:
                # Default to Simplex.
                interior = False
            simplex = not interior
        else:
            simplex = interior = False

        # Select appropriate options container.
        if simplex:
            options = glpk.glp_smcp()
            glpk.glp_init_smcp(options)
        elif interior:
            options = glpk.glp_iptcp()
            glpk.glp_init_iptcp(options)
        else:
            options = glpk.glp_iocp()
            glpk.glp_init_iocp(options)

        # Handle "verbose" option.
        verbosity = self.verbosity()
        if verbosity < 0:
            options.msg_lev = glpk.GLP_MSG_OFF
        elif verbosity == 0:
            options.msg_lev = glpk.GLP_MSG_ERR
        elif verbosity == 1:
            options.msg_lev = glpk.GLP_MSG_ON
        elif verbosity >= 2:
            options.msg_lev = glpk.GLP_MSG_ALL

        # Handle "tol" option.
        # Note that GLPK knows three different tolerances for Simplex but none
        # for the Interior Point Method, while PICOS states that "tol" is meant
        # only for the IPM.
        # XXX: The option is unsupported but does not default to None, so we
        #      cannot warn the user.
        pass

        # Handle "maxit" option.
        if not simplex:
            self._handle_unsupported_option("maxit",
                "GLPK supports the 'maxit' option only with Simplex.")
        elif self.ext.options["maxit"] is not None:
                options.it_lim = int(self.ext.options["maxit"])

        # Handle "lp_root_method" option.
        # Note that the PICOS option is explicitly also meant for the MIP
        # preprocessing step but GLPK does not support it in that scenario.
        if not continuous:
            self._handle_unsupported_option("lp_root_method",
                "GLPK supports the 'lp_root_method' option only for LPs.")
        elif self.ext.options["lp_root_method"] is not None:
            if self.ext.options["lp_root_method"] == "interior":
                # Handled above.
                pass
            elif self.ext.options["lp_root_method"] == "psimplex":
                assert simplex
                options.meth = glpk.GLP_PRIMAL
            elif self.ext.options["lp_root_method"] == "dsimplex":
                assert simplex
                options.meth = glpk.GLP_DUAL
            else:
                self._handle_bad_option_value("lp_root_method")

        # Handle "timelimit" option.
        if interior:
            self._handle_unsupported_option("timelimit",
                "GLPK does not support the 'timelimit' option with the "
                "Interior Point Method.")
        elif self.ext.options["timelimit"] is not None:
            options.tm_lim = 1000 * int(self.ext.options["timelimit"])

        # Handle "gaplim" option.
        # Note that the option is silently ignored if passed alongside an LP;
        # while the solver does not allow us to pass the option in that case, it
        # is still technically a valid option as every LP is also a MIP.
        # TODO: Find out if "mip_gap" is really equivalent to "gaplim".
        if self.ext.options["gaplim"] is not None:
            if not continuous:
                options.mip_gap = float(self.ext.options["gaplim"])

        # Handle unsupported options.
        self._handle_unsupported_options(
            "lp_node_method", "treememory", "nbsol", "hotstart")

        # TODO: Add GLPK-sepcific options. Candidates are:
        #       For both Simplex and MIPs:
        #           tol_*, out_*
        #       For Simplex:
        #           pricing, r_test, obj_*
        #       For the Interior Point Method:
        #           ord_alg
        #       For MIPs:
        #           *_tech, *_heur, ps_tm_lim, *_cuts, cb_size, binarize

        # Attempt to solve the problem.
        with self._header():
            with self._stopwatch():
                if simplex:
                    # TODO: Support glp_exact.
                    error = glpk.glp_simplex(p, options)
                elif interior:
                    error = glpk.glp_interior(p, options)
                else:
                    options.presolve = glpk.GLP_ON
                    error = glpk.glp_intopt(p, options)

            # Conert error codes to text output.
            # Note that by printing it above the footer, this output is made to
            # look like it's coming from GLPK, which is technically wrong but
            # semantically correct.
            if error == glpk.GLP_EBADB:
                self._warn("Unable to start the search, because the initial "
                    "basis specified in the problem object is invalid.")
            elif error == glpk.GLP_ESING:
                self._warn("Unable to start the search, because the basis "
                    "matrix corresponding to the initial basis is singular "
                    "within the working precision.")
            elif error == glpk.GLP_ECOND:
                self._warn("Unable to start the search, because the basis "
                    "matrix corresponding to the initial basis is "
                    "ill-conditioned.")
            elif error == glpk.GLP_EBOUND:
                self._warn("Unable to start the search, because some double-"
                    "bounded variables have incorrect bounds.")
            elif error == glpk.GLP_EFAIL:
                self._warn("The search was prematurely terminated due to a "
                    "solver failure.")
            elif error == glpk.GLP_EOBJLL:
                self._warn("The search was prematurely terminated, because the "
                    "objective function being maximized has reached its lower "
                    "limit and continues decreasing.")
            elif error == glpk.GLP_EOBJUL:
                self._warn("The search was prematurely terminated, because the "
                    "objective function being minimized has reached its upper "
                    "limit and continues increasing.")
            elif error == glpk.GLP_EITLIM:
                self._warn("The search was prematurely terminated, because the "
                    "simplex iteration limit has been exceeded.")
            elif error == glpk.GLP_ETMLIM:
                self._warn("The search was prematurely terminated, because the "
                    "time limit has been exceeded.")
            elif error == glpk.GLP_ENOPFS:
                self._verbose("The LP has no primal feasible solution.")
            elif error == glpk.GLP_ENODFS:
                self._verbose("The LP has no dual feasible solution.")
            elif error != 0:
                self._warn("GLPK error {:d}.".format(error))

        # Retrieve primals.
        if self.ext.options["noprimals"]:
            primals = None
        else:
            primals = {}

            for variable in self.ext.variables.values():
                value = []

                for localIndex, picosIndex \
                in enumerate(range(variable.startIndex, variable.endIndex)):
                    glpkIndex = self._picos2glpk_variable_index(picosIndex)

                    if simplex:
                        localValue = glpk.glp_get_col_prim(p, glpkIndex);
                    elif interior:
                        localValue = glpk.glp_ipt_col_prim(p, glpkIndex);
                    else:
                        localValue = glpk.glp_mip_col_val(p, glpkIndex);

                    value.append(localValue)

                primals[variable.name] = value

        # Retrieve duals.
        # XXX: Returns the duals as a flat cvx.matrix to be consistent with
        #      other solvers. This feels incorrect when the constraint was given
        #      as a proper two dimensional matrix.
        if self.ext.options["noduals"] or not continuous:
            duals = None
        else:
            duals = []
            rowOffset = 1
            for constraintNum, constraint in enumerate(self.ext.constraints):
                assert isinstance(constraint, AffineConstraint)
                numRows = len(constraint)
                values = []
                for localConIndex in range(numRows):
                    glpkConIndex = rowOffset + localConIndex
                    if simplex:
                        localValue = glpk.glp_get_row_dual(p, glpkConIndex);
                    elif interior:
                        localValue = glpk.glp_ipt_row_dual(p, glpkConIndex);
                    else:
                        assert False
                    values.append(localValue)
                if constraint.is_decreasing():
                    duals.append(-cvxopt.matrix(values))
                else:
                    duals.append(cvxopt.matrix(values))
                rowOffset += numRows
            if glpk.glp_get_obj_dir(p) == glpk.GLP_MIN:
                duals = [-d for d in duals]

        # Retrieve objective value.
        if simplex:
            objectiveValue = glpk.glp_get_obj_val(p)
        elif interior:
            objectiveValue = glpk.glp_ipt_obj_val(p)
        else:
            objectiveValue = glpk.glp_mip_obj_val(p)

        # Retrieve solution metadata.
        meta = {}

        if simplex:
            # Set common entry "status".
            status = glpk.glp_get_status(p)
            if status is glpk.GLP_OPT:
                meta["status"] = "optimal"
            elif status is glpk.GLP_FEAS:
                meta["status"] = "feasible"
            elif status in (glpk.GLP_INFEAS, glpk.GLP_NOFEAS):
                meta["status"] = "infeasible"
            elif status is glpk.GLP_UNBND:
                meta["status"] = "unbounded"
            elif status is glpk.GLP_UNDEF:
                meta["status"] = "undefined"
            else:
                meta["status"] = "unknown"

            # Set GLPK-specific entry "primal_status".
            primalStatus = glpk.glp_get_prim_stat(p)
            if primalStatus is glpk.GLP_FEAS:
                meta["primal_status"] = "feasible"
            elif primalStatus in (glpk.GLP_INFEAS, glpk.GLP_NOFEAS):
                meta["primal_status"] = "infeasible"
            elif primalStatus is glpk.GLP_UNDEF:
                meta["primal_status"] = "undefined"
            else:
                meta["primal_status"] = "unknown"

            # Set GLPK-specific entry "dual_status".
            dualStatus = glpk.glp_get_dual_stat(p)
            if dualStatus is glpk.GLP_FEAS:
                meta["dual_status"] = "feasible"
            elif dualStatus in (glpk.GLP_INFEAS, glpk.GLP_NOFEAS):
                meta["dual_status"] = "infeasible"
            elif dualStatus is glpk.GLP_UNDEF:
                meta["dual_status"] = "undefined"
            else:
                meta["dual_status"] = "unknown"
        elif interior:
            # Set common entry "status".
            status = glpk.glp_ipt_status(p)
            if status is glpk.GLP_OPT:
                meta["status"] = "optimal"
            elif status in (glpk.GLP_INFEAS, glpk.GLP_NOFEAS):
                meta["status"] = "infeasible"
            elif status is glpk.GLP_UNDEF:
                meta["status"] = "undefined"
            else:
                meta["status"] = "unknown"
        else:
            # Set common entry "status".
            status = glpk.glp_mip_status(p)
            if status is glpk.GLP_OPT:
                meta["status"] = "optimal"
            elif status is glpk.GLP_FEAS:
                meta["status"] = "feasible"
            elif status is glpk.GLP_NOFEAS:
                meta["status"] = "infeasible"
            elif status is glpk.GLP_UNDEF:
                meta["status"] = "undefined"
            else:
                meta["status"] = "unknown"

        return (primals, duals, objectiveValue, meta)
Example #16
0
    def minimize(self, direction_vec=None, columns=None, fail_on_unsat=True, print_on=False):
        '''minimize the lp, returning a list of assigments to each of the variables

        if direction_vec is not None, this will first assign the optimization direction (note: relative to cur_vars)
        if columns is not None, will only return the requested columns (default: all columns)
        if fail_on_unsat is True and the LP is infeasible, an UnsatError is raised
        unsat (sometimes happens in GLPK due to likely bug, see space station model)

        returns None if UNSAT, otherwise the optimization result. Use columns=[] if you're not interested in the result
        '''

        Timers.tic('minimize')

        if direction_vec is not None:
            self.set_minimize_direction(direction_vec)

        # setup lp params
        params = glpk.glp_smcp()
        glpk.glp_init_smcp(params)
        params.meth = glpk.GLP_DUALP # use dual simplex since we're reoptimizing often
        params.msg_lev = glpk.GLP_MSG_ALL if print_on else glpk.GLP_MSG_OFF
        params.tm_lim = 1000 # 1000 ms time limit

        Timers.tic('glp_simplex')
        simplex_res = glpk.glp_simplex(self.lp, params)
        Timers.toc('glp_simplex')

        if simplex_res != 0:
            # this can happen when you replace constraints after already solving once
            LpInstance.print_normal('Note: glp_simplex() failed ({}: {}), resetting and retrying'.format(
                simplex_res, LpInstance.get_simplex_error_string(simplex_res)))

            if simplex_res == glpk.GLP_ESING: # singular matrix, can happen after replacing constraints
                glpk.glp_std_basis(self.lp)
                simplex_res = glpk.glp_simplex(self.lp, params)

            if simplex_res != 0:
                glpk.glp_cpx_basis(self.lp) # resets the initial basis
                params.msg_lev = glpk.GLP_MSG_ON # turn printing on
                params.tm_lim = 30 * 1000 # second try: 30 second time limit
                simplex_res = glpk.glp_simplex(self.lp, params)

        # process simplex result
        rv = self._process_simplex_result(simplex_res, columns)

        Timers.toc('minimize')

        if rv is None and fail_on_unsat:
            LpInstance.print_normal("Note: minimize failed with fail_on_unsat was true, resetting and retrying...")

            glpk.glp_cpx_basis(self.lp) # resets the initial basis

            rv = self.minimize(direction_vec, columns, False, print_on=True)

            if rv is not None:
                LpInstance.print_verbose("Note: LP was infeasible, but then feasible after resetting statuses")

        if rv is None and fail_on_unsat:
            raise UnsatError("minimize returned UNSAT and fail_on_unsafe was True")

        return rv