Skip to content

Commit 5970be6

Browse files
authored
Weakdep (#20)
* implement Optim as a weak dependency * set Optimizer in __init__ of extension package * add Optim to Extras in project.toml
1 parent d4553f6 commit 5970be6

File tree

6 files changed

+61
-19
lines changed

6 files changed

+61
-19
lines changed

Project.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
1313
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
1414
StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
1515

16+
[weakdeps]
17+
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
18+
19+
[extras]
20+
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
21+
22+
[extensions]
23+
DistributionFitsOptimExt = "Optim"
24+
1625
[compat]
1726
Distributions = "0.25"
1827
FillArrays = "0.12, 0.13, 1"
@@ -22,3 +31,5 @@ StaticArrays = "1.2"
2231
StatsBase = "0.33"
2332
StatsFuns = "0.9, 1"
2433
julia = "1.6"
34+
Optim = "1.7"
35+

ext/DistributionFitsOptimExt.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module DistributionFitsOptimExt
2+
3+
isdefined(Base, :get_extension) ? (using Optim) : (using ..Optim)
4+
using DistributionFits: DistributionFits, optimize, AbstractDistributionFitOptimizer
5+
6+
struct OptimOptimizer <: AbstractDistributionFitOptimizer; end
7+
8+
function DistributionFits.optimize(f, ::OptimOptimizer, lower, upper)
9+
result = Optim.optimize(f, lower, upper)
10+
(;minimizer = result.minimizer, converged = result.converged, result)
11+
end
12+
13+
function __init__()
14+
@info "DistributionFits: setting OptimOptimizer"
15+
#DistributionFits.set_optimizer(DistributionFitsOptimExt.OptimOptimizer())
16+
DistributionFits.set_optimizer(OptimOptimizer())
17+
end
18+
19+
end

src/DistributionFits.jl

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ using Reexport
55

66
using FillArrays, StaticArrays
77
using StatsFuns: logit, logistic, normcdf
8-
using Requires: @require
8+
9+
if !isdefined(Base, :get_extension)
10+
using Requires
11+
end
912

1013
# for extension
1114
import Distributions: mean, var, mode
@@ -21,6 +24,11 @@ export
2124
@qs_cf90, @qs_cf95,
2225
fit_mean_relerror
2326

27+
# document but do not export - need to qualify by 'DistributionFits.'
28+
# export
29+
# # Optimizer detail
30+
# optimize, set_optimizer
31+
2432
# LogNormal
2533
export AbstractΣstar, Σstar, σstar
2634

@@ -30,11 +38,13 @@ export fit_mode_flat, shifloNormal
3038
# dependency inversion: need to define DistributionFits.optimize by user
3139
export AbstractDistributionFitOptimizer, optimize
3240

33-
3441
include("optimizer.jl")
3542

43+
3644
function __init__()
37-
@require Optim="429524aa-4258-5aef-a3af-852621145aeb" include("requires_optim.jl")
45+
@static if !isdefined(Base, :get_extension)
46+
@require Optim="429524aa-4258-5aef-a3af-852621145aeb" include("../ext/DistributionFitsOptimExt.jl")
47+
end
3848
end
3949

4050
# fitting distributions to stats

src/optimizer.jl

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ function `f` on bounded interval `[lower,upper]`:
1111
Returning an object with fields `minimizer` and `converged`.
1212
1313
`DistributionFits.set_optimizer(::AbstractDistributionFitOptimizer)`
14-
sets the optimizer used in calling the optimize function.
14+
sets the specific AbstractDistributionFitOptimizer that is used
15+
throughout the package for calling the optimize function.
1516
Specializing this function with a concrete type, allows using different
1617
optimization packages.
1718
@@ -20,21 +21,25 @@ package is in scope, the
2021
`OptimOptimizer` is set, which implements the interface by using Optim's
2122
[optimize](https://julianlsolvers.github.io/Optim.jl/stable/#user/minimization/#minimizing-a-univariate-function-on-a-bounded-interval) function.
2223
23-
Hence, the module using DistribuitonFits.jl has to either
24+
Hence, the module using `DistributionFits.jl` has to either
2425
2526
- explicitly invoke `using Optim`, or
2627
- call `set_optimizer` with the concrete subtype of `AbstractDistributionFitOptimizer`
27-
for which the corresponding optimize method is implemented.
28+
for which the corresponding `optimize` method is implemented.
29+
30+
Developers implementing usage of a different specific optimizer see code in
31+
ext/DistributionFitsOptimExt.
2832
"""
2933
abstract type AbstractDistributionFitOptimizer end
30-
struct OptimOptimizer <: AbstractDistributionFitOptimizer; end
3134
struct NotSetOptimizer <: AbstractDistributionFitOptimizer; end
3235

36+
# see to ext/DistributionFitsOptimExt.jl
3337

3438
optimize(f, ::NotSetOptimizer, lower, upper) = error(
3539
"Optimizer not set yet. Either invoke 'using Optim' or 'DistributionFits.set_optimizer(...)'.")
3640

3741

38-
optimizer = NotSetOptimizer();
39-
optimize(f, lower, upper) = optimize(f, optimizer, lower, upper)
40-
set_optimizer(opt::AbstractDistributionFitOptimizer) = (global optimizer = opt)
42+
df_optimizer = NotSetOptimizer();
43+
optimize(f, lower, upper) = optimize(f, df_optimizer, lower, upper)
44+
set_optimizer(opt::AbstractDistributionFitOptimizer) = (global df_optimizer = opt)
45+

src/requires_optim.jl

Lines changed: 0 additions & 7 deletions
This file was deleted.

test/runtests.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,20 @@ using Test
33
using Random: Random
44

55
@testset "optimize error" begin
6-
@test_throws Exception DistributionFits.optimize(x -> x*x, DistributionFits.optimizer, -1, 1)
6+
@test_throws Exception DistributionFits.optimize(x -> x*x, -1, 1)
77
end
88
# Optim package for interactive testing
99
i_loadlibs = () -> begin
1010
push!(LOAD_PATH, expanduser("~/julia/scimltools/")) # access local package repo
11+
push!(LOAD_PATH, expanduser("~/julia/18_tools/scimltools/")) # access local package repo
1112
end
1213
using Optim: Optim, optimize
14+
15+
DistributionFitsOptimExt = isdefined(Base, :get_extension) ? Base.get_extension(DistributionFits, :DistributionFitsOptimExt) : DistributionFits.DistributionFitsOptimExt
16+
1317
@testset "optimize set in __init__ after using Optim" begin
1418
# set in __init__
15-
@test DistributionFits.optimizer isa DistributionFits.OptimOptimizer
19+
@test DistributionFits.df_optimizer isa DistributionFitsOptimExt.OptimOptimizer
1620
end
1721

1822
const tests = [

0 commit comments

Comments
 (0)