Akshay Jain / Jul 27 2019
Remix of Julia by Nextjournal

SparseMvNormal Runtime

using Pkg; Pkg.add(PackageSpec(url="https://github.com/luca-aki/traceEstimation.jl"))
Pkg.add("Distributions")
Pkg.add("IterativeSolvers")
Pkg.add("JLD2")
using LinearAlgebra, SparseArrays, Distributions, IterativeSolvers

Following is an example application of Chebyhutch log-determinant. In this example, we are creating a struct SparseMvNormal that inherits from AbstractMvNormal. We will be using this to calculate log probability density function.

The implementation is fairly straightforward. The major change that we have done here is to include chebyhutch as a replacement for logdet.

export SparseMvNormal

struct SparseMvNormal{T<:Real, Cov<:AbstractSparseMatrix, Mean<:AbstractVector{T}} <: AbstractMvNormal
    μ::Mean
    Σ::Cov
end

# Constructor
function SparseMvNormal(μ::AbstractVector{T}, Σ::AbstractSparseMatrix{T}) where {T<:Real}
    size(Σ, 1) == size(μ, 1) || throw(DimensionMismatch("The dimensions of mu and Sigma are inconsistent."))
    SparseMvNormal{T, typeof(Σ), typeof(μ)}(μ, Σ)
end

# Basic stats
Base.length(d::SparseMvNormal) = length(d.μ)
Distributions.mean(d::SparseMvNormal) = d.μ

Distributions.var(d::SparseMvNormal) = diag(d.Σ)
Distributions.cov(d::SparseMvNormal) = d.Σ

struct Inv{T, Cov<:AbstractSparseMatrix}
    cov::Cov
end
Base.:\(a::Inv, x::AbstractVector) = cg(a.cov, x)
Distributions.invcov(d::SparseMvNormal) = Inv(d.cov)
Distributions.logdetcov(d::SparseMvNormal) = chebyhutch(d.Σ, 4, 6, fn = log)

# Evaluation
invquad(a::AbstractSparseMatrix, x::StridedVector) = dot(x, cg(a, x))
Distributions.sqmahal(d::SparseMvNormal, x::AbstractVector) = invquad(d.Σ, x .- d.μ)
Distributions.sqmahal!(r::AbstractVector, d::SparseMvNormal, x::AbstractMatrix) = invquad!(r, d.Σ, x .- d.μ)
gradlogpdf(d::SparseMvNormal, x::AbstractVector) = -(d.Σ \ (x .- d.μ))
SparseMvNormalCode
Julia