📄 共轭梯度法.cpp
字号:
#include<iostream.h>
#include<math.h>
int const n=2;
double fun(double x[n],double f_xs[n+n+1+(n-1)*n/2]);//输入变量为函数自变量初值
void Q_fun(double f_xs[n+n+1+(n-1)*n/2],double Q[n][n+1]);
void D_fun(double x[n],double Q[n][n+1],double g0[n]);//自变量初值,正定二次函数的各项系数,返回梯度的初值
void abc(double x[n],double p[n],double f_xs[n+n+1+(n-1)*n/2],double t[3]);//t[3]中返回的是a,b,c的系数值.开始计算minf(Xk+tPk)时的步长t的值,由于这是n元二次函数所以minf(t)是关于t>0的二次函数,先求二次方程a,b,c系数,用一阶导为零。
double t_c(double t[3]);//二次函数一阶导为零计算t的值,t>0
void xiang_cheng(double a[n],double b[n][n],double c[n]);//作乘法运算;
double n_ta(double g0[n],double Q[n][n+1],double p[n]);//返回n_ta
int H(double g0[n],double c);//判别准则:返回1结束,返回0继续迭代
void main()
{
double f_xs[n+n+1+(n-1)*n/2]={1,4,0,0,0,0};//正定二次函数的各项系数,第一个为:X1^2系数,第二个为:X2^2系数,第三个为:X1系数,第四个为:X2系数,第五个为:常数项,第六个为:X1X2系数;
//n元的系数存放类推
double x[n]={1,1};//函数自变量初值
double f0;//函数值
double g0[n];//梯度的值
double Q[n][n+1];//正定二次函数对应的实对称矩阵
double c=0.01;//H准则限值
double t[3];//返回求minf()时t的二次函数的a,b,c的系数值
double t_bc;//步长
double p[n];//保存矩阵相乘结果_加负号后变成下降方向
int i,tap=0;//迭代次数
Q_fun(f_xs,Q);//计算正定二次函数对应的实对称矩阵ok!
D_fun(x,Q,g0);//返回梯度的初值
for(i=0;i<n;i++)
{
p[i]=(-1)*g0[i];
}//确定了P0
for(;;)
{
D_fun(x,Q,g0);
abc(x,p,f_xs,t);//开始计算minf(Xk+tPk)时的步长t的值,
t_bc=t_c(t);//求一阶导来计算t
for(i=0;i<n;i++)
{
x[i]=x[i]+t_bc*p[i];
}
/*for(i=0;i<n;i++)
cout<<"x"<<i+1<<"="<<x[i]<<endl;*/
tap++;
if(H(g0,c)!=0)
break;
t_bc=n_ta(g0,Q,p);
for(i=0;i<n;i++)
{
p[i]=g0[i]+t_bc*p[i];
}
}
f0=fun(x,f_xs);
cout<<endl<<"共轭梯度法"<<endl;
cout<<"函数f(x1,x2)=X1^2+4X2^2.的极小点为:"<<"f="<<f0<<endl;
cout<<"自变量取值为:"<<endl;
for(i=0;i<n;i++)
{
cout<<"x"<<i+1<<"="<<x[i]<<endl;
}
cout<<"迭代次数为:"<<tap<<endl;
}
double fun(double x[n],double f_xs[n+n+1+(n-1)*n/2])//输入变量为函数自变量初值
{
int i,j;
double f=0;
for(i=0;i<n;i++)//计算X^2部分
{
f+=pow(x[i],2)*f_xs[i];
}
for(;i<2*n;i++)//计算X部分
{
f+=x[i%n]*f_xs[i];
}
f+=f_xs[i];//计算常数项部分
for(i=0;i<n;i++)//计算XiXj部分
{
for(j=i+1;j<n;j++)
{
f+=f_xs[(n+1)+n*(i+1)-i*(i+1)/2+j-i-1]*x[i]*x[j];
}
}
return f;
}
void Q_fun(double f_xs[n+n+1+(n-1)*n/2],double Q[n][n+1])
{
int i,j;
for(i=0;i<n;i++)
{
Q[i][i]=2*f_xs[i];
}
for(i=0;i<n;i++)
{
Q[i][n]=f_xs[n+i];
}
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
Q[j][i]=Q[i][j]=f_xs[(n+1)+n*(i+1)-i*(i+1)/2+j-i-1];
}
}
}
void D_fun(double x[n],double Q[n][n+1],double g0[n])//自变量初值,正定二次函数的各项系数,返回梯度的初值
{
int i,j;
for(i=0;i<n;i++)
{
g0[i]=0;//清零
for(j=0;j<n;j++)
{
if(i==j)
g0[i]+=Q[i][j]*x[j];
else
g0[i]+=Q[i][j]*x[j];
}
}
for(i=0;i<n;i++)
{
g0[i]+=Q[i][n];
}
/*cout<<endl<<"梯度g0的值="<<endl;
for(i=0;i<n;i++)
cout<<g0[i]<<endl;*/
}
void abc(double x[n],double p[n],double f_xs[n+n+1+(n-1)*n/2],double t[3])//t[3]中返回的是a,b,c的系数值
{
int i,j;
t[0]=t[1]=t[2]=0;
t[0]=fun(p,f_xs)-f_xs[2*n];
for(i=n;i<2*n;i++)
{
t[0]-=f_xs[i]*p[i%n];
}
for(i=0;i<n;i++)
{
t[1]+=2*f_xs[i]*x[i]*p[i];
}
for(;i<2*n;i++)
{
t[1]+=f_xs[i]*p[i%n];
}
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
t[1]+=f_xs[(n+1)+n*(i+1)-i*(i+1)/2+j-i-1]*(x[i]*p[j]+x[j]*p[i]);
}
}
t[2]=fun(x,f_xs);
//cout<<"二次函数minf(Xk):"<<endl<<"二次项系数:"<<t[0]<<endl<<"一次项系数:"<<t[1]<<endl<<"常数项系数:"<<t[2]<<endl;
}
double t_c(double t[3])
{
//cout<<"用一阶导求得步长为:t="<<-t[1]/t[0]/2<<endl;
return -t[1]/t[0]/2;
}
void xiang_cheng(double a[n],double b[n][n],double c[n])
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
c[i]=a[j]*b[i][j];
}
}
}
double n_ta(double g0[n],double Q[n][n+1],double p[n])//返回n_ta
{
int i,j;
double A[n][n];
double c[n];
double temp=0;
double t;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
A[i][j]=Q[i][j];
}
}
xiang_cheng(g0,A,c);
t=0;
for(i=0;i<n;i++)
{
t+=c[i]*p[i];
}
xiang_cheng(p,A,c);
for(i=0;i<n;i++)
{
temp+=c[i]*p[i];
}
t=t/temp;
return t;
}
int H(double g0[n],double c)//判别准则:返回1结束,返回0继续迭代
{
double s=0;
for(int i=0;i<n;i++)
{
s+=pow(g0[i],2);
}
if(sqrt(s)<c)
return 1;
else
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -