黄金分割法求解局部最小值——python实现

黄金分割法搜索局部最小值的原理是基于单峰函数的特性。

1、单峰函数

定义:

设f是定义在闭区间[a,b]上的一元函数,x是f在[a,b]上的极小点,并且对于任意的x1,x2属于[a,b],x1<x2;
若当x2<=x
时,f(x1)>f(x2), 当x*<=x1时,f(x2)>f(x1) 则称f是在闭区间[a,b]上的单峰函数。

形象地描述如图:

图中f(x)和g(x)均为单峰函数,即在一个区间上存在一个极值点可以将函数明确地分成两半具有单调性的曲线
图中f(x)和g(x)均为单峰函数,即在一个区间上存在一个极值点可以将函数明确地分成两半具有单调性的曲线。可以看到,单峰只是一个形象的称呼,也有单谷函数(区间)的称谓

2、黄金分割法

黄金分割法就是在单峰(谷)区间内搜索出最优解的算法,具体算法步骤如下图:

在这里插入图片描述

3、对黄金分割法的理论阐述

黄金分割法,顾名思义就是借用了黄金分割的办法。在具体说明黄金分割法之前,需要先说明试探法。
对于单峰(谷)区间,搜索出最优点的方法,可以从压缩区间考虑,如果搜索的区间足够小,那么在这个区间内的每一个点都可以当做是极小点。
基于这样的思路,开始进行试探。
在[a,b],选取两个试探点,x1, x2。计算出两个点的函数值,f(x1),f(x2)
比较f(x1)和f(x2):如果f(x1)>f(x2)存在两种情况
情况(1)
在这里插入图片描述
情况(2)
在这里插入图片描述
当f(x1)>f(x2)时存在上述两种情况,即x1和x2同在极小点的左侧,还是x1在左侧而x2在右侧。而可以肯定的一点就是:x1肯定不会在极小点的右侧。于是这时候就可以将极小点的范围从[a,b]缩小到[x1,b]。
同样的道理,当f(x1)<f(x2)时,可以将极小点的范围从[a,b]缩小到[a,x2].
以上就是试探法的基本原理,在我们选取试探点的时候,我们当然可以随意地选取,可以取两个试探点是[a,b]范围的随机数,这样也可以达到不断地缩小搜索区间的目的。但是作为一种算法,这存在了大量的随机,其算法的效率就是随机性的。因此,我们需要一种稳定的算法,最好就是每次都可以将区间按已知的比率压缩。
这时候我们可以在上一步的搜索区间中线性地设置试探点,即,两个试探点别是左侧的L分位点(L<0.5),和区间右侧的L分位点(L<0.5),这样,每次搜索都可以将区间压缩到原来区间的L倍。这样最终就可以得到足够小的搜索区间。
回到黄金分割数0.618.
于是这时候,我们的疑问转化为为什么L需要设置成1-0.618, 即为何每次要将区间压缩0.618倍。因为毕竟每次的L可以小到非常接近0.5。使得在迭代中压缩空间地更快。
这里面主要有节省算法中资源的考虑,在1-L为黄金分割数时,在进行下一次试探点的选取时候,可以将其中一个试探点取自上一时刻的点,节省了资源。推导过程如下:
在这里插入图片描述

4、python实现及验证

初学python练手,先用黄金分割法求解了f=exp(-x)+x**2在单谷区间(0,1)的最小值,最后调用了scipy库中的fminbound验证了程序有效

import math
from scipy.optimize import fmin,fminbound
# one dimension golden search
def f ( x ):
    L = math.exp(-x)+x**2
    return L
def golden(f ,*args):
    if not('a' in dir()):
        a=[]
        b=[]
    a.append(args[0])
    b.append(args[1])
    L=1e-16  # tolrence for convergence
    n=80   # max steps for iteration
    #a,b is the region containing opt point
    lambda1=a[0]+0.382*(b[0]-a[0])
    miu1=a[0]+0.618*(b[0]-a[0])
    #lambda1 miu1 is the test point of golden search method
    for k in range(0,n):
        if abs(b[k]-a[k])<=L:
            solve=(a[k]+b[k])/2
            break
        f_lambda1=f(lambda1)
        f_miu1=f(miu1)
        if f_lambda1>f_miu1:
            a.append(lambda1)
            b.append(b[k])
            lambda2=miu1
            miu2=a[k+1]+0.618*(b[k+1]-a[k+1])
        else:
            a.append(a[k])
            b.append(miu1)
            miu2=lambda1
            lambda2=a[k+1]+0.382*(b[k+1]-a[k+1])
        lambda1=lambda2
        miu1=miu2
    print('optimum point  is :',solve)
    return solve
print(golden(f,0,1))

验证程序结果:
这里调用的scipy库中的fminboud 函数。

# using embed fuction
min_global=fminbound(f,0,1)
print('min_global= ',min_global)

程序结果:

optimum point  is : 0.35173284738859334
0.35173284738859334
min_global=  0.35173538036861207

求解正确

  • 15
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
### 回答1: 牛顿是一种二次收敛的优化算,可用于求解非线性函数的最小。其基本思想是在当前点处,通过泰勒展开式来近似目标函数,然后求解近似函数的最小,得到下一个点的位置。该过程一直迭代下去,直到达到收敛条件。 下面是用Python实现牛顿求解最小的示例代码: ```python import numpy as np # 目标函数:f(x) = x^2 + 2x + 5 def func(x): return x**2 + 2*x + 5 # 目标函数的一阶导数 def grad_func(x): return 2*x + 2 # 目标函数的二阶导数 def hessian_func(x): return 2 # 牛顿求解最小 def newton_method(x0, eps=1e-6, max_iter=100): x = x0 iter_num = 0 while iter_num < max_iter: iter_num += 1 grad = grad_func(x) hessian = hessian_func(x) if abs(grad) < eps: break x = x - grad/hessian return x, iter_num # 测试 x0 = -5 x, iter_num = newton_method(x0) print("初始点:x0 = {}".format(x0)) print("最小点:x* = {}".format(x)) print("迭代次数:k = {}".format(iter_num)) print("最小:f(x*) = {}".format(func(x))) ``` 其中,`func`、`grad_func`和`hessian_func`分别表示目标函数、一阶导数和二阶导数。`newton_method`实现了牛顿求解最小的迭代过程。在测试中,初始点为`x0=-5`,精度为`eps=1e-6`,最大迭代次数为`max_iter=100`。运行结果如下: ``` 初始点:x0 = -5 最小点:x* = -0.9999999999999997 迭代次数:k = 6 最小:f(x*) = 4.999999999999998 ``` 除了牛顿,还有其他的拟牛顿可用于求解非线性函数的最小,如DFP算和BFGS算。这些算实现方式与牛顿类似,不同之处在于近似Hessian矩阵的更新方式。 ### 回答2: 牛顿是一种用于求解函数最小的迭代算。它基于泰勒级数展开,通过迭代逼近真实的最小。 首先,我们需要计算函数的一阶和二阶导数。在Python中,可以使用Scipy库的Optimize模块来实现。 接下来,我们需要选择一个初始作为迭代的起点。选择一个合适的初始对于收敛性至关重要。 然后,我们可以使用牛顿的迭代公式进行迭代。对于一元函数,迭代公式为:x = x - f(x)/f'(x)。对于多元函数,迭代公式为:x = x - H^(-1)*∇f(x),其中H为函数的海森矩阵,∇f(x)为函数的梯度。 在迭代过程中,我们需要设置一个停止准则。常用的准则包括函数的变化小于某个阈,迭代次数达到上限等等。 除了牛顿,拟牛顿也是一种常用的优化算。它通过迭代逼近海森矩阵的逆矩阵,而不需要计算海森矩阵本身。常用的拟牛顿包括DFP算和BFGS算。 牛顿和拟牛顿求解函数最小问题中具有较好的性能。它们在各类优化问题中被广泛应用,并且可以通过合适的参数调整来适应不同的目标函数。 总之,Python中可以使用Scipy库的Optimize模块来实现牛顿和拟牛顿求解函数的最小问题。这些算对于各类优化问题具有较好的性能和适用性。 ### 回答3: 牛顿和拟牛顿是最优化算中常见的求解最小的方之一,它们在python中可以很方便地实现。 牛顿的基本思想是通过使用二阶导数(海森矩阵)对目标函数进行近似,并通过迭代逼近目标函数的最小。在每一步迭代中,牛顿通过求解线性系统来确定迭代的方向。 具体实现牛顿的过程如下: 1. 定义目标函数,求目标函数的一阶导数和二阶导数。可以使用符号计算库(如SymPy)来自动求导。 2. 初始化迭代的起始点。 3. 在每一步迭代中,计算目标函数在当前点的一阶导数和二阶导数,并求得迭代方向。 4. 更新迭代点,重复步骤3,直到满足停止准则。 下面是一个使用牛顿求解最小的简单例子: ```python import sympy as sp def newton_method(f, x): # 求一阶导数和二阶导数 f_prime = sp.diff(f, x) f_double_prime = sp.diff(f_prime, x) # 初始化迭代起始点 x_0 = 0 while True: # 计算一阶导数和二阶导数在当前点的 f_prime_val = f_prime.subs(x, x_0).evalf() f_double_prime_val = f_double_prime.subs(x, x_0).evalf() # 计算牛顿方向 delta_x = -f_prime_val / f_double_prime_val # 更新迭代点 x_0 += delta_x # 判断停止准则 if abs(delta_x) < 1e-6: break return x_0.evalf() # 定义目标函数 x = sp.symbols('x') f = x ** 2 + sp.exp(x) # 使用牛顿求解最小 min_val = newton_method(f, x) print("The minimum value is:", min_val) ``` 除了牛顿,还有很多其他的最优化算可以用于求解最小,如拟牛顿。拟牛顿的思想是通过逐步构建一个近似的海森矩阵来代替目标函数的二阶导数,从而避免了求解二阶导数的复杂性。拟牛顿的具体实现和牛顿类似,只是在计算迭代方向时使用了近似的海森矩阵。 拟牛顿的一种常见算是BFGS算,其实现类似于牛顿,但在更新海森矩阵时使用了特定的公式。在python中,可以使用scipy库的optimize模块中的`minimize`函数来实现BFGS算。 以下是一个使用BFGS算求解最小的示例: ```python import scipy.optimize as opt # 定义目标函数 def f(x): return x ** 2 + np.exp(x) # 使用BFGS算求解最小 x_0 = 0 min_val = opt.minimize(f, x_0, method='BFGS').x print("The minimum value is:", min_val) ``` 以上就是使用python实现牛顿和拟牛顿求解最小的简单介绍。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值