template <class Model>
int command(int argc, const char* argv[])
template <class Model, class SampleRecorder, class DiagnosticRecorder,int command(std::vector<argument*> arguments)
class MessageRecorder, class InterruptHandler, ...>
I want to refactor the function:template <class Model>
int command(int argc, const char* argv[])
It is currently 769 lines and RStan pretty much reimplements the whole thing to run most of the functions. (I haven't looked at Allen's code, but my guess is PyStan also reimplements all of it.)
One way to deal with this is to change the interface to something like:template <class Model, class SampleRecorder, class DiagnosticRecorder,int command(std::vector<argument*> arguments)
class MessageRecorder, class InterruptHandler, ...>Each interface would be responsible for implementing the additional template parameters including the recorders and the "..." (tbd).
This function would then run based on what's passed in as arguments. It would be on the interfaces to translate to this argument structure.This would allow interface designers to focus on implementing the different recorders, handlers, etc. and translate from the interface to an argument structure. This should stay backwards compatible always, so interface implementers can be behind Stan without penalty and being forced to change interface code with every new version.
Michael, was the original intent of the argument structure to be used as configuration?
As it currently stands- there are no tests- not sure how easy it is to validate configurations
- how would we handle changes to configuration over time?- what helper methods are available for constructing a valid configuration?
For everyone else, anyone deal with configuration structures and have a pattern that they know about, is easy to maintain and implement, and will serve the purpose of capturing and communicating the configuration? Or... any thoughts on how to shape the arguments into something really easy to use cross-interface?
I think the stuff in src/stan/gm/arguments/ is almost there, but as it stands now, it needs a little bit more work to make it really usable. Maybe a combination of doc, tests, and factories might be enough? I'd love an extra set of eyes on the code.
Daniel
--
You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to stan-dev+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
As it currently stands- there are no tests
- not sure how easy it is to validate configurations
- how would we handle changes to configuration over time?- what helper methods are available for constructing a valid configuration?
I think you missed https://github.com/stan-dev/stan/tree/develop/src/test/integration/gm/arguments.
In particular, argument_parser_test builds up all possible combinations of valid/invalid argumentsdynamically and tests that each yields a valid/invalid configuration. Valid/invalid values aredefined by each argument and the configurations are built up from the recursive dependenciesof each argument so that nothing has to be hand-coded.
The alternative is to have each interface define some intermediate object, say a configuration string matching what we input to argv in CmdStan and let the parser handle the unpacking.
Turns out I do have a lot of thoughts on this. More below.
That would be great. I thought that was where you
On Jun 24, 2014, at 6:05 AM, Daniel Lee <bea...@alum.mit.edu> wrote:
> I want to refactor the function:
> template <class Model>
> int command(int argc, const char* argv[])
>
> It is currently 769 lines and RStan pretty much reimplements the whole thing to run most of the functions. (I haven't looked at Allen's code, but my guess is PyStan also reimplements all of it.)
were heading when you dove into R in the first place.
This is also why I think the design for the current R
interface proposal from Andrew and Ben is so important.
We're thinking a 3.0 version that breaks backward compatibility
but is much more consistent along all these fronts.
How about something like this:
> One way to deal with this is to change the interface to something like:
> template <class Model, class SampleRecorder, class DiagnosticRecorder,
> class MessageRecorder, class InterruptHandler, ...>
> int command(std::vector<argument*> arguments)
template <class Model,
class SampleWriter,
class DiagnosticWriter,
class MessageWriter,
class InterruptHandler, ...>
int command(const CmdConfig& config,
const Model& model,
SampleWriter& sampleRecorder,
...);
The classes won't be enough unless they can all be constructued
based on the config. And this way the caller won't need to
specify the template args.
I very much like the idea of there being a config object
that the interfaces just populate. If the mapping can be
general, then that's even better.
The only reasonable pattern for something general and
nested for config is the following
Simple: properties objects map string keys to values,
where a value is either a string or another property
object
Sequence Values: Add sequence values
Numeric Values: Add numeric values.
With sequence and numeric values, we basically get something that
could be coded as strings in JSON and would have a direct analogue
as an R list or Python dictionary. Then we can share the doc, with
only the method of constructing the nested object changing. It's
not super idiomatic for R, but I like it --- we're breaking the regular
command-line idioms for the commnad-line config. I don't know about Python's
idioms.
Defaults and Inheritance: Java's Properties class implementation maintains
a pointer to a parent properties class (which may be null). Keys are
first looked up in the local implementation, but if the key doesn't exist,
the call is delegated to the parent class. The whole thing can be flattened
for transport.
I'm not sure the best way to nest this in C++. A general
approach would be to use the variant structures from Boost that
are used in the abstract syntax tree for the parser, which has
the same problem in that right-hand sides can be one of many
things and you want to act differently for each.
Consistency: if we can manage purely compositional consistency,
that would be awesome. doc, testing and maintenance problems arise
as soon as values or existence of one key can depend on another (e.g.,
model string or model file in current setup).
I think it'd be great to get rid of the Rcpp dependency,
On Jun 24, 2014, at 6:29 PM, Daniel Lee <bea...@alum.mit.edu> wrote:
> Hi Allen,
>
> Thanks for the reminder! If we can get a C interface out, I think we could dance around Rcpp and Julia integration would be easy.
as it seems very brittle.
What would a C interface look like from the R side
and how would we have to restrict our output?
Hadley has a page up about it:
http://adv-r.had.co.nz/C-interface.html#c-data-structures
It looks really ugly. I see some other wrappers, but those
look like add-on packages like Rcpp, so we'd have to make sure
we're not just jumping out of the frying pan and into the fire.
It seems to me that one of two things will happen.
On Jun 24, 2014, at 6:28 PM, Daniel Lee <bea...@alum.mit.edu> wrote:
>
> As I was saying before, this sort of testing is more circular than I want it. Maybe it shouldn't be hand-coded, but perhaps we can serialize the current valid configurations to disk now and really force someone changing the spec to be conscious and think through the changes made to this spec.
1. It's easy to update the tests, so they won't test
that things stay fixed.
2. It's hard to update the tests, so the interfaces will
never get changed.
They will make people take a conscious step to change the interfaces,
but presumably they're doing that when they change the interfaces
anyway.
So we'd need to have something that tests current behavior, but
isn't just auto-generated.
To the extent we can make dependencies modular, we can test
those.
Why? Seems like the easiest way to do things to me.
> The alternative is to have each interface define some intermediate object, say a configuration string matching what we input to argv in CmdStan and let the parser handle the unpacking.
>
> I would not like to use a string as the configuration. I think that's really hard to maintain.
For instance, if we have something like JSON, that seems
more portable than passing objects around through Rcpp
or other interfaces. Not that I think it's the right thing
to do, just that it seems easiest.
Zombie programmers? I presume at least Marcus intended
On Jun 24, 2014, at 7:32 PM, Daniel Lee <bea...@alum.mit.edu> wrote:
> On Tue, Jun 24, 2014 at 1:23 PM, Bob Carpenter <ca...@alias-i.com> wrote:
>
> On Jun 24, 2014, at 6:28 PM, Daniel Lee <bea...@alum.mit.edu> wrote:
> >
> > As I was saying before, this sort of testing is more circular than I want it. Maybe it shouldn't be hand-coded, but perhaps we can serialize the current valid configurations to disk now and really force someone changing the spec to be conscious and think through the changes made to this spec.
>
> It seems to me that one of two things will happen.
>
> 1. It's easy to update the tests, so they won't test
> that things stay fixed.
>
> 2. It's hard to update the tests, so the interfaces will
> never get changed.
>
> They will make people take a conscious step to change the interfaces,
> but presumably they're doing that when they change the interfaces
> anyway.
>
> So we'd need to have something that tests current behavior, but
> isn't just auto-generated.
>
> Yeah, I'm out of ideas. Not sure where we should be between 1 & 2.
>
> I don't presume changes to the interface are conscious now.
to change the interface to include L-BFGS options. If other
things changed, they need to be documented and tested, as well,
of course.
>Agreed. I think I'd rather go with something like JSON
> To the extent we can make dependencies modular, we can test
> those.
>
> > The alternative is to have each interface define some intermediate object, say a configuration string matching what we input to argv in CmdStan and let the parser handle the unpacking.
> >
> > I would not like to use a string as the configuration. I think that's really hard to maintain.
>
> Why? Seems like the easiest way to do things to me.
> For instance, if we have something like JSON, that seems
> more portable than passing objects around through Rcpp
> or other interfaces. Not that I think it's the right thing
> to do, just that it seems easiest.
>
> Sorry, I really said the wrong thing. I would not like to use CmdStan's command line invocation as the string configuration. It feels a little too non-standard for me to be touting that as our public interface. But I'm happy to be out-voted here.
that has a more conventional structure. I was the one
who was strongly opposed to the new interface from the get
go, and I'm still on the fence about it. It works better
than I expected in practice, but it's still highly non-standard
and hence a pain to doc. The problem is that a more standard
interface has all the flat dependency issues which Michael neatly
solved with his approach, which is why I'm on the fence rather
than way over it.
- Bob
This really sounds like a breakdown of our development process. Reviewers should be asking thesequestions directly to the submitters and agreeing before checking off for the merge.
I think having tools to help reviewers identify changes can definitely be useful, but I would be hesitant to try tobootstrap them into the tests,.
On Jun 24, 2014, at 6:44 PM, Daniel Lee <bea...@alum.mit.edu> wrote:I believe Marcus intended to change the interface to include the L-BFGS options. But I can't tell if the change from "> 0" to ">= 0" in arg_tolerance or changes in arg_bfgs taking tol_obj from 1e-8 to 1e-12 was intended. Just not sure what to make of it just based on the changed code.
On Tue, Jun 24, 2014 at 2:03 PM, Michael Betancourt <betan...@gmail.com> wrote:This really sounds like a breakdown of our development process. Reviewers should be asking thesequestions directly to the submitters and agreeing before checking off for the merge.Well... it did happen.... well, not quite. It was dwarfed by more substantial changes.
And while we could just push back on the submitter, we actually want this in at some point, so we're trying to work with Marcus instead of just leaving it to him to fix.
I just see tests as a way of informing someone wanting to change it some unspecified amount of time in the future. The actual pull request, although not lost in theory, will be lost in practice. The tests would exist.