对之前的优化设计的课做一些总结,也是自己对优化算法的一些总结和感悟,这篇主要总结一下传统单变量算法,在下几篇将会对一些传统多变量以及智能优化算法进行总结。
传统的单变量主要有.进退法2.黄金分割法3.斐波那契法4.多项式近似法(牛顿法)5.多项式近似法(抛物线法)等。下面对上述方法原理简单介绍一下。
进退法又名爬山法,可以说来源于一种贪心的思想,设置初始步长以及初始值,当往更好的方向发展时,则增加步长更新位置,否则更新步长为-h/4,直至收敛。
黄金分割法既需要确定一定的区间,很明显其的劣势即必须寻找的极值需存在在事先确定的区间内,否则找不到极值。
斐波那契法与黄金分割法在原理上是类似的,只不过利用斐波那契数列的中的比值替代的黄金分割比。
牛顿法是假设函数可微,在x附近利用二次函数逼近fx,并根据极小值满足函数导数为0从而得到函数极值。
抛物线法即假定函数上的三点构造二次抛物线函数每次更新区间直至逼近极值。
下面附上自己编写的相关函数:
double Advance_retreat(double h, double x0,double accuracy,int function_number)
{
double x;
x=x0;
while(abs(h)>accuracy)//截止判断条件
{
if ((function_select(function_number,(x+h)))<(function_select(function_number,(x))))//进退法进成功的判断条件
{
x=x+h;
h=h*2;
}
else
{
h=-h/4;
x=x+h;
}
}
printf("极值点:%lf\n",x);
printf("极小值为:%lf\n",(function_select(function_number,x)));
return x;
}
double golden_section( double q,double a,double b,double accuracy,int function_number)
{
double u1,u2;//黄金分割法中间所需的试验点
while(abs(b-a)>accuracy)
{u1=b-q*(b-a);
u2=a+q*(b-a);
if((function_select(function_number,u1))<(function_select(function_number,u2)))
b=u2;
else
a=u1;
}
if((function_select(function_number,a))<(function_select(function_number,b)))
{
printf("极值点:%lf\n",a);
printf("极小值为:%lf\n",(function_select(function_number,a)));
return a;
}
else
{
printf("极值点:%lf\n",b);
printf("极小值为:%lf\n",(function_select(function_number,b)));
return b;
}
}
double *Determine_the_interva(double *p,double x,double h0,int function_number)//用来确定黄金分割法区间选择的函数
{
double a,b,h;
h=h0;
b=x+h;
while(function_select(function_number,b)<function_select(function_number,x))
{
h=2*h;
b=x+h;
}
h=h0;
a=x-h;
while(function_select(function_number,a)<function_select(function_number,x))
{
h=2*h;
a=x-h;
}
p[0]=a;
p[1]=b;
printf("利用区间选择法为您所确定的初始区间为[%lf %lf]\n",a,b);
return p;
}
void Fibonacci(double accuracy,double a,double b,int function_number)
{
double c,u1,u2;
c=(b-a)/accuracy;
double *F;
F=(double*)malloc(sizeof(double)*1000);
F[0]=1,F[1]=1;
int i=1;
while(F[i]<c)//构造斐波那契数列
{i++;
F[i]=F[i-1]+F[i-2];
}
int N=i;//保存满足条件的下标代号
while(N>=2)
{u1=a+(F[N-2]/F[N])*(b-a);
u2=a+(F[N-1]/F[N])*(b-a);
if((function_select(function_number,u1))<(function_select(function_number,u2)))
b=u2;
else
a=u1;
N--;
}
if((function_select(function_number,a))<(function_select(function_number,b)))
{
printf("极值点:%lf\n",a);
printf("极小值为:%lf\n",(function_select(function_number,a)));
}
else
{
printf("极值点:%lf\n",b);
printf("极小值为:%lf\n",(function_select(function_number,b)));
}
free(F);
}
void polynomial_approximation_Newton(double x0,double accuracy,int function_number)
{
double *p;//数组地址是常量,不能被指针赋值
double x;
x=x0;
int i;
p=(double*)malloc(2*sizeof(double));
p=(double*)one_dimensional_Function_gradient(p,x,function_number);//返回对应函数要求的保存梯度信息的指针
double *result;
result=(double*)malloc(1000*sizeof(double));
*result=x0;
*(result+1)=*result-(*p)/(*(p+1));
//printf("%lf\n",*p);
i=1;
while (abs(*(result+i)-*(result+i-1))>accuracy)
{
p=(double *)one_dimensional_Function_gradient(p, *(result+i), function_number);//返回对应函数要求的保存梯度信息的指针
*(result+i+1)=*(result+i)-(*p)/(*(p+1));
i++;
}
printf("极值点:%lf",result[i-1]);
printf("极值为:%lf\n",(function_select(function_number,result[i-1])));
free(p);
free(result);
p=NULL;
result=NULL;
}
void polynomial_approximation_paracurve(double accuracy,double x1,double x2,double x3,int function_number)
{
double x;
x=0.5*((x2*x2-x3*x3)*function_select(function_number,x1)+(x3*x3-x1*x1)*function_select(function_number,x2)+(x1*x1-x3*x3)*function_select(function_number,x3))/((x2-x3)*function_select(function_number,x1)+(x3-x1)*function_select(function_number,x2)+(x1-x3)*function_select(function_number,x3));
while (abs(x-x2)>accuracy)
{
if(function_select(function_number,x)>function_select(function_number,x2)&&(x<=x2))
{
x1=x;
}
else if(function_select(function_number,x)>function_select(function_number,x2)&&(x>x2))
{
x3=x;
}
else if(function_select(function_number,x)<function_select(function_number,x2)&&(x>x2))
{
x1=x2;
x2=x;
}
else if(function_select(function_number,x)<function_select(function_number,x2)&&(x<=x2))
{
x3=x2;
x2=x;
}
x=0.5*((x2*x2-x3*x3)*function_select(function_number,x1)+(x3*x3-x1*x1)*function_select(function_number,x2)+(x1*x1-x3*x3)*function_select(function_number,x3))/((x2-x3)*function_select(function_number,x1)+(x3-x1)*function_select(function_number,x2)+(x1-x3)*function_select(function_number,x3));
}
if((function_select(function_number,x))<(function_select(function_number,x2)))
{
printf("极值点:%lf\n",x);
printf("`` 小值为:%lf\n",(function_select(function_number,x)));
}
else
{
printf("极值点:%lf\n",x2);
printf("极小值为:%lf\n",(function_select(function_number,x2)));
}
}
上面是对于单变量函数的一些优化算法的归纳,很明显上述所有单变量方法都只是针对局部最优,其没有跳出局部最优的能力,即是说其结果是受初始值决定的,而一般而言寻找全局最后莫过于两种途径,增加初始点的数目并且自学习向全局最优解靠近如粒子羣算法,或者概率接收不好的解从而跳出局部最优如模拟退火算法,或者像遗传算法一样通过交叉和变异指向全局最优。后面将会对这些算法整理总结,欢迎大家讨论指正。