The goal this time around is to build a little I/O around stan::lang::compile so that a protobuf message can go in as input with the Stan program and a message can get returned with the C++ code. The protobuf version 2 file is attached, probably makes sense to use version 3 but Ubuntu doesn't have the protobuf compiler for that and the differences are minor.
I'm not proposing this as an addition to anything we have right now, but I'd like to go through and put it together in its own repo using boost::asio. Just looking for comments if you're interested.
Krzysztof
[1] https://groups.google.com/forum/#!searchin/stan-dev/IO/stan-dev/E1eYUI2FdYE/7d3kg8hcAwAJ
I steered clear of this bigger issue for now because there's supposed to be a C++ API refactor that's going to address standardizing input facilities and past discussions have devolved into "protobuf vs. C++ API for Stan". I'll give it a shot anyway... I think Alan leaves this implicit but here's why the Stan C++ API discussion should also be a protobuf message type discussion:
1) protobuf provides multi-language mappings for strongly-typed language-agnostic data types (see the 'scalar value types' table in [1]).
2) protobuf provides strongly-typed language-agnostic complex types from message definitions.
3) protobuf auto-generates a _message_ API's that a library can be compatible with, but it's an auto-generated API with all the boilerplate that entails.
I think this sets protobuf apart in an API discussion from something that only deals with the format (e.g.-JSON) but at the same time it can't replace a well-formed C++ API. An important secondary benefit of having the protobuf discussion at the same time as the C++ API discussion would be involving the interface developers in deciding what works well for them without everyone having to have an opinion on the C++ API.
[1] https://developers.google.com/protocol-buffers/docs/proto3
> Is there any prior art on this? Perhaps someone has already thought hard
> about standardizing a protobuf error message in this kind of situation?
Good point, I was under-thinking this one. For inter-process (especially remote) communication using the protobuf rpc stuff would make sense[2,3]. The C++ API would be a lot less overhead when used locally but as you've pointed out that's not always easy.
I think it makes sense to stick to just stanc-related protobuf stuff for now and I can do a test-drive of how it would work with some of the grpc server examples once we agree on some preliminary message types.
[2] http://www.grpc.io/docs/
[3] https://github.com/grpc/grpc/blob/release-0_11/examples/cpp/cpptutorial.md
>
> I think opening an issue on Github might be the best place to have a
> discussion on this. Or maybe starting a cmdstan-protobuf repository? (Or
> pystan-protobuf or rstan-protobuf, depending on how you imagined
> prototyping this.)
I will start a github repo soon but I wanted to give the broader discussion here a shot first. I don't think I really got how protobuf could fit into Stan until it went around a few times on the dev list.
Krzysztof
Wow, my name gets butchered often enough you'd think I would check spelling... sorry: Allen!
Krzysztof
Yes!
>
> Then a protocol buffer would be one way to implement
> an input var_context (not refactored yet) or an
> output_writer (in the middle of being refactored, I think).
>
> > I'll give it a shot anyway... I think Alan leaves this implicit but here's why the Stan C++ API discussion should also be a protobuf message type discussion:
> >
> > 1) protobuf provides multi-language mappings for strongly-typed language-agnostic data types (see the 'scalar value types' table in [1]).
>
> What's the type system? Is there an intro to protobuf types
> I can read somewhere?
Yes, look at the table of types in: https://developers.google.com/protocol-buffers/docs/proto3
> > 2) protobuf provides strongly-typed language-agnostic complex types from message definitions.
>
> Could you ealborate on this. What's a "complex type"? You
> mean like an array or a dictionary/hashmap/struct?
I was thinking struct. Look at any simple message definition, say:
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
}
It's composed of types that have well-defined functions for construction/reading/writing in multiple languages but they can serve the same function as a 'struct' in a C program. They're also allowed to be nested.
>
> > 3) protobuf auto-generates a _message_ API's that a library can be compatible with, but it's an auto-generated API with all the boilerplate that entails.
>
> I don't know what this means. You're thinking of something
> that might go into a REST-ful server? Or something that'd
> work through sockets in Docker?
I think this is one of the hard things to get across---protobuf lets you define messages that we can use to talk about how interfaces _could_ communicate (yes, in a way that's inefficient if you can do in-memory instead and really more optimal for client-server interaction). What they _can't_ do is replace a good C++ Stan API so I think any protobuf thing should rely on stan-dev/stan rather than trying to integrate with it.
>
> > I think this sets protobuf apart in an API discussion from something that only deals with the format (e.g.-JSON) but at the same time it can't replace a well-formed C++ API.
>
> I still don't see the conflict here.
Ditto.
>
> > An important secondary benefit of having the protobuf discussion at the same time as the C++ API discussion would be involving the interface developers in deciding what works well for them without everyone having to have an opinion on the C++ API.
> >
> > [1] https://developers.google.com/protocol-buffers/docs/proto3
>
> We should discuss all this together. I believe R and Python are
> going to continue to interface in memory. Are you saying you'd
> convert Python data structures to protocol buffers for consumption
> by Stan? And then vice-versa? That's one way to do it, but it
> seems like a wasted intermediate step.
I think this is better for a meeting rather than email because there's a bunch of
different goals we won't really sort out in email. I think rstan/pystan are
mature enough that this discussion doesn't really touch on them but for many
other interface, especially just for prototyping interfaces and making them
easy to maintain it would be a good strategy.
>
> >> Is there any prior art on this? Perhaps someone has already thought hard
> >> about standardizing a protobuf error message in this kind of situation?
> >
> > Good point, I was under-thinking this one. For inter-process (especially remote) communication using the protobuf rpc stuff would make sense[2,3]. The C++ API would be a lot less overhead when used locally but as you've pointed out that's not always easy.
> >
> > I think it makes sense to stick to just stanc-related protobuf stuff for now and I can do a test-drive of how it would work with some of the grpc server examples once we agree on some preliminary message types.
> >
> > [2] http://www.grpc.io/docs/
> > [3] https://github.com/grpc/grpc/blob/release-0_11/examples/cpp/cpptutorial.md
>
> Stanc? As in the compiler? That seems like the thing least
> in need of anything other than simple strings in and out with
> error messages.
Agreed, but that also makes it the easiest place to do a proof of concept.
> >> I think opening an issue on Github might be the best place to have a
> >> discussion on this. Or maybe starting a cmdstan-protobuf repository? (Or
> >> pystan-protobuf or rstan-protobuf, depending on how you imagined
> >> prototyping this.)
> >
> > I will start a github repo soon but I wanted to give the broader discussion here a shot first. I don't think I really got how protobuf could fit into Stan until it went around a few times on the dev list.
>
> Let's try to talk about this in a Stan meeting. I think we may just be
> talking past each other in these emails.
Yep, I think the meetings tend to be scheduled at times I can make so let me know when it can be an agenda item.
>
> - Bob
Yeah, that's why I was thinking of just taking the available API for stanc because
it's just string -> string (with some other strings for messages). I like the stand-alone
idea because I don't understand pystan well, but it could be pystan.
>
> Best,
>
> Allen
I will have some time in the next week to give this a shot---just as a proof of concept so don't anyone get worried about making work for other people. I've never looked at pystan's
internals or even tried to build it from source so I'll do something stand-alone.
So I'm enthusiastic about a stanc server as a prototype just
because protobuf and grpc (http://www.grpc.io/docs/
https://github.com/grpc/grpc/blob/release-0_11/examples/cpp/cpptutorial.md)
make it seem really straightforward.
>
> Or is the idea to rewrite compiler.hpp so that what
> gets passed in is a protocol buffer writer instead of
> an output stream?
I think Allen is more enthusiastic about writing a thin layer of
protobuf to make passing protobuf messages possible.
> I think an intermediate solution where
> we refactor the output produced by the parser and code
> generator the same way we're doing the rest of the interface
> so that it would take more general callbacks with methods
> to do the writing however they want. One such callback
> could be protocol buffers.
Yes, I think using this for streaming output could be a pretty
cool use of the writer refactor (and it's come up in a few
conversations but Michael suggested waiting till the writer
refactor was done).
So far the list of suggested protobuf-related test projects looks like:
1) stanc server
2) shim for interfaces (say over just stanc to start)
3) standardizing error messages
4) streaming output using the current writer refactor-ed code.
5) adding callbacks parallel to the writer refactor so that protobuf messages could be produced
Part of my goal for starting this discussion on the mailing list was
to see if we can agree on which items deserve priority.
(I'm happy to do a simple version of 1) just as a demo regardless since the stanc
interface is so straightforward...)
Krzysztof
Not until there's a goal for the code! :)
>
> - Bob
Would it make sense to make a "proto" repository under stan-dev so that the various attempts at applying protobuf share the same set of .proto files (and they can get discussed or have issues independently of a specific project)?
Krzysztof
On Friday, December 4, 2015 at 5:02:19 PM UTC-5, Bob Carpenter wrote:
> Thanks --- that clears things up a lot in terms
> of the space you're thinking about. I think all of
> this is a good idea.
>
> For (5), we'd just put write callbacks that wrote to
> protocol buffers.
>
> I think doing simple things first to get a handle for
> how it works is a good idea. The design's going to
> be tangled up in the refactor design, so we should
> keep this in mind. I don't see any special problems
> that writing to protocol buffers present --- in fact,
> they solve many of the problems that other kinds of
> writing (like to CSV files) have. I particularly like
> that they can be heterogeneously typed containers.
>
> - Bob
>
Bob, could you take a look into the repository at github.com/sakrejda/protostan? I don't have the permissions to add
a new repo to stan-dev but I did set up a new repo that depends on
stan-dev/stan and stan-dev/math as submodules. There's a little README.md,
a wrapper around stan::lang::compile, a tests for the wrapper that matches the
test for stan::lang::compile, and a compile-run.sh that should be a complete recipe for compiling and running the (two) tests.
My questions about this are:
1) Does this make sense as a stan-dev repo? If so, could you make a stan-dev fork?
2) What should the namespace setup be like? At the moment it's stan::proto::function_name and I was expecting it to just be flat (so that that's where someone writing an interface would fine all the external API functionality) I'm open to doing something different, I have no experience with this.
3) Does the directory structure make sense? Again, I have little experience with making something other developers would find intuitive so I just monkeyed what Stan has (with the potential complication of code in multiple languages, not just C++).
4) I'm thinking of this as a sketch so if there's something I can do to flesh out the intent of the project I'm open to input.
5) I'm working on a writer_callback that would make sense in this context but I can't quite tell which parts of Stan are meant to be an "external" API (the stuff in "services" maybe?) So suggestions on which parts to wrap are also welcome.
Thanks for any pointers!
Krzysztof
>
> - Bob
Thanks!
> Maybe Daniel, Michael and I can look at it while we're all here.
> They've spent much more time looking at interface I/O than me.
> Where it goes depends on whether we think of it as part of
> Stan itself or an interface like CmdStan. It may wind up
> being a bit of both.
There is a lot of complexity added with the protobuf dependencies
and the protobuf code generation so unless there's a compelling
reason I think it makes sense to keep it a separate repo. If
we find a compelling reason to merge things in the future that's
fine too.
> What are the licenses for the dependencies for protocol buffers?
I don't see any dependencies for protobuf (?)
> I'm afraid I don't understand what I'm looking at, for
> example, in /proto/stanc.proto. Is that a protocol buffer
> interface script? I've never used them before. What is
> State? Is that some kind of return code enum? And cpp code is
> what's produced? What's the 2, 3, and 4 for? I could guess a
> default value for state, but cpp_code and messages are numbers.
What's a proto file: the .proto file plays the same kind of role as
a .stan file in that it can be translated by the protobuf compiler
("protoc") into C++ (or other languages).
What's up with the numbers: protobuf makes you number your fields
and that has some implications for efficiency and backwards/forwards
compatibility and efficiency.
- Efficiency: items in a messages with field numbers under... 16
(or some small number like that, don't remember now) take less
storage space. I think this only really matters when you transmit
a LOT of really small messages.
- Compatibility: the generated code can be used to check whether a
field exists, so if you deprecate and remove a field but keep the fields
numbered (leaving a useless hole in the numbering) the code previously
generated from the .proto file can continue working (assuming it doesn't
require the presence of the deprecated field). If you do renumber
fields you break all the auto-generated code.
> I assume those binaries checked into protostan/test were put
> there by mistake --- they're 40MB+.
>
> And then do you check in all that autogenerated C++ code
> in /src/cpp/proto/stanc.pb.h?
I just left it in so you could see where it was going, but Allan made a pull request to clean this stuff up which I'm going to merge.
> Where is the actual test code?
src/cpp/protostan/lang/compiler.hpp has the wrapper
src/cpp/test/stanc-test.cpp has the few tests
Krzysztof
>
> - Bob
Ok, let's pretend we needed an interface for R. The interface author
could deal with R -> C -> C++ and associated memory management.
As an alternative the interface author could write their interface code
around constructing protobuf messages following this guide:
https://cran.r-project.org/web/packages/RProtoBuf/vignettes/RProtoBuf-quickref.pdf
Then the step of calling Stan would involve only calling simple functions , passing protobuf messages as argument, and receiving protobuf messages in return. The vignette linked above show that, for the example message "message", to code for constructing it is as simple as:
message <- new( tutorial.Person, id = 0,
name = "Romain Francois",
email = "fran...@huh.org" )
message[[ "name" ]] <- "Romain"
Now if we pretend we wanted a website driven Stan interface written by someone who knows PHP, they could do the same kind of song and dance in PHP. Following
https://github.com/allegro/php-protobuf/#example here's an example of using PHP to construct a protobuf message (the .proto file is at the link):
<?php
require_once 'pb_proto_foo.php';
$foo = new Foo();
$foo->setBar(1);
$foo->setBaz('two');
$foo->appendSpam(3.0);
$foo->appendSpam(4.0);
$packed = $foo->serializeToString();
$foo->clear();
try {
$foo->parseFromString($packed);
} catch (Exception $ex) {
die('Upss.. there is a bug in this example');
}
$foo->dump();
?>
Anyway, this really limits the complexity of the actual external calls from any given language and should make it easy to write a first interface. Given the promises protobuf makes about efficiency and limiting copying I don't think it would be a bad first interface. I don't know if that vision will work out in the end but if Stan is successful enough to have interfaces to a dozen more languages I think this approach would limit the maintenance headaches. I recognize that these goals overlap with the Stan 3 goals but I don't know enough about Stan 3 goals to know how much overlap there is.
> By dependencies, I meant are there any libraries you need
> to include and what are their licenses? Stan has dependencies
> currently on Boost and Eigen, but nothing else. Is this going
> to add new library dependencies? For example, who wrote the protobuf
> compiler?
If you rolled it into stan itself there would be one dependency for the supporting protobuf library. The protobuf compiler license is pretty simple:
https://github.com/google/protobuf/blob/master/LICENSE
The key bit is:
"Code generated by the Protocol Buffer compiler is owned by the owner of the input file used when generating it. This code is not
standalone and requires a support library to be linked with it. This
support library is itself covered by the above license."
Sorry this is confusing, I only brought it back up here you
sounded interested in seeing the code. It'll only make more
sense once we figure out exactly what we want to wrap and
produce a functional example.