As I was saying this morning, I have been working on the logarithm of one of the Bessel functions and have some questions about the implementation. Currently our Bessel functions can only be evaluated at integer orders even though Boost can calculate them with any order, but Boost does not implement log-versions. Here I am only talking about the (logarithm of the) modified Bessel function of the first kind.
The immediate reason for doing so is that line 72 of
overflows for kappa > 710. That can be fixed by using log_sum_exp logic, although for large kappa it requires summing many terms. For sufficiently large kappa it is much cheaper to use an asymptotic expansion, which Boost does for kappa > 100 and very small orders. Tiny values of kappa are not really a problem numerically, although there is an asymptotic expansion for them.
The first question is what to do about the derivatives. The derivative with respect to kappa involves the same Bessel function but at order -1. It is somewhat inefficient to evaluate the Bessel function separately for one order and then an adjacent order, when both can be calculated simultaneously. But that is not something that we typically do under stan/math/prim/scal/fun. Is it okay to return a std::pair<double,double>? It would make perfect sense for the version under stan/math/rev/scal/fun to calculate the value and the derivative simultaneously (although that is not what is being done now), but von_mises_lpdf() does not call the rev version.
A second reason for reimplementing this is that we cannot currently do the Von Mises-Fisher generalization
because you have to evaluate the (log of) the Bessel function at order p / 2 - 1 and that would currently only work for even p (the dimensionality of the hypersphere). My general implementation works for any real order greater than or equal to -1, although there are specializations that could be implemented for half-integer orders that only involve summation of a finite number of terms.
I am not sure if it is worth the effort.
The last question is whether this Bessel function comes up in any other statistical contexts? In other words, do we only need to get this right for the von Mises (- Fisher) distribution? The modified Bessel function of the second kind is more common in statistics and is defined in terms of the modified Bessel function of the first kind
but there are different computational issues there that would require a separate function.
@bgoodri, is there an issue in stan-dev/stan to add it with a signature? New functions are trivial to add to Stanāall we need is the doc for the manual and the function signature in stan/lang/function_signatures.h.
I see. Hereās the GitHub issue. Iāll assign myself and up-priortize it so I get to it.
@bgoodri: I see stan/math/prim/scal/fun/log_modified_bessel_first_kind.hpp. Can the Stan signature be:
real log_modified_bessel_first_kind(int v, real z);
Weāll be adding a generic data qualifier as soon as the refactor gets moved, so we could have a qualfiied real variable data real v that would have to resolve to data (i.e., something that doesnāt need a derivative).
OK, although we should doc that the log_ version requires the first argument to be greater than -1; otherwise we would be taking the log of something that might not be positive.
What is the best way to implement the derivatives of log_modified_bessel_first_kind? We know what the numerators are:
but those should get calculated simultaneously with I_v\left(z\right) because they share basically all of the computation. Is the best thing we can do to make a copy of the prim version, stick into the rev/ directory and insert things like
if (!is_constant_struct<T1>::value) {
// calculate digamma, etc.
}
if (!is_constant_struct<T2>::value) {
// pretend v is v + 1 and calculate part of log_bessel_first_kind(v + 1, z)
}
That sort of code can live in prim. We do things with shared computations all over the probability libraries and all the univariate ones only live in prim.
Hopefully that helps. Want me to send a specific example?
The current Stan implementation of the Bessel function does not accept non-integer orders.
Ideally, I would have used the {\displaystyle {}_{1}F_{1}} directly, but the function is currently not available in stan either.
Is there a possibility of having this function for users in the near future?
I think the problem may have been calculating derivatives with respect to non-integer orders. There are a couple of relevant issues with commentary and potential workarounds:
For completenes, Iāll also add that I spent some effort on implementing the log of modified bessel of the second time and getting the derivatives right (especially w.r.t. order) proved to be beyond my skill: