理解并将这段 Julia 代码翻译成 Python

3

我想将这个实现多元牛顿拉夫逊方法的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

这似乎是相当旧的Julia代码(parse(f)在1.0之前就存在了)。 - MarcMush
我不确定SymPyFun是做什么的,但已经确定它是一个用户定义函数,以及上面提到的任何SymPyXXX。其中一个例子似乎很奇怪,因为你有计算然后将其转换为字符串,似乎需要将其转换为表达式。我会寻找更符合惯用法的Julia代码进行转换。牛顿法绝对不是你想要进行符号计算的东西,当事情在数值上完成时,符号导数与自动微分相比没有任何优势。 - jverzani
1个回答

1

似乎找不到SymPyFun()的任何文档,这很奇怪。

因为它不存在。这份文件关于SymPy.jl和我从GitHub源代码中获取的信息中都没有提到SymPyFun。

我猜你正在跟随UIC的这个PDF,这是我能找到唯一提到该方法的东西。


1
谢谢提供信息。找到了!:http://homepages.math.uic.edu/~jan/mcs471/multinewton.jl - 10GeV

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接