最近做一个最优化的东西,涉及到内点法非线性优化的开源库Ipopt。在linux下用起来非常简单,但要在windows下用,还颇费了一番功夫。在此简要记录一下,算是给做过的东西留个印记,也方便有需要的人。
Ipopt是一个大规模高性能非线性约束优化开源库,采用了内点法。简单来说就是选定初始点为可行集中的点,在约束边界处利用人为添加的对数项,确保求解过程不会超出边界,从而利用无约束优化的算法求解非线性约束条件下的最优化问题。其官网地址如下:
https://coin-or.github.io/Ipopt/
一些最优化的概念可参考如下网址的说明:
https://zhuanlan.zhihu.com/p/412395207
Ipopt至少有两个依赖:一个是blas库,我选的openblas;另一个是求解器,找了一番之后,还是决定用推荐的HSL。前者很有名了,就不多说,HSL是某个大学搞的一整套求解器,包含了各种各样的算法。其官网如下:
但为了和Ipopt整合,更方便的是下载下面地址的算法包。不过下载还需要申请,好在立马就能发邮件给出下载链接。
https://www.hsl.rl.ac.uk/ipopt/
除此以外,为了成功编译Ipopt,还需要一套类Unix环境,官方建议是msys2。很久以前用过msys和mingw,不过后来都在linux下,也就没继续跟进。现在发现msys2很方便了,可以利用arch linux下的工具pacman来实现类似apt-get的功能,安装软件非常方便快捷,确实很好用。而且该软件是绿色软件,虽然有安装包,但装完之后直接复制到其他机器上也能用。
安装msys2之后,运行msys2.exe(或者msys2_shell.cmd),执行如下指令即可安装相关工具,用于编译Ipopt。
pacman -S binutils diffutils make patch pkg-config mingw-w64-x86_64-gcc-fortran
由于我已经安装了git,故未在上面的语句中增加git,否则也可增加git。官网上还有grep,但实际上msys2已经自带了grep。注意此处仅安装了64位的mingw gfortran,因此只能编译64位的库,将来的VS程序也只能是64位的。另外,要在路径中找到gfortran,需要运行mingw64.exe而非msys2.exe。最后,为了找到微软的编译器及相关工具,以方便后面优先使用微软编译器的选项,需要打开VS命令行工具,在里面找到msys2_shell.cmd,执行如下指令。
msys2_shell.cmd -use-full-path
/mingw64.exe
第一句继承当前环境变量(也就是VS命令行工具cmd环境下的环境变量)并打开msys2,第二句运行mingw64.exe,即打开包含mingw64工具的shell。
接下来编译openblas。openblas有很多种编译方法,比如利用cmake生成VS解决方案。但既然有了类Unix环境,自然直接用最简单的方法,直接执行make/make install即可。
cd OpenBLAS
make
make PREFIX=/path/to/install install
此处/path/to/install代表想把openblas库安装到什么路径。
本来可以直接编译HSL,但貌似直接编译会出问题,需要利用Ipopt提供的第三方库编译工具,才能顺利。不过HSL是运行时依赖,貌似编译的时候不需要。为了完整性,还是先编译吧。在如下地址下载Ipopt提供的第三方编译环境。
https://github.com/coin-or-tools/ThirdParty-HSL
下载后将先前下载的HSL库包解压缩放入该文件夹,并改名为coinhsl,然后执行如下命令进行编译。
cd ThirdParty-HSL-stable-2.2
./configure --prefix=/path/to/install --with-lapack-lflags="-L/path/of/openblas -lopenblas" --enable-msvc
make
make install
此处/path/to/install和前面一样,表示想把编译好的库安装到哪里,而/path/of/openblas则代表之前把openblas安装到哪里的路径。我的这两个路径是同一个,是某个目录下的FinalLib文件夹。
最后编译Ipopt,执行如下指令。
cd Ipopt-master
mkdir build
cd build
../configure --prefix=/path/to/install --with-lapack-lflags="-L/path/of/openblas -lopenblas" --enable-msvc
make
make install
我把所有编译好的库都放到FinalLib文件夹中,接下来就可以引用Ipopt库来写自己的代码了。新建VS工程,先把工程改成x64架构,然后在VC++ include附加包含目录中添加FinalLib/include/coin-or,在附加库目录中添加FinalLib/lib,输入库文件中添加libipopt.dll.a,这样即可成功编译。
但运行时会报一堆错,主要是找不到各种动态库dll。此时需要在VS工程属性的调试一栏中增加环境变量PATH=/path/to/msys2/mingw64/bin;%PATH%,这样即可找到运行时需要的动态库。
如果采用intel Parallel Studio XE套装,该过程将更加简单,因为intel MKL自带了blas和线性求解器Pardiso。所以不需要OpenBLAS和HSL,直接编译Ipopt即可。
值得注意的是,如果采用以上编译语句,编译出来的库是release版本,如果VS开发时选择debug,有可能会出现奇怪的运行时错误,换成release就好了。这块主要和 Ipopt 对计算中用到的 options 的设置有关,不过具体原因也没去深究。如果需要debug版本,configure时需要加上--enable-debug 项。