Skip to content
4 changes: 4 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
DensityInterface = "b429d917-457f-4dbc-8f4c-0cc954292b1d"
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
LogExpFunctions = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
IrrationalConstants = "92d709cd-6900-40b7-9082-c6be49f344b6"
PDMats = "90014a1f-27ba-587c-ab20-58faa44d9150"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
Expand Down Expand Up @@ -43,6 +45,8 @@ FiniteDifferences = "0.12"
ForwardDiff = "0.10, 1"
JSON = "0.21"
LinearAlgebra = "<0.0.1, 1"
LogExpFunctions = "0.3.29"
IrrationalConstants = "0.2.6"
OffsetArrays = "1"
PDMats = "0.11.35"
Printf = "<0.0.1, 1"
Expand Down
3 changes: 2 additions & 1 deletion src/Distributions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ import StatsBase: kurtosis, skewness, entropy, mode, modes,
import PDMats: dim, PDMat, invquad

using SpecialFunctions
import LogExpFunctions: logabssinh, log1psq
using Base.MathConstants: eulergamma

import IrrationalConstants: invπ
import AliasTables

export
Expand Down
63 changes: 46 additions & 17 deletions src/univariate/continuous/cosine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,37 +59,66 @@ kurtosis(d::Cosine{T}) where {T<:Real} = 6*(90-T(π)^4) / (5*(T(π)^2-6)^2)

#### Evaluation

function pdf(d::Cosine{T}, x::Real) where T<:Real
function pdf(d::Cosine{T}, x::S) where {T<:Real, S<:Real}
if insupport(d, x)
z = (x - d.μ) / d.σ
return (1 + cospi(z)) / (2d.σ)
else
return zero(T)
return zero(promote_type(T, S))
end
end

logpdf(d::Cosine, x::Real) = log(pdf(d, x))

function cdf(d::Cosine{T}, x::Real) where T<:Real
if x < d.μ - d.σ
return zero(T)
end
if x > d.μ + d.σ
return one(T)
function logpdf(d::Cosine{T}, x::S) where {T<:Real, S<:Real}
if insupport(d, x)
z = (x - d.μ) / d.σ
return log1p(cospi(z)) - log(2d.σ)
else
return typemin(promote_type(T, S))
end
end

function cdf(d::Cosine{T}, x::S) where {T<:Real, S<:Real}
W = promote_type(T, S)

x < d.μ - d.σ && return zero(W)
x > d.μ + d.σ && return one(W)

z = (x - d.μ) / d.σ
(1 + z + sinpi(z) * invπ) / 2
end

function ccdf(d::Cosine{T}, x::Real) where T<:Real
if x < d.μ - d.σ
return one(T)
end
if x > d.μ + d.σ
return zero(T)
end
function ccdf(d::Cosine{T}, x::S) where {T<:Real, S<:Real}
W = promote_type(T, S)

x < d.μ - d.σ && return one(W)
x > d.μ + d.σ && return zero(W)

nz = (d.μ - x) / d.σ
(1 + nz + sinpi(nz) * invπ) / 2
end

quantile(d::Cosine, p::Real) = quantile_bisect(d, p)

function mgf(d::Cosine, t::Real)
σt, μt = d.σ * t, d.μ * t
z = iszero(σt) ? one(float(σt)) : sinh(σt)/σt
return exp(μt) * (z / (1 + (invπ * σt)^2))
end

function cgf(d::Cosine, t::Real)
σt, μt = d.σ * t, d.μ * t
z = iszero(σt) ? zero(float(σt)) : logabssinh(σt) - log(σt)
return μt + z - log1psq(invπ * σt)
end

function cf(d::Cosine, t::Real)
σt, μt = d.σ * t, d.μ * t
abs(σt) ≈ π && return cis(μt) / 2
z = iszero(σt) ? one(float(σt)) : sin(σt)/σt
return cis(μt) * z / (1 - (invπ * σt)^2)
end

#### Affine transformations

Base.:+(d::Cosine, a::Real) = Cosine(d.μ + a, d.σ)
Base.:*(c::Real, d::Cosine) = Cosine(c * d.μ, abs(c) * d.σ)
13 changes: 13 additions & 0 deletions test/univariate/continuous/cosine.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@testset "Cosine" begin
@testset "mgf, cgf, cf" begin
@test cf(Cosine(1, 1), 1) ≈ cis(1) * sin(1)/(1 - π^-2)
@test mgf(Cosine(-1, 2), -1) ≈ exp(1) * sinh(-2) / (-2*(1 + 4π^-2))
@test cgf(Cosine(-1, 2), 2) ≈ -2 + log(sinh(4)) - log(4) - log(1 + 16π^-2)
end

@testset "affine transformations" begin
@test -Cosine(1, 1) == Cosine(-1, 1)
@test 3Cosine(1, 2) == Cosine(3, 6)
@test Cosine(0, 2) + 42 == Cosine(42, 2)
end
end
Loading