數學規划求解器lp_solve超詳細教程


前言

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

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

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

但是一拿到題目之后,掃了一眼。
驚得差點沒把筆吞下去。
這……城里人都這么會play的嗎?
我*,25個變量。
看着那一堆約束條件,
看着這堆變量x1,x2,x3,…,x25。
總感覺,這次真的是玩脫了。

用Table?開什么國際玩笑,
且不說這得算到猴年馬月,
在這期間如果搞錯一個數,
那簡直比吃了老壇酸菜牛肉面還酸爽。

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

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

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

imageimage

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

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

imageimage

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的所有資源都可以在這個主頁上找到。
包括本文后面介紹的所有文件。

imageimage

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

Part2

入門篇

簡單上手

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

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

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

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

LPSolve

IDELPSolve

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

界面如下:

imageimage

它的介紹如下:
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按鈕,就能馬上出結果了。

imageimage

如下面所示:

imageimage

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

imageimage

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

imageimage

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位系統請下載這兩個文件:

imageimage

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

imageimage

先進入文件夾lp_solve_5.5.2.0_MATLAB_exe_win64:

imageimage

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

imageimage imageimage

注意:如果系統是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 中,保存。設置如下圖:

imageimage

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

imageimage

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

imageimage

然后在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 1>> lp=mxlpsolve('make_lp', 0, 4);
2 2>> mxlpsolve('set_verbose', lp, 3);
3 3>> mxlpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1]);
4 4>> mxlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
5 5>> mxlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
6 6>> mxlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);
7 7>> mxlpsolve('set_lowbo', lp, 1, 28.6);
8 8>> mxlpsolve('set_lowbo', lp, 4, 18);
9 9>> mxlpsolve('set_upbo', lp, 4, 48.98);
1010>> mxlpsolve('set_col_name', lp, 1, 'COLONE');
1111>> mxlpsolve('set_col_name', lp, 2, 'COLTWO');
1212>> mxlpsolve('set_col_name', lp, 3, 'COLTHREE');
1313>> mxlpsolve('set_col_name', lp, 4, 'COLFOUR');
1414>> mxlpsolve('set_row_name', lp, 1, 'THISROW');
1515>> mxlpsolve('set_row_name', lp, 2, 'THATROW');
1616>> mxlpsolve('set_row_name', lp, 3, 'LASTROW');
1717>> mxlpsolve('write_lp', lp, 'a.lp');
1818>> mxlpsolve('get_mat', lp, 1, 2)
1919
2020ans =
2121
2222   78.2600
2323
2424>> mxlpsolve('solve', lp)
2525
2626ans =
2727
2828     0
2929
3030>> mxlpsolve('get_objective', lp)
3131
3232ans =
3333
3434   31.7828
3535
3636>> mxlpsolve('get_variables', lp)
3737
3838ans =
3939
4040   28.6000
4141         0
4242         0
4343   31.8276
4444
4545>> mxlpsolve('get_constraints', lp)
4646
4747ans =
4848
4949   92.3000
5050    6.8640
5151  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系統。

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

imageimage

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

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

imageimage
imageimage

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

imageimage

復制到C:\Windows\System32:

imageimage

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

>>> from lpsolve55 import *
>>> lpsolve()
如果顯示以下信息,則大功告成:

imageimage

至此,環境配置已經完成。
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里輸入下面代碼:

11>>> f = [4, 2, 1]
22>>> A = [[2, 1, 0], [1, 0, 2], [1, 1, 1]]
33>>> b = [1, 2, 1]
44>>> l = [ 0, 0, 0]
55>>> u = [ 1, 1, 2]

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

 1 1>>> from lpsolve55 import *
2 2>>> from lp_maker import *
3 3>>> lp = lp_maker(f, A, b, [-1, -1, 0], l, u, None, 1, 0)
4 4>>> solvestat = lpsolve('solve', lp)
5 5>>> obj = lpsolve('get_objective', lp)
6 6>>> print obj
7 72.5
8 8>>> x = lpsolve('get_variables', lp)[0]
9 9>>> print x
1010[0.5, 0.0, 0.5]
1111>>> 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/)把這個文件下載下來:

imageimage

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

imageimage

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

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

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

打開Visual Studio 2017,新建一個空項目,名字隨便寫,這里寫的是lptest。

imageimage

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

imageimage

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

imageimage

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

imageimage

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

imageimage

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

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

 1  1#include "lp_lib.h"
2  2   # define WIN32
3  3#pragma comment(lib, "lpsolve55.lib")
4  4
5  5int demo()
6  6{
7  7    lprec *lp;
8  8    int Ncol, *colno = NULL, j, ret = 0;
9  9    REAL *row = NULL;
10 10
11 11    /* We will build the model row by row
12 12    So we start with creating a model with 0 rows and 2 columns */
13 13    Ncol = 2; /* there are two variables in the model */
14 14    lp = make_lp(0, Ncol);
15 15    if (lp == NULL)
16 16        ret = 1; /* couldn't construct a new model... */
17 17
18 18    if (ret == 0) {
19 19        /* let us name our variables. Not required, but can be useful for debugging */
20 20        set_col_name(lp, 1, "x");
21 21        set_col_name(lp, 2, "y");
22 22
23 23        /* create space large enough for one row */
24 24        colno = (int *)malloc(Ncol * sizeof(*colno));
25 25        row = (REAL *)malloc(Ncol * sizeof(*row));
26 26        if ((colno == NULL) || (row == NULL))
27 27            ret = 2;
28 28    }
29 29
30 30    if (ret == 0) {
31 31        set_add_rowmode(lp, TRUE);  /* makes building the model faster if it is done rows by row */
32 32
33 33                                    /* construct first row (120 x + 210 y <= 15000) */
34 34        j = 0;
35 35
36 36        colno[j] = 1; /* first column */
37 37        row[j++] = 120;
38 38
39 39        colno[j] = 2; /* second column */
40 40        row[j++] = 210;
41 41
42 42        /* add the row to lpsolve */
43 43        if (!add_constraintex(lp, j, row, colno, LE, 15000))
44 44            ret = 3;
45 45    }
46 46
47 47    if (ret == 0) {
48 48        /* construct second row (110 x + 30 y <= 4000) */
49 49        j = 0;
50 50
51 51        colno[j] = 1; /* first column */
52 52        row[j++] = 110;
53 53
54 54        colno[j] = 2; /* second column */
55 55        row[j++] = 30;
56 56
57 57        /* add the row to lpsolve */
58 58        if (!add_constraintex(lp, j, row, colno, LE, 4000))
59 59            ret = 3;
60 60    }
61 61
62 62    if (ret == 0) {
63 63        /* construct third row (x + y <= 75) */
64 64        j = 0;
65 65
66 66        colno[j] = 1; /* first column */
67 67        row[j++] = 1;
68 68
69 69        colno[j] = 2; /* second column */
70 70        row[j++] = 1;
71 71
72 72        /* add the row to lpsolve */
73 73        if (!add_constraintex(lp, j, row, colno, LE, 75))
74 74            ret = 3;
75 75    }
76 76
77 77    if (ret == 0) {
78 78        set_add_rowmode(lp, FALSE); /* rowmode should be turned off again when done building the model */
79 79
80 80                                    /* set the objective function (143 x + 60 y) */
81 81        j = 0;
82 82
83 83        colno[j] = 1; /* first column */
84 84        row[j++] = 143;
85 85
86 86        colno[j] = 2; /* second column */
87 87        row[j++] = 60;
88 88
89 89        /* set the objective in lpsolve */
90 90        if (!set_obj_fnex(lp, j, row, colno))
91 91            ret = 4;
92 92    }
93 93
94 94    if (ret == 0) {
95 95        /* set the object direction to maximize */
96 96        set_maxim(lp);
97 97
98 98        /* just out of curioucity, now show the model in lp format on screen */
99 99        /* this only works if this is a console application. If not, use write_lp and a filename */
100100        write_LP(lp, stdout);
101101        /* write_lp(lp, "model.lp"); */
102102
103103        /* I only want to see important messages on screen while solving */
104104        set_verbose(lp, IMPORTANT);
105105
106106        /* Now let lpsolve calculate a solution */
107107        ret = solve(lp);
108108        if (ret == OPTIMAL)
109109            ret = 0;
110110        else
111111            ret = 5;
112112    }
113113
114114    if (ret == 0) {
115115        /* a solution is calculated, now lets get some results */
116116
117117        /* objective value */
118118        printf("Objective value: %f\n", get_objective(lp));
119119
120120        /* variable values */
121121        get_variables(lp, row);
122122        for (j = 0; j < Ncol; j++)
123123            printf("%s: %f\n", get_col_name(lp, j + 1), row[j]);
124124
125125        /* we are done now */
126126    }
127127
128128    /* free allocated memory */
129129    if (row != NULL)
130130        free(row);
131131    if (colno != NULL)
132132        free(colno);
133133
134134    if (lp != NULL) {
135135        /* clean up such that all used memory by lpsolve is freed */
136136        delete_lp(lp);
137137    }
138138
139139    return(ret);
140140}
141141
142142int main()
143143{
144144    demo();
145145}

代碼下載請在后台回復【lpsolve】即可下載。

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

imageimage

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

imageimage

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

imageimage

這只是一個非常簡單的例子,關於更多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/)把這兩個文件下載下來:

imageimage
imageimage

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

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

imageimage

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

imageimage

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

imageimage

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

imageimage

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

imageimage

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

imageimage
imageimage

這樣,就可以愉快使用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. 提取出最優結果對應的參數值

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

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

代碼下載請在后台回復【lpsolve】即可下載。

這是運行結果:

imageimage

關於更多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下載和拼接微信好友頭像圖片


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM