1,问题叙述
用牛顿法求解下面问题
初始点取为=(-2,-1)=(-2,-1),请输出第10次和第50次迭代的结果,f()和, f().
2,详细实现:
2.1、导入依赖包
import math
import matplotlib.pyplot as plt
import numpy as np
from sympy import *
import xlwt
x1,x2,t = symbols('x1,x2,t')#设置变量符号
2.2、定义函数表达式,海森矩阵
def func():
return x1**6/3 -2.1*x1**4 +4*x1**2 -x1*x2 -4*x2**2 + 4*x2**4
def haisen(func):
H_mat = []
H_mat.append(diff(diff(func,x1),x1))
H_mat.append(diff(diff(func,x1),x2))
H_mat.append(diff(diff(func,x2),x1))
H_mat.append(diff(diff(func,x2),x2))
return np.array(H_mat).reshape((2,2))
2.3、设计函数,求海森矩阵在data处的值 ,data存放x1和x2的值
def compute_haisen_value(haisen,data):
res = np.zeros_like(haisen)
for i in range(2):
for j in range(2):
res[i][j] = haisen[i][j].subs(x1,data[0]).subs(x2,data[1])
return res
2.4、 设计函数,求原函数在data处的梯度,data同上。
def grad(data):
f = func()
df = [diff(f,x1),diff(f,x2)]
res = np.zeros_like(df)
for i in range(len(df)):
item = df[i]
res[i] = item.subs(x1,data[0]).subs(x2,data[1])
return np.array(res)
2.5、一维搜索函数,t0为初值,h为搜索跨度,sigma是判断循环终止的条件,可视为精度。
def one_dim_search(func,t0,h,sigma):
value1 = func.subs(t,t0)
delta = sigma
while(True):
value2 = func.subs(t,t0+h)
if(value2<=value1):
t0 += h
h *= 2
value1 = value2
continue
else:
if(abs(h)<=sigma):
res = t0 + h
break
else:
h *= -0.25
continue
return res
2.6、牛顿法迭代求极小值,sigma同上;x0为初值,应为1x2的列表,包含x1和x2的初值;k为迭代次数
def iterration(sigma,x0,k):
x0 = np.array(x0)
loc_x = [x0[0]]
loc_y = [x0[1]]
f = func()
value = [f.subs(x1, x0[0]).subs(x2, x0[1])]
haisen_mat = haisen(f)
grad_vec = grad(x0)
haisen_vec = np.array(compute_haisen_value(haisen_mat,x0))
grad_len = math.sqrt(pow(grad_vec[0], 2) + pow(grad_vec[1], 2))
while(k>0):
k -= 1
p = -np.dot(haisen_vec,grad_vec)
p /= max(p[0],p[1])
new_x = x0 + t*p
gt = f.subs(x1,new_x[0]).subs(x2,new_x[1])
t_min = one_dim_search(gt,0,0.1,sigma)
x0 = x0 + t_min*p
grad_vec = grad(x0)
haisen_vec = np.array(compute_haisen_value(haisen_mat,x0))
grad_len = math.sqrt(pow(grad_vec[0], 2) + pow(grad_vec[1], 2))
loc_x.append(x0[0])
loc_y.append(x0[1])
value.append(f.subs(x1, x0[0]).subs(x2, x0[1]))
print("\nlastvalue:",f.subs(x1,x0[0]).subs(x2,x0[1]))
plt.plot(loc_x, loc_y)
plt.show()
return loc_x, loc_y, value
2.7、主函数,分别调用iteration获得结果集,将其写入到表格文件中。
if __name__ == '__main__':
#绘制迭代10次的结果,图像和具体值表格。
work_book = xlwt.Workbook() #生成工作簿对象
loc_x, loc_y, value = iterration(0.0001, [-2, -1], 10) #获得列表形式的结果集
sheet1 = work_book.add_sheet(u'迭代10', cell_overwrite_ok=True) #生成表一
sheet1.write(0, 1, 'x') #列属性名,下同
sheet1.write(0, 1, 'y')
sheet1.write(0, 1, '值')
for i in range(0, len(loc_x)):
sheet1.write(i + 1, 0, float(round(loc_x[i], 7))) #第一列为x坐标,保留7位小数
sheet1.write(i + 1, 1, float(round(loc_y[i], 7))) #第二列为y坐标,保留7位小数
sheet1.write(i + 1, 2, float(round(value[i], 7))) #第三列为函数值,保留7位小数
#绘制迭代50次的结果,图像和具体值表格。
loc_x2, loc_y2, value2 = iterration(0.0001, [-2, -1], 50)
sheet2 = work_book.add_sheet(u'迭代50', cell_overwrite_ok=True)
sheet2.write(0, 1, 'x')
sheet2.write(0, 1, 'y')
sheet2.write(0, 1, '值')
for i in range(0, len(loc_x2)):
sheet2.write(i + 1, 0, float(round(loc_x2[i], 7)))
sheet2.write(i + 1, 1, float(round(loc_y2[i], 7)))
sheet2.write(i + 1, 2, float(round(value2[i], 7)))
work_book.save('牛顿法.csv')
3,实验结果
3.1、迭代结果图:
3.2、详细结果列表:
第10次迭代:(-0.09301,-0.70874) -1.03145
第50次迭代:(-0.09223,-0.71172) -1.0316