Annoucing BridgeStan: a bridge to a Stan model's log_prob and gradient functions

BridgeStan provides a bridge from a Stan program to any language with a C foreign function interface (FFI), in order to expose log density evaluations and gradients of the contained Stan model.

So far BridgeStan has focused on a few core components, instead of features or doc.

  • Force a Stan model through a C interface to enable any higher level language with a C FFI to call BridgeStan. There are currently examples for Python and Julia.
  • Ensure calls from multi-threaded code (say from Julia) are handled correctly. Calls from parallelized code should also work. Much thanks to @wds15.
  • Tweak the Makefile to work on macOS, Linux, and Windows. Much thanks to @WardBrian.
  • Once Stan math issue #2743 is more widely available, BridgeStan should be entirely copy free. Right now the position vector is copied once for every call to the gradient function.

Short term goals for BridgeStan are feature and doc parity with @Bob_Carpenter’s Stan Model Server.

Give it a try. If you have any feedback, please let me know either on discourse or in the repo itself.

11 Likes

Thanks, @roualdes. I can attest to the utility of this package because it’s what Edward’s been using with Julia to evaluate Matt Hoffman’s new highly parallel samplers (CheeS, Snaper, MEADS). MEADS is particularly cool, being an adaptation- and tuning-parameter free version of Radford Neal’s new non-reversible acceptance sampler, which itself supports partial-momentum refresh Metropolis-adjusted Langevin (MALA).

2 Likes

This is very cool. One useful feature (I assume it’s a related problem, but perhaps not) might be access to definitions in the functions block. If I am doing straightforward but nonlinear curve-fitting, I often find myself defining the same function in Stan as well as in python, e.g., so I can plot smooth fits through the data.

Thanks for posting, @defjaf. RStan already lets you do this, so others have also asked for the functionality.

RStan already lets you do this, so others have also asked for the functionality.

Yes, I experimented with getting it to work within pystan a while back, but I couldn’t get it working except for very simple cases. (And in any case I imagine that it wouldn’t really be possible with cmdstanpy – or even cmdstanr? – which now seem to be favoured.)

But are you implying that this in the roadmap for BridgeStan? Or something separate?

Do you mean exposing the user-defined functions to the environment? For cmdstanr, that is possible but requires some extra work, that I have in an online tutorial: Exposing Stan user-defined functions using CmdStanR and Rcpp

I dont know if this is something that is doable in Python, I dont have enough experience with C++ - Python interoperability.

Thanks for that example. There is quite a bit of C/C++/Python interop so I suspect it’s possible but I imagine very different from R. Anyone out there with ideas or pointers?

I think if it can be made cffi-compatible a la BridgeStan then it is probably straightforward.

I think trying to expose the UDFs of a Stan program in something like bridgestan is not possible. The key idea that makes bridgestan work is that the model class always has some functions which are easy to expose to a C wrapper. The UDFs will be different for each and every model.

That said, in some sense the problem is actually easier, since you don’t need to worry about sharing memory with an instantiated object - all those functions can be called without instantiating a model. I suspect you could do it with something like the standalone functions trick @rok_cesnovar links to above and pybind11 documentation

Right. Plus there are issues of matching container types and memory layout from the arguments of the Stan function(s) to Python (or which ever higher level language). So exposing user defined functions is more complicated than what BridgeStan does.

@defjaf, I’m happy to help you work up a prototype if you want, though I myself would have to rely on help from either or both of Brian and/or Rok. If so, maybe a new thread would be best with a minimal example Stan program containing a user defined function of interest.

I wanted to bump this thread with two new things:

  1. Bridgestan now lives on Github at GitHub - roualdes/bridgestan
  2. Bridgestan has had an overhaul internally and is now feature complete. An R interface was added, the remaining model class functionality was exposed, and important bugs around topics like exception handling have been fixed.

We still haven’t formally declared a versioned release, but it is moving toward being production ready. Documentation is one of the bigger remaining hurdles.

1 Like

@WardBrian: Didn’t you say you had a prototype that exposed Stan functions in BridgeStan (but didn’t work on Windows)?

@Bob_Carpenter - I posted that as a separate topic recently

It’s not terribly related to Bridgestan other than that Bridgestan had me thinking more about foreign function interfaces

BridgeStan continues to move forward and is (hopefully) approaching battle tested.

Thanks to @Niko for finding a subtle bug, and big big up to @WardBrian and @stevebronder for squashing it within a day. They simultaneously solved another issue, found by @alphillips (I think), that showed up only on newer versions of gcc.

Thanks to all for your help.

7 Likes

Excellent work @WardBrian and @stevebronder!

Nice. Is there any hope /plans for being able to use bridgeStan in a CRAN package for R?

1 Like

At the moment we’re not thinking of any release avenues besides Github. Using it from R/Python/Julia will always require downloading the C++ code from there, and a working copy of CmdStan (or possibly just Stan, we’re investigating loosening the requirements there)

1 Like

Bumping this thread again to mention some major updates:

  • BridgeStan no longer depends on CmdStan but is a standalone repo which includes it’s own copy of the stan repo.
  • Autodiff Hessians are now available for supported models. Enable this at compile time with the BRIDGESTAN_AD_HESSIAN=true make argument.
  • The C-level API has had all symbols prefixed with bs_. The Python/Julia/R interfaces did not change

We are planning on a 1.0 release of the package soon, so if anyone has been sitting on issues or feedback please do share them soon!

4 Likes

Is this for log_prob with Jacobian adjustment or without? (I wish with, or at least to have an option to choose)

You can choose, the default is with the Jacobian

1 Like

What does supported models mean?