diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml deleted file mode 100644 index 94a5bd8..0000000 --- a/.JuliaFormatter.toml +++ /dev/null @@ -1,3 +0,0 @@ -style = "sciml" -yas_style_nesting=false -ignore = ["docs"] \ No newline at end of file diff --git a/.github/workflows/FormatCheck.yml b/.github/workflows/FormatCheck.yml index 0b092a8..fc89659 100644 --- a/.github/workflows/FormatCheck.yml +++ b/.github/workflows/FormatCheck.yml @@ -8,41 +8,11 @@ on: tags: '*' pull_request: -concurrency: - # Skip intermediate builds: always, but for the master branch and tags. - # Cancel intermediate builds: always, but for the master branch and tags. - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.ref != 'refs/heads/master' && github.refs != 'refs/tags/*'}} - jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - matrix: - julia-version: [1] - julia-arch: [x86] - os: [ubuntu-latest] + runic: + runs-on: ubuntu-latest steps: - - uses: julia-actions/setup-julia@latest - with: - version: ${{ matrix.julia-version }} - - uses: actions/checkout@v4 - - name: Install JuliaFormatter and format - # This will use the latest version by default but you can set the version like so: - # - # julia -e 'using Pkg; Pkg.add(PackageSpec(name="JuliaFormatter", version="0.13.0"))' - run: | - julia -e 'using Pkg; Pkg.add(PackageSpec(name="JuliaFormatter"))' - julia -e 'using JuliaFormatter; format(".", verbose=true)' - - name: Format check - run: | - julia -e ' - out = Cmd(`git diff`) |> read |> String - if out == "" - exit(0) - else - @error "Some files have not been formatted !!!" - write(stdout, out) - exit(1) - end' \ No newline at end of file + - uses: fredrikekre/runic-action@v1 + with: + version: '1' diff --git a/README.md b/README.md index 1b2ca3b..0ebc135 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Build Status](https://github.com/fides-dev/Fides.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/fides-dev/Fides.jl/actions/workflows/CI.yml?query=branch%3Amain) [![Aqua QA](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl) [![codecov](https://codecov.io/gh/fides-dev/Fides.jl/graph/badge.svg?token=J7PXRF30JG)](https://codecov.io/gh/fides-dev/Fides.jl) -[![SciML Code Style](https://img.shields.io/static/v1?label=code%20style&message=SciML&color=9558b2&labelColor=389826)](https://github.com/SciML/SciMLStyle) +[![code style: runic](https://img.shields.io/badge/code_style-%E1%9A%B1%E1%9A%A2%E1%9A%BE%E1%9B%81%E1%9A%B2-black)](https://github.com/fredrikekre/Runic.jl) Fides.jl is a Julia wrapper of the Python package [Fides.py](https://github.com/fides-dev/fides), which implements an Interior Trust Region Reflective algorithm for bounds constrained optimization problems based on [1, 2]. Fides targets problems on the form: @@ -15,7 +15,7 @@ Fides.jl is a Julia wrapper of the Python package [Fides.py](https://github.com/ Where `f` is a continues at least twice-differentiable function, and `lb` and `ub` are the lower and upper bounds respectively. -## Highlights +## Main features - Boundary-constrained interior trust-region optimization. - Recursive reflective and truncated constraint management. diff --git a/docs/make.jl b/docs/make.jl index f4d5cd9..7ccb5d6 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -3,22 +3,28 @@ using Documenter DocMeta.setdocmeta!(Fides, :DocTestSetup, :(using Fides); recursive = true) -format = Documenter.HTML(;prettyurls = get(ENV, "CI", "false") == "true", - assets = String["assets/custom_theme.css"], - repolink = "https://github.com/fides-dev/Fides.jl", - edit_link = "main") +format = Documenter.HTML(; + prettyurls = get(ENV, "CI", "false") == "true", + assets = String["assets/custom_theme.css"], + repolink = "https://github.com/fides-dev/Fides.jl", + edit_link = "main" +) -makedocs(; modules = [Fides], - repo = "https://github.com/fides-dev/Fides.jl/blob/{commit}{path}#{line}", - checkdocs = :exports, - warnonly = false, - format = format, - sitename = "Fides.jl", - pages = [ - "Home" => "index.md", - "Tutorial" => "tutorial.md", - "API" => "API.md", - ],) +makedocs(; + modules = [Fides], + repo = "https://github.com/fides-dev/Fides.jl/blob/{commit}{path}#{line}", + checkdocs = :exports, + warnonly = false, + format = format, + sitename = "Fides.jl", + pages = [ + "Home" => "index.md", + "Tutorial" => "tutorial.md", + "API" => "API.md", + ], +) -deploydocs(; repo = "github.com/fides-dev/Fides.jl.git", - devbranch = "main",) +deploydocs(; + repo = "github.com/fides-dev/Fides.jl.git", + devbranch = "main", +) diff --git a/src/Fides.jl b/src/Fides.jl index 052a2dd..d61aa15 100644 --- a/src/Fides.jl +++ b/src/Fides.jl @@ -13,6 +13,7 @@ const np_py = PythonCall.pynew() function __init__() PythonCall.pycopy!(fides_py, PythonCall.pyimport("fides")) PythonCall.pycopy!(np_py, PythonCall.pyimport("numpy")) + return nothing end const STEPBACK_STRATEGIES = ["mixed", "refine", "reflect", "reflect_single", "truncate"] diff --git a/src/hessian_update.jl b/src/hessian_update.jl index fb730d9..ad43496 100644 --- a/src/hessian_update.jl +++ b/src/hessian_update.jl @@ -101,8 +101,9 @@ struct BFGS{T <: Union{Nothing, AbstractMatrix}} enforce_curv_cond::Bool init_with_hess::Bool end -function BFGS(; init_hess::Union{Nothing, AbstractMatrix} = nothing, - enforce_curv_cond::Bool = true) +function BFGS(; + init_hess::Union{Nothing, AbstractMatrix} = nothing, enforce_curv_cond::Bool = true + ) init_with_hess = _get_init_with_hess(init_hess) return BFGS(init_hess, enforce_curv_cond, init_with_hess) end @@ -128,8 +129,9 @@ struct DFP{T <: Union{Nothing, AbstractMatrix}} enforce_curv_cond::Bool init_with_hess::Bool end -function DFP(; init_hess::Union{Nothing, AbstractMatrix} = nothing, - enforce_curv_cond::Bool = true) +function DFP(; + init_hess::Union{Nothing, AbstractMatrix} = nothing, enforce_curv_cond::Bool = true + ) init_with_hess = _get_init_with_hess(init_hess) return DFP(init_hess, enforce_curv_cond, init_with_hess) end @@ -162,8 +164,10 @@ struct Broyden{T <: Union{Nothing, AbstractMatrix}} enforce_curv_cond::Bool init_with_hess::Bool end -function Broyden(phi::AbstractFloat; init_hess::Union{Nothing, AbstractMatrix} = nothing, - enforce_curv_cond::Bool = true) +function Broyden( + phi::AbstractFloat; init_hess::Union{Nothing, AbstractMatrix} = nothing, + enforce_curv_cond::Bool = true + ) init_with_hess = _get_init_with_hess(init_hess) return Broyden(phi, init_hess, enforce_curv_cond, init_with_hess) end diff --git a/src/options.jl b/src/options.jl index 6f12793..e8fc5a2 100644 --- a/src/options.jl +++ b/src/options.jl @@ -55,13 +55,15 @@ struct FidesOptions{T <: Union{String, Nothing}} gamma2::Float64 history_file::T end -function FidesOptions(; maxiter::Integer = 1000, fatol::Float64 = 1e-8, - frtol::Float64 = 1e-8, gatol::Float64 = 1e-6, grtol::Float64 = 0.0, +function FidesOptions(; + maxiter::Integer = 1000, fatol::Float64 = 1.0e-8, + frtol::Float64 = 1.0e-8, gatol::Float64 = 1.0e-6, grtol::Float64 = 0.0, xtol::Float64 = 0.0, maxtime::Float64 = Inf, verbose = "warning", subspace_solver::String = "2D", stepback_strategy::String = "reflect", delta_init::Float64 = 1.0, mu::Float64 = 0.25, eta::Float64 = 0.75, theta_max = 0.95, gamma1::Float64 = 0.25, gamma2::Float64 = 2.0, - history_file = nothing)::FidesOptions + history_file = nothing + )::FidesOptions if !(stepback_strategy in STEPBACK_STRATEGIES) throw(ArgumentError("$(stepback_strategy) is not a valid stepback strategy. \ Valid options are $(STEPBACK_STRATEGIES)")) @@ -75,9 +77,10 @@ function FidesOptions(; maxiter::Integer = 1000, fatol::Float64 = 1e-8, options are $(LOGGING_LEVELS)")) end - return FidesOptions(maxiter, fatol, frtol, gatol, grtol, xtol, maxtime, verbose, - stepback_strategy, subspace_solver, delta_init, mu, eta, theta_max, - gamma1, gamma2, history_file) + return FidesOptions( + maxiter, fatol, frtol, gatol, grtol, xtol, maxtime, verbose, stepback_strategy, + subspace_solver, delta_init, mu, eta, theta_max, gamma1, gamma2, history_file + ) end """ @@ -113,8 +116,12 @@ end function _get_verbose_py(verbose::String)::Int64 @assert verbose in LOGGING_LEVELS "Incorrect verbose level $verbose" - verbose == "warning" && return 30 - verbose == "info" && return 20 - verbose == "error" && return 40 - verbose == "debug" && return 10 + if verbose == "warning" + return 30 + elseif verbose == "info" + return 20 + elseif verbose == "error" + return 40 + end + return 10 end diff --git a/src/problem.jl b/src/problem.jl index 297d36f..dc24dde 100644 --- a/src/problem.jl +++ b/src/problem.jl @@ -68,8 +68,10 @@ struct FidesProblem{T <: AbstractVector} ub::T user_hessian::Bool end -function FidesProblem(f::Function, grad!::Function, x0::InputVector; hess! = nothing, - lb = nothing, ub = nothing) +function FidesProblem( + f::Function, grad!::Function, x0::InputVector; hess! = nothing, lb = nothing, + ub = nothing + ) _lb = _get_bounds(x0, lb, :lower) _ub = _get_bounds(x0, ub, :upper) # To ensure correct input type to f, grad!, hess! a variable having the same type as @@ -81,7 +83,8 @@ function FidesProblem(f::Function, grad!::Function, x0::InputVector; hess! = not return FidesProblem(fides_objective, fides_objective_py, x0, _lb, _ub, user_hessian) end function FidesProblem( - fides_objective::Function, x0::InputVector; lb = nothing, ub = nothing) + fides_objective::Function, x0::InputVector; lb = nothing, ub = nothing + ) _lb = _get_bounds(x0, lb, :lower) _ub = _get_bounds(x0, ub, :upper) # Get number of output arguments @@ -103,11 +106,12 @@ function FidesProblem( end function _get_fides_objective( - f::Function, grad!::Function, hess!::Union{Function, Nothing}, - xinput::InputVector, py::Bool)::Function + f::Function, grad!::Function, hess!::Union{Function, Nothing}, xinput::InputVector, + py::Bool + )::Function if !isnothing(hess!) fides_objective = (x) -> let _grad! = grad!, _f = f, _hess! = hess!, - _xinput = xinput, _py = py + _xinput = xinput, _py = py return _fides_objective(x, _f, _grad!, _hess!, _xinput, _py) end @@ -118,15 +122,17 @@ function _get_fides_objective( end return fides_objective end -function _get_fides_objective(f_grad::Function, ::Nothing, xinput::InputVector, - py::Bool)::Function +function _get_fides_objective( + f_grad::Function, ::Nothing, xinput::InputVector, py::Bool + )::Function fides_objective = (x) -> let _f_grad = f_grad, _xinput = xinput, _py = py return _fides_objective(x, _f_grad, nothing, _xinput, _py) end return fides_objective end -function _get_fides_objective(f_grad_hess::Function, xinput::InputVector, - py::Bool)::Function +function _get_fides_objective( + f_grad_hess::Function, xinput::InputVector, py::Bool + )::Function fides_objective = (x) -> let _f_grad_hess = f_grad_hess, _xinput = xinput, _py = py return _fides_objective(x, _f_grad_hess, _xinput, _py) end @@ -139,8 +145,9 @@ function _fides_objective(x, f::Function, grad!::Function, xinput::InputVector, g = _grad_fides(xinput, grad!) return _get_fides_results(obj, g, py) end -function _fides_objective(x, f::Function, grad!::Function, hess!::Function, - xinput::InputVector, py::Bool) +function _fides_objective( + x, f::Function, grad!::Function, hess!::Function, xinput::InputVector, py::Bool + ) _get_xinput!(xinput, x) obj = f(xinput) g = _grad_fides(xinput, grad!) @@ -171,8 +178,9 @@ function _hess_fides(x::InputVector, hess!::Function)::Matrix return H end -function _get_bounds(x0::InputVector, bound::Union{InputVector, Nothing}, - which_bound::Symbol)::AbstractVector +function _get_bounds( + x0::InputVector, bound::Union{InputVector, Nothing}, which_bound::Symbol + )::AbstractVector @assert which_bound in [:lower, :upper] "Only lower and upper bounds are supported" !isnothing(bound) && return bound _bound = similar(x0) diff --git a/src/show.jl b/src/show.jl index 8e17035..42d418c 100644 --- a/src/show.jl +++ b/src/show.jl @@ -3,7 +3,7 @@ import Base.show function Base.show(io::IO, prob::FidesProblem) nps = length(prob.x0) header = styled"{bold:FidesProblem} with $(nps) parameters to estimate" - print(io, styled"$(header)") + return print(io, styled"$(header)") end function Base.show(io::IO, res::FidesSolution) header = styled"{bold:FidesSolution}" @@ -12,5 +12,5 @@ function Base.show(io::IO, res::FidesSolution) opt2 = @sprintf("Parameters estimated = %d\n", length(res.xmin)) opt3 = @sprintf("Optimiser iterations = %d\n", res.niterations) opt4 = @sprintf("Runtime = %.1es\n", res.runtime) - print(io, styled"$(header)$(optheader)$(opt1)$(opt2)$(opt3)$(opt4)") + return print(io, styled"$(header)$(optheader)$(opt1)$(opt2)$(opt3)$(opt4)") end diff --git a/src/solve.jl b/src/solve.jl index 21415ca..fc0bb74 100644 --- a/src/solve.jl +++ b/src/solve.jl @@ -40,8 +40,9 @@ approximations can be found in the See also [FidesOptions](@ref). """ -function solve(prob::FidesProblem, hess_update::HessianUpdate; - options::FidesOptions = FidesOptions())::FidesSolution +function solve( + prob::FidesProblem, hess_update::HessianUpdate; options::FidesOptions = FidesOptions() + )::FidesSolution if prob.user_hessian == false && hess_update isa CustomHessian throw(ArgumentError("\ The FidesProblem does not have a user provided Hessian. In this case \ @@ -58,21 +59,23 @@ function solve(prob::FidesProblem, hess_update::HessianUpdate; return _solve(prob, hess_update, options) end -function _solve(prob::FidesProblem, hess_update::HessianUpdate, - options::FidesOptions)::FidesSolution +function _solve( + prob::FidesProblem, hess_update::HessianUpdate, options::FidesOptions + )::FidesSolution @unpack fides_objective_py, lb, ub = prob verbose_py = _get_verbose_py(options.verbose_level) options_py = _fides_options(options) if !(hess_update isa CustomHessian) hess_update_py = _get_hess_update_py(hess_update) - fides_opt_py = fides_py.Optimizer(fides_objective_py, np_py.asarray(ub), - np_py.asarray(lb), options = options_py, - hessian_update = hess_update_py, - verbose = verbose_py) + fides_opt_py = fides_py.Optimizer( + fides_objective_py, np_py.asarray(ub), np_py.asarray(lb), options = options_py, + hessian_update = hess_update_py, verbose = verbose_py + ) else - fides_opt_py = fides_py.Optimizer(fides_objective_py, np_py.asarray(ub), - np_py.asarray(lb), options = options_py, - verbose = verbose_py) + fides_opt_py = fides_py.Optimizer( + fides_objective_py, np_py.asarray(ub), np_py.asarray(lb), options = options_py, + verbose = verbose_py + ) end if hess_update isa CustomHessian || hess_update.init_with_hess == false @@ -86,10 +89,12 @@ function _solve(prob::FidesProblem, hess_update::HessianUpdate, res = fides_opt_py.minimize(np_py.asarray(prob.x0), hess0 = hess_init_py) end end - return FidesSolution(PythonCall.pyconvert(Float64, res[0]), + return FidesSolution( + PythonCall.pyconvert(Float64, res[0]), PythonCall.pyconvert(Vector{Float64}, res[1]), PythonCall.pyconvert(Int64, fides_opt_py.iteration), runtime, - PythonCall.pyconvert(Symbol, fides_opt_py.exitflag._name_)) + PythonCall.pyconvert(Symbol, fides_opt_py.exitflag._name_) + ) end function _get_hess_update_py(hess_update::Union{BB, BG, SR1}) diff --git a/test/component_arrays.jl b/test/component_arrays.jl index 05e91c9..66ec489 100644 --- a/test/component_arrays.jl +++ b/test/component_arrays.jl @@ -9,10 +9,12 @@ ub = ComponentArray(p1 = 10.0, p2 = 10.0) @testset "ComponentArrays" begin prob1 = FidesProblem(rosenbrock_comp, rosenbrock_comp_grad!, x0; lb = lb, ub = ub) sol1 = solve(prob1, Fides.BFGS()) - @test all(.≈(sol1.xmin, [1.0, 1.0]; atol = 1e-6)) + @test all(.≈(sol1.xmin, [1.0, 1.0]; atol = 1.0e-6)) - prob2 = FidesProblem(rosenbrock_comp, rosenbrock_comp_grad!, x0; - hess! = rosenbrock_comp_hess!, lb = lb, ub = ub) + prob2 = FidesProblem( + rosenbrock_comp, rosenbrock_comp_grad!, x0; hess! = rosenbrock_comp_hess!, lb = lb, + ub = ub + ) sol2 = solve(prob2, Fides.CustomHessian()) - @test all(.≈(sol1.xmin, [1.0, 1.0]; atol = 1e-6)) + @test all(.≈(sol1.xmin, [1.0, 1.0]; atol = 1.0e-6)) end diff --git a/test/hess_approximations.jl b/test/hess_approximations.jl index 274b566..6330160 100644 --- a/test/hess_approximations.jl +++ b/test/hess_approximations.jl @@ -2,15 +2,17 @@ using Fides, ForwardDiff, Test include(joinpath(@__DIR__, "common.jl")) -function test_hess_approximation(prob, hess_approximation; tol_fmin = 1e-8, tol_xmin = 1e-4) +function test_hess_approximation(prob, hess_approximation; tol_fmin = 1.0e-8, tol_xmin = 1.0e-4) sol = solve(prob, hess_approximation; options = FidesOptions(; maxiter = 100000)) - @test sol.fmin≈0.0 atol=tol_fmin + @test sol.fmin ≈ 0.0 atol = tol_fmin @test all(.≈(sol.xmin, [1.0, 1.0], atol = tol_xmin)) return nothing end -fides_prob = FidesProblem(rosenbrock, rosenbrock_grad!, [2.0, 2.0]; lb = [-10.0, -10.0], - ub = [10.0, 10.0]) +fides_prob = FidesProblem( + rosenbrock, rosenbrock_grad!, [2.0, 2.0]; lb = [-10.0, -10.0], + ub = [10.0, 10.0] +) @testset "Hessian approximations" begin # Good approximation methods, should converge without problems @@ -18,9 +20,9 @@ fides_prob = FidesProblem(rosenbrock, rosenbrock_grad!, [2.0, 2.0]; lb = [-10.0, test_hess_approximation(fides_prob, Fides.SR1()) test_hess_approximation(fides_prob, Fides.Broyden(0.5)) # Worse approximation methods, should converge somewhat - test_hess_approximation(fides_prob, Fides.DFP(); tol_fmin = 1e-3, tol_xmin = 1e-1) - test_hess_approximation(fides_prob, Fides.BB(); tol_fmin = 1e-3, tol_xmin = 1e-1) - test_hess_approximation(fides_prob, Fides.BG(); tol_fmin = 1e-3, tol_xmin = 1e-1) + test_hess_approximation(fides_prob, Fides.DFP(); tol_fmin = 1.0e-3, tol_xmin = 1.0e-1) + test_hess_approximation(fides_prob, Fides.BB(); tol_fmin = 1.0e-3, tol_xmin = 1.0e-1) + test_hess_approximation(fides_prob, Fides.BG(); tol_fmin = 1.0e-3, tol_xmin = 1.0e-1) # Try to provide a custom initialization Hessian init_hess = [0.1 0.0; 0.0 0.1] test_hess_approximation(fides_prob, Fides.BFGS(init_hess = init_hess)) diff --git a/test/options.jl b/test/options.jl index 0e0634b..4144e04 100644 --- a/test/options.jl +++ b/test/options.jl @@ -2,16 +2,17 @@ using Fides, PythonCall, Test include(joinpath(@__DIR__, "common.jl")) -fides_prob = FidesProblem(rosenbrock, rosenbrock_grad!, [2.0, 2.0]; lb = [-10.0, -10.0], - ub = [10.0, 10.0]) +fides_prob = FidesProblem( + rosenbrock, rosenbrock_grad!, [2.0, 2.0]; lb = [-10.0, -10.0], ub = [10.0, 10.0] +) @testset "Fides options" begin # Test defaults are correct opt = FidesOptions() @test opt.maxiter == 1000 - @test opt.fatol == 1e-8 - @test opt.frtol == 1e-8 - @test opt.gatol == 1e-6 + @test opt.fatol == 1.0e-8 + @test opt.frtol == 1.0e-8 + @test opt.gatol == 1.0e-6 @test opt.grtol == 0.0 @test opt.maxtime == Inf @test opt.verbose_level == "warning" @@ -25,16 +26,17 @@ fides_prob = FidesProblem(rosenbrock, rosenbrock_grad!, [2.0, 2.0]; lb = [-10.0, @test opt.gamma2 == 2.0 # Test that all options can be set to none-default values - opt = FidesOptions(maxiter = 100, fatol = 1e-6, frtol = 1e-5, gatol = 1e-3, - maxtime = 10.0, grtol = 1e-2, verbose = "warning", - stepback_strategy = "refine", subspace_solver = "full", - delta_init = 2.0, mu = 0.30, eta = 0.8, theta_max = 0.99, - gamma1 = 0.20, gamma2 = 1.9) + opt = FidesOptions( + maxiter = 100, fatol = 1.0e-6, frtol = 1.0e-5, gatol = 1.0e-3, maxtime = 10.0, + grtol = 1.0e-2, verbose = "warning", stepback_strategy = "refine", + subspace_solver = "full", delta_init = 2.0, mu = 0.3, eta = 0.8, theta_max = 0.99, + gamma1 = 0.2, gamma2 = 1.9 + ) @test opt.maxiter == 100 - @test opt.fatol == 1e-6 - @test opt.frtol == 1e-5 - @test opt.gatol == 1e-3 - @test opt.grtol == 1e-2 + @test opt.fatol == 1.0e-6 + @test opt.frtol == 1.0e-5 + @test opt.gatol == 1.0e-3 + @test opt.grtol == 1.0e-2 @test opt.maxtime == 10.0 @test opt.verbose_level == "warning" @test opt.stepback_strategy == "refine" @@ -43,17 +45,17 @@ fides_prob = FidesProblem(rosenbrock, rosenbrock_grad!, [2.0, 2.0]; lb = [-10.0, @test opt.mu == 0.3 @test opt.eta == 0.8 @test opt.theta_max == 0.99 - @test opt.gamma1 == 0.20 + @test opt.gamma1 == 0.2 @test opt.gamma2 == 1.9 # Test options are properly converted to Python opt_py = Fides._fides_options(opt) @test pyconvert(Int64, opt_py["maxiter"]) == 100 - @test pyconvert(Float64, opt_py["fatol"]) == 1e-6 - @test pyconvert(Float64, opt_py["frtol"]) == 1e-5 - @test pyconvert(Float64, opt_py["gatol"]) == 1e-3 - @test pyconvert(Float64, opt_py["gatol"]) == 1e-3 + @test pyconvert(Float64, opt_py["fatol"]) == 1.0e-6 + @test pyconvert(Float64, opt_py["frtol"]) == 1.0e-5 + @test pyconvert(Float64, opt_py["gatol"]) == 1.0e-3 + @test pyconvert(Float64, opt_py["gatol"]) == 1.0e-3 @test pyconvert(Float64, opt_py["maxtime"]) == 10.0 - @test pyconvert(Float64, opt_py["grtol"]) == 1e-2 + @test pyconvert(Float64, opt_py["grtol"]) == 1.0e-2 @test pyconvert(String, opt_py["stepback_strategy"]._name_) == "REFINE" @test pyconvert(String, opt_py["subspace_solver"]._name_) == "FULL" @test pyconvert(Float64, opt_py["delta_init"]) == 2.0 @@ -71,12 +73,22 @@ fides_prob = FidesProblem(rosenbrock, rosenbrock_grad!, [2.0, 2.0]; lb = [-10.0, # Test options are propagated to solve sol = solve(fides_prob, Fides.BFGS(); options = FidesOptions(maxiter = 2)) @test sol.niterations == 2 - sol = solve(fides_prob, Fides.BFGS(); - options = FidesOptions(fatol = 0.0, frtol = 0.0, gatol = 0.0)) + sol = solve( + fides_prob, Fides.BFGS(); + options = FidesOptions(fatol = 0.0, frtol = 0.0, gatol = 0.0) + ) @test sol.retcode == :GTOL - sol = solve(fides_prob, Fides.BFGS(); - options = FidesOptions(stepback_strategy = "refine")) - @test sol.fmin≈0.0 atol=1e-8 + sol = solve( + fides_prob, Fides.BFGS(); options = FidesOptions(stepback_strategy = "refine") + ) + @test sol.fmin ≈ 0.0 atol = 1.0e-8 sol = solve(fides_prob, Fides.BFGS(); options = FidesOptions(subspace_solver = "full")) - @test sol.fmin≈0.0 atol=1e-8 + @test sol.fmin ≈ 0.0 atol = 1.0e-8 + # Test different options for solve + sol = solve(fides_prob, Fides.BFGS(); options = FidesOptions(verbose = "info")) + @test sol.fmin ≈ 0.0 atol = 1.0e-8 + sol = solve(fides_prob, Fides.BFGS(); options = FidesOptions(verbose = "error")) + @test sol.fmin ≈ 0.0 atol = 1.0e-8 + sol = solve(fides_prob, Fides.BFGS(); options = FidesOptions(verbose = "debug")) + @test sol.fmin ≈ 0.0 atol = 1.0e-8 end diff --git a/test/problem.jl b/test/problem.jl index 9a43c7d..6dda3be 100644 --- a/test/problem.jl +++ b/test/problem.jl @@ -29,25 +29,26 @@ x0, lb, ub = [2.0, 2.0], [-10.0, -10.0], [10.0, 10.0] @testset "FidesProblem" begin prob1 = FidesProblem(rosenbrock, rosenbrock_grad!, x0; lb = lb, ub = ub) sol1 = solve(prob1, Fides.BFGS()) - @test all(.≈(sol1.xmin, [1.0, 1.0]; atol = 1e-6)) + @test all(.≈(sol1.xmin, [1.0, 1.0]; atol = 1.0e-6)) - prob2 = FidesProblem(rosenbrock, rosenbrock_grad!, x0; hess! = rosenbrock_hess!, - lb = lb, ub = ub) + prob2 = FidesProblem( + rosenbrock, rosenbrock_grad!, x0; hess! = rosenbrock_hess!, lb = lb, ub = ub + ) sol2 = solve(prob2, Fides.CustomHessian()) - @test all(.≈(sol2.xmin, [1.0, 1.0]; atol = 1e-6)) + @test all(.≈(sol2.xmin, [1.0, 1.0]; atol = 1.0e-6)) prob3 = FidesProblem(fides_obj1, x0; lb = lb, ub = ub) sol3 = solve(prob3, Fides.BFGS()) - @test all(.≈(sol3.xmin, [1.0, 1.0]; atol = 1e-6)) + @test all(.≈(sol3.xmin, [1.0, 1.0]; atol = 1.0e-6)) prob4 = FidesProblem(fides_obj2, x0; lb = lb, ub = ub) sol4 = solve(prob4, Fides.CustomHessian()) - @test all(.≈(sol4.xmin, [1.0, 1.0]; atol = 1e-6)) + @test all(.≈(sol4.xmin, [1.0, 1.0]; atol = 1.0e-6)) # No bounds prob5 = FidesProblem(fides_obj2, x0) sol5 = solve(prob5, Fides.CustomHessian()) - @test all(.≈(sol5.xmin, [1.0, 1.0]; atol = 1e-6)) + @test all(.≈(sol5.xmin, [1.0, 1.0]; atol = 1.0e-6)) # Check correct Hessian input handling @test_throws ArgumentError begin diff --git a/test/show.jl b/test/show.jl index 98154bd..1924db8 100644 --- a/test/show.jl +++ b/test/show.jl @@ -8,6 +8,5 @@ sol = solve(prob, Fides.BFGS()) @testset "show" begin @test @sprintf("%s", prob) == "FidesProblem with 2 parameters to estimate" - @test @sprintf("%s", sol)[1:140] == - "FidesSolution\n---------------- Summary ---------------\nmin(f) = 3.30e-14\nParameters estimated = 2\nOptimiser iterations = 46" + @test @sprintf("%s", sol)[1:140] == "FidesSolution\n---------------- Summary ---------------\nmin(f) = 3.30e-14\nParameters estimated = 2\nOptimiser iterations = 46" end