1系统环境说明
操作系统:Window8 X64.
Matlab版本:Matlab2012b(Matlab 8.0).
VS版本:VS 2010.
添加系统环境变量:
Path变量中增加:C:\Program Files\MATLAB\R2012b\bin\win64;
重启电脑。
2 二次规划算法的Matlab实现
2.1 编程准备工作
首先为本文建立一个单独的文件夹\QPTEST,再在该文件夹下建立子文件夹\QPMAT。然后启动Matlab并将工作目录指定到\QPMAT下。
2.2 m文件编程
新建m文件并保存文件名为qpsubp.m,编辑内容如下,代码分析参考文献[1]程序12.1:
function [d,mu,lam] = qpsubp(dfk,Bk,Ae,hk,Ai,gk)n=length(dfk); l=length(hk); m=length(gk);gamma=0.05; epsilon=1.0e-6; rho=0.5; sigma=0.2;ep0=0.05; mu0=0.05*zeros(l,1); lam0=0.05*zeros(m,1);d0=ones(n,1); u0=[ep0;zeros(n+l+m,1)];z0=[ep0;d0;mu0;lam0];k=0;z=z0; ep=ep0; d=d0; mu=mu0; lam=lam0; while (k<=150) dh=dah(ep,d,mu,lam,dfk,Bk,Ae,hk,Ai,gk); if(norm(dh)0&&m>0) de=dz(1); dd=dz(2:n+1); du=dz(n+2:n+l+1); dl=dz(n+l+2:n+l+m+1); end if(l==0) de=dz(1); dd=dz(2:n+1); dl=dz(n+2:n+m+1); end if(m==0) de=dz(1); dd=dz(2:n+1); du=dz(n+2:n+l+1); end i=0; while (i<=20) if(l>0&&m>0) dh1=dah(ep+rho^i*de,d+rho^i*dd,mu+rho^i*du,lam+rho^i*dl,... dfk,Bk,Ae,hk,Ai,gk); end if(l==0) dh1=dah(ep+rho^i*de,d+rho^i*dd,mu,lam+rho^i*dl,... dfk,Bk,Ae,hk,Ai,gk); end if(m==0) dh1=dah(ep+rho^i*de,d+rho^i*dd,mu+rho^i*du,lam,... dfk,Bk,Ae,hk,Ai,gk); end if(norm(dh1)<=(1-sigma*(1-gamma*ep0)*rho^i)*norm(dh)) mk=i; break; end i=i+1; if(i==20) mk=10; end end alpha=rho^mk; if(l>0&&m>0) ep=ep+alpha*de; d=d+alpha*dd; mu=mu+alpha*du; lam=lam+alpha*dl; end if(l==0) ep=ep+alpha*de; d=d+alpha*dd; lam=lam+alpha*dl; end if(m==0) ep=ep+alpha*de; d=d+alpha*dd; mu=mu+alpha*du; end k=k+1;end%val = 0.5*d'*Bk*d+dfk'*d; function p=phi(ep,a,b)p=a+b-sqrt(a^2+b^2+2*ep^2); function bet=beta(ep,d,mu,lam,dfk,Bk,Ae,hk,Ai,gk,gamma)dh=dah(ep,d,mu,lam,dfk,Bk,Ae,hk,Ai,gk);bet=gamma*norm(dh)*min(1,norm(dh)); function [dd1,dd2,v1]=ddv(ep,d,lam,Ai,gk)m=length(gk);dd1=zeros(m,m); dd2=zeros(m,m); v1=zeros(m,1);for(i=1:m) fm=sqrt(lam(i)^2+(gk(i)+Ai(i,:)*d)^2+2*ep^2); dd1(i,i)=1-lam(i)/fm; dd2(i,i)=1-(gk(i)+Ai(i,:)*d)/fm; v1(i)=-2*ep/fm;end function A=JacobiH(ep,d,mu,lam,dfk,Bk,Ae,hk,Ai,gk)n=length(dfk); l=length(hk); m=length(gk);A=zeros(n+l+m+1,n+l+m+1);[dd1,dd2,v1]=ddv(ep,d,lam,Ai,gk);if(l>0&&m>0) A=[1, zeros(1,n), zeros(1,l), zeros(1,m); zeros(n,1), Bk, -Ae', -Ai'; zeros(l,l), Ae, zeros(l,l), zeros(l,m); v1,dd2*Ai, zeros(m,l),dd1];endif(l==0) A=[1, zeros(1,n), zeros(1,m); zeros(n,1), Bk, -Ai'; v1,dd2*Ai, dd1];endif(m==0) A=[1, zeros(1,n), zeros(1,l); zeros(n,1), Bk, -Ae'; zeros(l,1), Ae, zeros(l,l)];end function dh=dah(ep,d,mu,lam,dfk,Bk,Ae,hk,Ai,gk)n=length(dfk); l=length(hk); m=length(gk);dh=zeros(n+l+m+1,1);dh(1)=ep;if(l>0&&m>0) dh(2:n+1)=Bk*d-Ae'*mu-Ai'*lam+dfk; dh(n+2:n+l+1)=hk+Ae*d; for(i=1:m) dh(n+l+1+i)=phi(ep,lam(i),gk(i)+Ai(i,:)*d); endendif(l==0) dh(2:n+1)=Bk*d-Ai'*lam+dfk; for(i=1:m) dh(n+1+i)=phi(ep,lam(i),gk(i)+Ai(i,:)*d); endendif(m==0) dh(2:n+1)=Bk*d-Ae'*mu+dfk; dh(n+2:n+l+1)=hk+Ae*d;enddh=dh(:);
2.3 m文件测试
使用2.2中的程序求解如下二次规划问题:
该问题的极小值点为。在Matlab命令窗口中输入如下命令:
dfk=[-6 -2 -12]’; Bk=[2 1 0;1 4 0;0 0 0]; Ae=[1 1 1]; hk=[-2]’; Ai=[1 -2 0;1 0 0;0 1 0;0 0 1]; gk=[3 0 0 0]’; [d,mu,lam]=qpsubp(dfk,Bk,Ae,hk,Ai,gk)
输出结果如下:
d = -0.0000 -0.0000 2.0000mu = -12.0000lam = -0.0000 6.0000 10.0000 -0.0000
2.4 m文件编译
在Matlab命令行中输入编译命令:mcc -B cpplib:qpsubp qpsubp.m。第一次运行该命令是,Matlab会在本机上搜索可用的编译器,并列于命令窗口内,如下图所示:
选择输入1回车,等待编译结果,编译时间较长,编译后的输出提示如下图所示:
编译完成后,在\QPMAT文件夹下生成如下文件:
其中对于VS调用dll有用的文件包括qpsubp.h、qpsubp.lib与qpsubp.dll。
3 VS2010下测试dll
3.1 VS工程设置
启动VS2010,新建项目,项目目录选择\QPTEST,项目名称填QPVS,项目类型为win32下的控制台程序,如下图所示:
将文件\QPMAT文件夹下的qpsubp.h、qpsubp.lib与qpsubp.dll文件拷贝到文件夹\QPVS\QPVS下。由于操作系统和Matlab为64位,所以在VS下只能编译成64位程序才能正常链接到Matlab中的函数,需要在VS中新建一个64位的编译平台,步骤如下:
(1) 进入“配置管理器”
通过项目属性进入。
或者直接从工具栏平台的下拉箭头下进入:
(2)增加x64平台
确定,得到如下结果。
为工程添加Matlab的头文件和库文件路径,步骤如下:
项目属性——》VC++目录,如图:
包含目录增加:C:\Program Files\MATLAB\R2012b\extern\include
库目录增加:C:\Program Files\MATLAB\R2012b\extern\lib\win64\microsoft
3.2代码编辑
编辑文件SQVS.cpp。编辑内容如下:
(1)添加头文件与作用域声明
#include#include "qpsubp.h"using namespace std;
iostream为C++输入输出流类的头文件,与using namespace std配合后可调用cin、cout,qpsubp.h是调用二次规划dll的头文件。
(2) 链接库文件
#pragma comment(lib,"qpsubp.lib")#pragma comment(lib,"mclmcrrt.lib")
Qpsubp.lib为调用二次规划dll的库文件,mclmcrrt.lib是调用Matlab相关函数的库文件。
(3) 初始化库文件
if( !qpsubpInitializeWithHandlers(NULL,0) ) { std::cout << "Could not initialize the application!" << std::endl; return -1; } if(!qpsubpInitialize()) { std::cout << "Could not initialize the application!" << std::endl; return -1; } else { cout<<"Application is initialized successfully!"<
(4)定义输入输出变量并城市化(根据m文件测试所用例子)
mwArray mwdfk(3,1,mxDOUBLE_CLASS); mwArray mwBk(3,3,mxDOUBLE_CLASS); mwArray mwAe(1,3,mxDOUBLE_CLASS); mwArray mwhk(1,1,mxDOUBLE_CLASS); mwArray mwAi(4,3,mxDOUBLE_CLASS); mwArray mwgk(4,1,mxDOUBLE_CLASS); mwArray mwd; mwArray mwmu; mwArray mwlam; mwdfk(1,1)=-6; mwdfk(2,1)=-2; mwdfk(3,1)=-12; mwBk(1,1)=2; mwBk(1,2)=1; mwBk(1,3)=0; mwBk(2,1)=1; mwBk(2,2)=4; mwBk(2,3)=0; mwBk(3,1)=0; mwBk(3,2)=0; mwBk(3,3)=0; mwAe(1,1)=1; mwAe(1,2)=1; mwAe(1,3)=1; mwhk(1,1)=-2; mwAi(1,1)=1; mwAi(1,2)=-2; mwAi(1,3)=0; mwAi(2,1)=1; mwAi(2,2)=0; mwAi(2,3)=0; mwAi(3,1)=0; mwAi(3,2)=1; mwAi(3,3)=0; mwAi(4,1)=0; mwAi(4,2)=0; mwAi(4,3)=1; mwgk(1,1)=3; mwgk(2,1)=0; mwgk(3,1)=0; mwgk(4,1)=0;
(5)地用二次规划函数
qpsubp(3,mwd,mwmu,mwlam,mwdfk,mwBk,mwAe,mwhk,mwAi,mwgk);
(6)输出计算结果
cout<<"d = ["<<<","< <<","< <<"]"<
(7)屏幕停留、终止动态链接库与退出程序
cout <<"Press any key to exit!" <
3.3完整代码
#include "stdafx.h"#include#include "qpsubp.h" using namespace std; #pragma comment(lib,"qpsubp.lib")#pragma comment(lib,"mclmcrrt.lib") int _tmain(int argc, _TCHAR* argv[]){ if( !qpsubpInitializeWithHandlers(NULL,0) ) { std::cout << "Could not initialize the application!" << std::endl; return -1; } if(!qpsubpInitialize()) { std::cout << "Could not initialize the application!" << std::endl; return -1; } else { cout<<"Application is initialized successfully!"<
3.4运行结果
4参考文献
[1]马昌凤.最优化方法及其Matlab程序设计.北京:科学出版社,2010.
[2]刘维.精通Matlab与C/C++混合程序设计.北京:北京航空航天大学出版社,2007.