Skip to content

Commit

Permalink
format according to SciMLStyle
Browse files Browse the repository at this point in the history
  • Loading branch information
bgctw committed Oct 24, 2023
1 parent 5ea136b commit db76e41
Show file tree
Hide file tree
Showing 26 changed files with 484 additions and 452 deletions.
1 change: 1 addition & 0 deletions .JuliaFormatter.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
style = "sciml"
32 changes: 16 additions & 16 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,22 @@ using StatsPlots, Statistics # used in help
# https://juliadocs.github.io/Documenter.jl/stable/man/syntax/#@example-block
ENV["GKSwstype"] = "100"

DocMeta.setdocmeta!(DistributionFits, :DocTestSetup, :(using DistributionFits); recursive=true)
DocMeta.setdocmeta!(DistributionFits,
:DocTestSetup,
:(using DistributionFits);
recursive = true)

makedocs(;
modules=[DistributionFits],
authors="Thomas Wutzler <[email protected]> and contributors",
modules = [DistributionFits],
authors = "Thomas Wutzler <[email protected]> and contributors",
#repo="https://github.com/bgctw/DistributionFits.jl/blob/{commit}{path}#{line}",
repo = Remotes.GitHub("bgctw", "DistributionFits.jl"),
sitename="DistributionFits.jl",
format=Documenter.HTML(;
prettyurls=get(ENV, "CI", "false") == "true",
canonical="https://bgctw.github.io/DistributionFits.jl",
assets=String[],
),
pages=[
repo = Remotes.GitHub("bgctw", "DistributionFits.jl"),
sitename = "DistributionFits.jl",
format = Documenter.HTML(;
prettyurls = get(ENV, "CI", "false") == "true",
canonical = "https://bgctw.github.io/DistributionFits.jl",
assets = String[],),
pages = [
"Home" => "index.md",
"Parameter type" => "partype.md",
"Distributions" => [
Expand All @@ -31,10 +33,8 @@ makedocs(;
"Dependencies" => "set_optimize.md",
"API" => "api.md",
#"Details" => "z_autodocs.md",
],
)
],)

deploydocs(;
repo="github.com/bgctw/DistributionFits.jl",
devbranch="main",
)
repo = "github.com/bgctw/DistributionFits.jl",
devbranch = "main",)
8 changes: 4 additions & 4 deletions ext/DistributionFitsOptimExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ module DistributionFitsOptimExt
isdefined(Base, :get_extension) ? (using Optim) : (using ..Optim)
using DistributionFits: DistributionFits, optimize, AbstractDistributionFitOptimizer

struct OptimOptimizer <: AbstractDistributionFitOptimizer; end
struct OptimOptimizer <: AbstractDistributionFitOptimizer end

function DistributionFits.optimize(f, ::OptimOptimizer, lower, upper)
function DistributionFits.optimize(f, ::OptimOptimizer, lower, upper)
result = Optim.optimize(f, lower, upper)
(;minimizer = result.minimizer, converged = result.converged, result)
(; minimizer = result.minimizer, converged = result.converged, result)
end

function __init__()
Expand All @@ -16,4 +16,4 @@ function __init__()
DistributionFits.set_optimizer(OptimOptimizer())
end

end
end
29 changes: 14 additions & 15 deletions src/DistributionFits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ using StatsFuns: logit, logistic, normcdf
#using Infiltrator

if !isdefined(Base, :get_extension)
using Requires
using Requires
end

# for extension
Expand All @@ -17,16 +17,16 @@ import Distributions: mean, var, mode
import StatsAPI: fit
# Moments also extends getindex, mean, kurtorsis ....

export
# fitting distributions
AbstractMoments, Moments, n_moments, moments,
QuantilePoint,
fit_mean_quantile, fit_mode_quantile, fit_median_quantile,
@qp, @qp_ll, @qp_l, @qp_m, @qp_u, @qp_uu,
@qs_cf90, @qs_cf95,
qp, qp_ll, qp_l, qp_m, qp_u, qp_uu,
qs_cf90, qs_cf95,
fit_mean_relerror
export
# fitting distributions
AbstractMoments, Moments, n_moments, moments,
QuantilePoint,
fit_mean_quantile, fit_mode_quantile, fit_median_quantile,
@qp, @qp_ll, @qp_l, @qp_m, @qp_u, @qp_uu,
@qs_cf90, @qs_cf95,
qp, qp_ll, qp_l, qp_m, qp_u, qp_uu,
qs_cf90, qs_cf95,
fit_mean_relerror

# document but do not export - need to qualify by 'DistributionFits.'
# export
Expand All @@ -44,11 +44,10 @@ export AbstractDistributionFitOptimizer, optimize

include("optimizer.jl")


function __init__()
@static if !isdefined(Base, :get_extension)
@require Optim="429524aa-4258-5aef-a3af-852621145aeb" include("../ext/DistributionFitsOptimExt.jl")
end
@static if !isdefined(Base, :get_extension)
@require Optim="429524aa-4258-5aef-a3af-852621145aeb" include("../ext/DistributionFitsOptimExt.jl")
end
end

# fitting distributions to stats
Expand Down
160 changes: 96 additions & 64 deletions src/fitstats.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,40 @@ kurtosis(m) # throws error because its above 2nd moment
```
"""
abstract type AbstractMoments{N} end
n_moments(::Type{<:AbstractMoments{N}}) where N = N
n_moments(m::AbstractMoments{N}) where N = N
Distributions.mean(m::AbstractMoments) = n_moments(m) >= 1 ? m[1] :
n_moments(::Type{<:AbstractMoments{N}}) where {N} = N
n_moments(m::AbstractMoments{N}) where {N} = N
function Distributions.mean(m::AbstractMoments)
n_moments(m) >= 1 ? m[1] :
error("mean not recorded")
Distributions.var(m::AbstractMoments) = n_moments(m) >= 2 ? m[2] :
end
function Distributions.var(m::AbstractMoments)
n_moments(m) >= 2 ? m[2] :
error("variance not recorded")
Distributions.std(m::AbstractMoments) = n_moments(m) >= 2 ? sqrt(m[2]) :
end
function Distributions.std(m::AbstractMoments)
n_moments(m) >= 2 ? sqrt(m[2]) :
error("std not recorded")
Distributions.skewness(m::AbstractMoments) = n_moments(m) >= 3 ? m[3] :
end
function Distributions.skewness(m::AbstractMoments)
n_moments(m) >= 3 ? m[3] :
error("skewness not recorded")
Distributions.kurtosis(m::AbstractMoments) = n_moments(m) >= 4 ? m[4] :
end
function Distributions.kurtosis(m::AbstractMoments)
n_moments(m) >= 4 ? m[4] :
error("kurtosis not recorded")
end


struct Moments{N,T} <: AbstractMoments{N}
all::SVector{N,T}
struct Moments{N, T} <: AbstractMoments{N}
all::SVector{N, T}
end
Moments(x...) = Moments(SVector{length(x)}(promote(x...)))
Moments() = Moments(SA[])
Base.getindex(m::Moments, i) = n_moments(m) >= i ? m.all[i] :
function Base.getindex(m::Moments, i)
n_moments(m) >= i ? m.all[i] :
error("$(i)th moment not recorded.")
end
Base.convert(::Type{AbstractArray}, m::Moments) = m.all
Base.eltype(::Moments{N,T}) where {N,T} = T
Base.eltype(::Moments{N, T}) where {N, T} = T

"""
moments(D, ::Val{N} = Val(2))
Expand All @@ -67,15 +78,15 @@ moments(LogNormal(), Val(4)) # first four moments
moments(Normal()) # mean and variance
```
"""
function moments(d::Distribution, ::Val{N} = Val(2)) where N
function moments(d::Distribution, ::Val{N} = Val(2)) where {N}
N isa Integer || error("N must be a positive Integer")
N > 4 && error("Getting moments above 4 not yet implemented for " *
"distribution $(typeof(d)).")
N == 4 && return(Moments(mean(d), var(d), skewness(d), kurtosis(d)))
N == 3 && return(Moments(mean(d), var(d), skewness(d)))
N == 2 && return(Moments(mean(d), var(d)))
N == 1 && return(Moments(mean(d)))
N == 0 && return(Moments())
N > 4 && error("Getting moments above 4 not yet implemented for " *
"distribution $(typeof(d)).")
N == 4 && return (Moments(mean(d), var(d), skewness(d), kurtosis(d)))
N == 3 && return (Moments(mean(d), var(d), skewness(d)))
N == 2 && return (Moments(mean(d), var(d)))
N == 1 && return (Moments(mean(d)))
N == 0 && return (Moments())
error("N must be a positive Integer.")
end

Expand Down Expand Up @@ -113,9 +124,9 @@ plot(d, label = "lognormal", ylab="probability density")
plot!(Normal(3,1.2), label = "normal")
```
"""
fit(::Type{D}, m::AbstractMoments) where {D<:Distribution} =
function fit(::Type{D}, m::AbstractMoments) where {D <: Distribution}
error("fitting to moments not implemented for distribution of type $D")

end

"""
QuantilePoint
Expand Down Expand Up @@ -143,53 +154,68 @@ There are macros/functions for some commonly used sets of QuantilePoints: 90% an
- `@qs_cf90(q0_05,q0_95)`
- `@qs_cf95(q0_025,q0_975)` -> `Set([QuantilePoint(q0_025,0.025),QuantilePoint(q0_975,0.975)]))`
"""
struct QuantilePoint{TQ,TP}
struct QuantilePoint{TQ, TP}
q::TQ
p::TP
QuantilePoint{TQ,TP}(q,p) where {TQ,TP} = 0 < p < 1 ? new(q,p) :
function QuantilePoint{TQ, TP}(q, p) where {TQ, TP}
0 < p < 1 ? new(q, p) :
error("p must be in (0,1)")
end
end
QuantilePoint(q,p) = QuantilePoint{typeof(q),typeof(p)}(q,p)
QuantilePoint(q, p) = QuantilePoint{typeof(q), typeof(p)}(q, p)

QuantilePoint(qp::QuantilePoint; q = qp.q, p = qp.p) = QuantilePoint(q,p)
QuantilePoint(qp::QuantilePoint; q = qp.q, p = qp.p) = QuantilePoint(q, p)
Base.show(io::IO, qp::QuantilePoint) = print(io, "QuantilePoint($(qp.q),$(qp.p))")
function Base.isless(x::QuantilePoint,y::QuantilePoint)
function Base.isless(x::QuantilePoint, y::QuantilePoint)
is_equal_q = (x.q == y.q)
((x.p == y.p) && !is_equal_q) && error("incompatible: $x,$y")
isless = (x.q < y.q)
# for different p, q needs to be different
(isless && (x.p > y.p)) && error("incompatible: $(x),$(y)")
(!isless && !is_equal_q && (x.p < y.p)) && error("incompatible: $x,$y")
return(isless)
(!isless && !is_equal_q && (x.p < y.p)) && error("incompatible: $x,$y")
return (isless)
end

macro qp(q,p) :(QuantilePoint($(esc(q)), $(esc(p)))) end
macro qp_ll(q0_025) :(QuantilePoint($(esc(q0_025)),0.025)) end
macro qp_l(q0_05) :(QuantilePoint($(esc(q0_05)),0.05)) end
macro qp_m(median) :(QuantilePoint($(esc(median)),0.5)) end
macro qp_u(q0_95) :(QuantilePoint($(esc(q0_95)),0.95)) end
macro qp_uu(q0_975) :(QuantilePoint($(esc(q0_975)),0.975)) end
macro qp(q, p)
:(QuantilePoint($(esc(q)), $(esc(p))))
end
macro qp_ll(q0_025)
:(QuantilePoint($(esc(q0_025)), 0.025))
end
macro qp_l(q0_05)
:(QuantilePoint($(esc(q0_05)), 0.05))
end
macro qp_m(median)
:(QuantilePoint($(esc(median)), 0.5))
end
macro qp_u(q0_95)
:(QuantilePoint($(esc(q0_95)), 0.95))
end
macro qp_uu(q0_975)
:(QuantilePoint($(esc(q0_975)), 0.975))
end

macro qs_cf90(q0_05,q0_95)
:(Set([QuantilePoint($(esc(q0_05)),0.05),QuantilePoint($(esc(q0_95)),0.95)])) end
macro qs_cf95(q0_025,q0_975)
:(Set([QuantilePoint($(esc(q0_025)),0.025),QuantilePoint($(esc(q0_975)),0.975)])) end
macro qs_cf90(q0_05, q0_95)
:(Set([QuantilePoint($(esc(q0_05)), 0.05), QuantilePoint($(esc(q0_95)), 0.95)]))
end
macro qs_cf95(q0_025, q0_975)
:(Set([QuantilePoint($(esc(q0_025)), 0.025), QuantilePoint($(esc(q0_975)), 0.975)]))
end

# The non-macro versions return percentile whose type matches that of the argument
qp_ll(q0_025::T) where T = QuantilePoint(q0_025, T(0.025))
qp_l(q0_05::T) where T = QuantilePoint(q0_05, T(0.05))
qp_m(median::T) where T = QuantilePoint(median, T(0.5))
qp_u(q0_95::T) where T = QuantilePoint(q0_95, T(0.95))
qp_uu(q0_975::T) where T = QuantilePoint(q0_975, T(0.975))

function qs_cf90(q0_05::T,q0_95::T) where T
Set([QuantilePoint(q0_05,T(0.05)),QuantilePoint(q0_95,T(0.95))])
qp_ll(q0_025::T) where {T} = QuantilePoint(q0_025, T(0.025))
qp_l(q0_05::T) where {T} = QuantilePoint(q0_05, T(0.05))
qp_m(median::T) where {T} = QuantilePoint(median, T(0.5))
qp_u(q0_95::T) where {T} = QuantilePoint(q0_95, T(0.95))
qp_uu(q0_975::T) where {T} = QuantilePoint(q0_975, T(0.975))

function qs_cf90(q0_05::T, q0_95::T) where {T}
Set([QuantilePoint(q0_05, T(0.05)), QuantilePoint(q0_95, T(0.95))])
end
function qs_cf95(q0_025::T,q0_975::T) where T
Set([QuantilePoint(q0_025,T(0.025)),QuantilePoint(q0_975,T(0.975))])
function qs_cf95(q0_025::T, q0_975::T) where {T}
Set([QuantilePoint(q0_025, T(0.025)), QuantilePoint(q0_975, T(0.975))])
end


"""
fit(D, lower::QuantilePoint, upper::QuantilePoint)
Expand All @@ -208,12 +234,12 @@ quantile.(d, [0.5, 0.975]) ≈ [3,5]
true
```
"""
function fit(::Type{D}, lower::QuantilePoint, upper::QuantilePoint) where D<:Distribution
function fit(::Type{D},
lower::QuantilePoint,
upper::QuantilePoint) where {D <: Distribution}
error("fitting to two quantile points not implemented for distribution of type $D")
end



"""
fit(D, val, qp, ::Val{stats} = Val(:mean))
Expand All @@ -240,25 +266,31 @@ d = fit(LogNormal, 5.0, @qp_uu(14), Val(:mode));
(true, true)
```
"""
function fit(::Type{D}, val, qp::QuantilePoint, ::Val{stats} = Val(:mean)) where {D<:Distribution, stats}
stats == :mean && return(fit_mean_quantile(D, val, qp))
stats == :mode && return(fit_mode_quantile(D, val, qp))
stats == :median && return(fit_median_quantile(D, val, qp))
function fit(::Type{D},
val,
qp::QuantilePoint,
::Val{stats} = Val(:mean)) where {D <: Distribution, stats}
stats == :mean && return (fit_mean_quantile(D, val, qp))
stats == :mode && return (fit_mode_quantile(D, val, qp))
stats == :median && return (fit_median_quantile(D, val, qp))
error("unknown stats: $stats")
end,
function fit_median_quantile(::Type{D}, median, qp::QuantilePoint) where {D <: Distribution}
return(fit(D, @qp_m(median), qp))
function fit_median_quantile(::Type{D},
median,
qp::QuantilePoint) where {D <: Distribution}
return (fit(D, @qp_m(median), qp))
end,
function fit_mean_quantile(::Type{D}, mean::Real, qp::QuantilePoint) where D<:Distribution
function fit_mean_quantile(::Type{D},
mean::Real,
qp::QuantilePoint) where {D <: Distribution}
error("fit_mean_quantile not yet implemented for Distribution of type: $D")
end,
function fit_mode_quantile(::Type{D}, mode::Real, qp::QuantilePoint) where D<:Distribution
function fit_mode_quantile(::Type{D},
mode::Real,
qp::QuantilePoint) where {D <: Distribution}
error("fit_mode_quantile not yet implemented for Distribution of type: $D")
end

# function fit_mean_quantile(d::Type{D}, mean::Real, qp::QuantilePoint) where D<:Distribution
# error("fit_mean_quantile not yet implemented for Distribution of type: $D")
# end



10 changes: 5 additions & 5 deletions src/optimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ Developers implementing usage of a different specific optimizer see code in
ext/DistributionFitsOptimExt.
"""
abstract type AbstractDistributionFitOptimizer end
struct NotSetOptimizer <: AbstractDistributionFitOptimizer; end
struct NotSetOptimizer <: AbstractDistributionFitOptimizer end

# see to ext/DistributionFitsOptimExt.jl

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

function optimize(f, ::NotSetOptimizer, lower, upper)
error("Optimizer not set yet. Either invoke 'using Optim' " *
"or 'DistributionFits.set_optimizer(...)'.")
end

df_optimizer = NotSetOptimizer();
optimize(f, lower, upper) = optimize(f, df_optimizer, lower, upper)
set_optimizer(opt::AbstractDistributionFitOptimizer) = (global df_optimizer = opt)

Loading

0 comments on commit db76e41

Please sign in to comment.