Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

format according to SciMLStyle #27

Merged
merged 1 commit into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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