我正在尝试使用mpmath.findroot的多维牛顿方法以数字方式高精度地求解方程组。这是一个示例系统:
def f(x_0, x_1, x_2, x_3, x_4, x_5, y_0, y_1, y_2, y_3, y_4, y_5, l_0, l_1,l_2, l_3, l_4, l_5, l_6, l_7, l_8, l_9, l_10, l_11, l_12, l_13, l_14):
return -x_0, -y_0 + 1, -x_5, -y_5, -x_1 - x_2, -y_1 + y_2, -x_3 - x_4, -y_3 + y_4, -(x_1 - x_5)^2 - (y_1 - y_5)^2 + 1, -(x_1 - x_4)^2 - (y_1 - y_4)^2 + 1, -(x_0 - x_5)^2 - (y_0 - y_5)^2 + 1, -(x_3 - x_4)^2 - (y_3 - y_4)^2 + 1, -(x_2 - x_3)^2 - (y_2 - y_3)^2 + 1, -(x_2 - x_5)^2 - (y_2 - y_5)^2 + 1, -(x_0 - x_5)^2 - (y_0 - y_5)^2 + 1, 2*l_10*(x_0 - x_5) + 2*l_14*(x_0 - x_5) + l_0 - .5*y_1 + .5*y_2, 2*l_9*(x_1 - x_4) + 2*l_8*(x_1 - x_5) + l_4 + .5*y_0 - .5*y_3, 2*l_12*(x_2 - x_3) + 2*l_13*(x_2 - x_5) - .5*y_0 + .5*y_4, -2*l_12*(x_2 - x_3) + 2*l_11*(x_3 - x_4) + l_6 + .5*y_1 - .5*y_5, -2*l_9*(x_1 - x_4) - 2*l_11*(x_3 - x_4) - .5*y_2 + .5*y_5, -2*l_10*(x_0 - x_5) - 2*l_14*(x_0 - x_5) - 2*l_8*(x_1 - x_5) - 2*l_13*(x_2 - x_5) + l_2 + .5*y_3 - .5*y_4, 2*l_10*(y_0 - y_5) + 2*l_14*(y_0 - y_5) + l_1 + .5*x_1 - .5*x_2, 2*l_9*(y_1 - y_4) + 2*l_8*(y_1 - y_5) + l_5 - .5*x_0 + .5*x_3, 2*l_12*(y_2 - y_3) + 2*l_13*(y_2 - y_5) + .5*x_0 - .5*x_4, -2*l_12*(y_2 - y_3) + 2*l_11*(y_3 - y_4) + l_7 - .5*x_1 + .5*x_5, -2*l_9*(y_1 - y_4) - 2*l_11*(y_3 - y_4) + .5*x_2 - .5*x_5, -2*l_10*(y_0 - y_5) - 2*l_14*(y_0 - y_5) - 2*l_8*(y_1 - y_5) - 2*l_13*(y_2 - y_5) + l_3 - .5*x_3 + .5*x_4
import sage.libs.mpmath.all as mpmath
startsol=[0, -0.345847373297000, 0.345847770952000, -0.499999005131000, 0.500000393924000, 0, 0.999999726908000, 0.938291180327000, 0.938290404618000, 0.404864576964000, 0.404866700310000, 0, 0, 0.0205563218420000, 0.00287356421947000, -0.0200611112418000, 0.00371301649518000, 0.00363938213640000, -0.00658839856658000, -0.00414258257348000, 0.0391290458552000, 0.162094656373000, 0.0813226022151000, 0.0974643704937000, 0.158202488927000, 0.0432804352887000, 0.0813226022151000]
print f(*startsol)
mpmath.mp.dps=100
ans=mpmath.findroot(f, startsol)
不幸的是,它没有给我一个解决方案,但却抛出错误
ZeroDivisionError:矩阵是数字奇异的
这是否正在发生,因为findroot正试图计算jacobian?这是否意味着系统不确定?
我使用scipy的fmin_cg找到了起点,但我希望将解决方案提高到更高的精度。作为fmin_cg的函数,我最小化了函数f的27个条目的平方和。
如果无法避免mpmath.findroot的问题,有没有更好的方法来解决这个系统的高精度?
答案 0 :(得分:1)
是的,系统不确定,雅各布矩阵的等级为24(最多)而不是27.您可以使用SymPy来检查:
import sympy as sp
vars = sp.var('x_0, x_1, x_2, x_3, x_4, x_5, y_0, y_1, y_2, y_3, y_4, y_5, l_0, l_1,l_2, l_3, l_4, l_5, l_6, l_7, l_8, l_9, l_10, l_11, l_12, l_13, l_14')
F = sp.Matrix([-x_0, -y_0 + 1, -x_5, -y_5, -x_1 - x_2, -y_1 + y_2, -x_3 - x_4, -y_3 + y_4, -(x_1 - x_5)**2 - (y_1 - y_5)**2 + 1, -(x_1 - x_4)**2 - (y_1 - y_4)**2 + 1, -(x_0 - x_5)**2 $
J = F.jacobian(vars)
print(J.rank())
仔细观察雅可比矩阵可以看出冗余方程是什么。例如,这些是编号为0-3和10的等式:
-x_0 = 0
-y_0 + 1 = 0
-x_5 = 0
-y_5 = 0
-(x_0 - x_5)^2 - (y_0 - y_5)^2 + 1 = 0
显然,最后一个是前四个的结果。这种冗余需要消失。
如果mpmath.findroot没有给出计算雅可比行列式的函数,它将使用数值微分,引入额外的错误。如果可用,最好提供雅可比功能。这是一个完整性的小代码示例。
import sympy as sp
import mpmath as mp
vars = sp.var('x, y, z')
F = [x**2 + y**3 + z**4 - 6, x + y + z - 2, 3*x**2 + y - 5]
J = sp.Matrix(F).jacobian(vars)
f = lambda x0,y0,z0 : [Fc.subs(list(zip(vars, [x0,y0,z0]))) for Fc in F]
Jac = lambda x0,y0,z0 : J.subs(list(zip(vars, [x0,y0,z0]))).tolist()
start = [1, 1, 1]
print(mp.findroot(f, start, J = Jac))