SWIG-based Interfaces for Mathematical Programming
swIMP (SWIG-based Interfaces for Mathematical Programming) aims at making solvers written in C or C++ available for other languages. The current focus is on Java as target language and on LP/IP-solvers which are compatible to the Open Solver Interface (OSI) from the Coin-OR-project. This includes both Open Source solvers as well as reknown commercial solvers like CPLEX and Xpress (see Features).
swIMP comes with a binary distribution of several Coin-OR-solvers for Linux/x86-machines that takes just a few minutes to install.
The wrappers are implemented using the generator tool SWIG. SWIG generates both C++ code which is then compiled into a shared library and Java-code which accesses the shared library through the Java Native Interface (JNI). In principle, SWIG also supports other target languages like Python or Perl but this would require non-trivial modifications of the SWIG interface definitions currently provided by swIMP.
The swIMP project was started as a subproject of Combean. Combean is a Java framework for mathematical structures and optimization algorithms. Among other features it contains a convenient framework for constructing complex linear programming models. If you are going to use swIMP, you might thus also want to consider combining it with Combean.
Keywords: Java, Linear Programming, LP, Integer Programming, IP, Operations Research, OR, OSI, Coin, Clp, Symphony, CPLEX, Xpress, GLPK, MOSEK, SoPlex, SWIG, JNI, Open Source.
swIMP is distributed under the GNU Lesser General Public License.
swIMP comes with a binaries of Jakarta Commons, JUnit and Log4J. Please consider the LICENSE-files in the dist-directory for a detailed description of these 3rd party libraries. Source-code distributions of these libraries can be obtained at the given URLs.
There is also a binary distribution of swIMP for Linux on x86-machines. This distribution contains shared libraries in binary form for the Clp, Cbc, SYMPHONY and Vol solvers , as well as the OSI C++-frontend for these solvers (all from COIN-OR project). Please refer to the coin-directory in the binary distribution for a detailed description of the Coin-license. A source code distribution of COIN-OR-solvers can be obtained at the given COIN-OR project home page.
Furthermore, the binary distribution contains a the Osi-frontend for the GLPK-solver. Since GLPK is distributed under the GPL, it may not be distributed only in binary form. If you want to use the GLPK-solver, please obtain and install it yourself. The library that comes with the binary distribution will require the GLPK shared library in your system's library path (LD_LIBRARY_PATH on Linux machines).
swIMP is available for download at the Sourceforge project page.
swIMP is in beta-state and has been tested with a quite comprehensive test suite. We would be very much interested if you encounter any bugs or difficulties with the API as we would like to ensure that the quality is optimum before declaring the code ready for production.
In general, any feedback is highly welcome. You may consider using the Sourceforge tracking utility or the forums
The following solvers are currently supported:
Support for the following solvers should be easy to add (at most one day of work or so) but has not yet been added because I have no licenses for these solvers and can thus not test their integration (even though it should work out of the box with their OSI-frontend). A patch for including one of these solvers would of course be highly welcome:
./configure make forcegen # can be skipped, if all supported solvers are available. see below. make make check # (optional) make installshall suffice to build the shared library. You may want to give some arguments to configure, e.g.
./configure --prefix=/install/path \ CPPFLAGS="-I/path/to/coin/include" LDFLAGS="-L/path/to/coin/lib"
If you don't give any arguments to configure, swIMP will be compiled against the solvers in the binary distribution. This will not work if you are not on a Linux/x86-machine. Please use the switch --disable-binbundle in order to disable this behavior.
Make sure that the path where the shared library is installed is accessible by the dynamic linker. Under Linux this means that the path either has to be contained in /etc/ld.so.conf (remember to run ldconfig after changing the setting) or in the environment variable LD_LIBRARY_PATH. If you use the binaries that come with swIMP, it suffices to source the script swimpEnv.sh.
After the build, several jar-files (one per solver) are located in the dist-directory. You may want to put them to a more convenient place where you store other jars (like /usr/local/share/java) and include it in your CLASSPATH.
jars that swIMP depends on and which do not come with swIMP can be made available in two ways:
Of course, using swIMP only makes sense if you have some LP solvers installed that you would like to access through swIMP. If you do not want to/cannot use the binaries that come with swIMP, a quick way to get you started (if you don't have the solvers installed already) is as follows:
The ./configure script of swIMP tries to find out which LP solvers are installed at your site. This is done by checking whether header files of the given solvers are available for compilation. The following header files are used for this check:
|Solver||Corresponding header file|
If a header is found, the wrapper classes (both C++ and Java) for the corresponding solver are generated, otherwise the unavailable solver is excluded from the build. Please examine the output of ./configure to find out whether all the solver that you expect are indeed accessible during the build. For example the output
checking VolVolume.hpp usability... yes checking VolVolume.hpp presence... yes checking for VolVolume.hpp... yes checking symphony.h usability... no checking symphony.h presence... nomeans that the Vol-solver has been found but the SYMPHONY solver is not available. Please note that ./configure only checks the availability of the header file and not of the library of the solver. If the library is not accessible (e.g. due to a wrong LDFLAGS-setting), you will get an error during linking.
Currently, swIMP is distributed with a version of the generated C++ and Java classes which contains wrappers for all supported solvers except MOSEK (since MOSEK is a commercial solver and not everybody may have access to it). If this works for you, you do not need to invoke 'make forcegen' and in particular you will not need to install SWIG on your machine. If not all solver are available, however, you have to regenerate the wrappers by running 'make forcegen' first. Of course, this requires SWIG.
Alternatively, you can patch the file iface/coin_wrap.cxx. This is fairly easy. The only thing that has to be done is to comment out the JNI wrapper functions for the unavailable solver. In the future this shall be achieved by including suitable #ifdef's in coin_wrap.cxx but unfortunately I do not see a way to achieve this with SWIG directly and writing some kind of awk postprocessor or so looks like a quite ugly solution.
swIMP comes with a tool that tries to load the supported native libraries and reports which libraries are available. Simply, setup your class path to contain swimp.jar and execute probeSolvers.sh. By executing probeSolvers.sh -h you can get a description which shows further options provided by the tool.
When the shared library is available through the dynamic linker, you can execute the automatic test suite. This is done by executing
make testand test results will be written in the subdirectory testrep. The difference between 'make check' and 'make test' is that make test will execute the tests using your environment, whereas 'make check' uses the local copy of the library before installation. Thus, 'make test' checks your installation and not just the correctness of the build.
If you get an error message like
Testsuite: net.sourceforge.swimp.test.coin.TestCoinShallowPackedVectorBase Tests run: 1, Failures: 0, Errors: 1, Time elapsed: 0,013 sec Testcase: testMethodsOfDerivedClasses took 0,008 sec Caused an ERROR no swIMP in java.library.path java.lang.UnsatisfiedLinkError: no swIMP in java.library.path at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1517) at java.lang.Runtime.loadLibrary0(Runtime.java:788) at java.lang.System.loadLibrary(System.java:834) at net.sourceforge.swimp.coin.coinJNI.you should check your dynamic linker settings (i.e. your LD_LIBRARY_PATH on a Linux system).
(coinJNI.java:44) at net.sourceforge.swimp.coin.IntArray. (IntArray.java:41) at net.sourceforge.swimp.coin.coin.jarrayToSwig(coin.java:39) at net.sourceforge.swimp.test.coin.TestCoinShallowPackedVectorBase.setUp (TestCoinShallowPackedVectorBase.java:53)
Since version 0.9 swIMP uses a hand-tailored SWIG-mapping that hands Java-array of type int or double directly down to the C++ library layer. There is no copying of data involved. Measurements show that the overhead for using a Java-array in comparison to using a SWIG-generated wrapper for a C++-array (basically a representation of the pointer to the C++-array as a Java-long) is negligible.
Caveat: This mapping is based on the assumption that the data types jint and jdouble, used by JNI (Java Native Interface) and the native C++ data types int and double are identical. This is the case for the environment where we develop swIMP and we hope that this will be the case for most swIMP users. swIMP will stop the build process with an error if this assumption is not justified. In that case, please report this to the Sourceforge support tracker. If we see that there is need for that in the swIMP-user community, we will add an alternative mapping, which requires a bit more computational overhead but which will work without any assumptions on the structure of the data types jint and jdouble.
We have also compared the performance of swIMP-generated code with native C++-code. You can run our simple performance test suite by using the command make perftest. This show the times for calls to the methods setVector and setConstant of CoinPackedVector in the following three cases:
[exec] setVector(int, int*, double*): size=1000000, numVals=30000: 1060 (ms) [exec] setConstant(int, int*, double): size=1000000: 1040 (ms) [java] CoinPackedVector.setVector(Java): size=1000000, numVals = 30000: [java] count = 1 total = 1379 (ms) average = 1379.0 (ms) [java] CoinPackedVector.setVector(SWIG): size=1000000, numVals = 30000: [java] count = 1 total = 1333 (ms) average = 1333.0 (ms) [java] CoinPackedVector.setConstant(Java): size=1000000: [java] count = 1 total = 1326 (ms) average = 1326.0 (ms) [java] CoinPackedVector.setConstant(SWIG): size=1000000: [java] count = 1 total = 1280 (ms) average = 1280.0 (ms)