我想将这个实现多元牛顿拉夫逊方法的Julia代码翻译成Python,并扩展它以接受一个四元变量方程组。
代码如下:
using SymPy
x, y = Sym("x, y")
function SymPyDerivatives(f::String, g::String)
#
# Returns the string representations of all
# partial derivatives of the expression in x and y,
# given in the strings f and g.
#
formf = parse(f)
evalformf = eval(formf)
fx = diff(evalformf, x)
fy = diff(evalformf, y)
formg = parse(g)
evalformg = eval(formg)
gx = diff(evalformg, x)
gy = diff(evalformg, y)
return [string(fx) string(fy); string(gx) string(gy)]
end
function NewtonStep(fun::Array{SymPy.Sym,1},
jac::Array{SymPy.Sym,2},
x0::Float64, y0::Float64)
#
# Runs one step with Newton’s method
#
valfun = -SymPyFun(fun, x0, y0)
nfx = norm(valfun)
valmat = SymPyMatrixEvaluate(jac, x0, y0)
update = valmat\valfun
ndx = norm(update)
x1 = x0 + update[1]
y1 = y0 + update[2]
sfx = @sprintf("%.2e", nfx)
sdx = @sprintf("%.2e", ndx)
sx1 = @sprintf("%.16e", x1)
sy1 = @sprintf("%.16e", y1)
println(" $sfx $sdx $sx1 $sy1 ")
return [x1, y1]
end
function main()
#
# Prompts the user for expressions in x and y,
# calls SymPy to take the derivatives with respect
# to x and y of the two given expressions.
#
println("Reading two expressions, hit enter for examples")
print("Give a first expression in x and y : ")
one = readline(STDIN)
if one == ""
one = "exp(x) - y"
two = "x*y - exp(x)"
x0, y0 = 0.9, 2.5
else
print("Give a second expression in x and y : ")
two = readline(STDIN)
print("Give a value for x0 : ")
x0 = parse(Float64(readline(STDIN)))
print("Give a value for y0 : ")
y0 = parse(Float64(readline(STDIN)))
end
derivatives = SymPyDerivatives(one, two)
println("The Jacobian matrix :")
println(derivatives)
fx = derivatives[1,1]
fy = derivatives[1,2]
gx = derivatives[2,1]
gy = derivatives[2,2]
jacmat = SymPyMatrix(fx, fy, gx, gy)
valmat = SymPyMatrixEvaluate(jacmat, x0, y0)
vecfun = SymPyExpressions(one, two)
for i=1:5
xsol, ysol = NewtonStep(vecfun, jacmat, x0, y0)
x0, y0 = xsol, ysol
end
end
main()
我的问题是,我从未有效地使用过 Julia
,虽然我对牛顿法非常了解,但我不太明白这段代码。
以下是我目前的理解:
在 function NewtonStep()
内部
不确定这里发生了什么:
valfun = -SymPyFun(fun, x0, y0)
我们计算矩阵的范数
nfx = norm(valfun)
不确定这里发生了什么:
valmat = SympPyMatrixEvaluate(jax,c, x0, y0)
更新矩阵:
update = valmat\valfun
ndx = norm(update)
不确定接下来会发生什么。为什么function SymPyDerivatives()
从未被使用?它肯定有用途。
不太确定在function SymPyDerivatives()
内部发生了什么,除了计算偏导数的代码行。
更新:
尝试一步一步拆解,目前我已经了解了这些内容:
from sympy import symbols, diff
import numpy as np
class Localize:
receivers: list
def jacobian(f, g, h, k):
x, y, z = symbols('x y z', real=True)
fx = diff(f, x); gx = diff(g, x)
fy = diff(f, y); gy = diff(g, y)
hx = diff(h, x); kx = diff(k, x)
hy = diff(h, y); ky = diff(k, y)
def newtonStep(x0, x1):
# Magic happens
x1 = x0 + update[1]
y1 = y0 + update[2]
似乎找不到任何关于SymPyFun()
的文档,这很奇怪。
编辑:
根据我的研究和@steamsy的研究,似乎不存在SymPyFun()
,这很奇怪。也许有人知道这是什么意思以及在Python
中应该怎么做?不太确定它在这里应该做什么。
更新:
我找到了函数SymPyFun()
。
function SymPyFun(fun::Array{SymPy.Sym,1},
xval::Float64,yval::Float64)
#
# Given an array of SymPy expressions,
# evaluates the expressions at (xval, yval).
#
result1 = Float64(subs(subs(fun[1], x, xval), y, yval))
result2 = Float64(subs(subs(fun[2], x, xval), y, yval))
return [result1; result2]
end
parse(f)
在1.0之前就存在了)。 - MarcMushSymPyFun
是做什么的,但已经确定它是一个用户定义函数,以及上面提到的任何SymPyXXX
。其中一个例子似乎很奇怪,因为你有计算然后将其转换为字符串,似乎需要将其转换为表达式。我会寻找更符合惯用法的Julia代码进行转换。牛顿法绝对不是你想要进行符号计算的东西,当事情在数值上完成时,符号导数与自动微分相比没有任何优势。 - jverzani