Skip to content

Glm additions#17

Merged
rsenne merged 23 commits into
mainfrom
glm_additions
May 18, 2026
Merged

Glm additions#17
rsenne merged 23 commits into
mainfrom
glm_additions

Conversation

@rsenne
Copy link
Copy Markdown
Owner

@rsenne rsenne commented May 11, 2026

This pull request significantly expands and improves the documentation for EmissionModels.jl, adds new emission models and priors, and introduces several usability and performance enhancements to the codebase. The main changes include a comprehensive rewrite of the README.md, the addition of detailed documentation pages for distributions, GLM emissions, priors, and custom model interfaces, as well as new exports and improved internal handling for multivariate t-distributions.

Documentation improvements:

  • Major rewrite and expansion of README.md to include a clear package overview, quick start, model summaries, installation, and contribution guidelines. [1] [2]
  • Added new documentation pages: distributions, GLM emissions, priors, and custom emission models, with detailed usage examples and interface requirements. [1] [2] [3] [4] [5] [6]

Feature additions:

  • Exported new emission models and priors, including GaussianGLM, BernoulliGLM, PoissonGLM, multivariate GLMs, and prior types such as RidgePrior, with their associated penalty and gradient functions. [1] [2]
  • Added support for GLM emission models and regularization priors in the main module.

Multivariate t-distribution improvements:

  • Enhanced MultivariateT and MultivariateTDiag structs to include internal scratch buffers for more efficient and allocation-free fit! and density computations. [1] [2] [3] [4]
  • Improved logdensityof implementations for both full and diagonal multivariate t-distributions to reduce allocations and improve thread safety. [1] [2]

General usability:

  • Updated documentation and code to clarify and enforce the emission model interface required by HiddenMarkovModels.jl, including sampling, density evaluation, and parameter fitting.

References:

rsenne and others added 7 commits January 1, 2026 12:54
Introduce an AbstractPrior hierarchy (NoPrior, RidgePrior) with neglogprior, neglogprior_grad!, and neglogprior_hess! helpers. Add BernoulliGLM and PoissonGLM types with DensityInterface, Random.rand, and StatsAPI.fit! implementations that minimize the weighted negative log-posterior via Optim (Newton) and compose with priors. Extend GaussianGLM to carry a prior and apply the prior Hessian in weighted least squares (Ridge support). Export new symbols and pull in extra LogExpFunctions helpers (log1pexp, logistic). Add comprehensive tests for priors, BernoulliGLM, and PoissonGLM and include the new test file in runtests.jl.
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit

JuliaFormatter

[JuliaFormatter] reported by reviewdog 🐶

Σ_chol::Cholesky{T, Matrix{T}}


[JuliaFormatter] reported by reviewdog 🐶

B::AbstractMatrix{T},
Σ::AbstractMatrix{T},
prior::P,
) where {T<:Real, P<:AbstractPrior}


[JuliaFormatter] reported by reviewdog 🐶

size(Σ) == (k, k) ||
throw(DimensionMismatch("Σ must be $(k)×$(k) for B with $(k) columns, got $(size(Σ))"))


[JuliaFormatter] reported by reviewdog 🐶

return MvGaussianGLM{T, P}(
Matrix{T}(B), Matrix{T}(Σ), prior,
Σ_chol, logdet(Σ_chol), p, k,


[JuliaFormatter] reported by reviewdog 🐶

MvGaussianGLM(B::AbstractMatrix{T}, Σ::AbstractMatrix{T}) where {T<:Real} =
MvGaussianGLM(B, Σ, NoPrior())


[JuliaFormatter] reported by reviewdog 🐶

glm::MvGaussianGLM,
y::AbstractVector;
control_seq::AbstractVector{<:Real},


[JuliaFormatter] reported by reviewdog 🐶

length(control_seq) == glm.in_dim ||
throw(DimensionMismatch(
"control_seq length $(length(control_seq)) ≠ in_dim $(glm.in_dim)",
))


[JuliaFormatter] reported by reviewdog 🐶

rng::AbstractRNG,
glm::MvGaussianGLM{T};
control_seq::AbstractVector{<:Real},


[JuliaFormatter] reported by reviewdog 🐶

length(control_seq) == glm.in_dim ||
throw(DimensionMismatch(
"control_seq length $(length(control_seq)) ≠ in_dim $(glm.in_dim)",
))


[JuliaFormatter] reported by reviewdog 🐶

length(weight_seq) == n ||
throw(DimensionMismatch("weight_seq length $(length(weight_seq)) ≠ control_seq rows $n"))


[JuliaFormatter] reported by reviewdog 🐶

throw(DimensionMismatch(
"obs_seq[$i] length $(length(obs_i)) ≠ out_dim $k",
))
w = T(weight_seq[i])


[JuliaFormatter] reported by reviewdog 🐶

xa = x_i[a]


[JuliaFormatter] reported by reviewdog 🐶

w = T(weight_seq[i])


[JuliaFormatter] reported by reviewdog 🐶

mutable struct MvBernoulliGLM{T<:Real, P<:AbstractPrior} <: AbstractGLM


[JuliaFormatter] reported by reviewdog 🐶

function MvBernoulliGLM(B::AbstractMatrix{T}, prior::P) where {T<:Real, P<:AbstractPrior}


[JuliaFormatter] reported by reviewdog 🐶

return MvBernoulliGLM{T, P}(Matrix{T}(B), prior, p, k)


[JuliaFormatter] reported by reviewdog 🐶

MvBernoulliGLM(B::AbstractMatrix, prior::AbstractPrior) =
MvBernoulliGLM(float.(B), prior)


[JuliaFormatter] reported by reviewdog 🐶

glm::MvBernoulliGLM,
y::AbstractVector;
control_seq::AbstractVector{<:Real},


[JuliaFormatter] reported by reviewdog 🐶

length(control_seq) == glm.in_dim ||
throw(DimensionMismatch(
"control_seq length $(length(control_seq)) ≠ in_dim $(glm.in_dim)",
))


[JuliaFormatter] reported by reviewdog 🐶

for j in 1:glm.out_dim


[JuliaFormatter] reported by reviewdog 🐶

for r in 1:glm.in_dim


[JuliaFormatter] reported by reviewdog 🐶

rng::AbstractRNG,
glm::MvBernoulliGLM;
control_seq::AbstractVector{<:Real},


[JuliaFormatter] reported by reviewdog 🐶

length(control_seq) == glm.in_dim ||
throw(DimensionMismatch(
"control_seq length $(length(control_seq)) ≠ in_dim $(glm.in_dim)",
))


[JuliaFormatter] reported by reviewdog 🐶

for j in 1:glm.out_dim


[JuliaFormatter] reported by reviewdog 🐶

for r in 1:glm.in_dim


[JuliaFormatter] reported by reviewdog 🐶

length(weight_seq) == n ||
throw(DimensionMismatch("weight_seq length $(length(weight_seq)) ≠ control_seq rows $n"))


[JuliaFormatter] reported by reviewdog 🐶

length(obs_seq[i]) == k ||
throw(DimensionMismatch(
"obs_seq[$i] length $(length(obs_seq[i])) ≠ out_dim $k",
))


[JuliaFormatter] reported by reviewdog 🐶

g = Vector{T}(undef, p)
H = Matrix{T}(undef, p, p)
Δ = Vector{T}(undef, p)


[JuliaFormatter] reported by reviewdog 🐶

β_buf, g, H, Δ, _bernoulli_loss, _bernoulli_gh!,
yview, weight_seq, control_seq, glm.prior;
max_iter=max_iter, gtol=gtol, max_backtrack=max_backtrack,


[JuliaFormatter] reported by reviewdog 🐶

mutable struct MvPoissonGLM{T<:Real, P<:AbstractPrior} <: AbstractGLM


[JuliaFormatter] reported by reviewdog 🐶

function MvPoissonGLM(B::AbstractMatrix{T}, prior::P) where {T<:Real, P<:AbstractPrior}


[JuliaFormatter] reported by reviewdog 🐶

return MvPoissonGLM{T, P}(Matrix{T}(B), prior, p, k)


[JuliaFormatter] reported by reviewdog 🐶

MvPoissonGLM(B::AbstractMatrix, prior::AbstractPrior) =
MvPoissonGLM(float.(B), prior)


[JuliaFormatter] reported by reviewdog 🐶

glm::MvPoissonGLM,
y::AbstractVector;
control_seq::AbstractVector{<:Real},


[JuliaFormatter] reported by reviewdog 🐶

length(control_seq) == glm.in_dim ||
throw(DimensionMismatch(
"control_seq length $(length(control_seq)) ≠ in_dim $(glm.in_dim)",
))


[JuliaFormatter] reported by reviewdog 🐶

for j in 1:glm.out_dim


[JuliaFormatter] reported by reviewdog 🐶

for r in 1:glm.in_dim


[JuliaFormatter] reported by reviewdog 🐶

rng::AbstractRNG,
glm::MvPoissonGLM;
control_seq::AbstractVector{<:Real},


[JuliaFormatter] reported by reviewdog 🐶

length(control_seq) == glm.in_dim ||
throw(DimensionMismatch(
"control_seq length $(length(control_seq)) ≠ in_dim $(glm.in_dim)",
))


[JuliaFormatter] reported by reviewdog 🐶

for j in 1:glm.out_dim


[JuliaFormatter] reported by reviewdog 🐶

for r in 1:glm.in_dim


[JuliaFormatter] reported by reviewdog 🐶

length(weight_seq) == n ||
throw(DimensionMismatch("weight_seq length $(length(weight_seq)) ≠ control_seq rows $n"))


[JuliaFormatter] reported by reviewdog 🐶

length(obs_seq[i]) == k ||
throw(DimensionMismatch(
"obs_seq[$i] length $(length(obs_seq[i])) ≠ out_dim $k",
))


[JuliaFormatter] reported by reviewdog 🐶

g = Vector{T}(undef, p)
H = Matrix{T}(undef, p, p)
Δ = Vector{T}(undef, p)


[JuliaFormatter] reported by reviewdog 🐶

β_buf, g, H, Δ, _poisson_loss, _poisson_gh!,
yview, weight_seq, control_seq, glm.prior;
max_iter=max_iter, gtol=gtol, max_backtrack=max_backtrack,


[JuliaFormatter] reported by reviewdog 🐶

for j in 1:d, k in 1:j-1


[JuliaFormatter] reported by reviewdog 🐶

bench_logd(d, y, x, n) = (s = 0.0; for _ in 1:n; s += logdensityof(d, y; control_seq=x); end; s)
bench_logd_unctrl(d, y, n) = (s = 0.0; for _ in 1:n; s += logdensityof(d, y); end; s)
bench_rand_scalar(rng, d, x, n) = (s = 0.0; for _ in 1:n; s += rand(rng, d; control_seq=x); end; s)
bench_rand_int(rng, d, x, n) = (s = 0; for _ in 1:n; s += rand(rng, d; control_seq=x); end; s)
bench_rand!_v(rng, d, out, x, n) = (s = 0.0; for _ in 1:n; rand!(rng, d, out; control_seq=x); s += out[1]; end; s)
bench_rand!_i(rng, d, out, x, n) = (s = 0; for _ in 1:n; rand!(rng, d, out; control_seq=x); s += out[1]; end; s)
bench_rand_unctrl_scalar(rng, d, n) = (s = 0.0; for _ in 1:n; s += rand(rng, d); end; s)
bench_rand_unctrl_vec(rng, d, n) = (s = 0.0; for _ in 1:n; s += rand(rng, d)[1]; end; s)


[JuliaFormatter] reported by reviewdog 🐶

g = GaussianGLM([0.5, -1.0], 1.0)
b = BernoulliGLM([0.5, -1.0])
p = PoissonGLM([0.5, -1.0])


[JuliaFormatter] reported by reviewdog 🐶

yv = [0.1, 0.2]; yi = [0, 1]


[JuliaFormatter] reported by reviewdog 🐶

bench_logd(g, 0.5, x, 1); bench_logd(b, 1, x, 1); bench_logd(p, 2, x, 1)
bench_logd(mg, yv, x, 1); bench_logd(mb, yi, x, 1); bench_logd(mp, yi, x, 1)


[JuliaFormatter] reported by reviewdog 🐶

@test (@allocated bench_logd(g, 0.5, x, REPS)) == 0
@test (@allocated bench_logd(b, 1, x, REPS)) == 0
@test (@allocated bench_logd(p, 2, x, REPS)) == 0
@test (@allocated bench_logd(mb, yi, x, REPS)) == 0
@test (@allocated bench_logd(mp, yi, x, REPS)) == 0


[JuliaFormatter] reported by reviewdog 🐶

g = GaussianGLM([0.5, -1.0], 1.0)
b = BernoulliGLM([0.5, -1.0])
p = PoissonGLM([0.5, -1.0])


[JuliaFormatter] reported by reviewdog 🐶

gg = GaussianGLM([0.0, 0.0], 1.0); fit!(gg, yg, w; control_seq=X)


[JuliaFormatter] reported by reviewdog 🐶

gb = BernoulliGLM(zeros(2)); fit!(gb, yb, w; control_seq=X)


[JuliaFormatter] reported by reviewdog 🐶

gp = PoissonGLM(zeros(2)); fit!(gp, yp, w; control_seq=X)


[JuliaFormatter] reported by reviewdog 🐶

gmb = MvBernoulliGLM(zeros(2, 2)); fit!(gmb, ymb, w; control_seq=X)


[JuliaFormatter] reported by reviewdog 🐶

gmp = MvPoissonGLM(zeros(2, 2)); fit!(gmp, ymp, w; control_seq=X)


[JuliaFormatter] reported by reviewdog 🐶

bench_logd_unctrl(zip, 0, 1); bench_logd_unctrl(zip, 5, 1)


[JuliaFormatter] reported by reviewdog 🐶

zip2 = PoissonZeroInflated(1.0, 0.1); fit!(zip2, y, w)


[JuliaFormatter] reported by reviewdog 🐶

function _synthetic_gaussian_glm(rng, n::Int, p::Int; β::Vector{Float64}, σ2::Float64, weights=:uniform)


[JuliaFormatter] reported by reviewdog 🐶

X = hcat(ones(n), randn(rng, n, p-1)) # intercept + random features


[JuliaFormatter] reported by reviewdog 🐶

w = weights === :uniform ? ones(n) :
weights === :random ? (rand(rng, n) .+ 0.5) :


[JuliaFormatter] reported by reviewdog 🐶


[JuliaFormatter] reported by reviewdog 🐶

@testset "Constructor" begin
glm = GaussianGLM([0.5, -1.0], 1.0)
@test glm.β == [0.5, -1.0]
@test glm.σ2 == 1.0
glm2 = GaussianGLM([1, 2], 3)
@test glm2.β == [1, 2]
@test glm2.σ2 == 3
end


[JuliaFormatter] reported by reviewdog 🐶

@testset "DensityInterface" begin
glm = GaussianGLM([0.5, -1.0], 1.0)


[JuliaFormatter] reported by reviewdog 🐶

# Trait
@test DensityKind(glm) == HasDensity()


[JuliaFormatter] reported by reviewdog 🐶

X = [1.0 2.0; 1.0 3.0; 1.0 4.0]
μ = X * glm.β
y = rand.(Ref(rng), Normal.(μ, sqrt(glm.σ2)))


[JuliaFormatter] reported by reviewdog 🐶

# logdensityof matches closed form
for i in eachindex(y)
x_i = vec(X[i, :]) # ensure Vector
logp = logdensityof(glm, y[i]; control_seq=x_i)
@test isfinite(logp)


[JuliaFormatter] reported by reviewdog 🐶

expected = _expected_logpdf(y[i], dot(glm.β, x_i), glm.σ2)
@test logp expected rtol=1e-12 atol=0.0
end


[JuliaFormatter] reported by reviewdog 🐶

# Higher density near the mean than far away
x0 = vec(X[1, :])
y_at_mean = dot(glm.β, x0)
y_far = y_at_mean + 10.0
@test logdensityof(glm, y_at_mean; control_seq=x0) > logdensityof(glm, y_far; control_seq=x0)


[JuliaFormatter] reported by reviewdog 🐶

@testset "Random sampling" begin
glm = GaussianGLM([0.5, -1.0], 2.0) # variance 2.0
x = [1.0, 3.0]
n = 10_000
samples = [rand(rng, glm; control_seq=x) for _ in 1:n]


[JuliaFormatter] reported by reviewdog 🐶

@test all(s -> s isa Real, samples)


[JuliaFormatter] reported by reviewdog 🐶

# Empirical mean should be close to dot(β,x)
μ = dot(glm.β, x)
m = mean(samples)
@test m μ atol=0.15


[JuliaFormatter] reported by reviewdog 🐶

# Empirical variance should be close to σ2
v = var(samples)
@test v glm.σ2 atol=0.25
end


[JuliaFormatter] reported by reviewdog 🐶

@testset "fit! with uniform weights" begin
β_true = [0.3, -1.2] # p=2
σ2_true = 0.7
X, y, w = _synthetic_gaussian_glm(rng, 2000, 2; β=β_true, σ2=σ2_true, weights=:uniform)


[JuliaFormatter] reported by reviewdog 🐶

glm = GaussianGLM([0.0, 0.0], 1.0)
fit!(glm, y, w; control_seq=X)


[JuliaFormatter] reported by reviewdog 🐶

# Coefficients should be close with enough data
@test glm.β β_true atol=0.08
@test glm.σ2 σ2_true atol=0.10


[JuliaFormatter] reported by reviewdog 🐶

@test all(isfinite, glm.β)
@test isfinite(glm.σ2)
@test glm.σ2 > 0
end


[JuliaFormatter] reported by reviewdog 🐶

@testset "fit! with weighted observations" begin
β_true = [1.0, 0.6]
σ2_true = 1.5
X, y, w = _synthetic_gaussian_glm(rng, 2500, 2; β=β_true, σ2=σ2_true, weights=:random)


[JuliaFormatter] reported by reviewdog 🐶

glm = GaussianGLM([0.0, 0.0], 1.0)
fit!(glm, y, w; control_seq=X)


[JuliaFormatter] reported by reviewdog 🐶

@test glm.β β_true atol=0.10
@test glm.σ2 σ2_true atol=0.15
end


[JuliaFormatter] reported by reviewdog 🐶

@testset "Constructor with prior" begin
glm = GaussianGLM([0.0, 0.0], 1.0)
@test glm.prior isa NoPrior


[JuliaFormatter] reported by reviewdog 🐶

glm2 = GaussianGLM([0.0, 0.0], 1.0, RidgePrior(2.0))
@test glm2.prior isa RidgePrior
@test glm2.prior.λ == 2.0
end


[JuliaFormatter] reported by reviewdog 🐶

@testset "fit! with RidgePrior shrinks toward zero" begin
β_true = [3.0, -3.0]
σ2_true = 1.0
X, y, w = _synthetic_gaussian_glm(rng, 300, 2; β=β_true, σ2=σ2_true)


[JuliaFormatter] reported by reviewdog 🐶

glm_noprior = GaussianGLM([0.0, 0.0], 1.0)
fit!(glm_noprior, y, w; control_seq=X)


[JuliaFormatter] reported by reviewdog 🐶

glm_ridge = GaussianGLM([0.0, 0.0], 1.0, RidgePrior(10.0))
fit!(glm_ridge, y, w; control_seq=X)


[JuliaFormatter] reported by reviewdog 🐶

@test norm(glm_ridge.β) < norm(glm_noprior.β)
@test all(isfinite, glm_ridge.β)
end


[JuliaFormatter] reported by reviewdog 🐶


[JuliaFormatter] reported by reviewdog 🐶

function _synthetic_mvgaussian_glm(rng, n::Int, p::Int, k::Int;
B::Matrix{Float64}, Σ::Matrix{Float64},
weights=:uniform)


[JuliaFormatter] reported by reviewdog 🐶

X = hcat(ones(n), randn(rng, n, p-1))


[JuliaFormatter] reported by reviewdog 🐶

w = weights === :uniform ? ones(n) :
weights === :random ? (rand(rng, n) .+ 0.5) :


[JuliaFormatter] reported by reviewdog 🐶

return X, obs_seq, w


[JuliaFormatter] reported by reviewdog 🐶

@test_throws DimensionMismatch MvGaussianGLM(B, [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0])


[JuliaFormatter] reported by reviewdog 🐶

@test logdensityof(glm, y; control_seq=x) expected rtol=1e-10


[JuliaFormatter] reported by reviewdog 🐶

logdensityof(glm, μ .+ 10.0; control_seq=x)


[JuliaFormatter] reported by reviewdog 🐶

@test m μ_true atol=0.05


[JuliaFormatter] reported by reviewdog 🐶

@test S Σ atol=0.1


[JuliaFormatter] reported by reviewdog 🐶

X, obs_seq, w = _synthetic_mvgaussian_glm(rng, 4000, 3, 2;
B=B_true, Σ=Σ_true)


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B B_true atol=0.08
@test glm.Σ Σ_true atol=0.10


[JuliaFormatter] reported by reviewdog 🐶

X, obs_seq, w = _synthetic_mvgaussian_glm(rng, 3000, 2, 2;
B=B_true, Σ=Σ_true,
weights=:random)


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B B_true atol=0.10
@test glm.Σ Σ_true atol=0.12


[JuliaFormatter] reported by reviewdog 🐶

X, obs_seq, w = _synthetic_mvgaussian_glm(rng, 200, 2, 2;
B=B_true, Σ=Σ_true)


[JuliaFormatter] reported by reviewdog 🐶


[JuliaFormatter] reported by reviewdog 🐶


[JuliaFormatter] reported by reviewdog 🐶

@test logdensityof(glm, 1; control_seq=x) log(μ) rtol=1e-10
@test logdensityof(glm, 0; control_seq=x) log(1 - μ) rtol=1e-10


[JuliaFormatter] reported by reviewdog 🐶

@test mean(samples) _sigmoid(dot(glm.β, x)) atol=0.05


[JuliaFormatter] reported by reviewdog 🐶

@test glm.β β_true atol=0.15


[JuliaFormatter] reported by reviewdog 🐶

@test glm.β β_true atol=0.20


[JuliaFormatter] reported by reviewdog 🐶

@test_throws DimensionMismatch fit!(glm, ones(Int, 5), ones(5); control_seq=ones(5, 3))


[JuliaFormatter] reported by reviewdog 🐶


[JuliaFormatter] reported by reviewdog 🐶

@test logdensityof(glm, k; control_seq=x) logpdf(Poisson(μ), k) rtol=1e-10


[JuliaFormatter] reported by reviewdog 🐶

@test mean(samples) exp(glm.β[1]) atol=0.2


[JuliaFormatter] reported by reviewdog 🐶

@test glm.β β_true atol=0.15


[JuliaFormatter] reported by reviewdog 🐶

@test glm.β β_true atol=0.15


[JuliaFormatter] reported by reviewdog 🐶

@test_throws DimensionMismatch fit!(glm, ones(Int, 5), ones(5); control_seq=ones(5, 3))


[JuliaFormatter] reported by reviewdog 🐶

obs_seq[i] = Int[rand(rng) < _sigmoid(dot(B_true[:, j], X[i, :])) ? 1 : 0
for j in 1:k]


[JuliaFormatter] reported by reviewdog 🐶

@test logdensityof(glm, [1, 1]; control_seq=x) log(μ1) + log(μ2) rtol=1e-10
@test logdensityof(glm, [1, 0]; control_seq=x) log(μ1) + log(1 - μ2) rtol=1e-10
@test logdensityof(glm, [0, 1]; control_seq=x) log(1 - μ1) + log(μ2) rtol=1e-10
@test logdensityof(glm, [0, 0]; control_seq=x) log(1 - μ1) + log(1 - μ2) rtol=1e-10


[JuliaFormatter] reported by reviewdog 🐶

@test mean(Y[:, 1]) _sigmoid(dot(B[:, 1], x)) atol=0.05
@test mean(Y[:, 2]) _sigmoid(dot(B[:, 2], x)) atol=0.05


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B B_true atol=0.20


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B B_true atol=0.25


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B[:, j] glm_j.β rtol=1e-6


[JuliaFormatter] reported by reviewdog 🐶

glm, [zeros(Int, 2) for _ in 1:4], ones(5); control_seq=X,


[JuliaFormatter] reported by reviewdog 🐶

@test logdensityof(glm, [k1, k2]; control_seq=x) expected rtol=1e-10


[JuliaFormatter] reported by reviewdog 🐶

@test mean(Y[:, 1]) exp(B[1, 1]) atol=0.2
@test mean(Y[:, 2]) exp(B[1, 2]) atol=0.2


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B B_true atol=0.15


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B B_true atol=0.20


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B[:, j] glm_j.β rtol=1e-6


[JuliaFormatter] reported by reviewdog 🐶

glm, [zeros(Int, 2) for _ in 1:4], ones(5); control_seq=X,

@codecov
Copy link
Copy Markdown

codecov Bot commented May 11, 2026

Codecov Report

❌ Patch coverage is 99.35170% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 99.24%. Comparing base (11a0847) to head (941714f).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
src/glms/glm.jl 99.59% 2 Missing ⚠️
src/multivariate/t.jl 98.42% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #17      +/-   ##
==========================================
+ Coverage   98.83%   99.24%   +0.41%     
==========================================
  Files           2        3       +1     
  Lines         257      796     +539     
==========================================
+ Hits          254      790     +536     
- Misses          3        6       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit

JuliaFormatter

[JuliaFormatter] reported by reviewdog 🐶

@test S Σ atol=0.1


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B B_true atol=0.08
@test glm.Σ Σ_true atol=0.10


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B B_true atol=0.10
@test glm.Σ Σ_true atol=0.12


[JuliaFormatter] reported by reviewdog 🐶

@test logdensityof(glm, 1; control_seq=x) log(μ) rtol=1e-10
@test logdensityof(glm, 0; control_seq=x) log(1 - μ) rtol=1e-10


[JuliaFormatter] reported by reviewdog 🐶

@test mean(samples) _sigmoid(dot(glm.β, x)) atol=0.05


[JuliaFormatter] reported by reviewdog 🐶

@test glm.β β_true atol=0.15


[JuliaFormatter] reported by reviewdog 🐶

@test glm.β β_true atol=0.20


[JuliaFormatter] reported by reviewdog 🐶

@test logdensityof(glm, k; control_seq=x) logpdf(Poisson(μ), k) rtol=1e-10


[JuliaFormatter] reported by reviewdog 🐶

@test mean(samples) exp(glm.β[1]) atol=0.2


[JuliaFormatter] reported by reviewdog 🐶

@test glm.β β_true atol=0.15


[JuliaFormatter] reported by reviewdog 🐶

@test glm.β β_true atol=0.15


[JuliaFormatter] reported by reviewdog 🐶

@test logdensityof(glm, [1, 1]; control_seq=x) log(μ1) + log(μ2) rtol=1e-10
@test logdensityof(glm, [1, 0]; control_seq=x) log(μ1) + log(1 - μ2) rtol=1e-10
@test logdensityof(glm, [0, 1]; control_seq=x) log(1 - μ1) + log(μ2) rtol=1e-10
@test logdensityof(glm, [0, 0]; control_seq=x) log(1 - μ1) + log(1 - μ2) rtol=1e-10


[JuliaFormatter] reported by reviewdog 🐶

@test mean(Y[:, 1]) _sigmoid(dot(B[:, 1], x)) atol=0.05
@test mean(Y[:, 2]) _sigmoid(dot(B[:, 2], x)) atol=0.05


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B B_true atol=0.20


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B B_true atol=0.25


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B[:, j] glm_j.β rtol=1e-6


[JuliaFormatter] reported by reviewdog 🐶

@test logdensityof(glm, [k1, k2]; control_seq=x) expected rtol=1e-10


[JuliaFormatter] reported by reviewdog 🐶

@test mean(Y[:, 1]) exp(B[1, 1]) atol=0.2
@test mean(Y[:, 2]) exp(B[1, 2]) atol=0.2


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B B_true atol=0.15


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B B_true atol=0.20


[JuliaFormatter] reported by reviewdog 🐶

@test glm.B[:, j] glm_j.β rtol=1e-6

@rsenne rsenne self-assigned this May 11, 2026
rsenne and others added 15 commits May 11, 2026 11:53
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Gate JET linting on supported Julia versions

Avoid resolving JET on prerelease Julia versions where no compatible
registered release is available. Install JET only during supported lint
runs so normal package tests can run on newer Julia prereleases.
@rsenne rsenne merged commit cf5031d into main May 18, 2026
11 checks passed
@rsenne rsenne deleted the glm_additions branch May 18, 2026 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant