BesselK

An AD-compatible modified second-kind Bessel function.

https://github.com/cgeoga/besselk.jl

Science Score: 64.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
    Found CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
    Links to: arxiv.org
  • Committers with academic emails
    1 of 5 committers (20.0%) from academic institutions
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (11.4%) to scientific vocabulary
Last synced: 6 months ago · JSON representation ·

Repository

An AD-compatible modified second-kind Bessel function.

Basic Info
  • Host: GitHub
  • Owner: cgeoga
  • License: mit
  • Language: Julia
  • Default Branch: main
  • Homepage:
  • Size: 125 KB
Statistics
  • Stars: 16
  • Watchers: 1
  • Forks: 0
  • Open Issues: 1
  • Releases: 5
Created about 4 years ago · Last pushed 7 months ago
Metadata Files
Readme License Citation

README.md

BesselK.jl

This package implements one function: the modified second-kind Bessel function Kᵥ(x). It is designed specifically to be automatically differentiable with ForwardDiff.jl, including providing derivatives with respect to the order parameter v that are fast and non-allocating in the entire domain for both first and second order.

Derivatives with respect to \nu are significantly faster than any finite differencing method, including the most naive fixed-step minimum-order method, and in almost all of the domain are meaningful more accurate. Particularly near the origin you should expect to gain at least 3-5 digits. Second derivatives are even more dramatic, both in terms of the speedup and accuracy gains, now commonly giving 10+ more digits of accuracy.

As a happy accident/side-effect, if you're willing to give up the last couple digits of accuracy, you could also use ForwardDiff.jl on this code for derivatives with respect to argument for an order-of-magnitude speedup. In some casual testing the argument-derivative errors with this code are never worse than 1e-12, and they turn 1.4 μs with allocations into 140 ns without any allocations.

In order to avoid naming conflicts with other packages, this package exports three functions: * matern: the Matern covariance function in its most common parameterization. See the docstrings for more info. * adbesselk: Gives Kᵥ(x), using Bessels.jl if applicable and our more specialized order-AD codes otherwise. * adbesselkxv: Gives Kᵥ(x)*(x^v), using Bessels.jl if applicable and our more specialized order-AD codes otherwise.

Here is a very basic demo: ```julia using ForwardDiff, SpecialFunctions, BesselK

(v, x) = (1.1, 2.1)

For regular evaluations, you get what you're used to getting:

@assert isapprox(besselk(v, x), adbesselk(v, x)) @assert isapprox((x^v)*besselk(v, x), adbesselkxv(v, x))

But now you also get good (and fast!) derivatves:

@show ForwardDiff.derivative(v->adbesselk(v, x), v) # good to go. @show ForwardDiff.derivative(v->adbesselkxv(v, x), v) # good to go. ```

A note to people coming here from the paper

You'll see that this repo defines a great deal of specific derivative functions in the files in ./paperscripts. This is only because we specifically tested those quantities in the paper. If you're just here to fit a Matern covariance function, then you should not be doing that. Your code, at least in the simplest case, should probably look more like this: ```julia

using ForwardDiff, BesselK

function mycovariancefunction(loc1, loc2, params) ... # your awesome covariance function, presumably using adbesselk somewhere. end

const mydata = ... # load in your data const mylocations = ... # load in your locations

Create your likelihood and use ForwardDiff for the grad and Hessian:

function nll(params) K = cholesky!(Symmetric([mycovariancefunction(x, y, params) for x in mylocations, y in mylocations])) 0.5*(logdet(K) + dot(mydata, K\mydata)) end nllg(params) = ForwardDiff.gradient(nll, params) nllh(params) = ForwardDiff.hessian(nll, params)

mymle = someoptimizer(init_params, nll, nllg, nllh, ...) `` Or something like that. You of course do not *have* to do it this way, and could manually implement the gradient and Hessian of the likelihood after manually creating derivatives of the covariance function itself (see ./example/matern.jl` for a demo of that), and manual implementations, particularly for the Hessian, will be faster if they are thoughtful enough. But what I mean to emphasize here is that in general you should not be doing manual chain rule or derivative computations of your covariance function itself. Let the AD handle that for you and enjoy the power that Julia's composability offers.

Limitations

For the moment there are two primary limitations:

  • AD compatibility with ForwardDiff.jl only. The issue here is that in one particular case I use a different function branch of one is taking a derivative with respect to v or just evaluating besselk(v, x). The way that is currently checked in the code is with if (v isa AbstractFloat), which may not work properly for other methods.

  • Only derivatives up to the second are checked and confirmed accurate. The code uses a large number of local polynomial expansions at slightly hairy values of internal intermediate functions, and so at some sufficiently high level of derivative those local polynomials won't give accurate partial information.

Also consider: Bessels.jl

This software package was written with the pretty specific goal of computing derivatives of Kᵥ(x) with respect to the order using ForwardDiff.jl. While it is in general a bit faster than AMOS, we give up a few digits of accuracy here and there in the interest of better and faster derivatives. If you just want the fastest possible Kᵥ(x) for floating point order and argument (as in, you don't need to do AD), then you would probably be better off using Bessels.jl.

This code now uses Bessels.jl whenever possible, so now the only question is really about whether you need AD. If you need AD with respect to order, use this package. If you don't, then this package offers nothing beyond what Bessels.jl does.

Implementation details

See the reference for an entire paper discussing the implementation. But in a word, this code uses several routines to evaluate Kᵥ accurately on different parts of the domain, and has to use some non-standard to maintain AD compatibility and correctness. When v is an integer or half-integer, for example, a lot of additional work is required.

The code is also pretty well-optimized, and you can benchmark for yourself or look at the paper to see that in several cases the ForwardDiff.jl-generated derivatives are faster than a single call to SpecialFunctions.besselk. To achieve this performance, particularly for second derivatives, some work was required to make sure that all of the function calls are non-allocating, which means switching from raw Tuples to Polynomial types in places where the polynomials are large enough and things like that. Again this arguably makes the code look a bit disorganized or inconsistent, but to my knowledge it is all necessary. If somebody looking at the source finds a simplification, I would love to see it, either in terms of an issue or a PR or an email or a patch file or anything.

Citation

If you use this package in your research that gets compiled into some kind of report/article/poster/etc, please cite this paper: @misc{GMSS_2022, title={Fitting Mat\'ern Smoothness Parameters Using Automatic Differentiation}, author={Christopher J. Geoga and Oana Marin and Michel Schanen and Michael L. Stein}, year={2022}, journal={Statistics and Computing} } While this package ostensibly only covers a single function, putting all of this together and making it this fast and accurate was really a lot of work. I would really appreciate you citing this paper if this package was useful in your research. Like, for example, if you used this package to fit a Matern smoothness parameter with second order optimization methods.

Owner

  • Name: Chris Geoga
  • Login: cgeoga
  • Kind: user
  • Location: Madison, WI

Assistant Professor of Statistics at UW Madison

Citation (CITATION.cff)

cff-version: "1.2.0"
message: "If you use this software, please cite it as below."

authors:
  - family-names: Geoga
    given-names: Christopher J.
  - family-names: Marin
    given-names: Oana
  - family-names: Schanen
    given-names: Michel
  - family-names: Stein
    given-names: Michael L.
    
# Based on https://github.com/citation-file-format/citation-file-format/blob/main/schema-guide.md
identifiers:
  - type: other
    value: arXiv:2201.00090

title: "Fitting Mat\'ern Smoothness Parameters Using Automatic Differentiation"
year: 2022

GitHub Events

Total
  • Release event: 1
  • Watch event: 2
  • Push event: 1
  • Create event: 1
Last Year
  • Release event: 1
  • Watch event: 2
  • Push event: 1
  • Create event: 1

Committers

Last synced: 9 months ago

All Time
  • Total Commits: 44
  • Total Committers: 5
  • Avg Commits per committer: 8.8
  • Development Distribution Score (DDS): 0.136
Past Year
  • Commits: 2
  • Committers: 1
  • Avg Commits per committer: 2.0
  • Development Distribution Score (DDS): 0.0
Top Committers
Name Email Commits
Chris Geoga c****a@p****m 38
CompatHelper Julia c****y@j****g 3
Rik Huijzer t****r@r****l 1
Michel Schanen M****n@g****m 1
Chris Geoga c****s@c****m 1
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: 6 months ago

All Time
  • Total issues: 6
  • Total pull requests: 5
  • Average time to close issues: 25 days
  • Average time to close pull requests: about 10 hours
  • Total issue authors: 5
  • Total pull request authors: 3
  • Average comments per issue: 5.83
  • Average comments per pull request: 0.4
  • Merged pull requests: 5
  • Bot issues: 0
  • Bot pull requests: 3
Past Year
  • Issues: 0
  • Pull requests: 0
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Issue authors: 0
  • Pull request authors: 0
  • Average comments per issue: 0
  • Average comments per pull request: 0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • rikhuijzer (2)
  • ahbarnett (1)
  • MasonProtter (1)
  • oscardssmith (1)
  • JuliaTagBot (1)
Pull Request Authors
  • github-actions[bot] (3)
  • michel2323 (1)
  • rikhuijzer (1)
Top Labels
Issue Labels
Pull Request Labels

Packages

  • Total packages: 1
  • Total downloads:
    • julia 5 total
  • Total dependent packages: 1
  • Total dependent repositories: 0
  • Total versions: 13
juliahub.com: BesselK

An AD-compatible modified second-kind Bessel function.

  • Versions: 13
  • Dependent Packages: 1
  • Dependent Repositories: 0
  • Downloads: 5 Total
Rankings
Dependent repos count: 9.9%
Dependent packages count: 23.0%
Average: 29.8%
Stargazers count: 32.6%
Forks count: 53.5%
Last synced: 6 months ago

Dependencies

.github/workflows/TagBot.yml actions
  • JuliaRegistries/TagBot v1 composite
.github/workflows/ci.yml actions
  • actions/checkout v2 composite
  • julia-actions/julia-buildpkg latest composite
  • julia-actions/julia-runtest latest composite
  • julia-actions/setup-julia latest composite
.github/workflows/CompatHelper.yml actions