如何高效获取含两个局部极小值函数的全局最小值?
单变量双局部极小值函数的全局优化解决方案
问题背景
需要最小化一个已知存在两个局部极小值的函数,但使用scipy.optimize.minimize_scalar只能找到局部最优解。由于需要执行数千次该计算,要求解决方案高效、耗时低。
函数定义
用于计算目标结果的函数如下:
import numpy as np def get_v_theta(v, theta): vx = v[0] vy = v[1] vz = v[2] v_theta = (vx + vy)/2 + (vx - vy)/2*np.cos(2*theta) + vz*np.sin(2*theta) return v_theta def get_result(v1_theta, v2_theta): v_max = max(v1_theta, v2_theta) v_min = min(v1_theta, v2_theta) v_med = (v_max + v_min)/2 v_alt = (v_max - v_min)/2 if v_med > 0: result = (v_alt/100 + v_med/400)**(-1) else: result = 100/v_alt return result def get_result_theta(theta, v1, v2): v1_theta = get_v_theta(v1, theta) v2_theta = get_v_theta(v2, theta) return get_result(v1_theta, v2_theta)
复现问题
给定示例向量:
v1 = np.array([2.91931, 0.758059, 0.10201]) v2 = np.array([-1.29405, 7.76101, -1.75803])
通过绘图可观察到全局极小值约在θ ≈ -1.4处:
import matplotlib.pyplot as plt thetas = np.arange(-np.pi/2, np.pi/2, np.pi/100) results = [get_result_theta(t, v1, v2) for t in thetas] plt.plot(thetas, results) plt.show()
但直接使用minimize_scalar仅能得到局部极小值θ ≈ 0.147:
from scipy import optimize res = optimize.minimize_scalar(get_result_theta, args=(v1, v2), method='bounded', bounds=(-np.pi/2, np.pi/2)) print(res.x) # 输出约0.147
快速全局优化方案
由于已知函数仅有两个局部极小值,可通过多初始点局部优化的方式快速找到全局最优,该方法耗时远低于全局优化算法(如差分进化),适合大规模计算。
实现思路
在目标区间内选取多个覆盖不同区域的初始点,分别执行局部优化,最终保留结果最小的那个解。因为函数只有两个局部极小值,只需选取2-5个初始点即可覆盖所有可能的极小值区域。
代码实现
def find_global_min(v1, v2): # 选取覆盖区间的初始点,确保涵盖两个极小值区域 init_points = [-np.pi/2, -np.pi/4, 0, np.pi/4, np.pi/2] best_fun = float('inf') best_theta = None for init in init_points: # 执行局部有界优化 res = optimize.minimize_scalar( get_result_theta, args=(v1, v2), method='bounded', bounds=(-np.pi/2, np.pi/2), x0=init ) # 更新最优结果 if res.fun < best_fun: best_fun = res.fun best_theta = res.x return best_theta, best_fun # 测试示例 best_theta, best_fun = find_global_min(v1, v2) print(f"全局最优θ: {best_theta:.3f}, 最小结果: {best_fun:.3f}") # 输出应为θ≈-1.4,对应最小结果
额外优化:提升函数计算速度
由于需要执行数千次计算,可简化目标函数的计算逻辑,减少重复运算:
def get_v_theta(v, theta): cos2t = np.cos(2 * theta) sin2t = np.sin(2 * theta) return (v[0] + v[1])/2 + (v[0] - v[1])/2 * cos2t + v[2] * sin2t def get_result(v1_theta, v2_theta): v_max = max(v1_theta, v2_theta) v_min = min(v1_theta, v2_theta) v_med = (v_max + v_min) / 2 v_alt = (v_max - v_min) / 2 return (v_alt/100 + v_med/400)**(-1) if v_med > 0 else 100/v_alt
替代方案:粗扫描+局部优化
如果不确定初始点的选择,可先对区间进行粗扫描,找到结果较小的几个候选点,再对这些点做局部优化:
def find_global_min_scan(v1, v2): # 粗扫描区间 scan_thetas = np.linspace(-np.pi/2, np.pi/2, 20) scan_results = [get_result_theta(t, v1, v2) for t in scan_thetas] # 取结果最小的前2个点作为初始点 top2_indices = np.argsort(scan_results)[:2] init_points = scan_thetas[top2_indices] best_fun = float('inf') best_theta = None for init in init_points: res = optimize.minimize_scalar(get_result_theta, args=(v1, v2), method='bounded', bounds=(-np.pi/2, np.pi/2), x0=init) if res.fun < best_fun: best_fun = res.fun best_theta = res.x return best_theta, best_fun
内容的提问来源于stack exchange,提问作者Juan
相关产品推荐
相关产品推荐

