考虑非线性方程:
f ( x ) = sin ( x ) − e − x = 0 f(x)= \sin(x) - \mathrm{e}^{-x}=0 f(x)=sin(x)−e−x=0
1、 导入包库
import autograd.numpy as np
from autograd import grad
import matplotlib.pyplot as plt
2、定义函数
def sin_exp(x):
return np.sin(x) - np.exp(-x)
查看一下函数的图象:
x_points = np.linspace(-3,3,1000)
y_points = sin_exp(x_points)
plt.plot(x_points,y_points)
plt.show()
可见该函数在附近没有重根。
3、使用autograd
定义导数
grad_func = grad(sin_exp)
4、实现牛顿迭代
x k + 1 = x k − f ( x k ) f ′ ( x k ) x^{k+1} = x^{k} - \frac{f(x^{k})}{f'(x^{k})} xk+1=xk−f′(xk)f(xk)
x = -3. # grad只支持float
fun_vals = [sin_exp(x)] # 该变量用于存储函数值
for i in range(50):
x -= sin_exp(x)/grad_func(x)
fun_vals.append(sin_exp(x))
print('x=',x)
print('f(x)=',sin_exp(x))
x= 0.5885327439818611
f(x)= 0.0
画出收敛过程:
plt.plot(fun_vals)
plt.show()
# 前10个点
plt.plot(fun_vals[:10])
plt.show()
5、用scipy
对应方法检验结果
from scipy.optimize import root
result = root(sin_exp,-3.)
print('x=',result.x)
print('f(x)=',result.fun)
x= [0.58853274]
f(x)= [0.]
对比一下差距:
print(x-result.x)
[0.]
6、小结
(1)用autograd
实现简单非线性方程十分简单
(2)牛顿迭代收敛速度极快
另外:
(1)函数本身的性质仍然会影响算法的收敛性。本文选取的函数在给定区间内仅有一个根,更复杂的情况未讨论。
(2)初始值的选取仍然会影响算法收敛性,本文亦未讨论。