GLPK/Third-party API wrappers

This page describes "wrapper" classes which interface with the native GLPK API set to provide additional functionality. This page will be mostly of interest to programmers developing large applications.

The GLPK APIs are, in many respects, relatively low-level and not particularly smart (but they are improving). C++ developers, in particular, sometimes write wrapper classes to interface between GLPK and their client code. Their motivation normally stems from a desire for one or both features:

the provision of a higher-level and perhaps more tailored and more intelligent client call set

the ability to switch solvers without disturbing client code — as defined by the need to relink but not recompile.

Intelligence, in this context, includes the ability to maintain row and column counts internally, to recognize incomplete models, to select particular solver calls, to fail gracefully, and other related adaptive behaviors.

Both of the above aspects require design trade-offs, which means that API wrappers tend to be situation-specific to some degree. For instance, the ability to switch solvers may need to exclude specialist solver features in the interests of maintaining commonality.

Given the ongoing GLPK initiative to update its API set, the OsiGlpk code currently relies on depreciated APIs (as at December 2010, a 2008 ticket seeking alignment remains open [1]). This may not be an issue for LP problems but could be an issue for branch-and-cut methods. Developers are advised to confirm (and perhaps revise) this interface class before proceeding. COIN-OR Osi is otherwise under steady development.

Glop, the Generic Linear Optimization Package, is a library package that provides functions to create, manipulate and solve linear programs (LPs) from within your C or C++ program. Glop is mainly a wrapper library which allows the user to access different existing LP solvers through the same API. Glop supports GLPK and was written by Francois Galea.

LEMON is the Library for Efficient Modeling and Optimization in Networks.[2] This is a C++ template library providing a wide range of data structures and algorithms for "combinatorial optimization tasks connected mainly with graphs". GLPK is one of several solvers supported by LEMON.

The LEMON project was launched in 2003 by the Egerváry Research Group on Combinatorial Optimization (EGRES) at the Department of Operations Research, Eötvös Loránd University, Budapest, Hungary. LEMON is a member of the COIN-OR initiative, a collection of OR related open source projects. LEMON is distributed under the Boost Software License version 1.0, a permissive license enabling both commercial and non-commercial use. The Boost license is GPL-compatible. The project maintains an extensive website with user documentation, source browsing, and bug-tracking. It also operates several mailing lists.

The reason this works is that the C++ standard mandates a std::vector be held in contiguous memory. To this end, Josuttis (1999 p155) writes:[3]

"this example shows that whenever you need an array of type T for any reason (such as for an existing C library) you can use a std::vector<T> and pass it the address of the first element"

This idiom will fail just as surely as a C-style array if you try to read or write out-of-range — but it will throw a C++ exception with a more understandable error message. You can even catch the exception and then exit a little more gracefully if you wish. For example:

glp_prob*lp;try{// most of the above code in here}catch(conststd::out_of_range&e){std::cout<<"e.what()"<<std::endl;// any mopping up}glp_delete_prob(lp);glp_free_env();

Do not be tempted to reserve more capacity in your vectors at a later point — reallocation will automatically invalidate all references, pointers, and iterators!

If programming under the C++11 standard, you can use initialization lists (to save all the std::vector::push_back calls):

// load the structural matrix data using initialization listsstd::vector<int>iat={1,1,2,2};std::vector<int>jat={1,2,1,2};std::vector<double>art={1.0,2.0,3.0,1.0};// now prepend the required position zero placeholder (any value will do but zero is safe)// first create length one vectors using default member constructionstd::vector<int>iav(1);std::vector<int>jav(1);std::vector<double>arv(1);// then concatenate these with the original data vectorsiav.insert(iav.end(),iat.begin(),iat.end());jav.insert(jav.end(),jat.begin(),jat.end());arv.insert(arv.end(),art.begin(),art.end());// then load the structural matrix dataglp_load_matrix(lp,9,&iav[0],&jav[0],&arv[0]);// was: glp_load_matrix(lp, 9, ia, ja, ar)

The std::vector::insert calls are required because GLPK indexes from unity but C++ indexes from zero. Note too that std::deque containers do not guarantee contiguous use of memory.