1. 程式人生 > >幹貨 數學規劃求解器lp_solve超詳細教程

幹貨 數學規劃求解器lp_solve超詳細教程

sed them 點擊 容易 nic -c tis 彈出 工具箱

前言

最近小編學了運籌學中的單純形法。
於是,很快便按奈不住跳動的心。
這不得不讓我拿起紙和筆思考著,
一個至關重要的問題:
如何用單純形法裝一個完備的13?
技術分享圖片

恰巧,在我坐在圖書館陷入沈思的時候,
一位漂亮的×××姐靠過來,
說:“同學,你是在看線性規劃嗎?
你能幫我看看這道題該怎麽解好嗎?”

納尼?還真是瞌睡來了送枕頭。
但是,盡管心裏萬馬奔騰,
還是要裝作若無其事的樣子,蛋蛋一笑。
“這個啊,簡單!讓我來算算。”
技術分享圖片

但是一拿到題目之後,掃了一眼。
驚得差點沒把筆吞下去。
這……城裏人都這麽會play的嗎?
我*,25個變量。
看著那一堆約束條件,
看著這堆變量x1,x2,x3,...,x25。
總感覺,這次真的是玩脫了。
技術分享圖片

用Table?開什麽國際玩笑,

且不說這得算到猴年馬月,
在這期間如果搞錯一個數,
那簡直比吃了老壇酸菜牛肉面還酸爽。

用C++,
寫個Simple algorithm用電腦跑一跑?
但是,像小編這種,
上不知虛函數,下不曉純虛函數,
左不清explicit,右不明volatile。
連虛函數表都說不清道不明的小白,
打個simple algorithm的拼寫還差不多。

技術分享圖片

氣氛陷入了尷尬的沈默,
沈默是今晚的康橋。
在我快急哭了的時候,
×××姐卻淡淡一笑。

“解不出來嗎?”
“嗯……這個是有點麻煩。”
“哈哈~解不出來也沒關系啦。
哎,學弟你想考托福雅思嗎?”
×××姐話鋒一轉。“嗯哼???”
“我知道有幾家托福雅思的培訓機構,
那裏的老師很厲害,
你可以了解一下哦。”

“……”
“……”

技術分享圖片

不過話說回來,
對於復雜的線性規劃問題,
特別是變量很多的那種,
有什麽辦法呢?
難道真的要親自擼一遍單純形法?
那你就真的是out了。

今天給大家介紹一款神器:lpsolve
一款狂拽炫酷吊炸天阿姆斯特朗回旋加速棒棒的神器。

技術分享圖片

Part1

科普篇

lpsolve是什麽?

lpsolve是sourceforge下的一個開源項目,它的介紹如下:
Mixed Integer Linear Programming (MILP) solver lp_solve solves pure linear, (mixed) integer/binary, semi-cont and special ordered sets (SOS) models.lp_solve is written in ANSI C and can be compiled on many different platforms like Linux and WINDOWS

它的特點有:

  • Linear and Integer programming solver
  • Sensitivity analysis
  • Very strong API with many programming language examples
  • IDE
  • Open source
  • Pure C code
  • Windows, Unix, Linux, Mac OSX
  • 32 and 64 bit
  • Also precompiled binaries provided

它是一個混合整數線性規劃求解器,可以求解純線性、(混合)整數/二值、半連續和特殊有序集模型。並且經過實際驗證,有極高的求解效率。

應用領域:科學與研究,高級用戶終端,程序開發等

開發語言:C

應用平臺:可應用於Linux和WINDOWS等所有平臺。

相關資源sourceforge主頁:http://sourceforge.net/projects/lpsolve/?source=directory

有關lpsolve的所有資源都可以在這個主頁上找到。
包括本文後面介紹的所有文件。

技術分享圖片

有關lpsolve的詳細說明文檔:http://web.mit.edu/lpsolve/doc/

Part2

入門篇

簡單上手

看完了上面的介紹,相信大部分小夥伴還是一臉懵逼。說了這麽多牛逼,轉了半天,還沒告訴我怎麽用呢!(汗)

技術分享圖片

小編也不指望大家能耐下心來好好去讀那讓人頭大的英語說明文檔了。今天,本編就帶領大家一步一步上手這個神器的求解器……

說到這裏,可能有小夥伴又不樂意了,不會又要擼代碼吧?呃……不擼代碼是不可能了,這輩子都不可能了。

好在,天無絕人之路,lpsolver也提供了一個簡易的IDE(別問我什麽是IDE。IDE就是集成開發環境Integrated Development Environment ),提供給像小編這種小白使用。下面就給大家慢慢道來。

LPSolve

IDELPSolve

DE可謂是大大方便了各位新手朋友了。它的界面還算友好,功能十分強大。

界面如下:

技術分享圖片

它的介紹如下:
The LPSolve IDE (Integrated Development Interface) is a very user friendly Windows interface to the lpsolve API. All functionality of lpsolve can be accessed via a graphical and very user friendly application.

Many thanks to Henri Gourvest for making this nice interface to lpsolve and making it available to the community.

它的幾個特點如下:

  • Everything is graphical and mouse controled
  • Enter your lp model in all supported formats and even via an XLI interface (See External Language Interfaces)
  • Convert your lp model from any supported format to another supported format and even via an XLI interface (See External Language Interfaces)
  • Very user friendly editor to enter/change the model with syntax highlight.
  • Syntax checking of the model
  • Solve the model
  • See the results in grids
  • Control every possible lpsolve option (tolerances, presolve, scaling, ...)
  • View the matrix in grids
  • Export model to HTML, RTF, LaTeX output
  • Export matrix to CSV, HTML, RTF output
  • Export results to CSV, HTML, RTF output
  • Show statistics about the model.

...只需要把需要求解的線性規劃問題輸入到求解器裏面,然後點一下綠色的run按鈕,就能馬上出結果了。

技術分享圖片

如下面所示:

技術分享圖片

關於x,y的取值和目標最優值已經求出來了。還可以進行靈敏度等相關分析:
技術分享圖片

上面對應每個約束的條件的影子價格,以及變化範圍等等一應俱全。此外,lpsolveIDE還提供了很多選項,大家根據自己的需要勾選相應的功能即可。

技術分享圖片

IDE的使用很簡單,在這裏不再詳細說明了。另外輸入語法格式等問題,可以點下面的鏈接查看詳細說明:http://web.mit.edu/lpsolve/doc/
在左側列表定位到lp file format 即可。

另外,lpsolve還支持其他求解器的語法格式。具體有以下:

  • MPS file format
  • CPLEX lp file format
  • LINDO lp file format
  • GNU MathProg file format
  • LPFML XML file format

具體說明也可以點擊上面提供的鏈接,左側定位到
Formulation of an lp model in lpsolve 即可。

怎樣?是不是很神奇?

技術分享圖片

Part3

進階篇

MPL下調用lpsolve

有些同學問我MPL是什麽,我……,MPL就是Mathematical Programming Language 數學編程語言。lpsolve支持很多數學編程語言,有:

  • AMPL
  • MATLAB
  • O-Matrix
  • Sysquake
  • Scilab
  • Octave
  • FreeMat
  • Euler
  • Python
  • Sage
  • PHP
  • R
  • Microsoft Solver Foundation

礙於文章篇幅等原因,小編選取幾種常用的數學編程語言,來給大家演示怎麽在程序裏使用lpsolve求解相關線性規劃問題。

matlab下使用lpsolve環境配置在sourceforge網站(https://sourceforge.net/projects/lpsolve/files/lpsolve/5.5.2.0/)

下載相應系統所需的文件,如需配置matlab中的lpsolve則下載xxx_dev_win64/32以及xxx_MATLAB_exe_win64/32,不過在此之前你需要先確認自己的操作系統是多少位的,一般來說都是64位的Windows 10操作系統了。 如圖所示:

32位系統請下載這兩個文件:

技術分享圖片

技術分享圖片

64位系統請下載這兩個文件:
技術分享圖片

技術分享圖片

由於小編的電腦是64位win 10系統,所以下面的演示都是基於64位Windows系統的演示。
將下載的兩個文件夾解壓:

技術分享圖片

先進入文件夾lp_solve_5.5.2.0_MATLAB_exe_win64:

技術分享圖片

將解壓後...\lp_solve_5.5.2.0_MATLAB_exe_win64\bin\win64目錄下的mxlpsove.mexw64拷貝到...\lp_solve_5.5.2.0_MATLAB_exe_win64根目錄下,如圖所示:

技術分享圖片

技術分享圖片

註意:如果系統是32位的,則將mxlpsolve.dll文件一同拷貝到根目錄下。
下面設置 matlab 的 path 變量,使其能搜索到 lp_solve_5.5.2.0_MATLAB_exe_win32 目錄,在 命令行窗口中輸入: pathtool,並添加剛剛解壓設置好的lp_solve_5.5.2.0_MATLAB_exe_win32 目錄到 path 中,保存。設置如下圖:

技術分享圖片

這時心急的小夥伴感覺打開MATLAB運行一下,結果還是會出錯。會提示:

技術分享圖片

這下哦豁了。心急吃不了熱豆腐,我們還需要在做一步工作。在之前下載的lp_solve_5.5.2.0_dev_win64文件夾中找到lpsolve55.dll文件,

技術分享圖片

然後在matlab命令行窗口輸入“!path”命令 (註意,不是 path 命令,前面多了個英文狀態下的感嘆號) ,輸出結果包含一堆路徑:

PATH=C:\Program Files\MATLAB\R2014b\bin\win64;C:\ProgramData\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;.....(此處省略一萬字).....;C:\Users\xuesheng\AppData\Local\GitHubDesktop\bin;

其中每個目錄都是以分號隔開的。我們lpsolve55.dll文件拷貝到任意一個目錄下都可行的,如果不可行,那原因很有可能是(敲黑板!)因為下載的.dll文件版本不是對應64位的,如果是按照第一步下載的dev壓縮包,那應該是不會出問題的。

在 matlab 中 輸入 mxlpsolve 命令進行測試,如果輸出如下信息表明配置成功。則可以愉快的運行啦~:
mxlpsolve MATLAB Interface version 5.5.0.6using lpsolve version 5.5.2.0Usage: [ret1, ret2, ...] = mxlpsolve(‘functionname‘, arg1, arg2, ...)

至此,環境配置完成。

如何調用

以一個具體的例子說明用lpsolve求解數學規劃問題的方法。

假設我們要用matlab解決如下線性規劃問題:

max x1 + 3x2 + 6.24x3 + 0.1x4
s. t. 78.26x2 + 2.9x4 >= 92.3

0.24x1 + 11.31x3 <= 14.8
12.68x1 + 0.08x3 + 0.9x4 >= 4
x1 >= 28.6
x4 >= 18
x4 <= 48.98

matlab語句如下:

 1>> lp=mxlpsolve(‘make_lp‘, 0, 4);
 2>> mxlpsolve(‘set_verbose‘, lp, 3);
 3>> mxlpsolve(‘set_obj_fn‘, lp, [1, 3, 6.24, 0.1]);
 4>> mxlpsolve(‘add_constraint‘, lp, [0, 78.26, 0, 2.9], 2, 92.3);
 5>> mxlpsolve(‘add_constraint‘, lp, [0.24, 0, 11.31, 0], 1, 14.8);
 6>> mxlpsolve(‘add_constraint‘, lp, [12.68, 0, 0.08, 0.9], 2, 4);
 7>> mxlpsolve(‘set_lowbo‘, lp, 1, 28.6);
 8>> mxlpsolve(‘set_lowbo‘, lp, 4, 18);
 9>> mxlpsolve(‘set_upbo‘, lp, 4, 48.98);
10>> mxlpsolve(‘set_col_name‘, lp, 1, ‘COLONE‘);
11>> mxlpsolve(‘set_col_name‘, lp, 2, ‘COLTWO‘);
12>> mxlpsolve(‘set_col_name‘, lp, 3, ‘COLTHREE‘);
13>> mxlpsolve(‘set_col_name‘, lp, 4, ‘COLFOUR‘);
14>> mxlpsolve(‘set_row_name‘, lp, 1, ‘THISROW‘);
15>> mxlpsolve(‘set_row_name‘, lp, 2, ‘THATROW‘);
16>> mxlpsolve(‘set_row_name‘, lp, 3, ‘LASTROW‘);
17>> mxlpsolve(‘write_lp‘, lp, ‘a.lp‘);
18>> mxlpsolve(‘get_mat‘, lp, 1, 2)
19
20ans =
21
22   78.2600
23
24>> mxlpsolve(‘solve‘, lp)
25
26ans =
27
28     0
29
30>> mxlpsolve(‘get_objective‘, lp)
31
32ans =
33
34   31.7828
35
36>> mxlpsolve(‘get_variables‘, lp)
37
38ans =
39
40   28.6000
41         0
42         0
43   31.8276
44
45>> mxlpsolve(‘get_constraints‘, lp)
46
47ans =
48
49   92.3000
50    6.8640
51  391.2928

如果需還要其他功能,請參考包含完整API文檔的網址(重要,推薦看!!!):http://web.mit.edu/lpsolve/doc/MATLAB.htm

從以上的過程我們看到用 lpsolve 建立一個規劃問題的代碼還是夠麻煩的,想必你剛開始看到上面那些語句的時候,也是一頭霧水。不要著急,對於這類簡單的問題,還有更簡便的方法。

lpsolve 為我們提供了一種簡化的途徑,我們註意到以上文件列表中有一個lp_maker.m和lp_solve.m文件。lp_maker.m文件的功能是創建一個(混合整數)線性規劃問題,調用格式類似於其他matlab自帶的優化工具箱,你只需要為它提供f、A、b、l、u幾個矩陣,它會自動為你實現創建模型、設置目標函數、添加約束的過程

從以上的過程我們看到用 lpsolve 建立一個規劃問題的代碼還是夠麻煩的,想必你剛開始看到上面那些語句的時候,也是一頭霧水。不要著急,對於這類簡單的問題,還有更簡便的方法。

Python下使用lpsolve

環境配置

lpsolve目前最新也只能支持到Python2.6版本而已了,所以下面的演示也是基於Python2.6版本的,系統是64位Windows10系統。

首先大家根據自己的系統版本下載相應的包。

技術分享圖片

然後在電腦上把Python2.6版本也給裝上。

把剛剛下載的包解壓出來,找到如下文件,雙擊安裝,然後×××即可。(註意,此步要先安裝好Python2.6版本。)

技術分享圖片
技術分享圖片

最後還有一步,就是把之前lp_solve_5.5.2.0_dev_win64包下的dll文件復制到C:\Windows\System32目錄裏面。

技術分享圖片

復制到C:\Windows\System32:
技術分享圖片

最後,打開Python2.6(如果電腦裝了多個Python,註意打開的版本。),輸入:

\>>> from lpsolve55 import *
\>>> lpsolve()
如果顯示以下信息,則大功告成:
技術分享圖片

至此,環境配置已經完成。
Python調用

在Python下,lpsolve 同樣為我們提供了一種簡化的途徑。直接舉個例子吧。

假如我們要用Python解決以下線性規劃問題:

max 4x1 + 2x2 + x3
s. t. 2x1 + x2 <= 1
x1 + 2x3 <= 2
x1 + x2 + x3 = 1
x1 >= 0
x1 <= 1
x2 >= 0
x2 <= 1
x3 >= 0
x3 <= 2

從中我們可以得出幾個相關矩陣:

f = [4, 2, 1]
A = [[2, 1, 0], [1, 0, 2], [1, 1, 1]]
b = [1, 2, 1]

註意到我們的單個變量約束並沒有放進條件約束裏面,lp_solve 可以設置單個變量的界限,它們是:

l = [ 0, 0, 0]
u = [ 1, 1, 2]

現在在Python裏輸入下面代碼:

1>>> f = [4, 2, 1]
2>>> A = [[2, 1, 0], [1, 0, 2], [1, 1, 1]]
3>>> b = [1, 2, 1]
4>>> l = [ 0, 0, 0]
5>>> u = [ 1, 1, 2]

然後開始求解我們的問題:

 1>>> from lpsolve55 import *
 2>>> from lp_maker import *
 3>>> lp = lp_maker(f, A, b, [-1, -1, 0], l, u, None, 1, 0)
 4>>> solvestat = lpsolve(‘solve‘, lp)
 5>>> obj = lpsolve(‘get_objective‘, lp)
 6>>> print obj
 72.5
 8>>> x = lpsolve(‘get_variables‘, lp)[0]
 9>>> print x
10[0.5, 0.0, 0.5]
11>>> lpsolve(‘delete_lp‘, lp)

關於Python下使用lpsolve的更多說明,請訪問:http://web.mit.edu/lpsolve/doc/ ,

左側定位到Using lpsolve from Python即可。

Part4

實戰篇

高級編程語言使用lpsolve

上面講了幾種MPL怎麽調用lpsolve,可能又有部分小夥伴不樂意了。咱平時擼的都是C/C++、Java這等高級語言的代碼啊,哪裏用過什麽MATLAB什麽的。別急,萬能lpsolve怎麽可能不支持高級編程語言呢!下面小編就一一為各位看官道來。

lpsolve支持以下幾種編程語言:

  • C/C++
  • Java
  • Delphi, Free Pascal
  • VB, VBScript
  • http://VB.NET
  • C#.NET

官方介紹如下:

In several cases it is required that the solver is called from within the programming language in which an application is build. All the data is in memory and no files are created to provide data to the solver. lpsolve has a very rich, yet easy, API to do this.

礙於文章篇幅,我們還是挑幾個大家常用的語言來講解吧~。

C/C++使用lpsolve

在C/C++下配置lpsolve確實有點麻煩,所以,這裏大家一定要看仔細,操作仔細了。每一步都不能出錯,不然很難把程序編譯出來的。

首先,大家找到去在sourceforge網站(https://sourceforge.net/projects/lpsolve/files/lpsolve/5.5.2.5/)把這個文件下載下來:

技術分享圖片

為什麽是下載32位的文件呢,因為我們編譯的程序是x86程序,所以用的是32位的鏈接庫,下載後解壓出來,得到lp_solve_5.5.2.5_dev_win32 文件夾:

技術分享圖片

小編用的編譯器是微軟的Visual Studio 2017。無論什麽編譯器,都需要確保以下幾點才能運行成功:

  1. 添加頭文件目錄
  2. 添加庫文件目錄
  3. 鏈接時把庫文件添加進去

下面小編以自己的編譯環境為例,配置一下。

打開Visual Studio 2017,新建一個空項目,名字隨便寫,這裏寫的是lptest。
技術分享圖片

然後在右側解決方案資源管理器裏面-源文件裏面添加一個.c文件。代碼先別寫,後面會給出。

技術分享圖片

配置頭文件目錄,在右側解決方案資源管理器裏面找到項目名稱,右鍵屬性:

技術分享圖片

包含目錄庫目錄裏面將我們的lp_solve_5.5.2.5_dev_win32文件夾路徑添加進去,這個文件夾包含了程序所需的頭文件庫文件目錄

技術分享圖片

最後,就是在程序開頭,將這一句話添加進去,表示鏈接目標文件時,將lpsolve庫給鏈接進去。否則,編譯器將找不到函數的定義而報一堆錯誤。

技術分享圖片

可能,這樣設置一開始代碼還是不能編譯成功,小編在好幾臺電腦上測試了,不知道是不是編譯器的BUG。大家設置好以後生成提示未定義標識符之類的,請關掉編譯器,重新打開,多試幾次。

至此,環境配置完成。可以開始寫代碼了。下面一個代碼演示了求解一個線性規劃模型的示範,註釋也說得足夠清楚了,大家直接看代碼吧。

  1#include "lp_lib.h"
  2   # define WIN32
  3#pragma comment(lib, "lpsolve55.lib")
  4
  5int demo()
  6{
  7    lprec *lp;
  8    int Ncol, *colno = NULL, j, ret = 0;
  9    REAL *row = NULL;
 10
 11    /* We will build the model row by row
 12    So we start with creating a model with 0 rows and 2 columns */
 13    Ncol = 2; /* there are two variables in the model */
 14    lp = make_lp(0, Ncol);
 15    if (lp == NULL)
 16        ret = 1; /* couldn‘t construct a new model... */
 17
 18    if (ret == 0) {
 19        /* let us name our variables. Not required, but can be useful for debugging */
 20        set_col_name(lp, 1, "x");
 21        set_col_name(lp, 2, "y");
 22
 23        /* create space large enough for one row */
 24        colno = (int *)malloc(Ncol * sizeof(*colno));
 25        row = (REAL *)malloc(Ncol * sizeof(*row));
 26        if ((colno == NULL) || (row == NULL))
 27            ret = 2;
 28    }
 29
 30    if (ret == 0) {
 31        set_add_rowmode(lp, TRUE);  /* makes building the model faster if it is done rows by row */
 32
 33                                    /* construct first row (120 x + 210 y <= 15000) */
 34        j = 0;
 35
 36        colno[j] = 1; /* first column */
 37        row[j++] = 120;
 38
 39        colno[j] = 2; /* second column */
 40        row[j++] = 210;
 41
 42        /* add the row to lpsolve */
 43        if (!add_constraintex(lp, j, row, colno, LE, 15000))
 44            ret = 3;
 45    }
 46
 47    if (ret == 0) {
 48        /* construct second row (110 x + 30 y <= 4000) */
 49        j = 0;
 50
 51        colno[j] = 1; /* first column */
 52        row[j++] = 110;
 53
 54        colno[j] = 2; /* second column */
 55        row[j++] = 30;
 56
 57        /* add the row to lpsolve */
 58        if (!add_constraintex(lp, j, row, colno, LE, 4000))
 59            ret = 3;
 60    }
 61
 62    if (ret == 0) {
 63        /* construct third row (x + y <= 75) */
 64        j = 0;
 65
 66        colno[j] = 1; /* first column */
 67        row[j++] = 1;
 68
 69        colno[j] = 2; /* second column */
 70        row[j++] = 1;
 71
 72        /* add the row to lpsolve */
 73        if (!add_constraintex(lp, j, row, colno, LE, 75))
 74            ret = 3;
 75    }
 76
 77    if (ret == 0) {
 78        set_add_rowmode(lp, FALSE); /* rowmode should be turned off again when done building the model */
 79
 80                                    /* set the objective function (143 x + 60 y) */
 81        j = 0;
 82
 83        colno[j] = 1; /* first column */
 84        row[j++] = 143;
 85
 86        colno[j] = 2; /* second column */
 87        row[j++] = 60;
 88
 89        /* set the objective in lpsolve */
 90        if (!set_obj_fnex(lp, j, row, colno))
 91            ret = 4;
 92    }
 93
 94    if (ret == 0) {
 95        /* set the object direction to maximize */
 96        set_maxim(lp);
 97
 98        /* just out of curioucity, now show the model in lp format on screen */
 99        /* this only works if this is a console application. If not, use write_lp and a filename */
100        write_LP(lp, stdout);
101        /* write_lp(lp, "model.lp"); */
102
103        /* I only want to see important messages on screen while solving */
104        set_verbose(lp, IMPORTANT);
105
106        /* Now let lpsolve calculate a solution */
107        ret = solve(lp);
108        if (ret == OPTIMAL)
109            ret = 0;
110        else
111            ret = 5;
112    }
113
114    if (ret == 0) {
115        /* a solution is calculated, now lets get some results */
116
117        /* objective value */
118        printf("Objective value: %f\n", get_objective(lp));
119
120        /* variable values */
121        get_variables(lp, row);
122        for (j = 0; j < Ncol; j++)
123            printf("%s: %f\n", get_col_name(lp, j + 1), row[j]);
124
125        /* we are done now */
126    }
127
128    /* free allocated memory */
129    if (row != NULL)
130        free(row);
131    if (colno != NULL)
132        free(colno);
133
134    if (lp != NULL) {
135        /* clean up such that all used memory by lpsolve is freed */
136        delete_lp(lp);
137    }
138
139    return(ret);
140}
141
142int main()
143{
144    demo();
145}

代碼下載請在後臺回復【lpsolve】即可下載。

最後,還差一步,程序編譯完成以後,運行時可能會提示找不到dll文件。這時候,要回到lp_solve_5.5.2.5_dev_win32文件夾,找到lpsolve55.dll文件。

技術分享圖片

將這個文件復制到可執行程序目錄

技術分享圖片

終於,我們的程序運行成功了。

技術分享圖片

這只是一個非常簡單的例子,關於更多lpsolve接口的使用,請訪問:http://web.mit.edu/lpsolve/doc/,

左側定位到lp_solve API reference即可。

Java下使用lpsolve

環境配置

在這裏,要求的java是64位的JDK。

首先,大家找到去在sourceforge網站(https://sourceforge.net/projects/lpsolve/files/lpsolve/5.5.2.5/)把這兩個文件下載下來:

技術分享圖片
技術分享圖片

下載完成以後,分別解壓兩個包,得到lp_solve_5.5.2.5_dev_win64lp_solve_5.5.2.5_java兩個文件夾。然後需要進行下面步驟:

lp_solve_5.5.2.5_dev_win64文件夾中的lpsolve55.dll

技術分享圖片

拷貝到C:\Windows\System32文件下:

技術分享圖片

lp_solve_5.5.2.5_java中lp_solve_5.5_java\lib\win64文件夾下的lpsolve55j.dll

技術分享圖片

拷貝到C:\Windows\System32文件下:

技術分享圖片

在項目中添加相應的jar包。這裏我們新建一個演示項目名為lpsolve_test。右擊“lpsolve_test”→選擇Properties,在彈出的對話框左側列表中選擇Java Build Path,定位到Libraries,然後選擇右側的Add Exteral JARs

技術分享圖片

在彈出的對話框中,選擇我們之前lp_solve_5.5.2.5_java/lp_solve_5.5_java/lib下的lpsolve55j.jar這個包。

技術分享圖片
技術分享圖片

這樣,就可以愉快使用lpsolve了。

使用的話,Java和C/C++的API是差不多的。只不過由於Java的面向對象的特性,lpsolve API做了一層包裝,Java和C/C++的API詳細對照可以訪問以下鏈接:http://web.mit.edu/lpsolve/doc/Java/docs/reference.html

關於C/C++詳細的API可以參考官方說明文檔。訪問:http://web.mit.edu/lpsolve/doc/

定位到lp_solve API reference即可。

使用Java調用lpsolve求解混合線性最優化問題,由於lpsolve的說明文檔模糊,僅提供了一個Demo說明如何調用,以及API文檔,並且API文檔說明非常簡陋!不過小編為大家總結了一下使用的具體步驟:

  1. 創建LpSolve對象
  2. 添加目標函數
  3. 添加不等式約束
  4. 添加等式約束
  5. 設置參數是否為整數(默認為實數)
  6. 設置參數的上限值
  7. (可選)打印具體的矩陣
  8. 進行求解
  9. 提取出最優結果
  10. 提取出最優結果對應的參數值

下面提供一個比較通用的類:

  1package lpsolve_test;
  2import lpsolve.*;
  3import java.util.Arrays;
  4
  5
  6public class Optimator {
  7    private static LpSolve problem;
  8    /**
  9     * 求解整數規劃問題
 10     * @param goal          目標函數矩陣,由於LpSolve讀取數組時從下標1開始讀取,數據需從下標1開始填充,0-1的放前面,有上限的放後面
 11     * @param stIeMatrix    不等式約束方程矩陣,由於LpSolve讀取數組時從下標1開始讀取,內層數據需從下標1開始填充
 12     * @param stEqMatrix    等式約束方程矩陣,由於LpSolve讀取數組時從下標1開始讀取,內層數據需從下標1開始填充
 13     * @param stIeRest      不等式約束條件矩陣,每次傳入的是單個數字,不需要從1開始填充
 14     * @param stEqRest      等式約束條件矩陣,每次傳入的是單個數字,不需要從1開始填充
 15     * @param ups           上限約束矩陣
 16     */
 17    public static void optimate(double[] goal,double[][] stIeMatrix,double[][] stEqMatrix,
 18            double[] stIeRest,double[] stEqRest,double[] ups) throws LpSolveException{
 19
 20        //1、創建LpSolve對象
 21        problem = LpSolve.makeLp(0, goal.length-1);
 22        //2、添加目標函數,會從下標1開始讀取!下標1的參數會被忽略
 23        problem.setObjFn(goal);
 24
 25        //3、循環添加不等式約束,外層循環一次代表一個不等式
 26        if(stIeMatrix!=null){
 27            for(int i=0;i<stIeMatrix.length;i++){
 28                //同樣數組的讀取會從下標1開始
 29                problem.addConstraint(stIeMatrix[i], LpSolve.LE, stIeRest[i]);
 30            }
 31        }
 32
 33        //4、循環添加等式約束,外層循環一次代表一個等式
 34        if(stEqMatrix!=null){
 35            for(int i=0;i<stEqMatrix.length;i++){
 36                //同樣數組的讀取會從下標1開始
 37                problem.addConstraint(stEqMatrix[i], LpSolve.EQ, stEqRest[i]);
 38            }
 39        }
 40
 41        //5、設置參數的整數約束,1代表第一個參數
 42        for(int i=1;i<goal.length;i++){
 43            problem.setInt(i, true);
 44        }
 45
 46        //6、設置指定參數的上限值
 47        for(int i=1;i<=ups.length;i++){
 48            problem.setUpbo(i, ups[i-1]);
 49        }
 50
 51        problem.printLp();
 52        //求解
 53        problem.solve();
 54    }
 55    /**
 56     * 得到最優解
 57     * @return
 58     * @throws LpSolveException
 59     */
 60    public static double getObjective() throws LpSolveException{
 61        if(problem!=null){
 62            return problem.getWorkingObjective();
 63        }else{
 64            try {
 65                throw new Exception("還沒有進行求解!");
 66            } catch (Exception e) {
 67                // TODO Auto-generated catch block
 68                e.printStackTrace();
 69            } 
 70            return 0;
 71        }
 72    }
 73    /**
 74     * 得到最優解對應的變量
 75     * @return
 76     * @throws LpSolveException
 77     */
 78    public static double[] getVariables() throws LpSolveException{
 79        if(problem!=null){
 80            return problem.getPtrVariables();
 81        }else{
 82            try {
 83                throw new Exception("還沒有進行求解!");
 84            } catch (Exception e) {
 85                // TODO Auto-generated catch block
 86                e.printStackTrace();
 87            } 
 88            return null;
 89        }
 90    }
 91
 92//測試
 93    public static void main(String[] args) {
 94        try {
 95            double[][] stIeMatrix = new double[1][];
 96            stIeMatrix[0] = new double[]{0,1,2,3,4};
 97            double[] stRest = new double[]{1};
 98            optimate(new double[]{0,1,2,3,4},stIeMatrix,stIeMatrix,stRest,stRest,new double[]{1,1,5,6});
 99            System.out.println(getObjective());
100            System.out.println(Arrays.toString(getVariables()));
101        } catch (LpSolveException e) {
102            // TODO Auto-generated catch block
103            e.printStackTrace();
104        }
105    }
106}

代碼下載請在後臺回復【lpsolve】即可下載。

這是運行結果:

技術分享圖片

關於更多Java下lpsolve的使用,請訪問:http://web.mit.edu/lpsolve/doc/ ,左側定位到Using lpsolve from Java即可。

Part5

總結

前面說了這麽多,總之,總結起來,使用lpsolve就是以下三種方式:

  • 通過LPSolve IDE編寫模型或者讀取模型文件進行求解。
  • 使用數學編程語言創建模型,調用lpsolve求解。
  • 使用高級編程語言創建模型,調用lpsolve相關API進行求解。

至此,關於lpsolve的已經差不多講解完了。這麽長的文件,想必各位小夥伴看到這裏也不容易。可能還有很多細節沒有講解,要想面面俱到的小夥伴只能去看官方的doc了。

Part6

欲獲取代碼,請關註我們的微信公眾號【程序猿聲】,在後臺回復:lpsolve。即可獲取。

技術分享圖片

推薦文章:10分鐘教你用Python做個打飛機小遊戲超詳細教程
推薦文章:10分鐘教你用python下載和拼接微信好友頭像圖片

幹貨 數學規劃求解器lp_solve超詳細教程