1. 二分法
使用二分法求最小值需要函数f(x)一阶可导,即寻找导数为0的点:
因此,这一问题转化为求g(x)=f'(x)=0的根。
假设我们可以找到两个点和,,,根据中值定理,和之间一定有根。
二分法步骤如下:
1. 令.
2. 若,直接输出.
3. 否则:
1. 若,让;
2. 若,让;
4. 如果,停止循环,输出,否则返回步骤1.
代码实现如下:
def bisection(g,xl,xr,tol,maxit=200):
if g(xl)<0 and g(xr)>0:
i=0
while abs(xr-xl)>=tol and i<=maxit:
xm=(xl+xr)/2
#print(xl,xr)
if g(xm)>0:
xr=xm
if g(xm)<0:
xl=xm
if g(xm)==0:
break
i=i+1
return i,(xl+xr)/2
else:
print('wrong input')
return
根据二分法,我们可以找到f(x)近似的一个驻点。如果f(x)是凸函数,这个驻点为全局最小值点。
二分法容易实施,在实际应用中被广泛使用。然而,它存在缺点:我们必须知道f(x)的一阶导数形式。然而有时候函数的导数是非常难计算的。
所以,我们介绍另一种方法:黄金分割法。
黄金分割法的步骤如下:
假设我们有区间,。
1. 设.
2. 如果,最小值点一定在,故令。
3. 否则,令。
4. 如果,停止循环,输出,否则返回步骤1.
为了节约计算时间,我们想选择使得下一轮迭代的等于当前的,即。
解得。
代码实现:
import numpy as np
import matplotlib.pyplot as plt
def f(x):
return np.sqrt(1-x+x**2)-0.75*x
def golden_section(f,xl,xr,tol,maxit=200):
phi=(3-np.sqrt(5))/2
i=0
while abs(xr-xl)>=tol and i<=maxit:
xl_=phi*xr+(1-phi)*xl
xr_=phi*xl+(1-phi)*xr
#update xl and xr
if f(xl_)<f(xr_):
xr=xr_
else:
xl=xl_
i=i+1
#print(xl,xr)
return i,(xr+xl)/2
下面以
为例,分别使用二分法和黄金分割法进行求解:
def g(x):
return x*np.sin(x)*np.arctan(x)
#Derivation of g(x)
def delta_g(x):
return x*np.sin(x)/(1+x**2)+np.arctan(x)*(np.sin(x)+x*np.cos(x))
iter1,solution1=bisection(delta_g,-4,2,1e-5,200)
iter2,solution2=golden_section(g,-4,2,1e-5,200)
print('the bisection take %i interations get the solution %f'%(iter1,solution1))
print('the golden section take %i interations get the solution %f'%(iter2,solution2))