Skip to content

Commit 950a12c

Browse files
authored
Refactor code base (#163)
1 parent 72b1467 commit 950a12c

19 files changed

+307
-249
lines changed

.github/workflows/Test.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,6 @@ jobs:
2323
- 'lts'
2424
- '1'
2525
os: [ubuntu-latest, windows-latest, macOS-latest]
26-
exclude:
27-
- os: macOS-latest # Apple Silicon
28-
version: 'min'
29-
include:
30-
- os: macOS-13 # Intel
31-
version: 'min'
3226
steps:
3327
- uses: actions/checkout@v4
3428
- uses: julia-actions/setup-julia@v2

Project.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,31 @@
11
name = "NLSolversBase"
22
uuid = "d41bc354-129a-5804-8e4c-c37616107c6c"
3-
version = "7.10.0"
3+
version = "7.11.0"
44

55
[deps]
66
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
77
DifferentiationInterface = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63"
88
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
99
FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41"
1010
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
11+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1112

1213
[compat]
1314
ADTypes = "1.11.0"
1415
DifferentiationInterface = "0.6.43, 0.7"
1516
FiniteDiff = "2.0"
1617
ForwardDiff = "0.10, 1.0"
18+
LinearAlgebra = "<0.0.1, 1"
1719
julia = "1.10"
1820

1921
[extras]
2022
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
2123
ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66"
22-
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
2324
OptimTestProblems = "cec144fc-5a64-5bc6-99fb-dde8f63e154c"
2425
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
2526
RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd"
2627
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
2728
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
2829

2930
[targets]
30-
test = ["ADTypes", "ComponentArrays", "LinearAlgebra", "OptimTestProblems", "Random", "RecursiveArrayTools", "SparseArrays", "Test"]
31+
test = ["ADTypes", "ComponentArrays", "OptimTestProblems", "Random", "RecursiveArrayTools", "SparseArrays", "Test"]

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,10 @@ interface as shown below.
175175
```julia
176176
function fg!(F, G, x)
177177
common_calc(...)
178-
if !(G == nothing)
178+
if G !== nothing
179179
# mutating calculations specific to g!
180180
end
181-
if !(F == nothing)
181+
if F !== nothing
182182
# calculations specific to f
183183
return f
184184
end

src/NLSolversBase.jl

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
__precompile__(true)
2-
31
module NLSolversBase
42

53
using ADTypes: AbstractADType, AutoForwardDiff, AutoFiniteDiff
64
import DifferentiationInterface as DI
75
using FiniteDiff: FiniteDiff
86
using ForwardDiff: ForwardDiff
7+
using LinearAlgebra: LinearAlgebra
98
import Distributed: clear!
109
export AbstractObjective,
1110
NonDifferentiable,
@@ -51,7 +50,7 @@ function finitediff_fdtype(autodiff)
5150
fdtype = Val{:forward}
5251
elseif autodiff == :finitecomplex
5352
fdtype = Val{:complex}
54-
elseif any(autodiff .== (:finite, :central, :finitecentral))
53+
elseif autodiff == :finite || autodiff == :central || autodiff == :finitecentral
5554
fdtype = Val{:central}
5655
end
5756
fdtype
@@ -71,11 +70,11 @@ function get_adtype(autodiff::Union{Symbol,Bool}, chunk=nothing)
7170
elseif is_forwarddiff(autodiff)
7271
return AutoForwardDiff(; chunksize=forwarddiff_chunksize(chunk))
7372
else
74-
error("The autodiff value $autodiff is not supported. Use :finite or :forward.")
73+
throw(ArgumentError(LazyString("The autodiff value `", repr(autodiff), "` is not supported. Use `:finite` or `:forward`.")))
7574
end
7675
end
7776

78-
x_of_nans(x, Tf=eltype(x)) = fill!(Tf.(x), Tf(NaN))
77+
x_of_nans(x::AbstractArray, ::Type{Tf}=float(eltype(x))) where {Tf} = fill!(similar(x, Tf), NaN)
7978

8079
include("objective_types/inplace_factory.jl")
8180
include("objective_types/abstract.jl")

src/interface.jl

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Force (re-)evaluation of the objective value at `x`.
44
Returns `f(x)` and stores the value in `obj.F`
55
"""
66
function value!!(obj::AbstractObjective, x)
7-
obj.f_calls .+= 1
7+
obj.f_calls += 1
88
copyto!(obj.x_f, x)
99
obj.F = obj.f(x)
1010
value(obj)
@@ -15,7 +15,7 @@ Evaluates the objective value at `x`.
1515
Returns `f(x)`, but does *not* store the value in `obj.F`
1616
"""
1717
function value(obj::AbstractObjective, x)
18-
obj.f_calls .+= 1
18+
obj.f_calls += 1
1919
return obj.f(x)
2020
end
2121
"""
@@ -38,7 +38,7 @@ This does *not* update `obj.DF` or `obj.x_df`.
3838
function gradient(obj::AbstractObjective, x)
3939
newdf = copy(obj.DF)
4040
obj.df(newdf, x)
41-
obj.df_calls .+= 1
41+
obj.df_calls += 1
4242
return newdf
4343
end
4444
"""
@@ -58,7 +58,7 @@ Force (re-)evaluation of the gradient value at `x`.
5858
Stores the value in `obj.DF`.
5959
"""
6060
function gradient!!(obj::AbstractObjective, x)
61-
obj.df_calls .+= 1
61+
obj.df_calls += 1
6262
copyto!(obj.x_df, x)
6363
obj.df(obj.DF, x)
6464
gradient(obj)
@@ -75,8 +75,8 @@ function value_gradient!(obj::AbstractObjective, x)
7575
value(obj), gradient(obj)
7676
end
7777
function value_gradient!!(obj::AbstractObjective, x)
78-
obj.f_calls .+= 1
79-
obj.df_calls .+= 1
78+
obj.f_calls += 1
79+
obj.df_calls += 1
8080
copyto!(obj.x_f, x)
8181
copyto!(obj.x_df, x)
8282
obj.F = obj.fdf(gradient(obj), x)
@@ -90,7 +90,7 @@ function hessian!(obj::AbstractObjective, x)
9090
hessian(obj)
9191
end
9292
function hessian!!(obj::AbstractObjective, x)
93-
obj.h_calls .+= 1
93+
obj.h_calls += 1
9494
copyto!(obj.x_h, x)
9595
obj.h(obj.H, x)
9696
hessian(obj)
@@ -124,8 +124,8 @@ function value_jacobian!!(obj, F, J, x)
124124
obj.fdf(F, J, x)
125125
copyto!(obj.x_f, x)
126126
copyto!(obj.x_df, x)
127-
obj.f_calls .+= 1
128-
obj.df_calls .+= 1
127+
obj.f_calls += 1
128+
obj.df_calls += 1
129129
obj.df_calls
130130
F, J
131131
end
@@ -141,7 +141,7 @@ jacobian!!(obj, x) = jacobian!!(obj, obj.DF, x)
141141
function jacobian!!(obj, J, x)
142142
obj.df(J, x)
143143
copyto!(obj.x_df, x)
144-
obj.df_calls .+= 1
144+
obj.df_calls += 1
145145
obj.df_calls
146146
J
147147
end
@@ -156,7 +156,7 @@ end
156156
value(obj::NonDifferentiable{TF, TX}, x) where {TF<:AbstractArray, TX} = value(obj, copy(obj.F), x)
157157
value(obj::OnceDifferentiable{TF, TDF, TX}, x) where {TF<:AbstractArray, TDF, TX} = value(obj, copy(obj.F), x)
158158
function value(obj::AbstractObjective, F, x)
159-
obj.f_calls .+= 1
159+
obj.f_calls += 1
160160
return obj.f(F, x)
161161
end
162162

@@ -165,41 +165,41 @@ value!!(obj::OnceDifferentiable{TF, TDF, TX}, x) where {TF<:AbstractArray, TDF,
165165
function value!!(obj::AbstractObjective, F, x)
166166
obj.f(F, x)
167167
copyto!(obj.x_f, x)
168-
obj.f_calls .+= 1
168+
obj.f_calls += 1
169169
obj.f_calls
170170
F
171171
end
172172

173173
function _clear_f!(d::NLSolversBase.AbstractObjective)
174-
d.f_calls .= 0
175-
if typeof(d.F) <: AbstractArray
176-
d.F .= eltype(d.F)(NaN)
174+
d.f_calls = 0
175+
if d.F isa AbstractArray
176+
fill!(d.F, NaN)
177177
else
178-
d.F = typeof(d.F)(NaN)
178+
d.F = NaN
179179
end
180-
d.x_f .= eltype(d.x_f)(NaN)
180+
fill!(d.x_f, NaN)
181181
nothing
182182
end
183183

184184
function _clear_df!(d::NLSolversBase.AbstractObjective)
185-
d.df_calls .= 0
186-
d.DF .= eltype(d.DF)(NaN)
187-
d.x_df .= eltype(d.x_df)(NaN)
185+
d.df_calls = 0
186+
fill!(d.DF, NaN)
187+
fill!(d.x_df, NaN)
188188
nothing
189189
end
190190

191191
function _clear_h!(d::NLSolversBase.AbstractObjective)
192-
d.h_calls .= 0
193-
d.H .= eltype(d.H)(NaN)
194-
d.x_h .= eltype(d.x_h)(NaN)
192+
d.h_calls = 0
193+
fill!(d.H, NaN)
194+
fill!(d.x_h, NaN)
195195
nothing
196196
end
197197

198198
function _clear_hv!(d::NLSolversBase.AbstractObjective)
199-
d.hv_calls .= 0
200-
d.Hv .= eltype(d.Hv)(NaN)
201-
d.x_hv .= eltype(d.x_hv)(NaN)
202-
d.v_hv .= eltype(d.v_hv)(NaN)
199+
d.hv_calls = 0
200+
fill!(d.Hv, NaN)
201+
fill!(d.x_hv, NaN)
202+
fill!(d.v_hv, NaN)
203203
nothing
204204
end
205205

@@ -227,9 +227,9 @@ end
227227

228228
g_calls(d::NonDifferentiable) = 0
229229
h_calls(d::Union{NonDifferentiable, OnceDifferentiable}) = 0
230-
f_calls(d) = first(d.f_calls)
231-
g_calls(d) = first(d.df_calls)
232-
h_calls(d) = first(d.h_calls)
230+
f_calls(d) = d.f_calls
231+
g_calls(d) = d.df_calls
232+
h_calls(d) = d.h_calls
233233
hv_calls(d) = 0
234234
h_calls(d::TwiceDifferentiableHV) = 0
235-
hv_calls(d::TwiceDifferentiableHV) = first(d.hv_calls)
235+
hv_calls(d::TwiceDifferentiableHV) = d.hv_calls

src/objective_types/constraints.jl

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ function _cb(lx::AbstractArray{Tx}, ux::AbstractArray{Tx}, lc::AbstractVector{Tc
4040
end
4141

4242
Base.eltype(::Type{ConstraintBounds{T}}) where T = T
43-
Base.eltype(cb::ConstraintBounds) = eltype(typeof(cb))
4443

44+
Base.convert(::Type{ConstraintBounds{T}}, cb::ConstraintBounds{T}) where {T} = cb
4545
Base.convert(::Type{ConstraintBounds{T}}, cb::ConstraintBounds{S}) where {T,S} =
46-
ConstraintBounds(cb.nc, cb.eqx, convert(Vector{T}, cb.valx),
46+
ConstraintBounds{T}(cb.nc, cb.eqx, convert(Vector{T}, cb.valx),
4747
cb.ineqx, cb.σx, convert(Vector{T}, cb.bx),
4848
cb.eqc, convert(Vector{T}, cb.valc), cb.ineqc,
4949
cb.σc, convert(Vector{T}, cb.bc))
@@ -80,11 +80,11 @@ function Base.show(io::IO, cb::ConstraintBounds)
8080
indent = " "
8181
print(io, "ConstraintBounds:")
8282
print(io, "\n Variables:")
83-
showeq(io, indent, cb.eqx, cb.valx, 'x', :bracket)
84-
showineq(io, indent, cb.ineqx, cb.σx, cb.bx, 'x', :bracket)
83+
showeq(io, indent, cb.eqx, cb.valx, 'x', true) # bracket
84+
showineq(io, indent, cb.ineqx, cb.σx, cb.bx, 'x', true) # bracket
8585
print(io, "\n Linear/nonlinear constraints:")
86-
showeq(io, indent, cb.eqc, cb.valc, 'c', :subscript)
87-
showineq(io, indent, cb.ineqc, cb.σc, cb.bc, 'c', :subscript)
86+
showeq(io, indent, cb.eqc, cb.valc, 'c', false) # subscript
87+
showineq(io, indent, cb.ineqc, cb.σc, cb.bc, 'c', false) # subscript
8888
nothing
8989
end
9090

@@ -177,7 +177,7 @@ function TwiceDifferentiableConstraints(c!, lx::AbstractVector, ux::AbstractVect
177177
# TODO: get rid of this allocation with DI.Cache
178178
ccache_righttype = zeros(promote_type(T, eltype(_x)), nc)
179179
c!(ccache_righttype, _x)
180-
return sum(_λ[i] * ccache[i] for i in eachindex(_λ, ccache))
180+
return LinearAlgebra.dot(_λ, ccache_righttype)
181181
end
182182

183183
backend = get_adtype(autodiff, chunk)
@@ -281,17 +281,17 @@ corresponding entry in `ineq`/`σ`/`b`.
281281
T is the element-type of the non-Int outputs
282282
"""
283283
function parse_constraints(::Type{T}, l, u) where T
284-
size(l) == size(u) || throw(DimensionMismatch("l and u must be the same size, got $(size(l)) and $(size(u))"))
284+
if size(l) != size(u)
285+
throw(DimensionMismatch(LazyString("Size of lower bounds (", size(l), ") and number of upper bounds (", size(u), ") must be equal.")))
286+
end
285287
eq, ineq = Int[], Int[]
288+
σ = Int8[]
286289
val, b = T[], T[]
287-
σ = Array{Int8}(undef, 0)
288-
for i = 1:length(l)
289-
li, ui = l[i], u[i]
290-
li <= ui || throw(ArgumentError("l must be smaller than u, got $li, $ui"))
290+
for (i, (li, ui)) in enumerate(zip(l, u))
291291
if li == ui
292292
push!(eq, i)
293293
push!(val, ui)
294-
else
294+
elseif li < ui
295295
if isfinite(li)
296296
push!(ineq, i)
297297
push!(σ, 1)
@@ -302,36 +302,55 @@ function parse_constraints(::Type{T}, l, u) where T
302302
push!(σ, -1)
303303
push!(b, ui)
304304
end
305+
else
306+
throw(ArgumentError(LazyString("Lower bound (", li, ") must not be greater than upper bound (", ui, ").")))
305307
end
306308
end
307309
eq, val, ineq, σ, b
308310
end
309311

310312
### Compact printing of constraints
311313

312-
function showeq(io, indent, eq, val, chr, style)
313-
if !isempty(eq)
314+
function showeq(io::IO, indent::String, eqs::Vector{Int}, vals::Vector, chr::Char, bracket::Bool)
315+
if !isempty(eqs)
314316
print(io, '\n', indent)
315-
if style == :bracket
316-
eqstrs = map((i, v)->"$chr[$i]=$v", eq, val)
317+
if bracket
318+
for (i, (eq, val)) in enumerate(zip(eqs, vals))
319+
if i != 1
320+
print(io, ", ")
321+
end
322+
print(io, chr, "[", eq, "]=", val)
323+
end
317324
else
318-
eqstrs = map((i, v)->"$(chr)_$i=$v", eq, val)
325+
for (i, (eq, val)) in enumerate(zip(eqs, vals))
326+
if i != 1
327+
print(io, ", ")
328+
end
329+
print(io, chr, "_", eq, "=", val)
330+
end
319331
end
320-
foreach(s->print(io, s * ", "), eqstrs[1:end - 1])
321-
print(io, eqstrs[end])
322332
end
333+
return nothing
323334
end
324335

325-
function showineq(io, indent, ineqs, σs, bs, chr, style)
336+
function showineq(io::IO, indent::String, ineqs::Vector{Int}, σs::Vector{Int8}, bs::Vector, chr::Char, bracket::Bool)
326337
if !isempty(ineqs)
327338
print(io, '\n', indent)
328-
if style == :bracket
329-
ineqstrs = map((i, σ, b)->"$chr[$i]" * ineqstr(σ, b), ineqs, σs, bs)
339+
if bracket
340+
for (i, (ineq, σ, b)) in enumerate(zip(ineqs, σs, bs))
341+
if i != 1
342+
print(io, ", ")
343+
end
344+
print(io, chr, "[", ineq, "]", σ > 0 ? '' : '', b)
345+
end
330346
else
331-
ineqstrs = map((i, σ, b)->"$(chr)_$i" * ineqstr(σ, b), ineqs, σs, bs)
347+
for (i, (ineq, σ, b)) in enumerate(zip(ineqs, σs, bs))
348+
if i != 1
349+
print(io, ", ")
350+
end
351+
print(io, chr, "_", ineq, σ > 0 ? '' : '', b)
352+
end
332353
end
333-
foreach(s->print(io, s * ", "), ineqstrs[1:end - 1])
334-
print(io, ineqstrs[end])
335354
end
355+
return nothing
336356
end
337-
ineqstr(σ, b) = σ > 0 ? "$b" : "$b"

0 commit comments

Comments
 (0)