变尺度法BFGS算法的C++源码
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
//变尺度法BFGS算法的C++源码
#include "iostream.h"
#include "math.h"
#define A 8
#define B 10
#define C 7
#define D 0
#define START {5,4,5,5} //初始迭代点
const int n=4; //变量个数
const int nc=3; //不等式约束个数(也可根据题目需要增加等式约束个数修改约束构造函数)
const double epsilon1=1E-6; //一维搜索精度
const double epsilon2=1E-4; //变尺度法收敛精度
const double epsilon=1E-4; //惩罚函数法收敛精度
double r=1; //惩罚因子
double br=1; //变尺度法强行退出循环因子(可去除)
const double zr=10; //递增系数
double det=0.0014; //外惩罚函数法约束函数余量
//(此det值仅适合当前A B C D,修改请将其恢复为0.0001或其他建议值)
//计算梯度
void comput_grad(double (*pf)(double *x), int n, double *point, double *grad);
//无约束BFGS变尺度法(目标函数,维数,最小点) 返回0值
double BFGS(double (*pf)(double *x), int n, double *min_point);
//构造混合外点惩罚函数 返回惩罚函数值(构造点)
double funP(double *p);
//返回目标函数值,并返回约束函数值存入ys (计算点,约束函数值存放处)
double fun(double *x , double *ys );
//一维搜索函数 返回最优步长(目标函数,维数,初始点,方向)
double line_search( double (*pf)(double *x),int n,double *start,double *direction);
//配给与一维搜索函数 返回下一点的的惩罚函数值(计算点,计算方向,步长)
double funPt(double *x,double *direction,double t);
void main()
{
int i,j;
double c=0; //表示外惩罚函数循环次数
double f_min,f_temp,f_punish;
double *ys=new double[nc];
double x_x=0,f_ys=0;
double x_min[n]=START;
double x_temp[n]=START;
f_temp=fun(x_temp,ys);
for(;;)
{
c++;
BFGS(funP,n,x_min);
f_min=fun(x_min,ys);
for(j=0;j
for(i=0;i
x_x=sqrt(x_x);
//参考值显示
cout<<"\n"<<"外惩罚函数循环迭代第 "<
if((fabs(f_min)<=1)&&(fabs(f_min-f_temp)<=epsilon))
{cout<<"因为迭代xk与xk+1的函数值差距f_f达到收敛精度 "<
else if((fabs(f_min)>=1)&&(fabs((f_min-f_temp
)/f_min)<=epsilon))
{cout<<"\n 因为迭代xk与xk+1的函数值差距 det_f 达到收敛精度 "<
//--------------|
r=r*10;
for(i=0;i
f_temp=f_min;
}
if(f_min>f_temp)
{f_min=f_temp;
for(i=0;i
f_punish=funP(x_min);
if(f_ys>=1E10)
cout<<"\n!!!!!!!!!!!!!!!!!!由于不可知的原因,导致结果发散!!!!!!!!!!!!!!!!!!!"<
//梯度计算模块
//参数:指向目标函数的指针,变量个数,求梯度的点,结果存放处
void comput_grad(double (*pf)(double *x),
int n,
double *point,
double *grad)
{
double h=1E-5;
int i;
double *temp;
temp = new double[n];
for(i=1;i<=n;i++)
{
temp[i-1]=point[i-1];
}
for(i=1;i<=n;i++)
{
temp[i-1]+=0.5*h;
grad[i-1]=4*pf(temp)/(3*h);
temp[i-1]-=h;
grad[i-1]-=4*pf(temp)/(3*h);
temp[i-1]+=(3*h/2);
grad[i-1]-=(pf(temp)/(6*h));
temp[i-1]-=(2*h);
grad[i-1]+=(pf(temp)/(6*h));
temp[i-1]=point[i-1];
}
delete[] temp;
}
//无约束变尺度法BFGS函数声明
//参数:pf指向目标函数的指针,n变量个数,min_point接受初始点、存放结果
//返回0值
double BFGS(
double (*pf)(double *x),
int n,
double *min_point
)
{
int i,j;
int k=0;
double e=epsilon2;
double g_norm; //梯度的模
double *g0=new double[n]; //梯度
double *g1=new double[n];
double *dg=new double[n];
double *p=new double[n]; //搜索方向 =-g
double t; //一维搜索步长
double *x0=new double[n];
double *x1=new double[n];
double *dx=new double[n];
double **H=new double*[n];
for (i=0; i
double *Hg=new double[n];
double num1;
double num2; //------------- |
//初始化------
for(i=0;i
if(i==j)
H[j]=1.0; // H0=I
else H[j]=0.0;
}
for(i=0;i
comput_grad(pf,n,x0,g0);
for(i=0;i
do
{
t=line_search(pf,n,x0,p);
for(i=0;i
comput_grad(pf,n,x1,g1);
//调试程序时参考输出
// cout<<"k="<
}while(g_norm>e);
for(i=0;i
delete[] g1;
delete[] dg;
delete[] p;
delete[] x0;
delete[] x1;
delete[] dx;
for (i=0; i
delete[] gH;
delete[] Hg;
return
0;
}
/////////////
double fun(double *x , double *ys )//返回目标函数值
{
double f;
ys[0]=-x[0]*x[0]-x[1]*x[1]-x[2]*x[2]-x[3]*x[3]-x[0]+x[1]-x[2]+x[3]+A-det;
ys[1]=-x[0]*x[0]-2*x[1]*x[1]-x[2]*x[2]-2*x[3]*x[3]+x[0]+x[3]+B-det;
ys[2]=-2*x[0]*x[0]-x[1]*x[1]-x[2]*x[2]-2*x[0]+x[1]+x[3]+C-det;
f=x[0]*x[0]+x[1]*x[1]+x[2]*x[2]*2+x[3]*x[3]-5*x[0]-5*x[1]-21*x[2]+7*x[3]+D;
return f;
}
double funP(double *p) //构造混合外点惩罚函数 返回惩罚函数值
{
int i;
double f;
double *ys=new double[nc];
f=fun(p,ys);
if(nc!=0)
{
for(i=0;i
f+=r*pow(ys[0],2);
}
return f;
}
double line_search(double (*pf)(double *x),int n,double *start,double *direction)
//参数:指向目标函数的指针,变量个数,出发点,搜索方向
//返回:最优步长
{ double a,b,t1=1,t2,t3,tt,h=0.1,f1,f2,f3,j,c=epsilon1;
t2=t1+h;
f1=funPt(start,direction,t1);f2=funPt(start,direction,t2);
//进退法
if(f1>f2) //向前搜索
{ t3=t2+h;f3=funPt(start,direction,t3);
while(1)
if(f2<=f3) {a=t1,b=t3;break;}
else{h=2*h;t1=t2;t2=t3;t3=t2+h;
f2=funPt(start,direction,t2);f3=funPt(start,direction,t3);}
}
else
{ h=-1*h;
j=t1;t1=t2;t2=j;
j=f1;f1=f2;f2=j;
t3=t2+h;f3=funPt(start,direction,t3);
while(1)
if(f2<=f3){a=t3;b=t1;break;}
else{h=2*h;t1=t2;t2=t3;t3=t2+h;
f2=funPt(start,direction,t2);f3=funPt(start,direction,t3);}
}
t1=a+0.382*(b-a); t2=a+0.618*(b-a);
f1=funPt(start,direction,t1);f2=funPt(start,direction,t2);
while(b-a>c)
//黄金分割法,
if(f1>f2)
{a=t1;t1=t2;t2=a+0.618*(b-a);
f1=f2;f2=funPt(start,direction,t2);}
else
{
b=t2;t2=t1;t1=a+0.382*(b-a);
f2=f1;f1=funPt(start,direction,t1);}
tt=(t1+t2)/2;
return tt;
}
double funPt(double *x,double *direction,double t)
//返回带步长为参数的惩罚函数值(用于一维搜索步长时)
{
double *x1=new double[n];
int i;
for(i=0;i
return funP(x1);
}