Skip to content

Commit

Permalink
Support for reading mps files into matrices or glp_prob structs
Browse files Browse the repository at this point in the history
  • Loading branch information
mckib2 committed May 18, 2020
1 parent 40f5fbc commit 2ffd3b4
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 6 deletions.
2 changes: 1 addition & 1 deletion glpk/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

from ._glpk import glpk
from ._utils import mpsread, mpswrite
from ._glpk_defines import GLPK
from ._set_env import glpk_set_env
86 changes: 81 additions & 5 deletions glpk/_glpk_defines.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@

import ctypes
import os
import pathlib

from numpy.ctypeslib import ndpointer

Expand Down Expand Up @@ -33,6 +35,9 @@ class glp_iptcp(ctypes.Structure):
('foo_bar', ctypes.c_double*48),
]

class glp_mpscp(ctypes.Structure):
_fields_ = []

# LP problem structure
class glp_prob(ctypes.Structure):
class DMP(ctypes.Structure):
Expand Down Expand Up @@ -191,14 +196,20 @@ class GLPK:
GLP_ORD_AMD = 2
GLP_ORD_SYMAMD = 3

def __init__(self, libpath):
# MPS formats
GLP_MPS_DECK = 1 # fixed (ancient)
GLP_MPS_FILE = 2 # free (modern)

#glp_prob = self.glp_prob
#glp_smcp = self.glp_smcp
def __init__(self, libpath):

# Load the shared library
#so = '/home/nicholas/Downloads/glpk-4.65/src/.libs/libglpk.so'
# Load the shared library;
# Windows Octave installs require that we load from
# the same directory as libglpk.dll is found
cwd = os.getcwd()
os.chdir(pathlib.Path(libpath).parent)
_lib = ctypes.cdll.LoadLibrary(libpath)
os.chdir(cwd)

_lib.glp_version.restype = ctypes.c_char_p

_lib.glp_create_prob.restype = ctypes.POINTER(glp_prob)
Expand Down Expand Up @@ -277,6 +288,9 @@ def __init__(self, libpath):
_lib.glp_get_obj_coef.restype = ctypes.c_double
_lib.glp_get_obj_coef.argtypes = [ctypes.POINTER(glp_prob), ctypes.c_int]

_lib.glp_get_num_cols.restype = ctypes.c_int
_lib.glp_get_num_cols.argtypes = [ctypes.POINTER(glp_prob)]

_lib.glp_get_col_name.restype = ctypes.c_char_p
_lib.glp_get_col_name.argtypes = [ctypes.POINTER(glp_prob), ctypes.c_int]

Expand All @@ -286,6 +300,50 @@ def __init__(self, libpath):
_lib.glp_get_num_nz.restype = ctypes.c_int
_lib.glp_get_num_nz.argtypes = [ctypes.POINTER(glp_prob)]

_lib.glp_get_mat_row.restype = ctypes.c_int # len of col indices and values
_lib.glp_get_mat_row.argtypes = [
ctypes.POINTER(glp_prob),
ctypes.c_int, # ith row
ctypes.POINTER(ctypes.c_int), # col indices
ctypes.POINTER(ctypes.c_double), # values
]

_lib.glp_get_row_type.restype = ctypes.c_int
_lib.glp_get_row_type.argtypes = [
ctypes.POINTER(glp_prob),
ctypes.c_int, # ith row
]

_lib.glp_get_row_lb.restype = ctypes.c_double
_lib.glp_get_row_lb.argtypes = [
ctypes.POINTER(glp_prob),
ctypes.c_int, # ith row
]

_lib.glp_get_row_ub.restype = ctypes.c_double
_lib.glp_get_row_ub.argtypes = [
ctypes.POINTER(glp_prob),
ctypes.c_int, # ith row
]

_lib.glp_get_col_type.restype = ctypes.c_int
_lib.glp_get_col_type.argtypes = [
ctypes.POINTER(glp_prob),
ctypes.c_int, # jth col
]

_lib.glp_get_col_lb.restype = ctypes.c_double
_lib.glp_get_col_lb.argtypes = [
ctypes.POINTER(glp_prob),
ctypes.c_int, # jth col
]

_lib.glp_get_col_ub.restype = ctypes.c_double
_lib.glp_get_col_ub.argtypes = [
ctypes.POINTER(glp_prob),
ctypes.c_int, # jth col
]

_lib.glp_get_status.restype = ctypes.c_int
_lib.glp_get_status.argtypes = [ctypes.POINTER(glp_prob)]

Expand Down Expand Up @@ -346,5 +404,23 @@ def __init__(self, libpath):
_lib.glp_delete_prob.restype = None
_lib.glp_delete_prob.argtypes = [ctypes.POINTER(glp_prob)]

# Utility
_lib.glp_read_mps.restype = ctypes.c_int
_lib.glp_read_mps.argtypes = [
ctypes.POINTER(glp_prob),
ctypes.c_int, # format (GLP_MPS_DECK or GLP_MPS_FILE)
ctypes.POINTER(glp_mpscp), # should be NULL
ctypes.c_char_p, # filename
]

_lib.glp_write_mps.restype = ctypes.c_int
_lib.glp_write_mps.argtypes = [
ctypes.POINTER(glp_prob),
ctypes.c_int, # format (GLP_MPS_DECK or GLP_MPS_FILE)
ctypes.POINTER(glp_mpscp), # should be NULL
ctypes.c_char_p, # filename
]


# Make accessible for front-end interface
self._lib = _lib
26 changes: 26 additions & 0 deletions test_mps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'''Example showing how to use mpsread/write.'''

from scipy.optimize import linprog

from glpk import mpsread

if __name__ == '__main__':

libpath = '/home/nicholas/Downloads/glpk-4.65/src/.libs/libglpk.so'

filename = '~/Documents/HiGHS/check/instances/25fv47.mps'

lp = mpsread(filename, libpath=libpath)
c, A_ub, b_ub, A_eq, b_eq, bounds = lp

if A_ub is not None:
print(A_ub.nnz)
A_ub = A_ub.todense()
print(A_ub)
print(len(b_ub), c.shape)
print(A_ub.shape)
if A_eq is not None:
A_eq = A_eq.todense()

res = linprog(c, A_ub, b_ub, A_eq, b_eq, bounds)
print(res)

0 comments on commit 2ffd3b4

Please sign in to comment.