Skip to content

NLSolvers.converged(ci::ConvergenceInfo) #43

@longemen3000

Description

@longemen3000

i'm rewiewing some code that uses optim, and it uses the x_converged, g_converged and f_converged fields of OptimizationResults. at the moment, there are some functions with the same name, but not defined on the ConvergenceInfo object. a mockup (based on show(io,mime,ci::ConvergenceInfo) would be the following:

x_converged(ci::NLSolvers.ConvergenceInfo) = false
f_converged(ci::NLSolvers.ConvergenceInfo) = false
g_converged(ci::NLSolvers.ConvergenceInfo) = false

function x_converged(ci::NLSolvers.ConvergenceInfo{<:NLSolvers.NelderMead,<:Any,<:NLSolvers.OptimizationOptions})
    return ci.info.ρs <= ci.options.x_abstol
end

function x_converged(ci::NLSolvers.ConvergenceInfo{<:NLSolvers.SimulatedAnnealing,<:Any,<:NLSolvers.OptimizationOptions})
    #don't know what to do do here, simulated annealing does not "converge" in the typical sense
    return true
end

function x_converged(ci::NLSolvers.ConvergenceInfo{<:Any,<:Any,<:NLSolvers.OptimizationOptions})
    info = ci.info
    opt = ci.options
    x_abstol = haskey(info, :ρs) && (info.ρ <= opt.x_abstol)
    x_reltol = haskey(info, :ρs) && (info.ρs/info.ρx <= opt.x_reltol)
    return x_abstol || x_reltol
end

function f_converged(ci::NLSolvers.ConvergenceInfo{<:Any,<:Any,<:NLSolvers.OptimizationOptions})
    info = ci.info
    opt = ci.options
    f_limit = !isfinite(opt.f_limit) || (info.minimum <= opt.f_limit)
    f_abstol = haskey(info, :fx) && (abs(info.fx - info.minimum) <= opt.f_abstol)
    f_reltol = haskey(info, :fx) && (abs((info.fx - info.minimum)/info.fx) <= opt.f_reltol)
    return f_limit || f_abstol || f_reltol
end

function f_converged(ci::NLSolvers.ConvergenceInfo{<:Any,<:Any,<:NLSolvers.NEqOptions})
    ρF = norm(ci.info.best_residual, Inf)
    #ρFz = norm(ci.info.solution, 2)
    f_abstol = ρF <= opt.f_abstol
    return f_abstol
end

function g_converged(ci::NLSolvers.ConvergenceInfo{<:Any,<:Any,<:NLSolvers.OptimizationOptions})
    info = ci.info
    opt = ci.options
    if haskey(info, :∇fz)
        ρ∇f = opt.g_norm(info.∇fz)
        g_abstol = ρP<=opt.g_abstol
        g_reltol = ρ∇f/info.∇f0<=opt.g_reltol
        if haskey(info, :prob) && hasbounds(info.prob)
            ρP = opt.g_norm(
                info.solution .- clamp.(info.solution .- info.∇fz, info.prob.bounds...),
            )
            gp_abstol = ρP <= opt.g_abstol
        else
            gp_abstol = false
        end
    else
        g_abstol =  false
        g_reltol = false
    end
    return g_abstol || g_reltol || gp_abstol
end


function converged(ci::NLSolvers.ConvergenceInfo)
    opt = ci.options
    info = ci.info
    conv_flags = x_converged(ci) || f_converged(ci) || g_converged(ci)
    if haskey(info, :Δ)
        Δmin = ci.solver.Δupdate.Δmin isa Nothing ? 0 : ci.solver.Δupdate.Δmin
        Δ = info.Δ <= Δmin
        Δ_finite = isfinite(info.Δ)
    else
        Δ = false
        Δ_finite = true
    end
    x = x_converged(ci)
    f = f_converged(ci)
    g = g_converged(ci)
    #finite flags
    x_finite = all(isfinite,NLSolvers.solution(ci))
    conv_flags = f || x || g || Δ
    finite_flags = x_finite && Δ_finite #  && g_finite && f_finite
    return conv_flags && finite_flags
end

what is missing is a general way to calculate the finiteness of the other stopping criteria, to address JuliaNLSolvers/Optim.jl#997

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions