diff --git a/.github/workflows/Format.yml b/.github/workflows/Format.yml new file mode 100644 index 0000000..b793dcb --- /dev/null +++ b/.github/workflows/Format.yml @@ -0,0 +1,38 @@ +name: Runic formatting + +on: + push: + branches: + - 'master' + - 'release-' + tags: + - '*' + pull_request: + +jobs: + runic: + name: Runic + runs-on: ubuntu-latest + # Permissions needed for reviewdog/action-suggester to post comments + permissions: + contents: read + checks: write + issues: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + with: + version: '1' + - uses: julia-actions/cache@v2 + - uses: fredrikekre/runic-action@v1 + with: + version: '1' + format_files: true + # Fail on next step instead + continue-on-error: ${{ github.event_name == 'pull_request' }} + - uses: reviewdog/action-suggester@v1 + if: github.event_name == 'pull_request' + with: + tool_name: Runic + fail_level: warning diff --git a/README.md b/README.md index f337429..8d9b17a 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ NLSolversBase.jl ======== [![Aqua QA](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl) +[![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) Base functionality for optimization and solving systems of equations in Julia. diff --git a/src/NLSolversBase.jl b/src/NLSolversBase.jl index d82866d..e8b4968 100644 --- a/src/NLSolversBase.jl +++ b/src/NLSolversBase.jl @@ -7,40 +7,40 @@ using ForwardDiff: ForwardDiff using LinearAlgebra: LinearAlgebra export AbstractObjective, - NonDifferentiable, - OnceDifferentiable, - TwiceDifferentiable, - TwiceDifferentiableHV, - value, - value!, - value_gradient!, - value_jacobian!, - gradient, - gradient!, - jacobian, - jacobian!, - hessian, - hessian!, - value!!, - value_gradient!!, - value_jacobian!!, - hessian!!, - hv_product, - hv_product!, - only_fg!, - only_fgh!, - only_fj!, - only_fg, - only_fj, - only_g_and_fg, - only_j_and_fj, - only_fg_and_hv!, - only_fghv!, - clear!, - f_calls, - g_calls, - h_calls, - hv_calls + NonDifferentiable, + OnceDifferentiable, + TwiceDifferentiable, + TwiceDifferentiableHV, + value, + value!, + value_gradient!, + value_jacobian!, + gradient, + gradient!, + jacobian, + jacobian!, + hessian, + hessian!, + value!!, + value_gradient!!, + value_jacobian!!, + hessian!!, + hv_product, + hv_product!, + only_fg!, + only_fgh!, + only_fj!, + only_fg, + only_fj, + only_g_and_fg, + only_j_and_fj, + only_fg_and_hv!, + only_fghv!, + clear!, + f_calls, + g_calls, + h_calls, + hv_calls export AbstractConstraints, OnceDifferentiableConstraints, TwiceDifferentiableConstraints, ConstraintBounds @@ -63,19 +63,19 @@ forwarddiff_chunksize(::ForwardDiff.Chunk{C}) where {C} = C is_finitediff(autodiff) = autodiff ∈ (:central, :finite, :finiteforward, :finitecomplex) is_forwarddiff(autodiff) = autodiff ∈ (:forward, :forwarddiff, true) -get_adtype(autodiff::AbstractADType, chunk=nothing) = autodiff +get_adtype(autodiff::AbstractADType, chunk = nothing) = autodiff -function get_adtype(autodiff::Union{Symbol,Bool}, chunk=nothing) +function get_adtype(autodiff::Union{Symbol, Bool}, chunk = nothing) if is_finitediff(autodiff) - return AutoFiniteDiff(; fdtype=finitediff_fdtype(autodiff)()) + return AutoFiniteDiff(; fdtype = finitediff_fdtype(autodiff)()) elseif is_forwarddiff(autodiff) - return AutoForwardDiff(; chunksize=forwarddiff_chunksize(chunk)) + return AutoForwardDiff(; chunksize = forwarddiff_chunksize(chunk)) else throw(ArgumentError(LazyString("The autodiff value `", repr(autodiff), "` is not supported. Use `:finite` or `:forward`."))) end end -x_of_nans(x::AbstractArray, ::Type{Tf}=float(eltype(x))) where {Tf} = fill!(similar(x, Tf), NaN) +x_of_nans(x::AbstractArray, ::Type{Tf} = float(eltype(x))) where {Tf} = fill!(similar(x, Tf), NaN) include("objective_types/inplace_factory.jl") include("objective_types/abstract.jl") diff --git a/src/interface.jl b/src/interface.jl index dbc6fb8..7688dbb 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -7,7 +7,7 @@ function value!!(obj::AbstractObjective, x) obj.f_calls += 1 copyto!(obj.x_f, x) obj.F = obj.f(x) - value(obj) + return value(obj) end """ Evaluates the objective value at `x`. @@ -27,7 +27,7 @@ function value!(obj::AbstractObjective, x) if x != obj.x_f value!!(obj, x) end - value(obj) + return value(obj) end """ @@ -50,7 +50,7 @@ function gradient!(obj::AbstractObjective, x) if x != obj.x_df gradient!!(obj, x) end - gradient(obj) + return gradient(obj) end """ Force (re-)evaluation of the gradient value at `x`. @@ -61,7 +61,7 @@ function gradient!!(obj::AbstractObjective, x) obj.df_calls += 1 copyto!(obj.x_df, x) obj.df(obj.DF, x) - gradient(obj) + return gradient(obj) end function value_gradient!(obj::AbstractObjective, x) @@ -72,7 +72,7 @@ function value_gradient!(obj::AbstractObjective, x) elseif x != obj.x_df gradient!!(obj, x) end - value(obj), gradient(obj) + return value(obj), gradient(obj) end function value_gradient!!(obj::AbstractObjective, x) obj.f_calls += 1 @@ -80,20 +80,20 @@ function value_gradient!!(obj::AbstractObjective, x) copyto!(obj.x_f, x) copyto!(obj.x_df, x) obj.F = obj.fdf(gradient(obj), x) - value(obj), gradient(obj) + return value(obj), gradient(obj) end function hessian!(obj::AbstractObjective, x) if x != obj.x_h hessian!!(obj, x) end - hessian(obj) + return hessian(obj) end function hessian!!(obj::AbstractObjective, x) obj.h_calls += 1 copyto!(obj.x_h, x) obj.h(obj.H, x) - hessian(obj) + return hessian(obj) end # Getters are without ! and accept only an objective and index or just an objective @@ -117,7 +117,7 @@ function value_jacobian!(obj, F, J, x) elseif x != obj.x_df jacobian!!(obj, J, x) end - F, J + return F, J end value_jacobian!!(obj, x) = value_jacobian!!(obj, obj.F, obj.DF, x) function value_jacobian!!(obj, F, J, x) @@ -127,14 +127,14 @@ function value_jacobian!!(obj, F, J, x) obj.f_calls += 1 obj.df_calls += 1 obj.df_calls - F, J + return F, J end function jacobian!(obj, x) if x != obj.x_df jacobian!!(obj, x) end - jacobian(obj) + return jacobian(obj) end jacobian!!(obj, x) = jacobian!!(obj, obj.DF, x) @@ -143,7 +143,7 @@ function jacobian!!(obj, J, x) copyto!(obj.x_df, x) obj.df_calls += 1 obj.df_calls - J + return J end function jacobian(obj::AbstractObjective, x) tmp = copy(obj.DF) @@ -153,21 +153,21 @@ function jacobian(obj::AbstractObjective, x) return newdf end -value(obj::NonDifferentiable{TF, TX}, x) where {TF<:AbstractArray, TX} = value(obj, copy(obj.F), x) -value(obj::OnceDifferentiable{TF, TDF, TX}, x) where {TF<:AbstractArray, TDF, TX} = value(obj, copy(obj.F), x) +value(obj::NonDifferentiable{TF, TX}, x) where {TF <: AbstractArray, TX} = value(obj, copy(obj.F), x) +value(obj::OnceDifferentiable{TF, TDF, TX}, x) where {TF <: AbstractArray, TDF, TX} = value(obj, copy(obj.F), x) function value(obj::AbstractObjective, F, x) obj.f_calls += 1 return obj.f(F, x) end -value!!(obj::NonDifferentiable{TF, TX}, x) where {TF<:AbstractArray, TX} = value!!(obj, obj.F, x) -value!!(obj::OnceDifferentiable{TF, TDF, TX}, x) where {TF<:AbstractArray, TDF, TX} = value!!(obj, obj.F, x) +value!!(obj::NonDifferentiable{TF, TX}, x) where {TF <: AbstractArray, TX} = value!!(obj, obj.F, x) +value!!(obj::OnceDifferentiable{TF, TDF, TX}, x) where {TF <: AbstractArray, TDF, TX} = value!!(obj, obj.F, x) function value!!(obj::AbstractObjective, F, x) obj.f(F, x) copyto!(obj.x_f, x) obj.f_calls += 1 obj.f_calls - F + return F end function _clear_f!(d::AbstractObjective) @@ -178,21 +178,21 @@ function _clear_f!(d::AbstractObjective) d.F = NaN end fill!(d.x_f, NaN) - nothing + return nothing end function _clear_df!(d::AbstractObjective) d.df_calls = 0 fill!(d.DF, NaN) fill!(d.x_df, NaN) - nothing + return nothing end function _clear_h!(d::AbstractObjective) d.h_calls = 0 fill!(d.H, NaN) fill!(d.x_h, NaN) - nothing + return nothing end function _clear_hv!(d::AbstractObjective) @@ -200,29 +200,29 @@ function _clear_hv!(d::AbstractObjective) fill!(d.Hv, NaN) fill!(d.x_hv, NaN) fill!(d.v_hv, NaN) - nothing + return nothing end -clear!(d::NonDifferentiable) = _clear_f!(d) +clear!(d::NonDifferentiable) = _clear_f!(d) function clear!(d::OnceDifferentiable) _clear_f!(d) _clear_df!(d) - nothing + return nothing end function clear!(d::TwiceDifferentiable) _clear_f!(d) _clear_df!(d) _clear_h!(d) - nothing + return nothing end function clear!(d::TwiceDifferentiableHV) _clear_f!(d) _clear_df!(d) _clear_hv!(d) - nothing + return nothing end g_calls(d::NonDifferentiable) = 0 diff --git a/src/objective_types/abstract.jl b/src/objective_types/abstract.jl index 11d2ce7..e36bbb8 100644 --- a/src/objective_types/abstract.jl +++ b/src/objective_types/abstract.jl @@ -3,13 +3,13 @@ abstract type AbstractObjective end # Given callables to calculate objectives and partial first derivatives # create a function that calculates both. function make_fdf(x, F, f!, j!) - function fj!(fx, jx, x) + return function fj!(fx, jx, x) j!(jx, x) return f!(fx, x) end end function make_fdf(x, F::Number, f, g!) - function fg!(gx, x) + return function fg!(gx, x) g!(gx, x) return f(x) end @@ -19,8 +19,8 @@ end alloc_DF(x, F) = eltype(x)(NaN) .* vec(F) .* vec(x)' # Initialize a gradient shaped like x -alloc_DF(x, F::T) where T<:Number = x_of_nans(x, promote_type(eltype(x), T)) +alloc_DF(x, F::T) where {T <: Number} = x_of_nans(x, promote_type(eltype(x), T)) # Initialize an n-by-n Hessian -function alloc_H(x, F::T) where T<:Number - eltype(x)(NaN).*x*x' +function alloc_H(x, F::T) where {T <: Number} + return eltype(x)(NaN) .* x * x' end diff --git a/src/objective_types/constraints.jl b/src/objective_types/constraints.jl index efff3d0..66a7567 100644 --- a/src/objective_types/constraints.jl +++ b/src/objective_types/constraints.jl @@ -1,17 +1,17 @@ ### Constraints -# +# # Constraints are specified by the user as # lx_i ≤ x[i] ≤ ux_i # variable (box) constraints # lc_i ≤ c(x)[i] ≤ uc_i # linear/nonlinear constraints # and become equality constraints with l_i = u_i. ±∞ are allowed for l # and u, in which case the relevant side(s) are unbounded. -# +# # The user supplies functions to calculate c(x) and its derivatives. -# +# # Of course we could unify the box-constraints into the # linear/nonlinear constraints, but that would force the user to # provide the variable-derivatives manually, which would be silly. -# +# # This parametrization of the constraints gets "parsed" into a form # that speeds and simplifies the IPNewton algorithm, at the cost of many # additional variables. See `parse_constraints` for details. @@ -32,21 +32,23 @@ struct ConstraintBounds{T} bc::Vector{T} end function ConstraintBounds(lx, ux, lc, uc) - _cb(symmetrize(lx, ux)..., symmetrize(lc, uc)...) + return _cb(symmetrize(lx, ux)..., symmetrize(lc, uc)...) end -function _cb(lx::AbstractArray{Tx}, ux::AbstractArray{Tx}, lc::AbstractVector{Tc}, uc::AbstractVector{Tc}) where {Tx,Tc} +function _cb(lx::AbstractArray{Tx}, ux::AbstractArray{Tx}, lc::AbstractVector{Tc}, uc::AbstractVector{Tc}) where {Tx, Tc} T = promote_type(Tx, Tc) - ConstraintBounds{T}(length(lc), parse_constraints(T, lx, ux)..., parse_constraints(T, lc, uc)...) + return ConstraintBounds{T}(length(lc), parse_constraints(T, lx, ux)..., parse_constraints(T, lc, uc)...) end -Base.eltype(::Type{ConstraintBounds{T}}) where T = T +Base.eltype(::Type{ConstraintBounds{T}}) where {T} = T Base.convert(::Type{ConstraintBounds{T}}, cb::ConstraintBounds{T}) where {T} = cb -Base.convert(::Type{ConstraintBounds{T}}, cb::ConstraintBounds{S}) where {T,S} = - ConstraintBounds{T}(cb.nc, cb.eqx, convert(Vector{T}, cb.valx), - cb.ineqx, cb.σx, convert(Vector{T}, cb.bx), - cb.eqc, convert(Vector{T}, cb.valc), cb.ineqc, - cb.σc, convert(Vector{T}, cb.bc)) +Base.convert(::Type{ConstraintBounds{T}}, cb::ConstraintBounds{S}) where {T, S} = + ConstraintBounds{T}( + cb.nc, cb.eqx, convert(Vector{T}, cb.valx), + cb.ineqx, cb.σx, convert(Vector{T}, cb.bx), + cb.eqc, convert(Vector{T}, cb.valc), cb.ineqc, + cb.σc, convert(Vector{T}, cb.bc) +) """ @@ -73,7 +75,7 @@ function nconstraints_x(cb::ConstraintBounds) hasconstraint = falses(nmax) hasconstraint[cb.ineqx] .= true hasconstraint[cb.eqx] .= true - sum(hasconstraint) + return sum(hasconstraint) end function Base.show(io::IO, cb::ConstraintBounds) @@ -85,7 +87,7 @@ function Base.show(io::IO, cb::ConstraintBounds) print(io, "\n Linear/nonlinear constraints:") showeq(io, indent, cb.eqc, cb.valc, 'c', false) # subscript showineq(io, indent, cb.ineqc, cb.σc, cb.bc, 'c', false) # subscript - nothing + return nothing end # Synonym constructor for ConstraintBounds with no c(x) @@ -95,42 +97,46 @@ abstract type AbstractConstraints end nconstraints(constraints::AbstractConstraints) = nconstraints(constraints.bounds) -struct OnceDifferentiableConstraints{F,J,T} <: AbstractConstraints +struct OnceDifferentiableConstraints{F, J, T} <: AbstractConstraints c!::F # c!(storage, x) stores the value of the constraint-functions at x jacobian!::J # jacobian!(storage, x) stores the Jacobian of the constraint-functions bounds::ConstraintBounds{T} end -function OnceDifferentiableConstraints(c!, jacobian!, - lx::AbstractArray, ux::AbstractArray, - lc::AbstractArray, uc::AbstractArray) +function OnceDifferentiableConstraints( + c!, jacobian!, + lx::AbstractArray, ux::AbstractArray, + lc::AbstractArray, uc::AbstractArray + ) b = ConstraintBounds(lx, ux, lc, uc) - OnceDifferentiableConstraints(c!, jacobian!, b) + return OnceDifferentiableConstraints(c!, jacobian!, b) end function OnceDifferentiableConstraints(lx::AbstractArray, ux::AbstractArray) bounds = ConstraintBounds(lx, ux, [], []) - OnceDifferentiableConstraints(bounds) + return OnceDifferentiableConstraints(bounds) end function OnceDifferentiableConstraints(bounds::ConstraintBounds) - c! = (c, x)->nothing - J! = (J, x)->nothing - OnceDifferentiableConstraints(c!, J!, bounds) + c! = (c, x) -> nothing + J! = (J, x) -> nothing + return OnceDifferentiableConstraints(c!, J!, bounds) end function checked_chunk(lx) if isempty(lx) throw(ArgumentError("autodiff on constraints require the full lower bound vector `lx`.")) end - ForwardDiff.Chunk(lx) + return ForwardDiff.Chunk(lx) end -function OnceDifferentiableConstraints(c!, lx::AbstractVector, ux::AbstractVector, - lc::AbstractVector, uc::AbstractVector, - autodiff::Symbol = :central, - chunk::ForwardDiff.Chunk = checked_chunk(lx)) - +function OnceDifferentiableConstraints( + c!, lx::AbstractVector, ux::AbstractVector, + lc::AbstractVector, uc::AbstractVector, + autodiff::Symbol = :central, + chunk::ForwardDiff.Chunk = checked_chunk(lx) + ) + bounds = ConstraintBounds(lx, ux, lc, uc) T = eltype(bounds) sizex = size(lx) @@ -149,7 +155,7 @@ function OnceDifferentiableConstraints(c!, lx::AbstractVector, ux::AbstractVecto end -struct TwiceDifferentiableConstraints{F,J,H,T} <: AbstractConstraints +struct TwiceDifferentiableConstraints{F, J, H, T} <: AbstractConstraints c!::F # c!(storage, x) stores the value of the constraint-functions at x jacobian!::J # jacobian!(storage, x) stores the Jacobian of the constraint-functions h!::H # h!(storage, x) stores the hessian of the constraint functions @@ -158,13 +164,15 @@ end function TwiceDifferentiableConstraints(c!, jacobian!, h!, lx, ux, lc, uc) b = ConstraintBounds(lx, ux, lc, uc) - TwiceDifferentiableConstraints(c!, jacobian!, h!, b) + return TwiceDifferentiableConstraints(c!, jacobian!, h!, b) end -function TwiceDifferentiableConstraints(c!, lx::AbstractVector, ux::AbstractVector, - lc::AbstractVector, uc::AbstractVector, - autodiff::Symbol = :central, - chunk::ForwardDiff.Chunk = checked_chunk(lx)) +function TwiceDifferentiableConstraints( + c!, lx::AbstractVector, ux::AbstractVector, + lc::AbstractVector, uc::AbstractVector, + autodiff::Symbol = :central, + chunk::ForwardDiff.Chunk = checked_chunk(lx) + ) bounds = ConstraintBounds(lx, ux, lc, uc) T = eltype(bounds) nc = length(lc) @@ -172,7 +180,7 @@ function TwiceDifferentiableConstraints(c!, lx::AbstractVector, ux::AbstractVect x_example = zeros(T, nx) λ_example = zeros(T, nc) ccache = zeros(T, nc) - + function sum_constraints(_x, _λ) # TODO: get rid of this allocation with DI.Cache ccache_righttype = zeros(promote_type(T, eltype(_x)), nc) @@ -185,40 +193,41 @@ function TwiceDifferentiableConstraints(c!, lx::AbstractVector, ux::AbstractVect jac_prep = DI.prepare_jacobian(c!, ccache, backend, x_example) function con_jac!(_j, _x) - DI.jacobian!(c!, ccache, _j, jac_prep, backend, _x) + DI.jacobian!(c!, ccache, _j, jac_prep, backend, _x) return _j end hess_prep = DI.prepare_hessian(sum_constraints, backend, x_example, DI.Constant(λ_example)) function con_hess!(_h, _x, _λ) - DI.hessian!(sum_constraints, _h, hess_prep, backend, _x, DI.Constant(_λ)) + DI.hessian!(sum_constraints, _h, hess_prep, backend, _x, DI.Constant(_λ)) return _h end - - return TwiceDifferentiableConstraints(c!, con_jac!, con_hess!, bounds) + + return TwiceDifferentiableConstraints(c!, con_jac!, con_hess!, bounds) end -function TwiceDifferentiableConstraints(c!, con_jac!,lx::AbstractVector, ux::AbstractVector, - lc::AbstractVector, uc::AbstractVector, - autodiff::Symbol = :central, - chunk::ForwardDiff.Chunk = checked_chunk(lx)) +function TwiceDifferentiableConstraints( + c!, con_jac!, lx::AbstractVector, ux::AbstractVector, + lc::AbstractVector, uc::AbstractVector, + autodiff::Symbol = :central, + chunk::ForwardDiff.Chunk = checked_chunk(lx) + ) # TODO: is con_jac! still useful? we ignore it here - + return TwiceDifferentiableConstraints(c!, lx, ux, lc, uc, autodiff, chunk) end - function TwiceDifferentiableConstraints(lx::AbstractArray, ux::AbstractArray) bounds = ConstraintBounds(lx, ux, [], []) - TwiceDifferentiableConstraints(bounds) + return TwiceDifferentiableConstraints(bounds) end function TwiceDifferentiableConstraints(bounds::ConstraintBounds) - c! = (x, c)->nothing - J! = (x, J)->nothing - h! = (x, λ, h)->nothing - TwiceDifferentiableConstraints(c!, J!, h!, bounds) + c! = (x, c) -> nothing + J! = (x, J) -> nothing + h! = (x, λ, h) -> nothing + return TwiceDifferentiableConstraints(c!, J!, h!, bounds) end @@ -232,9 +241,9 @@ function symmetrize(l, u) end # TODO: change to indices? size(l) == size(u) || throw(DimensionMismatch("bounds arrays must be consistent, got sizes $(size(l)) and $(size(u))")) - _symmetrize(l, u) + return _symmetrize(l, u) end -_symmetrize(l::AbstractArray{T,N}, u::AbstractArray{T,N}) where {T,N} = l, u +_symmetrize(l::AbstractArray{T, N}, u::AbstractArray{T, N}) where {T, N} = l, u _symmetrize(l::Vector{Any}, u::Vector{Any}) = _symm(l, u) _symmetrize(l, u) = _symm(l, u) @@ -252,7 +261,7 @@ function _symm(l, u) u = Array{Union{}}(undef, 0) end end - promote(l, u) + return promote(l, u) end """ @@ -280,7 +289,7 @@ corresponding entry in `ineq`/`σ`/`b`. T is the element-type of the non-Int outputs """ -function parse_constraints(::Type{T}, l, u) where T +function parse_constraints(::Type{T}, l, u) where {T} if size(l) != size(u) throw(DimensionMismatch(LazyString("Size of lower bounds (", size(l), ") and number of upper bounds (", size(u), ") must be equal."))) end @@ -306,7 +315,7 @@ function parse_constraints(::Type{T}, l, u) where T throw(ArgumentError(LazyString("Lower bound (", li, ") must not be greater than upper bound (", ui, ")."))) end end - eq, val, ineq, σ, b + return eq, val, ineq, σ, b end ### Compact printing of constraints diff --git a/src/objective_types/incomplete.jl b/src/objective_types/incomplete.jl index 959e127..58ca909 100644 --- a/src/objective_types/incomplete.jl +++ b/src/objective_types/incomplete.jl @@ -13,8 +13,8 @@ struct InplaceObjective{DF, FDF, FGH, Hv, FGHv} hv::Hv fghv::FGHv end -InplaceObjective(;df=nothing, fdf=nothing, fgh=nothing, hv=nothing, fghv=nothing) = InplaceObjective(df, fdf, fgh, hv, fghv) -const InPlaceObjectiveFGH = InplaceObjective{<:Nothing, <:Nothing, <:Any, <:Nothing, <: Nothing} +InplaceObjective(; df = nothing, fdf = nothing, fgh = nothing, hv = nothing, fghv = nothing) = InplaceObjective(df, fdf, fgh, hv, fghv) +const InPlaceObjectiveFGH = InplaceObjective{<:Nothing, <:Nothing, <:Any, <:Nothing, <:Nothing} const InPlaceObjectiveFG_Hv = InplaceObjective{<:Nothing, <:Any, <:Nothing, <:Any, <:Nothing} const InPlaceObjectiveFGHv = InplaceObjective{<:Nothing, <:Nothing, <:Nothing, <:Nothing, <:Any} struct NotInplaceObjective{DF, FDF, FGH} @@ -23,19 +23,19 @@ struct NotInplaceObjective{DF, FDF, FGH} fgh::FGH end # Mutating version -only_fg!(fg) = InplaceObjective(fdf=fg) -only_fgh!(fgh) = InplaceObjective(fgh=fgh) -only_fj!(fj) = InplaceObjective(fdf=fj) +only_fg!(fg) = InplaceObjective(fdf = fg) +only_fgh!(fgh) = InplaceObjective(fgh = fgh) +only_fj!(fj) = InplaceObjective(fdf = fj) -only_fg_and_hv!(fg, hv) = InplaceObjective(fdf=fg, hv=hv) -only_fghv!(fghv) = InplaceObjective(fghv=fghv) +only_fg_and_hv!(fg, hv) = InplaceObjective(fdf = fg, hv = hv) +only_fghv!(fghv) = InplaceObjective(fghv = fghv) # Non-mutating version -only_fg(fg) = NotInplaceObjective(nothing, fg, nothing) -only_fj(fj) = NotInplaceObjective(nothing, fj, nothing) +only_fg(fg) = NotInplaceObjective(nothing, fg, nothing) +only_fj(fj) = NotInplaceObjective(nothing, fj, nothing) -only_g_and_fg(g, fg) = NotInplaceObjective(g, fg, nothing) -only_j_and_fj(j, fj) = NotInplaceObjective(j, fj, nothing) +only_g_and_fg(g, fg) = NotInplaceObjective(g, fg, nothing) +only_j_and_fj(j, fj) = NotInplaceObjective(j, fj, nothing) df(t::Union{InplaceObjective, NotInplaceObjective}) = t.df fdf(t::Union{InplaceObjective, NotInplaceObjective}) = t.fdf @@ -59,7 +59,9 @@ function make_f(t::InplaceObjective, x, F::Real) throw(ArgumentError("Cannot construct function for evaluating the objective function: No suitable function was provided.")) end end -make_f(t::InplaceObjective, x, F) = let fdf = t.fdf; (F, x) -> fdf(F, nothing, x); end +make_f(t::InplaceObjective, x, F) = let fdf = t.fdf + (F, x) -> fdf(F, nothing, x) +end function make_df(t::InplaceObjective, x, F) (; fdf, fgh, fghv) = t @@ -106,67 +108,71 @@ make_fdf(t::InplaceObjective, x, F) = fdf(t) # of whatever fdf returns. make_f(t::NotInplaceObjective, x, F::Real) = x -> fdf(t)(x)[1] make_f(t::NotInplaceObjective, x, F) = (F, x) -> copyto!(F, fdf(t)(x)[1]) -make_df(t::NotInplaceObjective{DF, TDF}, x, F) where {DF<:Nothing, TDF} = (DF, x) -> copyto!(DF, fdf(t)(x)[2]) +make_df(t::NotInplaceObjective{DF, TDF}, x, F) where {DF <: Nothing, TDF} = (DF, x) -> copyto!(DF, fdf(t)(x)[2]) make_df(t::NotInplaceObjective, x, F) = t.df function make_fdf(t::NotInplaceObjective, x, F::Real) return function ffgg!(G, x) f, g = fdf(t)(x) copyto!(G, g) - f + return f end end function make_fdf(t::NotInplaceObjective, x, F) return function ffjj!(F, J, x) f, j = fdf(t)(x) copyto!(J, j) - copyto!(F, f) + return copyto!(F, f) end end # Constructors function NonDifferentiable(t::Union{InplaceObjective, NotInplaceObjective}, x::AbstractArray, F::Real = real(zero(eltype(x)))) f = make_f(t, x, F) - NonDifferentiable(f, x, F) + return NonDifferentiable(f, x, F) end # this would not be possible if we could mark f, g, ... as non-AbstractArrays function NonDifferentiable(t::Union{InplaceObjective, NotInplaceObjective}, x::AbstractArray, F::AbstractArray) f = make_f(t, x, F) - NonDifferentiable(f, x, F) + return NonDifferentiable(f, x, F) end -const InPlaceFGH = InplaceObjective{<:Nothing,<:Nothing,TH,<:Nothing,<:Nothing} where {TH} -const InPlaceFG_HV = InplaceObjective{<:Nothing,TFG,<:Nothing,THv,<:Nothing} where {TFG,THv} -const InPlaceFGHV = InplaceObjective{<:Nothing,<:Nothing,<:Nothing,<:Nothing,TFGHv} where {TFGHv} +const InPlaceFGH = InplaceObjective{<:Nothing, <:Nothing, TH, <:Nothing, <:Nothing} where {TH} +const InPlaceFG_HV = InplaceObjective{<:Nothing, TFG, <:Nothing, THv, <:Nothing} where {TFG, THv} +const InPlaceFGHV = InplaceObjective{<:Nothing, <:Nothing, <:Nothing, <:Nothing, TFGHv} where {TFGHv} function TwiceDifferentiable(t::InPlaceFGH, x::AbstractArray, F::Real = real(zero(eltype(x))), G::AbstractArray = alloc_DF(x, F), H::AbstractMatrix = alloc_H(x, F)) - f = x -> t.fgh(F, nothing, nothing, x) - df = (G, x) -> t.fgh(nothing, G, nothing, x) + f = x -> t.fgh(F, nothing, nothing, x) + df = (G, x) -> t.fgh(nothing, G, nothing, x) fdf = (G, x) -> t.fgh(F, G, nothing, x) fdfh = (G, H, x) -> t.fgh(F, G, H, x) dfh = (G, H, x) -> t.fgh(nothing, G, H, x) - h = (H, x) -> t.fgh(F, nothing, H, x) + h = (H, x) -> t.fgh(F, nothing, H, x) x_f, x_df, x_h = x_of_nans(x), x_of_nans(x), x_of_nans(x) - TwiceDifferentiable(f, df, fdf, dfh, fdfh, h, - copy(F), copy(G), copy(H), - x_f, x_df, x_h, - 0, 0, 0) + return TwiceDifferentiable( + f, df, fdf, dfh, fdfh, h, + copy(F), copy(G), copy(H), + x_f, x_df, x_h, + 0, 0, 0 + ) end function TwiceDifferentiable(t::InPlaceFGH, x::AbstractVector{T}, F::Real = real(zero(eltype(x))), G::AbstractVector{Tx} = alloc_DF(x, F)) where {T, Tx} - f = x -> t.fgh(F, nothing, nothing, x) - df = (G, x) -> t.fgh(nothing, G, nothing, x) + f = x -> t.fgh(F, nothing, nothing, x) + df = (G, x) -> t.fgh(nothing, G, nothing, x) fdf = (G, x) -> t.fgh(F, G, nothing, x) fdfh = (G, H, x) -> t.fgh(F, G, H, x) dfh = (G, H, x) -> t.fgh(nothing, G, H, x) - h = (H, x) -> t.fgh(F, nothing, H, x) + h = (H, x) -> t.fgh(F, nothing, H, x) H = alloc_H(x, F) x_f, x_df, x_h = x_of_nans(x), x_of_nans(x), x_of_nans(x) - TwiceDifferentiable(f, df, fdf, dfh, fdfh, h, - copy(F), copy(G), copy(H), - x_f, x_df, x_h, - 0, 0, 0) + return TwiceDifferentiable( + f, df, fdf, dfh, fdfh, h, + copy(F), copy(G), copy(H), + x_f, x_df, x_h, + 0, 0, 0 + ) end function value_gradient_hessian!!(obj, x) obj.f_calls += 1 @@ -181,7 +187,7 @@ function value_gradient_hessian!!(obj, x) else obj.F = obj.fdfh(obj.DF, obj.H, x) end - obj.F, obj.DF, obj.H + return obj.F, obj.DF, obj.H end function gradient_hessian!!(obj, x) @@ -195,15 +201,15 @@ function gradient_hessian!!(obj, x) copyto!(obj.x_h, x) obj.dfh(obj.DF, obj.H, x) end - obj.DF, obj.H + return obj.DF, obj.H end function TwiceDifferentiableHV(t::InPlaceFG_HV, x::AbstractVector) - TwiceDifferentiableHV(nothing, t.fdf, t.hv, x) + return TwiceDifferentiableHV(nothing, t.fdf, t.hv, x) end function TwiceDifferentiableHV(t::InPlaceFGHV, x::AbstractVector, F::Real = real(zero(eltype(x)))) - fg = (F, G, x) -> t.fghv(F, G, nothing, x, nothing) - Hv = (Hv, x, v) -> t.fghv(nothing, nothing, Hv, x, v) - TwiceDifferentiableHV(nothing, fg, Hv, x) + fg = (F, G, x) -> t.fghv(F, G, nothing, x, nothing) + Hv = (Hv, x, v) -> t.fghv(nothing, nothing, Hv, x, v) + return TwiceDifferentiableHV(nothing, fg, Hv, x) end diff --git a/src/objective_types/inplace_factory.jl b/src/objective_types/inplace_factory.jl index 8cd0bbf..4f6992a 100644 --- a/src/objective_types/inplace_factory.jl +++ b/src/objective_types/inplace_factory.jl @@ -9,7 +9,7 @@ function f!_from_f(f, F::AbstractArray, inplace) else return function ff!(F, x) copyto!(F, f(x)) - F + return F end end end @@ -19,7 +19,7 @@ function df!_from_df(g, F::Real, inplace) else return function gg!(G, x) copyto!(G, g(x)) - G + return G end end end @@ -29,7 +29,7 @@ function df!_from_df(j, F::AbstractArray, inplace) else return function jj!(J, x) copyto!(J, j(x)) - J + return J end end end @@ -40,7 +40,7 @@ function fdf!_from_fdf(fg, F::Real, inplace) return function ffgg!(G, x) fx, gx = fg(x) copyto!(G, gx) - fx + return fx end end end @@ -51,7 +51,7 @@ function fdf!_from_fdf(fj, F::AbstractArray, inplace) return function ffjj!(F, J, x) fx, jx = fj(x) copyto!(J, jx) - copyto!(F, fx) + return copyto!(F, fx) end end end @@ -61,7 +61,7 @@ function h!_from_h(h, F::Real, inplace) else return function hh!(H, x) copyto!(H, h(x)) - H + return H end end end diff --git a/src/objective_types/nondifferentiable.jl b/src/objective_types/nondifferentiable.jl index e72d8e5..ffd5226 100644 --- a/src/objective_types/nondifferentiable.jl +++ b/src/objective_types/nondifferentiable.jl @@ -1,5 +1,5 @@ # Used for objectives and solvers where no gradient is available/exists -mutable struct NonDifferentiable{TF<:Union{AbstractArray,Real},TX<:AbstractArray} <: AbstractObjective +mutable struct NonDifferentiable{TF <: Union{AbstractArray, Real}, TX <: AbstractArray} <: AbstractObjective f F::TF x_f::TX @@ -9,15 +9,15 @@ end # These could be the same if we could restrict g below not to be an AbstractArray function NonDifferentiable(f, x::AbstractArray, F::Real = real(zero(eltype(x))); inplace = true) xnans = x_of_nans(x) - NonDifferentiable{typeof(F),typeof(xnans)}(f, F, xnans, 0) + return NonDifferentiable{typeof(F), typeof(xnans)}(f, F, xnans, 0) end function NonDifferentiable(f, x::AbstractArray, F::AbstractArray; inplace = true) f = inplace ? f : f!_from_f(f, F, inplace) xnans = x_of_nans(x) - NonDifferentiable{typeof(F),typeof(xnans)}(f, F, xnans, 0) + return NonDifferentiable{typeof(F), typeof(xnans)}(f, F, xnans, 0) end # this is the g referred to above! -NonDifferentiable(f, g, x::AbstractArray, F::Union{AbstractArray, Real} = real(zero(eltype(x)))) = NonDifferentiable(f, x, F) -NonDifferentiable(f, g, h, x::TX, F) where TX = NonDifferentiable(f, x, F) -NonDifferentiable(f, g, fg, h, x::TX, F) where TX = NonDifferentiable(f, x, F) +NonDifferentiable(f, g, x::AbstractArray, F::Union{AbstractArray, Real} = real(zero(eltype(x)))) = NonDifferentiable(f, x, F) +NonDifferentiable(f, g, h, x::TX, F) where {TX} = NonDifferentiable(f, x, F) +NonDifferentiable(f, g, fg, h, x::TX, F) where {TX} = NonDifferentiable(f, x, F) diff --git a/src/objective_types/oncedifferentiable.jl b/src/objective_types/oncedifferentiable.jl index da86f09..e25614a 100644 --- a/src/objective_types/oncedifferentiable.jl +++ b/src/objective_types/oncedifferentiable.jl @@ -1,5 +1,5 @@ # Used for objectives and solvers where the gradient is available/exists -mutable struct OnceDifferentiable{TF<:Union{AbstractArray,Real}, TDF<:AbstractArray, TX<:AbstractArray} <: AbstractObjective +mutable struct OnceDifferentiable{TF <: Union{AbstractArray, Real}, TDF <: AbstractArray, TX <: AbstractArray} <: AbstractObjective f # objective df # (partial) derivative of objective fdf # objective and (partial) derivative of objective @@ -13,26 +13,32 @@ end ### Only the objective # Ambiguity -OnceDifferentiable(f, x::AbstractArray, - F::Real = real(zero(eltype(x))), - DF::AbstractArray = alloc_DF(x, F); inplace::Bool = true, autodiff::Union{AbstractADType,Symbol,Bool} = :finite, - chunk::ForwardDiff.Chunk = ForwardDiff.Chunk(x)) = +OnceDifferentiable( + f, x::AbstractArray, + F::Real = real(zero(eltype(x))), + DF::AbstractArray = alloc_DF(x, F); inplace::Bool = true, autodiff::Union{AbstractADType, Symbol, Bool} = :finite, + chunk::ForwardDiff.Chunk = ForwardDiff.Chunk(x) +) = OnceDifferentiable(f, x, F, DF, autodiff, chunk) #OnceDifferentiable(f, x::AbstractArray, F::AbstractArray; autodiff = :finite) = # OnceDifferentiable(f, x::AbstractArray, F::AbstractArray, alloc_DF(x, F)) -function OnceDifferentiable(f, x::AbstractArray, - F::AbstractArray, DF::AbstractArray = alloc_DF(x, F); - inplace::Bool = true, autodiff::Union{AbstractADType,Symbol,Bool} = :finite) +function OnceDifferentiable( + f, x::AbstractArray, + F::AbstractArray, DF::AbstractArray = alloc_DF(x, F); + inplace::Bool = true, autodiff::Union{AbstractADType, Symbol, Bool} = :finite + ) f! = f!_from_f(f, F, inplace) - OnceDifferentiable(f!, x, F, DF, autodiff) + return OnceDifferentiable(f!, x, F, DF, autodiff) end -function OnceDifferentiable(f, x_seed::AbstractArray, - F::Real, - DF::AbstractArray, - autodiff::Union{AbstractADType,Symbol,Bool}, chunk::ForwardDiff.Chunk) +function OnceDifferentiable( + f, x_seed::AbstractArray, + F::Real, + DF::AbstractArray, + autodiff::Union{AbstractADType, Symbol, Bool}, chunk::ForwardDiff.Chunk + ) # When here, at the constructor with positional autodiff, it should already # be the case, that f is inplace. if f isa Union{InplaceObjective, NotInplaceObjective} @@ -59,19 +65,23 @@ end has_not_dep_symbol_in_ad = Ref{Bool}(true) OnceDifferentiable(f, x::AbstractArray, F::AbstractArray, autodiff::Symbol, chunk::ForwardDiff.Chunk = ForwardDiff.Chunk(x)) = -OnceDifferentiable(f, x, F, alloc_DF(x, F), autodiff, chunk) -function OnceDifferentiable(f, x::AbstractArray, F::AbstractArray, - autodiff::Bool, chunk::ForwardDiff.Chunk = ForwardDiff.Chunk(x)) + OnceDifferentiable(f, x, F, alloc_DF(x, F), autodiff, chunk) +function OnceDifferentiable( + f, x::AbstractArray, F::AbstractArray, + autodiff::Bool, chunk::ForwardDiff.Chunk = ForwardDiff.Chunk(x) + ) if autodiff == false throw(ErrorException("It is not possible to set the `autodiff` keyword to `false` when constructing a OnceDifferentiable instance from only one function. Pass in the (partial) derivative or specify a valid `autodiff` symbol.")) elseif has_not_dep_symbol_in_ad[] @warn("Setting the `autodiff` keyword to `true` is deprecated. Please use a valid symbol instead.") has_not_dep_symbol_in_ad[] = false end - OnceDifferentiable(f, x, F, alloc_DF(x, F), :forward, chunk) + return OnceDifferentiable(f, x, F, alloc_DF(x, F), :forward, chunk) end -function OnceDifferentiable(f, x_seed::AbstractArray, F::AbstractArray, DF::AbstractArray, - autodiff::Union{AbstractADType,Symbol,Bool}, chunk::ForwardDiff.Chunk = ForwardDiff.Chunk(x_seed)) +function OnceDifferentiable( + f, x_seed::AbstractArray, F::AbstractArray, DF::AbstractArray, + autodiff::Union{AbstractADType, Symbol, Bool}, chunk::ForwardDiff.Chunk = ForwardDiff.Chunk(x_seed) + ) if f isa Union{InplaceObjective, NotInplaceObjective} fF = make_f(f, x_seed, F) dfF = make_df(f, x_seed, F) @@ -94,40 +104,46 @@ function OnceDifferentiable(f, x_seed::AbstractArray, F::AbstractArray, DF::Abst end ### Objective and derivative -function OnceDifferentiable(f, df, - x::AbstractArray, - F::Real = real(zero(eltype(x))), - DF::AbstractArray = alloc_DF(x, F); - inplace::Bool = true) +function OnceDifferentiable( + f, df, + x::AbstractArray, + F::Real = real(zero(eltype(x))), + DF::AbstractArray = alloc_DF(x, F); + inplace::Bool = true + ) df! = df!_from_df(df, F, inplace) fdf! = make_fdf(x, F, f, df!) - OnceDifferentiable(f, df!, fdf!, x, F, DF) + return OnceDifferentiable(f, df!, fdf!, x, F, DF) end -function OnceDifferentiable(f, j, - x::AbstractArray, - F::AbstractArray, - J::AbstractArray = alloc_DF(x, F); - inplace::Bool = true) +function OnceDifferentiable( + f, j, + x::AbstractArray, + F::AbstractArray, + J::AbstractArray = alloc_DF(x, F); + inplace::Bool = true + ) f! = f!_from_f(f, F, inplace) j! = df!_from_df(j, F, inplace) fj! = make_fdf(x, F, f!, j!) - OnceDifferentiable(f!, j!, fj!, x, F, J) + return OnceDifferentiable(f!, j!, fj!, x, F, J) end ### Objective, derivative and combination -function OnceDifferentiable(f, df, fdf, - x::AbstractArray, - F::Real = real(zero(eltype(x))), - DF::AbstractArray = alloc_DF(x, F); - inplace::Bool = true) +function OnceDifferentiable( + f, df, fdf, + x::AbstractArray, + F::Real = real(zero(eltype(x))), + DF::AbstractArray = alloc_DF(x, F); + inplace::Bool = true + ) # f is never "inplace" since F is scalar df! = df!_from_df(df, F, inplace) @@ -135,17 +151,21 @@ function OnceDifferentiable(f, df, fdf, x_f, x_df = x_of_nans(x), x_of_nans(x) - OnceDifferentiable{typeof(F),typeof(DF),typeof(x)}(f, df!, fdf!, - copy(F), copy(DF), - x_f, x_df, - 0, 0) + return OnceDifferentiable{typeof(F), typeof(DF), typeof(x)}( + f, df!, fdf!, + copy(F), copy(DF), + x_f, x_df, + 0, 0 + ) end -function OnceDifferentiable(f, df, fdf, - x::AbstractArray, - F::AbstractArray, - DF::AbstractArray = alloc_DF(x, F); - inplace::Bool = true) +function OnceDifferentiable( + f, df, fdf, + x::AbstractArray, + F::AbstractArray, + DF::AbstractArray = alloc_DF(x, F); + inplace::Bool = true + ) f = f!_from_f(f, F, inplace) df! = df!_from_df(df, F, inplace) @@ -153,5 +173,5 @@ function OnceDifferentiable(f, df, fdf, x_f, x_df = x_of_nans(x), x_of_nans(x) - OnceDifferentiable(f, df!, fdf!, copy(F), copy(DF), x_f, x_df, 0, 0) + return OnceDifferentiable(f, df!, fdf!, copy(F), copy(DF), x_f, x_df, 0, 0) end diff --git a/src/objective_types/twicedifferentiable.jl b/src/objective_types/twicedifferentiable.jl index 3f2a8fa..595f1a9 100644 --- a/src/objective_types/twicedifferentiable.jl +++ b/src/objective_types/twicedifferentiable.jl @@ -1,5 +1,5 @@ # Used for objectives and solvers where the gradient and Hessian is available/exists -mutable struct TwiceDifferentiable{T<:Real,TDF<:AbstractArray,TH<:AbstractMatrix,TX<:AbstractArray} <: AbstractObjective +mutable struct TwiceDifferentiable{T <: Real, TDF <: AbstractArray, TH <: AbstractMatrix, TX <: AbstractArray} <: AbstractObjective f df fdf @@ -17,24 +17,28 @@ mutable struct TwiceDifferentiable{T<:Real,TDF<:AbstractArray,TH<:AbstractMatrix h_calls::Int end # compatibility with old constructor -function TwiceDifferentiable(f, g, fg, h, x::TX, F::T = real(zero(eltype(x))), G::TG = alloc_DF(x, F), H::TH = alloc_H(x, F); inplace::Bool = true) where {T<:Real, TG<:AbstractArray, TH<:AbstractMatrix, TX<:AbstractArray} +function TwiceDifferentiable(f, g, fg, h, x::TX, F::T = real(zero(eltype(x))), G::TG = alloc_DF(x, F), H::TH = alloc_H(x, F); inplace::Bool = true) where {T <: Real, TG <: AbstractArray, TH <: AbstractMatrix, TX <: AbstractArray} x_f, x_df, x_h = x_of_nans(x), x_of_nans(x), x_of_nans(x) g! = df!_from_df(g, F, inplace) fg! = fdf!_from_fdf(fg, F, inplace) h! = h!_from_h(h, F, inplace) - TwiceDifferentiable{T,TG,TH,TX}(f, g!, fg!, nothing, nothing, h!, - copy(F), copy(G), copy(H), - x_f, x_df, x_h, - 0, 0, 0) + return TwiceDifferentiable{T, TG, TH, TX}( + f, g!, fg!, nothing, nothing, h!, + copy(F), copy(G), copy(H), + x_f, x_df, x_h, + 0, 0, 0 + ) end -function TwiceDifferentiable(f, g, h, - x::AbstractArray, - F::Real = real(zero(eltype(x))), - G::AbstractArray = alloc_DF(x, F), - H::AbstractMatrix = alloc_H(x, F); inplace = true) +function TwiceDifferentiable( + f, g, h, + x::AbstractArray, + F::Real = real(zero(eltype(x))), + G::AbstractArray = alloc_DF(x, F), + H::AbstractMatrix = alloc_H(x, F); inplace = true + ) g! = df!_from_df(g, F, inplace) h! = h!_from_h(h, F, inplace) @@ -45,10 +49,11 @@ function TwiceDifferentiable(f, g, h, end - -function TwiceDifferentiable(f, g, - x_seed::AbstractArray, - F::Real = real(zero(eltype(x_seed))); autodiff::Union{AbstractADType,Symbol,Bool} = :finite, inplace::Bool = true) +function TwiceDifferentiable( + f, g, + x_seed::AbstractArray, + F::Real = real(zero(eltype(x_seed))); autodiff::Union{AbstractADType, Symbol, Bool} = :finite, inplace::Bool = true + ) g! = df!_from_df(g, F, inplace) fg! = make_fdf(x_seed, F, f, g!) @@ -58,14 +63,16 @@ function TwiceDifferentiable(f, g, DI.hessian!(f, _h, hess_prep, backend, _x) return _h end - TwiceDifferentiable(f, g!, fg!, h!, x_seed, F) + return TwiceDifferentiable(f, g!, fg!, h!, x_seed, F) end -TwiceDifferentiable(d::NonDifferentiable, x_seed::AbstractArray = d.x_f, F::Real = real(zero(eltype(x_seed))); autodiff::Union{AbstractADType,Symbol,Bool} = :finite) = +TwiceDifferentiable(d::NonDifferentiable, x_seed::AbstractArray = d.x_f, F::Real = real(zero(eltype(x_seed))); autodiff::Union{AbstractADType, Symbol, Bool} = :finite) = TwiceDifferentiable(d.f, x_seed, F; autodiff = autodiff) -function TwiceDifferentiable(d::OnceDifferentiable, x_seed::AbstractArray = d.x_f, - F::Real = real(zero(eltype(x_seed))); autodiff::Union{AbstractADType,Symbol,Bool} = :finite) +function TwiceDifferentiable( + d::OnceDifferentiable, x_seed::AbstractArray = d.x_f, + F::Real = real(zero(eltype(x_seed))); autodiff::Union{AbstractADType, Symbol, Bool} = :finite + ) backend = get_adtype(autodiff) hess_prep = DI.prepare_hessian(d.f, backend, x_seed) function h!(_h, _x) @@ -75,8 +82,10 @@ function TwiceDifferentiable(d::OnceDifferentiable, x_seed::AbstractArray = d.x_ return TwiceDifferentiable(d.f, d.df, d.fdf, h!, x_seed, F, gradient(d)) end -function TwiceDifferentiable(f, x::AbstractArray, F::Real = real(zero(eltype(x))); - autodiff::Union{AbstractADType,Symbol,Bool} = :finite, inplace::Bool = true) +function TwiceDifferentiable( + f, x::AbstractArray, F::Real = real(zero(eltype(x))); + autodiff::Union{AbstractADType, Symbol, Bool} = :finite, inplace::Bool = true + ) backend = get_adtype(autodiff) grad_prep = DI.prepare_gradient(f, backend, x) hess_prep = DI.prepare_hessian(f, backend, x) @@ -92,10 +101,10 @@ function TwiceDifferentiable(f, x::AbstractArray, F::Real = real(zero(eltype(x)) DI.hessian!(f, _h, hess_prep, backend, _x) return _h end - TwiceDifferentiable(f, g!, fg!, h!, x, F) + return TwiceDifferentiable(f, g!, fg!, h!, x, F) end function hv_product!(obj::TwiceDifferentiable, x, v) H = hessian!(obj, x) - return H*v + return H * v end diff --git a/src/objective_types/twicedifferentiablehv.jl b/src/objective_types/twicedifferentiablehv.jl index 7b3f388..c65b656 100644 --- a/src/objective_types/twicedifferentiablehv.jl +++ b/src/objective_types/twicedifferentiablehv.jl @@ -1,5 +1,5 @@ # Used for objectives and solvers where the gradient and Hessian is available/exists -mutable struct TwiceDifferentiableHV{T,TDF,THv,TX} <: AbstractObjective +mutable struct TwiceDifferentiableHV{T, TDF, THv, TX} <: AbstractObjective f fdf hv @@ -18,19 +18,21 @@ end # compatibility with old constructor function TwiceDifferentiableHV(f, fdf, h, x::TX, F::T, G::TG = copy(x), H::THv = copy(x)) where {T, TG, THv, TX} x_f, x_df, x_hv, v_hv = x_of_nans(x), x_of_nans(x), x_of_nans(x), x_of_nans(x) - TwiceDifferentiableHV{T,TG, THv, TX}(f, fdf, h, - copy(F), copy(G), copy(H), - x_f, x_df, x_hv, v_hv, - 0, 0, 0) + return TwiceDifferentiableHV{T, TG, THv, TX}( + f, fdf, h, + copy(F), copy(G), copy(H), + x_f, x_df, x_hv, v_hv, + 0, 0, 0 + ) end -function TwiceDifferentiableHV(f, fdf, h, x::AbstractVector{T}) where T +function TwiceDifferentiableHV(f, fdf, h, x::AbstractVector{T}) where {T} return TwiceDifferentiableHV(f, fdf, h, x, real(zero(T))) end # assumption: fg takes (f, g, x) -function TwiceDifferentiableHV(::Nothing, fg, hv, x::AbstractVector{T}) where T - f = x -> fg(0, nothing, x) +function TwiceDifferentiableHV(::Nothing, fg, hv, x::AbstractVector{T}) where {T} + f = x -> fg(0, nothing, x) fg! = (g, x) -> fg(0, g, x) return TwiceDifferentiableHV(f, fg!, hv, x) end @@ -38,20 +40,20 @@ end function gradient!!(obj::TwiceDifferentiableHV, x) obj.df_calls += 1 copyto!(obj.x_df, x) - obj.fdf(obj.DF, x) + return obj.fdf(obj.DF, x) end function hv_product!(obj::TwiceDifferentiableHV, x, v) if x != obj.x_hv || v != obj.v_hv hv_product!!(obj, x, v) end - obj.Hv + return obj.Hv end function hv_product!!(obj::TwiceDifferentiableHV, x, v) obj.hv_calls += 1 copyto!(obj.x_hv, x) copyto!(obj.v_hv, v) - obj.hv(obj.Hv, x, v) + return obj.hv(obj.Hv, x, v) end # Deprecate the following? # Using it makes code non-generic (it requires storage for the result) diff --git a/test/abstractarrays.jl b/test/abstractarrays.jl index 590195f..268b94b 100644 --- a/test/abstractarrays.jl +++ b/test/abstractarrays.jl @@ -1,10 +1,10 @@ @testset "ComponentArrays" begin x_seed_1 = [0.0] x_seed_2 = [0.0] - x_seed = ComponentArray(x_seed_1=x_seed_1, x_seed_2=x_seed_2) + x_seed = ComponentArray(x_seed_1 = x_seed_1, x_seed_2 = x_seed_2) g_seed_1 = [0.0] g_seed_2 = [0.0] - g_seed = ComponentArray(g_seed_1=g_seed_1, g_seed_2=g_seed_2) + g_seed = ComponentArray(g_seed_1 = g_seed_1, g_seed_2 = g_seed_2) f_x_seed = 8157.682077608529 nd = NonDifferentiable(exponential, x_seed) diff --git a/test/autodiff.jl b/test/autodiff.jl index 5ca921d..6b89e55 100644 --- a/test/autodiff.jl +++ b/test/autodiff.jl @@ -3,18 +3,18 @@ # Should throw, as :wah is not a proper autodiff choice err = ArgumentError("The autodiff value `:wah` is not supported. Use `:finite` or `:forward`.") - @test_throws err OnceDifferentiable(x->x, rand(10); autodiff=:wah) - @test_throws err OnceDifferentiable(x->x, rand(10), 0.0; autodiff=:wah) - @test_throws err TwiceDifferentiable(x->x, rand(10); autodiff=:wah) - @test_throws err TwiceDifferentiable(x->x, rand(10), 0.0; autodiff=:wah) + @test_throws err OnceDifferentiable(x -> x, rand(10); autodiff = :wah) + @test_throws err OnceDifferentiable(x -> x, rand(10), 0.0; autodiff = :wah) + @test_throws err TwiceDifferentiable(x -> x, rand(10); autodiff = :wah) + @test_throws err TwiceDifferentiable(x -> x, rand(10), 0.0; autodiff = :wah) #@test_throws err TwiceDifferentiable(x->x, rand(10), 0.0, rand(10); autodiff=:wah) - @test_throws err TwiceDifferentiable(x->x, x->x, rand(10); autodiff=:wah) - @test_throws err TwiceDifferentiable(x->x, x->x, rand(10), 0.0; autodiff=:wah) + @test_throws err TwiceDifferentiable(x -> x, x -> x, rand(10); autodiff = :wah) + @test_throws err TwiceDifferentiable(x -> x, x -> x, rand(10), 0.0; autodiff = :wah) #@test_throws err TwiceDifferentiable(x->x, x->x, rand(10), 0.0, rand(10); autodiff=:wah) for T in (OnceDifferentiable, TwiceDifferentiable) - odad1 = T(x->5.0, rand(1); autodiff = :finite) - odad2 = T(x->5.0, rand(1); autodiff = :forward) + odad1 = T(x -> 5.0, rand(1); autodiff = :finite) + odad2 = T(x -> 5.0, rand(1); autodiff = :forward) gradient!(odad1, rand(1)) gradient!(odad2, rand(1)) # odad3 = T(x->5., rand(1); autodiff = :reverse) @@ -25,31 +25,31 @@ for a in (1.0, 5.0) xa = rand(1) - odad1 = OnceDifferentiable(x->a*x[1], xa; autodiff = :finite) - odad2 = OnceDifferentiable(x->a*x[1], xa; autodiff = :forward) - # odad3 = OnceDifferentiable(x->a*x[1], xa; autodiff = :reverse) + odad1 = OnceDifferentiable(x -> a * x[1], xa; autodiff = :finite) + odad2 = OnceDifferentiable(x -> a * x[1], xa; autodiff = :forward) + # odad3 = OnceDifferentiable(x->a*x[1], xa; autodiff = :reverse) gradient!(odad1, xa) gradient!(odad2, xa) @test gradient(odad1) ≈ [a] @test gradient(odad2) == [a] - # @test odad3.g == [a] + # @test odad3.g == [a] end for a in (1.0, 5.0) xa = rand(1) - odad1 = OnceDifferentiable(x->a*x[1]^2, xa; autodiff = :finite) - odad2 = OnceDifferentiable(x->a*x[1]^2, xa; autodiff = :forward) - # odad3 = OnceDifferentiable(x->a*x[1]^2, xa; autodiff = :reverse) + odad1 = OnceDifferentiable(x -> a * x[1]^2, xa; autodiff = :finite) + odad2 = OnceDifferentiable(x -> a * x[1]^2, xa; autodiff = :forward) + # odad3 = OnceDifferentiable(x->a*x[1]^2, xa; autodiff = :reverse) gradient!(odad1, xa) gradient!(odad2, xa) - @test gradient(odad1) ≈ 2.0*a*xa - @test gradient(odad2) == 2.0*a*xa - # @test odad3.g == 2.0*a*xa + @test gradient(odad1) ≈ 2.0 * a * xa + @test gradient(odad2) == 2.0 * a * xa + # @test odad3.g == 2.0*a*xa end nx = 2 x = rand(nx) - f(x) = sum(x.^3) + f(x) = sum(x .^ 3) fx = f(x) - g(G, x) = copyto!(G, 3 .* x.^2) + g(G, x) = copyto!(G, 3 .* x .^ 2) gx = g(NLSolversBase.alloc_DF(x, 0.0), x) h(H, x) = copyto!(H, Diagonal(6 .* x)) hx = h(fill(0.0, nx, nx), x) @@ -72,7 +72,7 @@ if autodiff == :finite # we have to increase the tolerance here, as the hessian is # not very accurate - @test isapprox(hessian(differentiable), hx; atol = 1e-6) + @test isapprox(hessian(differentiable), hx; atol = 1.0e-6) else @test hessian(differentiable) == hx end @@ -80,7 +80,7 @@ end end @testset for autodiff in (:finite, :forward, AutoForwardDiff()) - td = TwiceDifferentiable(x->sum(x), (G, x)->copyto!(G, fill!(copy(x),1)), copy(x); autodiff = autodiff) + td = TwiceDifferentiable(x -> sum(x), (G, x) -> copyto!(G, fill!(copy(x), 1)), copy(x); autodiff = autodiff) value(td) value!(td, x) value_gradient!(td, x) @@ -88,7 +88,7 @@ hessian!(td, x) end @testset for autodiff in (:finite, :forward, AutoForwardDiff()) - for nd = (NonDifferentiable(x->sum(x), copy(x)), NonDifferentiable(x->sum(x), copy(x), 0.0)) + for nd in (NonDifferentiable(x -> sum(x), copy(x)), NonDifferentiable(x -> sum(x), copy(x), 0.0)) td = TwiceDifferentiable(nd; autodiff = autodiff) value(td) value!(td, x) @@ -96,7 +96,7 @@ gradient!(td, x) hessian!(td, x) end - for od = (OnceDifferentiable(x->sum(x), (G, x)->copyto!(G, fill!(copy(x),1)), copy(x)), OnceDifferentiable(x->sum(x), (G, x)->copyto!(G, fill!(copy(x),1)), copy(x), 0.0)) + for od in (OnceDifferentiable(x -> sum(x), (G, x) -> copyto!(G, fill!(copy(x), 1)), copy(x)), OnceDifferentiable(x -> sum(x), (G, x) -> copyto!(G, fill!(copy(x), 1)), copy(x), 0.0)) td = TwiceDifferentiable(od; autodiff = autodiff) value(td) value!(td, x) @@ -108,14 +108,14 @@ @testset "autodiff ℝᴺ → ℝᴺ" begin function f!(F, x) F[1] = 1.0 - x[1] - F[2] = 10.0*(x[2] - x[1]^2) + F[2] = 10.0 * (x[2] - x[1]^2) F end function j!(J, x) - J[1,1] = -1.0 - J[1,2] = 0.0 - J[2,1] = -20.0*x[1] - J[2,2] = 10.0 + J[1, 1] = -1.0 + J[1, 2] = 0.0 + J[2, 1] = -20.0 * x[1] + J[2, 2] = 10.0 J end # Some random x @@ -162,7 +162,7 @@ end @testset "value/grad" begin a = 3.0 x_seed = rand(1) - odad1 = OnceDifferentiable(x->a*x[1]^2, x_seed) + odad1 = OnceDifferentiable(x -> a * x[1]^2, x_seed) value_gradient!(odad1, x_seed) @test gradient(odad1) ≈ 2 .* a .* (x_seed) @testset "call counters" begin @@ -179,9 +179,9 @@ end @testset "residual function" begin function f!(F, x) - F[1] = 2x[1]+x[2] - F[2] = x[1]+x[2]^2 - F[3] = x[1]^2+x[2]^2 + F[1] = 2x[1] + x[2] + F[2] = x[1] + x[2]^2 + F[3] = x[1]^2 + x[2]^2 F end @@ -197,8 +197,8 @@ end F = zeros(3) J = zeros(3, 2) - x_init = [1., 1.] - od = OnceDifferentiable(f!, x_init, F) + x_init = [1.0, 1.0] + od = OnceDifferentiable(f!, x_init, F) value_jacobian!(od, x_init) @test length(value(od)) == length(F) @test value(od) ≈ f!(F, x_init) diff --git a/test/complex.jl b/test/complex.jl index b2a98d3..37c86a1 100644 --- a/test/complex.jl +++ b/test/complex.jl @@ -1,8 +1,8 @@ @testset "complex" begin - # Just catch that it doesn't error for now - x0 = randn(ComplexF64, 3) - @test_nowarn OnceDifferentiable(x -> sum(abs2, x), x0) - @test_nowarn NLSolversBase.value!(OnceDifferentiable(x -> sum(abs2, x), x0), x0) - @test_nowarn NLSolversBase.gradient!(OnceDifferentiable(x -> sum(abs2, x), x0), x0) - @test_nowarn NLSolversBase.value_gradient!(OnceDifferentiable(x -> sum(abs2, x), x0), x0) -end \ No newline at end of file + # Just catch that it doesn't error for now + x0 = randn(ComplexF64, 3) + @test_nowarn OnceDifferentiable(x -> sum(abs2, x), x0) + @test_nowarn NLSolversBase.value!(OnceDifferentiable(x -> sum(abs2, x), x0), x0) + @test_nowarn NLSolversBase.gradient!(OnceDifferentiable(x -> sum(abs2, x), x0), x0) + @test_nowarn NLSolversBase.value_gradient!(OnceDifferentiable(x -> sum(abs2, x), x0), x0) +end diff --git a/test/constraints.jl b/test/constraints.jl index ea50915..02d2a19 100644 --- a/test/constraints.jl +++ b/test/constraints.jl @@ -27,17 +27,17 @@ @test eltype(cb) === Float64 @test convert(ConstraintBounds{Float64}, cb) === cb - cb = ConstraintBounds([],[],[],[]) + cb = ConstraintBounds([], [], [], []) @test eltype(cb) === Union{} @test eltype(convert(ConstraintBounds{Int}, cb)) === Int - cb = ConstraintBounds([1,2], [3,4.0], [], [10.,20.,30.]) + cb = ConstraintBounds([1, 2], [3, 4.0], [], [10.0, 20.0, 30.0]) io = IOBuffer() show(io, cb) s = String(take!(io)) @test s == "ConstraintBounds:\n Variables:\n x[1]≥1.0, x[1]≤3.0, x[2]≥2.0, x[2]≤4.0\n Linear/nonlinear constraints:\n c_1≤10.0, c_2≤20.0, c_3≤30.0" - for i = 1:5 + for i in 1:5 cb = NLSolversBase.BoxConstraints(fill(0, i), fill(0, i)) @test NLSolversBase.nconstraints(cb) == 0 @test NLSolversBase.nconstraints_x(cb) == i @@ -45,7 +45,7 @@ end @testset "Once differentiable constraints" begin - lx, ux = (1.0,2.0) + lx, ux = (1.0, 2.0) odc = OnceDifferentiableConstraints([lx], [ux]) @test odc.bounds.bx == [lx, ux] @test isempty(odc.bounds.bc) @@ -57,8 +57,10 @@ odc = OnceDifferentiableConstraints(cb) @test odc.bounds == cb - odc = OnceDifferentiableConstraints(cbd.c!, cbd.jacobian!, - cbd.lx, cbd.ux, cbd.lc, cbd.uc) + odc = OnceDifferentiableConstraints( + cbd.c!, cbd.jacobian!, + cbd.lx, cbd.ux, cbd.lc, cbd.uc + ) @test isempty(odc.bounds.bx) @test isempty(odc.bounds.bc) @test odc.bounds.valc == [0.0] @@ -67,8 +69,10 @@ @testset "autodiff" begin # This throws because cbd.lc is empty (when using problem "HS9") - @test_throws ArgumentError OnceDifferentiableConstraints(cbd.c!, cbd.lx, cbd.ux, - cbd.lc, cbd.uc) + @test_throws ArgumentError OnceDifferentiableConstraints( + cbd.c!, cbd.lx, cbd.ux, + cbd.lc, cbd.uc + ) lx, ux, lc, uc = cbd.lx, cbd.ux, cbd.lc, cbd.uc nx = length(prob.initial_x) @@ -77,11 +81,15 @@ lx = fill(-Inf, nx) ux = fill(Inf, nx) end - @test_throws ArgumentError("The autodiff value `:wuoah` is not supported. Use `:finite` or `:forward`.") OnceDifferentiableConstraints(cbd.c!, lx, ux, - lc, uc, :wuoah) + @test_throws ArgumentError("The autodiff value `:wuoah` is not supported. Use `:finite` or `:forward`.") OnceDifferentiableConstraints( + cbd.c!, lx, ux, + lc, uc, :wuoah + ) for autodiff in (:finite, :forward) - odca = OnceDifferentiableConstraints(cbd.c!, lx, ux, - lc, uc, autodiff) + odca = OnceDifferentiableConstraints( + cbd.c!, lx, ux, + lc, uc, autodiff + ) T = eltype(odca.bounds) carr = zeros(T, nc) @@ -91,18 +99,18 @@ @test carr == carra - Jarr = zeros(T, nc, nx) + Jarr = zeros(T, nc, nx) Jarra = similar(Jarr) odc.jacobian!(Jarr, prob.initial_x) odca.jacobian!(Jarra, prob.initial_x) - @test isapprox(Jarr, Jarra, atol=1e-10) + @test isapprox(Jarr, Jarra, atol = 1.0e-10) end end end @testset "Twice differentiable constraints" begin - lx, ux = (1.0,2.0) + lx, ux = (1.0, 2.0) odc = TwiceDifferentiableConstraints([lx], [ux]) @test odc.bounds.bx == [lx, ux] @test isempty(odc.bounds.bc) @@ -114,14 +122,16 @@ odc = TwiceDifferentiableConstraints(cb) @test odc.bounds == cb - odc = TwiceDifferentiableConstraints(cbd.c!, cbd.jacobian!, cbd.h!, - cbd.lx, cbd.ux, cbd.lc, cbd.uc) + odc = TwiceDifferentiableConstraints( + cbd.c!, cbd.jacobian!, cbd.h!, + cbd.lx, cbd.ux, cbd.lc, cbd.uc + ) @test isempty(odc.bounds.bx) @test isempty(odc.bounds.bc) @test odc.bounds.valc == [0.0] @testset "second order autodiff" begin - + prob = MVP.ConstrainedProblems.examples["HS9"] cbd = prob.constraintdata nc = length(cbd.lc) @@ -129,47 +139,46 @@ lx = fill(-Inf, nx) ux = fill(Inf, nx) cb = ConstraintBounds(lx, ux, cbd.lc, cbd.uc) - odc = TwiceDifferentiableConstraints(cbd.c!, cbd.jacobian!, cbd.h!,lx, ux, cbd.lc, cbd.uc) + odc = TwiceDifferentiableConstraints(cbd.c!, cbd.jacobian!, cbd.h!, lx, ux, cbd.lc, cbd.uc) T = eltype(odc.bounds) - jac_result = zeros(T, nc,nx) - jac_result_autodiff = zeros(T, nc,nx) - - hess_result = zeros(T, nx,nx) - hess_result_autodiff = zeros(T, nx,nx) - λ = rand(T,nc) - λ0 = zeros(T,nc) - @test_throws ArgumentError("The autodiff value `:campanario` is not supported. Use `:finite` or `:forward`.") TwiceDifferentiableConstraints(cbd.c!,lx, ux, cbd.lc, cbd.uc,:campanario) - for autodiff in (:finite,:forward) #testing double differentiation - odca2 = TwiceDifferentiableConstraints(cbd.c!,lx, ux, cbd.lc, cbd.uc,autodiff) - - odca2.jacobian!(jac_result_autodiff,prob.initial_x) - odc.jacobian!(jac_result,prob.initial_x) - odca2.h!(hess_result_autodiff,prob.initial_x,λ0) #warmup,λ0 means no modification - odca2.h!(hess_result_autodiff,prob.initial_x,λ) - - odc.h!(hess_result,prob.initial_x,λ) - - - @test isapprox(jac_result, jac_result_autodiff, atol=1e-10) - @test isapprox(hess_result, hess_result_autodiff, atol=1e-6) - - fill!(hess_result_autodiff,zero(T)) - fill!(hess_result,zero(T)) - fill!(jac_result_autodiff,zero(T)) - fill!(jac_result,zero(T)) + jac_result = zeros(T, nc, nx) + jac_result_autodiff = zeros(T, nc, nx) + + hess_result = zeros(T, nx, nx) + hess_result_autodiff = zeros(T, nx, nx) + λ = rand(T, nc) + λ0 = zeros(T, nc) + @test_throws ArgumentError("The autodiff value `:campanario` is not supported. Use `:finite` or `:forward`.") TwiceDifferentiableConstraints(cbd.c!, lx, ux, cbd.lc, cbd.uc, :campanario) + for autodiff in (:finite, :forward) #testing double differentiation + odca2 = TwiceDifferentiableConstraints(cbd.c!, lx, ux, cbd.lc, cbd.uc, autodiff) + + odca2.jacobian!(jac_result_autodiff, prob.initial_x) + odc.jacobian!(jac_result, prob.initial_x) + odca2.h!(hess_result_autodiff, prob.initial_x, λ0) #warmup,λ0 means no modification + odca2.h!(hess_result_autodiff, prob.initial_x, λ) + + odc.h!(hess_result, prob.initial_x, λ) + + + @test isapprox(jac_result, jac_result_autodiff, atol = 1.0e-10) + @test isapprox(hess_result, hess_result_autodiff, atol = 1.0e-6) + + fill!(hess_result_autodiff, zero(T)) + fill!(hess_result, zero(T)) + fill!(jac_result_autodiff, zero(T)) + fill!(jac_result, zero(T)) end - @test_throws ArgumentError("The autodiff value `:qloctm` is not supported. Use `:finite` or `:forward`.") TwiceDifferentiableConstraints(cbd.c!, cbd.jacobian!,lx, ux, cbd.lc, cbd.uc,:qloctm) - for autodiff in (:finite,:forward) #testing autodiff hessian from constraint jacobian - odca2 = TwiceDifferentiableConstraints(cbd.c!, cbd.jacobian!,lx, ux, cbd.lc, cbd.uc,autodiff) - odca2.h!(hess_result_autodiff,prob.initial_x,λ0) #warmup,λ0 means no modification - odca2.h!(hess_result_autodiff,prob.initial_x,λ) - odc.h!(hess_result,prob.initial_x,λ) - @test isapprox(hess_result, hess_result_autodiff, atol=1e-6) - fill!(hess_result_autodiff,zero(T)) - fill!(hess_result,zero(T)) + @test_throws ArgumentError("The autodiff value `:qloctm` is not supported. Use `:finite` or `:forward`.") TwiceDifferentiableConstraints(cbd.c!, cbd.jacobian!, lx, ux, cbd.lc, cbd.uc, :qloctm) + for autodiff in (:finite, :forward) #testing autodiff hessian from constraint jacobian + odca2 = TwiceDifferentiableConstraints(cbd.c!, cbd.jacobian!, lx, ux, cbd.lc, cbd.uc, autodiff) + odca2.h!(hess_result_autodiff, prob.initial_x, λ0) #warmup,λ0 means no modification + odca2.h!(hess_result_autodiff, prob.initial_x, λ) + odc.h!(hess_result, prob.initial_x, λ) + @test isapprox(hess_result, hess_result_autodiff, atol = 1.0e-6) + fill!(hess_result_autodiff, zero(T)) + fill!(hess_result, zero(T)) end end end end - diff --git a/test/incomplete.jl b/test/incomplete.jl index ce293ce..7eb2c05 100644 --- a/test/incomplete.jl +++ b/test/incomplete.jl @@ -1,18 +1,18 @@ @testset "incomplete objectives" begin import NLSolversBase: df, fdf, make_f, make_df, make_fdf function f(x) - sum(x->x^2,x) + sum(x -> x^2, x) end g!(G, x) = G .= 2 .* x g(x) = 2 .* x - h!(H, _) = copyto!(H, 2*I) + h!(H, _) = copyto!(H, 2 * I) h(_) = Diagonal(fill(2, length(n))) function fg!(G, x) G .= 2 .* x - sum(x->x^2,x) + sum(x -> x^2, x) end function just_fg!(F, G, x) if G !== nothing @@ -21,13 +21,13 @@ if F === nothing return nothing else - return sum(x->x^2,x) + return sum(x -> x^2, x) end end fg(x) = f(x), g(x) function just_fgh!(F, G, H, x) if H !== nothing - copyto!(H, 2*I) + copyto!(H, 2 * I) end if G !== nothing G .= 2 .* x @@ -35,7 +35,7 @@ if F === nothing return nothing else - return sum(x->x^2,x) + return sum(x -> x^2, x) end end fgh(x) = f(x), g(x), h(x) @@ -46,7 +46,7 @@ Hv .= 2 .* v end function just_fghv!(F, G, Hv, x, v) - if G !== nothing + if G !== nothing G .= 2 .* x end if Hv !== nothing @@ -55,7 +55,7 @@ if F === nothing return nothing else - return sum(x->x^2, x) + return sum(x -> x^2, x) end end @@ -82,8 +82,8 @@ make_df(FDF, x, x[1])(G_cache, x) g!(G_cache2, x) @test G_cache == G_cache2 - f1 = make_fdf(FDF, x, x[1])(G_cache, x.*2) - f2 = fg!(G_cache2, x.*2) + f1 = make_fdf(FDF, x, x[1])(G_cache, x .* 2) + f2 = fg!(G_cache2, x .* 2) @test G_cache == G_cache2 @test f1 == f2 end @@ -101,8 +101,8 @@ od_fgh! = TwiceDifferentiable(only_fgh!(just_fgh!), x, _F) od_fgh! = TwiceDifferentiable(only_fgh!(just_fgh!), x, _F, similar(x)) od_fgh! = TwiceDifferentiable(only_fgh!(just_fgh!), x, _F, similar(x), NLSolversBase.alloc_H(x, _F)) -# od_fgh = TwiceDifferentiable(only_fgh(fgh), x) - for OD in (od_fg, od_fg!, od_fgh!)#, od_fgh) + # od_fgh = TwiceDifferentiable(only_fgh(fgh), x) + for OD in (od_fg, od_fg!, od_fgh!) #, od_fgh) value!(OD, x) @test value(OD) == f(x) gradient!(OD, x) @@ -116,7 +116,7 @@ # Incomplete TwiceDifferentiableHv v = randn(10) od_fg_and_hv = TwiceDifferentiableHV(only_fg_and_hv!(just_fg!, just_hv!), x) - od_fghv = TwiceDifferentiableHV(only_fghv!(just_fghv!), x) + od_fghv = TwiceDifferentiableHV(only_fghv!(just_fghv!), x) ndtdhv = NonDifferentiable(od_fghv, v) @test value(ndtdhv, v) === value(od_fghv, v) @@ -134,7 +134,7 @@ end @testset "incomplete objectives vectors" begin function tf(x) - x.^2 + x .^ 2 end function tf(F, x) copyto!(F, tf(x)) @@ -145,7 +145,7 @@ end function tfj!(F, J, x) copyto!(J, Diagonal(x)) - F .= x.^2 + F .= x .^ 2 end function just_tfj!(F, J, x) if J !== nothing @@ -154,7 +154,7 @@ end if F === nothing return nothing else - F .= x.^2 + F .= x .^ 2 return F end end @@ -188,8 +188,8 @@ end make_df(FDF, x, x)(J_cache, x) tj!(J_cache2, x) @test J_cache == J_cache2 - make_fdf(FDF, x, x)(F_cache, J_cache, x.*2) - tfj!(F_cache2, J_cache2, x.*2) + make_fdf(FDF, x, x)(F_cache, J_cache, x .* 2) + tfj!(F_cache2, J_cache2, x .* 2) @test F_cache == F_cache2 @test J_cache == J_cache2 end @@ -218,49 +218,49 @@ end @testset "https://github.com/JuliaNLSolvers/Optim.jl/issues/718" begin f(x) = (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2 function g!(G, x) - G[1] = -2.0 * (1.0 - x[1]) - 400.0 * (x[2] - x[1]^2) * x[1] - G[2] = 200.0 * (x[2] - x[1]^2) + G[1] = -2.0 * (1.0 - x[1]) - 400.0 * (x[2] - x[1]^2) * x[1] + G[2] = 200.0 * (x[2] - x[1]^2) end function h!(H, x) - H[1, 1] = 2.0 - 400.0 * x[2] + 1200.0 * x[1]^2 - H[1, 2] = -400.0 * x[1] - H[2, 1] = -400.0 * x[1] - H[2, 2] = 200.0 + H[1, 1] = 2.0 - 400.0 * x[2] + 1200.0 * x[1]^2 + H[1, 2] = -400.0 * x[1] + H[2, 1] = -400.0 * x[1] + H[2, 2] = 200.0 end - function fg!(F,G,x) - if G !== nothing - g!(G,x) - end - if F === nothing - return nothing - else - return f(x) - end + function fg!(F, G, x) + if G !== nothing + g!(G, x) + end + if F === nothing + return nothing + else + return f(x) + end end - function fgh!(F,G,H,x) - if G !== nothing - g!(G,x) - end - if H !== nothing - h!(H,x) - end - if F === nothing - return nothing - else - return f(x) - end + function fgh!(F, G, H, x) + if G !== nothing + g!(G, x) + end + if H !== nothing + h!(H, x) + end + if F === nothing + return nothing + else + return f(x) + end end - - gx = [0.0,0.0] - x=[0.0,0.0] - @test NLSolversBase.make_f(only_fgh!(fgh!),[0.0,0.0],0.0)(x) == 1.0 - @test NLSolversBase.make_df(only_fgh!(fgh!),[0.0,0.0],0.0)(gx, x) === nothing + gx = [0.0, 0.0] + x = [0.0, 0.0] + + @test NLSolversBase.make_f(only_fgh!(fgh!), [0.0, 0.0], 0.0)(x) == 1.0 + @test NLSolversBase.make_df(only_fgh!(fgh!), [0.0, 0.0], 0.0)(gx, x) === nothing @test gx == [-2.0, 0.0] - gx = [0.0,0.0] - @test NLSolversBase.make_fdf(only_fgh!(fgh!),[0.0,0.0],0.0)(gx, x) == 1.0 + gx = [0.0, 0.0] + @test NLSolversBase.make_fdf(only_fgh!(fgh!), [0.0, 0.0], 0.0)(gx, x) == 1.0 @test gx == [-2.0, 0.0] end diff --git a/test/interface.jl b/test/interface.jl index 51bb510..61b17e2 100644 --- a/test/interface.jl +++ b/test/interface.jl @@ -10,7 +10,7 @@ x_alt = [1.0, 1.0] f_x_alt = 57.316431861603284 g_x_alt = [-5.43656365691809, -218.39260013257694] - h_x_alt = [16.30969097075427 0.; 0. 982.7667005965963] + h_x_alt = [16.30969097075427 0.0; 0.0 982.7667005965963] # Construct instances nd = NonDifferentiable(exponential, x_seed) @@ -69,7 +69,7 @@ @test value(nd) == value(od) == value(td) == f_x_seed @test gradient(td) == g_x_alt - @test gradient(td) == [gradient(td, i) for i = 1:length(x_seed)] + @test gradient(td) == [gradient(td, i) for i in 1:length(x_seed)] @test hessian(td) == h_x_seed @test nd.f_calls == od.f_calls == td.f_calls == 3 @test od.df_calls == td.df_calls == 3 @@ -170,8 +170,8 @@ G = NLSolversBase.alloc_DF(x, 0.0) H = NLSolversBase.alloc_H(x, 0.0) MVP.hessian(prob)(H, x) - @test hv_product!(ddf, x, v) == H*v - @test hv_product(ddf) == H*v + @test hv_product!(ddf, x, v) == H * v + @test hv_product(ddf) == H * v @test hv_product(ddf) == ddf.Hv F, G = fg!(G, x) @test gradient!(ddf, x) == G @@ -193,14 +193,14 @@ # Test example: Rosenbrock MINPACK function f!(F::Vector, x::Vector) F[1] = 1 - x[1] - F[2] = 10(x[2]-x[1]^2) + F[2] = 10(x[2] - x[1]^2) F end function j!(J::Matrix, x::Vector) - J[1,1] = -1 - J[1,2] = 0 - J[2,1] = -20x[1] - J[2,2] = 10 + J[1, 1] = -1 + J[1, 2] = 0 + J[2, 1] = -20x[1] + J[2, 2] = 10 J end diff --git a/test/kwargs.jl b/test/kwargs.jl index 8e99707..2fe5862 100644 --- a/test/kwargs.jl +++ b/test/kwargs.jl @@ -4,8 +4,10 @@ fia1 = OnceDifferentiable(exponential, rand(2); inplace = false) fi1 = OnceDifferentiable(exponential, exponential_gradient, rand(2); inplace = false) fi2 = OnceDifferentiable(exponential, exponential_gradient, rand(2); inplace = false) - fi3 = OnceDifferentiable(exponential, exponential_gradient, exponential_value_gradient, - rand(2); inplace = false) + fi3 = OnceDifferentiable( + exponential, exponential_gradient, exponential_value_gradient, + rand(2); inplace = false + ) xr = rand(2) @test value!(f1, xr) ≈ value!(fia1, xr) ≈ value!(fi1, xr) ≈ value!(fi2, xr) ≈ value!(fi3, xr) @test gradient!(f1, xr) ≈ gradient!(fia1, xr) @@ -21,10 +23,14 @@ ftia1 = TwiceDifferentiable(exponential, rand(2); inplace = false) fti1 = TwiceDifferentiable(exponential, exponential_gradient, rand(2); inplace = false) fti2 = TwiceDifferentiable(exponential, exponential_gradient, rand(2); inplace = false) - fti3 = TwiceDifferentiable(exponential, exponential_gradient, exponential_hessian, - rand(2); inplace = false) - fti4 = TwiceDifferentiable(exponential, exponential_gradient, exponential_value_gradient, - exponential_hessian, rand(2); inplace = false) + fti3 = TwiceDifferentiable( + exponential, exponential_gradient, exponential_hessian, + rand(2); inplace = false + ) + fti4 = TwiceDifferentiable( + exponential, exponential_gradient, exponential_value_gradient, + exponential_hessian, rand(2); inplace = false + ) @test value!(ft1, xr) ≈ value!(ftia1, xr) ≈ value!(fti1, xr) ≈ value!(fti2, xr) ≈ value!(fti3, xr) ≈ value!(fti4, xr) @test gradient!(ft1, xr) ≈ gradient!(ftia1, xr) @@ -46,8 +52,10 @@ fia2 = OnceDifferentiable(exponential_gradient, rand(2), rand(2); inplace = false, autodiff = :forward) fi1 = OnceDifferentiable(exponential_gradient, exponential_hessian, rand(2), rand(2); inplace = false) fi2 = OnceDifferentiable(exponential_gradient, exponential_hessian, rand(2), rand(2); inplace = false) - fi3 = OnceDifferentiable(exponential_gradient, exponential_hessian, exponential_gradient_hessian, - rand(2), rand(2); inplace = false) + fi3 = OnceDifferentiable( + exponential_gradient, exponential_hessian, exponential_gradient_hessian, + rand(2), rand(2); inplace = false + ) xr = fill(2.0, 2) @test value!(f1, xr) ≈ value!(fia1, xr) ≈ value!(fia2, xr) ≈ value!(fi1, xr) ≈ value!(fi2, xr) ≈ value!(fi3, xr) @test jacobian!(f1, xr) ≈ jacobian!(fia1, xr) ≈ jacobian!(fia2, xr) ≈ jacobian!(fi1, xr) ≈ jacobian!(fi2, xr) ≈ jacobian!(fi3, xr) @@ -69,8 +77,10 @@ end @testset "autodiff" begin # base line api - f1 = OnceDifferentiable(exponential, exponential_gradient!, exponential_value_gradient!, - rand(2), 0.0, rand(2)) + f1 = OnceDifferentiable( + exponential, exponential_gradient!, exponential_value_gradient!, + rand(2), 0.0, rand(2) + ) # default autodiff R^N → R fa1 = OnceDifferentiable(exponential, rand(2)) # specific autodiff R^N → R diff --git a/test/qa.jl b/test/qa.jl index e780476..646b828 100644 --- a/test/qa.jl +++ b/test/qa.jl @@ -31,4 +31,4 @@ # Analyze methods based on their declared signature JET.test_package(NLSolversBase; target_defined_modules = true, toplevel_logger = nothing) end -end \ No newline at end of file +end diff --git a/test/runtests.jl b/test/runtests.jl index 764d3f5..38892a6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -23,7 +23,7 @@ end function exponential_gradient!(storage, x) storage[1] = -2.0 * (2.0 - x[1]) * exp((2.0 - x[1])^2) - storage[2] = -2.0 * (3.0 - x[2]) * exp((3.0 - x[2])^2) + return storage[2] = -2.0 * (3.0 - x[2]) * exp((3.0 - x[2])^2) end @@ -31,7 +31,7 @@ function exponential_gradient(x) storage = similar(x) storage[1] = -2.0 * (2.0 - x[1]) * exp((2.0 - x[1])^2) storage[2] = -2.0 * (3.0 - x[2]) * exp((3.0 - x[2])^2) - storage + return storage end @@ -56,7 +56,7 @@ function exponential_gradient_hessian(x) J[1, 2] = 0.0 J[2, 1] = 0.0 J[2, 2] = 2.0 * exp((3.0 - x[1])^2) * (2.0 * x[2]^2 - 12.0 * x[2] + 19) - F, J + return F, J end function exponential_hessian(x) @@ -66,24 +66,24 @@ function exponential_hessian(x) storage[1, 2] = 0.0 storage[2, 1] = 0.0 storage[2, 2] = 2.0 * exp((3.0 - x[1])^2) * (2.0 * x[2]^2 - 12.0 * x[2] + 19) - storage + return storage end function exponential_hessian!(storage, x) storage[1, 1] = 2.0 * exp((2.0 - x[1])^2) * (2.0 * x[1]^2 - 8.0 * x[1] + 9) storage[1, 2] = 0.0 storage[2, 1] = 0.0 - storage[2, 2] = 2.0 * exp((3.0 - x[1])^2) * (2.0 * x[2]^2 - 12.0 * x[2] + 19) + return storage[2, 2] = 2.0 * exp((3.0 - x[1])^2) * (2.0 * x[2]^2 - 12.0 * x[2] + 19) end function exponential_hessian_product!(storage, x) storage[1, 1] = 2.0 * exp((2.0 - x[1])^2) * (2.0 * x[1]^2 - 8.0 * x[1] + 9) storage[1, 2] = 0.0 storage[2, 1] = 0.0 - storage[2, 2] = 2.0 * exp((3.0 - x[1])^2) * (2.0 * x[2]^2 - 12.0 * x[2] + 19) + return storage[2, 2] = 2.0 * exp((3.0 - x[1])^2) * (2.0 * x[2]^2 - 12.0 * x[2] + 19) end -@testset verbose=true "NLSolversBase.jl" begin +@testset verbose = true "NLSolversBase.jl" begin include("objective_types.jl") include("interface.jl") include("incomplete.jl") diff --git a/test/sparse.jl b/test/sparse.jl index b006402..64293ad 100644 --- a/test/sparse.jl +++ b/test/sparse.jl @@ -1,8 +1,8 @@ @testset "sparse" begin @testset "𝐑ⁿ → 𝐑" begin - f(x) = sum(x->x^2, x) + f(x) = sum(x -> x^2, x) g(G, x) = G .= 2 .* x - h(H, _) = coptyo!(H, 2*I) + h(H, _) = coptyo!(H, 2 * I) obj_dense = TwiceDifferentiable(f, g, h, rand(40)) @test !issparse(obj_dense.H) @@ -15,12 +15,12 @@ G .= 2 .* x end if H !== nothing - copyto!(H, 2*I) + copyto!(H, 2 * I) end if F === nothing return nothing else - return sum(x->x^2, x) + return sum(x -> x^2, x) end end @@ -29,7 +29,7 @@ end @testset "𝐑ⁿ → 𝐑ⁿ" begin f(F, x) = F .= 2 .* x - j(J, _) = copyto!(J, 2.0*I) + j(J, _) = copyto!(J, 2.0 * I) # Test that with no spec on the Jacobian cache it is dense obj_dense = OnceDifferentiable(f, j, rand(40), rand(40)) @@ -47,7 +47,7 @@ F .= 2 .* x end if J !== nothing - copyto!(J, 2*I) + copyto!(J, 2 * I) end return F end diff --git a/test/utils.jl b/test/utils.jl index 84cd4fb..7921459 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -3,21 +3,21 @@ for T in (Int, Float32, Float64) for x in (zeros(T), zeros(T, 2), zeros(T, 3, 2)) x_nans = @inferred(NLSolversBase.x_of_nans(x)) - @test x_nans isa Array{float(T),ndims(x)} + @test x_nans isa Array{float(T), ndims(x)} @test size(x_nans) == size(x) @test all(isnan, x_nans) end - for x in (SArray{Tuple{}}(zeros(T)), SArray{Tuple{2}}(zeros(T, 2)), SArray{Tuple{3,2}}(zeros(T, 3, 2))) + for x in (SArray{Tuple{}}(zeros(T)), SArray{Tuple{2}}(zeros(T, 2)), SArray{Tuple{3, 2}}(zeros(T, 3, 2))) x_nans = @inferred(NLSolversBase.x_of_nans(x)) - @test x_nans isa MArray{Tuple{size(x)...},float(T)} + @test x_nans isa MArray{Tuple{size(x)...}, float(T)} @test size(x_nans) == size(x) @test all(isnan, x_nans) end - for x in (MArray{Tuple{}}(zeros(T)), MArray{Tuple{2}}(zeros(T, 2)), MArray{Tuple{3,2}}(zeros(T, 3, 2))) + for x in (MArray{Tuple{}}(zeros(T)), MArray{Tuple{2}}(zeros(T, 2)), MArray{Tuple{3, 2}}(zeros(T, 3, 2))) x_nans = @inferred(NLSolversBase.x_of_nans(x)) - @test x_nans isa MArray{Tuple{size(x)...},float(T)} + @test x_nans isa MArray{Tuple{size(x)...}, float(T)} @test size(x_nans) == size(x) @test all(isnan, x_nans) end