如何用Python求解SymPy定义的符号非线性函数的区间极值?
代码修改与结果提取方案
一、提取最小值的x与对应函数值
原代码中fmin_tnc的返回值是包含优化结果的元组,需先将SymPy表达式转为可调用的数值函数,再提取并计算结果。修改后的代码如下:
import sympy as smp import scipy as sp import numpy as np max_width_constraint = 1.4 min_width_constraint = 0.6 b_beam_prismatic = 112.0e-09 x = smp.symbols('x') b1 = 1.4 b2 = 0.0387587871746277 b3 = 1.28980485524082 b4 = 21.4341387770796 zeta = b1 * (1 - b2 * (x)**b3)**b4 # 将SymPy表达式转为可调用的数值函数 zeta_func = smp.lambdify(x, zeta, 'numpy') # 求解区间[0,1]内的最小值 min_result = sp.optimize.fmin_tnc(zeta_func, np.array([0.5]), approx_grad=True, bounds=[(0, 1)]) x_min = min_result[0][0] # 提取最优x值(返回的是一维数组,取第一个元素) zeta_min = zeta_func(x_min) # 计算对应最小值 print(f"最小值点x: {x_min:.6f}") print(f"最小值zeta: {zeta_min:.6f}")
说明:
- 调整初始猜测值为
0.5,避免局部优化器因初始点过偏陷入局部极值; fmin_tnc返回元组的第一个元素是优化后的x数组,需用[0][0]提取单个数值;- 通过转换后的
zeta_func代入x值计算函数值,结果更准确。
二、求解区间内的最大值
SciPy多数优化器默认求最小值,可通过最小化原函数的相反数实现最大值求解,代码如下:
# 定义原函数的相反数 neg_zeta = -zeta neg_zeta_func = smp.lambdify(x, neg_zeta, 'numpy') # 求解相反数的最小值,对应原函数的最大值 max_result = sp.optimize.fmin_tnc(neg_zeta_func, np.array([0.0]), approx_grad=True, bounds=[(0, 1)]) x_max = max_result[0][0] zeta_max = zeta_func(x_max) # 用原函数计算最大值 print(f"最大值点x: {x_max:.6f}") print(f"最大值zeta: {zeta_max:.6f}")
说明:初始猜测值设为0.0,是因为观察函数形式可知,x=0时括号内项为1,函数值达到初始峰值,更易找到全局最大值。
三、全局优化方案(可选,更可靠)
对于非线性函数,局部优化器可能陷入局部极值,推荐使用differential_evolution全局搜索,无需初始猜测,直接指定区间:
# 全局求解最小值 min_global = sp.optimize.differential_evolution(zeta_func, bounds=[(0, 1)]) x_min_global = min_global.x[0] zeta_min_global = min_global.fun # 全局求解最大值 max_global = sp.optimize.differential_evolution(neg_zeta_func, bounds=[(0, 1)]) x_max_global = max_global.x[0] zeta_max_global = -max_global.fun # 取反得到原函数最大值 print(f"全局最小值点x: {x_min_global:.6f}") print(f"全局最小值zeta: {zeta_min_global:.6f}") print(f"全局最大值点x: {x_max_global:.6f}") print(f"全局最大值zeta: {zeta_max_global:.6f}")
内容的提问来源于stack exchange,提问作者iKD
相关产品推荐
相关产品推荐

