Julia 使用NLsolve.jl的拉格朗日乘子法

Julia 使用NLsolve.jl的拉格朗日乘子法,julia,Julia,我想在g(z)=0的约束下最小化距离函数|dz-z | |。 我想用拉格朗日乘数来解决这个问题。然后我用NLsolve.jl来解我最后得到的非线性方程 using NLsolve using ForwardDiff function ProjLagrange(dz, g::Function) λ_init = ones(size(g(dz...),1)) initial_x = vcat(dz, λ_init) function gradL!(F, x)

我想在
g(z)=0
的约束下最小化距离函数
|dz-z | |
。 我想用拉格朗日乘数来解决这个问题。然后我用
NLsolve.jl
来解我最后得到的非线性方程

using NLsolve
using ForwardDiff

function ProjLagrange(dz, g::Function)
    λ_init = ones(size(g(dz...),1))
    initial_x = vcat(dz, λ_init)

    function gradL!(F, x)
        len_dz = length(dz)
        z = x[1:len_dz]
        λ = x[len_dz+1:end]
        
        F = Array{Float64}(undef, length(x))

        my_distance(z) = norm(dz - z)
        ∇f = z -> ForwardDiff.gradient(my_distance, z)
        F[1:len_dz] = ∇f(z) .- dot(λ, g(z...))

        if length(λ) == 1
            F[end] = g(z...) 
        else
            F[len_dz+1:end] = g(z) 
        end
    end
    nlsolve(gradL!, initial_x)
end


g_test(x1, x2, x3) = x1^2 + x2 - x2 + 5
z = [1000,1,1]

ProjLagrange(z, g_test)

但我总是以
零结尾:[NaN,NaN,NaN,NaN]
收敛:false
。 正如你所知道的,我已经通过使用
Optim.jl
并最小化以下函数来解方程:
Proj(z)=b*sum(abs.(g(z))+a*norm(dz-z)

但我真的很想知道NLsolve是否可以做到这一点。非常感谢您的帮助

我修改了您的代码,如下所示(请参见此处的注释),并获得了以下输出。它不再抛出
NaN
s,减少目标并收敛。这与您的
Optim.jl
结果是否不同

Results of Nonlinear Solver Algorithm
 * Algorithm: Trust-region with dogleg and autoscaling
 * Starting Point: [1000.0, 1.0, 1.0, 1.0]
 * Zero: [9.80003, -49.5203, 51.5203, -0.050888]
 * Inf-norm of residuals: 0.000000
 * Iterations: 10
 * Convergence: true
   * |x - x'| < 0.0e+00: false
   * |f(x)| < 1.0e-08: true
 * Function Calls (f): 11
 * Jacobian Calls (df/dx): 11


[编辑:调整了解决方案,将正确的梯度计算纳入g()]

几乎从零开始,维基百科的,因为它对我有好处,下面的代码似乎可以工作。我加了一个
λ₀s
参数设置为
ProjLagrange
函数,这样它就可以接受初始乘法器
λ
值的向量(我看到您将它们初始化为
1.0
,但我认为这更通用)。(请注意,这尚未针对性能进行优化!)

给我

julia> res = ProjLagrange(x₀_test, λ₀s_test, gs_test, n_it)
Results of Nonlinear Solver Algorithm
 * Algorithm: Trust-region with dogleg and autoscaling
 * Starting Point: [1000.0, 1.0, 1.0, 1.0]
 * Zero: [9.800027199717013, -49.52026655749088, 51.520266557490885, -0.050887973682118504]
 * Inf-norm of residuals: 0.000000
 * Iterations: 10
 * Convergence: true
 * |x - x'| < 0.0e+00: false
 * |f(x)| < 1.0e-08: true
 * Function Calls (f): 11
 * Jacobian Calls (df/dx): 11
julia>res=ProjLagrange(x₀_试验,λ₀s_测试、gs_测试、n_测试)
非线性求解算法的结果
*算法:带狗腿和自动缩放的信赖域
*起点:[1000.0,1.0,1.0,1.0]
*零:[9.800027199717013,-49.52026655749088,51.520266557490885,-0.0508879736682118504]
*残差的Inf范数:0.000000
*迭代次数:10次
*收敛性:正确
*| x-x'|<0.0e+00:错误
*| f(x)|<1.0e-08:正确
*函数调用(f):11
*雅可比调用(df/dx):11
using NLsolve, ForwardDiff, LinearAlgebra
function ProjLagrange(x₀, λ₀s, gs, n_it)
    # distance function from x₀ and its gradients
    f(x) = norm(x - x₀)
    ∇f(x) = ForwardDiff.gradient(f, x)

    # gradients of the constraints
    ∇gs = [x -> ForwardDiff.gradient(g, x) for g in gs]

    # Form the auxiliary function and its gradients
    ℒ(x,λs) = f(x) - sum(λ * g(x) for (λ,g) in zip(λs,gs))
    ∂ℒ∂x(x,λs) = ∇f(x) - sum(λ * ∇g(x) for (λ,∇g) in zip(λs,∇gs))
    ∂ℒ∂λ(x,λs) = [g(x) for g in gs]
    
    # as a function of a single argument
    nx = length(x₀)
    ℒ(v) = ℒ(v[1:nx], v[nx+1:end])
    ∇ℒ(v) = vcat(∂ℒ∂x(v[1:nx], v[nx+1:end]), ∂ℒ∂λ(v[1:nx], v[nx+1:end]))

    # and solve
    v₀ = vcat(x₀, λ₀s)
    nlsolve(∇ℒ, v₀, iterations=n_it)
end

# test
gs_test = [x -> x[1]^2 + x[2] - x[3] + 5]
λ₀s_test = [1.0]
x₀_test = [1000.0, 1.0, 1.0]
n_it = 100

res = ProjLagrange(x₀_test, λ₀s_test, gs_test, n_it)
julia> res = ProjLagrange(x₀_test, λ₀s_test, gs_test, n_it)
Results of Nonlinear Solver Algorithm
 * Algorithm: Trust-region with dogleg and autoscaling
 * Starting Point: [1000.0, 1.0, 1.0, 1.0]
 * Zero: [9.800027199717013, -49.52026655749088, 51.520266557490885, -0.050887973682118504]
 * Inf-norm of residuals: 0.000000
 * Iterations: 10
 * Convergence: true
 * |x - x'| < 0.0e+00: false
 * |f(x)| < 1.0e-08: true
 * Function Calls (f): 11
 * Jacobian Calls (df/dx): 11